yukigo-mini-parser 0.1.0 → 0.1.2
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/.mocharc.json +7 -7
- package/CHANGELOG.md +6 -0
- package/dist/grammar.js +11 -15
- package/dist/grammar.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/parse.js +11 -11
- package/dist/src/grammar.d.ts +28 -0
- package/dist/src/grammar.js +100 -0
- package/dist/src/grammar.js.map +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.js +33 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lexer.d.ts +38 -0
- package/dist/src/lexer.js +46 -0
- package/dist/src/lexer.js.map +1 -0
- package/dist/src/parse.d.ts +1 -0
- package/dist/src/parse.js +16 -0
- package/dist/src/parse.js.map +1 -0
- package/package.json +2 -2
- package/src/grammar.ne +131 -126
- package/src/grammar.ts +10 -14
- package/src/index.ts +39 -24
- package/src/lexer.ts +49 -49
- package/src/parse.ts +17 -17
- package/tests/parser.spec.ts +158 -158
- package/tsconfig.json +24 -17
- package/tutorial.md +752 -752
package/src/grammar.ne
CHANGED
|
@@ -1,127 +1,132 @@
|
|
|
1
|
-
@{%
|
|
2
|
-
import { MiniLexer } from "./lexer.js"
|
|
3
|
-
import {
|
|
4
|
-
SimpleType,
|
|
5
|
-
Assignment,
|
|
6
|
-
Variable,
|
|
7
|
-
ListPrimitive,
|
|
8
|
-
ListType,
|
|
9
|
-
ArithmeticBinaryOperation,
|
|
10
|
-
SymbolPrimitive,
|
|
11
|
-
NumberPrimitive,
|
|
12
|
-
ComparisonOperation,
|
|
13
|
-
BooleanPrimitive,
|
|
14
|
-
StringPrimitive,
|
|
15
|
-
ParameterizedType,
|
|
16
|
-
Sequence,
|
|
17
|
-
UnguardedBody,
|
|
18
|
-
If,
|
|
19
|
-
While,
|
|
20
|
-
VariablePattern,
|
|
21
|
-
Equation,
|
|
22
|
-
Procedure,
|
|
23
|
-
TypeSignature,
|
|
24
|
-
CharPrimitive,
|
|
25
|
-
NilPrimitive,
|
|
26
|
-
Return
|
|
27
|
-
} from "yukigo-ast"
|
|
28
|
-
%}
|
|
29
|
-
|
|
30
|
-
@preprocessor typescript
|
|
31
|
-
@lexer MiniLexer
|
|
32
|
-
|
|
33
|
-
program ->
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
1
|
+
@{%
|
|
2
|
+
import { MiniLexer } from "./lexer.js"
|
|
3
|
+
import {
|
|
4
|
+
SimpleType,
|
|
5
|
+
Assignment,
|
|
6
|
+
Variable,
|
|
7
|
+
ListPrimitive,
|
|
8
|
+
ListType,
|
|
9
|
+
ArithmeticBinaryOperation,
|
|
10
|
+
SymbolPrimitive,
|
|
11
|
+
NumberPrimitive,
|
|
12
|
+
ComparisonOperation,
|
|
13
|
+
BooleanPrimitive,
|
|
14
|
+
StringPrimitive,
|
|
15
|
+
ParameterizedType,
|
|
16
|
+
Sequence,
|
|
17
|
+
UnguardedBody,
|
|
18
|
+
If,
|
|
19
|
+
While,
|
|
20
|
+
VariablePattern,
|
|
21
|
+
Equation,
|
|
22
|
+
Procedure,
|
|
23
|
+
TypeSignature,
|
|
24
|
+
CharPrimitive,
|
|
25
|
+
NilPrimitive,
|
|
26
|
+
Return
|
|
27
|
+
} from "yukigo-ast"
|
|
28
|
+
%}
|
|
29
|
+
|
|
30
|
+
@preprocessor typescript
|
|
31
|
+
@lexer MiniLexer
|
|
32
|
+
|
|
33
|
+
program -> _ statements _ %EOF {% (d) => d[1].flat(Infinity) %}
|
|
34
|
+
|
|
35
|
+
statements ->
|
|
36
|
+
statement {% (d) => [d[0]] %}
|
|
37
|
+
| statements _ statement {% (d) => [...d[0], d[2]] %}
|
|
38
|
+
|
|
39
|
+
# Statements
|
|
40
|
+
|
|
41
|
+
statement -> (assignment | variable_statement | function_statement | return_statement | if_statement | while_statement) _ ";" {% (d) => d[0][0] %}
|
|
42
|
+
|
|
43
|
+
variable_statement -> type __ variable (_ ":=" _ expression):? {% (d) => new Variable(d[2], d[3] ? d[3][3] : new NilPrimitive(null), d[0]) %}
|
|
44
|
+
|
|
45
|
+
return_statement -> "return" _ expression {% (d) => new Return(d[2]) %}
|
|
46
|
+
|
|
47
|
+
while_statement -> "while" _ condition _ statement_list {% d => new While(d[2], d[4]) %}
|
|
48
|
+
|
|
49
|
+
if_statement -> "if" _ condition _ statement_list _ "else" _ statement_list {% d => new If(d[2], d[4], d[8]) %}
|
|
50
|
+
|
|
51
|
+
condition -> "(" _ expression _ ")" {% (d) => d[2] %}
|
|
52
|
+
|
|
53
|
+
statement_list -> "{" _ body _ "}" {% d => d[2] %}
|
|
54
|
+
body ->
|
|
55
|
+
statements {% (d) => new Sequence(d[0].flat(Infinity)) %}
|
|
56
|
+
| null {% () => new Sequence([]) %}
|
|
57
|
+
|
|
58
|
+
assignment -> variable _ ":=" _ expression {% (d) => new Assignment(d[0], d[4]) %}
|
|
59
|
+
|
|
60
|
+
## Function rules
|
|
61
|
+
|
|
62
|
+
function_statement -> type __ variable ("(" _ param_list:? _ ")" _ statement_list) {% (d) => {
|
|
63
|
+
const paramTypeList = []
|
|
64
|
+
const patternList = []
|
|
65
|
+
if(d[3][2]) {
|
|
66
|
+
for(const [paramType, paramPattern] of d[3][2]) {
|
|
67
|
+
paramTypeList.push(paramType);
|
|
68
|
+
patternList.push(paramPattern);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const signatureType = new ParameterizedType(paramTypeList, d[0], [])
|
|
72
|
+
|
|
73
|
+
const signature = new TypeSignature(d[2], signatureType);
|
|
74
|
+
const procedure = new Procedure(d[2], [new Equation(patternList, new UnguardedBody(d[3][6]))])
|
|
75
|
+
return [signature, procedure]
|
|
76
|
+
}%}
|
|
77
|
+
|
|
78
|
+
param_list -> param (_ "," _ param):* {% d => [d[0], ...d[1].map(x => x[3])] %}
|
|
79
|
+
|
|
80
|
+
param -> type __ variable {% d => [d[0], new VariablePattern(d[2])] %}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Expressions
|
|
84
|
+
|
|
85
|
+
expression -> comparison {% (d) => d[0] %}
|
|
86
|
+
|
|
87
|
+
comparison ->
|
|
88
|
+
addition _ comparison_operator _ addition {% (d) => new ComparisonOperation(d[2], d[0], d[4]) %}
|
|
89
|
+
| addition {% (d) => d[0] %}
|
|
90
|
+
|
|
91
|
+
addition ->
|
|
92
|
+
addition _ "+" _ multiplication {% (d) => new ArithmeticBinaryOperation("Plus", d[0], d[4]) %}
|
|
93
|
+
| addition _ "-" _ multiplication {% (d) => new ArithmeticBinaryOperation("Minus", d[0], d[4]) %}
|
|
94
|
+
| multiplication {% (d) => d[0] %}
|
|
95
|
+
|
|
96
|
+
multiplication ->
|
|
97
|
+
multiplication _ "*" _ primary {% (d) => new ArithmeticBinaryOperation("Multiply", d[0], d[4]) %}
|
|
98
|
+
| multiplication _ "/" _ primary {% (d) => new ArithmeticBinaryOperation("Divide", d[0], d[4]) %}
|
|
99
|
+
| primary {% (d) => d[0] %}
|
|
100
|
+
|
|
101
|
+
primary ->
|
|
102
|
+
"(" _ expression _ ")" {% (d) => d[2] %}
|
|
103
|
+
| primitive {% (d) => d[0] %}
|
|
104
|
+
|
|
105
|
+
primitive ->
|
|
106
|
+
%number {% (d) => new NumberPrimitive(Number(d[0].value)) %}
|
|
107
|
+
| %char {% (d) => new CharPrimitive(d[0].value) %}
|
|
108
|
+
| %string {% (d) => new StringPrimitive(d[0].value) %}
|
|
109
|
+
| %bool {% (d) => new BooleanPrimitive(d[0].value) %}
|
|
110
|
+
| variable {% (d) => d[0] %}
|
|
111
|
+
| list_primitive {% d => d[0] %}
|
|
112
|
+
|
|
113
|
+
type ->
|
|
114
|
+
variable {% (d) => new SimpleType(d[0].value, []) %}
|
|
115
|
+
| type "[" "]" {% (d) => new ListType(d[0], []) %}
|
|
116
|
+
|
|
117
|
+
list_primitive -> "[" _ expression_list _ "]" {% (d) => new ListPrimitive(d[2]) %}
|
|
118
|
+
|
|
119
|
+
expression_list -> expression _ ("," _ expression):* {% (d) => ([d[0], ...d[2].map(x => x[2])]) %}
|
|
120
|
+
|
|
121
|
+
variable -> %variable {% (d) => new SymbolPrimitive(d[0].value) %}
|
|
122
|
+
|
|
123
|
+
comparison_operator ->
|
|
124
|
+
%equal {% d => "Equal" %}
|
|
125
|
+
| %notEqual {% d => "NotEqual" %}
|
|
126
|
+
| %lt {% d => "LessThan" %}
|
|
127
|
+
| %lte {% d => "LessOrEqualThan" %}
|
|
128
|
+
| %gt {% d => "GreaterThan" %}
|
|
129
|
+
| %gte {% d => "GreaterOrEqualThan" %}
|
|
130
|
+
|
|
131
|
+
_ -> %WS:* {% d => null %}
|
|
127
132
|
__ -> %WS:+ {% d => null %}
|
package/src/grammar.ts
CHANGED
|
@@ -74,16 +74,16 @@ interface Grammar {
|
|
|
74
74
|
const grammar: Grammar = {
|
|
75
75
|
Lexer: MiniLexer,
|
|
76
76
|
ParserRules: [
|
|
77
|
-
{"name": "program
|
|
78
|
-
{"name": "
|
|
79
|
-
{"name": "
|
|
77
|
+
{"name": "program", "symbols": ["_", "statements", "_", (MiniLexer.has("EOF") ? {type: "EOF"} : EOF)], "postprocess": (d) => d[1].flat(Infinity)},
|
|
78
|
+
{"name": "statements", "symbols": ["statement"], "postprocess": (d) => [d[0]]},
|
|
79
|
+
{"name": "statements", "symbols": ["statements", "_", "statement"], "postprocess": (d) => [...d[0], d[2]]},
|
|
80
80
|
{"name": "statement$subexpression$1", "symbols": ["assignment"]},
|
|
81
81
|
{"name": "statement$subexpression$1", "symbols": ["variable_statement"]},
|
|
82
82
|
{"name": "statement$subexpression$1", "symbols": ["function_statement"]},
|
|
83
83
|
{"name": "statement$subexpression$1", "symbols": ["return_statement"]},
|
|
84
84
|
{"name": "statement$subexpression$1", "symbols": ["if_statement"]},
|
|
85
85
|
{"name": "statement$subexpression$1", "symbols": ["while_statement"]},
|
|
86
|
-
{"name": "statement", "symbols": ["statement$subexpression$1", "_", {"literal":";"}
|
|
86
|
+
{"name": "statement", "symbols": ["statement$subexpression$1", "_", {"literal":";"}], "postprocess": (d) => d[0][0]},
|
|
87
87
|
{"name": "variable_statement$ebnf$1$subexpression$1", "symbols": ["_", {"literal":":="}, "_", "expression"]},
|
|
88
88
|
{"name": "variable_statement$ebnf$1", "symbols": ["variable_statement$ebnf$1$subexpression$1"], "postprocess": id},
|
|
89
89
|
{"name": "variable_statement$ebnf$1", "symbols": [], "postprocess": () => null},
|
|
@@ -92,13 +92,13 @@ const grammar: Grammar = {
|
|
|
92
92
|
{"name": "while_statement", "symbols": [{"literal":"while"}, "_", "condition", "_", "statement_list"], "postprocess": d => new While(d[2], d[4])},
|
|
93
93
|
{"name": "if_statement", "symbols": [{"literal":"if"}, "_", "condition", "_", "statement_list", "_", {"literal":"else"}, "_", "statement_list"], "postprocess": d => new If(d[2], d[4], d[8])},
|
|
94
94
|
{"name": "condition", "symbols": [{"literal":"("}, "_", "expression", "_", {"literal":")"}], "postprocess": (d) => d[2]},
|
|
95
|
-
{"name": "statement_list
|
|
96
|
-
{"name": "
|
|
97
|
-
{"name": "
|
|
95
|
+
{"name": "statement_list", "symbols": [{"literal":"{"}, "_", "body", "_", {"literal":"}"}], "postprocess": d => d[2]},
|
|
96
|
+
{"name": "body", "symbols": ["statements"], "postprocess": (d) => new Sequence(d[0].flat(Infinity))},
|
|
97
|
+
{"name": "body", "symbols": [], "postprocess": () => new Sequence([])},
|
|
98
98
|
{"name": "assignment", "symbols": ["variable", "_", {"literal":":="}, "_", "expression"], "postprocess": (d) => new Assignment(d[0], d[4])},
|
|
99
99
|
{"name": "function_statement$subexpression$1$ebnf$1", "symbols": ["param_list"], "postprocess": id},
|
|
100
100
|
{"name": "function_statement$subexpression$1$ebnf$1", "symbols": [], "postprocess": () => null},
|
|
101
|
-
{"name": "function_statement$subexpression$1", "symbols": [{"literal":"("}, "_", "function_statement$subexpression$1$ebnf$1", "_", {"literal":")"}, "_",
|
|
101
|
+
{"name": "function_statement$subexpression$1", "symbols": [{"literal":"("}, "_", "function_statement$subexpression$1$ebnf$1", "_", {"literal":")"}, "_", "statement_list"]},
|
|
102
102
|
{"name": "function_statement", "symbols": ["type", "__", "variable", "function_statement$subexpression$1"], "postprocess": (d) => {
|
|
103
103
|
const paramTypeList = []
|
|
104
104
|
const patternList = []
|
|
@@ -111,7 +111,7 @@ const grammar: Grammar = {
|
|
|
111
111
|
const signatureType = new ParameterizedType(paramTypeList, d[0], [])
|
|
112
112
|
|
|
113
113
|
const signature = new TypeSignature(d[2], signatureType);
|
|
114
|
-
const procedure = new Procedure(d[2], [new Equation(patternList, d[3][
|
|
114
|
+
const procedure = new Procedure(d[2], [new Equation(patternList, new UnguardedBody(d[3][6]))])
|
|
115
115
|
return [signature, procedure]
|
|
116
116
|
}},
|
|
117
117
|
{"name": "param_list$ebnf$1", "symbols": []},
|
|
@@ -119,9 +119,6 @@ const grammar: Grammar = {
|
|
|
119
119
|
{"name": "param_list$ebnf$1", "symbols": ["param_list$ebnf$1", "param_list$ebnf$1$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])},
|
|
120
120
|
{"name": "param_list", "symbols": ["param", "param_list$ebnf$1"], "postprocess": d => [d[0], ...d[1].map(x => x[3])]},
|
|
121
121
|
{"name": "param", "symbols": ["type", "__", "variable"], "postprocess": d => [d[0], new VariablePattern(d[2])]},
|
|
122
|
-
{"name": "body$ebnf$1", "symbols": []},
|
|
123
|
-
{"name": "body$ebnf$1", "symbols": ["body$ebnf$1", "statement"], "postprocess": (d) => d[0].concat([d[1]])},
|
|
124
|
-
{"name": "body", "symbols": ["body$ebnf$1"], "postprocess": (d) => new UnguardedBody(new Sequence(d[0]))},
|
|
125
122
|
{"name": "expression", "symbols": ["comparison"], "postprocess": (d) => d[0]},
|
|
126
123
|
{"name": "comparison", "symbols": ["addition", "_", "comparison_operator", "_", "addition"], "postprocess": (d) => new ComparisonOperation(d[2], d[0], d[4])},
|
|
127
124
|
{"name": "comparison", "symbols": ["addition"], "postprocess": (d) => d[0]},
|
|
@@ -131,7 +128,6 @@ const grammar: Grammar = {
|
|
|
131
128
|
{"name": "multiplication", "symbols": ["multiplication", "_", {"literal":"*"}, "_", "primary"], "postprocess": (d) => new ArithmeticBinaryOperation("Multiply", d[0], d[4])},
|
|
132
129
|
{"name": "multiplication", "symbols": ["multiplication", "_", {"literal":"/"}, "_", "primary"], "postprocess": (d) => new ArithmeticBinaryOperation("Divide", d[0], d[4])},
|
|
133
130
|
{"name": "multiplication", "symbols": ["primary"], "postprocess": (d) => d[0]},
|
|
134
|
-
{"name": "primary", "symbols": ["variable"], "postprocess": (d) => d[0]},
|
|
135
131
|
{"name": "primary", "symbols": [{"literal":"("}, "_", "expression", "_", {"literal":")"}], "postprocess": (d) => d[2]},
|
|
136
132
|
{"name": "primary", "symbols": ["primitive"], "postprocess": (d) => d[0]},
|
|
137
133
|
{"name": "primitive", "symbols": [(MiniLexer.has("number") ? {type: "number"} : number)], "postprocess": (d) => new NumberPrimitive(Number(d[0].value))},
|
|
@@ -144,7 +140,7 @@ const grammar: Grammar = {
|
|
|
144
140
|
{"name": "type", "symbols": ["type", {"literal":"["}, {"literal":"]"}], "postprocess": (d) => new ListType(d[0], [])},
|
|
145
141
|
{"name": "list_primitive", "symbols": [{"literal":"["}, "_", "expression_list", "_", {"literal":"]"}], "postprocess": (d) => new ListPrimitive(d[2])},
|
|
146
142
|
{"name": "expression_list$ebnf$1", "symbols": []},
|
|
147
|
-
{"name": "expression_list$ebnf$1$subexpression$1", "symbols": [{"literal":","}, "_", "expression"
|
|
143
|
+
{"name": "expression_list$ebnf$1$subexpression$1", "symbols": [{"literal":","}, "_", "expression"]},
|
|
148
144
|
{"name": "expression_list$ebnf$1", "symbols": ["expression_list$ebnf$1", "expression_list$ebnf$1$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])},
|
|
149
145
|
{"name": "expression_list", "symbols": ["expression", "_", "expression_list$ebnf$1"], "postprocess": (d) => ([d[0], ...d[2].map(x => x[2])])},
|
|
150
146
|
{"name": "variable", "symbols": [(MiniLexer.has("variable") ? {type: "variable"} : variable)], "postprocess": (d) => new SymbolPrimitive(d[0].value)},
|
package/src/index.ts
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
import { YukigoParser } from "yukigo-ast";
|
|
2
|
-
import nearley from "nearley";
|
|
3
|
-
import grammar from "./grammar.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
1
|
+
import { AST, Expression, YukigoParser } from "yukigo-ast";
|
|
2
|
+
import nearley from "nearley";
|
|
3
|
+
import grammar from "./grammar.js";
|
|
4
|
+
import { Token } from "moo";
|
|
5
|
+
|
|
6
|
+
class UnexpectedToken extends Error {
|
|
7
|
+
constructor(token: Token) {
|
|
8
|
+
super(
|
|
9
|
+
`Parser: Unexpected '${token.type}' token '${token.value}' at line ${token.line} col ${token.col}.`
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class YukigoMiniParser implements YukigoParser {
|
|
15
|
+
public errors: string[] = [];
|
|
16
|
+
|
|
17
|
+
public parse(code: string): AST {
|
|
18
|
+
return this.feedParser(code);
|
|
19
|
+
}
|
|
20
|
+
public parseExpression(code: string): Expression {
|
|
21
|
+
return this.feedParser(code);
|
|
22
|
+
}
|
|
23
|
+
private feedParser(code: string): any {
|
|
24
|
+
const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));
|
|
25
|
+
try {
|
|
26
|
+
parser.feed(code);
|
|
27
|
+
parser.finish();
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if ("token" in error) throw new UnexpectedToken(error.token);
|
|
30
|
+
throw error
|
|
31
|
+
}
|
|
32
|
+
const results = parser.results;
|
|
33
|
+
if (results.length > 1)
|
|
34
|
+
throw Error(
|
|
35
|
+
`Ambiguous grammar. The parser generated ${results.length} ASTs`
|
|
36
|
+
);
|
|
37
|
+
return results[0];
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/lexer.ts
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
import moo from "moo";
|
|
2
|
-
import { makeLexer } from "moo-ignore";
|
|
3
|
-
|
|
4
|
-
const keywords = [
|
|
5
|
-
"return",
|
|
6
|
-
"if",
|
|
7
|
-
"else"
|
|
8
|
-
]
|
|
9
|
-
|
|
10
|
-
export const MiniLexerConfig = {
|
|
11
|
-
EOF: "*__EOF__*",
|
|
12
|
-
wildcard: "_",
|
|
13
|
-
WS: /[ \t]+/,
|
|
14
|
-
comment: /--.*?$|{-[\s\S]*?-}/,
|
|
15
|
-
number:
|
|
16
|
-
/0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:\d*\.\d+|\d+)(?:[eE][+-]?\d+)?/,
|
|
17
|
-
char: /'(?:\\['\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^'\\\n\r])?'/,
|
|
18
|
-
string: /"(?:\\["\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^"\\\n\r])*"/,
|
|
19
|
-
bool: {
|
|
20
|
-
match: ["True", "False"],
|
|
21
|
-
},
|
|
22
|
-
semicolon: ";",
|
|
23
|
-
assign: ":=",
|
|
24
|
-
notEqual: "!=",
|
|
25
|
-
equal: "==",
|
|
26
|
-
gte: ">=",
|
|
27
|
-
gt: ">",
|
|
28
|
-
lte: "<=",
|
|
29
|
-
lt: "<",
|
|
30
|
-
lparen: "(",
|
|
31
|
-
rparen: ")",
|
|
32
|
-
lsquare: "[",
|
|
33
|
-
rsquare: "]",
|
|
34
|
-
lbracket: "{",
|
|
35
|
-
rbracket: "}",
|
|
36
|
-
comma: ",",
|
|
37
|
-
operator: /\+|\*/,
|
|
38
|
-
variable: {
|
|
39
|
-
match: /[a-z_][a-zA-Z0-9_']*/,
|
|
40
|
-
type: moo.keywords({
|
|
41
|
-
keyword: keywords,
|
|
42
|
-
}),
|
|
43
|
-
},
|
|
44
|
-
NL: { match: /\r?\n/, lineBreaks: true },
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export const MiniLexer = makeLexer(MiniLexerConfig, ["NL", "comment"], {
|
|
48
|
-
eof: true,
|
|
49
|
-
});
|
|
1
|
+
import moo from "moo";
|
|
2
|
+
import { makeLexer } from "moo-ignore";
|
|
3
|
+
|
|
4
|
+
const keywords = [
|
|
5
|
+
"return",
|
|
6
|
+
"if",
|
|
7
|
+
"else"
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
export const MiniLexerConfig = {
|
|
11
|
+
EOF: "*__EOF__*",
|
|
12
|
+
wildcard: "_",
|
|
13
|
+
WS: /[ \t]+/,
|
|
14
|
+
comment: /--.*?$|{-[\s\S]*?-}/,
|
|
15
|
+
number:
|
|
16
|
+
/0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:\d*\.\d+|\d+)(?:[eE][+-]?\d+)?/,
|
|
17
|
+
char: /'(?:\\['\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^'\\\n\r])?'/,
|
|
18
|
+
string: /"(?:\\["\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^"\\\n\r])*"/,
|
|
19
|
+
bool: {
|
|
20
|
+
match: ["True", "False"],
|
|
21
|
+
},
|
|
22
|
+
semicolon: ";",
|
|
23
|
+
assign: ":=",
|
|
24
|
+
notEqual: "!=",
|
|
25
|
+
equal: "==",
|
|
26
|
+
gte: ">=",
|
|
27
|
+
gt: ">",
|
|
28
|
+
lte: "<=",
|
|
29
|
+
lt: "<",
|
|
30
|
+
lparen: "(",
|
|
31
|
+
rparen: ")",
|
|
32
|
+
lsquare: "[",
|
|
33
|
+
rsquare: "]",
|
|
34
|
+
lbracket: "{",
|
|
35
|
+
rbracket: "}",
|
|
36
|
+
comma: ",",
|
|
37
|
+
operator: /\+|\*/,
|
|
38
|
+
variable: {
|
|
39
|
+
match: /[a-z_][a-zA-Z0-9_']*/,
|
|
40
|
+
type: moo.keywords({
|
|
41
|
+
keyword: keywords,
|
|
42
|
+
}),
|
|
43
|
+
},
|
|
44
|
+
NL: { match: /\r?\n/, lineBreaks: true },
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const MiniLexer = makeLexer(MiniLexerConfig, ["NL", "comment"], {
|
|
48
|
+
eof: true,
|
|
49
|
+
});
|
package/src/parse.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { YukigoMiniParser } from "./index.js";
|
|
2
|
-
|
|
3
|
-
const parser = new YukigoMiniParser()
|
|
4
|
-
|
|
5
|
-
const code = `int n
|
|
6
|
-
int result
|
|
7
|
-
|
|
8
|
-
n := 5
|
|
9
|
-
result := 1
|
|
10
|
-
|
|
11
|
-
while n > 0 do
|
|
12
|
-
result := result * n
|
|
13
|
-
n := n - 1
|
|
14
|
-
endwhile
|
|
15
|
-
|
|
16
|
-
print result # This should print 120`
|
|
17
|
-
|
|
1
|
+
import { YukigoMiniParser } from "./index.js";
|
|
2
|
+
|
|
3
|
+
const parser = new YukigoMiniParser()
|
|
4
|
+
|
|
5
|
+
const code = `int n
|
|
6
|
+
int result
|
|
7
|
+
|
|
8
|
+
n := 5
|
|
9
|
+
result := 1
|
|
10
|
+
|
|
11
|
+
while n > 0 do
|
|
12
|
+
result := result * n
|
|
13
|
+
n := n - 1
|
|
14
|
+
endwhile
|
|
15
|
+
|
|
16
|
+
print result # This should print 120`
|
|
17
|
+
|
|
18
18
|
console.log(parser.parse(code))
|