-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcommon.ts
More file actions
134 lines (111 loc) · 2.89 KB
/
common.ts
File metadata and controls
134 lines (111 loc) · 2.89 KB
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
import { SimpleIdentifierListContext } from "../generated";
import {
CircomValueType,
VariableContext,
VariableContextWithNull,
} from "../types";
export function parseSimpleIdentifierList(
ctx: SimpleIdentifierListContext,
): string[] {
const result: string[] = [];
if (ctx === null || ctx === undefined) {
return result;
}
ctx.ID_list().forEach((node) => {
result.push(node.getText());
});
return result;
}
export function buildVariableContext(
names: string[],
values: CircomValueType[],
): VariableContext {
if (names.length !== values.length) {
throw new Error("Names and values must have the same length");
}
const context: VariableContext = {};
for (let i = 0; i < names.length; i++) {
const bindContext = bindVariableContext(
names[i],
getArrayDimensions(values[i]),
values[i],
);
for (const key in bindContext) {
if (bindContext[key] !== null) {
context[key] = bindContext[key];
}
}
}
return context;
}
export function getArrayDimensions(value: CircomValueType): number[] {
if (Array.isArray(value)) {
return [value.length, ...getArrayDimensions(value[0])];
}
return [];
}
export function bindVariableContext(
variableName: string,
dimensions: number[],
values: CircomValueType,
): VariableContextWithNull {
const context: VariableContextWithNull = {};
const resolved = resolveDimensions(variableName, dimensions);
for (const variable of resolved) {
try {
context[variable] = parseVariable(
values,
variable.replace(variableName, ""),
);
} catch {
context[variable] = null;
}
}
return context;
}
export function resolveDimensions(
variableName: string,
dimensions: number[],
): string[] {
return internalResolveDimensions([variableName], dimensions, 0);
}
// reference MUST be similar to [0][1]
function parseVariable(
value: CircomValueType,
reference: string,
): CircomValueType {
const parts = reference
.split("[")
.map((part) => part.replace("]", ""))
.filter((part) => part !== "")
.map((part) => parseInt(part));
return getReferenceValueInternal(value, parts);
}
function getReferenceValueInternal(
value: CircomValueType,
reference: number[],
): CircomValueType {
if (reference.length === 0) {
return value;
}
if (!Array.isArray(value)) {
throw new Error("INTERNAL ERROR! Reference is invalid");
}
return getReferenceValueInternal(value[reference[0]], reference.slice(1));
}
function internalResolveDimensions(
variables: string[],
dimensions: number[],
layer: number,
): string[] {
if (layer >= dimensions.length) {
return variables;
}
const result: string[] = [];
for (let i = 0; i < dimensions[layer]; i++) {
for (const variable of variables) {
result.push(`${variable}[${i}]`);
}
}
return internalResolveDimensions(result, dimensions, layer + 1);
}