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