| 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 |
23x
23x
23x
23x
90x
90x
90x
27x
27x
3x
3x
1x
2x
2x
38x
38x
38x
25x
25x
25x
25x
25x
13x
2x
2x
2x
11x
11x
13x
| /**
* Imports Plugin
*
* @flow
*/
import Syntax from 'walt-syntax';
import {
current,
add,
index as scopeIndex,
namespace,
} from 'walt-parser-tools/scope';
import { mapNode } from 'walt-parser-tools/map-node';
import { FUNCTION_INDEX, TYPE_INDEX, TYPE_CONST } from '../semantics/metadata';
import type { SemanticPlugin } from '../flow/types';
export default function Imports(): SemanticPlugin {
return {
semantics: () => ({
[Syntax.Import]: _next => args => {
const [node, context] = args;
return mapNode({
[Syntax.BinaryExpression]: (as, transform) => {
const [maybePair, asIdentifier] = as.params;
// if the original import is not typed this isn't a valid import and is ignored
if (maybePair.Type !== Syntax.Pair) {
// No transform happens here (the transform is what creates the global fn to reference)
return as;
}
// Continue transforming the import as before, the AS metadata will notify
// the generator to ask for the original import.
const [original, typeNode] = maybePair.params;
return transform({
...maybePair,
params: [
{
...asIdentifier,
meta: {
...original.meta,
// <new-value> AS <original-value>
AS: original.value,
},
},
typeNode,
],
});
},
[Syntax.Pair]: (pairNode, __) => {
const { types, functions } = context;
const [identifierNode, typeNode] = pairNode.params;
if (types[typeNode.value] != null) {
// crate a new type
const functionIndex = Object.keys(functions).length;
const typeIndex = Object.keys(types).indexOf(typeNode.value);
const functionNode = {
...identifierNode,
id: identifierNode.value,
type: types[typeNode.value].type,
meta: {
...identifierNode.meta,
[FUNCTION_INDEX]: functionIndex,
[TYPE_INDEX]: typeIndex,
FUNCTION_METADATA:
types[typeNode.value].meta.FUNCTION_METADATA,
DEFAULT_ARGUMENTS:
types[typeNode.value].meta.DEFAULT_ARGUMENTS,
},
};
functions[identifierNode.value] = functionNode;
return {
...pairNode,
params: [functionNode, types[typeNode.value]],
};
}
if (!['Table', 'Memory'].includes(typeNode.value)) {
const scope = current(context.scopes);
const index = scopeIndex(scope, identifierNode.value);
add(context.scopes, identifierNode.value, {
...identifierNode,
meta: { [scope[namespace]]: index, [TYPE_CONST]: true },
type: typeNode.type,
});
} else {
const bucket =
typeNode.value === 'Memory' ? 'memories' : 'tables';
context[bucket].push(identifierNode);
}
return pairNode;
},
})(node);
},
}),
};
}
|