arnaucube
arnaucube/circomPublic Self-hosted repository
circom/src/gencode.js
src/gencode.jsRaw
  1const bigInt = require("big-integer");
  2
  3module.exports = gen;
  4
  5
  6function ident(text) {
  7    let lines = text.split("\n");
  8    for (let i=0; i<lines.length; i++) {
  9        if (lines[i]) lines[i] = "    "+lines[i];
 10    }
 11    return lines.join("\n");
 12}
 13
 14function gen(ctx, ast) {
 15    if ((ast.type == "NUMBER") ) {
 16        return genNumber(ctx, ast);
 17    } else if (ast.type == "VARIABLE") {
 18        return genVariable(ctx, ast);
 19    } else if (ast.type == "PIN") {
 20        return genPin(ctx, ast);
 21    } else if (ast.type == "OP") {
 22        if (ast.op == "=") {
 23            return genVarAssignement(ctx, ast);
 24        } else if (ast.op == "<--") {
 25            return genVarAssignement(ctx, ast);
 26        } else if (ast.op == "<==") {
 27            return genSignalAssignConstrain(ctx, ast);
 28        } else if (ast.op == "===") {
 29            return genConstrain(ctx, ast);
 30        } else if (ast.op == "+=") {
 31            return genVarAddAssignement(ctx, ast);
 32        } else if (ast.op == "*=") {
 33            return genVarMulAssignement(ctx, ast);
 34        } else if (ast.op == "+") {
 35            return genAdd(ctx, ast);
 36        } else if (ast.op == "-") {
 37            return genSub(ctx, ast);
 38        } else if (ast.op == "UMINUS") {
 39            return genUMinus(ctx, ast);
 40        } else if (ast.op == "*") {
 41            return genMul(ctx, ast);
 42        } else if (ast.op == "PLUSPLUSRIGHT") {
 43            return genPlusPlusRight(ctx, ast);
 44        } else if (ast.op == "PLUSPLUSLEFT") {
 45            return genPlusPlusLeft(ctx, ast);
 46        } else if (ast.op == "**") {
 47            return genExp(ctx, ast);
 48        } else if (ast.op == "&") {
 49            return genBAnd(ctx, ast);
 50        } else if (ast.op == "<<") {
 51            return genShl(ctx, ast);
 52        } else if (ast.op == ">>") {
 53            return genShr(ctx, ast);
 54        } else if (ast.op == "<") {
 55            return genLt(ctx, ast);
 56        } else if (ast.op == "==") {
 57            return genEq(ctx, ast);
 58        } else if (ast.op == "?") {
 59            return genTerCon(ctx, ast);
 60        } else {
 61            error(ctx, ast, "Invalid operation: " + ast.op);
 62        }
 63    } else if (ast.type == "DECLARE") {
 64        if (ast.declareType == "COMPONENT") {
 65            return genDeclareComponent(ctx, ast);
 66        } else if ((ast.declareType == "SIGNALIN")||
 67                   (ast.declareType == "SIGNALOUT")||
 68                   (ast.declareType == "SIGNAL")) {
 69            return genDeclareSignal(ctx, ast);
 70        } else if (ast.declareType == "VARIABLE") {
 71            return genDeclareVariable(ctx, ast);
 72        } else {
 73            error(ctx, ast, "Invalid declaration: " + ast.declareType);
 74        }
 75    } else if (ast.type == "FUNCTIONCALL") {
 76        return genFunctionCall(ctx, ast);
 77    } else if (ast.type == "BLOCK") {
 78        return genBlock(ctx, ast);
 79    } else if (ast.type == "FOR") {
 80        return genFor(ctx, ast);
 81    } else if (ast.type == "WHILE") {
 82        return genWhile(ctx, ast);
 83    } else if (ast.type == "RETURN") {
 84        return genReturn(ctx, ast);
 85    } else if (ast.type == "TEMPLATEDEF") {
 86        return genTemplateDef(ctx, ast);
 87    } else if (ast.type == "FUNCTIONDEF") {
 88        return genFunctionDef(ctx, ast);
 89    } else if (ast.type == "INCLUDE") {
 90        return genInclude(ctx, ast);
 91    } else if (ast.type == "ARRAY") {
 92        return genArray(ctx, ast);
 93    } else {
 94        error(ctx, ast, "GEN -> Invalid AST node type: " + ast.type);
 95    }
 96}
 97
 98
 99function error(ctx, ast, errStr) {
100    ctx.error = {
101        pos:   {
102            first_line: ast.first_line,
103            first_column: ast.first_column,
104            last_line: ast.last_line,
105            last_column: ast.last_column
106        },
107        errStr: errStr,
108        ast: ast
109    };
110}
111
112
113function getScope(ctx, name) {
114    for (let i=ctx.scopes.length-1; i>=0; i--) {
115        if (ctx.scopes[i][name]) return ctx.scopes[i][name];
116    }
117    return null;
118}
119
120
121function genFunctionCall(ctx, ast) {
122    let S = "[";
123    for (let i=0; i<ast.params.length; i++) {
124        if (i>0) S += ",";
125        S += gen(ctx, ast.params[i]);
126    }
127    S+="]";
128
129    return `ctx.callFunction("${ast.name}", ${S})`;
130}
131
132function genBlock(ctx, ast) {
133    let body = "";
134    for (let i=0; i<ast.statements.length; i++) {
135        const l = gen(ctx, ast.statements[i]);
136        if (ctx.error) return;
137        if (l) {
138            body += l;
139            if (body[body.length-1] != "\n") body += ";\n";
140        }
141    }
142    return "{\n"+ident(body)+"}\n";
143}
144
145function genTemplateDef(ctx, ast) {
146    let S = "function(ctx) ";
147
148    const newScope = {};
149    for (let i=0; i< ast.params.length; i++) {
150        newScope[ast.params[i]] = { type: "VARIABLE" };
151    }
152
153    ctx.scopes.push(newScope);
154    S += genBlock(ctx, ast.block);
155    ctx.scopes.pop();
156
157//    const scope = ctx.scopes[ctx.scopes.length-1];
158    const scope = ctx.scopes[0];  // Scope for templates is top
159
160    scope[ast.name] = {
161        type: "TEMPLATE"
162    };
163
164    ctx.templates[ast.name] = S;
165    return "";
166}
167
168function genFunctionDef(ctx, ast) {
169    let S = "function(ctx) ";
170
171    const newScope = {};
172    const params = [];
173    for (let i=0; i< ast.params.length; i++) {
174        newScope[ast.params[i]] = { type: "VARIABLE" };
175        params.push(ast.params[i]);
176    }
177
178    ctx.scopes.push(newScope);
179    S += genBlock(ctx, ast.block);
180    ctx.scopes.pop();
181
182//     const scope = ctx.scopes[0]; // Scope for templates is top
183    const scope = ctx.scopes[ctx.scopes.length-1];
184
185    scope[ast.name] = {
186        type: "FUNCTION"
187    };
188
189    ctx.functions[ast.name] = S;
190    ctx.functionParams[ast.name] = params;
191    return "";
192}
193
194function genFor(ctx, ast) {
195    const init = gen(ctx, ast.init);
196    if (ctx.error) return;
197    const condition = gen(ctx, ast.condition);
198    if (ctx.error) return;
199    const step = gen(ctx, ast.step);
200    if (ctx.error) return;
201    const body = gen(ctx, ast.body);
202    if (ctx.error) return;
203    return `for (${init};${condition};${step})\n${body}`;
204}
205
206function genWhile(ctx, ast) {
207    const condition = gen(ctx, ast.condition);
208    if (ctx.error) return;
209    const body = gen(ctx, ast.body);
210    if (ctx.error) return;
211    return `while (${condition})\n${body}`;
212}
213
214function genReturn(ctx, ast) {
215    const value = gen(ctx, ast.value);
216    if (ctx.error) return;
217    return `return ${value};`;
218}
219
220function genDeclareComponent(ctx, ast) {
221    const scope = ctx.scopes[ctx.scopes.length - 1];
222
223    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
224    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
225
226    scope[ast.name.name] = {
227        type: "COMPONENT"
228    };
229
230    return "";
231}
232
233function genDeclareSignal(ctx, ast) {
234    const scope = ctx.scopes[ctx.scopes.length-1];
235
236    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
237    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
238
239    scope[ast.name.name] = {
240        type: "SIGNAL"
241    };
242
243    return "";
244}
245
246function genDeclareVariable(ctx, ast) {
247    const scope = ctx.scopes[ctx.scopes.length-1];
248
249    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
250    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
251
252    scope[ast.name.name] = {
253        type: "VARIABLE"
254    };
255
256    return "";
257}
258
259function genNumber(ctx, ast) {
260    return `"${ast.value.toString()}"`;
261}
262
263function genVariable(ctx, ast) {
264    const v = getScope(ctx, ast.name);
265
266    const sels = [];
267    for (let i=0; i<ast.selectors.length; i++) {
268        sels.push(gen(ctx, ast.selectors[i]));
269        if (ctx.error) return;
270    }
271
272
273    if (v.type == "VARIABLE") {
274        return `ctx.getVar("${ast.name}",[${sels.join(",")}])`;
275    } else if (v.type == "SIGNAL") {
276        return `ctx.getSignal("${ast.name}", [${sels.join(",")}])`;
277    } else {
278        error(ctx, ast, "Invalid Variable type");
279    }
280}
281
282function genPin(ctx, ast) {
283    let componentName = ast.component.name;
284    let componentSelectors = [];
285    for (let i=0; i<ast.component.selectors.length; i++) {
286        componentSelectors.push(gen(ctx, ast.component.selectors[i]));
287    }
288    componentSelectors = "["+ componentSelectors.join(",") + "]";
289    let pinName = ast.pin.name;
290    let pinSelectors = [];
291    for (let i=0; i<ast.pin.selectors.length; i++) {
292        pinSelectors.push(gen(ctx, ast.pin.selectors[i]));
293    }
294    pinSelectors = "["+ pinSelectors.join(",") + "]";
295    return `ctx.getPin("${componentName}", ${componentSelectors}, "${pinName}", ${pinSelectors})`;
296}
297
298function genVarAssignement(ctx, ast) {
299
300    const sels = [];
301    let vName;
302
303    if (ctx.error) return;
304
305    if (ast.values[0].type == "PIN") {
306        let componentName = ast.values[0].component.name;
307        let componentSelectors = [];
308        for (let i=0; i<ast.values[0].component.selectors.length; i++) {
309            componentSelectors.push(gen(ctx, ast.values[0].component.selectors[i]));
310        }
311        componentSelectors = "["+ componentSelectors.join(",") + "]";
312        let pinName = ast.values[0].pin.name;
313        let pinSelectors = [];
314        for (let i=0; i<ast.values[0].pin.selectors.length; i++) {
315            pinSelectors.push(gen(ctx, ast.values[0].pin.selectors[i]));
316        }
317        pinSelectors = "["+ pinSelectors.join(",") + "]";
318        const res = gen(ctx, ast.values[1]);
319        return `ctx.setPin("${componentName}", ${componentSelectors}, "${pinName}", ${pinSelectors}, ${res})`;
320    }
321
322    if (ast.values[0].type == "DECLARE") {
323        gen(ctx, ast.values[0]);
324        if (ctx.error) return;
325        vName = ast.values[0].name.name;
326    } else {
327        vName = ast.values[0].name;
328        for (let i=0; i<ast.values[0].selectors.length; i++) {
329            sels.push(gen(ctx, ast.values[0].selectors[i]));
330            if (ctx.error) return;
331        }
332    }
333
334
335    const v = getScope(ctx, vName);
336
337    // Component instantiation is already done.
338    if (v.type == "COMPONENT") return "";
339
340    const res = gen(ctx, ast.values[1]);
341    if (v.type == "VARIABLE") {
342        return `ctx.setVar("${vName}", [${sels.join(",")}], ${res})`;
343    } else if (v.type == "SIGNAL") {
344        return `ctx.setSignal("${vName}", [${sels.join(",")}], ${res})`;
345    } else {
346        return error(ctx, ast, "Assigning to invalid");
347    }
348}
349
350function genConstrain(ctx, ast) {
351    const a = gen(ctx, ast.values[0]);
352    if (ctx.error) return;
353    const b = gen(ctx, ast.values[1]);
354    if (ctx.error) return;
355    return `ctx.assert(${a}, ${b})`;
356}
357
358function genSignalAssignConstrain(ctx, ast) {
359    return genVarAssignement(ctx, ast) + ";\n" + genConstrain(ctx, ast);
360}
361
362function genVarAddAssignement(ctx, ast) {
363    return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]});
364}
365
366function genVarMulAssignement(ctx, ast) {
367    return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]});
368}
369
370function genPlusPlusRight(ctx, ast) {
371    return `(${genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`;
372}
373
374function genPlusPlusLeft(ctx, ast) {
375    return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]});
376}
377
378function genAdd(ctx, ast) {
379    const a = gen(ctx, ast.values[0]);
380    if (ctx.error) return;
381    const b = gen(ctx, ast.values[1]);
382    if (ctx.error) return;
383    return `bigInt(${a}).add(bigInt(${b})).mod(__P__)`;
384}
385
386function genMul(ctx, ast) {
387    const a = gen(ctx, ast.values[0]);
388    if (ctx.error) return;
389    const b = gen(ctx, ast.values[1]);
390    if (ctx.error) return;
391    return `bigInt(${a}).mul(bigInt(${b})).mod(__P__)`;
392}
393
394function genSub(ctx, ast) {
395    const a = gen(ctx, ast.values[0]);
396    if (ctx.error) return;
397    const b = gen(ctx, ast.values[1]);
398    if (ctx.error) return;
399    return `bigInt(${a}).add(__P__).sub(bigInt(${b})).mod(__P__)`;
400}
401
402function genExp(ctx, ast) {
403    const a = gen(ctx, ast.values[0]);
404    if (ctx.error) return;
405    const b = gen(ctx, ast.values[1]);
406    if (ctx.error) return;
407    return `bigInt(${a}).modPow(bigInt(${b}), __P__)`;
408}
409
410function genBAnd(ctx, ast) {
411    const a = gen(ctx, ast.values[0]);
412    if (ctx.error) return;
413    const b = gen(ctx, ast.values[1]);
414    if (ctx.error) return;
415    return `bigInt(${a}).and(bigInt(${b})).and(__MASK__)`;
416}
417
418function genShl(ctx, ast) {
419    const a = gen(ctx, ast.values[0]);
420    if (ctx.error) return;
421    const b = gen(ctx, ast.values[1]);
422    if (ctx.error) return;
423    return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shl(bigInt(${b})).and(__MASK__)`;
424}
425
426function genShr(ctx, ast) {
427    const a = gen(ctx, ast.values[0]);
428    if (ctx.error) return;
429    const b = gen(ctx, ast.values[1]);
430    if (ctx.error) return;
431    return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shr(bigInt(${b})).and(__MASK__)`;
432}
433
434function genLt(ctx, ast) {
435    const a = gen(ctx, ast.values[0]);
436    if (ctx.error) return;
437    const b = gen(ctx, ast.values[1]);
438    if (ctx.error) return;
439    return `bigInt(${a}).lt(bigInt(${b})) ? 1 : 0`;
440}
441
442function genEq(ctx, ast) {
443    const a = gen(ctx, ast.values[0]);
444    if (ctx.error) return;
445    const b = gen(ctx, ast.values[1]);
446    if (ctx.error) return;
447    return `bigInt(${a}).eq(bigInt(${b})) ? 1 : 0`;
448}
449
450function genUMinus(ctx, ast) {
451    const a = gen(ctx, ast.values[0]);
452    if (ctx.error) return;
453    return `__P__.sub(bigInt(${a})).mod(__P__)`;
454}
455
456function genTerCon(ctx, ast) {
457    const a = gen(ctx, ast.values[0]);
458    if (ctx.error) return;
459    const b = gen(ctx, ast.values[1]);
460    if (ctx.error) return;
461    const c = gen(ctx, ast.values[2]);
462    if (ctx.error) return;
463    return `bigInt(${a}).neq(bigInt(0)) ? (${b}) : (${c})`;
464}
465
466function genInclude(ctx, ast) {
467    return ast.block ? gen(ctx, ast.block) : "";
468}
469
470function genArray(ctx, ast) {
471    let S = "[";
472    for (let i=0; i<ast.values.length; i++) {
473        if (i>0) S += ",";
474        S += gen(ctx, ast.values[i]);
475    }
476    S+="]";
477    return S;
478}
479