/*
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;
}