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 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<htMap.length; j++) {
|
||||
@@ -106,7 +104,7 @@ function buildEntryTables(ctx) {
|
||||
const h = utils.fnvHash(keys.join(","));
|
||||
if (definedHashTables[h]) return 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 = [];
|
||||
const t = [];
|
||||
for (let i=0; i<keys.length; i++) {
|
||||
@@ -145,19 +143,32 @@ function buildCode(ctx) {
|
||||
if (!fDefined[fName]) {
|
||||
|
||||
|
||||
const scope = {_prefix : ""};
|
||||
ctx.scopes = [scope];
|
||||
ctx.scopes = [{}];
|
||||
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.refs = [];
|
||||
|
||||
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);
|
||||
if (ctx.error) return;
|
||||
|
||||
const S =
|
||||
"/*\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) {
|
||||
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; i<ctx.functions[name].params.length; i++) {
|
||||
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;
|
||||
|
||||
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.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;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
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.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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"in": 0}
|
||||
{"in1": 1, "in2": [2,3], "in3":[[4,5], [6,7], [8,9]]}
|
||||
|
||||
Reference in New Issue
Block a user