Skip to content

Commit c0b49a1

Browse files
committed
wasm: toAST - remove offset stuff, copy big mapping test in
1 parent dad65af commit c0b49a1

File tree

2 files changed

+150
-32
lines changed

2 files changed

+150
-32
lines changed

packages/miniohm-js/toAST.js

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
const assert = (cond, msg = 'Assertion failed') => {
2-
throw new Error(msg);
3-
};
4-
51
function handleListOf(child) {
62
return child.toAST(this.args.mapping);
73
}
@@ -30,13 +26,13 @@ class Visitor {
3026
this.mapping = mapping;
3127
}
3228

33-
visit(node, offset) {
29+
visit(node) {
3430
if (node.isTerminal()) {
35-
return this.visitTerminal(node, offset);
31+
return this.visitTerminal(node);
3632
} else if (node.isNonterminal()) {
37-
return this.visitNonterminal(node, offset);
33+
return this.visitNonterminal(node);
3834
} else if (node.isIter()) {
39-
return this.visitIter(node, offset);
35+
return this.visitIter(node);
4036
} else {
4137
throw new Error(`Unknown node type: ${node._type}`);
4238
}
@@ -46,17 +42,10 @@ class Visitor {
4642
return node.sourceString;
4743
}
4844

49-
visitNonterminal(node, offset) {
45+
visitNonterminal(node) {
5046
const {children, ruleName} = node;
5147
const {mapping} = this;
5248

53-
let currOffset = offset;
54-
const childOffsets = node.children.flatMap((c, i) => {
55-
const origOffset = currOffset;
56-
currOffset += c.matchLength;
57-
return c.isNonterminal() && c.ruleName === '$spaces' ? [] : origOffset;
58-
});
59-
6049
// without customization
6150
if (!Object.hasOwn(mapping, ruleName)) {
6251
// lexical rule
@@ -67,15 +56,13 @@ class Visitor {
6756
// singular node (e.g. only surrounded by literals or lookaheads)
6857
const realChildren = children.filter(c => !c.isTerminal());
6958
if (realChildren.length === 1) {
70-
const idx = children.indexOf(realChildren[0]);
71-
return this.visit(realChildren[0], childOffsets[idx]);
59+
return this.visit(realChildren[0]);
7260
}
7361

7462
// rest: terms with multiple children
7563
}
7664
// direct forward
7765
if (typeof mapping[ruleName] === 'number') {
78-
assert(false, 'not handled: direct forward');
7966
return this.visit(children[mapping[ruleName]]);
8067
}
8168

@@ -89,7 +76,7 @@ class Visitor {
8976
const mappedProp = mapping[ruleName] && mapping[ruleName][prop];
9077
if (typeof mappedProp === 'number') {
9178
// direct forward
92-
ans[prop] = this.visit(children[mappedProp], childOffsets[mappedProp]);
79+
ans[prop] = this.visit(children[mappedProp]);
9380
} else if (
9481
typeof mappedProp === 'string' ||
9582
typeof mappedProp === 'boolean' ||

packages/wasm/test/test-toAST.js

Lines changed: 143 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {toAST} from '@ohm-js/miniohm-js/toAST.js';
22
import test from 'ava';
33
import * as ohm from 'ohm-js';
44

5-
import {matchWithInput, wasmMatcherForGrammar} from './_helpers.js';
5+
import {wasmMatcherForGrammar} from './_helpers.js';
66

77
const arithmetic = ohm.grammar(`
88
Arithmetic {
@@ -26,23 +26,154 @@ const arithmetic = ohm.grammar(`
2626
// eslint-disable-next-line ava/no-skip-test
2727
test('toAST basic', async t => {
2828
const m = await wasmMatcherForGrammar(arithmetic);
29-
const match = str => (m.setInput(str), m.match(str));
29+
m.setInput('10 + 20');
30+
let matchResult = m.match();
31+
let ast = toAST(matchResult, {
32+
AddExp_plus: {
33+
expr1: 0,
34+
expr2: 2,
35+
},
36+
});
37+
let expected = {
38+
expr1: '10',
39+
expr2: '20',
40+
type: 'AddExp_plus',
41+
};
42+
t.deepEqual(ast, expected, 'proper AST with mapped properties');
3043

31-
const r = match('10 + 20');
32-
t.true(r.succeeded());
33-
const ast = toAST(r, {
44+
ast = toAST(matchResult, {
3445
AddExp_plus: {
3546
expr1: 0,
47+
op: 1,
3648
expr2: 2,
3749
},
3850
});
39-
t.deepEqual(
40-
ast,
41-
{
42-
expr1: '10',
43-
expr2: '20',
51+
expected = {
52+
expr1: '10',
53+
op: '+',
54+
expr2: '20',
55+
type: 'AddExp_plus',
56+
};
57+
t.deepEqual(ast, expected, 'proper AST with explicitly mapped property');
58+
59+
ast = toAST(matchResult, {
60+
AddExp_plus: {
61+
0: 0,
62+
},
63+
});
64+
expected = {
65+
0: '10',
66+
type: 'AddExp_plus',
67+
};
68+
t.deepEqual(ast, expected, 'proper AST with explicitly removed property');
69+
70+
ast = toAST(matchResult, {
71+
AddExp_plus: {
72+
0: 0,
73+
type: undefined,
74+
},
75+
});
76+
expected = {
77+
0: '10',
78+
};
79+
t.deepEqual(ast, expected, 'proper AST with explicitly removed type');
80+
81+
ast = toAST(matchResult, {
82+
AddExp_plus: {
83+
expr1: 0,
84+
op: 'plus',
85+
expr2: 2,
86+
},
87+
});
88+
expected = {
89+
expr1: '10',
90+
op: 'plus',
91+
expr2: '20',
92+
type: 'AddExp_plus',
93+
};
94+
t.deepEqual(ast, expected, 'proper AST with static property');
95+
96+
ast = toAST(matchResult, {
97+
AddExp_plus: {
98+
expr1: Object(0),
99+
op: 'plus',
100+
expr2: Object(2),
101+
},
102+
});
103+
expected = {
104+
expr1: 0,
105+
op: 'plus',
106+
expr2: 2,
107+
type: 'AddExp_plus',
108+
};
109+
t.deepEqual(ast, expected, 'proper AST with boxed number property');
110+
111+
// ast = toAST(matchResult, {
112+
// AddExp_plus: {
113+
// expr1: 0,
114+
// expr2: 2,
115+
// str(children) {
116+
// return children
117+
// .map(function(child) {
118+
// return child.toAST(this.args.mapping);
119+
// }, this)
120+
// .join('');
121+
// },
122+
// },
123+
// });
124+
// expected = {
125+
// expr1: '10',
126+
// expr2: '20',
127+
// str: '10+20',
128+
// type: 'AddExp_plus',
129+
// };
130+
// t.deepEqual(ast, expected, 'proper AST with computed property');
131+
132+
m.setInput('10 + 20 - 30');
133+
matchResult = m.match();
134+
ast = toAST(matchResult, {
135+
AddExp_plus: 2,
136+
});
137+
expected = {
138+
0: '20', // child 2 of AddExp_plus
139+
2: '30',
140+
type: 'AddExp_minus',
141+
};
142+
t.deepEqual(ast, expected, 'proper AST with forwarded child node');
143+
144+
// const myToAST = node =>
145+
// toAST(node, {
146+
// AddExp_plus(expr1, _, expr2) {
147+
// expr1 = expr1.toAST(this.args.mapping);
148+
// expr2 = expr2.toAST(this.args.mapping);
149+
// return 'plus(' + expr1 + ', ' + expr2 + ')';
150+
// },
151+
// });
152+
// ast = myToAST(matchResult);
153+
// expected = {
154+
// 0: 'plus(10, 20)', // child 2 of AddExp_plus
155+
// 2: '30',
156+
// type: 'AddExp_minus',
157+
// };
158+
// t.deepEqual(ast, expected, 'proper AST with computed node/operation extension');
159+
160+
ast = toAST(matchResult, {
161+
Exp: {
162+
type: 'Exp',
163+
0: 0,
164+
},
165+
});
166+
expected = {
167+
0: {
168+
0: {
169+
0: '10',
170+
2: '20',
44171
type: 'AddExp_plus',
45172
},
46-
'proper AST with mapped properties',
47-
);
173+
2: '30',
174+
type: 'AddExp_minus',
175+
},
176+
type: 'Exp',
177+
};
178+
t.deepEqual(ast, expected, 'proper AST with explicity reintroduced node');
48179
});

0 commit comments

Comments
 (0)