1
1
import { SimpleIdentifierListContext } from "../generated" ;
2
+ import {
3
+ CircomValueType ,
4
+ VariableContext ,
5
+ VariableContextWithNull ,
6
+ } from "../types" ;
2
7
3
8
export function parseSimpleIdentifierList (
4
9
ctx : SimpleIdentifierListContext ,
@@ -15,3 +20,115 @@ export function parseSimpleIdentifierList(
15
20
16
21
return result ;
17
22
}
23
+
24
+ export function buildVariableContext (
25
+ names : string [ ] ,
26
+ values : CircomValueType [ ] ,
27
+ ) : VariableContext {
28
+ if ( names . length !== values . length ) {
29
+ throw new Error ( "Names and values must have the same length" ) ;
30
+ }
31
+
32
+ const context : VariableContext = { } ;
33
+
34
+ for ( let i = 0 ; i < names . length ; i ++ ) {
35
+ const bindContext = bindVariableContext (
36
+ names [ i ] ,
37
+ getArrayDimensions ( values [ i ] ) ,
38
+ values [ i ] ,
39
+ ) ;
40
+
41
+ for ( const key in bindContext ) {
42
+ if ( bindContext [ key ] !== null ) {
43
+ context [ key ] = bindContext [ key ] ;
44
+ }
45
+ }
46
+ }
47
+
48
+ return context ;
49
+ }
50
+
51
+ export function getArrayDimensions ( value : CircomValueType ) : number [ ] {
52
+ if ( Array . isArray ( value ) ) {
53
+ return [ value . length , ...getArrayDimensions ( value [ 0 ] ) ] ;
54
+ }
55
+
56
+ return [ ] ;
57
+ }
58
+
59
+ export function bindVariableContext (
60
+ variableName : string ,
61
+ dimensions : number [ ] ,
62
+ values : CircomValueType ,
63
+ ) : VariableContextWithNull {
64
+ const context : VariableContextWithNull = { } ;
65
+ const resolved = resolveDimensions ( variableName , dimensions ) ;
66
+
67
+ for ( const variable of resolved ) {
68
+ try {
69
+ context [ variable ] = parseVariable (
70
+ values ,
71
+ variable . replace ( variableName , "" ) ,
72
+ ) ;
73
+ } catch {
74
+ context [ variable ] = null ;
75
+ }
76
+ }
77
+
78
+ return context ;
79
+ }
80
+
81
+ export function resolveDimensions (
82
+ variableName : string ,
83
+ dimensions : number [ ] ,
84
+ ) : string [ ] {
85
+ return internalResolveDimensions ( [ variableName ] , dimensions , 0 ) ;
86
+ }
87
+
88
+ // reference MUST be similar to [0][1]
89
+ function parseVariable (
90
+ value : CircomValueType ,
91
+ reference : string ,
92
+ ) : CircomValueType {
93
+ const parts = reference
94
+ . split ( "[" )
95
+ . map ( ( part ) => part . replace ( "]" , "" ) )
96
+ . filter ( ( part ) => part !== "" )
97
+ . map ( ( part ) => parseInt ( part ) ) ;
98
+
99
+ return getReferenceValueInternal ( value , parts ) ;
100
+ }
101
+
102
+ function getReferenceValueInternal (
103
+ value : CircomValueType ,
104
+ reference : number [ ] ,
105
+ ) : CircomValueType {
106
+ if ( reference . length === 0 ) {
107
+ return value ;
108
+ }
109
+
110
+ if ( ! Array . isArray ( value ) ) {
111
+ throw new Error ( "INTERNAL ERROR! Reference is invalid" ) ;
112
+ }
113
+
114
+ return getReferenceValueInternal ( value [ reference [ 0 ] ] , reference . slice ( 1 ) ) ;
115
+ }
116
+
117
+ function internalResolveDimensions (
118
+ variables : string [ ] ,
119
+ dimensions : number [ ] ,
120
+ layer : number ,
121
+ ) : string [ ] {
122
+ if ( layer >= dimensions . length ) {
123
+ return variables ;
124
+ }
125
+
126
+ const result : string [ ] = [ ] ;
127
+ for ( let i = 0 ; i < dimensions [ layer ] ; i ++ ) {
128
+ for ( const variable of variables ) {
129
+ result . push ( `${ variable } [${ i } ]` ) ;
130
+ }
131
+ }
132
+
133
+ return internalResolveDimensions ( result , dimensions , layer + 1 ) ;
134
+ }
0 commit comments