| 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
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 |
23x
23x
23x
23x
23x
23x
2x
2x
2x
6x
2x
90x
90x
90x
90x
2x
2x
2x
2x
6x
6x
6x
6x
6x
6x
2x
2x
2x
2x
2x
90x
42x
21x
17x
4x
4x
90x
68x
68x
90x
181x
181x
181x
181x
84x
181x
| /**
* Static value plugin
*
* @flow
*/
import Syntax from 'walt-syntax';
import { stringEncoder } from '../utils/string';
import OutputStream from '../utils/output-stream';
import wasmTypes from 'wasm-types';
import type { SemanticPlugin } from '../flow/types';
const escapeMap = {
['\\0']: 0x00,
['\\a']: 0x07,
['\\b']: 0x08,
['\\t']: 0x09,
['\\n']: 0x0a,
['\\v']: 0x0b,
['\\f']: 0x0c,
['\\r']: 0x0d,
["\\'"]: 0x27,
};
const sizeMap = {
i64: 8,
f64: 8,
i32: 4,
f32: 4,
};
function encodeArray(array, type) {
const stream = new OutputStream();
const encodeType = wasmTypes[type];
array.forEach(v => {
stream.push(encodeType, v, String(v));
});
return stream;
}
export default function Strings(): SemanticPlugin {
let count = 0;
return {
semantics: ({ stmt }) => ({
[Syntax.StaticDeclaration]: _next => ([node, context], transform) => {
const { userTypes, statics } = context;
const bareType = String(node.type).slice(0, -2);
const typeSize = sizeMap[bareType];
const meta = node.params.reduce(
(acc, v, i) => {
const n = transform([v, context]);
acc.OBJECT_SIZE += typeSize;
acc.TYPE_OBJECT[i] = i * typeSize;
acc.OBJECT_KEY_TYPES[i] = bareType;
acc.VALUES.push(Number(n.value));
return acc;
},
{
OBJECT_SIZE: 0,
TYPE_OBJECT: {},
OBJECT_KEY_TYPES: {},
VALUES: [],
STATIC: bareType,
}
);
const uid = `__auto_gen_${node.value}_${count}`;
count += 1;
userTypes[uid] = {
...node,
value: uid,
Type: Syntax.Type,
meta,
params: [],
};
statics[uid] = encodeArray(meta.VALUES, bareType);
// Short circuit the middleware and instead transform a declaration
return transform([
{
...node,
meta,
type: uid,
Type: Syntax.ImmutableDeclaration,
params: [
{
...node.params[0],
value: uid,
Type: Syntax.StaticValueList,
},
],
},
context,
]);
},
[Syntax.ArraySubscript]: next => ([node, context], transform) => {
const [target, offset] = node.params.map(p => transform([p, context]));
if (!target.meta.STATIC) {
return next([node, context]);
}
const shift = { i32: 2, f32: 2, i64: 3, f64: 3 }[target.meta.STATIC];
return transform([
stmt`${
target.meta.STATIC
}.load(${target} + (${offset} << ${shift}));`,
context,
]);
},
[Syntax.CharacterLiteral]: _ => ([node, context], transform) => {
const codePoint = escapeMap[node.value] || node.value.codePointAt(0);
return transform([
{
...node,
Type: 'Constant',
type: 'i32',
value: String(codePoint),
},
context,
]);
},
[Syntax.StringLiteral]: _ignore => args => {
const [stringLiteral, context] = args;
const { statics } = context;
const { value } = stringLiteral;
// did we already encode the static?
if (!(value in statics)) {
statics[value] = stringEncoder(value);
}
// It's too early to transform a string at this point
// we need additional information, only available in the generator.
// This also avoids doing the work in two places, in semantics AND gen
return stringLiteral;
},
}),
};
}
|