yukigo-mini-parser 0.1.0 → 0.1.1

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/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
- export class YukigoMiniParser implements YukigoParser {
6
- public errors: string[] = [];
7
-
8
- public parse(code: string) {
9
- const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));
10
- try {
11
- parser.feed(code);
12
- parser.finish();
13
- } catch (error) {
14
- const token = error.token;
15
- const message = `Unexpected '${token.type}' token '${token.value}' at line ${token.line} col ${token.col}.`;
16
- this.errors.push(message)
17
- }
18
- const results = parser.results
19
- if(results.length > 1)
20
- throw Error(`Ambiguous grammar. The parser generated ${results.length} ASTs`)
21
-
22
- return results[0]
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))
@@ -1,158 +1,158 @@
1
- import { assert } from "chai";
2
- import {
3
- ArithmeticBinaryOperation,
4
- Assignment,
5
- ComparisonOperation,
6
- Equation,
7
- If,
8
- ListPrimitive,
9
- ListType,
10
- NilPrimitive,
11
- NumberPrimitive,
12
- ParameterizedType,
13
- Procedure,
14
- Return,
15
- Sequence,
16
- SimpleType,
17
- SymbolPrimitive,
18
- TypeSignature,
19
- UnguardedBody,
20
- Variable,
21
- VariablePattern,
22
- While,
23
- YukigoParser,
24
- } from "yukigo-ast";
25
- import { YukigoMiniParser } from "../src/index.js";
26
-
27
- describe("Parser Tests", () => {
28
- let parser: YukigoParser;
29
- beforeEach(() => {
30
- parser = new YukigoMiniParser();
31
- });
32
-
33
- it("should parse assignment", () => {
34
- const code = `int n; int result;`;
35
- assert.deepEqual(parser.parse(code), [
36
- new Variable(
37
- new SymbolPrimitive("n"),
38
- new NilPrimitive(null),
39
- new SimpleType("int", [])
40
- ),
41
- new Variable(
42
- new SymbolPrimitive("result"),
43
- new NilPrimitive(null),
44
- new SimpleType("int", [])
45
- ),
46
- ]);
47
- });
48
- it("should parse function declaration", () => {
49
- const code = `int add(int x, int y) {
50
- int result := x + y;
51
- return result;
52
- };`;
53
- assert.deepEqual(parser.parse(code), [
54
- new TypeSignature(
55
- new SymbolPrimitive("add"),
56
- new ParameterizedType(
57
- [new SimpleType("int", []), new SimpleType("int", [])],
58
- new SimpleType("int", []),
59
- []
60
- )
61
- ),
62
- new Procedure(new SymbolPrimitive("add"), [
63
- new Equation(
64
- [
65
- new VariablePattern(new SymbolPrimitive("x")),
66
- new VariablePattern(new SymbolPrimitive("y")),
67
- ],
68
- new UnguardedBody(
69
- new Sequence([
70
- new Variable(
71
- new SymbolPrimitive("result"),
72
- new ArithmeticBinaryOperation(
73
- "Plus",
74
- new SymbolPrimitive("x"),
75
- new SymbolPrimitive("y")
76
- ),
77
- new SimpleType("int", [])
78
- ),
79
- new Return(new SymbolPrimitive("result")),
80
- ])
81
- )
82
- ),
83
- ]),
84
- ]);
85
- });
86
- it("should parse list primitive", () => {
87
- const code = `int[] numberList := [1, 2, 3 + 4];`;
88
- assert.deepEqual(parser.parse(code), [
89
- new Variable(
90
- new SymbolPrimitive("numberList"),
91
- new ListPrimitive([
92
- new NumberPrimitive(1),
93
- new NumberPrimitive(2),
94
- new ArithmeticBinaryOperation(
95
- "Plus",
96
- new NumberPrimitive(3),
97
- new NumberPrimitive(4)
98
- ),
99
- ]),
100
- new ListType(new SimpleType("int", []), [])
101
- ),
102
- ]);
103
- });
104
- it("should parse if statement", () => {
105
- const code = `if(a != b) { c := a + b; } else { c := a * 2; };`;
106
- assert.deepEqual(parser.parse(code), [
107
- new If(
108
- new ComparisonOperation(
109
- "NotEqual",
110
- new SymbolPrimitive("a"),
111
- new SymbolPrimitive("b")
112
- ),
113
- new Sequence([
114
- new Assignment(
115
- new SymbolPrimitive("c"),
116
- new ArithmeticBinaryOperation(
117
- "Plus",
118
- new SymbolPrimitive("a"),
119
- new SymbolPrimitive("b")
120
- )
121
- ),
122
- ]),
123
- new Sequence([
124
- new Assignment(
125
- new SymbolPrimitive("c"),
126
- new ArithmeticBinaryOperation(
127
- "Multiply",
128
- new SymbolPrimitive("a"),
129
- new NumberPrimitive(2)
130
- )
131
- ),
132
- ]),
133
- ),
134
- ]);
135
- });
136
- it("should parse while loop statement", () => {
137
- const code = `while(a < 10) { a := a + 1; };`;
138
- assert.deepEqual(parser.parse(code), [
139
- new While(
140
- new ComparisonOperation(
141
- "LessThan",
142
- new SymbolPrimitive("a"),
143
- new NumberPrimitive(10)
144
- ),
145
- new Sequence([
146
- new Assignment(
147
- new SymbolPrimitive("a"),
148
- new ArithmeticBinaryOperation(
149
- "Plus",
150
- new SymbolPrimitive("a"),
151
- new NumberPrimitive(1)
152
- )
153
- ),
154
- ]),
155
- ),
156
- ]);
157
- });
158
- });
1
+ import { assert } from "chai";
2
+ import {
3
+ ArithmeticBinaryOperation,
4
+ Assignment,
5
+ ComparisonOperation,
6
+ Equation,
7
+ If,
8
+ ListPrimitive,
9
+ ListType,
10
+ NilPrimitive,
11
+ NumberPrimitive,
12
+ ParameterizedType,
13
+ Procedure,
14
+ Return,
15
+ Sequence,
16
+ SimpleType,
17
+ SymbolPrimitive,
18
+ TypeSignature,
19
+ UnguardedBody,
20
+ Variable,
21
+ VariablePattern,
22
+ While,
23
+ YukigoParser,
24
+ } from "yukigo-ast";
25
+ import { YukigoMiniParser } from "../src/index.js";
26
+
27
+ describe("Parser Tests", () => {
28
+ let parser: YukigoParser;
29
+ beforeEach(() => {
30
+ parser = new YukigoMiniParser();
31
+ });
32
+
33
+ it("should parse assignment", () => {
34
+ const code = `int n; int result;`;
35
+ assert.deepEqual(parser.parse(code), [
36
+ new Variable(
37
+ new SymbolPrimitive("n"),
38
+ new NilPrimitive(null),
39
+ new SimpleType("int", [])
40
+ ),
41
+ new Variable(
42
+ new SymbolPrimitive("result"),
43
+ new NilPrimitive(null),
44
+ new SimpleType("int", [])
45
+ ),
46
+ ]);
47
+ });
48
+ it("should parse function declaration", () => {
49
+ const code = `int add(int x, int y) {
50
+ int result := x + y;
51
+ return result;
52
+ };`;
53
+ assert.deepEqual(parser.parse(code), [
54
+ new TypeSignature(
55
+ new SymbolPrimitive("add"),
56
+ new ParameterizedType(
57
+ [new SimpleType("int", []), new SimpleType("int", [])],
58
+ new SimpleType("int", []),
59
+ []
60
+ )
61
+ ),
62
+ new Procedure(new SymbolPrimitive("add"), [
63
+ new Equation(
64
+ [
65
+ new VariablePattern(new SymbolPrimitive("x")),
66
+ new VariablePattern(new SymbolPrimitive("y")),
67
+ ],
68
+ new UnguardedBody(
69
+ new Sequence([
70
+ new Variable(
71
+ new SymbolPrimitive("result"),
72
+ new ArithmeticBinaryOperation(
73
+ "Plus",
74
+ new SymbolPrimitive("x"),
75
+ new SymbolPrimitive("y")
76
+ ),
77
+ new SimpleType("int", [])
78
+ ),
79
+ new Return(new SymbolPrimitive("result")),
80
+ ])
81
+ )
82
+ ),
83
+ ]),
84
+ ]);
85
+ });
86
+ it("should parse list primitive", () => {
87
+ const code = `int[] numberList := [1, 2, 3 + 4];`;
88
+ assert.deepEqual(parser.parse(code), [
89
+ new Variable(
90
+ new SymbolPrimitive("numberList"),
91
+ new ListPrimitive([
92
+ new NumberPrimitive(1),
93
+ new NumberPrimitive(2),
94
+ new ArithmeticBinaryOperation(
95
+ "Plus",
96
+ new NumberPrimitive(3),
97
+ new NumberPrimitive(4)
98
+ ),
99
+ ]),
100
+ new ListType(new SimpleType("int", []), [])
101
+ ),
102
+ ]);
103
+ });
104
+ it("should parse if statement", () => {
105
+ const code = `if (a != b) { c := a + b; } else { c := a * 2; };`;
106
+ assert.deepEqual(parser.parse(code), [
107
+ new If(
108
+ new ComparisonOperation(
109
+ "NotEqual",
110
+ new SymbolPrimitive("a"),
111
+ new SymbolPrimitive("b")
112
+ ),
113
+ new Sequence([
114
+ new Assignment(
115
+ new SymbolPrimitive("c"),
116
+ new ArithmeticBinaryOperation(
117
+ "Plus",
118
+ new SymbolPrimitive("a"),
119
+ new SymbolPrimitive("b")
120
+ )
121
+ ),
122
+ ]),
123
+ new Sequence([
124
+ new Assignment(
125
+ new SymbolPrimitive("c"),
126
+ new ArithmeticBinaryOperation(
127
+ "Multiply",
128
+ new SymbolPrimitive("a"),
129
+ new NumberPrimitive(2)
130
+ )
131
+ ),
132
+ ])
133
+ ),
134
+ ]);
135
+ });
136
+ it("should parse while loop statement", () => {
137
+ const code = `while (a < 10) { a := a + 1; };`;
138
+ assert.deepEqual(parser.parse(code), [
139
+ new While(
140
+ new ComparisonOperation(
141
+ "LessThan",
142
+ new SymbolPrimitive("a"),
143
+ new NumberPrimitive(10)
144
+ ),
145
+ new Sequence([
146
+ new Assignment(
147
+ new SymbolPrimitive("a"),
148
+ new ArithmeticBinaryOperation(
149
+ "Plus",
150
+ new SymbolPrimitive("a"),
151
+ new NumberPrimitive(1)
152
+ )
153
+ ),
154
+ ])
155
+ ),
156
+ ]);
157
+ });
158
+ });
package/tsconfig.json CHANGED
@@ -1,17 +1,24 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2024",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2024"],
7
- "outDir": "./dist",
8
- "declaration": true,
9
- "esModuleInterop": true,
10
- "allowSyntheticDefaultImports": true,
11
- "sourceMap": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "skipLibCheck": true
14
- },
15
- "include": ["src"],
16
- "exclude": ["dist/**/*"]
17
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2024",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2024"],
7
+ "outDir": "./dist",
8
+ "declaration": true,
9
+ "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
11
+ "sourceMap": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "skipLibCheck": true
14
+ },
15
+ "include": ["src"],
16
+ "exclude": [
17
+ "dist/**/*"
18
+ ],
19
+ "references": [
20
+ {
21
+ "path": "../yukigo-ast"
22
+ }
23
+ ]
24
+ }