From 818eb959e78f724122c6b388c98a1d9c14c9c25d Mon Sep 17 00:00:00 2001 From: SoraSuegami Date: Thu, 2 Nov 2023 09:42:47 +0900 Subject: [PATCH] Modify ts in compiler and add tsc compile. --- packages/compiler/Cargo.toml | 2 +- packages/compiler/package.json | 11 +-- packages/compiler/src/circom.rs | 4 ++ packages/compiler/src/gen_circom.ts | 24 ++++--- packages/compiler/src/lib.rs | 1 + packages/compiler/src/regex.ts | 61 ++++++++-------- packages/compiler/tsconfig.json | 104 ++++++++++++++++++++++++++++ tsconfig.json | 5 +- 8 files changed, 164 insertions(+), 48 deletions(-) create mode 100644 packages/compiler/tsconfig.json diff --git a/packages/compiler/Cargo.toml b/packages/compiler/Cargo.toml index b6c0242..3aa40ca 100644 --- a/packages/compiler/Cargo.toml +++ b/packages/compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zk-regex-compiler" -version = "1.0.5" +version = "1.0.6" authors = [ "Javier Su ", "Kata Choi ", diff --git a/packages/compiler/package.json b/packages/compiler/package.json index edc9a2e..31a0381 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@zk-email/zk-regex-compiler", - "version": "1.0.5", + "version": "1.0.6", "description": "a compiler to generate a regex verification circuit in circom from a user-defined regex. Please check [zk-regex](https://github.com/zkemail/zk-regex/tree/main) for the detail.", "main": "index.node", "contributors": [ @@ -14,19 +14,20 @@ "url": "git+https://github.com/zkemail/zk-regex.git" }, "scripts": { - "build": "cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics", + "build": "npx tsc && cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics", "build-debug": "npm run build --", "build-release": "npm run build -- --release", - "install": "node-pre-gyp install --fallback-to-build=false || npm run build-release", + "install": "npx tsc && node-pre-gyp install --fallback-to-build=false || npm run build-release", "test": "cargo test", "package": "node-pre-gyp package", "upload-binary": "npm run package && node-pre-gyp-github publish" }, "license": "MIT", "dependencies": { - "cargo-cp-artifact": "^0.1", "@mapbox/node-pre-gyp": "^1.0", - "node-pre-gyp-github": "https://github.com/ultamatt/node-pre-gyp-github.git" + "cargo-cp-artifact": "^0.1", + "node-pre-gyp-github": "https://github.com/ultamatt/node-pre-gyp-github.git", + "typescript": "^5.2.2" }, "binary": { "module_name": "index", diff --git a/packages/compiler/src/circom.rs b/packages/compiler/src/circom.rs index 4b6c6eb..1dbd5ff 100644 --- a/packages/compiler/src/circom.rs +++ b/packages/compiler/src/circom.rs @@ -25,6 +25,10 @@ impl RegexAndDFA { let circom = gen_circom_allstr(&self.dfa_val, template_name)?; if gen_substrs { self.add_substrs_constraints(circom_path, circom)?; + } else { + let mut circom_file = File::create(circom_path)?; + write!(circom_file, "{}", circom)?; + circom_file.flush()?; } Ok(()) } diff --git a/packages/compiler/src/gen_circom.ts b/packages/compiler/src/gen_circom.ts index 55ee615..c34164a 100644 --- a/packages/compiler/src/gen_circom.ts +++ b/packages/compiler/src/gen_circom.ts @@ -16,7 +16,7 @@ function genCircomAllstr(graph_json: Graph, template_name: string): string { to_init_graph.push([]); } - let accept_nodes: Set = new Set(); + const accept_nodes: Set = new Set(); for (let i = 0; i < N; i++) { const node = graph_json[i]; for (let k in node.edges) { @@ -43,21 +43,22 @@ function genCircomAllstr(graph_json: Graph, template_name: string): string { if (init_going_state !== null) { for (const [going_state, chars] of Object.entries(to_init_graph)) { + const going_state_num = Number(going_state); if (chars.length === 0) { continue; } - if (rev_graph[going_state][init_going_state] == null) { - rev_graph[going_state][init_going_state] = []; + if (rev_graph[going_state_num][init_going_state] == null) { + rev_graph[going_state_num][init_going_state] = []; } - rev_graph[going_state][init_going_state] = rev_graph[going_state][init_going_state].concat(chars); + rev_graph[going_state_num][init_going_state] = rev_graph[going_state_num][init_going_state].concat(chars); } } - if (accept_nodes[0] === null) { - throw new Error("accept node must not be 0"); + if (accept_nodes.size === 0) { + throw new Error("accept node must exist"); } - accept_nodes.add([...accept_nodes][0]); - if (accept_nodes.size !== 1) { + const accept_nodes_array = [...accept_nodes]; + if (accept_nodes_array.length !== 1) { throw new Error("the size of accept nodes must be one"); } @@ -80,8 +81,9 @@ function genCircomAllstr(graph_json: Graph, template_name: string): string { for (let i = 1; i < N; i++) { const outputs: number[] = []; // let is_negates = []; - for (let prev_i of Object.keys(rev_graph[i])) { - const k = rev_graph[i][prev_i]; + for (const prev_i of Object.keys(rev_graph[i])) { + const prev_i_num = Number(prev_i); + const k = rev_graph[i][prev_i_num]; k.sort((a, b) => Number(a) - Number(b)); const eq_outputs: [string, number][] = []; let vals: Set = new Set(k); @@ -270,7 +272,7 @@ function genCircomAllstr(graph_json: Graph, template_name: string): string { lines = declarations.concat(init_code).concat(lines); - const accept_node: number = accept_nodes[0]; + const accept_node: number = accept_nodes_array[0]; const accept_lines = [""]; accept_lines.push("\tcomponent final_state_result = MultiOR(num_bytes+1);"); accept_lines.push("\tfor (var i = 0; i <= num_bytes; i++) {"); diff --git a/packages/compiler/src/lib.rs b/packages/compiler/src/lib.rs index a0b650b..b9d8f64 100644 --- a/packages/compiler/src/lib.rs +++ b/packages/compiler/src/lib.rs @@ -89,6 +89,7 @@ impl DecomposedRegexConfig { all_regex += &config.regex_def; } let dfa_val = regex_to_dfa(&all_regex)?; + println!("dfa_val {:?}", dfa_val); let substrs_defs = self.extract_substr_ids(&dfa_val)?; Ok(RegexAndDFA { // max_byte_size: self.max_byte_size, diff --git a/packages/compiler/src/regex.ts b/packages/compiler/src/regex.ts index 551aba1..109b9f8 100644 --- a/packages/compiler/src/regex.ts +++ b/packages/compiler/src/regex.ts @@ -14,12 +14,12 @@ type CusNode = { type?: string; sub?: CusNode; parts?: CusNode[]; - text?: string; + text?: string | [string]; begin: number; end: number; } -type NfaEdge = [string, NfaNode]; +type NfaEdge = [string | [string], NfaNode]; type NfaNode = { type: string; @@ -33,10 +33,11 @@ type DfaNode = { id: string | number; key: string, items: NfaNode[], - symbols: string[], + symbols: (string | [string])[], type: string, edges: DfaEdge[], - trans: Record; + trans: { [key: string | [string]]: DfaNode }, + // trans: Record; nature: number; }; @@ -61,7 +62,7 @@ type DfaNode = { */ function parseRegex(text: string): CusNode | string { 'use strict'; - function parseSub(text: string, begin: number, end: number, first: boolean): CusNode | string { + function parseSub(text: (string | [string])[], begin: number, end: number, first: boolean): CusNode | string { var i: number, sub: CusNode | string, last: number = 0, @@ -205,16 +206,16 @@ function parseRegex(text: string): CusNode | string { return node; } - let char: string = ''; - let new_text: string = ''; + let char: string | [string]; + let new_text: (string | [string])[] = []; let i: number = 0; let is_in_brancket: boolean = false; - let brancket_text: string = ''; + let brancket_text: (string | [string])[] = []; while (i < text.length) { char = text[i]; if (text[i] == '\\') { - char = text[i + 1]; + char = [text[i + 1]]; // new_text.push([text[i + 1]]); i += 1; } @@ -224,7 +225,7 @@ function parseRegex(text: string): CusNode | string { return `Error: unexpected [ at ${i}.`; } is_in_brancket = true; - brancket_text = ''; + brancket_text = []; // new_text.push(char); i += 1; } else if (char === ']') { @@ -234,11 +235,10 @@ function parseRegex(text: string): CusNode | string { is_in_brancket = false; if (brancket_text[0] === '^') { - brancket_text = brancket_text.slice(1); - let rev_text: string = ''; - let code_char: string = ''; - const brancket_text_array: string[] = brancket_text.split(''); - const brancket_text_jsons: string[] = brancket_text_array.map((c) => JSON.stringify(c)); + brancket_text.shift(); + let rev_text: (string | [string])[] = []; + let code_char: string | [string] = ''; + const brancket_text_jsons = brancket_text.map(val => JSON.stringify(val)); for (let idx = 0; idx < 255; idx++) { code_char = String.fromCodePoint(idx); @@ -257,26 +257,26 @@ function parseRegex(text: string): CusNode | string { '|', '-' ].indexOf(code_char) != -1) { - code_char = code_char[0]; + code_char = [code_char]; } if (brancket_text_jsons.indexOf(JSON.stringify(code_char)) === -1) { - rev_text += code_char; + rev_text.push(code_char); } } brancket_text = rev_text; } - new_text += '('; + new_text.push('('); for (const c of brancket_text) { - new_text += c; - new_text += '|'; + new_text.push(c); + new_text.push('|'); } new_text = new_text.slice(0, -1); - new_text += ')'; + new_text.push(')'); i += 1; } else if (is_in_brancket) { if (!Array.isArray(char) && ['(', ')', '[', '*', '+', '?', 'ϵ'].includes(char)) { @@ -288,10 +288,10 @@ function parseRegex(text: string): CusNode | string { } // new_text.push(char); // new_text.push('|'); - brancket_text += char; + brancket_text.push(char); i += 1; } else { - new_text += char; + new_text.push(char); i += 1; } } @@ -392,7 +392,7 @@ function nfaToDfa(nfa: NfaNode): DfaNode { function getClosure(nodes: NfaNode[]): DfaNode { const closure: NfaNode[] = []; const stack: NfaNode[] = []; - const symbols: string[] = []; + const symbols: (string | [string])[] = []; let type = ''; let top: NfaNode | string; @@ -447,7 +447,7 @@ function nfaToDfa(nfa: NfaNode): DfaNode { }; } - function getClosedMove(closure: DfaNode, symbol: string): DfaNode { + function getClosedMove(closure: DfaNode, symbol: string | [string]): DfaNode { const nexts: NfaNode[] = []; for (const node of closure.items) { @@ -514,7 +514,7 @@ function nfaToDfa(nfa: NfaNode): DfaNode { * @param {object} dfa @see nfaToDfa(), the function assumes that the given DFA is valid. * @return {object} dfa Returns the first element of the minimum DFA. */ -function minDfa(dfa) { +function minDfa(dfa: DfaNode) { 'use strict'; function getReverseEdges(start: DfaNode): [string[], Record, Record>] { const symbols: Record = {}; // The input alphabet @@ -724,8 +724,8 @@ function minDfa(dfa) { }); Object.keys(edges).forEach((from) => { - Object.keys(edges[from]).forEach((to) => { - const symbol = JSON.stringify(Object.keys(edges[from][to]).sort()); + Object.keys(edges[Number(from)]).forEach((to) => { + const symbol = JSON.stringify(Object.keys(edges[Number(from)][Number(to)]).sort()); nodes[parseInt(from)].symbols.push(symbol); nodes[parseInt(from)].edges.push([symbol, nodes[parseInt(to)]]); nodes[parseInt(from)].trans[symbol] = nodes[parseInt(to)]; @@ -767,12 +767,13 @@ function toNature(col: string): number { function regexToDfa(regex: string): string { const nfa = regexToNfa(regex); - + console.log(nfa); if (typeof nfa === 'string') { return nfa; } const dfa = minDfa(nfaToDfa(nfa)); + console.log(dfa); const states: Record = {}; const nodes: DfaNode[] = []; const stack: DfaNode[] = [dfa]; @@ -809,7 +810,7 @@ function regexToDfa(regex: string): string { } graph[node.nature - 1] = curr; } - // console.log(`graph: ${JSON.stringify(graph, null, 2)}`); + console.log(`graph: ${JSON.stringify(graph, null, 2)}`); return JSON.stringify(graph); } diff --git a/packages/compiler/tsconfig.json b/packages/compiler/tsconfig.json new file mode 100644 index 0000000..7db0f2c --- /dev/null +++ b/packages/compiler/tsconfig.json @@ -0,0 +1,104 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": [ + "src/**/*" + ], +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index fae6584..795450d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,5 +9,8 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, - "include": ["./scripts", "./test"] + "include": [ + "./scripts", + "./test" + ] } \ No newline at end of file