From e3ae1a6e9ecd96f7db4ed72fcdb5018e497efa58 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 25 Dec 2024 01:26:54 +0000 Subject: [PATCH 01/15] Load browser compiler --- apps/noir-compiler/src/app/app.tsx | 9 + .../src/app/services/noirFileManager.ts | 163 ++++++++++++++++ .../src/app/services/noirPluginClient.ts | 40 +++- .../src/app/services/remixMockFs.ts | 38 ++++ apps/noir-compiler/src/css/app.css | 0 apps/noir-compiler/src/main.tsx | 3 +- apps/noir-compiler/src/profile.json | 4 +- apps/remix-ide/project.json | 2 +- apps/remix-ide/src/app/plugins/matomo.ts | 2 +- apps/remix-ide/src/remixAppManager.js | 3 +- apps/remix-ide/src/remixEngine.js | 1 + .../helper/src/lib/remix-ui-helper.ts | 2 +- libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx | 10 +- package.json | 1 + yarn.lock | 177 +++++++++++++++++- 15 files changed, 436 insertions(+), 19 deletions(-) create mode 100644 apps/noir-compiler/src/app/app.tsx create mode 100644 apps/noir-compiler/src/app/services/noirFileManager.ts create mode 100644 apps/noir-compiler/src/app/services/remixMockFs.ts create mode 100644 apps/noir-compiler/src/css/app.css diff --git a/apps/noir-compiler/src/app/app.tsx b/apps/noir-compiler/src/app/app.tsx new file mode 100644 index 00000000000..e037648cfcb --- /dev/null +++ b/apps/noir-compiler/src/app/app.tsx @@ -0,0 +1,9 @@ +import { NoirPluginClient } from "./services/noirPluginClient"; + +const plugin = new NoirPluginClient() + +function App() { + return <> +} + +export default App \ No newline at end of file diff --git a/apps/noir-compiler/src/app/services/noirFileManager.ts b/apps/noir-compiler/src/app/services/noirFileManager.ts new file mode 100644 index 00000000000..62a4f46bfbb --- /dev/null +++ b/apps/noir-compiler/src/app/services/noirFileManager.ts @@ -0,0 +1,163 @@ +import { dirname, isAbsolute, join } from 'path'; + +/** + * A file system interface that matches the node fs module. + */ +export interface FileSystem { + /** Checks if the file exists */ + existsSync: (path: string) => boolean; + /** Creates a directory structure */ + mkdir: ( + dir: string, + opts?: { + /** Create parent directories as needed */ + recursive: boolean; + }, + ) => Promise; + /** Writes a file */ + writeFile: (path: string, data: Uint8Array) => Promise; + /** Reads a file */ + readFile: (path: string, encoding?: 'utf-8') => Promise; + /** Renames a file */ + rename: (oldPath: string, newPath: string) => Promise; + /** Reads a directory */ + readdir: ( + path: string, + options?: { + /** Traverse child directories recursively */ + recursive: boolean; + }, + ) => Promise; +} + +/** + * A file manager that writes file to a specific directory but reads globally. + */ +export class FileManager { + #fs: FileSystem; + #dataDir: string; + + constructor(fs: FileSystem, dataDir: string) { + this.#fs = fs; + this.#dataDir = dataDir; + } + + /** + * Returns the data directory + */ + getDataDir() { + return this.#dataDir; + } + + /** + * Saves a file to the data directory. + * @param name - File to save + * @param stream - File contents + */ + public async writeFile(name: string, stream: ReadableStream): Promise { + if (isAbsolute(name)) { + throw new Error("can't write absolute path"); + } + + const path = this.#getPath(name); + const chunks: Uint8Array[] = []; + const reader = stream.getReader(); + + // eslint-disable-next-line no-constant-condition + while (true) { + const { done, value } = await reader.read(); + if (done) { + break; + } + + chunks.push(value); + } + + const file = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0)); + let offset = 0; + for (const chunk of chunks) { + file.set(chunk, offset); + offset += chunk.length; + } + + await this.#fs.mkdir(dirname(path), { recursive: true }); + await this.#fs.writeFile(this.#getPath(path), file); + } + + /** + * Reads a file from the filesystem and returns a buffer + * Saves a file to the data directory. + * @param oldName - File to save + * @param newName - File contents + */ + async moveFile(oldName: string, newName: string) { + if (isAbsolute(oldName) || isAbsolute(newName)) { + throw new Error("can't move absolute path"); + } + + const oldPath = this.#getPath(oldName); + const newPath = this.#getPath(newName); + + await this.#fs.mkdir(dirname(newPath), { recursive: true }); + await this.#fs.rename(oldPath, newPath); + } + + /** + * Reads a file from the disk and returns a buffer + * @param name - File to read + */ + public async readFile(name: string): Promise; + /** + * Reads a file from the filesystem as a string + * @param name - File to read + * @param encoding - Encoding to use + */ + public async readFile(name: string, encoding: 'utf-8'): Promise; + /** + * Reads a file from the filesystem + * @param name - File to read + * @param encoding - Encoding to use + */ + public async readFile(name: string, encoding?: 'utf-8'): Promise { + const path = this.#getPath(name); + const data = await this.#fs.readFile(path, encoding); + + if (!encoding) { + return typeof data === 'string' + ? new TextEncoder().encode(data) // this branch shouldn't be hit, but just in case + : new Uint8Array(data.buffer, data.byteOffset, data.byteLength / Uint8Array.BYTES_PER_ELEMENT); + } + + return data; + } + + /** + * Checks if a file exists and is accessible + * @param name - File to check + */ + public hasFileSync(name: string): boolean { + return this.#fs.existsSync(this.#getPath(name)); + } + + #getPath(name: string) { + return isAbsolute(name) ? name : join(this.#dataDir, name); + } + + /** + * Reads a file from the filesystem + * @param dir - File to read + * @param options - Readdir options + */ + public async readdir( + dir: string, + options?: { + /** + * Traverse child directories recursively + */ + recursive: boolean; + }, + ) { + const dirPath = this.#getPath(dir); + return await this.#fs.readdir(dirPath, options); + } +} \ No newline at end of file diff --git a/apps/noir-compiler/src/app/services/noirPluginClient.ts b/apps/noir-compiler/src/app/services/noirPluginClient.ts index e2872172100..421ad8d6038 100644 --- a/apps/noir-compiler/src/app/services/noirPluginClient.ts +++ b/apps/noir-compiler/src/app/services/noirPluginClient.ts @@ -1,15 +1,31 @@ import { PluginClient } from '@remixproject/plugin' import { createClient } from '@remixproject/plugin-webview' import EventManager from 'events' +// @ts-ignore +import { compile_program, compile_contract, createFileManager } from '@noir-lang/noir_wasm/default' +import { NoirFS } from './remixMockFs' +import { FileManager } from './noirFileManager' +const DEFAULT_TOML_CONFIG = `[package] +name = "test" +authors = [""] +compiler_version = ">=0.18.0" +type = "bin" + +[dependencies] +` export class NoirPluginClient extends PluginClient { public internalEvents: EventManager + public fs: NoirFS + public fm: FileManager constructor() { super() - this.methods = ['init'] + this.methods = ['init', 'parse', 'compile'] createClient(this) this.internalEvents = new EventManager() + this.fs = new NoirFS(this) + this.fm = new FileManager(this.fs, '/') this.onload() } @@ -20,4 +36,26 @@ export class NoirPluginClient extends PluginClient { onActivation(): void { this.internalEvents.emit('noir_activated') } + + compile(path: string): void { + this.parse(path) + } + + async parse(path: string): Promise { + // @ts-ignore + const tomlFileExists = await this.call('fileManager', 'exists', '/Nargo.toml') + // @ts-ignore + const srcDirExists = await this.call('fileManager', 'exists', '/src') + + if (!tomlFileExists) { + await this.call('fileManager', 'writeFile', '/Nargo.toml', DEFAULT_TOML_CONFIG) + } + if (!srcDirExists) { + await this.call('fileManager', 'mkdir', '/src') + } + // @ts-ignore + const program = await compile_program(this.fm) + + console.log('program: ', program) + } } diff --git a/apps/noir-compiler/src/app/services/remixMockFs.ts b/apps/noir-compiler/src/app/services/remixMockFs.ts new file mode 100644 index 00000000000..9111e8baa40 --- /dev/null +++ b/apps/noir-compiler/src/app/services/remixMockFs.ts @@ -0,0 +1,38 @@ +import type { FileSystem } from './noirFileManager' +import { PluginClient } from '@remixproject/plugin' + +export class NoirFS implements FileSystem { + plugin: PluginClient + + constructor (plugin: PluginClient) { + this.plugin = plugin + } + + existsSync: (path: string) => boolean + + async readdir (path: string, options?: { recursive: boolean }): Promise { + console.log('readdir: ', path) + // @ts-ignore + return await this.plugin.call('fileManager', 'readdir', path, options) + } + + async rename (oldPath: string, newPath: string): Promise { + // @ts-ignore + return await this.plugin.call('fileManager', 'rename', oldPath, newPath) + } + + async readFile (path: string, encoding?: 'utf-8'): Promise { + // @ts-ignore + return await this.plugin.call('fileManager', 'readFile', path, { encoding: null }) + } + + async writeFile (path: string, data: Uint8Array): Promise { + // @ts-ignore + return await this.plugin.call('fileManager', 'writeFile', path, data, { encoding: null }) + } + + async mkdir (dir: string, opts?: { recursive: boolean }): Promise { + // @ts-ignore + return await this.plugin.call('fileManager', 'mkdir', dir, opts) + } +} \ No newline at end of file diff --git a/apps/noir-compiler/src/css/app.css b/apps/noir-compiler/src/css/app.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/noir-compiler/src/main.tsx b/apps/noir-compiler/src/main.tsx index 7c379bc3869..502a6c93a3d 100644 --- a/apps/noir-compiler/src/main.tsx +++ b/apps/noir-compiler/src/main.tsx @@ -1,8 +1,9 @@ import React from 'react' import { createRoot } from 'react-dom/client' +import App from './app/app' const container = document.getElementById('root') if (container) { - createRoot(container).render(<>) + createRoot(container).render() } \ No newline at end of file diff --git a/apps/noir-compiler/src/profile.json b/apps/noir-compiler/src/profile.json index e617ef74d66..5384f2a1919 100644 --- a/apps/noir-compiler/src/profile.json +++ b/apps/noir-compiler/src/profile.json @@ -4,11 +4,11 @@ "displayName": "Noir Compiler", "events": [], "version": "2.0.0", - "methods": ["init", "parse"], + "methods": ["init", "parse", "compile"], "canActivate": [], "url": "", "description": "Enables support for noir circuit compilation", - "icon": "assets/img/circom-icon-bw-800b.webp", + "icon": "assets/img/noir-icon-bw-800b.webp", "location": "sidePanel", "documentation": "", "repo": "https://github.com/ethereum/remix-project/tree/master/apps/noir-compiler", diff --git a/apps/remix-ide/project.json b/apps/remix-ide/project.json index a0f749c399c..ed4eb4d8510 100644 --- a/apps/remix-ide/project.json +++ b/apps/remix-ide/project.json @@ -3,7 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "apps/remix-ide/src", "projectType": "application", - "implicitDependencies": ["doc-gen", "doc-viewer", "contract-verification", "vyper", "solhint", "walletconnect", "circuit-compiler", "learneth", "quick-dapp", "remix-dapp"], + "implicitDependencies": ["doc-gen", "doc-viewer", "contract-verification", "vyper", "solhint", "walletconnect", "circuit-compiler", "learneth", "quick-dapp", "remix-dapp", "noir-compiler"], "targets": { "build": { "executor": "@nrwl/webpack:webpack", diff --git a/apps/remix-ide/src/app/plugins/matomo.ts b/apps/remix-ide/src/app/plugins/matomo.ts index 0421ec6a499..40c61e718e7 100644 --- a/apps/remix-ide/src/app/plugins/matomo.ts +++ b/apps/remix-ide/src/app/plugins/matomo.ts @@ -11,7 +11,7 @@ const profile = { version: '1.0.0' } -const allowedPlugins = ['LearnEth', 'etherscan', 'vyper', 'circuit-compiler', 'doc-gen', 'doc-viewer', 'solhint', 'walletconnect', 'scriptRunner', 'scriptRunnerBridge', 'dgit', 'contract-verification'] +const allowedPlugins = ['LearnEth', 'etherscan', 'vyper', 'circuit-compiler', 'doc-gen', 'doc-viewer', 'solhint', 'walletconnect', 'scriptRunner', 'scriptRunnerBridge', 'dgit', 'contract-verification', 'noir-compiler'] export class Matomo extends Plugin { diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 04179529601..c8df53a0580 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -95,7 +95,7 @@ let requiredModules = [ // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] -const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'contract-verification', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler', 'learneth', 'quick-dapp'] +const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'contract-verification', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler', 'learneth', 'quick-dapp', 'noir-compiler'] const partnerPlugins = ['cookbookdev'] @@ -151,6 +151,7 @@ export function isNative(name) { 'contract-verification', 'popupPanel', 'LearnEth', + 'noir-compiler' ] return nativePlugins.includes(name) || requiredModules.includes(name) || isInjectedProvider(name) || isVM(name) || isScriptRunner(name) } diff --git a/apps/remix-ide/src/remixEngine.js b/apps/remix-ide/src/remixEngine.js index b883655e55e..ba26ef02470 100644 --- a/apps/remix-ide/src/remixEngine.js +++ b/apps/remix-ide/src/remixEngine.js @@ -31,6 +31,7 @@ export class RemixEngine extends Engine { if (name === 'cookbookdev') return { queueTimeout: 60000 * 3 } if (name === 'contentImport') return { queueTimeout: 60000 * 3 } if (name === 'circom') return { queueTimeout: 60000 * 4 } + if (name === 'noir-compiler') return { queueTimeout: 60000 * 4 } return { queueTimeout: 10000 } } diff --git a/libs/remix-ui/helper/src/lib/remix-ui-helper.ts b/libs/remix-ui/helper/src/lib/remix-ui-helper.ts index aecc3ebc690..7657a3a7cfa 100644 --- a/libs/remix-ui/helper/src/lib/remix-ui-helper.ts +++ b/libs/remix-ui/helper/src/lib/remix-ui-helper.ts @@ -82,7 +82,7 @@ export const getPathIcon = (path: string) => { ? 'fad fa-brackets-curly' : path.endsWith('.cairo') ? 'small fa-kit fa-cairo' : path.endsWith('.circom') ? 'fa-kit fa-circom' : path.endsWith('.nr') - ? 'fa-duotone fa-regular fa-diamond' : 'far fa-file' + ? 'fa-kit fa-noir' : 'far fa-file' } export const isNumeric = (value) => { diff --git a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx index 0d279961a33..b8d1ce97346 100644 --- a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx +++ b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx @@ -66,6 +66,7 @@ const tabsReducer = (state: ITabsState, action: ITabsAction) => { return state } } +const PlayExtList = ['js', 'ts', 'sol', 'circom', 'vy', 'nr'] export const TabsUI = (props: TabsUIProps) => { const [tabsState, dispatch] = useReducer(tabsReducer, initialTabsState) @@ -208,23 +209,22 @@ export const TabsUI = (props: TabsUIProps) => { - - ) -} \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/components/container.tsx b/apps/circuit-compiler/src/app/components/container.tsx index c1034576f70..c54e9f710e9 100644 --- a/apps/circuit-compiler/src/app/components/container.tsx +++ b/apps/circuit-compiler/src/app/components/container.tsx @@ -1,17 +1,17 @@ import { useContext } from 'react' -import { CustomTooltip, RenderIf } from '@remix-ui/helper' +import { CompileBtn, CustomTooltip, RenderIf } from '@remix-ui/helper' import { FormattedMessage } from 'react-intl' import { CircuitAppContext } from '../contexts' -import { CompileOptions } from './options' +import { CompileOptions } from '@remix-ui/helper' import { VersionList } from './versions' import { Toggler } from './toggler' import { Configurations } from './configurations' -import { CircuitActions } from './actions' import { WitnessSection } from './witness' import { CompilerFeedback } from './feedback' import { CompilerReport, PrimeValue } from '../types' import { SetupExports } from './setupExports' import { GenerateProof } from './generateProof' +import { compileCircuit } from '../actions' export function Container () { const circuitApp = useContext(CircuitAppContext) @@ -102,6 +102,10 @@ export function Container () { } } + const handleCompileClick = () => { + compileCircuit(circuitApp.plugin, circuitApp.appState) + } + return (
@@ -123,7 +127,9 @@ export function Container () { - +
+ +
diff --git a/apps/circuit-compiler/src/app/components/options.tsx b/apps/circuit-compiler/src/app/components/options.tsx deleted file mode 100644 index 85161c1b3fc..00000000000 --- a/apps/circuit-compiler/src/app/components/options.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import {FormattedMessage} from 'react-intl' -import { CompileOptionsProps } from '../types' - -export function CompileOptions ({autoCompile, hideWarnings, setCircuitAutoCompile, setCircuitHideWarnings}: CompileOptionsProps) { - - return ( -
-
- setCircuitAutoCompile(e.target.checked)} - title="Auto compile" - checked={autoCompile} - id="autoCompileCircuit" - /> - -
-
- setCircuitHideWarnings(e.target.checked)} - id="hideCircuitWarnings" - type="checkbox" - title="Hide warnings" - checked={hideWarnings} - /> - -
-
- ) -} \ No newline at end of file diff --git a/apps/noir-compiler/src/app/actions/index.ts b/apps/noir-compiler/src/app/actions/index.ts new file mode 100644 index 00000000000..0fbae216441 --- /dev/null +++ b/apps/noir-compiler/src/app/actions/index.ts @@ -0,0 +1,16 @@ +import { NoirPluginClient } from "../services/noirPluginClient" +import { AppState } from "../types" + +export const compileNoirCircuit = async (plugin: NoirPluginClient, appState: AppState) => { + try { + if (appState.status !== "compiling") { + await plugin.compile(appState.filePath) + } else { + console.log('Existing noir compilation in progress') + } + } catch (e) { + plugin.emit('statusChanged', { key: 'error', title: e.message, type: 'error' }) + plugin.internalEvents.emit('noir_compiling_errored', e) + console.error(e) + } +} \ No newline at end of file diff --git a/apps/noir-compiler/src/app/app.tsx b/apps/noir-compiler/src/app/app.tsx index 23d8fb1bbc8..5fae7839e59 100644 --- a/apps/noir-compiler/src/app/app.tsx +++ b/apps/noir-compiler/src/app/app.tsx @@ -1,14 +1,15 @@ -import { useEffect, useState } from "react" +import { useEffect, useReducer, useState } from "react" import { NoirPluginClient } from "./services/noirPluginClient" import { RenderIf } from '@remix-ui/helper' import { IntlProvider } from 'react-intl' import { Container } from "./components/container" import { NoirAppContext } from "./contexts" +import { appInitialState, appReducer } from "./reducers/state" const plugin = new NoirPluginClient() function App() { - // const [appState, dispatch] = useReducer(appReducer, appInitialState) + const [appState, dispatch] = useReducer(appReducer, appInitialState) const [locale, setLocale] = useState<{code: string; messages: any}>({ code: 'en', messages: null @@ -40,7 +41,9 @@ function App() { } const value = { - plugin + plugin, + dispatch, + appState } return ( diff --git a/apps/noir-compiler/src/app/components/container.tsx b/apps/noir-compiler/src/app/components/container.tsx index 32a6498ccbc..886b5255591 100644 --- a/apps/noir-compiler/src/app/components/container.tsx +++ b/apps/noir-compiler/src/app/components/container.tsx @@ -1,7 +1,9 @@ import { useContext } from 'react' -import { CustomTooltip, RenderIf } from '@remix-ui/helper' +import { CompileBtn, CustomTooltip, RenderIf } from '@remix-ui/helper' import { FormattedMessage } from 'react-intl' import { NoirAppContext } from '../contexts' +import { CompileOptions } from '@remix-ui/helper' +import { compileNoirCircuit } from '../actions' export function Container () { const noirApp = useContext(NoirAppContext) @@ -19,11 +21,6 @@ export function Container () { } } - // const handleVersionSelect = (version: string) => { - // circuitApp.plugin.compilerVersion = version - // circuitApp.dispatch({ type: 'SET_COMPILER_VERSION', payload: version }) - // } - // const handleOpenErrorLocation = async (location: string, startRange: string) => { // if (location) { // const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) @@ -41,13 +38,13 @@ export function Container () { // circuitApp.dispatch({ type: 'SET_PRIME_VALUE', payload: value as PrimeValue }) // } - // const handleCircuitAutoCompile = (value: boolean) => { - // circuitApp.dispatch({ type: 'SET_AUTO_COMPILE', payload: value }) - // } + const handleCircuitAutoCompile = (value: boolean) => { + noirApp.dispatch({ type: 'SET_AUTO_COMPILE', payload: value }) + } - // const handleCircuitHideWarnings = (value: boolean) => { - // circuitApp.dispatch({ type: 'SET_HIDE_WARNINGS', payload: value }) - // } + const handleCircuitHideWarnings = (value: boolean) => { + noirApp.dispatch({ type: 'SET_HIDE_WARNINGS', payload: value }) + } // const askGPT = async (report: CompilerReport) => { // if (report.labels.length > 0) { @@ -92,6 +89,10 @@ export function Container () { // } // } + const handleCompileClick = () => { + compileNoirCircuit(noirApp.plugin, noirApp.appState) + } + return (
@@ -108,13 +109,11 @@ export function Container () { > showCompilerLicense()}> - {/* - - - - - - + +
+ +
+ {/* */} diff --git a/apps/noir-compiler/src/app/reducers/state.ts b/apps/noir-compiler/src/app/reducers/state.ts new file mode 100644 index 00000000000..3fd53e48f56 --- /dev/null +++ b/apps/noir-compiler/src/app/reducers/state.ts @@ -0,0 +1,34 @@ +import { Actions, AppState } from '../types' + +export interface ActionPayloadTypes { + SET_AUTO_COMPILE: boolean, + SET_HIDE_WARNINGS: boolean +} + +export const appInitialState: AppState = { + filePath: '', + filePathToId: {}, + autoCompile: false, + hideWarnings: false, + status: 'idle' +} + +export const appReducer = (state = appInitialState, action: Actions): AppState => { + switch (action.type) { + + case 'SET_AUTO_COMPILE': + return { + ...state, + autoCompile: action.payload + } + + case 'SET_HIDE_WARNINGS': + return { + ...state, + hideWarnings: action.payload + } + + default: + throw new Error() + } +} diff --git a/apps/noir-compiler/src/app/types/index.ts b/apps/noir-compiler/src/app/types/index.ts index ecb6d622e75..96a84cf241e 100644 --- a/apps/noir-compiler/src/app/types/index.ts +++ b/apps/noir-compiler/src/app/types/index.ts @@ -1,18 +1,26 @@ import { compiler_list } from 'circom_wasm' import { Dispatch } from 'react' import type { NoirPluginClient } from '../services/noirPluginClient' +import { ActionPayloadTypes } from '../reducers/state' +export type CompilerStatus = "compiling" | "idle" | "errored" | "warning" export interface INoirAppContext { - // appState: AppState -// dispatch: Dispatch, + appState: AppState + dispatch: Dispatch, plugin: NoirPluginClient } export interface AppState { - version: string, - versionList: typeof compiler_list.wasm_builds, filePath: string, filePathToId: Record, autoCompile: boolean, - hideWarnings: boolean + hideWarnings: boolean, + status: CompilerStatus } + +export interface Action { + type: T + payload: ActionPayloadTypes[T] +} + +export type Actions = {[A in keyof ActionPayloadTypes]: Action}[keyof ActionPayloadTypes] diff --git a/apps/noir-compiler/src/css/app.css b/apps/noir-compiler/src/css/app.css index e69de29bb2d..b5676189ff3 100644 --- a/apps/noir-compiler/src/css/app.css +++ b/apps/noir-compiler/src/css/app.css @@ -0,0 +1,101 @@ +body { + font-size : .8rem; +} +.noir_section { + padding: 12px 24px 16px; +} +.noir_label { + margin-bottom: 2px; + font-size: 11px; + line-height: 12px; + text-transform: uppercase; +} +.noir_warnings_box { + display: flex; + align-items: center; +} +.noir_warnings_box label { + margin: 0; +} +.noir_config_section:hover { + cursor: pointer; +} +.noir_config_section { + font-size: 1rem; +} +.noir_config { + display: flex; + align-items: center; +} +.noir_config label { + margin: 0; +} +.noir_inner_label { + margin-bottom: 2px; + font-size: 11px; + line-height: 12px; + text-transform: uppercase; +} +.noir_errors_box { + word-break: break-word; +} +.noir_feedback.success, +.noir_feedback.error, +.noir_feedback.warning { + white-space: pre-line; + word-wrap: break-word; + cursor: pointer; + position: relative; + margin: 0.5em 0 1em 0; + border-radius: 5px; + line-height: 20px; + padding: 8px 15px; +} + +.noir_feedback.success pre, +.noir_feedback.error pre, +.noir_feedback.warning pre { + white-space: pre-line; + overflow-y: hidden; + background-color: transparent; + margin: 0; + font-size: 12px; + border: 0 none; + padding: 0; + border-radius: 0; +} + +.noir_feedback.success .close, +.noir_feedback.error .close, +.noir_feedback.warning .close { + visibility: hidden; + white-space: pre-line; + font-weight: bold; + position: absolute; + color: hsl(0, 0%, 0%); /* black in style-guide.js */ + top: 0; + right: 0; + padding: 0.5em; +} + +.noir_feedback.success a, +.noir_feedback.error a, +.noir_feedback.warning a { + bottom: 0; + right: 0; +} +.custom-dropdown-items { + padding: 0.25rem 0.25rem; + border-radius: .25rem; + background: var(--custom-select); +} +.custom-dropdown-items a { + border-radius: .25rem; + text-transform: none; + text-decoration: none; + font-weight: normal; + font-size: 0.875rem; + padding: 0.25rem 0.25rem; + width: auto; + color: var(--text); +} diff --git a/apps/noir-compiler/webpack.config.js b/apps/noir-compiler/webpack.config.js index 22bc8fabb37..0298a8605f7 100644 --- a/apps/noir-compiler/webpack.config.js +++ b/apps/noir-compiler/webpack.config.js @@ -11,7 +11,7 @@ module.exports = composePlugins(withNx(), (config) => { let pkgNoirWasm = fs.readFileSync(path.resolve(__dirname, '../../node_modules/@noir-lang/noir_wasm/package.json'), 'utf8') let typeCount = 0 - pkgNoirWasm = pkgNoirWasm.replace("node", "./node").replace("import", "./import").replace("require", "./require").replace(/"types"/g, match => ++typeCount === 2 ? '"./types"' : match).replace("default", "./default") + pkgNoirWasm = pkgNoirWasm.replace(/"node"/, '"./node"').replace(/"import"/, '"./import"').replace(/"require"/, '"./require"').replace(/"types"/g, match => ++typeCount === 2 ? '"./types"' : match).replace(/"default"/, '"./default"') fs.writeFileSync(path.resolve(__dirname, '../../node_modules/@noir-lang/noir_wasm/package.json'), pkgNoirWasm) console.log('pkgNoirWasm: ', pkgNoirWasm) diff --git a/libs/remix-ui/helper/src/lib/helper-components.tsx b/libs/remix-ui/helper/src/lib/helper-components.tsx index 663955414e3..81d7aa9d5e3 100644 --- a/libs/remix-ui/helper/src/lib/helper-components.tsx +++ b/libs/remix-ui/helper/src/lib/helper-components.tsx @@ -1,5 +1,9 @@ import { LayoutCompatibilityReport } from '@openzeppelin/upgrades-core/dist/storage/report' import React from 'react' +import { FormattedMessage } from 'react-intl' +import { CompileOptionsProps } from '../types/compilerTypes' +import { CustomTooltip } from './components/custom-tooltip' +import { extractNameFromKey } from './remix-ui-helper' export const fileChangedToastMsg = (from: string, path: string) => (
@@ -142,3 +146,75 @@ export function RenderIf({ condition, children }: { condition: boolean, children export function RenderIfNot({ condition, children }: { condition: boolean, children: JSX.Element }) { return condition ? null : children } + +export const CompileOptions = ({ autoCompile, hideWarnings, setCircuitAutoCompile, setCircuitHideWarnings }: CompileOptionsProps) => ( + +
+
+ setCircuitAutoCompile(e.target.checked)} + title="Auto compile" + checked={autoCompile} + id="autoCompileCircuit" + /> + +
+
+ setCircuitHideWarnings(e.target.checked)} + id="hideCircuitWarnings" + type="checkbox" + title="Hide warnings" + checked={hideWarnings} + /> + +
+
+) + +export const CompileBtn = ({ plugin, appState, id, compileAction }: { plugin: any, appState: { status, filePath }, id: string, compileAction: () => void }) => ( + +
+ Ctrl+S to compile {appState.filePath} +
+
+ } + > + + +) diff --git a/libs/remix-ui/helper/src/types/compilerTypes.ts b/libs/remix-ui/helper/src/types/compilerTypes.ts new file mode 100644 index 00000000000..b7741b5ac72 --- /dev/null +++ b/libs/remix-ui/helper/src/types/compilerTypes.ts @@ -0,0 +1,6 @@ +export type CompileOptionsProps = { + setCircuitAutoCompile: (value: boolean) => void, + setCircuitHideWarnings: (value: boolean) => void, + autoCompile: boolean, + hideWarnings: boolean + } \ No newline at end of file From b6a69db0d70342edc3d6f02d07ce0a3ae9bdfb1d Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 15 Jan 2025 09:05:52 +0000 Subject: [PATCH 07/15] show compile button for .nr files --- apps/noir-compiler/src/app/app.tsx | 14 +++ .../src/app/components/container.tsx | 113 +++++++++--------- apps/noir-compiler/src/app/reducers/state.ts | 11 +- apps/noir-compiler/src/app/types/index.ts | 6 +- .../helper/src/lib/components/feedback.tsx | 72 +++++++++++ .../src/lib/components/feedbackAlert.tsx | 32 +++++ .../helper/src/lib/remix-ui-helper.ts | 3 +- 7 files changed, 185 insertions(+), 66 deletions(-) create mode 100644 libs/remix-ui/helper/src/lib/components/feedback.tsx create mode 100644 libs/remix-ui/helper/src/lib/components/feedbackAlert.tsx diff --git a/apps/noir-compiler/src/app/app.tsx b/apps/noir-compiler/src/app/app.tsx index 5fae7839e59..bcb69ddf334 100644 --- a/apps/noir-compiler/src/app/app.tsx +++ b/apps/noir-compiler/src/app/app.tsx @@ -23,6 +23,20 @@ function App() { plugin.on('locale', 'localeChanged', (locale: any) => { setLocale(locale) }) + plugin.on('fileManager', 'currentFileChanged', (filePath) => { + if (filePath.endsWith('.nr')) { + dispatch({ type: 'SET_FILE_PATH', payload: filePath }) + plugin.parse(filePath) + } + }) + // @ts-ignore + plugin.on('editor', 'contentChanged', async (path: string, content: string) => { + setIsContentChanged(true) + // check if autoCompile is enabled + // if (path.endsWith('.nr')) { + // plugin.parse(path, content) + // } + }) setIsPluginActivated(true) }) }, []) diff --git a/apps/noir-compiler/src/app/components/container.tsx b/apps/noir-compiler/src/app/components/container.tsx index 886b5255591..0fe4ffc8e84 100644 --- a/apps/noir-compiler/src/app/components/container.tsx +++ b/apps/noir-compiler/src/app/components/container.tsx @@ -21,22 +21,17 @@ export function Container () { } } - // const handleOpenErrorLocation = async (location: string, startRange: string) => { - // if (location) { - // const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) + const handleOpenErrorLocation = async (location: string, startRange: string) => { + if (location) { + const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) - // await circuitApp.plugin.call('fileManager', 'open', fullPathLocation) - // // @ts-ignore - // const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange) - // // @ts-ignore - // await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column) - // } - // } - - // const handlePrimeChange = (value: PrimeValue) => { - // circuitApp.plugin.compilerPrime = value - // circuitApp.dispatch({ type: 'SET_PRIME_VALUE', payload: value as PrimeValue }) - // } + await circuitApp.plugin.call('fileManager', 'open', fullPathLocation) + // @ts-ignore + const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange) + // @ts-ignore + await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column) + } + } const handleCircuitAutoCompile = (value: boolean) => { noirApp.dispatch({ type: 'SET_AUTO_COMPILE', payload: value }) @@ -46,48 +41,48 @@ export function Container () { noirApp.dispatch({ type: 'SET_HIDE_WARNINGS', payload: value }) } - // const askGPT = async (report: CompilerReport) => { - // if (report.labels.length > 0) { - // const location = circuitApp.appState.filePathToId[report.labels[0].file_id] - // const error = report.labels[0].message + const askGPT = async (report: CompilerReport) => { + if (report.labels.length > 0) { + const location = circuitApp.appState.filePathToId[report.labels[0].file_id] + const error = report.labels[0].message - // if (location) { - // const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) - // const content = await circuitApp.plugin.call('fileManager', 'readFile', fullPathLocation) - // const message = ` - // circom code: ${content} - // error message: ${error} - // full circom error: ${JSON.stringify(report, null, 2)} - // explain why the error occurred and how to fix it. - // ` - // await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) - // setTimeout(async () => { - // await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) - // }, 500) - // } else { - // const message = ` - // error message: ${error} - // full circom error: ${JSON.stringify(report, null, 2)} - // explain why the error occurred and how to fix it. - // ` - // await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) - // setTimeout(async () => { - // await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) - // }, 500) - // } - // } else { - // const error = report.message - // const message = ` - // error message: ${error} - // full circom error: ${JSON.stringify(report, null, 2)} - // explain why the error occurred and how to fix it. - // ` - // await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) - // setTimeout(async () => { - // await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) - // }, 500) - // } - // } + if (location) { + const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) + const content = await circuitApp.plugin.call('fileManager', 'readFile', fullPathLocation) + const message = ` + circom code: ${content} + error message: ${error} + full circom error: ${JSON.stringify(report, null, 2)} + explain why the error occurred and how to fix it. + ` + await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) + setTimeout(async () => { + await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) + }, 500) + } else { + const message = ` + error message: ${error} + full circom error: ${JSON.stringify(report, null, 2)} + explain why the error occurred and how to fix it. + ` + await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) + setTimeout(async () => { + await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) + }, 500) + } + } else { + const error = report.message + const message = ` + error message: ${error} + full circom error: ${JSON.stringify(report, null, 2)} + explain why the error occurred and how to fix it. + ` + await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) + setTimeout(async () => { + await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) + }, 500) + } + } const handleCompileClick = () => { compileNoirCircuit(noirApp.plugin, noirApp.appState) @@ -113,9 +108,9 @@ export function Container () {
- {/* - - */} + + +
diff --git a/apps/noir-compiler/src/app/reducers/state.ts b/apps/noir-compiler/src/app/reducers/state.ts index 3fd53e48f56..8230ade8200 100644 --- a/apps/noir-compiler/src/app/reducers/state.ts +++ b/apps/noir-compiler/src/app/reducers/state.ts @@ -1,10 +1,5 @@ import { Actions, AppState } from '../types' -export interface ActionPayloadTypes { - SET_AUTO_COMPILE: boolean, - SET_HIDE_WARNINGS: boolean -} - export const appInitialState: AppState = { filePath: '', filePathToId: {}, @@ -28,6 +23,12 @@ export const appReducer = (state = appInitialState, action: Actions): AppState = hideWarnings: action.payload } + case 'SET_FILE_PATH': + return { + ...state, + filePath: action.payload + } + default: throw new Error() } diff --git a/apps/noir-compiler/src/app/types/index.ts b/apps/noir-compiler/src/app/types/index.ts index 96a84cf241e..f927f9c31b0 100644 --- a/apps/noir-compiler/src/app/types/index.ts +++ b/apps/noir-compiler/src/app/types/index.ts @@ -1,7 +1,6 @@ import { compiler_list } from 'circom_wasm' import { Dispatch } from 'react' import type { NoirPluginClient } from '../services/noirPluginClient' -import { ActionPayloadTypes } from '../reducers/state' export type CompilerStatus = "compiling" | "idle" | "errored" | "warning" export interface INoirAppContext { @@ -18,6 +17,11 @@ export interface AppState { status: CompilerStatus } +export interface ActionPayloadTypes { + SET_AUTO_COMPILE: boolean, + SET_HIDE_WARNINGS: boolean, + SET_FILE_PATH: string +} export interface Action { type: T payload: ActionPayloadTypes[T] diff --git a/libs/remix-ui/helper/src/lib/components/feedback.tsx b/libs/remix-ui/helper/src/lib/components/feedback.tsx new file mode 100644 index 00000000000..af42b20d862 --- /dev/null +++ b/libs/remix-ui/helper/src/lib/components/feedback.tsx @@ -0,0 +1,72 @@ +import { useState } from 'react' +import { CompilerFeedbackProps, CompilerReport } from '../types' +import { RenderIf } from '@remix-ui/helper' +import { CopyToClipboard } from '@remix-ui/clipboard' +import { FeedbackAlert } from './feedbackAlert' + +export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openErrorLocation, askGPT }: CompilerFeedbackProps) { + const [showException, setShowException] = useState(true) + + const handleCloseException = () => { + setShowException(false) + } + + const handleOpenError = (report: CompilerReport) => { + if (report.labels.length > 0) { + openErrorLocation(filePathToId[report.labels[0].file_id], report.labels[0].range.start) + } + } + + const handleAskGPT = (report: CompilerReport) => { + askGPT(report) + } + + return ( +
+ { + (feedback && typeof feedback === 'string') || (Array.isArray(feedback) && feedback.length > 0) ? ( +
+ +
+ <>{ feedback } +
+ +
+
+ + + +
+
+
+ + <> + { + Array.isArray(feedback) && feedback.map((response, index) => ( +
handleOpenError(response)}> + +
+ handleAskGPT(response) } /> +
+
+ +
+ { handleAskGPT(response) }} /> +
+
+
+ ) + ) + } + +
+
+ ) : <> + } +
+ ) +} diff --git a/libs/remix-ui/helper/src/lib/components/feedbackAlert.tsx b/libs/remix-ui/helper/src/lib/components/feedbackAlert.tsx new file mode 100644 index 00000000000..c6328dd510a --- /dev/null +++ b/libs/remix-ui/helper/src/lib/components/feedbackAlert.tsx @@ -0,0 +1,32 @@ +import { useState } from 'react' +import { FeedbackAlertProps } from '../types' +import { RenderIf } from '@remix-ui/helper' +import {CopyToClipboard} from '@remix-ui/clipboard' + +export function FeedbackAlert ({ message, askGPT }: FeedbackAlertProps) { + const [ showAlert, setShowAlert] = useState(true) + + const handleCloseAlert = () => { + setShowAlert(false) + } + + return ( + + <> + { message } +
+ +
+
+ + + + { + e.stopPropagation() + askGPT() + }}>Ask RemixAI +
+ +
+ ) +} diff --git a/libs/remix-ui/helper/src/lib/remix-ui-helper.ts b/libs/remix-ui/helper/src/lib/remix-ui-helper.ts index 7657a3a7cfa..32e3947b822 100644 --- a/libs/remix-ui/helper/src/lib/remix-ui-helper.ts +++ b/libs/remix-ui/helper/src/lib/remix-ui-helper.ts @@ -82,7 +82,8 @@ export const getPathIcon = (path: string) => { ? 'fad fa-brackets-curly' : path.endsWith('.cairo') ? 'small fa-kit fa-cairo' : path.endsWith('.circom') ? 'fa-kit fa-circom' : path.endsWith('.nr') - ? 'fa-kit fa-noir' : 'far fa-file' + ? 'fa-kit fa-noir' : path.endsWith('.toml') + ? 'fad fa-cog': 'far fa-file' } export const isNumeric = (value) => { From 1f1ba79db90ecc587a659fe14bd1da7193fff4b3 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 20 Jan 2025 18:01:00 +0000 Subject: [PATCH 08/15] Show warnings and add new icon --- .../src/app/components/container.tsx | 26 +++-- .../src/app/components/feedback.tsx | 72 ------------- .../src/app/components/feedbackAlert.tsx | 32 ------ .../src/app/services/circomPluginClient.ts | 4 +- apps/circuit-compiler/src/app/types/index.ts | 29 +----- apps/noir-compiler/src/app/actions/index.ts | 14 +-- apps/noir-compiler/src/app/app.tsx | 18 ++++ .../src/app/components/container.tsx | 95 +++++++++--------- apps/noir-compiler/src/app/reducers/state.ts | 15 ++- .../src/app/services/noirPluginClient.ts | 24 +++-- apps/noir-compiler/src/app/types/index.ts | 7 +- apps/noir-compiler/src/profile.json | 2 +- apps/remix-ide/src/assets/img/noir-icon.webp | Bin 0 -> 8258 bytes libs/remix-ui/helper/src/index.ts | 4 +- .../helper/src/lib/components/feedback.tsx | 20 +--- .../src/lib/components/feedbackAlert.tsx | 8 +- .../helper/src/types/compilerTypes.ts | 28 ++++++ 17 files changed, 168 insertions(+), 230 deletions(-) delete mode 100644 apps/circuit-compiler/src/app/components/feedback.tsx delete mode 100644 apps/circuit-compiler/src/app/components/feedbackAlert.tsx create mode 100644 apps/remix-ide/src/assets/img/noir-icon.webp diff --git a/apps/circuit-compiler/src/app/components/container.tsx b/apps/circuit-compiler/src/app/components/container.tsx index c54e9f710e9..7d3c092c64b 100644 --- a/apps/circuit-compiler/src/app/components/container.tsx +++ b/apps/circuit-compiler/src/app/components/container.tsx @@ -2,13 +2,13 @@ import { useContext } from 'react' import { CompileBtn, CustomTooltip, RenderIf } from '@remix-ui/helper' import { FormattedMessage } from 'react-intl' import { CircuitAppContext } from '../contexts' -import { CompileOptions } from '@remix-ui/helper' +import { CompileOptions, CompilerReport } from '@remix-ui/helper' import { VersionList } from './versions' import { Toggler } from './toggler' import { Configurations } from './configurations' import { WitnessSection } from './witness' -import { CompilerFeedback } from './feedback' -import { CompilerReport, PrimeValue } from '../types' +import { CompilerFeedback } from '@remix-ui/helper' +import { PrimeValue } from '../types' import { SetupExports } from './setupExports' import { GenerateProof } from './generateProof' import { compileCircuit } from '../actions' @@ -34,15 +34,19 @@ export function Container () { circuitApp.dispatch({ type: 'SET_COMPILER_VERSION', payload: version }) } - const handleOpenErrorLocation = async (location: string, startRange: string) => { - if (location) { - const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) + const handleOpenErrorLocation = async (report: CompilerReport) => { + if (report.labels.length > 0) { + const location = circuitApp.appState.filePathToId[report.labels[0].file_id] + const startRange = report.labels[0].range.start + if (location) { + const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) - await circuitApp.plugin.call('fileManager', 'open', fullPathLocation) - // @ts-ignore - const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange) - // @ts-ignore - await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column) + await circuitApp.plugin.call('fileManager', 'open', fullPathLocation) + // @ts-ignore + const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange) + // @ts-ignore + await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column) + } } } diff --git a/apps/circuit-compiler/src/app/components/feedback.tsx b/apps/circuit-compiler/src/app/components/feedback.tsx deleted file mode 100644 index af42b20d862..00000000000 --- a/apps/circuit-compiler/src/app/components/feedback.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { useState } from 'react' -import { CompilerFeedbackProps, CompilerReport } from '../types' -import { RenderIf } from '@remix-ui/helper' -import { CopyToClipboard } from '@remix-ui/clipboard' -import { FeedbackAlert } from './feedbackAlert' - -export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openErrorLocation, askGPT }: CompilerFeedbackProps) { - const [showException, setShowException] = useState(true) - - const handleCloseException = () => { - setShowException(false) - } - - const handleOpenError = (report: CompilerReport) => { - if (report.labels.length > 0) { - openErrorLocation(filePathToId[report.labels[0].file_id], report.labels[0].range.start) - } - } - - const handleAskGPT = (report: CompilerReport) => { - askGPT(report) - } - - return ( -
- { - (feedback && typeof feedback === 'string') || (Array.isArray(feedback) && feedback.length > 0) ? ( -
- -
- <>{ feedback } -
- -
-
- - - -
-
-
- - <> - { - Array.isArray(feedback) && feedback.map((response, index) => ( -
handleOpenError(response)}> - -
- handleAskGPT(response) } /> -
-
- -
- { handleAskGPT(response) }} /> -
-
-
- ) - ) - } - -
-
- ) : <> - } -
- ) -} diff --git a/apps/circuit-compiler/src/app/components/feedbackAlert.tsx b/apps/circuit-compiler/src/app/components/feedbackAlert.tsx deleted file mode 100644 index c6328dd510a..00000000000 --- a/apps/circuit-compiler/src/app/components/feedbackAlert.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useState } from 'react' -import { FeedbackAlertProps } from '../types' -import { RenderIf } from '@remix-ui/helper' -import {CopyToClipboard} from '@remix-ui/clipboard' - -export function FeedbackAlert ({ message, askGPT }: FeedbackAlertProps) { - const [ showAlert, setShowAlert] = useState(true) - - const handleCloseAlert = () => { - setShowAlert(false) - } - - return ( - - <> - { message } -
- -
-
- - - - { - e.stopPropagation() - askGPT() - }}>Ask RemixAI -
- -
- ) -} diff --git a/apps/circuit-compiler/src/app/services/circomPluginClient.ts b/apps/circuit-compiler/src/app/services/circomPluginClient.ts index ff3170f26e0..daee5c96067 100644 --- a/apps/circuit-compiler/src/app/services/circomPluginClient.ts +++ b/apps/circuit-compiler/src/app/services/circomPluginClient.ts @@ -7,8 +7,8 @@ import * as compilerV218 from 'circom_wasm/v2.1.8' import * as compilerV217 from 'circom_wasm/v2.1.7' import * as compilerV216 from 'circom_wasm/v2.1.6' import * as compilerV215 from 'circom_wasm/v2.1.5' -import { extractNameFromKey, extractParentFromKey } from '@remix-ui/helper' -import { CompilationConfig, CompilerReport, PrimeValue } from '../types' +import { extractNameFromKey, extractParentFromKey, CompilerReport } from '@remix-ui/helper' +import { CompilationConfig, PrimeValue } from '../types' import isElectron from 'is-electron' export class CircomPluginClient extends PluginClient { diff --git a/apps/circuit-compiler/src/app/types/index.ts b/apps/circuit-compiler/src/app/types/index.ts index bd770bbec17..33c2420cb9a 100644 --- a/apps/circuit-compiler/src/app/types/index.ts +++ b/apps/circuit-compiler/src/app/types/index.ts @@ -1,6 +1,7 @@ import { compiler_list } from 'circom_wasm' import { Dispatch } from 'react' import type { CircomPluginClient } from '../services/circomPluginClient' +import { CompilerReport } from '@remix-ui/helper' export type CompilerStatus = "compiling" | "computing" | "idle" | "errored" | "warning" | "exporting" | "proving" @@ -87,34 +88,6 @@ export type CompilationConfig = { export type PrimeValue = "bn128" | "bls12381" | "goldilocks" | "grumpkin" | "pallas" | "vesta" -export type CompilerFeedbackProps = { - feedback: string | CompilerReport[], - filePathToId: Record, - openErrorLocation: (location: string, startRange: string) => void, - hideWarnings: boolean, - askGPT: (report: CompilerReport) => void -} - -export type CompilerReport = { - type: "Error" | "Bug" | "Help" | "Note" | "Warning" | "Unknown", - message: string, - labels: { - style: "Primary" | "Secondary" | "Unknown", - file_id: string, - range: { - start: string, - end: string - }, - message: string - }[], - notes: string[] -} - -export type FeedbackAlertProps = { - message: string, - askGPT: () => void -} - export type ConfigurationsProps = { setPrimeValue: (prime: PrimeValue) => void, primeValue: PrimeValue, diff --git a/apps/noir-compiler/src/app/actions/index.ts b/apps/noir-compiler/src/app/actions/index.ts index 0fbae216441..7b5564abe71 100644 --- a/apps/noir-compiler/src/app/actions/index.ts +++ b/apps/noir-compiler/src/app/actions/index.ts @@ -2,15 +2,9 @@ import { NoirPluginClient } from "../services/noirPluginClient" import { AppState } from "../types" export const compileNoirCircuit = async (plugin: NoirPluginClient, appState: AppState) => { - try { - if (appState.status !== "compiling") { - await plugin.compile(appState.filePath) - } else { - console.log('Existing noir compilation in progress') - } - } catch (e) { - plugin.emit('statusChanged', { key: 'error', title: e.message, type: 'error' }) - plugin.internalEvents.emit('noir_compiling_errored', e) - console.error(e) + if (appState.status !== "compiling") { + await plugin.compile(appState.filePath) + } else { + console.log('Existing noir compilation in progress') } } \ No newline at end of file diff --git a/apps/noir-compiler/src/app/app.tsx b/apps/noir-compiler/src/app/app.tsx index bcb69ddf334..a865d7066b8 100644 --- a/apps/noir-compiler/src/app/app.tsx +++ b/apps/noir-compiler/src/app/app.tsx @@ -37,6 +37,13 @@ function App() { // plugin.parse(path, content) // } }) + // noir compiling events + plugin.internalEvents.on('noir_compiling_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'compiling' })) + plugin.internalEvents.on('noir_compiling_done', () => { + dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' }) + dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: null }) + }) + plugin.internalEvents.on('noir_compiling_errored', noirCompilerErrored) setIsPluginActivated(true) }) }, []) @@ -47,6 +54,17 @@ function App() { } }, [isPluginActivated]) + const noirCompilerErrored = (err: ErrorEvent) => { + dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' }) + try { + const report = JSON.parse(err.message) + + dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: report }) + } catch (e) { + dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: err.message }) + } + } + const setCurrentLocale = async () => { // @ts-ignore const currentLocale = await plugin.call('locale', 'currentLocale') diff --git a/apps/noir-compiler/src/app/components/container.tsx b/apps/noir-compiler/src/app/components/container.tsx index 0fe4ffc8e84..cb26e617404 100644 --- a/apps/noir-compiler/src/app/components/container.tsx +++ b/apps/noir-compiler/src/app/components/container.tsx @@ -1,5 +1,5 @@ import { useContext } from 'react' -import { CompileBtn, CustomTooltip, RenderIf } from '@remix-ui/helper' +import { CompileBtn, CompilerFeedback, CompilerReport, CustomTooltip, RenderIf } from '@remix-ui/helper' import { FormattedMessage } from 'react-intl' import { NoirAppContext } from '../contexts' import { CompileOptions } from '@remix-ui/helper' @@ -21,15 +21,20 @@ export function Container () { } } - const handleOpenErrorLocation = async (location: string, startRange: string) => { - if (location) { - const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) + const handleOpenErrorLocation = async (report: CompilerReport) => { + if (report.labels.length > 0) { + // const location = noirApp.appState.filePathToId[report.labels[0].file_id] + // const startRange = report.labels[0].range.start - await circuitApp.plugin.call('fileManager', 'open', fullPathLocation) - // @ts-ignore - const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange) - // @ts-ignore - await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column) + // if (location) { + // const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) + + // await circuitApp.plugin.call('fileManager', 'open', fullPathLocation) + // // @ts-ignore + // const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange) + // // @ts-ignore + // await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column) + // } } } @@ -43,44 +48,44 @@ export function Container () { const askGPT = async (report: CompilerReport) => { if (report.labels.length > 0) { - const location = circuitApp.appState.filePathToId[report.labels[0].file_id] - const error = report.labels[0].message + // const location = circuitApp.appState.filePathToId[report.labels[0].file_id] + // const error = report.labels[0].message - if (location) { - const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) - const content = await circuitApp.plugin.call('fileManager', 'readFile', fullPathLocation) - const message = ` - circom code: ${content} - error message: ${error} - full circom error: ${JSON.stringify(report, null, 2)} - explain why the error occurred and how to fix it. - ` - await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) - setTimeout(async () => { - await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) - }, 500) - } else { - const message = ` - error message: ${error} - full circom error: ${JSON.stringify(report, null, 2)} - explain why the error occurred and how to fix it. - ` - await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) - setTimeout(async () => { - await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) - }, 500) - } + // if (location) { + // const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) + // const content = await circuitApp.plugin.call('fileManager', 'readFile', fullPathLocation) + // const message = ` + // circom code: ${content} + // error message: ${error} + // full circom error: ${JSON.stringify(report, null, 2)} + // explain why the error occurred and how to fix it. + // ` + // await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) + // setTimeout(async () => { + // await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) + // }, 500) + // } else { + // const message = ` + // error message: ${error} + // full circom error: ${JSON.stringify(report, null, 2)} + // explain why the error occurred and how to fix it. + // ` + // await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) + // setTimeout(async () => { + // await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) + // }, 500) + // } } else { - const error = report.message - const message = ` - error message: ${error} - full circom error: ${JSON.stringify(report, null, 2)} - explain why the error occurred and how to fix it. - ` - await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) - setTimeout(async () => { - await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) - }, 500) + // const error = report.message + // const message = ` + // error message: ${error} + // full circom error: ${JSON.stringify(report, null, 2)} + // explain why the error occurred and how to fix it. + // ` + // await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) + // setTimeout(async () => { + // await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) + // }, 500) } } diff --git a/apps/noir-compiler/src/app/reducers/state.ts b/apps/noir-compiler/src/app/reducers/state.ts index 8230ade8200..7fe068a42ab 100644 --- a/apps/noir-compiler/src/app/reducers/state.ts +++ b/apps/noir-compiler/src/app/reducers/state.ts @@ -5,7 +5,8 @@ export const appInitialState: AppState = { filePathToId: {}, autoCompile: false, hideWarnings: false, - status: 'idle' + status: 'idle', + compilerFeedback: '' } export const appReducer = (state = appInitialState, action: Actions): AppState => { @@ -29,6 +30,18 @@ export const appReducer = (state = appInitialState, action: Actions): AppState = filePath: action.payload } + case 'SET_COMPILER_FEEDBACK': + return { + ...state, + compilerFeedback: action.payload + } + + case 'SET_COMPILER_STATUS': + return { + ...state, + status: action.payload + } + default: throw new Error() } diff --git a/apps/noir-compiler/src/app/services/noirPluginClient.ts b/apps/noir-compiler/src/app/services/noirPluginClient.ts index 26c660455f7..11c73e915e4 100644 --- a/apps/noir-compiler/src/app/services/noirPluginClient.ts +++ b/apps/noir-compiler/src/app/services/noirPluginClient.ts @@ -38,14 +38,26 @@ export class NoirPluginClient extends PluginClient { } async compile(path: string): Promise { - // @ts-ignore - const fileContent = await this.call('fileManager', 'readFile', path) - const fileBytes = new TextEncoder().encode(fileContent) + try { + this.internalEvents.emit('noir_compiling_start') + this.emit('statusChanged', { key: 'loading', title: 'Compiling Noir Circuit...', type: 'info' }) + // @ts-ignore + this.call('terminal', 'log', { type: 'log', value: 'Compiling ' + path }) + // @ts-ignore + const fileContent = await this.call('fileManager', 'readFile', path) + const fileBytes = new TextEncoder().encode(fileContent) - this.fm.writeFile(`src/${path}`, new Blob([fileBytes]).stream()) - const program = await compile_program(this.fm) + this.fm.writeFile(`src/${path}`, new Blob([fileBytes]).stream()) + const program = await compile_program(this.fm) - console.log('program: ', program) + console.log('program: ', program) + this.internalEvents.emit('noir_compiling_done') + this.emit('statusChanged', { key: 'succeed', title: 'Noir circuit compiled successfully', type: 'success' }) + } catch (e) { + this.emit('statusChanged', { key: 'error', title: e.message, type: 'error' }) + this.internalEvents.emit('noir_compiling_errored', e) + console.error(e) + } } async parse(path: string): Promise { diff --git a/apps/noir-compiler/src/app/types/index.ts b/apps/noir-compiler/src/app/types/index.ts index f927f9c31b0..42753b3f050 100644 --- a/apps/noir-compiler/src/app/types/index.ts +++ b/apps/noir-compiler/src/app/types/index.ts @@ -14,13 +14,16 @@ export interface AppState { filePathToId: Record, autoCompile: boolean, hideWarnings: boolean, - status: CompilerStatus + status: CompilerStatus, + compilerFeedback: string } export interface ActionPayloadTypes { SET_AUTO_COMPILE: boolean, SET_HIDE_WARNINGS: boolean, - SET_FILE_PATH: string + SET_FILE_PATH: string, + SET_COMPILER_FEEDBACK: string, + SET_COMPILER_STATUS: CompilerStatus } export interface Action { type: T diff --git a/apps/noir-compiler/src/profile.json b/apps/noir-compiler/src/profile.json index 5384f2a1919..dcf409d212a 100644 --- a/apps/noir-compiler/src/profile.json +++ b/apps/noir-compiler/src/profile.json @@ -8,7 +8,7 @@ "canActivate": [], "url": "", "description": "Enables support for noir circuit compilation", - "icon": "assets/img/noir-icon-bw-800b.webp", + "icon": "assets/img/noir-icon.webp", "location": "sidePanel", "documentation": "", "repo": "https://github.com/ethereum/remix-project/tree/master/apps/noir-compiler", diff --git a/apps/remix-ide/src/assets/img/noir-icon.webp b/apps/remix-ide/src/assets/img/noir-icon.webp new file mode 100644 index 0000000000000000000000000000000000000000..1fab6574b8b4df383e7d54d74f5861ca771c8c36 GIT binary patch literal 8258 zcma)BWmw&8wmrDJ7q{YaaEAiL-QBHt@#0dvSaElEcXxM(;_fYO=hDu6cfOgqKW_dc zd7k9W+Iz3HcCw=+DJI540syFg6jo4E;38psJ65;{q=V6Bg4cr!#7N{wQ|9Gn=cgo5 zSE0k1+dexo9VO2{XC^og=K_G%?xhZMJuN{M%{%qWgoK^@ML>S1bLss`7ta)sJu!o(8fTobEWW zHmVDPF=CSlHTV468Z_0flJ8R+{66If`B!1BH_Gye?4yM>kfwmjH+=N6DE#A zS|LFCZ|mQFrNXNb;>k?^c}H;$E}Sf&t;#>Dh)jQx_y=gg-~&a9?MSE|)_&O@oQ-0# zl85vR)0PoK|G&c6bQJlKwoFUyd*RfCc*k9DkgGOM`X%gDbBkLJ@Q-DFV@)OA{r;(y zmeLVztfBQIQ^1N?45vwGbVJ1l^~k_n(*8FDZwXqx65S>I5%}!dtN^}vh?67M#$T7! z-;9wRa$M;5F{Zh`<4^K#pB1@bT(f-$&s6~Rk5Gp(mG&!fV&y5qERQ!s&wf4#XqI|^ z(%rZnI>g(KaDU;D1ywmK8u41jWH(C2p8rc8R5d?n+nbzut`+jx+#`&N zz#uCpa)}$JCVr~+*?o=!@`VUW6HvN#pjU=!Z}2$;rXE7{p24=V_(TyZJNBN zyaYZ|9_xIuBf8_{+QES}$EkH$!B0AzF+}&=>mP3^zFlHrBKX8sRoHOjh)oHLwQ6#p z{=q}KH!0HLDGr)E*~Xu3!Mgnbf~e?))9;P-C~}K@U7V7h4U;y<`*hp)?ZME)_c3MV#33A3X&qK3Il&u{7;H8oJ4~6VSN?K+Y@HDCiZ5LjcZuqz)&^o z9IXI46?=h+12Ksh4ihwk*F6x54K>hLsO4RAc|@gbBxjQ~uU!~3e3<}cB>hs$sb#Gx z`W&8CuHQ}1!w9+gxMl?T0kd-AxkNzT9I`~olkcHTb|oXx)HzQN!!v@Fz7xA`RpAIk zx_1#N*Z6m^jof^@m$}7Doa~%JsLeafm;#~ARaZZ12tRWSv-?^#Ow#vxL6cd`Hp0>* z6LW8x{zEwGN)ZlY|Bn=V4)A>gIhq?D5;O0w0Gji60hGY1J#l_!b~hv@u|mXR=v2&t54N{z3_ zR`*j^Z$kfVv^mPl)Yo7EDLtsrswZRO@{d+)>Nxp~z=(}}IRTE4Cg&Yf{nr$Q?TLps zZU#PE#waDX*O-;FXeayBrIP1H1F1b}5JTuRRCLifU;k$Me`<>~pEL~fi{*u(6ft8&Pi05(FW+wO zmbYSV8Z*0kb6(LuMn(E>9cRwGK`PppVEt)6@ONsT^r9O67sPKH?tZNhZS0Zv+-~o( z)6|uf_$%yxcC9*o6yJ#NFC2vaL?tG343NkdBpE3G(buAiVDLB@-o(@K-~H~b9o+f? zUSDsr0B@Tf$$nAu)Ydwp#EE=MOIF|UFVchgC4mBNmmoL{<>S}8RonD>SNA(cDaq#9 z$CELe!gkqX`128FC2;iuH==@?EXC`M<9L=qyKh2KGpD$m&E+zMxgW;ZtyS32>mq&H zA8OHA;Uj$k05nyIXCe_Y!>;xEr(>RV;lL)5=yuyxD2vIjnfNkGhI077{?|p#J3-QaINJY(Hah7JA6u{OqrG{R|lwv@ZI=; zh0SPrEm3UrD`B0&n)&AYpEAr^zrrE`0B}8|Cpu~I^%C@1S#EmM+htN)4ET1t?+y%i z%ya8x$F#O{c|(fl4GiHsWEP$VVUo*&WZoI#!`2*IzPO343A%>fsYi>%(lJ61qzeHc zemW>e220#QQiJdyLYE>(eY3WgdJAlCuX$w)PYP+zvixlqBHRO!FlOVyJLTLXti?VN z9GLMkV2R1uzV8rHn1QLX^Ch4LKobX>%UgV1l1XL25w#34)T;qiPcuqY(*b7XTK#wLI&|Tv?As zr^c)~H-CM_)qFkU`N{nYnF+(g8jU5SRHKzxha>YQ!mlFH@+-lU;gm+xvop0dfh
  • 7MLI{oxvQlK~Xfrccd$# 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 literal 0 HcmV?d00001 diff --git a/libs/remix-ui/helper/src/index.ts b/libs/remix-ui/helper/src/index.ts index 94dab78f43e..5156d0a3da2 100644 --- a/libs/remix-ui/helper/src/index.ts +++ b/libs/remix-ui/helper/src/index.ts @@ -3,4 +3,6 @@ export * from './lib/bleach' export * from './lib/helper-components' export * from './lib/components/PluginViewWrapper' export * from './lib/components/custom-dropdown' -export * from './lib/components/custom-tooltip' \ No newline at end of file +export * from './lib/components/custom-tooltip' +export * from './lib/components/feedback' +export type { CompilerReport } from './types/compilerTypes' \ No newline at end of file diff --git a/libs/remix-ui/helper/src/lib/components/feedback.tsx b/libs/remix-ui/helper/src/lib/components/feedback.tsx index af42b20d862..2c8ebabdcff 100644 --- a/libs/remix-ui/helper/src/lib/components/feedback.tsx +++ b/libs/remix-ui/helper/src/lib/components/feedback.tsx @@ -1,5 +1,5 @@ -import { useState } from 'react' -import { CompilerFeedbackProps, CompilerReport } from '../types' +import React, { useState } from 'react' +import { CompilerFeedbackProps, CompilerReport } from '../../types/compilerTypes' import { RenderIf } from '@remix-ui/helper' import { CopyToClipboard } from '@remix-ui/clipboard' import { FeedbackAlert } from './feedbackAlert' @@ -11,16 +11,6 @@ export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openEr setShowException(false) } - const handleOpenError = (report: CompilerReport) => { - if (report.labels.length > 0) { - openErrorLocation(filePathToId[report.labels[0].file_id], report.labels[0].range.start) - } - } - - const handleAskGPT = (report: CompilerReport) => { - askGPT(report) - } - return (
    { @@ -43,19 +33,19 @@ export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openEr <> { Array.isArray(feedback) && feedback.map((response, index) => ( -
    handleOpenError(response)}> +
    openErrorLocation(response)}>
    handleAskGPT(response) } /> + askGPT={ () => askGPT(response) } />
    { handleAskGPT(response) }} /> + askGPT={() => { askGPT(response) }} />
    diff --git a/libs/remix-ui/helper/src/lib/components/feedbackAlert.tsx b/libs/remix-ui/helper/src/lib/components/feedbackAlert.tsx index c6328dd510a..cf7137ab20e 100644 --- a/libs/remix-ui/helper/src/lib/components/feedbackAlert.tsx +++ b/libs/remix-ui/helper/src/lib/components/feedbackAlert.tsx @@ -1,10 +1,10 @@ -import { useState } from 'react' -import { FeedbackAlertProps } from '../types' +import React, { useState } from 'react' +import { FeedbackAlertProps } from '../../types/compilerTypes' import { RenderIf } from '@remix-ui/helper' -import {CopyToClipboard} from '@remix-ui/clipboard' +import { CopyToClipboard } from '@remix-ui/clipboard' export function FeedbackAlert ({ message, askGPT }: FeedbackAlertProps) { - const [ showAlert, setShowAlert] = useState(true) + const [showAlert, setShowAlert] = useState(true) const handleCloseAlert = () => { setShowAlert(false) diff --git a/libs/remix-ui/helper/src/types/compilerTypes.ts b/libs/remix-ui/helper/src/types/compilerTypes.ts index b7741b5ac72..17b96cd48e5 100644 --- a/libs/remix-ui/helper/src/types/compilerTypes.ts +++ b/libs/remix-ui/helper/src/types/compilerTypes.ts @@ -3,4 +3,32 @@ export type CompileOptionsProps = { setCircuitHideWarnings: (value: boolean) => void, autoCompile: boolean, hideWarnings: boolean + } + +export type FeedbackAlertProps = { + message: string, + askGPT: () => void + } + +export type CompilerFeedbackProps = { + feedback: string | CompilerReport[], + filePathToId: Record, + openErrorLocation: (report: CompilerReport) => void, + hideWarnings: boolean, + askGPT: (report: CompilerReport) => void + } + +export type CompilerReport = { + type: "Error" | "Bug" | "Help" | "Note" | "Warning" | "Unknown", + message: string, + labels: { + style: "Primary" | "Secondary" | "Unknown", + file_id: string, + range: { + start: string, + end: string + }, + message: string + }[], + notes: string[] } \ No newline at end of file From 920f2230c5ece62fcac5cf55b274c4768e7ca64a Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 22 Jan 2025 11:43:36 +0000 Subject: [PATCH 09/15] Fixes and extracts exports --- .../src/app/actions/constants.ts | 8 ++++ apps/noir-compiler/src/app/app.tsx | 19 ++++++-- .../src/app/services/noirPluginClient.ts | 47 ++++++++++++------- apps/noir-compiler/src/css/app.css | 26 +++++----- apps/noir-compiler/webpack.config.js | 2 - 5 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 apps/noir-compiler/src/app/actions/constants.ts diff --git a/apps/noir-compiler/src/app/actions/constants.ts b/apps/noir-compiler/src/app/actions/constants.ts new file mode 100644 index 00000000000..de94fbe570e --- /dev/null +++ b/apps/noir-compiler/src/app/actions/constants.ts @@ -0,0 +1,8 @@ +export const DEFAULT_TOML_CONFIG = `[package] +name = "test" +authors = [""] +compiler_version = ">=0.18.0" +type = "bin" + +[dependencies] +` \ No newline at end of file diff --git a/apps/noir-compiler/src/app/app.tsx b/apps/noir-compiler/src/app/app.tsx index a865d7066b8..4c5d396f85f 100644 --- a/apps/noir-compiler/src/app/app.tsx +++ b/apps/noir-compiler/src/app/app.tsx @@ -5,6 +5,7 @@ import { IntlProvider } from 'react-intl' import { Container } from "./components/container" import { NoirAppContext } from "./contexts" import { appInitialState, appReducer } from "./reducers/state" +import { compileNoirCircuit } from "./actions" const plugin = new NoirPluginClient() @@ -31,11 +32,10 @@ function App() { }) // @ts-ignore plugin.on('editor', 'contentChanged', async (path: string, content: string) => { - setIsContentChanged(true) - // check if autoCompile is enabled - // if (path.endsWith('.nr')) { - // plugin.parse(path, content) - // } + if (path.endsWith('.nr')) { + setIsContentChanged(true) + plugin.parse(path, content) + } }) // noir compiling events plugin.internalEvents.on('noir_compiling_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'compiling' })) @@ -54,6 +54,15 @@ function App() { } }, [isPluginActivated]) + useEffect(() => { + if (isContentChanged) { + (async () => { + if (appState.autoCompile) await compileNoirCircuit(plugin, appState) + })() + setIsContentChanged(false) + } + }, [appState.autoCompile, isContentChanged]) + const noirCompilerErrored = (err: ErrorEvent) => { dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' }) try { diff --git a/apps/noir-compiler/src/app/services/noirPluginClient.ts b/apps/noir-compiler/src/app/services/noirPluginClient.ts index 11c73e915e4..a55a8b02a6f 100644 --- a/apps/noir-compiler/src/app/services/noirPluginClient.ts +++ b/apps/noir-compiler/src/app/services/noirPluginClient.ts @@ -4,15 +4,7 @@ import EventManager from 'events' // @ts-ignore import { compile_program, createFileManager } from '@noir-lang/noir_wasm/default' import type { FileManager } from '@noir-lang/noir_wasm/dist/node/main' - -const DEFAULT_TOML_CONFIG = `[package] -name = "test" -authors = [""] -compiler_version = ">=0.18.0" -type = "bin" - -[dependencies] -` +import { DEFAULT_TOML_CONFIG } from '../actions/constants' export class NoirPluginClient extends PluginClient { public internalEvents: EventManager public fm: FileManager @@ -23,9 +15,6 @@ export class NoirPluginClient extends PluginClient { createClient(this) this.internalEvents = new EventManager() this.fm = createFileManager('/') - const fileBytes = new TextEncoder().encode(DEFAULT_TOML_CONFIG) - - this.fm.writeFile('Nargo.toml', new Blob([fileBytes]).stream()) this.onload() } @@ -35,6 +24,24 @@ export class NoirPluginClient extends PluginClient { onActivation(): void { this.internalEvents.emit('noir_activated') + this.setup() + } + + async setup(): Promise { + // @ts-ignore + const nargoTomlExists = await this.call('fileManager', 'exists', 'Nargo.toml') + + if (!nargoTomlExists) { + await this.call('fileManager', 'writeFile', 'Nargo.toml', DEFAULT_TOML_CONFIG) + const fileBytes = new TextEncoder().encode(DEFAULT_TOML_CONFIG) + + this.fm.writeFile('Nargo.toml', new Blob([fileBytes]).stream()) + } else { + const nargoToml = await this.call('fileManager', 'readFile', 'Nargo.toml') + const fileBytes = new TextEncoder().encode(nargoToml) + + this.fm.writeFile('Nargo.toml', new Blob([fileBytes]).stream()) + } } async compile(path: string): Promise { @@ -43,11 +50,6 @@ export class NoirPluginClient extends PluginClient { this.emit('statusChanged', { key: 'loading', title: 'Compiling Noir Circuit...', type: 'info' }) // @ts-ignore this.call('terminal', 'log', { type: 'log', value: 'Compiling ' + path }) - // @ts-ignore - const fileContent = await this.call('fileManager', 'readFile', path) - const fileBytes = new TextEncoder().encode(fileContent) - - this.fm.writeFile(`src/${path}`, new Blob([fileBytes]).stream()) const program = await compile_program(this.fm) console.log('program: ', program) @@ -60,6 +62,15 @@ export class NoirPluginClient extends PluginClient { } } - async parse(path: string): Promise { + async parse(path: string, content?: string): Promise { + if (!content) { + // @ts-ignore + content = await this.call('fileManager', 'readFile', path) + } + const depImports = Array.from(content.matchAll(/mod\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*(=\s*["'](.*?)["'])?\s*;/g), match => match[3] || match[1]); + console.log('depImports: ', depImports) + const fileBytes = new TextEncoder().encode(content) + + this.fm.writeFile(`src/${path}`, new Blob([fileBytes]).stream()) } } diff --git a/apps/noir-compiler/src/css/app.css b/apps/noir-compiler/src/css/app.css index b5676189ff3..5d68203a992 100644 --- a/apps/noir-compiler/src/css/app.css +++ b/apps/noir-compiler/src/css/app.css @@ -36,12 +36,12 @@ body { line-height: 12px; text-transform: uppercase; } -.noir_errors_box { +.circuit_errors_box { word-break: break-word; } -.noir_feedback.success, -.noir_feedback.error, -.noir_feedback.warning { +.circuit_feedback.success, +.circuit_feedback.error, +.circuit_feedback.warning { white-space: pre-line; word-wrap: break-word; cursor: pointer; @@ -52,9 +52,9 @@ body { padding: 8px 15px; } -.noir_feedback.success pre, -.noir_feedback.error pre, -.noir_feedback.warning pre { +.circuit_feedback.success pre, +.circuit_feedback.error pre, +.circuit_feedback.warning pre { white-space: pre-line; overflow-y: hidden; background-color: transparent; @@ -65,9 +65,9 @@ body { border-radius: 0; } -.noir_feedback.success .close, -.noir_feedback.error .close, -.noir_feedback.warning .close { +.circuit_feedback.success .close, +.circuit_feedback.error .close, +.circuit_feedback.warning .close { visibility: hidden; white-space: pre-line; font-weight: bold; @@ -78,9 +78,9 @@ body { padding: 0.5em; } -.noir_feedback.success a, -.noir_feedback.error a, -.noir_feedback.warning a { +.circuit_feedback.success a, +.circuit_feedback.error a, +.circuit_feedback.warning a { bottom: 0; right: 0; } diff --git a/apps/noir-compiler/webpack.config.js b/apps/noir-compiler/webpack.config.js index 0298a8605f7..48f51d27a88 100644 --- a/apps/noir-compiler/webpack.config.js +++ b/apps/noir-compiler/webpack.config.js @@ -13,8 +13,6 @@ module.exports = composePlugins(withNx(), (config) => { pkgNoirWasm = pkgNoirWasm.replace(/"node"/, '"./node"').replace(/"import"/, '"./import"').replace(/"require"/, '"./require"').replace(/"types"/g, match => ++typeCount === 2 ? '"./types"' : match).replace(/"default"/, '"./default"') fs.writeFileSync(path.resolve(__dirname, '../../node_modules/@noir-lang/noir_wasm/package.json'), pkgNoirWasm) - - console.log('pkgNoirWasm: ', pkgNoirWasm) // add fallback for node modules config.resolve.fallback = { From 62e9a03930ab34304f985103897e17c36c82975d Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 23 Jan 2025 20:20:53 +0000 Subject: [PATCH 10/15] Resolve noir dependencies --- .../src/app/services/noirPluginClient.ts | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/apps/noir-compiler/src/app/services/noirPluginClient.ts b/apps/noir-compiler/src/app/services/noirPluginClient.ts index a55a8b02a6f..1d562efba4e 100644 --- a/apps/noir-compiler/src/app/services/noirPluginClient.ts +++ b/apps/noir-compiler/src/app/services/noirPluginClient.ts @@ -4,6 +4,7 @@ import EventManager from 'events' // @ts-ignore import { compile_program, createFileManager } from '@noir-lang/noir_wasm/default' import type { FileManager } from '@noir-lang/noir_wasm/dist/node/main' +import pathModule from 'path' import { DEFAULT_TOML_CONFIG } from '../actions/constants' export class NoirPluginClient extends PluginClient { public internalEvents: EventManager @@ -63,14 +64,54 @@ export class NoirPluginClient extends PluginClient { } async parse(path: string, content?: string): Promise { - if (!content) { - // @ts-ignore - content = await this.call('fileManager', 'readFile', path) - } - const depImports = Array.from(content.matchAll(/mod\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*(=\s*["'](.*?)["'])?\s*;/g), match => match[3] || match[1]); - console.log('depImports: ', depImports) + if (!content) content = await this.call('fileManager', 'readFile', path) + await this.resolveDependencies(path, content) const fileBytes = new TextEncoder().encode(content) - this.fm.writeFile(`src/${path}`, new Blob([fileBytes]).stream()) + this.fm.writeFile(`${path}`, new Blob([fileBytes]).stream()) + } + + async resolveDependencies (filePath: string, fileContent: string, blackPath: string[] = []): Promise { + const imports = Array.from(fileContent.matchAll(/mod\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*(=\s*["'](.*?)["'])?\s*;/g), match => match[3] || match[1]); + console.log('depImports: ', imports) + + for (let dep of imports) { + if (!dep.endsWith('.nr')) dep += '.nr' + if (blackPath.includes(dep)) return + let dependencyContent = '' + let path = dep.replace(/(\.\.\/)+/g, '') + + // @ts-ignore + const pathExists = await this.call('fileManager', 'exists', path) + + if (pathExists) { + dependencyContent = await this.call('fileManager', 'readFile', path) + } else { + let relativePath = pathModule.resolve(filePath.slice(0, filePath.lastIndexOf('/')), dep) + + if (relativePath.indexOf('/') === 0) relativePath = relativePath.slice(1) + // @ts-ignore + const relativePathExists = await this.call('fileManager', 'exists', relativePath) + + if (relativePathExists) { + path = relativePath + dependencyContent = await this.call('fileManager', 'readFile', relativePath) + } else { + console.error(`Dependency ${dep} not found in Remix file system`) + } + } + + blackPath.push(dep) + // extract all includes from the dependency content + const depImports = Array.from(fileContent.matchAll(/mod\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*(=\s*["'](.*?)["'])?\s*;/g), match => match[3] || match[1]) + + if (depImports.length > 0 && dependencyContent.length > 0) { + await this.resolveDependencies(path, dependencyContent, blackPath) + const fileBytes = new TextEncoder().encode(dependencyContent) + + console.log('writing file: ', `src/${dep}`) + this.fm.writeFile(`src/${dep}`, new Blob([fileBytes]).stream()) + } + } } } From 97a93683c82de5a4a842072a7cd7ba17014fa8ff Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Tue, 28 Jan 2025 22:31:19 +0000 Subject: [PATCH 11/15] Solution for circular dependency and a working flat structure --- .../src/app/services/noirPluginClient.ts | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/apps/noir-compiler/src/app/services/noirPluginClient.ts b/apps/noir-compiler/src/app/services/noirPluginClient.ts index 1d562efba4e..58e72b7572c 100644 --- a/apps/noir-compiler/src/app/services/noirPluginClient.ts +++ b/apps/noir-compiler/src/app/services/noirPluginClient.ts @@ -71,13 +71,12 @@ export class NoirPluginClient extends PluginClient { this.fm.writeFile(`${path}`, new Blob([fileBytes]).stream()) } - async resolveDependencies (filePath: string, fileContent: string, blackPath: string[] = []): Promise { + async resolveDependencies (filePath: string, fileContent: string, parentPath: string = '', visited: Record = {}): Promise { const imports = Array.from(fileContent.matchAll(/mod\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*(=\s*["'](.*?)["'])?\s*;/g), match => match[3] || match[1]); - console.log('depImports: ', imports) for (let dep of imports) { if (!dep.endsWith('.nr')) dep += '.nr' - if (blackPath.includes(dep)) return + if (visited[filePath] && visited[filePath].includes(parentPath)) return console.log('circular dependency detected') let dependencyContent = '' let path = dep.replace(/(\.\.\/)+/g, '') @@ -96,21 +95,20 @@ export class NoirPluginClient extends PluginClient { if (relativePathExists) { path = relativePath dependencyContent = await this.call('fileManager', 'readFile', relativePath) - } else { - console.error(`Dependency ${dep} not found in Remix file system`) - } - } + visited[filePath] = visited[filePath] ? [...visited[filePath], path] : [path] + // extract all mod imports from the dependency content + const depImports = Array.from(fileContent.matchAll(/mod\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*(=\s*["'](.*?)["'])?\s*;/g), match => match[3] || match[1]) - blackPath.push(dep) - // extract all includes from the dependency content - const depImports = Array.from(fileContent.matchAll(/mod\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*(=\s*["'](.*?)["'])?\s*;/g), match => match[3] || match[1]) + if (depImports.length > 0 && dependencyContent.length > 0) { + const fileBytes = new TextEncoder().encode(dependencyContent) + const writePath = parentPath ? `${filePath.replace('.nr', '')}/${dep}` : path - if (depImports.length > 0 && dependencyContent.length > 0) { - await this.resolveDependencies(path, dependencyContent, blackPath) - const fileBytes = new TextEncoder().encode(dependencyContent) - - console.log('writing file: ', `src/${dep}`) - this.fm.writeFile(`src/${dep}`, new Blob([fileBytes]).stream()) + this.fm.writeFile(writePath, new Blob([fileBytes]).stream()) + await this.resolveDependencies(path, dependencyContent, filePath, visited) + } + } else { + throw new Error(`Dependency ${dep} not found in Remix file system`) + } } } } From 053e169f173a91239fac6f0bc0e785e8f7f49fe2 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sat, 1 Feb 2025 14:36:26 +0000 Subject: [PATCH 12/15] Parse Noir files --- .../src/app/services/noirParser.ts | 104 ++++++++++++++++++ .../src/app/services/noirPluginClient.ts | 6 + package.json | 2 + yarn.lock | 10 ++ 4 files changed, 122 insertions(+) create mode 100644 apps/noir-compiler/src/app/services/noirParser.ts diff --git a/apps/noir-compiler/src/app/services/noirParser.ts b/apps/noir-compiler/src/app/services/noirParser.ts new file mode 100644 index 00000000000..323f86124ab --- /dev/null +++ b/apps/noir-compiler/src/app/services/noirParser.ts @@ -0,0 +1,104 @@ +// Noir Circuit Program Parser +// Detects syntax errors and warnings in .nr files + +class NoirParser { + errors: any; + currentLine: any; + currentColumn: number; + constructor() { + this.errors = []; + this.currentLine = 1; + this.currentColumn = 1; + } + + parseNoirCode(code) { + this.errors = []; + this.currentLine = 1; + this.currentColumn = 1; + + const lines = code.split('\n'); + let inFunctionBody = false; + + for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) { + const line = lines[lineIdx].trim(); + + // Skip empty lines or comments + if (line === '' || line.startsWith('//')) { + this.currentLine++; + continue; + } + + // Track function body + if (line.includes('{')) { + inFunctionBody = true; + } else if (line.includes('}')) { + inFunctionBody = false; + } + + // Check for multiple semicolons + const semicolonMatches = [...line.matchAll(/;/g)]; + if (semicolonMatches.length > 1) { + this.addError( + 'Multiple semicolons in a single statement', + lineIdx + 1, + semicolonMatches[1].index + 1, + [lineIdx + 1, line.length] + ); + } + + // Check module imports + if (line.startsWith('mod ')) { + const modulePattern = /^mod\s+[a-zA-Z_][a-zA-Z0-9_]*\s*;?$/; + if (!modulePattern.test(line)) { + this.addError( + 'Invalid module import syntax', + lineIdx + 1, + 1, + [lineIdx + 1, line.length] + ); + } + } + + // Check statement semicolons + if (inFunctionBody && + !line.endsWith('{') && + !line.endsWith('}') && + !line.startsWith('fn ') && + !line.startsWith('//') && + !line.endsWith(';') && + line.length > 0) { + this.addError( + 'Missing semicolon at statement end', + lineIdx + 1, + line.length, + [lineIdx + 1, line.length] + ); + } + + // Check for trailing whitespace + if (lines[lineIdx].endsWith(' ')) { + this.addError( + 'Trailing whitespace', + lineIdx + 1, + lines[lineIdx].length, + [lineIdx + 1, lines[lineIdx].length] + ); + } + + this.currentLine++; + } + + return this.errors; + } + + addError(message, line, column, range) { + this.errors.push({ + message, + line, + column, + range: range || [line, column] + }); + } +} + +export default NoirParser; \ No newline at end of file diff --git a/apps/noir-compiler/src/app/services/noirPluginClient.ts b/apps/noir-compiler/src/app/services/noirPluginClient.ts index 58e72b7572c..e27154d23e1 100644 --- a/apps/noir-compiler/src/app/services/noirPluginClient.ts +++ b/apps/noir-compiler/src/app/services/noirPluginClient.ts @@ -6,9 +6,11 @@ import { compile_program, createFileManager } from '@noir-lang/noir_wasm/default import type { FileManager } from '@noir-lang/noir_wasm/dist/node/main' import pathModule from 'path' import { DEFAULT_TOML_CONFIG } from '../actions/constants' +import NoirParser from './noirParser' export class NoirPluginClient extends PluginClient { public internalEvents: EventManager public fm: FileManager + public parser: NoirParser constructor() { super() @@ -16,6 +18,7 @@ export class NoirPluginClient extends PluginClient { createClient(this) this.internalEvents = new EventManager() this.fm = createFileManager('/') + this.parser = new NoirParser() this.onload() } @@ -66,6 +69,9 @@ export class NoirPluginClient extends PluginClient { async parse(path: string, content?: string): Promise { if (!content) content = await this.call('fileManager', 'readFile', path) await this.resolveDependencies(path, content) + const result = this.parser.parseNoirCode(content) + + console.log('result: ', result) const fileBytes = new TextEncoder().encode(content) this.fm.writeFile(`${path}`, new Blob([fileBytes]).stream()) diff --git a/package.json b/package.json index 9b72ab53a67..36f4c15fadd 100644 --- a/package.json +++ b/package.json @@ -142,6 +142,7 @@ "core-js": "^3.6.5", "cors": "^2.8.5", "create-hash": "^1.2.0", + "dedent": "^1.5.3", "deep-equal": "^1.0.1", "document-register-element": "1.13.1", "electron-squirrel-startup": "^1.0.0", @@ -175,6 +176,7 @@ "merge": "^2.1.1", "npm-install-version": "^6.0.2", "octokit": "^3.1.2", + "ohm-js": "^17.1.0", "path-browserify": "^1.0.1", "prettier": "^2.8.4", "prettier-plugin-solidity": "^1.0.0-beta.24", diff --git a/yarn.lock b/yarn.lock index 4a0223ec1a2..9f9010fe812 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13536,6 +13536,11 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= +dedent@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== + deep-eql@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.0.1.tgz#2b65bc89491d193780c452edee2144a91bb0a445" @@ -24065,6 +24070,11 @@ ofetch@^1.3.3: node-fetch-native "^1.4.0" ufo "^1.3.0" +ohm-js@^17.1.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/ohm-js/-/ohm-js-17.1.0.tgz#50d8e08f69d7909931998d75202d35e2a90c8885" + integrity sha512-xc3B5dgAjTBQGHaH7B58M2Pmv6WvzrJ/3/7LeUzXNg0/sY3jQPdSd/S2SstppaleO77rifR1tyhdfFGNIwxf2Q== + on-exit-leak-free@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" From aaa67ebc1c7418fea8e2a651b066c73d15beccec Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 3 Feb 2025 15:51:43 +0000 Subject: [PATCH 13/15] Improve noir circuit parsing --- .../src/app/services/noirParser.ts | 273 +++++++++++++----- .../src/app/services/noirPluginClient.ts | 38 ++- 2 files changed, 237 insertions(+), 74 deletions(-) diff --git a/apps/noir-compiler/src/app/services/noirParser.ts b/apps/noir-compiler/src/app/services/noirParser.ts index 323f86124ab..daf81906638 100644 --- a/apps/noir-compiler/src/app/services/noirParser.ts +++ b/apps/noir-compiler/src/app/services/noirParser.ts @@ -1,103 +1,240 @@ -// Noir Circuit Program Parser -// Detects syntax errors and warnings in .nr files - class NoirParser { - errors: any; - currentLine: any; + errors: { + message: string; + type: string; + position: { + start: { line: number; column: number }; + end: { line: number; column: number }; + }; + }[]; + currentLine: number; currentColumn: number; + noirTypes: string[]; + constructor() { this.errors = []; this.currentLine = 1; this.currentColumn = 1; + this.noirTypes = ['Field', 'bool', 'u8', 'u16', 'u32', 'u64', 'i8', 'i16', 'i32', 'i64']; } parseNoirCode(code) { this.errors = []; - this.currentLine = 1; - this.currentColumn = 1; - const lines = code.split('\n'); - let inFunctionBody = false; + const functions = this.analyzeFunctions(lines); for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) { - const line = lines[lineIdx].trim(); + const line = lines[lineIdx]; + const trimmedLine = line.trim(); - // Skip empty lines or comments - if (line === '' || line.startsWith('//')) { - this.currentLine++; + if (trimmedLine === '' || trimmedLine.startsWith('//')) continue; + if (trimmedLine.startsWith('mod ')) { + this.checkModuleImport(trimmedLine, lineIdx, line); continue; } + const currentFunction = functions.find(f => lineIdx >= f.startLine && lineIdx <= f.endLine); - // Track function body - if (line.includes('{')) { - inFunctionBody = true; - } else if (line.includes('}')) { - inFunctionBody = false; + if (currentFunction) { + if (lineIdx === currentFunction.startLine) this.checkFunctionReturnType(trimmedLine, lineIdx, line); + else this.checkFunctionBodyStatement(trimmedLine, lineIdx, line, currentFunction, lines); } - // Check for multiple semicolons - const semicolonMatches = [...line.matchAll(/;/g)]; - if (semicolonMatches.length > 1) { - this.addError( - 'Multiple semicolons in a single statement', - lineIdx + 1, - semicolonMatches[1].index + 1, - [lineIdx + 1, line.length] - ); + if (/[ \t]$/.test(line)) { + this.addError({ + message: 'Trailing whitespace detected', + type: 'style', + position: this.calculatePosition(lineIdx, line.length - 1, line.length) + }); } + } + + return this.errors; + } + + analyzeFunctions(lines) { + const functions = []; + let currentFunction = null; + let bracketCount = 0; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const codePart = line.split('//')[0].trim(); + + if (codePart.startsWith('fn ')) { + if (currentFunction !== null) { + this.addError({ + message: 'Nested function definition not allowed', + type: 'syntax', + position: this.calculatePosition(i, 0, line.length) + }); + } + const fnMatch = codePart.match(/fn\s+([a-zA-Z_][a-zA-Z0-9_]*)/); - // Check module imports - if (line.startsWith('mod ')) { - const modulePattern = /^mod\s+[a-zA-Z_][a-zA-Z0-9_]*\s*;?$/; - if (!modulePattern.test(line)) { - this.addError( - 'Invalid module import syntax', - lineIdx + 1, - 1, - [lineIdx + 1, line.length] - ); + if (!fnMatch) { + this.addError({ + message: 'Invalid function name', + type: 'syntax', + position: this.calculatePosition(i, 0, line.length) + }); + continue; } + currentFunction = { + startLine: i, + name: fnMatch[1], + returnType: this.extractReturnType(codePart), + bracketCount: 0 + }; } - // Check statement semicolons - if (inFunctionBody && - !line.endsWith('{') && - !line.endsWith('}') && - !line.startsWith('fn ') && - !line.startsWith('//') && - !line.endsWith(';') && - line.length > 0) { - this.addError( - 'Missing semicolon at statement end', - lineIdx + 1, - line.length, - [lineIdx + 1, line.length] - ); + if (currentFunction) { + const open = (codePart.match(/{/g) || []).length; + const close = (codePart.match(/}/g) || []).length; + + bracketCount += open - close; + if (bracketCount === 0) { + currentFunction.endLine = i; + functions.push({ ...currentFunction }); + currentFunction = null; + } } + } + + return functions; + } + + checkFunctionBodyStatement(line, lineIdx, originalLine, currentFunction, allLines) { + if (line === '' || line.startsWith('//') || line === '{' || line === '}') return; + const codePart = line.split('//')[0].trimEnd(); + const isLastStatement = this.isLastStatementInFunction(lineIdx, currentFunction, allLines); - // Check for trailing whitespace - if (lines[lineIdx].endsWith(' ')) { - this.addError( - 'Trailing whitespace', - lineIdx + 1, - lines[lineIdx].length, - [lineIdx + 1, lines[lineIdx].length] - ); + if (!isLastStatement && !codePart.endsWith(';') && !codePart.endsWith('{')) { + const nextNonEmptyLine = this.findNextNonEmptyLine(lineIdx + 1, allLines); + if (nextNonEmptyLine && !nextNonEmptyLine.trim().startsWith('//')) { + this.addError({ + message: 'Missing semicolon at statement end', + type: 'syntax', + position: this.calculatePosition( + lineIdx, + originalLine.length, + originalLine.length + ) + }); } + } + const semicolonMatches = [...codePart.matchAll(/;/g)]; - this.currentLine++; + if (semicolonMatches.length > 1) { + this.addError({ + message: 'Multiple semicolons in a single statement', + type: 'syntax', + position: this.calculatePosition( + lineIdx, + semicolonMatches[1].index, + originalLine.length + ) + }); } + } - return this.errors; + extractReturnType(line) { + const returnMatch = line.match(/->\s*([a-zA-Z_][a-zA-Z0-9_:<>, ]*)/); + + return returnMatch ? returnMatch[1].trim() : null; + } + + checkFunctionReturnType(line, lineIdx, originalLine) { + const returnMatch = line.match(/->\s*([a-zA-Z_][a-zA-Z0-9_:<>, ]*)/); + + if (returnMatch) { + const returnType = returnMatch[1].trim(); + + // Check if it's a valid Noir type or a custom type + if (!this.isValidNoirType(returnType)) { + this.addError({ + message: `Potentially invalid return type: ${returnType}`, + type: 'warning', + position: this.calculatePosition( + lineIdx, + originalLine.indexOf(returnType), + originalLine.indexOf(returnType) + returnType.length + ) + }); + } + } + } + + isLastStatementInFunction(currentLine, currentFunction, lines) { + for (let i = currentLine + 1; i <= currentFunction.endLine; i++) { + const line = lines[i].trim(); + if (line && !line.startsWith('//') && line !== '}') { + return false; + } + } + return true; + } + + findNextNonEmptyLine(startIndex, lines) { + for (let i = startIndex; i < lines.length; i++) { + const line = lines[i].trim(); + if (line && !line.startsWith('//')) { + return line; + } + } + return null; + } + + checkModuleImport(line, lineIdx, originalLine) { + const modulePattern = /^mod\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*;?$/; + const match = line.match(modulePattern); + + if (!match) { + this.addError({ + message: 'Invalid module import syntax', + type: 'syntax', + position: this.calculatePosition(lineIdx, 0, originalLine.length) + }); + } else if (!line.endsWith(';')) { + this.addError({ + message: 'Missing semicolon after module import', + type: 'syntax', + position: this.calculatePosition( + lineIdx, + originalLine.length, + originalLine.length + ) + }); + } + } + + isValidNoirType(type) { + // Basic types + if (this.noirTypes.includes(type)) return true; + + // Array types + if (type.includes('[') && type.includes(']')) { + const baseType = type.match(/\[(.*?);/)?.[1]; + return baseType && this.noirTypes.includes(baseType); + } + + // Generic types or custom types (not supported for now) + return false; + } + + calculatePosition(line, startColumn, endColumn) { + return { + start: { + line: line + 1, + column: startColumn + 1 + }, + end: { + line: line + 1, + column: endColumn + 1 + } + }; } - addError(message, line, column, range) { - this.errors.push({ - message, - line, - column, - range: range || [line, column] - }); + addError(error) { + this.errors.push(error); } } diff --git a/apps/noir-compiler/src/app/services/noirPluginClient.ts b/apps/noir-compiler/src/app/services/noirPluginClient.ts index e27154d23e1..90d7fe94ee4 100644 --- a/apps/noir-compiler/src/app/services/noirPluginClient.ts +++ b/apps/noir-compiler/src/app/services/noirPluginClient.ts @@ -51,14 +51,16 @@ export class NoirPluginClient extends PluginClient { async compile(path: string): Promise { try { this.internalEvents.emit('noir_compiling_start') - this.emit('statusChanged', { key: 'loading', title: 'Compiling Noir Circuit...', type: 'info' }) + this.emit('statusChanged', { key: 'loading', title: 'Compiling Noir Program...', type: 'info' }) // @ts-ignore this.call('terminal', 'log', { type: 'log', value: 'Compiling ' + path }) - const program = await compile_program(this.fm) + const program = await compile_program(this.fm, null, this.logFn.bind(this), this.debugFn.bind(this)) console.log('program: ', program) this.internalEvents.emit('noir_compiling_done') this.emit('statusChanged', { key: 'succeed', title: 'Noir circuit compiled successfully', type: 'success' }) + // @ts-ignore + this.call('terminal', 'log', { type: 'log', value: 'Compiled successfully' }) } catch (e) { this.emit('statusChanged', { key: 'error', title: e.message, type: 'error' }) this.internalEvents.emit('noir_compiling_errored', e) @@ -68,13 +70,29 @@ export class NoirPluginClient extends PluginClient { async parse(path: string, content?: string): Promise { if (!content) content = await this.call('fileManager', 'readFile', path) - await this.resolveDependencies(path, content) const result = this.parser.parseNoirCode(content) - console.log('result: ', result) - const fileBytes = new TextEncoder().encode(content) + if (result.length > 0) { + const markers = [] + + for (const error of result) { + markers.push({ + message: error.message, + severity: 'error', + position: error.position, + file: path, + }) + } + // @ts-ignore + await this.call('editor', 'addErrorMarker', markers) + } else { + await this.resolveDependencies(path, content) + const fileBytes = new TextEncoder().encode(content) - this.fm.writeFile(`${path}`, new Blob([fileBytes]).stream()) + this.fm.writeFile(`${path}`, new Blob([fileBytes]).stream()) + // @ts-ignore + await this.call('editor', 'clearErrorMarkers', [path]) + } } async resolveDependencies (filePath: string, fileContent: string, parentPath: string = '', visited: Record = {}): Promise { @@ -118,4 +136,12 @@ export class NoirPluginClient extends PluginClient { } } } + + logFn(log) { + this.call('terminal', 'log', { type: 'error', value: log }) + } + + debugFn(log) { + this.call('terminal', 'log', { type: 'log', value: log }) + } } From 927c69be2edaa8aa6f43a85b7d7863d9498a15b0 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 3 Feb 2025 15:55:26 +0000 Subject: [PATCH 14/15] Remove unused code --- .../src/app/components/container.tsx | 60 +------------------ .../src/app/services/noirPluginClient.ts | 2 +- 2 files changed, 3 insertions(+), 59 deletions(-) diff --git a/apps/noir-compiler/src/app/components/container.tsx b/apps/noir-compiler/src/app/components/container.tsx index cb26e617404..062149bb598 100644 --- a/apps/noir-compiler/src/app/components/container.tsx +++ b/apps/noir-compiler/src/app/components/container.tsx @@ -21,22 +21,7 @@ export function Container () { } } - const handleOpenErrorLocation = async (report: CompilerReport) => { - if (report.labels.length > 0) { - // const location = noirApp.appState.filePathToId[report.labels[0].file_id] - // const startRange = report.labels[0].range.start - - // if (location) { - // const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) - - // await circuitApp.plugin.call('fileManager', 'open', fullPathLocation) - // // @ts-ignore - // const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange) - // // @ts-ignore - // await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column) - // } - } - } + const handleOpenErrorLocation = async (report: CompilerReport) => {} const handleCircuitAutoCompile = (value: boolean) => { noirApp.dispatch({ type: 'SET_AUTO_COMPILE', payload: value }) @@ -46,48 +31,7 @@ export function Container () { noirApp.dispatch({ type: 'SET_HIDE_WARNINGS', payload: value }) } - const askGPT = async (report: CompilerReport) => { - if (report.labels.length > 0) { - // const location = circuitApp.appState.filePathToId[report.labels[0].file_id] - // const error = report.labels[0].message - - // if (location) { - // const fullPathLocation = await circuitApp.plugin.resolveReportPath(location) - // const content = await circuitApp.plugin.call('fileManager', 'readFile', fullPathLocation) - // const message = ` - // circom code: ${content} - // error message: ${error} - // full circom error: ${JSON.stringify(report, null, 2)} - // explain why the error occurred and how to fix it. - // ` - // await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) - // setTimeout(async () => { - // await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) - // }, 500) - // } else { - // const message = ` - // error message: ${error} - // full circom error: ${JSON.stringify(report, null, 2)} - // explain why the error occurred and how to fix it. - // ` - // await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) - // setTimeout(async () => { - // await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) - // }, 500) - // } - } else { - // const error = report.message - // const message = ` - // error message: ${error} - // full circom error: ${JSON.stringify(report, null, 2)} - // explain why the error occurred and how to fix it. - // ` - // await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true) - // setTimeout(async () => { - // await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) - // }, 500) - } - } + const askGPT = async (report: CompilerReport) => {} const handleCompileClick = () => { compileNoirCircuit(noirApp.plugin, noirApp.appState) diff --git a/apps/noir-compiler/src/app/services/noirPluginClient.ts b/apps/noir-compiler/src/app/services/noirPluginClient.ts index 90d7fe94ee4..718727f5e2e 100644 --- a/apps/noir-compiler/src/app/services/noirPluginClient.ts +++ b/apps/noir-compiler/src/app/services/noirPluginClient.ts @@ -56,7 +56,7 @@ export class NoirPluginClient extends PluginClient { this.call('terminal', 'log', { type: 'log', value: 'Compiling ' + path }) const program = await compile_program(this.fm, null, this.logFn.bind(this), this.debugFn.bind(this)) - console.log('program: ', program) + this.call('fileManager', 'writeFile', path.replace('.nr', '.json'), JSON.stringify(program, null, 2)) this.internalEvents.emit('noir_compiling_done') this.emit('statusChanged', { key: 'succeed', title: 'Noir circuit compiled successfully', type: 'success' }) // @ts-ignore From c5f8618243c0a32b78b40814d8f6928c363575bf Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 3 Feb 2025 16:01:30 +0000 Subject: [PATCH 15/15] Remove unused libraries --- package.json | 2 -- yarn.lock | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/package.json b/package.json index 36f4c15fadd..9b72ab53a67 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,6 @@ "core-js": "^3.6.5", "cors": "^2.8.5", "create-hash": "^1.2.0", - "dedent": "^1.5.3", "deep-equal": "^1.0.1", "document-register-element": "1.13.1", "electron-squirrel-startup": "^1.0.0", @@ -176,7 +175,6 @@ "merge": "^2.1.1", "npm-install-version": "^6.0.2", "octokit": "^3.1.2", - "ohm-js": "^17.1.0", "path-browserify": "^1.0.1", "prettier": "^2.8.4", "prettier-plugin-solidity": "^1.0.0-beta.24", diff --git a/yarn.lock b/yarn.lock index 9f9010fe812..4a0223ec1a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13536,11 +13536,6 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= -dedent@^1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" - integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== - deep-eql@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.0.1.tgz#2b65bc89491d193780c452edee2144a91bb0a445" @@ -24070,11 +24065,6 @@ ofetch@^1.3.3: node-fetch-native "^1.4.0" ufo "^1.3.0" -ohm-js@^17.1.0: - version "17.1.0" - resolved "https://registry.yarnpkg.com/ohm-js/-/ohm-js-17.1.0.tgz#50d8e08f69d7909931998d75202d35e2a90c8885" - integrity sha512-xc3B5dgAjTBQGHaH7B58M2Pmv6WvzrJ/3/7LeUzXNg0/sY3jQPdSd/S2SstppaleO77rifR1tyhdfFGNIwxf2Q== - on-exit-leak-free@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209"