yukigo-haskell-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 +3 -3
- package/CHANGELOG.md +51 -9
- package/README.md +5 -5
- 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 +6 -9
- 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/utils/helpers.ts
CHANGED
|
@@ -1,29 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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
|
-
|
|
1
|
+
import { AST } from "yukigo-ast";
|
|
2
|
+
import { Function } from "yukigo-ast";
|
|
3
|
+
|
|
4
|
+
export class UnexpectedNode extends Error {
|
|
5
|
+
constructor(nodeCons: string, context: string) {
|
|
6
|
+
super(`${nodeCons} not expected in ${context}.`)
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function groupFunctionDeclarations(ast: AST): AST {
|
|
11
|
+
const groups: Record<string, Function[]> = {};
|
|
12
|
+
const others: AST = [];
|
|
13
|
+
|
|
14
|
+
for (const node of ast) {
|
|
15
|
+
if (node instanceof Function) {
|
|
16
|
+
const name = node.identifier.value;
|
|
17
|
+
if (!groups[name]) {
|
|
18
|
+
groups[name] = [];
|
|
19
|
+
}
|
|
20
|
+
groups[name].push(node);
|
|
21
|
+
} else {
|
|
22
|
+
others.push(node);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Merge equations for each function name
|
|
27
|
+
const functionGroups: Function[] = Object.values(groups).map((functions) => {
|
|
28
|
+
const identifier = functions[0].identifier;
|
|
29
|
+
const allEquations = functions.flatMap((f) => f.equations);
|
|
30
|
+
return new Function(identifier, allEquations, identifier.loc);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return [...others, ...functionGroups];
|
|
34
|
+
}
|
package/src/utils/types.ts
CHANGED
|
@@ -1,63 +1,75 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
["
|
|
60
|
-
["
|
|
61
|
-
["
|
|
62
|
-
["
|
|
63
|
-
]
|
|
1
|
+
export const keywords = [
|
|
2
|
+
"type",
|
|
3
|
+
"where",
|
|
4
|
+
"in",
|
|
5
|
+
"if",
|
|
6
|
+
"else",
|
|
7
|
+
"then",
|
|
8
|
+
"data",
|
|
9
|
+
"case",
|
|
10
|
+
"error",
|
|
11
|
+
"class",
|
|
12
|
+
"do",
|
|
13
|
+
"default",
|
|
14
|
+
"deriving",
|
|
15
|
+
"import",
|
|
16
|
+
"infix",
|
|
17
|
+
"infixl",
|
|
18
|
+
"infixr",
|
|
19
|
+
"instance",
|
|
20
|
+
"let",
|
|
21
|
+
"module",
|
|
22
|
+
"newtype",
|
|
23
|
+
"of",
|
|
24
|
+
"qualified",
|
|
25
|
+
"hiding",
|
|
26
|
+
"foreign",
|
|
27
|
+
"describe",
|
|
28
|
+
"it",
|
|
29
|
+
"shouldBe",
|
|
30
|
+
"shouldNotBe",
|
|
31
|
+
"shouldSatisfy",
|
|
32
|
+
"shouldThrow"
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export enum YUTYPES { // primitivos
|
|
36
|
+
YuNumber = "YuNumber",
|
|
37
|
+
YuString = "YuString",
|
|
38
|
+
YuChar = "YuChar",
|
|
39
|
+
YuBoolean = "YuBoolean",
|
|
40
|
+
YuNil = "YuNil",
|
|
41
|
+
// constructores
|
|
42
|
+
Tuple = "Tuple",
|
|
43
|
+
List = "List",
|
|
44
|
+
Arrow = "->"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const typeMappings: { [key: string]: YUTYPES } = {
|
|
48
|
+
Float: YUTYPES.YuNumber,
|
|
49
|
+
Double: YUTYPES.YuNumber,
|
|
50
|
+
Int: YUTYPES.YuNumber,
|
|
51
|
+
Integer: YUTYPES.YuNumber,
|
|
52
|
+
String: YUTYPES.YuString,
|
|
53
|
+
Char: YUTYPES.YuChar,
|
|
54
|
+
Boolean: YUTYPES.YuBoolean,
|
|
55
|
+
Bool: YUTYPES.YuBoolean,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const typeClasses: Map<string, YUTYPES[]> = new Map([
|
|
59
|
+
["Bounded", [YUTYPES.YuChar, YUTYPES.YuNumber]],
|
|
60
|
+
["Enum", [YUTYPES.YuChar, YUTYPES.YuNumber]],
|
|
61
|
+
["Ord", [YUTYPES.YuNumber, YUTYPES.YuString, YUTYPES.YuChar]],
|
|
62
|
+
["Eq", [YUTYPES.YuNumber, YUTYPES.YuString, YUTYPES.YuChar, YUTYPES.YuBoolean]],
|
|
63
|
+
["Floating", [YUTYPES.YuNumber]],
|
|
64
|
+
["Fractional", [YUTYPES.YuNumber]],
|
|
65
|
+
["Integral", [YUTYPES.YuNumber]],
|
|
66
|
+
["Num", [YUTYPES.YuNumber]],
|
|
67
|
+
["Random", [YUTYPES.YuBoolean, YUTYPES.YuChar, YUTYPES.YuNumber]],
|
|
68
|
+
["Read", [YUTYPES.YuChar, YUTYPES.YuNumber]],
|
|
69
|
+
|
|
70
|
+
["Real", [YUTYPES.YuNumber]],
|
|
71
|
+
["RealFloat", [YUTYPES.YuNumber]],
|
|
72
|
+
["RealFrac", [YUTYPES.YuNumber]],
|
|
73
|
+
["Show", [YUTYPES.YuNumber, YUTYPES.YuString, YUTYPES.YuChar]],
|
|
74
|
+
|
|
75
|
+
]);
|
package/tests/hspec.spec.ts
CHANGED
|
@@ -1,92 +1,95 @@
|
|
|
1
|
-
import { expect } from "chai";
|
|
2
|
-
import { YukigoHaskellParser } from "../src/index.js";
|
|
3
|
-
import {
|
|
4
|
-
TestGroup,
|
|
5
|
-
Test,
|
|
6
|
-
Assert,
|
|
7
|
-
Equality,
|
|
8
|
-
Truth,
|
|
9
|
-
Failure,
|
|
10
|
-
Raise,
|
|
11
|
-
NumberPrimitive,
|
|
12
|
-
SymbolPrimitive,
|
|
13
|
-
Application,
|
|
14
|
-
StringPrimitive,
|
|
15
|
-
BooleanPrimitive
|
|
16
|
-
} from "yukigo-ast";
|
|
17
|
-
|
|
18
|
-
describe("HSpec Parsing", () => {
|
|
19
|
-
const parser = new YukigoHaskellParser("", {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
it
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
expect(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
expect(group.
|
|
36
|
-
expect(group.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
expect(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
expect(test.
|
|
43
|
-
expect(test.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
expect(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
expect(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
expect(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
expect(
|
|
76
|
-
|
|
77
|
-
expect(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
expect(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
import { expect } from "chai";
|
|
2
|
+
import { YukigoHaskellParser } from "../src/index.js";
|
|
3
|
+
import {
|
|
4
|
+
TestGroup,
|
|
5
|
+
Test,
|
|
6
|
+
Assert,
|
|
7
|
+
Equality,
|
|
8
|
+
Truth,
|
|
9
|
+
Failure,
|
|
10
|
+
Raise,
|
|
11
|
+
NumberPrimitive,
|
|
12
|
+
SymbolPrimitive,
|
|
13
|
+
Application,
|
|
14
|
+
StringPrimitive,
|
|
15
|
+
BooleanPrimitive,
|
|
16
|
+
} from "yukigo-ast";
|
|
17
|
+
|
|
18
|
+
describe("HSpec Parsing", () => {
|
|
19
|
+
const parser = new YukigoHaskellParser("", {
|
|
20
|
+
typecheck: true,
|
|
21
|
+
includePrims: false,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should parse describe and it blocks", () => {
|
|
25
|
+
const code = `
|
|
26
|
+
describe "Math" do
|
|
27
|
+
it "adds 1 and 1" do
|
|
28
|
+
(1 + 1) shouldBe 2
|
|
29
|
+
`;
|
|
30
|
+
const ast = parser.parse(code);
|
|
31
|
+
expect(ast).to.have.lengthOf(1);
|
|
32
|
+
expect(ast[0]).to.be.instanceOf(TestGroup);
|
|
33
|
+
|
|
34
|
+
const group = ast[0] as TestGroup;
|
|
35
|
+
expect(group.name).to.be.instanceOf(StringPrimitive);
|
|
36
|
+
expect((group.name as StringPrimitive).value).to.equal("Math");
|
|
37
|
+
|
|
38
|
+
expect(group.group.statements).to.have.lengthOf(1);
|
|
39
|
+
expect(group.group.statements[0]).to.be.instanceOf(Test);
|
|
40
|
+
|
|
41
|
+
const test = group.group.statements[0] as Test;
|
|
42
|
+
expect(test.name).to.be.instanceOf(StringPrimitive);
|
|
43
|
+
expect((test.name as StringPrimitive).value).to.equal("adds 1 and 1");
|
|
44
|
+
|
|
45
|
+
expect(test.body.statements).to.have.lengthOf(1);
|
|
46
|
+
expect(test.body.statements[0]).to.be.instanceOf(Assert);
|
|
47
|
+
|
|
48
|
+
const assert = test.body.statements[0] as Assert;
|
|
49
|
+
expect(assert.negated).to.be.instanceOf(BooleanPrimitive);
|
|
50
|
+
expect((assert.negated as BooleanPrimitive).value).to.be.false;
|
|
51
|
+
expect(assert.body).to.be.instanceOf(Equality);
|
|
52
|
+
|
|
53
|
+
const equality = assert.body as Equality;
|
|
54
|
+
expect(equality.expected).to.be.instanceOf(NumberPrimitive);
|
|
55
|
+
expect((equality.expected as NumberPrimitive).value).to.equal(2);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should parse shouldNotBe", () => {
|
|
59
|
+
const code = `it "negation" do 1 shouldNotBe 2`;
|
|
60
|
+
const ast = parser.parse(code);
|
|
61
|
+
const test = ast[0] as Test;
|
|
62
|
+
const assert = test.body.statements[0] as Assert;
|
|
63
|
+
expect((assert.negated as BooleanPrimitive).value).to.be.true;
|
|
64
|
+
expect(assert.body).to.be.instanceOf(Equality);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should parse shouldSatisfy", () => {
|
|
68
|
+
const code = `it "satisfy" do 5 shouldSatisfy odd`;
|
|
69
|
+
const ast = parser.parse(code);
|
|
70
|
+
const test = ast[0] as Test;
|
|
71
|
+
const assert = test.body.statements[0] as Assert;
|
|
72
|
+
expect(assert.body).to.be.instanceOf(Truth);
|
|
73
|
+
|
|
74
|
+
const truth = assert.body as Truth;
|
|
75
|
+
expect(truth.body).to.be.instanceOf(Application);
|
|
76
|
+
const app = truth.body as Application;
|
|
77
|
+
expect(app.functionExpr).to.be.instanceOf(SymbolPrimitive);
|
|
78
|
+
expect((app.functionExpr as SymbolPrimitive).value).to.equal("odd");
|
|
79
|
+
expect(app.parameter).to.be.instanceOf(NumberPrimitive);
|
|
80
|
+
expect((app.parameter as NumberPrimitive).value).to.equal(5);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should parse shouldThrow", () => {
|
|
84
|
+
const code = `it "throws" do error "fail" shouldThrow anyException`;
|
|
85
|
+
const ast = parser.parse(code);
|
|
86
|
+
const test = ast[0] as Test;
|
|
87
|
+
const assert = test.body.statements[0] as Assert;
|
|
88
|
+
expect(assert.body).to.be.instanceOf(Failure);
|
|
89
|
+
|
|
90
|
+
const failure = assert.body as Failure;
|
|
91
|
+
expect(failure.func).to.be.instanceOf(Raise);
|
|
92
|
+
expect(failure.message).to.be.instanceOf(SymbolPrimitive);
|
|
93
|
+
expect((failure.message as SymbolPrimitive).value).to.equal("anyException");
|
|
94
|
+
});
|
|
95
|
+
});
|