@weborigami/language 0.3.3-jse.3 → 0.3.3

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.
@@ -20,15 +20,14 @@ import {
20
20
  makeBinaryOperation,
21
21
  makeCall,
22
22
  makeDeferredArguments,
23
- makeDocument,
24
23
  makeJsPropertyAccess,
25
24
  makeObject,
26
25
  makePipeline,
27
26
  makeProperty,
27
+ makeReference,
28
28
  makeTemplate,
29
29
  makeUnaryOperation,
30
- makeYamlObject,
31
- markers,
30
+ makeYamlObject
32
31
  } from "./parserHelpers.js";
33
32
  import isOrigamiFrontMatter from "./isOrigamiFrontMatter.js";
34
33
 
@@ -41,7 +40,7 @@ __
41
40
  }
42
41
 
43
42
  additiveExpression
44
- = head:multiplicativeExpression tail:(whitespaceShell @additiveOperator whitespaceShell @multiplicativeExpression)* {
43
+ = head:multiplicativeExpression tail:(whitespace @additiveOperator whitespace @multiplicativeExpression)* {
45
44
  return tail.reduce(makeBinaryOperation, head);
46
45
  }
47
46
 
@@ -49,50 +48,11 @@ additiveOperator
49
48
  = "+"
50
49
  / "-"
51
50
 
52
- angleBracketLiteral
53
- = "<" __ protocol:angleBracketProtocol "//"? path:angleBracketPath __ ">" {
54
- return annotate([protocol, ...path], location());
55
- }
56
- / "<" __ "/" path:angleBracketPath __ ">" {
57
- const root = annotate([ops.rootDirectory], location());
58
- return path.length > 0 ? annotate([root, ...path], location()) : root;
59
- }
60
- / "<" __ "~" "/"? path:angleBracketPath __ ">" {
61
- const home = annotate([ops.homeDirectory], location());
62
- return path.length > 0 ? annotate([home, ...path], location()) : home;
63
- }
64
- / "<" __ path:angleBracketPath __ ">" {
65
- // Angle bracket paths always reference scope
66
- const scope = annotate([ops.scope], location());
67
- return annotate([scope, ...path], location());
68
- }
69
-
70
- angleBracketPath
71
- = @angleBracketPathKey|0.., "/"| "/"?
72
-
73
- angleBracketPathKey
74
- = chars:angleBracketPathChar+ slashFollows:slashFollows? {
75
- // Append a trailing slash if one follows (but don't consume it)
76
- const key = chars.join("") + (slashFollows ? "/" : "");
77
- return annotate([ops.literal, key], location());
78
- }
79
-
80
- // A single character in a slash-separated path segment
81
- angleBracketPathChar
82
- = [^/:<>] // Much more permissive than an identifier
83
- / escapedChar
84
-
85
- angleBracketProtocol
86
- = protocol:jsIdentifier ":" {
87
- return annotate([markers.global, `${protocol[1]}:`], location());
88
- }
89
-
90
51
  arguments "function arguments"
91
52
  = parenthesesArguments
92
- / shellMode @pathArguments
53
+ / pathArguments
93
54
  / jsPropertyAccess
94
55
  / computedPropertyAccess
95
- / optionalChaining
96
56
  / templateLiteral
97
57
 
98
58
  arrayLiteral "array"
@@ -152,7 +112,7 @@ bitwiseXorOperator
152
112
  // `fn(arg1)(arg2)(arg3)`.
153
113
  callExpression "function call"
154
114
  = head:protocolExpression tail:arguments* {
155
- return tail.reduce((target, args) => makeCall(target, args, options.mode), head);
115
+ return tail.reduce(makeCall, head);
156
116
  }
157
117
 
158
118
  // A comma-separated list of expressions: `x, y, z`
@@ -171,7 +131,7 @@ comment "comment"
171
131
 
172
132
  computedPropertyAccess
173
133
  = __ "[" expression:expression expectClosingBracket {
174
- return annotate([markers.traverse, expression], location());
134
+ return annotate([ops.traverse, expression], location());
175
135
  }
176
136
 
177
137
  conditionalExpression
@@ -364,16 +324,23 @@ identifierChar
364
324
 
365
325
  implicitParenthesesCallExpression "function call with implicit parentheses"
366
326
  = head:arrowFunction args:(inlineSpace+ @implicitParensthesesArguments)? {
367
- return args ? makeCall(head, args, options.mode) : head;
327
+ return args ? makeCall(head, args) : head;
368
328
  }
369
329
 
370
330
  // A separated list of values for an implicit parens call. This differs from
371
331
  // `list` in that the value term can't be a pipeline.
372
332
  implicitParensthesesArguments
373
- = shellMode values:shorthandFunction|1.., separator| separator? {
333
+ = values:shorthandFunction|1.., separator| separator? {
374
334
  return annotate(values, location());
375
335
  }
376
336
 
337
+ inherited
338
+ = rootDirectory
339
+ / homeDirectory
340
+ / qualifiedReference
341
+ / namespace
342
+ / scopeReference
343
+
377
344
  inlineSpace
378
345
  = [ \t]
379
346
 
@@ -382,13 +349,8 @@ integerLiteral "integer"
382
349
  return annotate([ops.literal, parseInt(text())], location());
383
350
  }
384
351
 
385
- jseMode
386
- = &{ return options.mode === "jse" }
387
-
388
352
  jsIdentifier
389
- = id:$( jsIdentifierStart jsIdentifierPart* ) {
390
- return annotate([ops.literal, id], location());
391
- }
353
+ = $( jsIdentifierStart jsIdentifierPart* )
392
354
 
393
355
  // Continuation of a JavaScript identifier
394
356
  // https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#prod-IdentifierPart
@@ -402,20 +364,20 @@ jsIdentifierStart "JavaScript identifier start"
402
364
 
403
365
  jsPropertyAccess
404
366
  = __ "." __ property:jsIdentifier {
405
- return annotate([markers.traverse, property], location());
367
+ const literal = annotate([ops.literal, property], location());
368
+ return annotate([ops.traverse, literal], location());
406
369
  }
407
370
 
408
- jsReference "identifier reference"
409
- = id:jsIdentifier {
410
- return annotate([markers.reference, id], location());
411
- }
412
-
413
371
  // A separated list of values
414
372
  list "list"
415
373
  = values:pipelineExpression|1.., separator| separator? {
416
374
  return annotate(values, location());
417
375
  }
418
376
 
377
+ literal
378
+ = numericLiteral
379
+ / stringLiteral
380
+
419
381
  logicalAndExpression
420
382
  = head:bitwiseOrExpression tail:(__ "&&" __ @bitwiseOrExpression)* {
421
383
  return tail.length === 0
@@ -440,7 +402,7 @@ multiLineComment
440
402
  = "/*" (!"*/" .)* "*/" { return null; }
441
403
 
442
404
  multiplicativeExpression
443
- = head:exponentiationExpression tail:(whitespaceShell @multiplicativeOperator whitespaceShell @exponentiationExpression)* {
405
+ = head:exponentiationExpression tail:(whitespace @multiplicativeOperator whitespace @exponentiationExpression)* {
444
406
  return tail.reduce(makeBinaryOperation, head);
445
407
  }
446
408
 
@@ -452,20 +414,9 @@ multiplicativeOperator
452
414
  // A namespace reference is a string of letters only, followed by a colon.
453
415
  namespace
454
416
  = chars:[A-Za-z]+ ":" {
455
- return annotate([markers.global, chars.join("") + ":"], location());
417
+ return annotate([ops.builtin, chars.join("") + ":"], location());
456
418
  }
457
419
 
458
- // A new expression: `new Foo()`
459
- newExpression
460
- = "new" __ head:jsReference tail:parenthesesArguments {
461
- const args = tail?.[0] !== undefined ? tail : [];
462
- return annotate([ops.construct, head, ...args], location());
463
- }
464
- / "new:" head:jsReference tail:parenthesesArguments {
465
- const args = tail?.[0] !== undefined ? tail : [];
466
- return annotate([ops.construct, head, ...args], location());
467
- }
468
-
469
420
  newLine
470
421
  = "\n"
471
422
  / "\r\n"
@@ -529,34 +480,21 @@ objectProperty "object property"
529
480
  // A shorthand reference inside an object literal: `foo`
530
481
  objectShorthandProperty "object identifier"
531
482
  = key:objectPublicKey {
532
- const reference = annotate([markers.reference, key], location());
533
- return annotate([key, reference], location());
483
+ const inherited = annotate([ops.inherited, key], location());
484
+ return annotate([key, inherited], location());
534
485
  }
535
- / jseMode path:angleBracketLiteral {
536
- let lastKey = path.at(-1);
537
- if (lastKey instanceof Array) {
538
- lastKey = lastKey[1]; // get scope identifier or literal
539
- }
540
- return annotate([lastKey, path], location());
541
- }
542
486
 
543
487
  objectPublicKey
544
488
  = identifier:identifier slash:"/"? {
545
- return identifier + (slash ?? "");
546
- }
489
+ return identifier + (slash ?? "");
490
+ }
547
491
  / string:stringLiteral {
548
- // Remove `ops.literal` from the string code
549
- return string[1];
550
- }
551
-
552
- optionalChaining
553
- = __ "?." __ property:jsIdentifier {
554
- return annotate([ops.optionalTraverse, property], location());
492
+ // Remove `ops.literal` from the string code
493
+ return string[1];
555
494
  }
556
-
495
+
557
496
  parameter
558
- = jseMode @jsIdentifier
559
- / shellMode identifier:identifier {
497
+ = identifier:identifier {
560
498
  return annotate([ops.literal, identifier], location());
561
499
  }
562
500
 
@@ -592,7 +530,7 @@ path "slash-separated path"
592
530
  // A slash-separated path of keys that follows a call target
593
531
  pathArguments
594
532
  = path:path {
595
- return annotate([markers.traverse, ...path], location());
533
+ return annotate([ops.traverse, ...path], location());
596
534
  }
597
535
 
598
536
  // A single key in a slash-separated path: `/a`
@@ -618,33 +556,18 @@ pathSegmentChar
618
556
  pipelineExpression
619
557
  = head:shorthandFunction tail:(__ singleArrow __ @shorthandFunction)* {
620
558
  return annotate(
621
- tail.reduce((arg, fn) => makePipeline(arg, fn, options.mode), downgradeReference(head)),
559
+ tail.reduce(makePipeline, downgradeReference(head)),
622
560
  location()
623
561
  );
624
562
  }
625
563
 
626
564
  primary
627
- = numericLiteral
628
- / stringLiteral
565
+ = literal
629
566
  / arrayLiteral
630
567
  / objectLiteral
631
568
  / group
632
569
  / templateLiteral
633
- / shellMode @primaryShell
634
- / jseMode @primaryJse
635
-
636
- // Primary allowed in JSE mode
637
- primaryJse
638
- = angleBracketLiteral
639
- / jsReference
640
- / regexLiteral
641
-
642
- primaryShell
643
- = rootDirectory
644
- / homeDirectory
645
- / qualifiedReference
646
- / namespace
647
- / scopeReference
570
+ / inherited
648
571
 
649
572
  // Top-level Origami progam with possible shebang directive (which is ignored)
650
573
  program "Origami program"
@@ -654,38 +577,19 @@ program "Origami program"
654
577
  protocolExpression
655
578
  = fn:namespace "//" host:(host / slash) path:path? {
656
579
  const keys = annotate([host, ...(path ?? [])], location());
657
- return makeCall(fn, keys, options.mode);
580
+ return makeCall(fn, keys);
658
581
  }
659
- / newExpression
660
582
  / primary
661
583
 
662
584
  // A namespace followed by a key: `foo:x`
663
585
  qualifiedReference
664
586
  = fn:namespace reference:scopeReference {
665
- return makeCall(fn, [reference[1]], options.mode);
666
- }
667
-
668
- regexFlags
669
- = flags:[gimuy]* {
670
- return flags.join("");
671
- }
672
-
673
- regexLiteral
674
- = "/" chars:regexLiteralChar* "/" flags:regexFlags? {
675
- const regex = new RegExp(chars.join(""), flags);
676
- return annotate([ops.literal, regex], location());
587
+ const literal = annotate([ops.literal, reference[1]], reference.location);
588
+ return makeCall(fn, [literal]);
677
589
  }
678
590
 
679
- regexLiteralChar
680
- = [^/\n\r] // No unescaped slashes or newlines
681
- / escapedChar
682
-
683
591
  relationalExpression
684
- // We disallow a newline before the relational operator to support a newline
685
- // as a separator in an object literal that has an object shorthand property
686
- // with an angle bracket path. Otherwise the opening angle bracket would be
687
- // interpreted as a relational operator.
688
- = head:shiftExpression tail:(inlineSpace @relationalOperator __ @shiftExpression)* {
592
+ = head:shiftExpression tail:(__ @relationalOperator __ @shiftExpression)* {
689
593
  return tail.reduce(makeBinaryOperation, head);
690
594
  }
691
595
 
@@ -695,29 +599,29 @@ relationalOperator
695
599
  / ">="
696
600
  / ">"
697
601
 
698
- // The root folder: `/`
602
+ // A top-level folder below the root: `/foo`
603
+ // or the root folder itself: `/`
699
604
  rootDirectory
700
- = &("/" !"/") {
605
+ = "/" key:pathKey {
606
+ return annotate([ops.rootDirectory, key], location());
607
+ }
608
+ / "/" !"/" {
701
609
  return annotate([ops.rootDirectory], location());
702
610
  }
703
611
 
704
612
  scopeReference "scope reference"
705
613
  = identifier:identifier slashFollows:slashFollows? {
706
614
  const id = identifier + (slashFollows ? "/" : "");
707
- const idCode = annotate([ops.literal, identifier], location());
708
- return annotate([markers.reference, idCode], location());
615
+ return annotate(makeReference(id), location());
709
616
  }
710
617
 
711
618
  separator
712
619
  = __ "," __
713
- / @whitespaceWithNewLine
620
+ / whitespaceWithNewLine
714
621
 
715
622
  shebang
716
623
  = "#!" [^\n\r]* { return null; }
717
624
 
718
- shellMode
719
- = &{ return options.mode === "shell" }
720
-
721
625
  shiftExpression
722
626
  = head:additiveExpression tail:(__ @shiftOperator __ @additiveExpression)* {
723
627
  return tail.reduce(makeBinaryOperation, head);
@@ -731,7 +635,7 @@ shiftOperator
731
635
  // A shorthand lambda expression: `=foo(_)`
732
636
  shorthandFunction "lambda function"
733
637
  // Avoid a following equal sign (for an equality)
734
- = shellMode "=" !"=" __ definition:implicitParenthesesCallExpression {
638
+ = "=" !"=" __ definition:implicitParenthesesCallExpression {
735
639
  const lambdaParameters = annotate(
736
640
  [annotate([ops.literal, "_"], location())],
737
641
  location()
@@ -769,20 +673,27 @@ slashFollows
769
673
  }
770
674
 
771
675
  spreadElement
772
- = ellipsis __ value:expectPipelineExpression {
676
+ = ellipsis __ value:pipelineExpression {
773
677
  return annotate([ops.spread, value], location());
774
678
  }
775
679
 
776
680
  stringLiteral "string"
777
681
  = doubleQuoteString
778
682
  / singleQuoteString
779
- / shellMode @guillemetString
683
+ / guillemetString
780
684
 
781
685
  // The body of a template document is a kind of template literal that can
782
686
  // contain backticks at the top level.
783
687
  templateBody "template"
784
688
  = head:templateBodyText tail:(templateSubstitution templateBodyText)* {
785
- return makeTemplate(ops.templateIndent, head, tail, location());
689
+ const lambdaParameters = annotate(
690
+ [annotate([ops.literal, "_"], location())],
691
+ location()
692
+ );
693
+ return annotate(
694
+ [ops.lambda, lambdaParameters, makeTemplate(ops.templateIndent, head, tail, location())],
695
+ location()
696
+ );
786
697
  }
787
698
 
788
699
  // Template document bodies can contain backticks at the top level
@@ -796,25 +707,18 @@ templateBodyText "template text"
796
707
 
797
708
  templateDocument "template document"
798
709
  = front:frontMatterExpression __ body:templateBody {
799
- const macroName = options.mode === "jse" ? "_template" : "@template";
800
- return annotate(applyMacro(front, macroName, body), location());
801
- }
802
- / front:frontMatterYaml body:templateBody {
803
- return makeDocument(options.mode, front, body, location());
710
+ return annotate(applyMacro(front, "@template", body), location());
804
711
  }
805
- / body:templateBody {
806
- const lambdaParameters = annotate(
807
- [annotate([ops.literal, "_"], location())],
808
- location()
809
- );
810
- return annotate([ops.lambda, lambdaParameters, body], location());
712
+ / front:frontMatterYaml? body:templateBody {
713
+ return front
714
+ ? annotate([ops.document, front, body], location())
715
+ : annotate(body, location());
811
716
  }
812
717
 
813
718
  // A backtick-quoted template literal
814
719
  templateLiteral "template literal"
815
720
  = "`" head:templateLiteralText tail:(templateSubstitution templateLiteralText)* expectBacktick {
816
- const op = options.mode === "jse" ? ops.templateStandard : ops.templateTree;
817
- return makeTemplate(op, head, tail, location());
721
+ return makeTemplate(ops.template, head, tail, location());
818
722
  }
819
723
 
820
724
  templateLiteralChar
@@ -846,21 +750,13 @@ unaryExpression
846
750
  unaryOperator
847
751
  = "!"
848
752
  / "+"
849
- // Don't match a front matter delimiter. For some reason, the negative
850
- // lookahead !"--\n" doesn't work.
851
- / @"-" !"-\n"
852
- // Don't match a path that starts with a tilde: ~/foo
853
- / @"~" !"/"
753
+ / "-"
754
+ / "~"
854
755
 
855
756
  whitespace
856
757
  = inlineSpace
857
758
  / newLine
858
759
  / comment
859
760
 
860
- // Whitespace required in shell mode, optional in JSE mode
861
- whitespaceShell
862
- = shellMode whitespace
863
- / jseMode __
864
-
865
761
  whitespaceWithNewLine
866
762
  = inlineSpace* comment? newLine __