@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.
- package/main.js +1 -3
- package/package.json +3 -3
- package/src/compiler/compile.js +2 -10
- package/src/compiler/optimize.js +93 -147
- package/src/compiler/origami.pegjs +67 -171
- package/src/compiler/parse.js +946 -1810
- package/src/compiler/parserHelpers.js +58 -159
- package/src/runtime/HandleExtensionsTransform.js +1 -10
- package/src/runtime/evaluate.js +35 -28
- package/src/runtime/expressionObject.js +4 -4
- package/src/runtime/handlers.js +54 -18
- package/src/runtime/mergeTrees.js +5 -0
- package/src/runtime/ops.js +156 -101
- package/src/runtime/symbols.js +0 -1
- package/src/runtime/{templateIndent.js → taggedTemplateIndent.js} +2 -2
- package/test/compiler/codeHelpers.js +1 -3
- package/test/compiler/compile.test.js +27 -52
- package/test/compiler/optimize.test.js +23 -92
- package/test/compiler/parse.test.js +342 -574
- package/test/runtime/evaluate.test.js +20 -4
- package/test/runtime/expressionObject.test.js +4 -5
- package/test/runtime/handlers.test.js +10 -19
- package/test/runtime/mergeTrees.test.js +5 -0
- package/test/runtime/ops.test.js +82 -103
- package/test/runtime/taggedTemplateIndent.test.js +1 -1
- package/src/runtime/getHandlers.js +0 -10
- package/src/runtime/jsGlobals.js +0 -99
- package/src/runtime/templateStandard.js +0 -13
- package/test/runtime/templateText.test.js +0 -18
|
@@ -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:(
|
|
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
|
-
/
|
|
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(
|
|
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([
|
|
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
|
|
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
|
-
=
|
|
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
|
-
=
|
|
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
|
-
|
|
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:(
|
|
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([
|
|
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
|
|
533
|
-
return annotate([key,
|
|
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
|
-
|
|
546
|
-
|
|
489
|
+
return identifier + (slash ?? "");
|
|
490
|
+
}
|
|
547
491
|
/ string:stringLiteral {
|
|
548
|
-
|
|
549
|
-
|
|
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
|
-
=
|
|
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([
|
|
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(
|
|
559
|
+
tail.reduce(makePipeline, downgradeReference(head)),
|
|
622
560
|
location()
|
|
623
561
|
);
|
|
624
562
|
}
|
|
625
563
|
|
|
626
564
|
primary
|
|
627
|
-
=
|
|
628
|
-
/ stringLiteral
|
|
565
|
+
= literal
|
|
629
566
|
/ arrayLiteral
|
|
630
567
|
/ objectLiteral
|
|
631
568
|
/ group
|
|
632
569
|
/ templateLiteral
|
|
633
|
-
/
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
708
|
-
return annotate([markers.reference, idCode], location());
|
|
615
|
+
return annotate(makeReference(id), location());
|
|
709
616
|
}
|
|
710
617
|
|
|
711
618
|
separator
|
|
712
619
|
= __ "," __
|
|
713
|
-
/
|
|
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
|
-
=
|
|
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:
|
|
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
|
-
/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
807
|
-
|
|
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
|
-
|
|
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
|
-
|
|
850
|
-
|
|
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 __
|