@marko/tree-sitter 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/grammar.js +2 -0
- package/package.json +14 -14
- package/prebuilds/darwin-arm64/@marko+tree-sitter.node +0 -0
- package/prebuilds/darwin-x64/@marko+tree-sitter.node +0 -0
- package/prebuilds/linux-arm64/@marko+tree-sitter.node +0 -0
- package/prebuilds/linux-x64/@marko+tree-sitter.node +0 -0
- package/prebuilds/win32-x64/@marko+tree-sitter.node +0 -0
- package/src/grammar.json +8 -0
- package/src/node-types.json +12 -0
- package/src/parser.c +2151 -2050
- package/src/scanner.c +163 -2
- package/tree-sitter-marko.wasm +0 -0
- package/tree-sitter.json +1 -1
package/src/scanner.c
CHANGED
|
@@ -79,6 +79,7 @@ enum TokenType {
|
|
|
79
79
|
TYPES_CLOSE, // ">"
|
|
80
80
|
ATTR_GROUP_OPEN, // "["
|
|
81
81
|
ATTR_GROUP_CLOSE, // "]"
|
|
82
|
+
ATTR_METHOD_ASYNC, // "async" before a shorthand method
|
|
82
83
|
ATTR_NAME,
|
|
83
84
|
ATTR_EQ, // "="
|
|
84
85
|
ATTR_BOUND_EQ, // ":="
|
|
@@ -499,7 +500,11 @@ static bool should_terminate(EStream *es, ExprState *e, int32_t code,
|
|
|
499
500
|
return next == '>';
|
|
500
501
|
case '>':
|
|
501
502
|
// `=>` continues unless it is the very start of the expression.
|
|
502
|
-
|
|
503
|
+
if (at_start) return true;
|
|
504
|
+
if (prev == '=') return false;
|
|
505
|
+
// A whitespace preceded ">=" is always a comparison: a closed tag
|
|
506
|
+
// would have put the "=" in its body content.
|
|
507
|
+
return !(is_ws(prev) && next == '=');
|
|
503
508
|
default:
|
|
504
509
|
return false;
|
|
505
510
|
}
|
|
@@ -738,6 +743,11 @@ static bool check_for_operators(EStream *es, ExprState *e, bool eol) {
|
|
|
738
743
|
}
|
|
739
744
|
|
|
740
745
|
int32_t next_c = es_peek(es, k);
|
|
746
|
+
// In HTML mode a "</" is a close tag rather than a less-than operator.
|
|
747
|
+
if (!is_concise(s) && next_c == '<' && es_peek(es, k + 1) == '/') {
|
|
748
|
+
return false;
|
|
749
|
+
}
|
|
750
|
+
|
|
741
751
|
if (next_c >= 0 && !should_terminate(es, e, next_c, k)) {
|
|
742
752
|
int64_t consume = look_ahead_for_operator(es, e, k);
|
|
743
753
|
if (consume != -1) {
|
|
@@ -1335,6 +1345,144 @@ static ExprCfg cfg_type_expr(void) {
|
|
|
1335
1345
|
return cfg;
|
|
1336
1346
|
}
|
|
1337
1347
|
|
|
1348
|
+
static inline bool is_attr_name_char(int32_t c) {
|
|
1349
|
+
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
|
1350
|
+
(c >= '0' && c <= '9') || c == '_' || c == '$' || c == '-';
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
// Whitespace the async keyword may be separated from its method by. A newline
|
|
1354
|
+
// ends a concise mode attribute, so only indentation counts there.
|
|
1355
|
+
static inline bool skip_async_space(EStream *es, Scanner *s, uint32_t k) {
|
|
1356
|
+
int32_t c = es_peek(es, k);
|
|
1357
|
+
if (c < 0) return false;
|
|
1358
|
+
return is_concise(s) ? is_indent_code(c) : is_ws(c);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// A token cannot be taken back, so the whole signature is checked up front:
|
|
1362
|
+
// the parser defers instead, until the args close and a "{" follows.
|
|
1363
|
+
// The attribute name is exactly "async": a longer name ("asyncfoo") or one
|
|
1364
|
+
// carrying a modifier ("async:mod") is an ordinary attribute name.
|
|
1365
|
+
static bool is_async_keyword(EStream *es) {
|
|
1366
|
+
static const char kw[] = "async";
|
|
1367
|
+
for (uint32_t i = 0; i < 5; i++) {
|
|
1368
|
+
if (es_peek(es, i) != kw[i]) return false;
|
|
1369
|
+
}
|
|
1370
|
+
int32_t c = es_peek(es, 5);
|
|
1371
|
+
return c != ':' && !is_attr_name_char(c);
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// Skips a balanced group, stepping over the literals and comments whose
|
|
1375
|
+
// contents would otherwise be counted as delimiters.
|
|
1376
|
+
static bool skip_async_group(EStream *es, uint32_t *pk, int32_t open,
|
|
1377
|
+
int32_t close) {
|
|
1378
|
+
uint32_t k = *pk;
|
|
1379
|
+
uint32_t depth = 0;
|
|
1380
|
+
int32_t prev = 0;
|
|
1381
|
+
|
|
1382
|
+
do {
|
|
1383
|
+
int32_t c = es_peek(es, k);
|
|
1384
|
+
if (c < 0) return false;
|
|
1385
|
+
|
|
1386
|
+
if (c == '"' || c == '\'' || c == '`') {
|
|
1387
|
+
int32_t quote = c;
|
|
1388
|
+
uint32_t tmpl_depth = 0;
|
|
1389
|
+
k++;
|
|
1390
|
+
for (;;) {
|
|
1391
|
+
c = es_peek(es, k);
|
|
1392
|
+
if (c < 0) return false;
|
|
1393
|
+
k++;
|
|
1394
|
+
if (c == '\\') {
|
|
1395
|
+
if (es_peek(es, k) < 0) return false;
|
|
1396
|
+
k++;
|
|
1397
|
+
} else if (quote == '`' && c == '$' && es_peek(es, k) == '{') {
|
|
1398
|
+
tmpl_depth++;
|
|
1399
|
+
k++;
|
|
1400
|
+
} else if (tmpl_depth && c == '}') {
|
|
1401
|
+
tmpl_depth--;
|
|
1402
|
+
} else if (c == quote && !tmpl_depth) {
|
|
1403
|
+
break;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
prev = quote;
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
if (c == '/') {
|
|
1411
|
+
int32_t next = es_peek(es, k + 1);
|
|
1412
|
+
if (!can_follow_division(prev)) { // a regular expression literal
|
|
1413
|
+
bool in_class = false;
|
|
1414
|
+
k++;
|
|
1415
|
+
for (;;) {
|
|
1416
|
+
c = es_peek(es, k);
|
|
1417
|
+
if (c < 0 || c == '\n') return false;
|
|
1418
|
+
k++;
|
|
1419
|
+
if (c == '\\') {
|
|
1420
|
+
if (es_peek(es, k) < 0) return false;
|
|
1421
|
+
k++;
|
|
1422
|
+
} else if (c == '[') in_class = true;
|
|
1423
|
+
else if (c == ']') in_class = false;
|
|
1424
|
+
else if (c == '/' && !in_class) break;
|
|
1425
|
+
}
|
|
1426
|
+
prev = '/';
|
|
1427
|
+
continue;
|
|
1428
|
+
}
|
|
1429
|
+
if (next == '/') {
|
|
1430
|
+
while ((c = es_peek(es, k)) >= 0 && c != '\n') k++;
|
|
1431
|
+
continue;
|
|
1432
|
+
}
|
|
1433
|
+
if (next == '*') {
|
|
1434
|
+
k += 2;
|
|
1435
|
+
while ((c = es_peek(es, k)) >= 0 &&
|
|
1436
|
+
!(c == '*' && es_peek(es, k + 1) == '/')) {
|
|
1437
|
+
k++;
|
|
1438
|
+
}
|
|
1439
|
+
if (c < 0) return false;
|
|
1440
|
+
k += 2;
|
|
1441
|
+
continue;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
if (c == open) depth++;
|
|
1446
|
+
else if (c == close) depth--;
|
|
1447
|
+
if (!is_ws(c)) prev = c;
|
|
1448
|
+
k++;
|
|
1449
|
+
} while (depth);
|
|
1450
|
+
|
|
1451
|
+
*pk = k;
|
|
1452
|
+
return true;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
static bool is_async_method_ahead(EStream *es, Scanner *s) {
|
|
1456
|
+
uint32_t k = 0;
|
|
1457
|
+
|
|
1458
|
+
// In concise mode a newline ends the attribute, so the method cannot
|
|
1459
|
+
// continue onto the next line.
|
|
1460
|
+
bool had_space = false;
|
|
1461
|
+
while (skip_async_space(es, s, k)) {
|
|
1462
|
+
k++;
|
|
1463
|
+
had_space = true;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// An optional method name, which must be separated from the keyword.
|
|
1467
|
+
if (is_attr_name_char(es_peek(es, k))) {
|
|
1468
|
+
if (!had_space) return false;
|
|
1469
|
+
while (is_attr_name_char(es_peek(es, k))) k++;
|
|
1470
|
+
while (skip_async_space(es, s, k)) k++;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
// Optional type params, then the params, then the body opener.
|
|
1474
|
+
if (es_peek(es, k) == '<') {
|
|
1475
|
+
if (!skip_async_group(es, &k, '<', '>')) return false;
|
|
1476
|
+
while (skip_async_space(es, s, k)) k++;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
if (es_peek(es, k) != '(') return false;
|
|
1480
|
+
if (!skip_async_group(es, &k, '(', ')')) return false;
|
|
1481
|
+
|
|
1482
|
+
while (skip_async_space(es, s, k)) k++;
|
|
1483
|
+
return es_peek(es, k) == '{';
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1338
1486
|
static ExprCfg cfg_attr_name(Scanner *s) {
|
|
1339
1487
|
ExprCfg cfg;
|
|
1340
1488
|
memset(&cfg, 0, sizeof(cfg));
|
|
@@ -3273,6 +3421,18 @@ static bool scan_open_tag_es(Scanner *s, TSLexer *lexer, const bool *valid,
|
|
|
3273
3421
|
s->tag_has_attrs = 1;
|
|
3274
3422
|
}
|
|
3275
3423
|
|
|
3424
|
+
// Both readings span the same text, so only the symbol depends on the
|
|
3425
|
+
// lookahead; marking first is what keeps the extent right while peeking.
|
|
3426
|
+
if (c == 'a' && is_async_keyword(es)) {
|
|
3427
|
+
for (int i = 0; i < 5; i++) es_next_mark(es); // "async"
|
|
3428
|
+
bool method = is_async_method_ahead(es, s);
|
|
3429
|
+
if (!valid[method ? ATTR_METHOD_ASYNC : ATTR_NAME]) return false;
|
|
3430
|
+
s->attr_stage = ATTR_NAME_STAGE;
|
|
3431
|
+
lexer->result_symbol = method ? ATTR_METHOD_ASYNC : ATTR_NAME;
|
|
3432
|
+
concise_tag_epilogue(s, lexer);
|
|
3433
|
+
return true;
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3276
3436
|
if (c == '<') return false; // INVALID_ATTRIBUTE_NAME
|
|
3277
3437
|
{
|
|
3278
3438
|
bool empty = false;
|
|
@@ -3550,7 +3710,8 @@ static const char *const TOKEN_NAMES[] = {
|
|
|
3550
3710
|
"PARAM_TYPE", "PARAM_EQ", "PARAM_DEFAULT", "PARAM_COMMA",
|
|
3551
3711
|
"PARAMS_CLOSE", "TYPE_ARGS_OPEN",
|
|
3552
3712
|
"TYPE_PARAMS_OPEN", "TYPE_EXPR", "TYPES_CLOSE", "ATTR_GROUP_OPEN",
|
|
3553
|
-
"ATTR_GROUP_CLOSE", "
|
|
3713
|
+
"ATTR_GROUP_CLOSE", "ATTR_METHOD_ASYNC", "ATTR_NAME", "ATTR_EQ",
|
|
3714
|
+
"ATTR_BOUND_EQ",
|
|
3554
3715
|
"ATTR_SPREAD_START", "ATTR_VALUE_EXPR", "METHOD_BODY_OPEN",
|
|
3555
3716
|
"METHOD_BODY_EXPR", "METHOD_BODY_CLOSE", "OPEN_TAG_END",
|
|
3556
3717
|
"OPEN_TAG_END_SELF", "CONCISE_OPEN_TAG_END", "CLOSE_TAG_START",
|
package/tree-sitter-marko.wasm
CHANGED
|
Binary file
|