| 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 |
23x
23x
23x
23x
90x
90x
90x
100x
100x
4x
96x
90x
643x
643x
643x
636x
7x
3x
7x
90x
173x
173x
173x
172x
1x
1x
90x
260x
260x
260x
260x
255x
5x
5x
5x
6x
5x
| /**
* Function pointer plugin.
* Handles function pointer declaration and indirect calls.
*
* @flow
*/
import Syntax from 'walt-syntax';
import { find } from 'walt-parser-tools/scope';
import { extendNode } from '../utils/extend-node';
import {
TYPE_INDEX,
GLOBAL_INDEX,
FUNCTION_INDEX,
} from '../semantics/metadata';
import type { SemanticPlugin } from '../flow/types';
export default function functionPointer(): SemanticPlugin {
return {
semantics() {
return {
// Handle Table definitions
[Syntax.ImmutableDeclaration]: next =>
function defineTable(args) {
const [decl, context] = args;
// Short circuit since memory is a special type of declaration
if (!context.locals && decl.type === 'Table') {
return {
...decl,
meta: {
...decl.meta,
[GLOBAL_INDEX]: -1,
},
};
}
return next(args);
},
[Syntax.Identifier]: next =>
function pointer(args) {
const [node, context] = args;
const { functions, table, scopes } = context;
if (find(scopes, node.value) || !functions[node.value]) {
return next(args);
}
if (table[node.value] == null) {
table[node.value] = functions[node.value];
}
return {
...node,
type: 'i32',
meta: {
[FUNCTION_INDEX]: functions[node.value].meta[FUNCTION_INDEX],
},
value: Object.keys(table).indexOf(node.value),
Type: Syntax.FunctionPointer,
};
},
[Syntax.FunctionResult]: next => (args, transform) => {
const [node, context] = args;
const { types } = context;
if (!types[node.type]) {
return next(args);
}
return next([
extendNode(
{
type: 'i32',
meta: { ALIAS: node.type },
params: node.params.map(p => transform([p, context])),
},
node
),
context,
]);
},
[Syntax.FunctionCall]: next =>
function indirectCall(args, transform) {
const [call, context] = args;
const { scopes, types } = context;
const ref = find(scopes, call.value);
// Nothing we need transform
if (!ref) {
return next(args);
}
const typedef = types[ref.type];
const typeIndex = Object.keys(types).indexOf(ref.type);
// We will short all of the other middleware so transform the parameters
// here and append an identifier which will be used to get the table
// value
const params = [
...call.params.slice(1),
{ ...ref, Type: Syntax.Identifier },
].map(p => transform([p, context]));
return {
...call,
meta: {
...call.meta,
...ref.meta,
[TYPE_INDEX]: typeIndex,
},
type: typedef != null ? typedef.type : call.type,
params,
Type: Syntax.IndirectFunctionCall,
};
},
};
},
};
}
|