From ff1c12bcc3e0ba4b91363284ec78719d314cffcf Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Sat, 7 Dec 2019 12:58:11 +0100 Subject: [PATCH] scopes work og in code generation --- src/c_build.js | 97 +++---- src/c_gen.js | 635 ++++++++++++++++++++++-------------------- src/ctx.js | 55 ++++ src/iterateast.js | 69 +++++ src/utils.js | 6 + test/circuits/in.json | 2 +- 6 files changed, 505 insertions(+), 359 deletions(-) create mode 100644 src/iterateast.js diff --git a/src/c_build.js b/src/c_build.js index 4dfc4f1..44ac485 100644 --- a/src/c_build.js +++ b/src/c_build.js @@ -21,7 +21,7 @@ const assert = require("assert"); const bigInt = require("big-integer"); const utils = require("./utils"); const gen = require("./c_gen").gen; -const newRef = require("./c_gen").newRef; +const createRefs = require("./c_gen").createRefs; module.exports = buildC; @@ -32,14 +32,12 @@ function buildC(ctx) { ctx.buildFunction = buildFunction; ctx.code = ""; ctx.conditionalCodeHeader = ""; - ctx.tmpNames = {}; - ctx.getTmpName = getTmpName; ctx.codes_sizes = []; ctx.definedSizes = {}; ctx.addSizes = addSizes; const entryTables = buildEntryTables(ctx); - ctx.globalNames = ctx.tmpNames; + ctx.globalNames = ctx.uniqueNames; const code = buildCode(ctx); const functions = buildFuncFunctions(ctx); @@ -72,7 +70,7 @@ function buildEntryTables(ctx) { const {htName, htMap} = addHashTable(i); let code = ""; - const componentEntriesTableName = ctx.getTmpName("entryTable_" + ctx.components[i].template); + const componentEntriesTableName = ctx.getUniqueName("_entryTable" + ctx.components[i].template); code += `Circom_ComponentEntry ${componentEntriesTableName}[${htMap.length}] = {\n`; for (let j=0; j 0)&&(str[p2-1] == "_")) p2--; - - return str.slice(p1,p2); - } - -} - function addSizes(_sizes) { const sizes = _sizes || []; let name = "sizes"; @@ -355,8 +338,8 @@ function addSizes(_sizes) { if (name=="sizes") name="sizes_0"; if (this.definedSizes[name]) return this.definedSizes[name]; - - const labelName = this.getTmpName(name); + name = "_" + name; + const labelName = this.getUniqueName(name); this.definedSizes[name] = labelName; const accSizes = utils.accSizes(sizes); @@ -382,21 +365,21 @@ function buildFunction(name, paramValues) { fnName: `${name}_${h}` }; - const oldScopes = ctx.scopes; + const oldRefs = ctx.refs; const oldConditionalCode = ctx.conditionalCode; const oldCode = ctx.code; const oldCodeHeader = ctx.codeHeader; const oldCodeFooter = ctx.codeFooter; - const oldTmpNames = ctx.tmpNames; + const oldUniqueNames = ctx.uniqueNames; - const scope = {_prefix : ""}; - ctx.scopes = [scope]; + ctx.scopes = [{}]; + ctx.refs = []; ctx.conditionalCode = false; ctx.code = ""; ctx.codeHeader = "// Header\n"; ctx.codeFooter = "// Footer\n"; - ctx.tmpNames = Object.assign({},ctx.globalNames); + ctx.uniqueNames = Object.assign({},ctx.globalNames); ctx.returnValue = null; ctx.returnSizes = null; @@ -406,26 +389,32 @@ function buildFunction(name, paramValues) { if (paramValues[i].used) { paramsStr += `,PBigInt ${ctx.functions[name].params[i]}`; - scope[ctx.functions[name].params[i]] = { - stack: true, + const idRef = ctx.refs.length; + ctx.refs.push({ type: "BIGINT", used: true, sizes: paramValues[i].sizes, label: ctx.functions[name].params[i], - }; + }); + ctx.scopes[0][ctx.functions[name].params[i]] = idRef; } else { - scope[ctx.functions[name].params[i]] = { - stack: true, + const idRef = ctx.refs.length; + ctx.refs.push({ type: "BIGINT", used: false, sizes: paramValues[i].sizes, label: ctx.functions[name].params[i], value: paramValues[i].value - }; + }); + ctx.scopes[0][ctx.functions[name].params[i]] = idRef; } } + createRefs(ctx, ctx.functions[name].block); + if (ctx.error) return; + gen(ctx, ctx.functions[name].block); + if (ctx.error) return; if (ctx.returnValue == null) { if (ctx.returnSizes == null) assert(false, `Funciont ${name} does not return any value`); @@ -448,12 +437,12 @@ function buildFunction(name, paramValues) { res.returnSizes = ctx.returnSizes; } - ctx.scopes = oldScopes; + ctx.refs = oldRefs; ctx.conditionalCode = oldConditionalCode; ctx.code = oldCode; ctx.codeHeader = oldCodeHeader; ctx.codeFooter = oldCodeFooter; - ctx.tmpNames = oldTmpNames; + ctx.uniqueNames = oldUniqueNames; ctx.definedFunctions[h] = res; @@ -508,7 +497,7 @@ function hashFunctionCall(ctx, name, paramValues) { const constParams = []; for (let i=0; iallocBigInts(${sizes[0]});\n`; + const label = ctx.getUniqueName("_const"); + ctx.codeHeader += `PBigInt ${label};\n`; + ctx.codeHeader += `${label} = ctx->allocBigInts(${sizes[0]});\n`; for (let i=0; ifreeBigInts(${res}, ${sizes[0]});\n`; - return res; + ctx.codeFooter += `ctx->freeBigInts(${label}, ${sizes[0]});\n`; + const refId = ctx.refs.length; + ctx.refs.push({ + type: "BIGINT", + used: true, + sizes: sizes, + label: label + }); + return refId; } -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 createRefs(ctx, ast) { + const scopeLabels = []; + iterateAST(ast, (ast, level) => { + while ((scopeLabels.length>0)&&(!scopeLabels[scopeLabels.length-1].startsWith(level))) { + ctx.scopes.pop(); + scopeLabels.pop(); + } + if (ast.type == "DECLARE") { + if (ctx.scopes[ctx.scopes.length-1][ast.name.name]) return ctx.throwError(ast, `Name already defined: ${ast.name.name}`); + for (let i=ctx.scopes.length-2; i>=0; i--) { + if (ctx.scopes[i][ast.name.name]) ctx.logWarning(ast, `Shadowing variable: ${ast.name.name}`); + } + let entry = {}; + if (ast.declareType == "COMPONENT") { + entry.type= "COMPONENT"; + entry.label = ast.name.name; + } else if ((ast.declareType == "SIGNALIN")|| + (ast.declareType == "SIGNALOUT")|| + (ast.declareType == "SIGNAL")) { + entry.type = "SIGNAL"; + entry.label = ast.name.name; + } else if (ast.declareType == "VARIABLE") { + entry.type = "BIGINT"; + entry.used = false; + entry.sizes = null; + entry.label = ctx.getUniqueName(ast.name.name); + } else { + return ctx.throwError(ast, "Invalid declaration: " + ast.declareType); + } + const refId = ctx.refs.length; + ctx.refs.push(entry); + ast.refId = refId; + ctx.scopes[ctx.scopes.length-1][ast.name.name] = refId; + } else if (["BLOCK", "FOR", "IF", "WHILE", "COMPUTE"].indexOf(ast.type) >= 0) { + scopeLabels.push(level); + ctx.scopes.push({}); + } else if (ast.type == "VARIABLE") { + ast.refId = name2ref(ast.name); + } + }); -function getScope(ctx, name) { - for (let i=ctx.scopes.length-1; i>=0; i--) { - if (ctx.scopes[i][name]) return ctx.scopes[i][name]; + function name2ref(n) { + for (let i=ctx.scopes.length-1; i>=0; i--) { + if (typeof ctx.scopes[i][n] !== "undefined") return ctx.scopes[i][n]; + } + return -1; } - return null; } - - function gen(ctx, ast) { if ((ast.type == "NUMBER") ) { return genNumber(ctx, ast); @@ -180,7 +202,7 @@ function gen(ctx, ast) { } else if (ast.op == "?") { return genTerCon(ctx, ast); } else { - error(ctx, ast, "Invalid operation: " + ast.op); + ctx.throwError(ast, "Invalid operation: " + ast.op); } } else if (ast.type == "DECLARE") { if (ast.declareType == "COMPONENT") { @@ -192,7 +214,7 @@ function gen(ctx, ast) { } else if (ast.declareType == "VARIABLE") { return genDeclareVariable(ctx, ast); } else { - error(ctx, ast, "Invalid declaration: " + ast.declareType); + ctx.throwError(ast, "Invalid declaration: " + ast.declareType); } } else if (ast.type == "FUNCTIONCALL") { return genFunctionCall(ctx, ast); @@ -213,12 +235,12 @@ function gen(ctx, ast) { } else if (ast.type == "ARRAY") { return genArray(ctx, ast); } else { - error(ctx, ast, "GEN -> Invalid AST node type: " + ast.type); + ctx.throwError(ast, "GEN -> Invalid AST node type: " + ast.type); } } function genBlock(ctx, ast) { - ctx.scopes.push({_prefix : ""}); + ctx.scopes.push({}); const oldCode = ctx.code; let res = null; ctx.code = ""; @@ -262,81 +284,43 @@ function genForSrcComment(ctx, ast) { 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", - label: ast.name.name - }; - - return ast.name.name; + return ast.refId; } 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); - - const res = { - type: "SIGNAL", - label: ast.name.name - }; - - scope[ast.name.name] = res; - - return res; + return ast.refId; } function genDeclareVariable(ctx, ast) { - const scope = ctx.scopes[ctx.scopes.length-1]; - - const varName = ast.name.name; - const labelName = scope._prefix + ast.name.name; - if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); - if (typeof scope[varName] != "undefined") return error(ctx, ast, "Name already exists: "+varName); + const v = ctx.refs[ast.refId]; let sizes; - if (ast.name.selectors.length>0) { sizes=[]; for (let i=0; i< ast.name.selectors.length; i++) { - const sizeName = gen(ctx, ast.name.selectors[i]); - const size = getScope(ctx, sizeName); - if (size.sizes[0] != 1) return error(ctx, ast, "A selector cannot be an array"); - if (ctx.error) return; - - if (size.used) { - return error(ctx, ast, "Variable size variables not allowed"); - } else { - sizes.push(size.value[0].toJSNumber()); - } + const sizeRef = gen(ctx, ast.name.selectors[i]); + const size = ctx.refs[sizeRef]; + if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array"); + if (size.used) return ctx.throwError(ast, "Variable size variables not allowed"); + sizes.push(size.value[0].toJSNumber()); } sizes = utils.accSizes(sizes); } else { sizes = null; // If not sizes, the sized are defined in the first assignement. } - const res = scope[varName] = { - stack: true, - type: "BIGINT", - sizes: sizes, - label: labelName, - used: false, - }; - - if (sizes) { - res.value = new Array(sizes[0]); + if ((!v.sizes)&&(sizes)) { + v.sizes = sizes; + v.value = new Array(sizes[0]); } - scope[varName] = res; + if (v.sizes) { + if (!utils.sameSizes(v.sizes, sizes)) return ctx.throwError(ast, "Redefined a var with different sized"); + } - return varName; + return ast.refId; } function genNumber(ctx, ast) { @@ -345,36 +329,36 @@ function genNumber(ctx, ast) { -function genGetOffset(ctx, vOffset, vSizes, sels) { +function genGetOffset(ctx, refOffset, vSizes, sels) { let rN = 0; let rStr = ""; - let iOffset; + let offset; - if (vOffset) { - iOffset = getScope(ctx, vOffset); - if (iOffset.used) { - rStr += iOffset.label; + if (refOffset) { + offset = ctx.refs[refOffset]; + if (offset.used) { + rStr += offset.label; } else { - rN += iOffset.value.toJSNumber(); + rN += offset.value.toJSNumber(); } } if ((sels)&&(sels.length>0)) { let iSizes; - if (typeof vSizes == "string") { - iSizes = getScope(ctx, vSizes); - } else { + if (Array.isArray(vSizes)) { iSizes = { used: false, sizes: vSizes }; + } else { + iSizes = ctx.refs[vSizes]; } for (let i=0; i0) { - const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", ast.name); - const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", ast.name); + const vsOffset = genGetSigalOffset(ctx, -1, ast.name); + const vsSizes = genGetSignalSizes(ctx, -1, ast.name); vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors ); } else { - vOffset = genGetSigalOffset(ctx, "ctx->cIdx", ast.name); + vOffset = genGetSigalOffset(ctx, -1, ast.name); } - return genGetSignal(ctx, "ctx->cIdx", vOffset); + return genGetSignal(ctx, -1, vOffset); } else if (v.type == "BIGINT") { - const vOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors ); - const offset = getScope(ctx, vOffset); + const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors ); + const offset = ctx.refs[refOffset]; if (v.used) { if (offset.used) { - const resN = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); - const res = getScope(ctx, resN); + const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); + const res = ctx.refs[refRes]; res.used = true; ctx.codeHeader += `PBigInt ${res.label};\n`; - ctx.code += `${res.label} = ${ast.name} + ${offset.label};\n`; - return resN; - } else if (offset.value) { - const resN = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); - const res = getScope(ctx, resN); + ctx.code += `${res.label} = ${v.label} + ${offset.label};\n`; + return refRes; + } else if ((offset.value[0])||(l>0)) { + const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); + const res = ctx.refs[refRes]; res.used = true; ctx.codeHeader += `PBigInt ${res.label};\n`; - ctx.code += `${res.label} = ${ast.name} + ${offset.value};\n`; - return resN; + ctx.code += `${res.label} = ${v.label} + ${offset.value[0]};\n`; + return refRes; } else { - return ast.name; + return ast.refId; } } else { if (offset.used) { - instantiateRef(ctx, ast.name, v.value); - const res = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); + instantiateRef(ctx, ast.refId, v.value); + const resRef = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); + const res = ctx.refs[resRef]; res.used = true; ctx.codeHeader += `PBigInt ${res};\n`; - ctx.code += `${res} = ${ast.name} + ${offset.label};\n`; + ctx.code += `${res.label} = ${v.label} + ${offset.label};\n`; return res; } else { // return newSubRef(ctx, ast.name, ast.selectors); @@ -472,34 +458,17 @@ function genVariable(ctx, ast) { } } } - - const sels = []; - for (let i=0; i0) { - const vcOffset = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.component.name); - const vcSizes = genGetSubComponentSizes(ctx, "ctx->cIdx", ast.component.name); + const vcOffset = genGetSubComponentOffset(ctx, -1, ast.component.name); + const vcSizes = genGetSubComponentSizes(ctx, -1, ast.component.name); vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.component.selectors ); } else { - vcIdx = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.component.name); + vcIdx = genGetSubComponentOffset(ctx, -1, ast.component.name); } let vsIdx; @@ -514,67 +483,116 @@ function genPin(ctx, ast) { return genGetSignal(ctx, vcIdx, vsIdx); } -function genGetSubComponentOffset(ctx, cIdx, label) { - const vOffset = newRef(ctx, "INT", "_compIdx"); - instantiateRef(ctx, vOffset); +function genGetSubComponentOffset(ctx, cIdxRef, label) { + const refOffset = newRef(ctx, "INT", "_compIdx"); + const offset = ctx.refs[refOffset]; + instantiateRef(ctx, refOffset); const h = utils.fnvHash(label); - ctx.code += `${vOffset} = ctx->getSubComponentOffset(${cIdx}, 0x${h}LL /* ${label} */);\n`; - return vOffset; + let s; + if (cIdxRef>=0) { + const cIdx = ctx.refs[cIdxRef]; + s = cIdx.label; + } else { + s = "ctx->cIdx"; + } + ctx.code += `${offset.label} = ctx->getSubComponentOffset(${s}, 0x${h}LL /* ${label} */);\n`; + return refOffset; } -function genGetSubComponentSizes(ctx, cIdx, label) { - const vSizes = newRef(ctx, "SIZES", "_compSizes"); - instantiateRef(ctx, vSizes); +function genGetSubComponentSizes(ctx, cIdxRef, label) { + const sizesRef = newRef(ctx, "SIZES", "_compSizes"); + const sizes = ctx.refs[sizesRef]; + instantiateRef(ctx, sizesRef); const h = utils.fnvHash(label); - ctx.code += `${vSizes} = ctx->getSubComponentSizes(${cIdx}, 0x${h}LL /* ${label} */);\n`; - return vSizes; + let s; + if (cIdxRef>=0) { + const cIdx = ctx.refs[cIdxRef]; + s = cIdx.label; + } else { + s = "ctx->cIdx"; + } + ctx.code += `${sizes.label} = ctx->getSubComponentSizes(${s}, 0x${h}LL /* ${label} */);\n`; + return sizesRef; } -function genGetSigalOffset(ctx, sIdx, label) { - const vOffset = newRef(ctx, "INT", "_sigIdx"); - instantiateRef(ctx, vOffset); +function genGetSigalOffset(ctx, cIdxRef, label) { + const refOffset = newRef(ctx, "INT", "_sigIdx"); + const offset = ctx.refs[refOffset]; + instantiateRef(ctx, refOffset); const h = utils.fnvHash(label); - ctx.code += `${vOffset} = ctx->getSignalOffset(${sIdx}, 0x${h}LL /* ${label} */);\n`; - return vOffset; + let s; + if (cIdxRef>=0) { + const cIdx = ctx.refs[cIdxRef]; + s = cIdx.label; + } else { + s = "ctx->cIdx"; + } + ctx.code += `${offset.label} = ctx->getSignalOffset(${s}, 0x${h}LL /* ${label} */);\n`; + return refOffset; } -function genGetSignalSizes(ctx, sIdx, label) { - const vSizes = newRef(ctx, "SIZES", "_sigSizes"); - instantiateRef(ctx, vSizes); +function genGetSignalSizes(ctx, cIdxRef, label) { + const sizesRef = newRef(ctx, "SIZES", "_sigSizes"); + const sizes = ctx.refs[sizesRef]; + instantiateRef(ctx, sizesRef); + let s; + if (cIdxRef>=0) { + const cIdx = ctx.refs[cIdxRef]; + s = cIdx.label; + } else { + s = "ctx->cIdx"; + } const h = utils.fnvHash(label); - ctx.code += `${vSizes} = ctx->getSignalSizes(${sIdx}, 0x${h}LL /* ${label} */);\n`; - return vSizes; + ctx.code += `${sizes.label} = ctx->getSignalSizes(${s}, 0x${h}LL /* ${label} */);\n`; + return sizesRef; } -function genSetSignal(ctx, cIdx, sIdx, value) { - const v = getScope(ctx, value); +function genSetSignal(ctx, cIdxRef, sIdxRef, valueRef) { + const v = ctx.refs[valueRef]; if (!v.used) { - value = instantiateConstant(ctx, v.value); + instantiateRef(ctx, valueRef, v.value); + } + let s; + if (cIdxRef>=0) { + const cIdx = ctx.refs[cIdxRef]; + s = cIdx.label; + } else { + s = "ctx->cIdx"; } - ctx.code += `ctx->setSignal(${cIdx}, ${sIdx}, ${value});\n`; + const sIdx = ctx.refs[sIdxRef]; + ctx.code += `ctx->setSignal(${s}, ${sIdx.label}, ${v.label});\n`; - return value; + return valueRef; } -function genGetSignal(ctx, cIdx, sIdx) { - const res = newRef(ctx, "BIGINT", "_sigValue"); - instantiateRef(ctx, res); - ctx.code += `ctx->getSignal(${cIdx}, ${sIdx}, ${res});\n`; - return res; +function genGetSignal(ctx, cIdxRef, sIdxRef) { + const resRef = newRef(ctx, "BIGINT", "_sigValue"); + const res = ctx.refs[resRef]; + instantiateRef(ctx, resRef); + let s; + if (cIdxRef>=0) { + const cIdx = ctx.refs[cIdxRef]; + s = cIdx.label; + } else { + s = "ctx->cIdx"; + } + const sIdx = ctx.refs[sIdxRef]; + ctx.code += `ctx->getSignal(${s}, ${sIdx.label}, ${res.label});\n`; + return resRef; } function genPinAssignement(ctx, ast) { let vcIdx; if (ast.values[0].component.selectors.length>0) { - const vcOffset = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name); - const vcSizes = genGetSubComponentSizes(ctx, "ctx->cIdx", ast.values[0].component.name); + const vcOffset = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name); + const vcSizes = genGetSubComponentSizes(ctx, -1, ast.values[0].component.name); vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.values[0].component.selectors ); } else { - vcIdx = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name); + vcIdx = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name); } let vsIdx; @@ -595,59 +613,60 @@ function genPinAssignement(ctx, ast) { function genSignalAssignmen(ctx, ast, lName, sels, rName) { let vsIdx; + const signal = ctx.refs[lName]; if (sels.length>0) { - const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", lName); - const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", lName); + const vsOffset = genGetSigalOffset(ctx, -1, signal.label); + const vsSizes = genGetSignalSizes(ctx, -1, signal.label); vsIdx = genGetOffset(ctx, vsOffset, vsSizes, sels ); } else { - vsIdx = genGetSigalOffset(ctx, "ctx->cIdx", lName); + vsIdx = genGetSigalOffset(ctx, -1, signal.label); } - return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName); + return genSetSignal(ctx, -1, vsIdx, rName); } -function genVarAssignment(ctx, ast, lName, sels, rName) { +function genVarAssignment(ctx, ast, lRef, sels, rRef) { - const left = getScope(ctx, lName); - const right = getScope(ctx, rName); + const left = ctx.refs[lRef]; + const right = ctx.refs[rRef]; if (!utils.isDefined(left.sizes)) { left.sizes = right.sizes; left.value = new Array(left.sizes[0]); } - if (!utils.sameSizes(left.sizes.slice(sels.length), right.sizes)) return error(ctx, ast, "Sizes do not match"); + if (!utils.sameSizes(left.sizes.slice(sels.length), right.sizes)) return ctx.throwError(ast, "Sizes do not match"); - const oName = genGetOffset(ctx, 0, left.sizes, sels); - const offset = getScope(ctx, oName); + const oRef = genGetOffset(ctx, 0, left.sizes, sels); + const offset = ctx.refs[oRef]; let instantiated=false; if (left.used) { - instantiateRef(ctx, rName, right.value); + instantiateRef(ctx, rRef, right.value); instantiated=true; } else if (right.used) { if (sels.length == 0) { - instantiateRef(ctx,lName); + instantiateRef(ctx,lRef); } else { - instantiateRef(ctx,lName, left.value); + instantiateRef(ctx,lRef, left.value); } instantiated=true; } else if (offset.used) { - instantiateRef(ctx, rName, right.value); + instantiateRef(ctx, rRef, right.value); if (sels.length == 0) { - instantiateRef(ctx,lName); + instantiateRef(ctx,lRef); } else { - instantiateRef(ctx,lName, left.value); + instantiateRef(ctx,lRef, left.value); } instantiated=true; } if (instantiated) { if (offset.used) { - ctx.code += `ctx->field->copyn(${lName} + ${oName}, ${rName}, ${right.sizes[0]});\n`; + ctx.code += `ctx->field->copyn(${left.label} + ${offset.label}, ${right.label}, ${right.sizes[0]});\n`; } else { if (offset.value[0]>0) { - ctx.code += `ctx->field->copyn(${lName} + ${offset.value[0]}, ${rName}, ${right.sizes[0]});\n`; + ctx.code += `ctx->field->copyn(${left.label} + ${offset.value[0]}, ${right.label}, ${right.sizes[0]});\n`; } else { - ctx.code += `ctx->field->copyn(${lName}, ${rName}, ${right.sizes[0]});\n`; + ctx.code += `ctx->field->copyn(${left.label}, ${right.label}, ${right.sizes[0]});\n`; } } } else { @@ -661,7 +680,7 @@ function genVarAssignment(ctx, ast, lName, sels, rName) { function genAssignement(ctx, ast) { - let lName; + let lRef; let sels; if (ctx.error) return; @@ -669,61 +688,57 @@ function genAssignement(ctx, ast) { if (ast.values[0].type == "PIN") return genPinAssignement(ctx, ast); if (ast.values[0].type == "DECLARE") { - lName = gen(ctx, ast.values[0]); + lRef = gen(ctx, ast.values[0]); if (ctx.error) return; sels = []; } else { - lName = ast.values[0].name; + lRef = ast.values[0].refId; sels = ast.values[0].selectors; } - const left = getScope(ctx, lName); - if (!left) return error(ctx, ast, "Variable does not exists: "+ast.values[0].name); + const left = ctx.refs[lRef]; + if (!left) return ctx.throwError(ast, "Variable does not exists: "+ast.values[0].name); // Component instantiation is already done. - if (left.type == "COMPONENT") { - ctx.last = lName; - return; - } + if (left.type == "COMPONENT") return; - if (ctx.conditionalCode && !left.used) { - instantiateRef(ctx, lName, left.value); - } - - const rName = gen(ctx, ast.values[1]); + const rRef = gen(ctx, ast.values[1]); + if (ctx.error) return; - if (left.type == "SIGNAL") return genSignalAssignmen(ctx, ast, lName, sels, rName); + if (left.type == "SIGNAL") return genSignalAssignmen(ctx, ast, lRef, sels, rRef); - if (left.type == "BIGINT") return genVarAssignment(ctx, ast, lName, sels, rName); + if (left.type == "BIGINT") return genVarAssignment(ctx, ast, lRef, sels, rRef); - return error(ctx, ast, "Assigning to invalid"); + return ctx.throwError(ast, "Assigning to invalid"); } function genConstraint(ctx, ast) { - const a = gen(ctx, ast.values[0]); + const aRef = gen(ctx, ast.values[0]); + const a = ctx.refs[aRef]; if (ctx.error) return; - const b = gen(ctx, ast.values[1]); + const bRef = gen(ctx, ast.values[1]); + const b = ctx.refs[bRef]; if (ctx.error) return; const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column; - ctx.code += `ctx->checkConstraint(${a}, ${b}, "${strErr}");`; + ctx.code += `ctx->checkConstraint(${a.label}, ${b.label}, "${strErr}");`; } function genArray(ctx, ast) { let subSizes; let instantiate = false; - if (ast.values.length == 0) return error(ctx, ast, "Arrays with zero elements not allowed"); + if (ast.values.length == 0) return ctx.throwError(ast, "Arrays with zero elements not allowed"); const value = []; - const names = []; + const refs = []; for (let i=0; ifield->copyn(${rName}+${i*subSizes[0]}, ${names[i]}, ${subSizes[0]});\n`; + const v = ctx.refs[refs[i]]; + const r = ctx.refs[rRef]; + ctx.code += `ctx->field->copyn(${r.label}+${i*subSizes[0]}, ${v.label}, ${subSizes[0]});\n`; } - return rName; + return rRef; } else { - const rName = newRef(ctx, "BIGINT", "_arr", value, newSize); - return rName; + const rRef = newRef(ctx, "BIGINT", "_arr", value, newSize); + return rRef; } } @@ -754,34 +771,44 @@ function genArray(ctx, ast) { function genFunctionCall(ctx, ast) { const params = []; for (let i=0; i { + if (ast.type == "OP") { + if (["=", "+=", "*=", "PLUSPLUSLEFT", "PLUSPLUSRIGHT", "MINUSMINUSLEFT", "MINUSMINUSRIGHT"].indexOf(ast.op) >= 0) { + let refId; + refId = ast.values[0].refId; + const ref = ctx.refs[refId]; + instantiateRef(ctx, refId, ref.value); + } + } + }); ctx.conditionalCode = 1; - ctx.conditionalCodeHeader = ""; - ctx.code += "__CONDITIONAL_CODE_HEADER__"; } else { ctx.conditionalCode ++; } @@ -791,11 +818,6 @@ function leaveConditionalCode(ctx) { assert(ctx.conditionalCode, "Leaving conditional code too many times"); ctx.conditionalCode --; if (!ctx.conditionalCode) { - ctx.code = ctx.code.replace("__CONDITIONAL_CODE_HEADER__", - "// Conditional Code Header\n" + - ctx.conditionalCodeHeader+ - "\n"); - delete ctx.conditionalCodeHeader; delete ctx.conditionalCode; } } @@ -803,29 +825,31 @@ function leaveConditionalCode(ctx) { function genFor(ctx, ast) { genForSrcComment(ctx, ast); let inLoop = false; - ctx.scopes.push({_prefix : ""}); + ctx.scopes.push({}); gen(ctx, ast.init); if (ctx.error) return; let end=false; + let condVarRef; let condVar; - const condName = gen(ctx, ast.condition); - const cond = getScope(ctx, condName); - if (!utils.sameSizes(cond.sizes, [1,0])) return error(ctx, ast.condition, "Operation cannot be done on an array"); + const condRef = gen(ctx, ast.condition); + const cond = ctx.refs[condRef]; + if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array"); if (cond.used) { inLoop = true; - enterConditionalCode(ctx); - condVar = newRef(ctx, "INT", "_cond"); - instantiateRef(ctx, condVar); + enterConditionalCode(ctx, ast); + condVarRef = newRef(ctx, "INT", "_cond"); + condVar = ctx.refs[condVarRef]; + instantiateRef(ctx, condVarRef); ctx.code += - `${condVar} = ctx->field->isTrue(${condName});\n` + - `while (${condVar}) {\n`; + `${condVar.label} = ctx->field->isTrue(${cond.label});\n` + + `while (${condVar.label}) {\n`; } else { - if (!utils.isDefined(cond.value)) return error(ctx, ast, "condition value not assigned"); + if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned"); if (cond.value[0].isZero()) end=true; } @@ -842,22 +866,22 @@ function genFor(ctx, ast) { gen(ctx, ast.step); if (ctx.error) return; - const condName2 = gen(ctx, ast.condition); - const cond2 = getScope(ctx, condName2); + const condRef2 = gen(ctx, ast.condition); + const cond2 = ctx.refs[condRef2]; if (!inLoop) { if (cond2.used) { ctx.code = oldCode + ctx.code; inLoop = true; - enterConditionalCode(ctx); + enterConditionalCode(ctx, ast); condVar = newRef(ctx, "INT", "_cond"); instantiateRef(ctx, condVar); ctx.code = oldCode + ctx.code + - `${condVar} = ctx->field->isTrue(${condName2});\n` + - `while (${condVar}) {\n`; + `${condVar.label} = ctx->field->isTrue(${cond2.label});\n` + + `while (${condVar.label}) {\n`; } else { ctx.code = oldCode + ctx.code; if (cond2.value[0].isZero()) end=true; @@ -867,7 +891,7 @@ function genFor(ctx, ast) { oldCode + utils.ident( ctx.code + - `${condVar} = ctx->field->isTrue(${condName2});\n`); + `${condVar.label} = ctx->field->isTrue(${cond2.label});\n`); end=true; } } @@ -908,26 +932,26 @@ function genIf(ctx, ast) { function genReturn(ctx, ast) { - const vName = gen(ctx, ast.value); - const v= getScope(ctx, vName); + const vRef = gen(ctx, ast.value); + const v= ctx.refs[vRef]; if (ctx.returnSizes) { - if (!utils.sizesEqual(vName.sizes, ctx.returnSizes)) return error(ctx, ast, "Diferent return sizes"); + if (!utils.sizesEqual(v.sizes, ctx.returnSizes)) return ctx.throwError(ast, "Diferent return sizes"); } else { ctx.returnSizes = v.sizes; } if (ctx.conditionalCode) { - instantiateRef(ctx, vName, vName.value); + instantiateRef(ctx, vRef, v.value); } if (v.used) { - ctx.code += `ctx->field->copyn(__retValue, ${vName}, ${v.sizes[0]});\n`; + ctx.code += `ctx->field->copyn(__retValue, ${v.label}, ${v.sizes[0]});\n`; } else { - if (!utils.isDefined(v.value)) return error(ctx, ast, "Returning an unknown value"); + if (!utils.isDefined(v.value)) return ctx.throwError(ast, "Returning an unknown value"); if (!utils.isDefined(ctx.returnValue)) { ctx.returnValue = v.value; } } ctx.code += "goto returnFunc;\n"; - return vName; + return vRef; } @@ -964,35 +988,38 @@ function genMinusMinusLeft(ctx, ast) { } function genBinaryOp(ctx, ast, op) { - let aName = gen(ctx, ast.values[0]); + let aRef = gen(ctx, ast.values[0]); if (ctx.error) return; - const a = getScope(ctx, aName); + let a = ctx.refs[aRef]; - let bName = gen(ctx, ast.values[1]); + let bRef = gen(ctx, ast.values[1]); if (ctx.error) return; - const b = getScope(ctx, bName); + let b = ctx.refs[bRef]; - if ((!a.used)&&(!utils.isDefined(a.value))) return error(ctx, ast, "Using a not assigned varialble: "+aName); - if ((!b.used)&&(!utils.isDefined(b.value))) return error(ctx, ast, "Using a not assigned varialble: "+bName); - if (!utils.sameSizes(a.sizes, [1,0])) return error(ctx, ast, "Operation cannot be done on an array"); - if (!utils.sameSizes(b.sizes, [1,0])) return error(ctx, ast, "Operation cannot be done on an array"); + if ((!a.used)&&(!utils.isDefined(a.value))) return ctx.throwError(ast, "Using a not assigned varialble: "); + if ((!b.used)&&(!utils.isDefined(b.value))) return ctx.throwError(ast, "Using a not assigned varialble: "); + if (!utils.sameSizes(a.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array"); + if (!utils.sameSizes(b.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array"); - let rName; + let rRef; if (a.used || b.used) { if (!a.used) { - aName = instantiateConstant(ctx, a.value); + aRef = instantiateConstant(ctx, a.value); + a = ctx.refs[aRef]; } if (!b.used) { - bName = instantiateConstant(ctx, b.value); + bRef = instantiateConstant(ctx, b.value); + b = ctx.refs[bRef]; } - rName = newRef(ctx, "BIGINT", "_tmp"); - instantiateRef(ctx, rName); - ctx.code += `ctx->field->${op}(${rName},${aName}, ${bName});\n`; + rRef = newRef(ctx, "BIGINT", "_tmp"); + instantiateRef(ctx, rRef); + const r = ctx.refs[rRef]; + ctx.code += `ctx->field->${op}(${r.label},${a.label}, ${b.label});\n`; } else { - rName = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](a.value[0], b.value[0])); + rRef = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](a.value[0], b.value[0])); } - return rName; + return rRef; } diff --git a/src/ctx.js b/src/ctx.js index ca5bb50..e129ba0 100644 --- a/src/ctx.js +++ b/src/ctx.js @@ -115,6 +115,8 @@ module.exports = class Ctx { this.nComponents =0; this.names = new TableName(this); this.main=false; + this.error = null; + this.warnings = []; const oneIdx = this.addSignal("one"); this.signals[oneIdx] = { @@ -122,6 +124,8 @@ module.exports = class Ctx { o: this.ONE, e: -1, }; + + this.uniqueNames = {}; } addSignal(name, sizes) { @@ -168,4 +172,55 @@ module.exports = class Ctx { return new TableName(this); } + _buildErr(ast, errStr) { + if (typeof ast == "string") { + ast = null; + errStr = ast; + } + if (ast) { + return { + 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, + errFile: ast.fileName + }; + } else { + return { + errStr: errStr, + message: errStr + }; + } + } + + throwError(ast, errStr) { + const err = this._buildErr(ast, errStr); + this.error = err; + } + + logWarning(ast, errStr) { + const w = this._buildErr(ast, errStr); + this.warnings.push(w); + } + + getUniqueName(suggestedName) { + if (!suggestedName) { + suggestedName = "_tmp"; + } + + if (typeof(this.uniqueNames[suggestedName]) == "undefined") { + this.uniqueNames[suggestedName] = 1; + return suggestedName; + } else { + const name = suggestedName + "_" + this.uniqueNames[suggestedName]; + this.uniqueNames[suggestedName]++; + return name; + } + } + }; diff --git a/src/iterateast.js b/src/iterateast.js new file mode 100644 index 0000000..b8853f4 --- /dev/null +++ b/src/iterateast.js @@ -0,0 +1,69 @@ + +const assert = require("assert"); + +module.exports = iterateAST; + + +function iterateAST(ast, fn, _pfx) { + if (!ast) return; + + const pfx = _pfx || ""; + let itPfx = 0; + + function getPfx() { + res = pfx+"."+itPfx; + itPfx ++; + return res; + } + + + let res = fn(ast, pfx); + if (res) return res; + function iterate(arr) { + if (arr) { + for (let i=0; i Invalid AST iteration: " + ast.type); + } + + +} diff --git a/src/utils.js b/src/utils.js index b5dc2a7..847e33e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -12,6 +12,7 @@ module.exports.stringifyBigInts = stringifyBigInts; module.exports.unstringifyBigInts = unstringifyBigInts; module.exports.sameSizes = sameSizes; module.exports.isDefined = isDefined; +module.exports.accSizes2Str = accSizes2Str; function ident(text) { let lines = text.split("\n"); @@ -116,5 +117,10 @@ function isDefined(v) { return ((typeof(v) != "undefined")&&(v != null)); } +function accSizes2Str(sizes) { + if (sizes.length == 2) return ""; + return `[${sizes[0]/sizes[1]}]`+accSizes2Str(sizes.slice(1)); +} + diff --git a/test/circuits/in.json b/test/circuits/in.json index bf794f9..7235f9c 100644 --- a/test/circuits/in.json +++ b/test/circuits/in.json @@ -1 +1 @@ -{"in": 0} +{"in1": 1, "in2": [2,3], "in3":[[4,5], [6,7], [8,9]]}