yukigo-haskell-parser 0.1.2 → 0.2.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/.mocharc.json +3 -3
- package/CHANGELOG.md +41 -7
- package/README.md +5 -10
- package/dist/index.js +21 -13
- package/dist/index.js.map +1 -1
- package/dist/parser/grammar.cjs +397 -0
- package/dist/parser/grammar.cjs.map +1 -0
- package/dist/parser/grammar.d.cts +38 -0
- package/dist/parser/lexer.d.ts +2 -1
- package/dist/parser/lexer.js +6 -1
- package/dist/parser/lexer.js.map +1 -1
- package/dist/prelude.js +279 -279
- package/dist/typechecker/DeclarationCollector.d.ts +2 -0
- package/dist/typechecker/DeclarationCollector.js +6 -5
- package/dist/typechecker/DeclarationCollector.js.map +1 -1
- package/dist/typechecker/TypeBuilder.js +9 -7
- package/dist/typechecker/TypeBuilder.js.map +1 -1
- package/dist/typechecker/checker.d.ts +9 -4
- package/dist/typechecker/checker.js +66 -94
- package/dist/typechecker/checker.js.map +1 -1
- package/dist/typechecker/core.js +8 -7
- package/dist/typechecker/core.js.map +1 -1
- package/dist/typechecker/inference.d.ts +4 -1
- package/dist/typechecker/inference.js +39 -19
- package/dist/typechecker/inference.js.map +1 -1
- package/dist/utils/helpers.d.ts +3 -0
- package/dist/utils/helpers.js +5 -0
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/types.d.ts +12 -3
- package/dist/utils/types.js +34 -22
- package/dist/utils/types.js.map +1 -1
- package/package.json +9 -10
- package/src/index.ts +223 -192
- package/src/parser/{grammar.ts → grammar.cjs} +191 -223
- package/src/parser/grammar.d.ts +3 -0
- package/src/parser/grammar.ne +521 -518
- package/src/parser/lexer.ts +357 -353
- package/src/prelude.ts +281 -281
- package/src/typechecker/DeclarationCollector.ts +160 -157
- package/src/typechecker/TypeBuilder.ts +153 -150
- package/src/typechecker/checker.ts +487 -501
- package/src/typechecker/core.ts +195 -192
- package/src/typechecker/inference.ts +1442 -1421
- package/src/utils/helpers.ts +34 -29
- package/src/utils/types.ts +75 -63
- package/tests/hspec.spec.ts +95 -92
- package/tests/lexer.spec.ts +175 -175
- package/tests/parser.spec.ts +838 -829
- package/tests/prelude.spec.ts +17 -17
- package/tests/typechecker.spec.ts +326 -327
- package/tsconfig.build.json +16 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +29 -26
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/parser/grammar.d.ts +0 -28
- package/dist/parser/grammar.js +0 -393
- package/dist/parser/grammar.js.map +0 -1
package/src/index.ts
CHANGED
|
@@ -1,192 +1,223 @@
|
|
|
1
|
-
import grammar from "./parser/grammar.
|
|
2
|
-
import nearley from "nearley";
|
|
3
|
-
import { groupFunctionDeclarations } from "./utils/helpers.js";
|
|
4
|
-
import { TypeChecker } from "./typechecker/checker.js";
|
|
5
|
-
import {
|
|
6
|
-
ArithmeticUnaryOperation,
|
|
7
|
-
AST,
|
|
8
|
-
Equation,
|
|
9
|
-
Expression,
|
|
10
|
-
Function,
|
|
11
|
-
Instance,
|
|
12
|
-
ListType,
|
|
13
|
-
Return,
|
|
14
|
-
Sequence,
|
|
15
|
-
SimpleType,
|
|
16
|
-
StringOperation,
|
|
17
|
-
StringPrimitive,
|
|
18
|
-
SymbolPrimitive,
|
|
19
|
-
TypePattern,
|
|
20
|
-
UnguardedBody,
|
|
21
|
-
VariablePattern,
|
|
22
|
-
YukigoParser,
|
|
23
|
-
} from "yukigo-ast";
|
|
24
|
-
import { preludeCode } from "./prelude.js";
|
|
25
|
-
import { typeMappings } from "./utils/types.js";
|
|
26
|
-
import { Token } from "moo";
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
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
|
-
const
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return
|
|
187
|
-
}
|
|
188
|
-
public
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
1
|
+
import grammar from "./parser/grammar.cjs";
|
|
2
|
+
import nearley from "nearley";
|
|
3
|
+
import { groupFunctionDeclarations } from "./utils/helpers.js";
|
|
4
|
+
import { TypeChecker } from "./typechecker/checker.js";
|
|
5
|
+
import {
|
|
6
|
+
ArithmeticUnaryOperation,
|
|
7
|
+
AST,
|
|
8
|
+
Equation,
|
|
9
|
+
Expression,
|
|
10
|
+
Function,
|
|
11
|
+
Instance,
|
|
12
|
+
ListType,
|
|
13
|
+
Return,
|
|
14
|
+
Sequence,
|
|
15
|
+
SimpleType,
|
|
16
|
+
StringOperation,
|
|
17
|
+
StringPrimitive,
|
|
18
|
+
SymbolPrimitive,
|
|
19
|
+
TypePattern,
|
|
20
|
+
UnguardedBody,
|
|
21
|
+
VariablePattern,
|
|
22
|
+
YukigoParser,
|
|
23
|
+
} from "yukigo-ast";
|
|
24
|
+
import { preludeCode } from "./prelude.js";
|
|
25
|
+
import { typeMappings } from "./utils/types.js";
|
|
26
|
+
import { Token } from "moo";
|
|
27
|
+
|
|
28
|
+
interface NearleyError {
|
|
29
|
+
token?: any;
|
|
30
|
+
offset?: number;
|
|
31
|
+
[key: string]: any;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class UnexpectedToken extends Error {
|
|
35
|
+
constructor(token: Token) {
|
|
36
|
+
super(
|
|
37
|
+
`Parser: Unexpected '${token.type}' token '${token.value}' at line ${token.line} col ${token.col}.`,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
class AmbiguityError extends Error {
|
|
42
|
+
constructor(amountAST: number) {
|
|
43
|
+
super(
|
|
44
|
+
`Parser: Too much ambiguity. ${amountAST} ASTs parsed. Output not generated.`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class TypeError extends Error {
|
|
49
|
+
constructor(errors: string[]) {
|
|
50
|
+
super(`Found type errors.\n\t-${errors.join("\n\t-")}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type HaskellConfig = {
|
|
55
|
+
typecheck: boolean;
|
|
56
|
+
includePrims: boolean;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const HaskellDefaultConfig = {
|
|
60
|
+
typecheck: true,
|
|
61
|
+
includePrims: true,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export class YukigoHaskellParser implements YukigoParser {
|
|
65
|
+
public errors: string[] = [];
|
|
66
|
+
private prelude: AST;
|
|
67
|
+
private config: HaskellConfig;
|
|
68
|
+
private checker?: TypeChecker;
|
|
69
|
+
|
|
70
|
+
constructor(
|
|
71
|
+
prelude: string = preludeCode,
|
|
72
|
+
config: HaskellConfig = HaskellDefaultConfig,
|
|
73
|
+
) {
|
|
74
|
+
this.errors = [];
|
|
75
|
+
this.prelude = this.feedParser(prelude);
|
|
76
|
+
this.config = config;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private preprocessor(code: string): string {
|
|
80
|
+
return code.replace(/Exception\.evaluate/g, "evaluate");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public parse(code: string): AST {
|
|
84
|
+
const processedCode = this.preprocessor(code);
|
|
85
|
+
const result = this.feedParser(processedCode);
|
|
86
|
+
const fullAst = this.prelude.concat(result);
|
|
87
|
+
|
|
88
|
+
const makePrim = (name: string) => {
|
|
89
|
+
const returnExpr = new Return(
|
|
90
|
+
new ArithmeticUnaryOperation(
|
|
91
|
+
"ToString",
|
|
92
|
+
new SymbolPrimitive("x"),
|
|
93
|
+
),
|
|
94
|
+
);
|
|
95
|
+
return new Function(new SymbolPrimitive(name), [
|
|
96
|
+
new Equation(
|
|
97
|
+
[new VariablePattern(new SymbolPrimitive("x"))],
|
|
98
|
+
new UnguardedBody(
|
|
99
|
+
new Sequence([returnExpr]),
|
|
100
|
+
),
|
|
101
|
+
returnExpr,
|
|
102
|
+
),
|
|
103
|
+
]);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const prims = [
|
|
107
|
+
makePrim("primShow"),
|
|
108
|
+
makePrim("primShowChar"),
|
|
109
|
+
makePrim("primShowString"),
|
|
110
|
+
makePrim("primShowList"),
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
const resolveYukigoType = (t: any): any => {
|
|
114
|
+
if (t instanceof SimpleType) {
|
|
115
|
+
const mapped = typeMappings[t.value];
|
|
116
|
+
if (mapped) {
|
|
117
|
+
const runtimeTypeName = mapped.replace(/^Yu/, "");
|
|
118
|
+
return new SimpleType(runtimeTypeName, t.constraints, t.loc);
|
|
119
|
+
}
|
|
120
|
+
return t;
|
|
121
|
+
}
|
|
122
|
+
if (t instanceof ListType) return t;
|
|
123
|
+
return t;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const primShowStringReturnExpr = new Return(
|
|
127
|
+
new StringOperation(
|
|
128
|
+
"Concat",
|
|
129
|
+
new StringPrimitive('"'),
|
|
130
|
+
new StringOperation(
|
|
131
|
+
"Concat",
|
|
132
|
+
new SymbolPrimitive("s"),
|
|
133
|
+
new StringPrimitive('"'),
|
|
134
|
+
),
|
|
135
|
+
),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const primShowString = new Function(new SymbolPrimitive("primShowString"), [
|
|
139
|
+
new Equation(
|
|
140
|
+
[new VariablePattern(new SymbolPrimitive("s"))],
|
|
141
|
+
new UnguardedBody(
|
|
142
|
+
new Sequence([primShowStringReturnExpr]),
|
|
143
|
+
),
|
|
144
|
+
primShowStringReturnExpr,
|
|
145
|
+
),
|
|
146
|
+
]);
|
|
147
|
+
|
|
148
|
+
// Transform Instance nodes into Function nodes with TypePatterns
|
|
149
|
+
const transformedAst: AST = this.config.includePrims
|
|
150
|
+
? [...prims, primShowString]
|
|
151
|
+
: [];
|
|
152
|
+
for (const node of fullAst) {
|
|
153
|
+
if (node instanceof Instance) {
|
|
154
|
+
const instanceNode = node as Instance;
|
|
155
|
+
const yukigoType = resolveYukigoType(instanceNode.type);
|
|
156
|
+
|
|
157
|
+
for (const func of instanceNode.functions) {
|
|
158
|
+
const overloadedEquations = func.equations.map((eq) => {
|
|
159
|
+
const firstPattern = eq.patterns[0];
|
|
160
|
+
const typePattern = new TypePattern(yukigoType, firstPattern);
|
|
161
|
+
return new Equation(
|
|
162
|
+
[typePattern, ...eq.patterns.slice(1)],
|
|
163
|
+
eq.body,
|
|
164
|
+
eq.returnExpr,
|
|
165
|
+
eq.loc,
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
transformedAst.unshift(
|
|
169
|
+
new Function(func.identifier, overloadedEquations, func.loc),
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
transformedAst.push(node);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const ast = groupFunctionDeclarations(transformedAst);
|
|
178
|
+
if (this.config.typecheck) {
|
|
179
|
+
this.checker = new TypeChecker();
|
|
180
|
+
const errors = this.checker.check(ast);
|
|
181
|
+
if (errors.length > 0) {
|
|
182
|
+
this.errors.push(...errors);
|
|
183
|
+
throw new TypeError(errors);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return ast;
|
|
187
|
+
}
|
|
188
|
+
public parseExpression(code: string): Expression {
|
|
189
|
+
const processedCode = this.preprocessor(code);
|
|
190
|
+
const expr = this.feedParser(processedCode)[0];
|
|
191
|
+
return expr;
|
|
192
|
+
}
|
|
193
|
+
private feedParser(code: string): any {
|
|
194
|
+
const parser = new nearley.Parser(
|
|
195
|
+
nearley.Grammar.fromCompiled(grammar as any),
|
|
196
|
+
);
|
|
197
|
+
try {
|
|
198
|
+
parser.feed(code);
|
|
199
|
+
parser.finish();
|
|
200
|
+
} catch (e: unknown) {
|
|
201
|
+
const error = e as NearleyError; // Assert the shape
|
|
202
|
+
if (error.token) {
|
|
203
|
+
throw new UnexpectedToken(error.token);
|
|
204
|
+
}
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
const { results } = parser;
|
|
208
|
+
if (results.length > 1) throw new AmbiguityError(results.length);
|
|
209
|
+
if (results.length == 0) return [];
|
|
210
|
+
return results[0];
|
|
211
|
+
}
|
|
212
|
+
public typeOfExpression(code: string): string {
|
|
213
|
+
if (!this.config.typecheck || !this.checker)
|
|
214
|
+
throw new Error("Type checking not initialized. Did you load a file?");
|
|
215
|
+
|
|
216
|
+
const expr = this.parseExpression(code);
|
|
217
|
+
return this.checker.inferExpression(expr);
|
|
218
|
+
}
|
|
219
|
+
public getKnownSymbols(): string[] {
|
|
220
|
+
if (!this.config.typecheck || !this.checker) return [];
|
|
221
|
+
return this.checker.getKnownSymbols();
|
|
222
|
+
}
|
|
223
|
+
}
|