scopes work og in code generation

This commit is contained in:
Jordi Baylina
2019-12-07 12:58:11 +01:00
parent fbcc753bc1
commit ff1c12bcc3
6 changed files with 521 additions and 375 deletions

View File

@@ -21,7 +21,7 @@ const assert = require("assert");
const bigInt = require("big-integer"); const bigInt = require("big-integer");
const utils = require("./utils"); const utils = require("./utils");
const gen = require("./c_gen").gen; const gen = require("./c_gen").gen;
const newRef = require("./c_gen").newRef; const createRefs = require("./c_gen").createRefs;
module.exports = buildC; module.exports = buildC;
@@ -32,14 +32,12 @@ function buildC(ctx) {
ctx.buildFunction = buildFunction; ctx.buildFunction = buildFunction;
ctx.code = ""; ctx.code = "";
ctx.conditionalCodeHeader = ""; ctx.conditionalCodeHeader = "";
ctx.tmpNames = {};
ctx.getTmpName = getTmpName;
ctx.codes_sizes = []; ctx.codes_sizes = [];
ctx.definedSizes = {}; ctx.definedSizes = {};
ctx.addSizes = addSizes; ctx.addSizes = addSizes;
const entryTables = buildEntryTables(ctx); const entryTables = buildEntryTables(ctx);
ctx.globalNames = ctx.tmpNames; ctx.globalNames = ctx.uniqueNames;
const code = buildCode(ctx); const code = buildCode(ctx);
const functions = buildFuncFunctions(ctx); const functions = buildFuncFunctions(ctx);
@@ -72,7 +70,7 @@ function buildEntryTables(ctx) {
const {htName, htMap} = addHashTable(i); const {htName, htMap} = addHashTable(i);
let code = ""; 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`; code += `Circom_ComponentEntry ${componentEntriesTableName}[${htMap.length}] = {\n`;
for (let j=0; j<htMap.length; j++) { for (let j=0; j<htMap.length; j++) {
@@ -106,7 +104,7 @@ function buildEntryTables(ctx) {
const h = utils.fnvHash(keys.join(",")); const h = utils.fnvHash(keys.join(","));
if (definedHashTables[h]) return definedHashTables[h]; if (definedHashTables[h]) return definedHashTables[h];
definedHashTables[h] = {}; definedHashTables[h] = {};
definedHashTables[h].htName = ctx.getTmpName("ht_"+ctx.components[cIdx].template); definedHashTables[h].htName = ctx.getUniqueName("_ht"+ctx.components[cIdx].template);
definedHashTables[h].htMap = []; definedHashTables[h].htMap = [];
const t = []; const t = [];
for (let i=0; i<keys.length; i++) { for (let i=0; i<keys.length; i++) {
@@ -145,19 +143,32 @@ function buildCode(ctx) {
if (!fDefined[fName]) { if (!fDefined[fName]) {
const scope = {_prefix : ""}; ctx.scopes = [{}];
ctx.scopes = [scope];
ctx.conditionalCode = false; ctx.conditionalCode = false;
ctx.code = ""; ctx.code = "";
ctx.codeHeader = "// Header\n"; ctx.codeHeader = "// Header\n";
ctx.codeFooter = "// Footer\n"; ctx.codeFooter = "// Footer\n";
ctx.tmpNames = Object.assign({},ctx.globalNames); ctx.uniqueNames = Object.assign({},ctx.globalNames);
ctx.refs = [];
for (let p in ctx.components[i].params) { for (let p in ctx.components[i].params) {
newRef(ctx, "BIGINT", p, bigInt(ctx.components[i].params[p])); if (ctx.scopes[0][p]) return ctx.throwError(`Repeated parameter at ${ctx.components[i].template}: ${p}`);
const refId = ctx.refs.length;
ctx.refs.push({
type: "BIGINT",
used: false,
value: utils.flatArray(ctx.components[i].params[p]),
sizes: utils.accSizes(utils.extractSizes(ctx.components[i].params[p])),
label: ctx.getUniqueName(p)
});
ctx.scopes[0][p] = refId;
} }
createRefs(ctx, ctx.templates[ctx.components[i].template].block);
if (ctx.error) return;
gen(ctx, ctx.templates[ctx.components[i].template].block); gen(ctx, ctx.templates[ctx.components[i].template].block);
if (ctx.error) return;
const S = const S =
"/*\n" + "/*\n" +
@@ -318,34 +329,6 @@ function buildCircuitVar() {
function getTmpName(_suggestedName) {
let suggestedName;
if (_suggestedName) {
suggestedName = trimUnderscore(_suggestedName);
} else {
suggestedName = "tmp";
}
if (typeof(this.tmpNames[suggestedName]) == "undefined") {
this.tmpNames[suggestedName] = 1;
return "_"+suggestedName;
} else {
const name = "_" + suggestedName + "_" + this.tmpNames[suggestedName];
this.tmpNames[suggestedName]++;
return name;
}
function trimUnderscore(str) {
let p1=0;
while ((p1 < str.length)&&(str[p1] == "_")) p1++;
let p2=str.length;
while ((p2 > 0)&&(str[p2-1] == "_")) p2--;
return str.slice(p1,p2);
}
}
function addSizes(_sizes) { function addSizes(_sizes) {
const sizes = _sizes || []; const sizes = _sizes || [];
let name = "sizes"; let name = "sizes";
@@ -355,8 +338,8 @@ function addSizes(_sizes) {
if (name=="sizes") name="sizes_0"; if (name=="sizes") name="sizes_0";
if (this.definedSizes[name]) return this.definedSizes[name]; if (this.definedSizes[name]) return this.definedSizes[name];
name = "_" + name;
const labelName = this.getTmpName(name); const labelName = this.getUniqueName(name);
this.definedSizes[name] = labelName; this.definedSizes[name] = labelName;
const accSizes = utils.accSizes(sizes); const accSizes = utils.accSizes(sizes);
@@ -382,21 +365,21 @@ function buildFunction(name, paramValues) {
fnName: `${name}_${h}` fnName: `${name}_${h}`
}; };
const oldScopes = ctx.scopes; const oldRefs = ctx.refs;
const oldConditionalCode = ctx.conditionalCode; const oldConditionalCode = ctx.conditionalCode;
const oldCode = ctx.code; const oldCode = ctx.code;
const oldCodeHeader = ctx.codeHeader; const oldCodeHeader = ctx.codeHeader;
const oldCodeFooter = ctx.codeFooter; const oldCodeFooter = ctx.codeFooter;
const oldTmpNames = ctx.tmpNames; const oldUniqueNames = ctx.uniqueNames;
const scope = {_prefix : ""}; ctx.scopes = [{}];
ctx.scopes = [scope]; ctx.refs = [];
ctx.conditionalCode = false; ctx.conditionalCode = false;
ctx.code = ""; ctx.code = "";
ctx.codeHeader = "// Header\n"; ctx.codeHeader = "// Header\n";
ctx.codeFooter = "// Footer\n"; ctx.codeFooter = "// Footer\n";
ctx.tmpNames = Object.assign({},ctx.globalNames); ctx.uniqueNames = Object.assign({},ctx.globalNames);
ctx.returnValue = null; ctx.returnValue = null;
ctx.returnSizes = null; ctx.returnSizes = null;
@@ -406,26 +389,32 @@ function buildFunction(name, paramValues) {
if (paramValues[i].used) { if (paramValues[i].used) {
paramsStr += `,PBigInt ${ctx.functions[name].params[i]}`; paramsStr += `,PBigInt ${ctx.functions[name].params[i]}`;
scope[ctx.functions[name].params[i]] = { const idRef = ctx.refs.length;
stack: true, ctx.refs.push({
type: "BIGINT", type: "BIGINT",
used: true, used: true,
sizes: paramValues[i].sizes, sizes: paramValues[i].sizes,
label: ctx.functions[name].params[i], label: ctx.functions[name].params[i],
}; });
ctx.scopes[0][ctx.functions[name].params[i]] = idRef;
} else { } else {
scope[ctx.functions[name].params[i]] = { const idRef = ctx.refs.length;
stack: true, ctx.refs.push({
type: "BIGINT", type: "BIGINT",
used: false, used: false,
sizes: paramValues[i].sizes, sizes: paramValues[i].sizes,
label: ctx.functions[name].params[i], label: ctx.functions[name].params[i],
value: paramValues[i].value 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); gen(ctx, ctx.functions[name].block);
if (ctx.error) return;
if (ctx.returnValue == null) { if (ctx.returnValue == null) {
if (ctx.returnSizes == null) assert(false, `Funciont ${name} does not return any value`); 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; res.returnSizes = ctx.returnSizes;
} }
ctx.scopes = oldScopes; ctx.refs = oldRefs;
ctx.conditionalCode = oldConditionalCode; ctx.conditionalCode = oldConditionalCode;
ctx.code = oldCode; ctx.code = oldCode;
ctx.codeHeader = oldCodeHeader; ctx.codeHeader = oldCodeHeader;
ctx.codeFooter = oldCodeFooter; ctx.codeFooter = oldCodeFooter;
ctx.tmpNames = oldTmpNames; ctx.uniqueNames = oldUniqueNames;
ctx.definedFunctions[h] = res; ctx.definedFunctions[h] = res;
@@ -508,7 +497,7 @@ function hashFunctionCall(ctx, name, paramValues) {
const constParams = []; const constParams = [];
for (let i=0; i<ctx.functions[name].params.length; i++) { for (let i=0; i<ctx.functions[name].params.length; i++) {
if (!paramValues[i].used) { if (!paramValues[i].used) {
constParams.push(ctx.functions[name].params[i] + "=" + value2str(paramValues[i].value)); constParams.push(ctx.functions[name].params[i] + utils.accSizes2Str(paramValues[i].sizes) + "=" + value2str(paramValues[i].value));
} }
} }
let instanceDef = name; let instanceDef = name;

File diff suppressed because it is too large Load Diff

View File

@@ -115,6 +115,8 @@ module.exports = class Ctx {
this.nComponents =0; this.nComponents =0;
this.names = new TableName(this); this.names = new TableName(this);
this.main=false; this.main=false;
this.error = null;
this.warnings = [];
const oneIdx = this.addSignal("one"); const oneIdx = this.addSignal("one");
this.signals[oneIdx] = { this.signals[oneIdx] = {
@@ -122,6 +124,8 @@ module.exports = class Ctx {
o: this.ONE, o: this.ONE,
e: -1, e: -1,
}; };
this.uniqueNames = {};
} }
addSignal(name, sizes) { addSignal(name, sizes) {
@@ -168,4 +172,55 @@ module.exports = class Ctx {
return new TableName(this); 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;
}
}
}; };

69
src/iterateast.js Normal file
View File

@@ -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<arr.length; i++) {
res = iterateAST(arr[i], fn, getPfx());
if (res) return res;
}
}
}
if ((ast.type == "NUMBER")) {
//
} else if (ast.type == "VARIABLE") {
iterate(ast.selectors);
} else if (ast.type == "PIN") {
iterate(ast.component.selectors);
iterate(ast.pin.selectors);
} else if (ast.type == "OP") {
iterate(ast.values);
} else if (ast.type == "DECLARE") {
iterate(ast.name.selectors);
} else if (ast.type == "FUNCTIONCALL") {
iterate(ast.params);
} else if (ast.type == "BLOCK") {
iterate(ast.statements);
} else if (ast.type == "COMPUTE") {
iterateAST(ast.body, fn, getPfx());
} else if (ast.type == "FOR") {
iterateAST(ast.init, fn, getPfx());
iterateAST(ast.condition, fn, getPfx());
iterateAST(ast.step, fn, getPfx());
iterateAST(ast.body, fn, getPfx());
} else if (ast.type == "WHILE") {
iterateAST(ast.condition, fn, getPfx());
iterateAST(ast.body, fn, getPfx());
} else if (ast.type == "IF") {
iterateAST(ast.condition, fn, getPfx());
iterateAST(ast.then, fn, getPfx());
iterateAST(ast.else, fn, getPfx());
} else if (ast.type == "RETURN") {
iterateAST(ast.value, fn, getPfx());
} else if (ast.type == "ARRAY") {
iterate(ast.values);
} else {
assert(false, "GEN -> Invalid AST iteration: " + ast.type);
}
}

View File

@@ -12,6 +12,7 @@ module.exports.stringifyBigInts = stringifyBigInts;
module.exports.unstringifyBigInts = unstringifyBigInts; module.exports.unstringifyBigInts = unstringifyBigInts;
module.exports.sameSizes = sameSizes; module.exports.sameSizes = sameSizes;
module.exports.isDefined = isDefined; module.exports.isDefined = isDefined;
module.exports.accSizes2Str = accSizes2Str;
function ident(text) { function ident(text) {
let lines = text.split("\n"); let lines = text.split("\n");
@@ -116,5 +117,10 @@ function isDefined(v) {
return ((typeof(v) != "undefined")&&(v != null)); return ((typeof(v) != "undefined")&&(v != null));
} }
function accSizes2Str(sizes) {
if (sizes.length == 2) return "";
return `[${sizes[0]/sizes[1]}]`+accSizes2Str(sizes.slice(1));
}

View File

@@ -1 +1 @@
{"in": 0} {"in1": 1, "in2": [2,3], "in3":[[4,5], [6,7], [8,9]]}