tree-sitter-sed 0.12.0 → 0.14.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/Cargo.toml CHANGED
@@ -10,7 +10,7 @@ name = "tree-sitter-sed"
10
10
  publish = false
11
11
  readme = "README.md"
12
12
  repository = "https://github.com/konomanoasa/tree-sitter-sed"
13
- version = "0.12.0"
13
+ version = "0.14.0"
14
14
 
15
15
  build = "bindings/rust/build.rs"
16
16
  include = [
@@ -10,8 +10,9 @@ fn compile_parser(
10
10
  let mut c_config = cc::Build::new();
11
11
  c_config.std("c17").include(source_dir);
12
12
 
13
- #[cfg(target_env = "msvc")]
14
- c_config.flag("-utf-8");
13
+ if c_config.get_compiler().is_like_msvc() {
14
+ c_config.flag("-utf-8");
15
+ }
15
16
 
16
17
  if let Some(headers) = wasm_headers {
17
18
  c_config.include(headers);
@@ -426,27 +426,86 @@ mod tests {
426
426
  {
427
427
  let mut parser = tree_sitter::Parser::new();
428
428
  parser.set_language(&language.into()).unwrap();
429
- for (name, source, start, row, column, normal_kind, allow_replacement) in [
429
+ for (name, source, start, row, column, normal_nodes, allow_replacement) in [
430
430
  (
431
431
  "initial comment text",
432
432
  &b"#xn\np\n"[..],
433
433
  1,
434
434
  0,
435
435
  1,
436
- "comment_text",
436
+ ("comment_text", None),
437
+ true,
438
+ ),
439
+ (
440
+ "label definition",
441
+ &b":axb\np\n"[..],
442
+ 2,
443
+ 0,
444
+ 2,
445
+ ("label_literal", Some("label")),
446
+ true,
447
+ ),
448
+ (
449
+ "branch label",
450
+ &b"b axb\np\n"[..],
451
+ 3,
452
+ 0,
453
+ 3,
454
+ ("label_literal", Some("label")),
455
+ true,
456
+ ),
457
+ (
458
+ "test label",
459
+ &b"t axb\np\n"[..],
460
+ 3,
461
+ 0,
462
+ 3,
463
+ ("label_literal", Some("label")),
464
+ true,
465
+ ),
466
+ (
467
+ "rfile",
468
+ &b"r axb\np\n"[..],
469
+ 3,
470
+ 0,
471
+ 3,
472
+ ("file_literal", Some("rfile")),
473
+ true,
474
+ ),
475
+ (
476
+ "wfile",
477
+ &b"w axb\np\n"[..],
478
+ 3,
479
+ 0,
480
+ 3,
481
+ ("file_literal", Some("wfile")),
482
+ true,
483
+ ),
484
+ (
485
+ "substitution wfile",
486
+ &b"s/a/b/w axb\np\n"[..],
487
+ 9,
488
+ 0,
489
+ 9,
490
+ ("file_literal", Some("wfile")),
491
+ true,
492
+ ),
493
+ (
494
+ "text",
495
+ &b"a\\\naxb\np\n"[..],
496
+ 4,
497
+ 1,
498
+ 1,
499
+ ("text_literal", None),
437
500
  true,
438
501
  ),
439
- ("label", &b": axb\np\n"[..], 3, 0, 3, "label", true),
440
- ("rfile", &b"r axb\np\n"[..], 3, 0, 3, "rfile", true),
441
- ("wfile", &b"w axb\np\n"[..], 3, 0, 3, "wfile", true),
442
- ("text", &b"a\\\naxb\np\n"[..], 4, 1, 1, "text_literal", true),
443
502
  (
444
503
  "replacement",
445
504
  &b"s/a/axb/\np\n"[..],
446
505
  5,
447
506
  0,
448
507
  5,
449
- "replacement_literal",
508
+ ("replacement_literal", None),
450
509
  true,
451
510
  ),
452
511
  (
@@ -455,7 +514,7 @@ mod tests {
455
514
  3,
456
515
  0,
457
516
  3,
458
- "translation_literal",
517
+ ("translation_literal", None),
459
518
  true,
460
519
  ),
461
520
  (
@@ -464,7 +523,7 @@ mod tests {
464
523
  7,
465
524
  0,
466
525
  7,
467
- "translation_literal",
526
+ ("translation_literal", None),
468
527
  true,
469
528
  ),
470
529
  (
@@ -473,7 +532,7 @@ mod tests {
473
532
  5,
474
533
  1,
475
534
  2,
476
- "text_backslash_escape",
535
+ ("text_backslash_escape", None),
477
536
  false,
478
537
  ),
479
538
  (
@@ -482,7 +541,7 @@ mod tests {
482
541
  6,
483
542
  0,
484
543
  6,
485
- "replacement_escape",
544
+ ("replacement_escape", None),
486
545
  false,
487
546
  ),
488
547
  (
@@ -491,7 +550,7 @@ mod tests {
491
550
  4,
492
551
  0,
493
552
  4,
494
- "translation_escape",
553
+ ("translation_escape", None),
495
554
  false,
496
555
  ),
497
556
  (
@@ -500,7 +559,7 @@ mod tests {
500
559
  8,
501
560
  0,
502
561
  8,
503
- "translation_escape",
562
+ ("translation_escape", None),
504
563
  false,
505
564
  ),
506
565
  (
@@ -509,7 +568,7 @@ mod tests {
509
568
  2,
510
569
  0,
511
570
  2,
512
- "ordinary_character",
571
+ ("ordinary_character", None),
513
572
  true,
514
573
  ),
515
574
  (
@@ -518,7 +577,7 @@ mod tests {
518
577
  3,
519
578
  0,
520
579
  3,
521
- "collating_element",
580
+ ("collating_element", None),
522
581
  true,
523
582
  ),
524
583
  (
@@ -527,7 +586,7 @@ mod tests {
527
586
  5,
528
587
  0,
529
588
  5,
530
- "coll_elem_multi",
589
+ ("coll_elem_multi", None),
531
590
  true,
532
591
  ),
533
592
  (
@@ -536,7 +595,7 @@ mod tests {
536
595
  5,
537
596
  0,
538
597
  5,
539
- "coll_elem_multi",
598
+ ("coll_elem_multi", None),
540
599
  true,
541
600
  ),
542
601
  (
@@ -545,16 +604,25 @@ mod tests {
545
604
  5,
546
605
  0,
547
606
  5,
548
- "class_name",
607
+ ("class_name", None),
549
608
  false,
550
609
  ),
551
610
  ] {
552
- for invalid in [&b"\xff"[..], &b"\xff\xfe"[..]] {
611
+ let (normal_kind, owner_kind) = normal_nodes;
612
+ let mut invalid_inputs = vec![&b"\xff"[..], &b"\xff\xfe"[..]];
613
+ if owner_kind.is_some() {
614
+ invalid_inputs.extend([&b"\0"[..], &b"\xff\0\xfe"[..]]);
615
+ }
616
+ for invalid in invalid_inputs {
553
617
  let mut tree = parser.parse(source, None).unwrap();
554
618
  assert!(!tree.root_node().has_error(), "{mode}, {name}");
555
619
  assert!(issue_signatures(&tree).is_empty(), "{mode}, {name}");
556
620
  let mut old_length = 1;
557
- let mut replacements = vec![invalid, &source[start..start + 1]];
621
+ let mut replacements = vec![invalid];
622
+ if owner_kind.is_some() {
623
+ replacements.push(&b""[..]);
624
+ }
625
+ replacements.push(&source[start..start + 1]);
558
626
  if allow_replacement {
559
627
  replacements.push("\u{fffd}".as_bytes());
560
628
  }
@@ -585,23 +653,83 @@ mod tests {
585
653
  };
586
654
  let expected: Vec<_> = ranges
587
655
  .iter()
588
- .map(|range| {
589
- (
590
- "invalid_syntax".to_owned(),
591
- "invalid_encoding".to_owned(),
592
- *range,
593
- )
656
+ .zip(invalid)
657
+ .map(|(range, byte)| {
658
+ let (outcome, reason) = if *byte == 0 {
659
+ ("nonconforming_syntax", "nul_character")
660
+ } else {
661
+ ("invalid_syntax", "invalid_encoding")
662
+ };
663
+ (outcome.to_owned(), reason.to_owned(), *range)
594
664
  })
595
665
  .collect();
666
+ let encoding_ranges: Vec<_> = expected
667
+ .iter()
668
+ .filter(|(_, reason, _)| reason == "invalid_encoding")
669
+ .map(|(_, _, range)| *range)
670
+ .collect();
596
671
  let context =
597
672
  format!("{mode}, {name}, invalid {invalid:?}, step {step}");
598
673
  for parsed in [&fresh, &incremental] {
599
674
  assert!(!parsed.root_node().has_error(), "{context}");
600
675
  assert_eq!(issue_signatures(parsed), expected, "{context}");
601
- assert_invalid_encoding_leaves(parsed, &ranges, &context);
676
+ assert_invalid_encoding_leaves(
677
+ parsed,
678
+ &encoding_ranges,
679
+ &context,
680
+ );
602
681
  let mut nodes = vec![parsed.root_node()];
603
682
  let mut repaired_leaf = false;
683
+ let mut owners = 0;
604
684
  while let Some(node) = nodes.pop() {
685
+ if Some(node.kind()) == owner_kind {
686
+ owners += 1;
687
+ let owner_range = Range {
688
+ start_byte: start - 1,
689
+ end_byte: start + replacement.len() + 1,
690
+ start_point: Point::new(row, column - 1),
691
+ end_point: Point::new(row, column + replacement.len() + 1),
692
+ };
693
+ assert_eq!(node.range(), owner_range, "{context}");
694
+ let expected_children = if step == 0 {
695
+ let mut children = vec![(
696
+ normal_kind,
697
+ Range {
698
+ end_byte: start,
699
+ end_point: Point::new(row, column),
700
+ ..owner_range
701
+ },
702
+ )];
703
+ children.extend(
704
+ ranges.iter().map(|range| ("syntax_issue", *range)),
705
+ );
706
+ children.push((
707
+ normal_kind,
708
+ Range {
709
+ start_byte: start + replacement.len(),
710
+ start_point: Point::new(
711
+ row,
712
+ column + replacement.len(),
713
+ ),
714
+ ..owner_range
715
+ },
716
+ ));
717
+ children
718
+ } else {
719
+ vec![(normal_kind, owner_range)]
720
+ };
721
+ let children: Vec<_> = (0..node.child_count())
722
+ .map(|index| {
723
+ let child = node.child(index).unwrap();
724
+ assert!(child.is_named(), "{context}");
725
+ if child.kind() == normal_kind {
726
+ assert_eq!(child.child_count(), 0, "{context}");
727
+ }
728
+ (child.kind(), child.range())
729
+ })
730
+ .collect();
731
+ assert_eq!(children, expected_children, "{context}");
732
+ }
605
733
  if name == "initial comment text" {
606
734
  assert_ne!(
607
735
  node.kind(),
@@ -624,6 +752,9 @@ mod tests {
624
752
  if step > 0 {
625
753
  assert!(repaired_leaf, "{context}: normal leaf must return");
626
754
  }
755
+ if owner_kind.is_some() {
756
+ assert_eq!(owners, 1, "{context}: operand must have one owner");
757
+ }
627
758
  }
628
759
  assert_eq!(
629
760
  incremental.root_node().to_sexp(),
package/common/grammar.js CHANGED
@@ -32,13 +32,13 @@ function lineOperand($, first, rest) {
32
32
  return prec.right(
33
33
  seq(
34
34
  choice(
35
- first,
35
+ namedExternal($, first, "file_literal"),
36
36
  issueField($, "nul_character"),
37
37
  issueField($, "invalid_encoding"),
38
38
  ),
39
39
  repeat(
40
40
  choice(
41
- rest,
41
+ namedExternal($, rest, "file_literal"),
42
42
  issueField($, "nul_character"),
43
43
  issueField($, "invalid_encoding"),
44
44
  ),
@@ -718,7 +718,7 @@ function functionRules() {
718
718
  prec.right(
719
719
  repeat1(
720
720
  choice(
721
- $._line_word,
721
+ namedExternal($, $._line_word, "label_literal"),
722
722
  issueField($, "nul_character"),
723
723
  issueField($, "invalid_encoding"),
724
724
  ),
@@ -746,7 +746,7 @@ function functionRules() {
746
746
  field("closing", $.closing_brace),
747
747
  issueField($, "missing_closing_brace"),
748
748
  ),
749
- optional($._blanks),
749
+ optional($._block_trailing_blanks),
750
750
  ],
751
751
  text: ($) => [
752
752
  choice(
@@ -935,6 +935,25 @@ function sedRules(mode) {
935
935
  };
936
936
  }
937
937
 
938
+ const missingCommandDefinitions = [
939
+ { reason: "missing_function", atBoundary: true },
940
+ { reason: "missing_label", atBoundary: true },
941
+ { reason: "missing_rfile", atBoundary: true },
942
+ { reason: "missing_wfile", atBoundary: true },
943
+ { reason: "missing_text_introducer", atBoundary: true },
944
+ {
945
+ reason: "incomplete_text_introducer",
946
+ rule: ($) => $._text_incomplete_introducer,
947
+ },
948
+ { reason: "missing_text" },
949
+ { reason: "missing_closing_brace" },
950
+ { reason: "missing_opening_delimiter", atBoundary: true },
951
+ ];
952
+
953
+ const boundaryMissingReasons = missingCommandDefinitions
954
+ .filter(({ atBoundary }) => atBoundary)
955
+ .map(({ reason }) => reason);
956
+
938
957
  function missingMarkerNames(mode) {
939
958
  return [
940
959
  "omitted_address",
@@ -956,12 +975,7 @@ function missingMarkerNames(mode) {
956
975
  "missing_opening_delimiter",
957
976
  "missing_separator_before_unmatched_brace",
958
977
  "missing_separator_after_unmatched_brace",
959
- "nonconforming_missing_function",
960
- "nonconforming_missing_label",
961
- "nonconforming_missing_rfile",
962
- "nonconforming_missing_wfile",
963
- "nonconforming_missing_text_introducer",
964
- "nonconforming_missing_opening_delimiter",
978
+ ...boundaryMissingReasons.map((reason) => `nonconforming_${reason}`),
965
979
  "missing_subexpression_placeholder",
966
980
  "incomplete_bracket_list",
967
981
  "incomplete_bracket_expression",
@@ -975,15 +989,6 @@ function issueDefinitions(mode) {
975
989
  return ($) => $[`_${reason}_marker`];
976
990
  }
977
991
 
978
- const boundaryMissingReasons = [
979
- "missing_function",
980
- "missing_label",
981
- "missing_rfile",
982
- "missing_wfile",
983
- "missing_text_introducer",
984
- "missing_opening_delimiter",
985
- ];
986
-
987
992
  return [
988
993
  {
989
994
  reason: "malformed_bracket_term",
@@ -1403,51 +1408,11 @@ function issueDefinitions(mode) {
1403
1408
  outcome: "nonconforming_syntax",
1404
1409
  rule: missing(`nonconforming_${reason}`),
1405
1410
  })),
1406
- {
1407
- reason: "missing_function",
1408
- outcome: "incomplete_syntax",
1409
- rule: missing("missing_function"),
1410
- },
1411
- {
1412
- reason: "missing_label",
1413
- outcome: "incomplete_syntax",
1414
- rule: missing("missing_label"),
1415
- },
1416
- {
1417
- reason: "missing_rfile",
1418
- outcome: "incomplete_syntax",
1419
- rule: missing("missing_rfile"),
1420
- },
1421
- {
1422
- reason: "missing_wfile",
1423
- outcome: "incomplete_syntax",
1424
- rule: missing("missing_wfile"),
1425
- },
1426
- {
1427
- reason: "missing_text_introducer",
1428
- outcome: "incomplete_syntax",
1429
- rule: missing("missing_text_introducer"),
1430
- },
1431
- {
1432
- reason: "incomplete_text_introducer",
1433
- outcome: "incomplete_syntax",
1434
- rule: ($) => $._text_incomplete_introducer,
1435
- },
1436
- {
1437
- reason: "missing_text",
1438
- outcome: "incomplete_syntax",
1439
- rule: missing("missing_text"),
1440
- },
1441
- {
1442
- reason: "missing_closing_brace",
1443
- outcome: "incomplete_syntax",
1444
- rule: missing("missing_closing_brace"),
1445
- },
1446
- {
1447
- reason: "missing_opening_delimiter",
1411
+ ...missingCommandDefinitions.map(({ reason, rule }) => ({
1412
+ reason,
1448
1413
  outcome: "incomplete_syntax",
1449
- rule: missing("missing_opening_delimiter"),
1450
- },
1414
+ rule: rule ?? missing(reason),
1415
+ })),
1451
1416
  {
1452
1417
  reason: "missing_subexpression",
1453
1418
  outcome: "incomplete_syntax",
@@ -1651,6 +1616,7 @@ function externalTokens($, mode) {
1651
1616
  $._line_word,
1652
1617
  $._argument_separator,
1653
1618
  $._right_brace,
1619
+ $._block_trailing_blanks,
1654
1620
  $._empty_command_marker,
1655
1621
  $._reserved_unknown_function_token,
1656
1622
  $._regex_incomplete_group,
package/common/regex.js CHANGED
@@ -316,6 +316,20 @@ function regularExpressionEscape($) {
316
316
  );
317
317
  }
318
318
 
319
+ function oneCharOrCollElem($, ...additional) {
320
+ return choice(
321
+ issueField($, "invalid_regular_expression_character"),
322
+ issueField($, "invalid_encoding"),
323
+ $.ordinary_character,
324
+ regularExpressionEscape($),
325
+ $.sed_newline_escape,
326
+ $.period,
327
+ $._bracket_expression,
328
+ issueField($, "special_delimiter_escape"),
329
+ ...additional,
330
+ );
331
+ }
332
+
319
333
  function commonRegularExpressionRules() {
320
334
  return {
321
335
  dup_count: ($) => $._regex_dup_count,
@@ -432,15 +446,8 @@ function breRules() {
432
446
  backreference: ($) => $._regex_backreference,
433
447
 
434
448
  one_char_or_coll_elem_bre: ($) =>
435
- choice(
436
- issueField($, "invalid_regular_expression_character"),
437
- issueField($, "invalid_encoding"),
438
- $.ordinary_character,
439
- regularExpressionEscape($),
440
- $.sed_newline_escape,
441
- $.period,
442
- $._bracket_expression,
443
- issueField($, "special_delimiter_escape"),
449
+ oneCharOrCollElem(
450
+ $,
444
451
  issueField($, "bre_vertical_line_escape"),
445
452
  issueField($, "bre_question_mark_escape"),
446
453
  issueField($, "bre_plus_escape"),
@@ -524,17 +531,7 @@ function ereRules() {
524
531
  field("operator", issueNode($, "leading_duplication_symbol")),
525
532
  ),
526
533
 
527
- one_char_or_coll_elem_ere: ($) =>
528
- choice(
529
- issueField($, "invalid_regular_expression_character"),
530
- issueField($, "invalid_encoding"),
531
- $.ordinary_character,
532
- regularExpressionEscape($),
533
- $.sed_newline_escape,
534
- $.period,
535
- $._bracket_expression,
536
- issueField($, "special_delimiter_escape"),
537
- ),
534
+ one_char_or_coll_elem_ere: ($) => oneCharOrCollElem($),
538
535
 
539
536
  ere_dupl_symbol: ($) =>
540
537
  seq(