/* Copyright 2018 0KIMS association. This file is part of circom (Zero Knowledge Circuit Compiler). circom is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. circom is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with circom. If not, see . */ const bigInt = require("big-integer"); module.exports = gen; function ident(text) { let lines = text.split("\n"); for (let i=0; i>") { return genShr(ctx, ast); } else if (ast.op == "<") { return genLt(ctx, ast); } else if (ast.op == ">") { return genGt(ctx, ast); } else if (ast.op == "<=") { return genLte(ctx, ast); } else if (ast.op == ">=") { return genGte(ctx, ast); } else if (ast.op == "==") { return genEq(ctx, ast); } else if (ast.op == "!=") { return genNeq(ctx, ast); } else if (ast.op == "?") { return genTerCon(ctx, ast); } else { error(ctx, ast, "Invalid operation: " + ast.op); } } else if (ast.type == "DECLARE") { if (ast.declareType == "COMPONENT") { return genDeclareComponent(ctx, ast); } else if ((ast.declareType == "SIGNALIN")|| (ast.declareType == "SIGNALOUT")|| (ast.declareType == "SIGNAL")) { return genDeclareSignal(ctx, ast); } else if (ast.declareType == "VARIABLE") { return genDeclareVariable(ctx, ast); } else { error(ctx, ast, "Invalid declaration: " + ast.declareType); } } else if (ast.type == "FUNCTIONCALL") { return genFunctionCall(ctx, ast); } else if (ast.type == "BLOCK") { return genBlock(ctx, ast); } else if (ast.type == "COMPUTE") { return genCompute(ctx, ast); } else if (ast.type == "FOR") { return genFor(ctx, ast); } else if (ast.type == "WHILE") { return genWhile(ctx, ast); } else if (ast.type == "IF") { return genIf(ctx, ast); } else if (ast.type == "RETURN") { return genReturn(ctx, ast); } else if (ast.type == "TEMPLATEDEF") { return genTemplateDef(ctx, ast); } else if (ast.type == "FUNCTIONDEF") { return genFunctionDef(ctx, ast); } else if (ast.type == "INCLUDE") { return genInclude(ctx, ast); } else if (ast.type == "ARRAY") { return genArray(ctx, ast); } else { error(ctx, ast, "GEN -> Invalid AST node type: " + ast.type); } } function error(ctx, ast, errStr) { ctx.error = { pos: { first_line: ast.first_line, first_column: ast.first_column, last_line: ast.last_line, last_column: ast.last_column }, errStr: errStr, ast: ast, message: errStr }; } function getScope(ctx, name) { for (let i=ctx.scopes.length-1; i>=0; i--) { if (ctx.scopes[i][name]) return ctx.scopes[i][name]; } return null; } function genFunctionCall(ctx, ast) { let S = "["; for (let i=0; i0) S += ","; S += gen(ctx, ast.params[i]); } S+="]"; return `ctx.callFunction("${ast.name}", ${S})`; } function genBlock(ctx, ast) { let body = ""; for (let i=0; i { return ctx.c.getLocal(ast.params[i].name); }, setter: (v) => { return ctx.c.setLocal(ast.params[i].name, v); } }; } genBlock(ctx, ast.block); ctx.scope = null; ctx.c = null; ctx.f = null; } function genFunctionDef(ctx, ast) { let S = "function(ctx) "; const newScope = {}; const params = []; for (let i=0; i< ast.params.length; i++) { newScope[ast.params[i]] = { type: "VARIABLE" }; params.push(ast.params[i]); } ctx.scopes.push(newScope); S += genBlock(ctx, ast.block); ctx.scopes.pop(); // const scope = ctx.scopes[0]; // Scope for templates is top const scope = ctx.scopes[ctx.scopes.length-1]; scope[ast.name] = { type: "FUNCTION" }; ctx.functions[ast.name] = S; ctx.functionParams[ast.name] = params; return ""; } function genFor(ctx, ast) { ctx.scopes.push({}); const init = gen(ctx, ast.init); if (ctx.error) return; const condition = gen(ctx, ast.condition); if (ctx.error) return; const step = gen(ctx, ast.step); if (ctx.error) return; const body = gen(ctx, ast.body); if (ctx.error) return; ctx.scopes.pop(); return `for (${init};bigInt(${condition}).neq(bigInt(0));${step}) { \n${body}\n }\n`; } function genWhile(ctx, ast) { const condition = gen(ctx, ast.condition); if (ctx.error) return; const body = gen(ctx, ast.body); if (ctx.error) return; return `while (bigInt(${condition}).neq(bigInt(0))) {\n${body}\n}\n`; } function genCompute(ctx, ast) { const body = gen(ctx, ast.body); if (ctx.error) return; return `{\n${body}\n}\n`; } function genIf(ctx, ast) { const condition = gen(ctx, ast.condition); if (ctx.error) return; const thenBody = gen(ctx, ast.then); if (ctx.error) return; if (ast.else) { const elseBody = gen(ctx, ast.else); if (ctx.error) return; return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n} else {\n${elseBody}\n}\n`; } else { return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n}\n`; } } function genReturn(ctx, ast) { const value = gen(ctx, ast.value); if (ctx.error) return; return `return ${value};`; } function genDeclareComponent(ctx, ast) { const scope = ctx.scopes[ctx.scopes.length - 1]; if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); scope[ast.name.name] = { type: "COMPONENT" }; return ""; } function genDeclareSignal(ctx, ast) { const scope = ctx.scopes[ctx.scopes.length-1]; if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); scope[ast.name.name] = { type: "SIGNAL" }; return ""; } function genDeclareVariable(ctx, ast) { const scope = ctx.scopes[ctx.scopes.length-1]; if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); scope[ast.name.name] = { type: "VARIABLE" }; return ""; } function genNumber(ctx, ast) { return `"${ast.value.toString()}"`; } function genVariable(ctx, ast) { const v = getScope(ctx, ast.name); const sels = []; for (let i=0; i0) S += ","; S += gen(ctx, ast.values[i]); } S+="]"; return S; }