mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-06 18:56:40 +01:00
scopes work og in code generation
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
667
src/c_gen.js
667
src/c_gen.js
File diff suppressed because it is too large
Load Diff
55
src/ctx.js
55
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
src/iterateast.js
Normal file
69
src/iterateast.js
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 @@
|
|||||||
{"in": 0}
|
{"in1": 1, "in2": [2,3], "in3":[[4,5], [6,7], [8,9]]}
|
||||||
|
|||||||
Reference in New Issue
Block a user