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/src/grammar.ne CHANGED
@@ -1,132 +1,131 @@
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 %}
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.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
- }
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
- 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
+ // @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
+ });