-
Notifications
You must be signed in to change notification settings - Fork 952
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3996 from ethereum/circom-parser
Parse circom code and display errors and warnings in the editor
- Loading branch information
Showing
24 changed files
with
524 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
{ | ||
"name": "circuit-compiler", | ||
"$schema": "../../node_modules/nx/schemas/project-schema.json", | ||
"sourceRoot": "apps/circuit-compiler/src", | ||
"projectType": "application", | ||
"implicitDependencies": ["remixd"], | ||
"targets": { | ||
"build": { | ||
"executor": "@nrwl/webpack:webpack", | ||
"outputs": ["{options.outputPath}"], | ||
"defaultConfiguration": "development", | ||
"options": { | ||
"compiler": "babel", | ||
"outputPath": "dist/apps/circuit-compiler", | ||
"index": "apps/circuit-compiler/src/index.html", | ||
"baseHref": "./", | ||
"main": "apps/circuit-compiler/src/main.tsx", | ||
"polyfills": "apps/circuit-compiler/src/polyfills.ts", | ||
"tsConfig": "apps/circuit-compiler/tsconfig.app.json", | ||
"assets": ["apps/circuit-compiler/src/profile.json"], | ||
"styles": ["apps/circuit-compiler/src/css/app.css"], | ||
"scripts": [], | ||
"webpackConfig": "apps/circuit-compiler/webpack.config.js" | ||
}, | ||
"configurations": { | ||
"development": { | ||
}, | ||
"production": { | ||
"fileReplacements": [ | ||
{ | ||
"replace": "apps/circuit-compiler/src/environments/environment.ts", | ||
"with": "apps/circuit-compiler/src/environments/environment.prod.ts" | ||
} | ||
] | ||
} | ||
} | ||
}, | ||
"serve": { | ||
"executor": "@nrwl/webpack:dev-server", | ||
"defaultConfiguration": "development", | ||
"options": { | ||
"buildTarget": "circuit-compiler:build", | ||
"hmr": true, | ||
"baseHref": "/" | ||
}, | ||
"configurations": { | ||
"development": { | ||
"buildTarget": "circuit-compiler:build:development", | ||
"port": 2023 | ||
}, | ||
"production": { | ||
"buildTarget": "circuit-compiler:build:production" | ||
} | ||
} | ||
} | ||
}, | ||
"tags": [] | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import React, { useEffect } from 'react' | ||
|
||
import { CircomPluginClient } from './services/circomPluginClient' | ||
|
||
function App() { | ||
|
||
useEffect(() => { | ||
new CircomPluginClient() | ||
}, []) | ||
|
||
return ( | ||
<div className="App"> | ||
</div> | ||
) | ||
} | ||
|
||
export default App |
224 changes: 224 additions & 0 deletions
224
apps/circuit-compiler/src/app/services/circomPluginClient.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
import {PluginClient} from '@remixproject/plugin' | ||
import {createClient} from '@remixproject/plugin-webview' | ||
import EventManager from 'events' | ||
import pathModule from 'path' | ||
import {parse} from 'circom_wasm' | ||
|
||
export class CircomPluginClient extends PluginClient { | ||
public internalEvents: EventManager | ||
|
||
constructor() { | ||
super() | ||
createClient(this) | ||
this.internalEvents = new EventManager() | ||
this.methods = ['init', 'parse'] | ||
this.onload() | ||
} | ||
|
||
init(): void { | ||
console.log('initializing circom plugin...') | ||
} | ||
|
||
onActivation(): void { | ||
// @ts-ignore | ||
this.on('editor', 'contentChanged', (path: string, fileContent) => { | ||
if (path.endsWith('.circom')) { | ||
this.parse(path, fileContent) | ||
} | ||
}) | ||
} | ||
|
||
async parse(path: string, fileContent: string): Promise<void> { | ||
let buildFiles = { | ||
[path]: fileContent | ||
} | ||
|
||
buildFiles = await this.resolveDependencies(path, fileContent, buildFiles) | ||
const parsedOutput = parse(path, buildFiles) | ||
|
||
try { | ||
const result = JSON.parse(parsedOutput) | ||
|
||
if (result.length === 0) { | ||
// @ts-ignore | ||
await this.call('editor', 'clearErrorMarkers', [path]) | ||
} else { | ||
const markers = [] | ||
|
||
for (const report of result) { | ||
for (const label in report.labels) { | ||
if (report.labels[label].file_id === '0') { | ||
// @ts-ignore | ||
const startPosition: {lineNumber: number; column: number} = | ||
await this.call( | ||
'editor', | ||
// @ts-ignore | ||
'getPositionAt', | ||
report.labels[label].range.start | ||
) | ||
// @ts-ignore | ||
const endPosition: {lineNumber: number; column: number} = | ||
await this.call( | ||
'editor', | ||
// @ts-ignore | ||
'getPositionAt', | ||
report.labels[label].range.end | ||
) | ||
|
||
markers.push({ | ||
message: report.message, | ||
severity: report.type.toLowerCase(), | ||
position: { | ||
start: { | ||
line: startPosition.lineNumber, | ||
column: startPosition.column | ||
}, | ||
end: { | ||
line: endPosition.lineNumber, | ||
column: endPosition.column | ||
} | ||
}, | ||
file: path | ||
}) | ||
} | ||
} | ||
} | ||
|
||
if (markers.length > 0) { | ||
// @ts-ignore | ||
await this.call('editor', 'addErrorMarker', markers) | ||
} else { | ||
// @ts-ignore | ||
await this.call('editor', 'clearErrorMarkers', [path]) | ||
} | ||
} | ||
} catch (e) { | ||
console.log(e) | ||
} | ||
} | ||
|
||
async resolveDependencies( | ||
filePath: string, | ||
fileContent: string, | ||
output = {}, | ||
depPath: string = '', | ||
blackPath: string[] = [] | ||
): Promise<Record<string, string>> { | ||
// extract all includes | ||
const includes = (fileContent.match(/include ['"].*['"]/g) || []).map( | ||
(include) => include.replace(/include ['"]/g, '').replace(/['"]/g, '') | ||
) | ||
|
||
await Promise.all( | ||
includes.map(async (include) => { | ||
// fix for endless recursive includes | ||
if (blackPath.includes(include)) return | ||
let dependencyContent = '' | ||
let path = include | ||
// @ts-ignore | ||
const pathExists = await this.call('fileManager', 'exists', path) | ||
|
||
if (pathExists) { | ||
// fetch file content if include import (path) exists within same level as current file opened in editor | ||
dependencyContent = await this.call('fileManager', 'readFile', path) | ||
} else { | ||
// if include import (path) does not exist, try to construct relative path using the original file path (current file opened in editor) | ||
let relativePath = pathModule.resolve( | ||
filePath.slice(0, filePath.lastIndexOf('/')), | ||
include | ||
) | ||
if (relativePath.indexOf('/') === 0) | ||
relativePath = relativePath.slice(1) | ||
const relativePathExists = await this.call( | ||
'fileManager', | ||
// @ts-ignore | ||
'exists', | ||
relativePath | ||
) | ||
|
||
if (relativePathExists) { | ||
// fetch file content if include import exists as a relative path | ||
dependencyContent = await this.call( | ||
'fileManager', | ||
'readFile', | ||
relativePath | ||
) | ||
} else { | ||
if (depPath) { | ||
// if depPath is provided, try to resolve include import from './deps' folder in remix | ||
path = pathModule.resolve( | ||
depPath.slice(0, depPath.lastIndexOf('/')), | ||
include | ||
) | ||
if (path.indexOf('/') === 0) path = path.slice(1) | ||
dependencyContent = await this.call( | ||
'contentImport', | ||
'resolveAndSave', | ||
path, | ||
null | ||
) | ||
} else { | ||
if (include.startsWith('circomlib')) { | ||
// try to resolve include import from github if it is a circomlib dependency | ||
const splitInclude = include.split('/') | ||
const version = splitInclude[1].match(/v[0-9]+.[0-9]+.[0-9]+/g) | ||
|
||
if (version && version[0]) { | ||
path = `https://raw.githubusercontent.com/iden3/circomlib/${ | ||
version[0] | ||
}/circuits/${splitInclude.slice(2).join('/')}` | ||
dependencyContent = await this.call( | ||
'contentImport', | ||
'resolveAndSave', | ||
path, | ||
null | ||
) | ||
} else { | ||
path = `https://raw.githubusercontent.com/iden3/circomlib/master/circuits/${splitInclude | ||
.slice(1) | ||
.join('/')}` | ||
dependencyContent = await this.call( | ||
'contentImport', | ||
'resolveAndSave', | ||
path, | ||
null | ||
) | ||
} | ||
} else { | ||
// If all import cases are not true, use the default import to try fetching from node_modules and unpkg | ||
dependencyContent = await this.call( | ||
'contentImport', | ||
'resolveAndSave', | ||
path, | ||
null | ||
) | ||
} | ||
} | ||
} | ||
} | ||
// extract all includes from the dependency content | ||
const dependencyIncludes = ( | ||
dependencyContent.match(/include ['"].*['"]/g) || [] | ||
).map((include) => | ||
include.replace(/include ['"]/g, '').replace(/['"]/g, '') | ||
) | ||
|
||
blackPath.push(include) | ||
// recursively resolve all dependencies of the dependency | ||
if (dependencyIncludes.length > 0) { | ||
await this.resolveDependencies( | ||
filePath, | ||
dependencyContent, | ||
output, | ||
path, | ||
blackPath | ||
) | ||
output[include] = dependencyContent | ||
} else { | ||
output[include] = dependencyContent | ||
} | ||
}) | ||
) | ||
return output | ||
} | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
pragma circom 2.0.0; | ||
|
||
template Multiplier2() { | ||
signal input a; | ||
signal input b; | ||
signal output c; | ||
c <== a*b; | ||
} | ||
|
||
component main = Multiplier2(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<title>Circuit - Compiler</title> | ||
<base href="./" /> | ||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous"/> | ||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous"> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import React from 'react' | ||
import ReactDOM from 'react-dom' | ||
import App from './app/app' | ||
|
||
ReactDOM.render( | ||
<App />, | ||
document.getElementById('root') | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** | ||
* Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. | ||
* | ||
* See: https://github.com/zloirock/core-js#babel | ||
*/ | ||
import 'core-js/stable'; | ||
import 'regenerator-runtime/runtime'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "circuit-compiler", | ||
"kind": "provider", | ||
"displayName": "Circuit Compiler", | ||
"events": [], | ||
"version": "2.0.0", | ||
"methods": ["init", "parse"], | ||
"canActivate": [], | ||
"url": "", | ||
"description": "Enables circuit compilation and computing a witness for ZK proofs", | ||
"icon": "https://docs.circom.io/assets/images/favicon.png", | ||
"location": "sidePanel", | ||
"documentation": "", | ||
"repo": "https://github.com/ethereum/remix-project/tree/master/apps/circuit-compiler", | ||
"maintainedBy": "Remix", | ||
"authorContact": "" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"extends": "./tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "../../dist/out-tsc", | ||
"types": ["node"] | ||
}, | ||
"files": [ | ||
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts", | ||
"../../node_modules/@nrwl/react/typings/image.d.ts" | ||
], | ||
"exclude": [ | ||
"jest.config.ts", | ||
"**/*.spec.ts", | ||
"**/*.test.ts", | ||
"**/*.spec.tsx", | ||
"**/*.test.tsx", | ||
"**/*.spec.js", | ||
"**/*.test.js", | ||
"**/*.spec.jsx", | ||
"**/*.test.jsx" | ||
], | ||
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] | ||
} | ||
|
Oops, something went wrong.