| 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
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
107
108
109
110
111
112
113
114
115
116 |
23x
23x
23x
23x
23x
23x
23x
23x
180x
209x
209x
199x
10x
10x
40x
40x
40x
40x
40x
40x
90x
90x
636x
636x
636x
550x
86x
90x
100x
100x
100x
77x
23x
23x
23x
23x
23x
90x
17x
17x
17x
17x
17x
1x
16x
90x
| /**
* Array Plugin
*
* @flow
*/
import Syntax from 'walt-syntax';
import invariant from 'invariant';
import { find } from 'walt-parser-tools/scope';
import { extendNode } from '../utils/extend-node';
import withContext from '../utils/transform-with-context';
import pick from '../utils/pick';
import type { SemanticPlugin } from '../flow/types';
const shifts = { i32: 2, f32: 2, i64: 3, f64: 3 };
const NATIVE_ARRAY_TYPE = 'i32';
function semantics({ stmt }) {
const declaration = next => args => {
const [node, context] = args;
// For every declaration of array types we will strip the declaration type
// to a core type (i32) and attach the original type reference as metadata
if (!String(node.type).endsWith('[]')) {
return next(args);
}
const decl = extendNode(
{
type: NATIVE_ARRAY_TYPE,
meta: { TYPE_ARRAY: node.type.slice(0, -2) },
},
node
);
return next([decl, context]);
};
function arrayOffset(base, offset) {
const shift = shifts[base.meta.TYPE_ARRAY] || 2;
// if (shift == null) {
// return null;
// }
return offset.Type !== Syntax.Constant || Number(offset.value)
? stmt`(${base} + (${offset} << ${shift}));`
: stmt`(${base});`;
}
function sanityCheck(subscript) {
return !(subscript.type == null || subscript.index == null);
}
function produceSubscript([base, offset]) {
let type = base.meta.TYPE_ARRAY;
// if (context.userTypes[type]) {
// type = 'i32';
// }
const index = arrayOffset(base, offset);
return { type, index, TYPE_ARRAY: base.meta.TYPE_ARRAY };
}
return {
[Syntax.Declaration]: declaration,
[Syntax.ImmutableDeclaration]: declaration,
[Syntax.Identifier]: next => args => {
const [node, context] = args;
const ref = find(context.scopes, node.value);
if (!(ref && ref.meta.TYPE_ARRAY)) {
return next(args);
}
// Before moving on to the core parser all identifiers need to have
// concrete basic types
return next([extendNode(pick(['type', 'meta'], ref), node), context]);
},
[Syntax.Assignment]: next => (args, t) => {
const [node, context] = args;
const [lhs, rhs] = node.params;
if (lhs.Type !== Syntax.ArraySubscript) {
return next(args);
}
const transform = withContext(t, context);
const subscript = produceSubscript(lhs.params.map(transform));
const { type, index } = subscript;
invariant(
sanityCheck(subscript),
`PANIC - Cannot assign to subscript of ${lhs.value}`
);
return transform(stmt`${type}.store(${index}, ${rhs});`);
},
[Syntax.ArraySubscript]: next => (args, t) => {
const [node, context] = args;
const transform = withContext(t, context);
const subscript = produceSubscript(node.params.map(transform));
const { type, index, TYPE_ARRAY } = subscript;
if (!sanityCheck(subscript)) {
return next(args);
}
return extendNode(
{ meta: { TYPE_ARRAY } },
transform(stmt`${type}.load(${index});`)
);
},
};
}
export default function arrayPlugin(): SemanticPlugin {
return { semantics };
}
|