Browse Source

scopes work og in code generation

feature/witness_bin
Jordi Baylina 5 years ago
parent
commit
ff1c12bcc3
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
6 changed files with 505 additions and 359 deletions
  1. +43
    -54
      src/c_build.js
  2. +331
    -304
      src/c_gen.js
  3. +55
    -0
      src/ctx.js
  4. +69
    -0
      src/iterateast.js
  5. +6
    -0
      src/utils.js
  6. +1
    -1
      test/circuits/in.json

+ 43
- 54
src/c_build.js

@ -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 = [scope];
ctx.scopes = [{}];
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];
const labelName = this.getTmpName(name);
name = "_" + 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 = [scope];
ctx.scopes = [{}];
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]] = {
stack: true,
const idRef = ctx.refs.length;
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]] = {
stack: true,
const idRef = ctx.refs.length;
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;

+ 331
- 304
src/c_gen.js
File diff suppressed because it is too large
View File


+ 55
- 0
src/ctx.js

@ -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
- 0
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<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);
}
}

+ 6
- 0
src/utils.js

@ -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));
}

+ 1
- 1
test/circuits/in.json

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

Loading…
Cancel
Save