From ad2916b018bfb8957ae0e54782f9f453d7cc3687 Mon Sep 17 00:00:00 2001 From: lichx <lchx751176501@gmail.com> Date: Tue, 19 Nov 2024 21:09:20 +0800 Subject: [PATCH] =?UTF-8?q?[feature]=20=E5=8F=AA=E6=98=AF=E8=83=BD?= =?UTF-8?q?=E8=B7=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 24 + .vscode/extensions.json | 3 + README.md | 5 + index.html | 13 + package-lock.json | 1606 ++++++++++++++++++++++++++ package.json | 35 + public/vite.svg | 1 + src/App.vue | 32 + src/assets/compile.png | Bin 0 -> 2512 bytes src/assets/play.png | Bin 0 -> 4848 bytes src/assets/refresh.png | Bin 0 -> 6882 bytes src/assets/step.png | Bin 0 -> 3839 bytes src/assets/stop.png | Bin 0 -> 6994 bytes src/components/CodeInput.vue | 121 ++ src/components/ControlPanel.vue | 87 ++ src/components/Editors.vue | 147 +++ src/components/LEDScreen.vue | 38 + src/components/MachineCodeLayout.vue | 90 ++ src/components/MemoryLayout.vue | 163 +++ src/components/SingleLED.vue | 54 + src/main.ts | 5 + src/my-asm-grammar | 62 + src/style.css | 28 + src/utils/CodeChecker.ts | 50 + src/utils/Complier.ts | 217 ++++ src/utils/MemoryManager.ts | 166 +++ src/utils/Runner.ts | 374 ++++++ src/utils/parser.js | 16 + src/utils/parser.terms.js | 20 + src/vite-env.d.ts | 6 + tsconfig.app.json | 27 + tsconfig.json | 7 + tsconfig.node.json | 24 + vite.config.ts | 7 + 34 files changed, 3428 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 README.md create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/vite.svg create mode 100644 src/App.vue create mode 100644 src/assets/compile.png create mode 100644 src/assets/play.png create mode 100644 src/assets/refresh.png create mode 100644 src/assets/step.png create mode 100644 src/assets/stop.png create mode 100644 src/components/CodeInput.vue create mode 100644 src/components/ControlPanel.vue create mode 100644 src/components/Editors.vue create mode 100644 src/components/LEDScreen.vue create mode 100644 src/components/MachineCodeLayout.vue create mode 100644 src/components/MemoryLayout.vue create mode 100644 src/components/SingleLED.vue create mode 100644 src/main.ts create mode 100644 src/my-asm-grammar create mode 100644 src/style.css create mode 100644 src/utils/CodeChecker.ts create mode 100644 src/utils/Complier.ts create mode 100644 src/utils/MemoryManager.ts create mode 100644 src/utils/Runner.ts create mode 100644 src/utils/parser.js create mode 100644 src/utils/parser.terms.js create mode 100644 src/vite-env.d.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a7cea0b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar"] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..33895ab --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Vue 3 + TypeScript + Vite + +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more. + +Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup). diff --git a/index.html b/index.html new file mode 100644 index 0000000..dde16aa --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <link rel="icon" type="image/svg+xml" href="/vite.svg" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Vite + Vue + TS</title> + </head> + <body> + <div id="app"></div> + <script type="module" src="/src/main.ts"></script> + </body> +</html> diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0cc3904 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1606 @@ +{ + "name": "led_simulator", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "led_simulator", + "version": "0.0.0", + "dependencies": { + "@codemirror/autocomplete": "^6.18.2", + "@codemirror/lang-css": "^6.3.0", + "@codemirror/lang-html": "^6.4.9", + "@codemirror/lang-javascript": "^6.2.2", + "@codemirror/lint": "^6.8.2", + "@codemirror/theme-one-dark": "^6.1.2", + "@codemirror/view": "^6.34.2", + "@lezer/lr": "^1.0.0", + "codemirror": "^6.0.1", + "codemirror-one-dark-theme": "^1.1.1", + "lezer": "^0.13.5", + "vue": "^3.5.12", + "vue-codemirror": "^6.1.1" + }, + "devDependencies": { + "@lezer/generator": "^1.0.0", + "@types/node": "^22.9.0", + "@vitejs/plugin-vue": "^5.1.4", + "typescript": "~5.6.2", + "vite": "^5.4.10", + "vue-tsc": "^2.1.8" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.2", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@codemirror/autocomplete": { + "version": "6.18.2", + "resolved": "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.18.2.tgz", + "integrity": "sha512-wJGylKtMFR/Ds6Gh01+OovXE/pncPiKZNNBKuC39pKnH+XK5d9+WsNqcrdxPjFPFTigRBqse0rfxw9UxrfyhPg==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.7.1", + "resolved": "https://registry.npmmirror.com/@codemirror/commands/-/commands-6.7.1.tgz", + "integrity": "sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-css": { + "version": "6.3.0", + "resolved": "https://registry.npmmirror.com/@codemirror/lang-css/-/lang-css-6.3.0.tgz", + "integrity": "sha512-CyR4rUNG9OYcXDZwMPvJdtb6PHbBDKUc/6Na2BIwZ6dKab1JQqKa4di+RNRY9Myn7JB81vayKwJeQ7jEdmNVDA==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.1.7" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.4.9", + "resolved": "https://registry.npmmirror.com/@codemirror/lang-html/-/lang-html-6.4.9.tgz", + "integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz", + "integrity": "sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.10.3", + "resolved": "https://registry.npmmirror.com/@codemirror/language/-/language-6.10.3.tgz", + "integrity": "sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.8.2", + "resolved": "https://registry.npmmirror.com/@codemirror/lint/-/lint-6.8.2.tgz", + "integrity": "sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.7", + "resolved": "https://registry.npmmirror.com/@codemirror/search/-/search-6.5.7.tgz", + "integrity": "sha512-6+iLsXvITWKHYlkgHPCs/qiX4dNzn8N78YfhOFvPtPYCkuXqZq10rAfsUMhOq7O/1VjJqdXRflyExlfVcu/9VQ==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmmirror.com/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==", + "license": "MIT" + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.2", + "resolved": "https://registry.npmmirror.com/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz", + "integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.34.2", + "resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.34.2.tgz", + "integrity": "sha512-d6n0WFvL970A9Z+l9N2dO+Hk9ev4hDYQzIx+B9tCyBP0W5wPEszi1rhuyFesNSkLZzXbQE5FPH7F/z/TMJfoPA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@lezer/common": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "license": "MIT" + }, + "node_modules/@lezer/css": { + "version": "1.1.9", + "resolved": "https://registry.npmmirror.com/@lezer/css/-/css-1.1.9.tgz", + "integrity": "sha512-TYwgljcDv+YrV0MZFFvYFQHCfGgbPMR6nuqLabBdmZoFH3EP1gvw8t0vae326Ne3PszQkbXfVBjCnf3ZVCr0bA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/generator": { + "version": "1.7.1", + "resolved": "https://registry.npmmirror.com/@lezer/generator/-/generator-1.7.1.tgz", + "integrity": "sha512-MgPJN9Si+ccxzXl3OAmCeZuUKw4XiPl4y664FX/hnnyG9CTqUPq65N3/VGPA2jD23D7QgMTtNqflta+cPN+5mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.1.0", + "@lezer/lr": "^1.3.0" + }, + "bin": { + "lezer-generator": "src/lezer-generator.cjs" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.2.1.tgz", + "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.10", + "resolved": "https://registry.npmmirror.com/@lezer/html/-/html-1.3.10.tgz", + "integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.4.19", + "resolved": "https://registry.npmmirror.com/@lezer/javascript/-/javascript-1.4.19.tgz", + "integrity": "sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.2", + "resolved": "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.4.tgz", + "integrity": "sha512-jfUJrFct/hTA0XDM5p/htWKoNNTbDLY0KRwEt6pyOA6k2fmk0WVwl65PdUdJZgzGEHWx+49LilkcSaumQRyNQw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.4.tgz", + "integrity": "sha512-j4nrEO6nHU1nZUuCfRKoCcvh7PIywQPUCBa2UsootTHvTHIoIu2BzueInGJhhvQO/2FTRdNYpf63xsgEqH9IhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.4.tgz", + "integrity": "sha512-GmU/QgGtBTeraKyldC7cDVVvAJEOr3dFLKneez/n7BvX57UdhOqDsVwzU7UOnYA7AAOt+Xb26lk79PldDHgMIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.4.tgz", + "integrity": "sha512-N6oDBiZCBKlwYcsEPXGDE4g9RoxZLK6vT98M8111cW7VsVJFpNEqvJeIPfsCzbf0XEakPslh72X0gnlMi4Ddgg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.4.tgz", + "integrity": "sha512-py5oNShCCjCyjWXCZNrRGRpjWsF0ic8f4ieBNra5buQz0O/U6mMXCpC1LvrHuhJsNPgRt36tSYMidGzZiJF6mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.4.tgz", + "integrity": "sha512-L7VVVW9FCnTTp4i7KrmHeDsDvjB4++KOBENYtNYAiYl96jeBThFfhP6HVxL74v4SiZEVDH/1ILscR5U9S4ms4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.4.tgz", + "integrity": "sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.4.tgz", + "integrity": "sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.4.tgz", + "integrity": "sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.4.tgz", + "integrity": "sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.4.tgz", + "integrity": "sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.4.tgz", + "integrity": "sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.4.tgz", + "integrity": "sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.4.tgz", + "integrity": "sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.4.tgz", + "integrity": "sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.4.tgz", + "integrity": "sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.4.tgz", + "integrity": "sha512-V3nCe+eTt/W6UYNr/wGvO1fLpHUrnlirlypZfKCT1fG6hWfqhPgQV/K/mRBXBpxc0eKLIF18pIOFVPh0mqHjlg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.4.tgz", + "integrity": "sha512-LTw1Dfd0mBIEqUVCxbvTE/LLo+9ZxVC9k99v1v4ahg9Aak6FpqOfNu5kRkeTAn0wphoC4JU7No1/rL+bBCEwhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.9.0", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.1.4", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.1.4.tgz", + "integrity": "sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.9", + "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.9.tgz", + "integrity": "sha512-t++GIrUeQnKCieZdY9e+Uar2VmTqOE4Z9KcEcdSHKmKZPuqpbbWow1YKe1i3HpU2s1JqLRVM8y/n87WKXyxJAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.9" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.9", + "resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.9.tgz", + "integrity": "sha512-UGE+WgJwk64OcfBwBOBKIzmF+uNx4dC5GzOvaVsHbTBp/IVqeTVsGiO5CwBAt6l3vVXYbMuddG2DU8FEnBRxTg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.9", + "resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.9.tgz", + "integrity": "sha512-Zmh3Bq8CFD6OANKYsi4vs/l7togwfjFH0kgrT12uAsDff2AJQjbEUKTVUnxmHbnbH2B9ja7Lb6Mu/Wj9wBuJlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.9", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.12.tgz", + "integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.12", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", + "integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.12", + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", + "integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.12", + "@vue/compiler-dom": "3.5.12", + "@vue/compiler-ssr": "3.5.12", + "@vue/shared": "3.5.12", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.47", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", + "integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.12", + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmmirror.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/@vue/language-core": { + "version": "2.1.10", + "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-2.1.10.tgz", + "integrity": "sha512-DAI289d0K3AB5TUG3xDp9OuQ71CnrujQwJrQnfuZDwo6eGNf0UoRlPuaVNO+Zrn65PC3j0oB2i7mNmVPggeGeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~2.4.8", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^0.2.0", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.12.tgz", + "integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.12.tgz", + "integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.12", + "@vue/shared": "3.5.12" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz", + "integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.12", + "@vue/runtime-core": "3.5.12", + "@vue/shared": "3.5.12", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.12.tgz", + "integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.12", + "@vue/shared": "3.5.12" + }, + "peerDependencies": { + "vue": "3.5.12" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.12.tgz", + "integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==", + "license": "MIT" + }, + "node_modules/alien-signals": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-0.2.0.tgz", + "integrity": "sha512-StlonZhBBrsPPwrDjiPAiVTf/rolxffLxVPT60Qv/t88BZ81BvUVzHgGqEFvJ1ii8HXtm1+zU2Icr59tfWEcag==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "node_modules/codemirror-one-dark-theme": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/codemirror-one-dark-theme/-/codemirror-one-dark-theme-1.1.1.tgz", + "integrity": "sha512-SuGz+mjIhWZcU59PQT1KQL8YDdCZOB7zWyPSKC9T8KCjiFCsNaRnaOpI9LDamHUx8X+a7tEfiogemx6L/WDZCg==", + "license": "MIT" + }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/lezer": { + "version": "0.13.5", + "resolved": "https://registry.npmmirror.com/lezer/-/lezer-0.13.5.tgz", + "integrity": "sha512-cAiMQZGUo2BD8mpcz7Nv1TlKzWP7YIdIRrX41CiP5bk5t4GHxskOxWUx2iAOuHlz8dO+ivbuXr0J1bfHsWD+lQ==", + "deprecated": "This package has been replaced by @lezer/lr", + "license": "MIT", + "dependencies": { + "lezer-tree": "^0.13.2" + } + }, + "node_modules/lezer-tree": { + "version": "0.13.2", + "resolved": "https://registry.npmmirror.com/lezer-tree/-/lezer-tree-0.13.2.tgz", + "integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ==", + "deprecated": "This package has been replaced by @lezer/common", + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.12", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.24.4.tgz", + "integrity": "sha512-vGorVWIsWfX3xbcyAS+I047kFKapHYivmkaT63Smj77XwvLSJos6M1xGqZnBPFQFBRZDOcG1QnYEIxAvTr/HjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.24.4", + "@rollup/rollup-android-arm64": "4.24.4", + "@rollup/rollup-darwin-arm64": "4.24.4", + "@rollup/rollup-darwin-x64": "4.24.4", + "@rollup/rollup-freebsd-arm64": "4.24.4", + "@rollup/rollup-freebsd-x64": "4.24.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.4", + "@rollup/rollup-linux-arm-musleabihf": "4.24.4", + "@rollup/rollup-linux-arm64-gnu": "4.24.4", + "@rollup/rollup-linux-arm64-musl": "4.24.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.4", + "@rollup/rollup-linux-riscv64-gnu": "4.24.4", + "@rollup/rollup-linux-s390x-gnu": "4.24.4", + "@rollup/rollup-linux-x64-gnu": "4.24.4", + "@rollup/rollup-linux-x64-musl": "4.24.4", + "@rollup/rollup-win32-arm64-msvc": "4.24.4", + "@rollup/rollup-win32-ia32-msvc": "4.24.4", + "@rollup/rollup-win32-x64-msvc": "4.24.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "5.4.10", + "resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.10.tgz", + "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.12", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.12.tgz", + "integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.12", + "@vue/compiler-sfc": "3.5.12", + "@vue/runtime-dom": "3.5.12", + "@vue/server-renderer": "3.5.12", + "@vue/shared": "3.5.12" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-codemirror": { + "version": "6.1.1", + "resolved": "https://registry.npmmirror.com/vue-codemirror/-/vue-codemirror-6.1.1.tgz", + "integrity": "sha512-rTAYo44owd282yVxKtJtnOi7ERAcXTeviwoPXjIc6K/IQYUsoDkzPvw/JDFtSP6T7Cz/2g3EHaEyeyaQCKoDMg==", + "license": "MIT", + "dependencies": { + "@codemirror/commands": "6.x", + "@codemirror/language": "6.x", + "@codemirror/state": "6.x", + "@codemirror/view": "6.x" + }, + "peerDependencies": { + "codemirror": "6.x", + "vue": "3.x" + } + }, + "node_modules/vue-tsc": { + "version": "2.1.10", + "resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-2.1.10.tgz", + "integrity": "sha512-RBNSfaaRHcN5uqVqJSZh++Gy/YUzryuv9u1aFWhsammDJXNtUiJMNoJ747lZcQ68wUQFx6E73y4FY3D8E7FGMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "~2.4.8", + "@vue/language-core": "2.1.10", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..556bde6 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "led_simulator", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc -b && vite build", + "preview": "vite preview", + "prepare": "lezer-generator src/my-asm-grammar -o src/parser.js" + }, + "dependencies": { + "@codemirror/autocomplete": "^6.18.2", + "@codemirror/lang-css": "^6.3.0", + "@codemirror/lang-html": "^6.4.9", + "@codemirror/lang-javascript": "^6.2.2", + "@codemirror/lint": "^6.8.2", + "@codemirror/theme-one-dark": "^6.1.2", + "@codemirror/view": "^6.34.2", + "@lezer/lr": "^1.0.0", + "codemirror": "^6.0.1", + "codemirror-one-dark-theme": "^1.1.1", + "lezer": "^0.13.5", + "vue": "^3.5.12", + "vue-codemirror": "^6.1.1" + }, + "devDependencies": { + "@lezer/generator": "^1.0.0", + "@types/node": "^22.9.0", + "@vitejs/plugin-vue": "^5.1.4", + "typescript": "~5.6.2", + "vite": "^5.4.10", + "vue-tsc": "^2.1.8" + } +} diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg> \ No newline at end of file diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..9d83dc4 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,32 @@ +<script setup lang="ts"> +import {provide} from "vue"; +import LEDScreen from "./components/LEDScreen.vue"; +import {MemoryManager} from "./utils/MemoryManager.ts"; +import {CodeChecker} from "./utils/CodeChecker.ts"; +import "./style.css"; +import Editors from "./components/Editors.vue"; +import {Runner} from "./utils/Runner.ts"; +import ControlPanel from "./components/ControlPanel.vue"; +import {Compiler} from "./utils/Complier.ts"; + +let memManager = new MemoryManager(); +let compiler = new Compiler(); +provide("compiler", compiler); +provide("memoryManager", memManager); +provide("codeChecker", new CodeChecker()); +provide("runner", new Runner(memManager,compiler)); +</script> + +<template> + <h1>LED显示屏模拟器</h1> + <p>made by li_chx</p> + <LEDScreen/> + <ControlPanel/> + <Editors/> + +</template> + +<style scoped> + + +</style> diff --git a/src/assets/compile.png b/src/assets/compile.png new file mode 100644 index 0000000000000000000000000000000000000000..38bde3d8a0da76134e5d80c297be7b42fd787d3f GIT binary patch literal 2512 zcmbVO2~ZPP7><Za@Mx=yrHZmHSZm8>a}Y>YBPaoa8c_)a9UR&0F0kg<kX=kbgrS`( zRE^M%$5_-lT6LfvSP?6h>ZsL@mMWciHrje)6l55%fMVZrWJGBl&CKTg|Gw{i|M~ve zqPcTohx?B46$k{w<235|U_HY>K7+ykp5(n-z#_D07O(=r&{6y|K(MLQUm);qpmoVy zvUWB`FeVXBGI~m6H(3B$Aeb6qx8Q_<;vhYhPMcM5WA)E4M3X8wNv;)ZEm2ekt;w-c z2|06gM2>+_l5oT{XsR6p1SX2ZA-l<FW-+@8?&8IO%)drqs0+dwRPc1(Ae5|~3q>(j z3Q~$B2q6|rpm3!KSCFCMa#;u@6-#BPScXbvh**Ki!!TJm)boRZIV+il%~!|t7z3IL z&fqu;hN3o`O=Oda7;8EzQ7V<FSc*!e2tXigwwc52h?x!QWl&QrVWlk`&6pvc5!W+W zoC*f6cE@0{cxcURPo6-=P&;lxB_c5&Qx}jVJUC01)!1d6Bv8sonJ6>I0<6S?wPY|H z!)7r5LG9V@V*un<tM%CE*B6t?V}j+Pmx3^Q64Ec4)n!{KbUwv0SyqCIUJBd{;-j%( zQC14)7^{w9jJ=hb+v_qU4Hbn!A0^RdlCiOqUpPRiagI{KplYFrM1n}dbP_oxQ(!XL zC!l;{aW_=UkaSvhzfdJ6?F$7xL*g9%S};jqX^ho`gMeuho=%|_b2<!p(uhSdM#c&Z z1Mg&AUTC#goSEftGeO0vRWOKIMAIZj5E490CX*pDad<c)(T9d3dQuXKD5O#eh06$q zK26?xUd<3$d}VvjlW%xF-b#b3g&W_Rhre)qOJEwB1;xtlxe*CeW{+f~p{_2#aDwk{ z6-@ADrAWBvHT~8Z=%%%0P=NG*%H0iPnKaIZTdC>kAX~3(Clol3^7pVi4)o;^yY^nV zv%PRI2zb#mf`H-~Vw4$7E-M&Om-GJq6->UuIQ4X$z4Xza*XG^+)NjQF<XAT6t4<9l zS_M6g^qzWIxjL$Tm}Xn^{vmDn>?<b<x7OURt6Si1^4o1osxJ>JJ73>kgQi~ot#05k z`6wT6uYySE-9F3Vu?rs_F*hh{TRYA+M=jo0{oTF4mMwAx<W=WiMOCLKujni%#l`Zr z>IaV#vKF_Ox$1s+tWC<gUp{`r7GhX={>hvp`PkD$7rMxa*DtWI+P*C1T0>KbbIAOO zUl}SY6=h)~HS09%51j&%A1@tn0%<gm?jE`WB!6By&;q0}K-zh6MnK}&5j$oEC(sie zWovkrib}uO#DN96A~Iypsd-KflnDQ*Ta~Gk^K`Y&B>{<R1_4+?Wk77==Kyv)dC%#2 z&I|x+Tdk;}!-_vH$yEnDr!gQLo#beg2ZD3g3vb1GwI#Vr3W<%8ox7ZxlTDI>qkk+6 zzIn!5`t3TPDhqN`!S*eMm+;V-B86j8al8>3nOPbG#a^Bnd{ePG(s8g=b24*$L22q9 zfXnq#UbqUscbf9HuBcSQj<dqsvoDP=Qv5QZcxZ|t_@@8bND*fO_ENk)IL-r_gk<on zSlB`Pkm^~{u%q6GBw1b;l3pyY3rRQu=-EExj0B*!`H*^o*M;O@g4c!QhZ|yG2jxS? z+ym<!A2MwhuM5cmr+HmSPS^@?Zm4+Ba=#+Q-j$J~Tc?f8OnJW`rJzbvwgh#!>sppS zzoox~h<!s0yT7R37MPotecg4@ePUx^XQjC{{z?2w$-cO6b{>wXKBCk)JD;_uLRBs8 z=M$e$=LVSFEfr;*0nM8Z*6&@C6m(;&t7;khJkNFGr55YkaQ$iGf9B+zZQr&Xi8;R} zS9fmV-IOU)`gCc3hx)T}jzES?_@1i0qHx~cTv_^{V!iTG?TA;q{xy8%d6Rx>?8y7l z?RZvGrM%S9d30PqSLZb(UdPMcF(seH1$R@>w~6MnD<e$z%Q{-tZn(EKzHM_&yGwm* zzkX3mb>7b3H#O_NURiUueWCG6sjVb7<V}<1pF8Q9!S#@Fw`4ZpsY(}ascam#LlD?h gIOvrL!H0P~VleZ_kdKI$^50x>(R0*$XQY1iFP?#A@&Et; literal 0 HcmV?d00001 diff --git a/src/assets/play.png b/src/assets/play.png new file mode 100644 index 0000000000000000000000000000000000000000..dd0c18e36f99718e0657240009ae58d149ab9fe7 GIT binary patch literal 4848 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 literal 0 HcmV?d00001 diff --git a/src/assets/refresh.png b/src/assets/refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..f203cc51cdcd7f0782e3c31b17be45e708579fb1 GIT binary patch literal 6882 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 Jxt`mV{{m4ScxC_q literal 0 HcmV?d00001 diff --git a/src/assets/step.png b/src/assets/step.png new file mode 100644 index 0000000000000000000000000000000000000000..89a66851b88ea57347287881a7829940c34bf9a0 GIT binary patch literal 3839 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 literal 0 HcmV?d00001 diff --git a/src/assets/stop.png b/src/assets/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..2a8f983dfe507f50091f24898e363ba9b5c921e0 GIT binary patch literal 6994 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 literal 0 HcmV?d00001 diff --git a/src/components/CodeInput.vue b/src/components/CodeInput.vue new file mode 100644 index 0000000..961378a --- /dev/null +++ b/src/components/CodeInput.vue @@ -0,0 +1,121 @@ +<script setup lang="ts"> +import {inject, ref} from "vue"; +import "../style.css" +import {CodeChecker} from "../utils/CodeChecker.ts"; +import {Codemirror} from "vue-codemirror"; +// @ts-ignore +import {parser} from "../utils/parser.js" +import {foldNodeProp, foldInside} from "@codemirror/language" +import {styleTags, tags as t} from "@lezer/highlight" +import {LRLanguage} from "@codemirror/language" +import {completeFromList} from "@codemirror/autocomplete" +import {LanguageSupport} from "@codemirror/language" +import {oneDark} from "@codemirror/theme-one-dark" +import {keymap} from "@codemirror/view" +import {Compiler} from "../utils/Complier.ts"; +import {insertTab} from "@codemirror/commands" + +let compiler = inject("compiler") as Compiler; + + +let parserWithMetadata = parser.configure({ + props: [ + styleTags({ + Mnemonic: t.keyword, + Register: t.variableName, + ImmediateToken: t.number, + CommentToken: t.lineComment, + LabelToken: t.labelName, + Db: t.definitionKeyword, + Dw: t.definitionKeyword, + NumberList: t.literal, + StringList: t.literal + }), + foldNodeProp.add({ + Statement: foldInside + }) + ] +}) + +const myASMLanguage = LRLanguage.define({ + parser: parserWithMetadata, + languageData: { + commentTokens: {line: ";"} + } +}) + + +const myASMCompletion = myASMLanguage.data.of({ + autocomplete: completeFromList([ + ...CodeChecker.KeyWords.map(keyword => ({label: keyword, type: "keyword"})), + ...CodeChecker.Registers.map(register => ({label: register, type: "variableName"})) + ]) +}) + +function languageSupport() { + return new LanguageSupport(myASMLanguage, [myASMCompletion]) +} + +let code = ref("t: dw 'Hello World'\n" + + "mov \tAX, t\n" + + "ldc \tCX, 0\n" + + "ldc \tDX, 8\n" + + "ldc \tEX, 0\n" + + "ldc\t\tFX, 0\n" + + "ldc\t\tGX, 8\n" + + "lp1:\n" + + "ldc \tBX, 1\n" + + "call \t0, lp\n" + + "add \tAX, DX\n" + + "add \tCX, BX\n" + + "add\t\tFX, BX\n" + + "mov \tBX, FX\n" + + "ltjp\tGX, lp1\n" + + "\n" + + "ldc \tCX, 64\n" + + "ldc\t\tFX, 0\n" + + "ldc\t\tGX, 3\n" + + "lp2:\n" + + "ldc \tBX, 1\n" + + "call \t0, lp\n" + + "add \tAX, DX\n" + + "add \tCX, BX\n" + + "add\t\tFX, BX\n" + + "mov \tBX, FX\n" + + "ltjp\tGX, lp2\n" + + "\n" + + "\n" + + "ret \t0,0\n" + + "lp:\n" + + "ldc\t\tBX, 1\n" + + "cp\t\tAX, CX\n" + + "add\t\tAX, BX\n" + + "add\t\tCX, DX\n" + + "add\t\tEX, BX\n" + + "mov\t\tBX, EX\n" + + "ltjp\tDX,\tlp\n" + + "ret\t\t0,0"); +// compiler.Code = code.value; +compiler.Code = code.value; + +function onCodeChange() { + compiler.Code = code.value; + compiler.CodeChanged = true; +} +</script> + +<template> + <div> + <h2>Code Input</h2> + <codemirror class="CodeMirror custom-codemirror" v-model="code" style="height: 500px;" + :extensions="[languageSupport(), oneDark, keymap.of([{key: 'Tab', run: (view) => insertTab(view)}])]" + :options="{lineNumbers: true}" + @update:modelValue="onCodeChange"/> + </div> +</template> + +<style scoped> +.custom-codemirror { + font-size: 20px; +} +</style> \ No newline at end of file diff --git a/src/components/ControlPanel.vue b/src/components/ControlPanel.vue new file mode 100644 index 0000000..e947463 --- /dev/null +++ b/src/components/ControlPanel.vue @@ -0,0 +1,87 @@ +<script setup lang="ts"> + +import {Runner, RunnerState} from "../utils/Runner.ts"; +import {inject} from "vue"; +import {Compiler} from "../utils/Complier.ts"; +let runner:Runner = inject("runner") as Runner; +console.log(runner); +let compiler = inject("compiler") as Compiler; +function compileCode() { + runner.Stop(); + compiler.CompileCode(); +} +function startOrContinue() { + switch (runner.State) + { + case RunnerState.Running: + break; + case RunnerState.Step: + runner.Resume(); + break; + case RunnerState.Stop: + runner.Run(); + break; + } +} +function step() { + if(compiler.CodeChanged) + { + compiler.CompileCode(); + } + runner.Step(); +} +function stop() { + runner.Stop(); +} +function refresh() { + runner.Refresh(); +} +</script> + +<template> + <div id="controlPanel"> + <div></div> + <div id="buttons"> + <img class="button" src="../assets/compile.png" alt="编译" @click="compileCode"> + <img class="button" src="../assets/play.png" alt="运行/恢复运行" @click="startOrContinue"> + <img class="button" src="../assets/step.png" alt="步过" @click="step"> + <img class="button" src="../assets/stop.png" alt="停止" @click="stop"> + <img class="button" src="../assets/refresh.png" alt="重新调试" @click="refresh"> + </div> + </div> + +</template> + +<style scoped> +#controlPanel { + margin-top: 20px; + display: flex; + flex-direction: row; + align-items: center; +} +#controlPanel > :first-child { + flex: 1; +} +#controlPanel > :last-child { + flex: 0; +} + +#buttons{ + display: flex; +} + +.button{ + flex: 0; + width: 20px; + height: 20px; + margin: 0 3px; + padding: 5px; + cursor: pointer; + border-radius: 5px; + +} +.button:hover{ + background-color: #555555; +} + +</style> \ No newline at end of file diff --git a/src/components/Editors.vue b/src/components/Editors.vue new file mode 100644 index 0000000..cc03333 --- /dev/null +++ b/src/components/Editors.vue @@ -0,0 +1,147 @@ +<script setup lang="ts"> + +import CodeInput from "./CodeInput.vue"; +import MemoryLayout from "./MemoryLayout.vue"; +import MachineCodeLayout from "./MachineCodeLayout.vue"; +import "../style.css"; +import {computed, ref} from "vue"; + +const startX = ref(0); +const parentWidth = ref(0); +const codeInputFlex = ref(1); +const machineCodeLayoutFlex = ref(1); +const memoryLayoutFlex = ref(1); +const startCodeInputFlex = ref(1); +const startMachineCodeLayoutFlex = ref(1); +const startMemoryLayoutFlex = ref(1); +const movingSplitId = ref(""); +const cssVars = computed(() => ({ + '--code-input-flex': codeInputFlex.value, + '--machine-code-layout-flex': machineCodeLayoutFlex.value, + '--memory-layout-flex': memoryLayoutFlex.value + }) +) + +function onMouseDown(event: MouseEvent) { + const htmlElement = event.target as HTMLElement; + parentWidth.value = htmlElement.parentElement!.offsetWidth - 12; + + startX.value = event.clientX; + startCodeInputFlex.value = codeInputFlex.value; + startMachineCodeLayoutFlex.value = machineCodeLayoutFlex.value; + startMemoryLayoutFlex.value = memoryLayoutFlex.value; + if (htmlElement.id === "split1") { + movingSplitId.value = "split1" + } else if (htmlElement.id === "split2") { + movingSplitId.value = "split2" + } + document.body.addEventListener('mousemove', onMouseMove); + document.body.addEventListener('mouseup', onMouseUp); +} + +function onMouseMove(event: MouseEvent) { + const minLimit = 500 / parentWidth.value; + + function limit(t: number, maxLimit: number): number { + t = Math.max(t, minLimit); + t = Math.min(t, maxLimit); + return t; + } + + if (movingSplitId.value === "split1") { + const maxLimit = startCodeInputFlex.value + startMachineCodeLayoutFlex.value - minLimit; + codeInputFlex.value = limit((startCodeInputFlex.value * parentWidth.value + 3 * (event.clientX - startX.value)) / parentWidth.value, maxLimit); + machineCodeLayoutFlex.value = limit((startMachineCodeLayoutFlex.value * parentWidth.value - 3 * (event.clientX - startX.value)) / parentWidth.value, maxLimit); + } else if (movingSplitId.value === "split2") { + const maxLimit = startMachineCodeLayoutFlex.value + startMemoryLayoutFlex.value - minLimit; + machineCodeLayoutFlex.value = limit((startMachineCodeLayoutFlex.value * parentWidth.value + 3 * (event.clientX - startX.value)) / parentWidth.value, maxLimit); + memoryLayoutFlex.value = limit((startMemoryLayoutFlex.value * parentWidth.value - 3 * (event.clientX - startX.value)) / parentWidth.value, maxLimit); + } + +} + +function onMouseUp(event: MouseEvent) { + document.body.removeEventListener('mousemove', onMouseMove); + document.body.removeEventListener('mouseup', onMouseUp); + onMouseMove(event) + startMemoryLayoutFlex.value = memoryLayoutFlex.value; + startMachineCodeLayoutFlex.value = machineCodeLayoutFlex.value; + startCodeInputFlex.value = codeInputFlex.value; +} +</script> + +<template> + <div id="editors"> + <div id="code"> + <CodeInput :style="cssVars"/> + <div id="split1" class="split" @mousedown="onMouseDown"></div> + <MachineCodeLayout :style="cssVars"/> + <div id="split2" class="split" @mousedown="onMouseDown"></div> + <MemoryLayout :style="cssVars"/> + </div> + </div> +</template> + +<style scoped> + +#editors { + margin-top: 5px; + padding: 5px; + border-radius: 15px; + background-color: rgb(55, 55, 55); +} + +@media screen and (min-width: 900px) { + #code { + display: flex; + margin: 0; + padding: 0; + } +} + +#code > * { + background-color: rgb(30, 30, 30); + text-align: left; + flex: 3; + margin: 0; +} + +#code > :nth-child(1) { + border-bottom-left-radius: 15px; + border-top-left-radius: 15px; + flex: var(--code-input-flex); + overflow: hidden; + min-width: 100px; +} + +#code > :nth-child(3) { + flex: var(--machine-code-layout-flex); + overflow: hidden; + min-width: 100px; +} + +#code > :nth-child(5) { + border-bottom-right-radius: 15px; + border-top-right-radius: 15px; + + textarea { + border-bottom-right-radius: 15px; + } + + flex: var(--memory-layout-flex); + overflow: hidden; + min-width: 100px; +} + +#code .split { + flex: 0; + cursor: ew-resize; + background-color: rgb(55, 55, 55); + padding-right: 6px; +} + +#code .split:hover { + background-color: rgb(70, 70, 70); + +} +</style> \ No newline at end of file diff --git a/src/components/LEDScreen.vue b/src/components/LEDScreen.vue new file mode 100644 index 0000000..5ff53ec --- /dev/null +++ b/src/components/LEDScreen.vue @@ -0,0 +1,38 @@ +<script setup lang="ts"> +import {computed, inject} from "vue"; +import SingleLED from "./SingleLED.vue"; +import {MemoryManager} from "../utils/MemoryManager.ts"; + +let memoryManager = inject("memoryManager") as MemoryManager; +let screenMemory = computed(() => { + return memoryManager.screenMemory.value.map(row => row.map(byte => byte.value)); +}) +</script> + +<template> + <div class="screen"> + <div class="screen-row" v-for="(row, rowIndex) in screenMemory" :key="rowIndex"> + <div v-for="(col, colIndex) in row" :key="colIndex" class="led-group"> + <SingleLED v-for="(led, ledIndex) in col.slice().reverse()" :rowIndex="rowIndex" :colIndex="colIndex" + :ledIndex="ledIndex" v-bind:isActive="led"/> + </div> + </div> + </div> +</template> + +<style scoped> +.screen { + display: flex; + flex-direction: column; + white-space: nowrap; /* Prevent wrapping */ + overflow-x: auto; + margin: 0 auto; + padding-top: 20px; +} + +.screen-row { + display: flex; + flex-direction: row; + margin: 0 auto; +} +</style> \ No newline at end of file diff --git a/src/components/MachineCodeLayout.vue b/src/components/MachineCodeLayout.vue new file mode 100644 index 0000000..8bd552f --- /dev/null +++ b/src/components/MachineCodeLayout.vue @@ -0,0 +1,90 @@ +<script setup lang="ts"> +import "../style.css" +import {inject, Ref, ref} from "vue"; +import {Compiler} from "../utils/Complier.ts"; +import {Runner, RunnerState} from "../utils/Runner.ts"; + +let compiler: Compiler = inject("compiler") as Compiler; +let runner: Runner = inject("runner") as Runner; +let machineCode: Ref<string[][], string[][]> = ref([]); +let currentPC: Ref<number, number> = ref(-1); +compiler.AddEventListener("CompileFinished", (_) => { + machineCode.value = Array.from(compiler.PCToMachineCode.values()).map((x) => { + x = x.slice(2); + return [x.slice(0, 2), x.slice(2, 4), x.slice(4, 6)]; + }); +}) +runner.AddEventListener("PCChanged", (_) => { + currentPC.value = runner.State===RunnerState.Stop?-1: runner._processCounter; +}) +</script> + +<template> + <div> + <h2>Machine Code Layout</h2> + <div id="code-area"> + <div v-for="(instruction,index) in machineCode"> + <div class="code" :class="{currentCode: index === currentPC}"> + <span class="line-number">{{ index + 1 }}</span> + <div class="gutter"></div> + <span class="mnemonic">{{ instruction[0] }}</span> + <span class="operand">{{ instruction[1] }}</span> + <span class="operand">{{ instruction[2] }}</span> + </div> + </div> + </div> + </div> +</template> + +<style scoped> +#code-area { + padding-top: 4px; + padding-bottom: 4px; + background-color: #282c34; + height: 492px; + overflow-x: auto; +} + +.currentCode { + background-color: #3e4451; +} + +.code { + /*这里的显示需要和 Assembly Code 对齐 但我不知道CodeMirror的行高是怎么算出来的 + 反正edge样式中是这个数,但是其他设备很可能会不对齐*/ + height: 28px; + line-height: 28px; + display: flex; +} + +span { + display: inline; + font-family: monospace; + line-height: 28px; + overflow-wrap: normal; + margin: 0; + font-size: 20px; +} + +.line-number { + padding-right: 3px; + padding-left: 5px; + width: 20px; + text-align: right; + color: rgb(125, 135, 153); +} + +.mnemonic { + color: rgb(198, 120, 221); + margin-right: 3px; +} + +.operand { + color: rgb(224, 108, 117); +} + +.gutter { + display: inline; + width: 9px; +} +</style> \ No newline at end of file diff --git a/src/components/MemoryLayout.vue b/src/components/MemoryLayout.vue new file mode 100644 index 0000000..fb2f697 --- /dev/null +++ b/src/components/MemoryLayout.vue @@ -0,0 +1,163 @@ +<script setup lang="ts"> +import "../style.css" +import {MemoryManager} from "../utils/MemoryManager.ts"; +import {computed, inject, onMounted, Ref, ref} from "vue"; +import {Runner} from "../utils/Runner.ts"; + +const looseLayout = ref(false); +onMounted(() => { + const resizeObserver = new ResizeObserver(entries => { + looseLayout.value = entries[0].target.clientWidth > 525; + }); + resizeObserver.observe(document.querySelector('#memories')!); +}); + +let memoryManager = inject("memoryManager") as MemoryManager; +let runner = inject("runner") as Runner; +let registers: Ref<string[], string[]> = ref([...runner.GetRegisters().map((x) => (x.GetValue(16) as string)) , "00"]); +runner.AddEventListener("RegistersChanged", (_) => { + registers.value = [...runner.GetRegisters().map((x) => (x.GetValue(16) as string)), runner.GetPC().toString(16).padStart(2, '0')]; +}) +let screenMemory = computed(() => { + return memoryManager.screenMemory.value.map(row => row.map(byte => byte.GetValue(16) as string)); +}) +let memory = computed(() => { + let mem = memoryManager.memory; + let res:string[][]; + if(looseLayout.value) + { + res = Array.from({length: 8}, () => Array.from({length: 16}, () => "")); + for (let i = 0; i < 8; i++) { + for (let j = 0; j < 16; j++) { + res[i][j] = mem.value[i * 16 + j].GetValue(16) as string; + } + } + } + else { + res = Array.from({length: 16}, () => Array.from({length: 8}, () => "")); + for (let i = 0; i < 16; i++) { + for (let j = 0; j < 8; j++) { + res[i][j] = mem.value[i * 8 + j].GetValue(16) as string; + } + } + } + return res; +}); +</script> + +<template> + <div> + <h2>Memory Layout</h2> + <div id="memories"> + <p>Screen Memory:</p> + <div id="screen-memory-area"> + <div class="screen-row" v-for="(row, rowIndex) in screenMemory" :key="rowIndex"> + <span class="screen-line-number">{{ rowIndex }}</span> + <div class="gutter"></div> + <span v-for="(col, colIndex) in row" :key="colIndex" class="screen-memory"> + {{ col }} + </span> + </div> + </div> + <p>Registers:</p> + <div id="registers-area" + :class="{'register-loose-layout':looseLayout, 'register-compact-layout':!looseLayout}"> + <div class="registers" v-for="(register,index) in registers"> + <span class="register-name">{{ index!=7? String.fromCharCode('A'.charCodeAt(0) + index) + 'X':'PC' }}</span> + <span class="register-value">{{ register }}</span> + </div> + </div> + <p>Memory:</p> + <div id="screen-memory-area"> + <div class="screen-row" v-for="(row, rowIndex) in memory" :key="rowIndex"> + <span class="screen-line-number">{{ rowIndex }}</span> + <div class="gutter"></div> + <span v-for="(col, colIndex) in row" :key="colIndex" class="screen-memory"> + {{ col }} + </span> + </div> + </div> + </div> + </div> +</template> + +<style scoped> +#memories { + background-color: #282c34; + height: 492px; + padding-bottom: 4px; + padding-top: 4px; + overflow-x: auto; +} + +#registers-area { + line-height: 28px; + display: grid; +} + +.register-loose-layout { + grid-template-columns: repeat(7, 1fr); +} + +.register-compact-layout { + grid-template-columns: repeat(4, 1fr); + grid-template-rows: 1fr 1fr; +} + +p { + margin: 0; + padding: 10px; + color: white; + font-family: monospace; + font-size: 30px; + height: 36px; + white-space: nowrap; + overflow: hidden; +} + +span { + display: inline; + font-family: monospace; + line-height: 28px; + overflow-wrap: normal; + margin: 0; + font-size: 20px; +} + +.registers { + height: 28px; +} + +.register-name { + padding-right: 3px; + padding-left: 5px; + color: rgb(198, 120, 221); +} + +.register-value { + color: rgb(224, 108, 117); +} + +.screen-line-number { + color: rgb(125, 135, 153); + padding-right: 3px; + padding-left: 5px; + display: inline-block; + width: 20px; + height: 28px; + text-align: right; +} + +.screen-row { + color: rgb(224, 188, 105); +} + +.screen-memory { + padding-left: 5px; +} + +.gutter { + display: inline-block; + width: 9px; +} +</style> \ No newline at end of file diff --git a/src/components/SingleLED.vue b/src/components/SingleLED.vue new file mode 100644 index 0000000..059ae80 --- /dev/null +++ b/src/components/SingleLED.vue @@ -0,0 +1,54 @@ +<script setup lang="ts"> +import {ref} from "vue"; +const props = defineProps<{ + isActive: boolean + colIndex: number + rowIndex: number + ledIndex: number +}>(); +const showTooltip = ref(false); +</script> + +<template> + <div class="led-container" @mouseenter="showTooltip = true" @mouseleave="showTooltip = false"> + <div class="led" :class="{ active: isActive }"></div> + <div v-if="showTooltip" class="tooltip" @mouseover="showTooltip = false">{{ props.rowIndex }},{{ props.colIndex * 8 + props.ledIndex }} + 0x{{ (props.rowIndex * 8 + props.colIndex).toString(16).toUpperCase().padStart(2, '0') }} + </div> + </div> +</template> + +<style scoped> +.led-container { + position: relative; + display: inline-block; +} + +.led { + width: 10px; + height: 10px; + background-color: rgb(32, 42, 32); + border-radius: 50%; + box-shadow: 0 0 5px rgba(32, 42, 32, 0.5); + margin: 2px; +} + +.active { + background-color: rgb(137, 221, 64); + box-shadow: 0 0 3px rgba(137, 221, 64, 0.5); +} + +.tooltip { + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%); + background-color: #333; + color: #fff; + padding: 5px; + border-radius: 3px; + white-space: nowrap; + z-index: 10; + opacity: 0.8; +} +</style> \ No newline at end of file diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..2425c0f --- /dev/null +++ b/src/main.ts @@ -0,0 +1,5 @@ +import { createApp } from 'vue' +import './style.css' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/src/my-asm-grammar b/src/my-asm-grammar new file mode 100644 index 0000000..5faf65f --- /dev/null +++ b/src/my-asm-grammar @@ -0,0 +1,62 @@ +@top Program { Statement* } + +Statement { + Label Mnemonic Operand "," Operand Comment? Newline + | Mnemonic Operand "," Operand Comment? Newline + | Label Comment? Newline + | Comment Newline + | Label Db Comment? Newline + | Label Dw Comment? Newline +} + +Mnemonic { + "nop"|"ldc"|"add"|"div"|"and"|"or"|"xor"|"not"|"lsl"|"lsr"|"ld"|"st"|"mov"|"cp"|"jp"|"ltjp"|"gtjp"|"eqjp"|"call"|"ret" +} + +Operand { + Register | Immediate +} + +Register { + "AX" | "BX" | "CX" | "DX" | "EX" | "FX" | "GX" +} + +Immediate { + ImmediateToken +} + +Comment { + CommentToken +} + +Label { + LabelToken +} + +Newline { + NewlineToken +} + +Db { + "db" NumberList +} + +Dw { + "dw" StringList +} + +NumberList { + ImmediateToken ("," ImmediateToken)* +} + +StringList { + StringToken ("," StringToken)* +} + +@tokens { + ImmediateToken { $[0-9]+ } + CommentToken { ";" $[^\n]* } + LabelToken { $[a-zA-Z_]$[a-zA-Z0-9_]* ":" } + StringToken { "'" $[a-zA-Z0-9_]* "'" } + NewlineToken { "\n" } +} \ No newline at end of file diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..2760e58 --- /dev/null +++ b/src/style.css @@ -0,0 +1,28 @@ + +:root{ + color-scheme: light dark; + background-color: rgb(30, 30, 30); + --code-input-flex: 1; + --machine-code-layout-flex: 1; + --memory-layout-flex: 1; + --current-hover-code: -1; +} + +#app { + text-align: center; +} + + +#code>*>h2{ + padding-left: 20px; + white-space: nowrap; + overflow: hidden; +} +#code>*>textarea{ + background-color: rgb(55, 55, 55); + width: 100%; + overflow-y: scroll; + height: 100em; + max-height: 420px; + resize: none; +} \ No newline at end of file diff --git a/src/utils/CodeChecker.ts b/src/utils/CodeChecker.ts new file mode 100644 index 0000000..88e4f96 --- /dev/null +++ b/src/utils/CodeChecker.ts @@ -0,0 +1,50 @@ + +export class Token { + constructor(public content: string, public type: string) {} +} +export class CodeChecker { +/* - 0x00: nop, 0, 0: 无操作 + - 0x01: ldc, n, number: 寄存器n赋值为number + - 0x10: add, n, m: 寄存器n的值加通用寄存器m的值,结果存回寄存器n中 + - 0x11: div, n, m: 寄存器n中的值除以通用寄存器m的值,结果存回寄存器n中,并将余数存入寄存器1 + - 0x12: and, n, m: 寄存器n中的值和寄存器m中的值按位与,结果存回寄存器n中 + - 0x13: or, n, m: 寄存器n中的值和寄存器m中的值按位或,结果存回寄存器n中 + - 0x14: xor, n, m: 寄存器n中的值和寄存器m中的值按位异或,结果存回寄存器n中 + - 0x15: not, n, 0: 寄存器n中的值按位翻转 + - 0x16: lsl, n, m: 寄存器n中的值左移,位数为寄存器m中的值 + - 0x17: lsr, n, m: 寄存器n中的值右移,位数为寄存器m中的值 + - 0x20: ld, n, addr: 将地址addr处的值加载到寄存器n中 + - 0x21: st, n, addr: 将寄存器n中的值保存到地址addr处 + - 0x23: mov, n, m: 将寄存器m中的值复制到寄存器n中 + - 0x30: cp, src, dst: 将地址为src处的数据复制到dst处,复制的字节数为通用寄存器2的值 + - 0x40: jp, 0, k: 无条件跳转到第k条指令 + - 0x41: ltjp, n, k: 如果寄存器2中的值小于寄存器n中的值,则跳转到第k条指令 + - 0x42: gtjp, n, k: 如果寄存器2中的值大于寄存器n中的值,则跳转到第k条指令 + - 0x43: eqjp, n, k: 如果寄存器2中的值等于寄存器n中的值,则跳转到第k条指令 + - 0x50: call, 0, k: 将7个通用寄存器及下一条指令的序号推入栈中,然后跳转到第k条指令 + - 0x51: ret, 0, 0: 如果栈为空,则程序终止;如果栈不为空,则恢复7个通用寄存器的值,跳转到之前存入的第k条指令 +*/ + static KeyWords = ["nop","ldc","add","div","and","or","xor","not","lsl","lsr","ld","st","mov","cp","jp","ltjp","gtjp","eqjp","call","ret"]; + static Registers = ["AX","BX","CX","DX","EX","FX","GX"]; + static highlightCode(code: string): Token[] { + if(code.length === 0) + return []; + let res:string[] = code.split(","); + let ans:Token[] = []; + for(let key of res) + { + const temp = key.trim(); + console.log(temp); + if(this.KeyWords.includes(temp)) + ans.push(new Token(key, "keyword")); + else if(this.Registers.includes(temp)) + ans.push(new Token(key, "register")); + else + ans.push(new Token(key, "normal")); + ans.push(new Token(",", "normal")); + } + ans.pop(); + console.log(ans); + return ans; + } +} \ No newline at end of file diff --git a/src/utils/Complier.ts b/src/utils/Complier.ts new file mode 100644 index 0000000..815217d --- /dev/null +++ b/src/utils/Complier.ts @@ -0,0 +1,217 @@ +import {Byte} from "./MemoryManager.ts"; + +export class CompileError extends Error { + constructor(message: string, index: number) { + super(message); + this.index = index; + } + + index: number; +} + +export class Compiler { + // ["CompileFinished(info)", "CompileError(info,CompileError)"] + // 感觉这里写的不好 类型限制不够 + _events: Map<string, ((arg0: string, arg1?: any) => void)[]> = new Map<string, ((arg0: string, arg1?: any) => void)[]>(); + + AddEventListener(event: string, callback: (arg0: string, arg1?: any) => void) { + if (!this._events.has(event)) + this._events.set(event, [callback]); + else + this._events.get(event)!.push(callback); + } + + Notify(event: string, data?: any) { + if (this._events.has(event)) + if (data === undefined) + this._events.get(event)!.forEach(callback => callback(event)); + else + this._events.get(event)!.forEach(callback => callback(event, data)); + } + + /* + - 0x00: nop, 0, 0: 无操作 + - 0x01: ldc, n, number: 寄存器n赋值为number + - 0x10: add, n, m: 寄存器n的值加通用寄存器m的值,结果存回寄存器n中 + - 0x11: div, n, m: 寄存器n中的值除以通用寄存器m的值,结果存回寄存器n中,并将余数存入寄存器1 + - 0x12: and, n, m: 寄存器n中的值和寄存器m中的值按位与,结果存回寄存器n中 + - 0x13: or, n, m: 寄存器n中的值和寄存器m中的值按位或,结果存回寄存器n中 + - 0x14: xor, n, m: 寄存器n中的值和寄存器m中的值按位异或,结果存回寄存器n中 + - 0x15: not, n, 0: 寄存器n中的值按位翻转 + - 0x16: lsl, n, m: 寄存器n中的值左移,位数为寄存器m中的值 + - 0x17: lsr, n, m: 寄存器n中的值右移,位数为寄存器m中的值 + - 0x20: ld, n, addr: 将地址addr处的值加载到寄存器n中 + - 0x21: st, n, addr: 将寄存器n中的值保存到地址addr处 + - 0x23: mov, n, m: 将寄存器m中的值复制到寄存器n中 + - 0x30: cp, src, dst: 将地址为src处的数据复制到dst处,复制的字节数为通用寄存器2的值 + - 0x40: jp, 0, k: 无条件跳转到第k条指令 + - 0x41: ltjp, n, k: 如果寄存器2中的值小于寄存器n中的值,则跳转到第k条指令 + - 0x42: gtjp, n, k: 如果寄存器2中的值大于寄存器n中的值,则跳转到第k条指令 + - 0x43: eqjp, n, k: 如果寄存器2中的值等于寄存器n中的值,则跳转到第k条指令 + - 0x50: call, 0, k: 将7个通用寄存器及下一条指令的序号推入栈中,然后跳转到第k条指令 + - 0x51: ret, 0, 0: 如果栈为空,则程序终止;如果栈不为空,则恢复7个通用寄存器的值,跳转到之前存入的第k条指令 + */ + static KeyWordsToMachineCode: Map<string, string> = new Map<string, string>([ + ["nop", "0x00"], + ["ldc", "0x01"], + ["add", "0x10"], + ["div", "0x11"], + ["and", "0x12"], + ["or", "0x13"], + ["xor", "0x14"], + ["not", "0x15"], + ["lsl", "0x16"], + ["lsr", "0x17"], + ["ld", "0x20"], + ["st", "0x21"], + ["mov", "0x23"], + ["cp", "0x30"], + ["jp", "0x40"], + ["ltjp", "0x41"], + ["gtjp", "0x42"], + ["eqjp", "0x43"], + ["call", "0x50"], + ["ret", "0x51"] + ]); + static Registers: Map<string, string> = new Map<string, string>([ + ["AX", "01"], + ["BX", "02"], + ["CX", "03"], + ["DX", "04"], + ["EX", "05"], + ["FX", "06"], + ["GX", "07"] + ]) + static font8x8: { [key: string]: number[] } = { + 'A': [0x7E, 0x11, 0x11, 0x7E, 0x11, 0x11, 0x11, 0x00], + 'B': [0x7C, 0x12, 0x12, 0x7C, 0x12, 0x12, 0x7C, 0x00], + 'C': [0x3E, 0x41, 0x40, 0x40, 0x40, 0x41, 0x3E, 0x00], + 'D': [0x7C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7C, 0x00], + 'E': [0x7F, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x7F, 0x00], + 'F': [0x7F, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00], + 'G': [0x3E, 0x41, 0x40, 0x4F, 0x41, 0x41, 0x3E, 0x00], + 'H': [0x41, 0x41, 0x41, 0x7F, 0x41, 0x41, 0x41, 0x00], + 'I': [0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00], + 'J': [0x0F, 0x02, 0x02, 0x02, 0x02, 0x42, 0x3C, 0x00], + 'K': [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11, 0x00], + 'L': [0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7F, 0x00], + 'M': [0x41, 0x63, 0x55, 0x49, 0x41, 0x41, 0x41, 0x00], + 'N': [0x41, 0x61, 0x51, 0x49, 0x45, 0x43, 0x41, 0x00], + 'O': [0x3E, 0x41, 0x41, 0x41, 0x41, 0x41, 0x3E, 0x00], + 'P': [0x7E, 0x11, 0x11, 0x7E, 0x40, 0x40, 0x40, 0x00], + 'Q': [0x3E, 0x41, 0x41, 0x41, 0x45, 0x42, 0x3D, 0x00], + 'R': [0x7E, 0x41, 0x41, 0x7E, 0x44, 0x42, 0x41, 0x00], + 'S': [0x3E, 0x41, 0x40, 0x3E, 0x01, 0x41, 0x3E, 0x00], + 'T': [0x7F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00], + 'U': [0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x3E, 0x00], + 'V': [0x41, 0x41, 0x41, 0x41, 0x22, 0x14, 0x08, 0x00], + 'W': [0x41, 0x41, 0x41, 0x49, 0x55, 0x63, 0x41, 0x00], + 'X': [0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x00], + 'Y': [0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00], + 'Z': [0x7F, 0x02, 0x04, 0x08, 0x10, 0x20, 0x7F, 0x00], + '0': [0x3E, 0x41, 0x43, 0x45, 0x49, 0x51, 0x3E, 0x00], + '1': [0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x3E, 0x00], + '2': [0x3E, 0x41, 0x01, 0x3E, 0x40, 0x40, 0x7F, 0x00], + '3': [0x3E, 0x41, 0x01, 0x1E, 0x01, 0x41, 0x3E, 0x00], + '4': [0x10, 0x30, 0x50, 0x90, 0x7F, 0x10, 0x10, 0x00], + '5': [0x7F, 0x40, 0x7E, 0x01, 0x01, 0x41, 0x3E, 0x00], + '6': [0x3E, 0x40, 0x7E, 0x41, 0x41, 0x41, 0x3E, 0x00], + '7': [0x7F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00], + '8': [0x3E, 0x41, 0x41, 0x3E, 0x41, 0x41, 0x3E, 0x00], + '9': [0x3E, 0x41, 0x41, 0x3F, 0x01, 0x41, 0x3E, 0x00], + '+': [0x00, 0x08, 0x08, 0x7F, 0x08, 0x08, 0x00, 0x00], + '-': [0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00], + 'x': [0x00, 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41], + '/': [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00], + ' ': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + }; + Code: string = ""; + CodeChanged: boolean = true; + PCToIndex: Map<number, number> = new Map<number, number>(); + PCToCode: Map<number, string> = new Map<number, string>(); + PCToMachineCode: Map<number, string> = new Map<number, string>(); + Labels: Map<string, number> = new Map<string, number>(); + MemorySet: Byte[] = []; + + Clear() { + this.PCToIndex.clear(); + this.PCToCode.clear(); + this.PCToMachineCode.clear(); + this.Labels.clear(); + this.MemorySet = []; + } + + CompileCode(fullCode: string = this.Code) { + this.Clear(); + this.CodeChanged = false; + try { + fullCode.split("\n").forEach((line, index) => { + //code -> a: b ; c + let pc = this.PCToCode.size; + let labelAndCode = (line.includes(";") ? line.slice(0, line.indexOf(";")) : line).split(":"); + let code = ""; + if (labelAndCode.length === 2) { + if (this.Labels.has(labelAndCode[0].trim())) + throw new Error("Duplicate label"); + this.Labels.set(labelAndCode[0].trim(), pc); + code = labelAndCode[1].trim(); + } else if (labelAndCode.length === 1) + code = labelAndCode[0].trim(); + else + throw new CompileError("Invalid code", index); + if (code === "") + return; + if (code.startsWith("db")) { + if (labelAndCode.length === 1) + throw new CompileError("db must start with a label.", index); + this.Labels.set(labelAndCode[0].trim(), this.MemorySet.length + 128); + code.slice(2).split(",").forEach(val => { + let num = val.toUpperCase().endsWith('H') ? parseInt(val, 16) : parseInt(val); + if (isNaN(num) || num < 0 || num > 255) + throw new CompileError("Invalid number", index); + this.MemorySet.push(new Byte(num)); + }); + return; + } else if (code.startsWith("dw")) { + if (labelAndCode.length === 1) + throw new CompileError("dw must start with a label.", index); + this.Labels.set(labelAndCode[0].trim(), this.MemorySet.length + 128); + code.slice(3).toUpperCase().split(",").forEach(val => { + let str = val.slice(1, -1); + for (let c of str) { + if (!(c in Compiler.font8x8)) + throw new CompileError("Invalid char", index); + Compiler.font8x8[c].forEach(byte => this.MemorySet.push(new Byte(byte))); + } + }); + return; + } + this.PCToCode.set(pc, code); + this.PCToIndex.set(pc, index); + }); + console.log(this.Labels); + this.PCToCode.forEach((code, pc) => { + let index = this.PCToIndex.get(pc)!; + let mnemonicAndVals = code.split(/[\s,]+/); + if (mnemonicAndVals.length !== 3) + throw new CompileError("Invalid code", index); + if (!Compiler.KeyWordsToMachineCode.has(mnemonicAndVals[0])) + throw new CompileError("Invalid mnemonic", index); + for (let i = 1; i <= 2; i++) + if ((Compiler.Registers.has(mnemonicAndVals[i]))) + mnemonicAndVals[i] = Compiler.Registers.get(mnemonicAndVals[i])!; + else if(this.Labels.has(mnemonicAndVals[i])) + mnemonicAndVals[i] = this.Labels.get(mnemonicAndVals[i])!.toString(16).padStart(2,'0'); + else + mnemonicAndVals[i] = parseInt(mnemonicAndVals[i]).toString(16).padStart(2,'0'); + this.PCToMachineCode.set(pc, Compiler.KeyWordsToMachineCode.get(mnemonicAndVals[0])! + mnemonicAndVals[1] + mnemonicAndVals[2]); + }); + } catch (e) { + if (e instanceof CompileError) + this.Notify("CompileError", e); + throw e; + } + this.Notify("CompileFinished"); + } + +} \ No newline at end of file diff --git a/src/utils/MemoryManager.ts b/src/utils/MemoryManager.ts new file mode 100644 index 0000000..32112e7 --- /dev/null +++ b/src/utils/MemoryManager.ts @@ -0,0 +1,166 @@ +import {ref, Ref} from "vue"; + +export class Byte { + value: boolean[] + + constructor(); + constructor(value: boolean[]); + constructor(value: number); + constructor(value: Byte); + constructor(value?: boolean[] | number | Byte) { + if (value) { + if(value instanceof Byte) + { + this.value = value.value.slice(); + return; + } + else if (typeof value === 'number') { + if (value < 0 || value >= 256 || !Number.isInteger(value)) + throw new Error("Invalid argument"); + this.value = Array(8).fill(false); + for (let i = 0; i < 8; i++) { + this.value[i] = (value & (1 << i)) !== 0; + } + } else if (value.length === 8) + this.value = value; + else + throw new Error("Invalid argument"); + } else + this.value = Array(8).fill(false); + } + + SetValue(num: number | string | Byte) { + if(num instanceof Byte) + { + this.value = num.value.slice(); + return; + } + if (typeof num === 'string') { + num = parseInt(num); + } + if (num < 0 || num >= 256) + throw new Error("Invalid argument"); + this.value = Array(8).fill(false); + for (let i = 0; i < 8; i++) { + this.value[i] = (num & (1 << i)) !== 0; + } + } + + GetValue(format: number = 10): number | string { + if (format === 10) + return this.value.reduce((acc, val, index) => acc + (val ? 2 ** index : 0), 0); + if (format === 16) + return this.value.reduce((acc, val, index) => acc + (val ? 2 ** index : 0), 0).toString(16).padStart(2, '0'); + throw new Error("Invalid argument"); + } + + Copy(){ + return new Byte(this); + } + + //ignore carry + Add(b: Byte) { + return new Byte(((this.GetValue() as number) + (b.GetValue() as number)) % 256); + } + + //ignore carry + AddAndAssign(b: Byte) { + this.SetValue(((this.GetValue() as number) + (b.GetValue() as number)) % 256); + return this; + } + + Sub(b: Byte) { + if (this.GetValue() < b.GetValue()) + return new Byte(((this.GetValue() as number) + 256 - (b.GetValue() as number)) % 256); + return new Byte(((this.GetValue() as number) - (b.GetValue() as number)) % 256); + } + + SubAndAssign(b: Byte) { + if (this.GetValue() < b.GetValue()) { + this.SetValue(((this.GetValue() as number) + 256 - (b.GetValue() as number)) % 256); + return this + } + this.SetValue(((this.GetValue() as number) - (b.GetValue() as number)) % 256); + return this; + } + And(b: Byte) { + return new Byte(this.value.map((val, index) => val && b.value[index])); + } + AndAndAssign(b: Byte) { + this.value = this.value.map((val, index) => val && b.value[index]); + return this; + } + Or(b: Byte) { + return new Byte(this.value.map((val, index) => val || b.value[index])); + } + OrAndAssign(b: Byte) { + this.value = this.value.map((val, index) => val || b.value[index]); + return this; + } + Xor(b: Byte) { + return new Byte(this.value.map((val, index) => val !== b.value[index])); + } + XorAndAssign(b: Byte) { + this.value = this.value.map((val, index) => val !== b.value[index]); + return this; + } + Not() { + return new Byte(this.value.map(val => !val)); + } + NotAndAssign() { + this.value = this.value.map(val => !val); + return this; + } + Lsl(b: Byte) { + return new Byte(this.value.slice(b.GetValue() as number).concat(Array(b.GetValue() as number).fill(false))); + } + LslAndAssign(b: Byte) { + this.value = this.value.slice(b.GetValue() as number).concat(Array(b.GetValue() as number).fill(false)); + return this; + } + Lsr(b: Byte) { + return new Byte(Array(b.GetValue() as number).fill(false).concat(this.value.slice(0, 8 - (b.GetValue() as number)))); + } + LsrAndAssign(b: Byte) { + this.value = Array(b.GetValue() as number).fill(false).concat(this.value.slice(0, 8 - (b.GetValue() as number))); + return this; + } +} + +export class MemoryManager { + screenMemory: Ref<Byte[][]>; + memory: Ref<Byte[]>; + + constructor() { + this.screenMemory = ref(Array.from({length: 16}, () => Array.from({length: 8}, () => new Byte(255)))); + this.memory = ref(Array(128).fill(new Byte(0))); + } + + clear() { + for (let t of this.screenMemory.value) + t.forEach(val => val.SetValue(0)); + this.memory.value.forEach(val => val.SetValue(0)); + } + + GetVal(t:number) + { + if(t>=128) + return this.memory.value[t-128]; + else + return this.screenMemory.value[Math.floor(t/8)][t%8]; + } + SetVal(t:number, val:Byte) + { + if(t>=128) + this.memory.value[t-128] = new Byte(val); + else + this.screenMemory.value[Math.floor(t/8)][t%8] = new Byte(val); + } + + SetMemSet(memorySet: Byte[]) { + if(memorySet.length > 128) + throw new Error("No enough space"); + for(let i = 0;i<memorySet.length;i++) + this.memory.value[i] = memorySet[i]; + } +} \ No newline at end of file diff --git a/src/utils/Runner.ts b/src/utils/Runner.ts new file mode 100644 index 0000000..1f74a5a --- /dev/null +++ b/src/utils/Runner.ts @@ -0,0 +1,374 @@ +import {MemoryManager, Byte} from "./MemoryManager"; +import {Compiler} from "./Complier.ts"; + +export enum RunnerState { + Stop, + Running, + Step +} + +export class Runner { + // 与Compiler 类似的事件机制 要是再来一个我就把这段逻辑单独抽出来 + //[PCChanged,RegistersChanged] + _events: Map<string, ((arg0: string, arg1?: any) => void)[]> = new Map<string, ((arg0: string, arg1?: any) => void)[]>(); + + AddEventListener(event: string, callback: (arg0: string, arg1?: any) => void) { + if (!this._events.has(event)) + this._events.set(event, [callback]); + else + this._events.get(event)!.push(callback); + } + + Notify(event: string, data?: any) { + if (this._events.has(event)) + if (data === undefined) + this._events.get(event)!.forEach(callback => callback(event)); + else + this._events.get(event)!.forEach(callback => callback(event, data)); + } + + State: RunnerState = RunnerState.Stop; + _processor: Processor; + _memory: MemoryManager; + _processCounter: number = 0; + _compiler: Compiler; + _stack: [Byte[], number][] = []; + _intervalId: NodeJS.Timeout | null = null; + + StartInterval() { + if (this._intervalId === null) + this._intervalId = setInterval(() => { + if (this._processCounter >= this._compiler.PCToCode.size) { + this.Stop(); + return; + } + this.RunOneLineCode(); + }, 20); + } + + StopInterval() { + if (this._intervalId !== null) { + clearInterval(this._intervalId); + this._intervalId = null; + } + } + + constructor(memoryManager: MemoryManager, compiler: Compiler) { + this._memory = memoryManager + this._processor = new Processor(); + this._compiler = compiler; + compiler.AddEventListener("CompileFinished", (_) => { + this._memory.SetMemSet(compiler.MemorySet) + }); + // Bind methods to the instance + this.GetMemory = this.GetMemory.bind(this); + this.SetMemory = this.SetMemory.bind(this); + this.SetPC = this.SetPC.bind(this); + this.SaveEnv = this.SaveEnv.bind(this); + this.RestoreEnv = this.RestoreEnv.bind(this); + } + + CommandParsing(): [string, number | string, number | string] { + let code = ""; + if (this._compiler.PCToCode.has(this._processCounter)) + code = this._compiler.PCToCode.get(this._processCounter) as string; + else + throw new Error("PC out of range"); + this._processCounter++; + let mnemonicAndVals = code.split(/[\s,]+/); + // 如果指令不合法 Compiler应该会有异常抛出 则不能执行到这里 + if (mnemonicAndVals.length !== 3) + throw new Error("Invalid code"); + let mnemonic = mnemonicAndVals[0]; + function getVal(runner:Runner, val: string) { + if (runner._processor._registers.has(val)) + return val; + else if(runner._compiler.Labels.has(val)) + return runner._compiler.Labels.get(val) as number; + else { + let t = parseInt(val); + if(isNaN(t)) + throw new Error("Invalid argument"); + return t; + } + } + return [mnemonic, getVal(this,mnemonicAndVals[1]), getVal(this,mnemonicAndVals[2])]; + } + + RunOneLineCode() { + this._processor.RunCode(...this.CommandParsing(), this.GetMemory, this.SetMemory, this.SetPC, this.SaveEnv, this.RestoreEnv); + this.Notify("PCChanged"); + this.Notify("RegistersChanged"); + } + + Init() { + this._memory.clear(); + this._compiler.CompileCode(); + this._processCounter = 0; + } + + Run() { + this.State = RunnerState.Running; + this.Init(); + this.StartInterval(); + } + + Resume() { + this.State = RunnerState.Running; + this.StartInterval(); + } + + Step() { + if (this._processCounter >= this._compiler.PCToCode.size) + return; + if (this.State === RunnerState.Running) { + this.Stop(); + } + this.State = RunnerState.Step; + this.RunOneLineCode() + } + + Stop() { + this.State = RunnerState.Stop; + this.StopInterval() + } + + Refresh() { + this.Run(); + } + + GetMemory(t: number): Byte { + console.log(this._memory) + return this._memory.GetVal(t); + } + + SetMemory(t: number, val: Byte): void { + console.log("mem Test:") + console.log(this) + console.log(this._memory) + + this._memory.SetVal(t, val); + } + + SaveEnv() { + if (this._stack.length > 8) + throw new Error("Stack overflow"); + this._stack.push([this._processor.GetRegisters().map(x=>x.Copy()), this._processCounter]); + } + + RestoreEnv() { + if (this._stack.length === 0) { + this.Stop(); + return; + } + let [regs, pc] = this._stack.pop()!; + console.log('restore',regs); + this._processor.SetRegisters(regs); + this._processCounter = pc; + } + + SetPC(addr: number) { + this._processCounter = addr; + console.log("PC set to", addr); + } + + GetRegisters(): Byte[] { + return this._processor.GetRegisters(); + } + + GetPC(): number { + return this._processCounter; + } +} + +class Processor { + _registers: Map<string, Byte>; + + constructor() { + this._registers = new Map<string, Byte>([ + ["AX", new Byte()], + ["BX", new Byte()], + ["CX", new Byte()], + ["DX", new Byte()], + ["EX", new Byte()], + ["FX", new Byte()], + ["GX", new Byte()] + ]); + } + +// static KeyWords = ["nop","ldc","add","div","and","or","xor","not","lsl","lsr","ld","st","mov","cp","jp","ltjp","gtjp","eqjp","call","ret"]; +// static Registers = ["AX","BX","CX","DX","EX","FX","GX"]; + GetRegister(register: string | number): Byte { + if (this._registers.has(register as string)) + return this._registers.get(register as string)!; + else + throw new Error("Invalid register"); + } + + GetRegisters(): Byte[] { + console.log("Get", this._registers.values()); + return Array.from(this._registers.values()); + } + + SetRegisters(registers: Byte[]) { + for (let i = 0; i < 7; i++) { + console.log("Set", String.fromCharCode('A'.charCodeAt(0) + i) + 'X',registers[i].value); + this._registers.get(String.fromCharCode('A'.charCodeAt(0) + i) + 'X')!.SetValue(registers[i]); + } + } + + GetRegisterValue(register: string | number): number { + return this.GetRegister(register).GetValue() as number; + } + + SetRegisterValue(register: string | number, value: number) { + this.GetRegister(register).SetValue(value); + } + + InRegister(register: string | number): boolean { + return typeof register === 'string' && this._registers.has(register); + } + + RunCode(mnemonic: string, operandA: number | string, operandB: number | string, getMemory: (addr: number) => Byte, setMemory: (addr: number, value: Byte) => void, setPC: (addr: number) => void, saveEnv: () => void, restoreEnv: () => void) { + console.log(mnemonic, operandA, operandB); + if(this.InRegister(operandA)) + console.log(this.GetRegisterValue(operandA)); + if(this.InRegister(operandB)) + console.log(this.GetRegisterValue(operandB)); + switch (mnemonic) { + case "nop": + break; + case "ldc": + if (this.InRegister(operandA) && typeof operandB === 'number') { + this.GetRegister(operandA).SetValue(operandB); + return; + } + break; + case "add": + if (this.InRegister(operandA) && this.InRegister(operandB)) { + this.GetRegister(operandA).AddAndAssign(this._registers.get(operandB as string)!); + return; + } + break; + case "div": + if (this.InRegister(operandA) && this.InRegister(operandB)) { + let a = this.GetRegisterValue(operandA), b = this.GetRegisterValue(operandB); + this.SetRegisterValue(operandA, Math.floor(a / b)); + this.SetRegisterValue("AX", a % b); + return; + } + break; + case "and": + if (this.InRegister(operandA) && this.InRegister(operandB)) { + this.GetRegister(operandA).AndAndAssign(this.GetRegister(operandB)); + return; + } + break; + case "or": + if (this.InRegister(operandA) && this.InRegister(operandB)) { + this.GetRegister(operandA).OrAndAssign(this.GetRegister(operandB)); + return; + } + break; + case "xor": + if (this.InRegister(operandA) && this.InRegister(operandB)) { + this.GetRegister(operandA).XorAndAssign(this.GetRegister(operandB)); + return; + } + break; + case "not": + if (this.InRegister(operandA) && operandB === 0) { + this.GetRegister(operandA).NotAndAssign(); + return; + } + break; + case "lsl": + if (this.InRegister(operandA) && this.InRegister(operandB)) { + this.GetRegister(operandA).LslAndAssign(this.GetRegister(operandB)); + return; + } + break; + case "lsr": + if (this.InRegister(operandA) && this.InRegister(operandB)) { + this.GetRegister(operandA).LsrAndAssign(this.GetRegister(operandB)); + return; + } + break; + case "ld": + if (this.InRegister(operandA) && typeof operandB === 'number') { + this.GetRegister(operandA).SetValue(getMemory(operandB as number)); + return; + } + break; + case "st": + console.log(operandA, operandB); + if (this.InRegister(operandA) && typeof operandB === 'number') { + setMemory(operandB as number, this.GetRegister(operandA)); + return; + } + break; + case "mov": + if (this.InRegister(operandA) && this.InRegister(operandB)) { + this.GetRegister(operandA).SetValue(this.GetRegister(operandB)); + return; + } + else if(this.InRegister(operandA) && typeof operandB === 'number') { + this.GetRegister(operandA).SetValue(operandB); + return; + } + break; + case "cp": + console.log(operandA, operandB); + operandA = this.InRegister(operandA) ? this.GetRegisterValue(operandA) : operandA; + operandB = this.InRegister(operandB) ? this.GetRegisterValue(operandB) : operandB; + if (typeof operandA === 'number' && typeof operandB === 'number') { + console.log(operandA, operandB); + for (let i = 0; i < (this._registers.get("BX")!.GetValue() as number); i++) + setMemory(operandB + i, getMemory(operandA + i)); + return; + } + break; + case "jp": + if (typeof operandA === 'number' && typeof operandB === 'number' && operandA === 0) { + setPC(operandB as number); + return; + } + break; + case "ltjp": + if (this.InRegister(operandA) && typeof operandB === 'number') { + if (this.GetRegisterValue("BX") < this.GetRegisterValue(operandA)) + setPC(operandB as number); + return; + } + break; + case "gtjp": + if (this.InRegister(operandA) && typeof operandB === 'number') { + if (this.GetRegisterValue("BX") > this.GetRegisterValue(operandA)) + setPC(operandB as number); + return; + } + break; + case "eqjp": + if (this.InRegister(operandA) && typeof operandB === 'number') { + if (this.GetRegisterValue("BX") === this.GetRegisterValue(operandA)) + setPC(operandB as number); + return; + } + break; + case "call": + if (typeof operandA === 'number' && typeof operandB === 'number' && operandA === 0) { + saveEnv(); + setPC(operandB as number); + return; + } + break; + case "ret": + if (typeof operandA === 'number' && typeof operandB === 'number' && operandA === 0 && operandB === 0) { + restoreEnv(); + return; + } + break + } + throw new Error("Invalid argument"); + } +} diff --git a/src/utils/parser.js b/src/utils/parser.js new file mode 100644 index 0000000..04710e5 --- /dev/null +++ b/src/utils/parser.js @@ -0,0 +1,16 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +import {LRParser} from "@lezer/lr" +export const parser = LRParser.deserialize({ + version: 14, + states: "'OQQOPOOOOOO'#C_'#C_OOOO'#Ca'#CaOOOO'#Cf'#CfO!hOQO'#C^O!uOQO'#C^O#aOPO'#C^OOOO'#Co'#CoQQOPOOOOOO'#Ch'#ChO#fOPO'#CjO#kOPO'#ClO!uOQO,58xOOOO,58x,58xO#aOPO,58xO#pOPO,58xOOOO'#Cc'#CcOOOO'#Cd'#CdOOOO'#Cb'#CbO#xOPO,58xOOOO-E6m-E6mO#}OPO'#CkOOOO,59U,59UO$YOPO'#CmOOOO,59W,59WO$eOPO1G.dOOOO1G.d1G.dO#aOPO1G.dO!uOQO1G.dO$jOPO'#CpO$oOPO,59VO$zOPO'#CqO%POPO,59XO!uOQO7+$OOOOO7+$O7+$OO#pOPO7+$OOOOO,59[,59[OOOO-E6n-E6nOOOO,59],59]OOOO-E6o-E6oO#pOPO<<GjOOOO<<Gj<<GjO#aOPO<<GjOOOOAN=UAN=UO#aOPOAN=UOOOOG22pG22p", + stateData: "%[~OSPOZROgQOhQOiQOjQOkQOlQOmQOnQOoQOpQOqQOrQOsQOtQOuQOvQOwQOxQOyQOzQO~O]XO!TYO!UZO~PTOXaO{`O|`O}`O!O`O!P`O!Q`O!R`O~O]XO~OXeO~ObgO~OZRO]XO~O!SlO~O!SmOZ_X]_X~O!SoOZaX]aX~O!SqO~OXtO~O!SmOZ_a]_a~ObvO~O!SoOZaa]aa~O", + goto: "#lfPPgkPov!S!SP!YP!jP#P#S#P#VP#Y#`#fTVOWTSOWSTOWR[SQcTQi[QslRxqXbT[lqSUOWQ^SQk_QzsR|xS]SUSj^_QrkQysS{xzR}|R_SRfYRhZQWORdWQneRunQpgRwp", + nodeNames: "⚠ Program Statement Label LabelToken Mnemonic Operand Register Immediate ImmediateToken Comment CommentToken Newline NewlineToken Db NumberList Dw StringList StringToken", + maxTerm: 52, + skippedNodes: [0], + repeatNodeCount: 3, + tokenData: "E`~RrYZ#]wx#b|}#y!Q![$O!]!^$W!c!d$c!d!e%x!e!f&v!f!g't!g!h(r!h!i)p!i!j*n!j!}${#R#S${#T#U+l#U#V${#V#W.W#W#X0o#X#Y3]#Y#Z${#Z#[5]#[#^${#^#_7]#_#`${#`#a8Z#a#b<|#b#c>d#c#d@f#d#f${#f#gAd#g#hBz#h#l${#l#mCx#m#o${~#bO]~~#eTwx#t!Q![#b!c!}#b#R#S#b#T#o#b~#yOb~~$OO!S~~$TPX~!Q![$O~$]QZ~YZ$W#Q#R$WR$fV!Q![${![!]%_!c!z${!z!{%d!{!}${#R#S${#T#o${P%OT!Q![${![!]%_!c!}${#R#S${#T#o${P%dOSPR%iT{Q!Q![${![!]%_!c!}${#R#S${#T#o${R%{V!Q![${![!]%_!c!z${!z!{&b!{!}${#R#S${#T#o${R&gT|Q!Q![${![!]%_!c!}${#R#S${#T#o${R&yV!Q![${![!]%_!c!z${!z!{'`!{!}${#R#S${#T#o${R'eT}Q!Q![${![!]%_!c!}${#R#S${#T#o${R'wV!Q![${![!]%_!c!z${!z!{(^!{!}${#R#S${#T#o${R(cT!OQ!Q![${![!]%_!c!}${#R#S${#T#o${R(uV!Q![${![!]%_!c!z${!z!{)[!{!}${#R#S${#T#o${R)aT!PQ!Q![${![!]%_!c!}${#R#S${#T#o${R)sV!Q![${![!]%_!c!z${!z!{*Y!{!}${#R#S${#T#o${R*_T!QQ!Q![${![!]%_!c!}${#R#S${#T#o${R*qV!Q![${![!]%_!c!z${!z!{+W!{!}${#R#S${#T#o${R+]T!RQ!Q![${![!]%_!c!}${#R#S${#T#o${~+oX!Q![${![!]%_!c!}${#R#S${#T#W${#W#X,[#X#b${#b#c-Y#c#o${~,_V!Q![${![!]%_!c!}${#R#S${#T#W${#W#X,t#X#o${~,yTi~!Q![${![!]%_!c!}${#R#S${#T#o${~-]V!Q![${![!]%_!c!}${#R#S${#T#W${#W#X-r#X#o${~-wTk~!Q![${![!]%_!c!}${#R#S${#T#o${~.ZW!Q![${![!]%_!c!}${#R#S${#T#U.s#U#d${#d#e0Z#e#o${~.vV!Q![${![!]%_!c!}${#R#S${#T#`${#`#a/]#a#o${~/`V!Q![${![!]%_!c!}${#R#S${#T#`${#`#a/u#a#o${~/zTy~!Q![${![!]%_!c!}${#R#S${#T#o${~0`Tt~!Q![${![!]%_!c!}${#R#S${#T#o${~0rZ!Q![${![!]%_!c!}${#R#S${#T#U${#U#V1e#V#]${#]#^1y#^#k${#k#l2w#l#o${R1jT!TQ!Q![${![!]%_!c!}${#R#S${#T#o${~1|V!Q![${![!]%_!c!}${#R#S${#T#j${#j#k2c#k#o${~2hTj~!Q![${![!]%_!c!}${#R#S${#T#o${R2|T!UQ!Q![${![!]%_!c!}${#R#S${#T#o${~3`V!Q![${![!]%_!c!}${#R#S${#T#e${#e#f3u#f#o${~3xV!Q![${![!]%_!c!}${#R#S${#T#^${#^#_4_#_#o${~4bV!Q![${![!]%_!c!}${#R#S${#T#d${#d#e4w#e#o${~4|Tx~!Q![${![!]%_!c!}${#R#S${#T#o${~5`V!Q![${![!]%_!c!}${#R#S${#T#h${#h#i5u#i#o${~5xV!Q![${![!]%_!c!}${#R#S${#T#^${#^#_6_#_#o${~6bV!Q![${![!]%_!c!}${#R#S${#T#d${#d#e6w#e#o${~6|Tw~!Q![${![!]%_!c!}${#R#S${#T#o${~7`V!Q![${![!]%_!c!}${#R#S${#T#d${#d#e7u#e#o${~7zTu~!Q![${![!]%_!c!}${#R#S${#T#o${~8^Y!Q![${![!]%_!c!}${#R#S${#T#W${#W#X8|#X#g${#g#h9|#h#i;f#i#o${~9RVq~!Q![${![!]%_!c!}${#R#S${#T#V${#V#W9h#W#o${~9mTh~!Q![${![!]%_!c!}${#R#S${#T#o${~:PX!Q![${![!]%_!c!}${#R#S${#T#`${#`#a:l#a#f${#f#g;Q#g#o${~:qTo~!Q![${![!]%_!c!}${#R#S${#T#o${~;VTp~!Q![${![!]%_!c!}${#R#S${#T#o${~;iV!Q![${![!]%_!c!}${#R#S${#T#^${#^#_<O#_#o${~<RV!Q![${![!]%_!c!}${#R#S${#T#d${#d#e<h#e#o${~<mTv~!Q![${![!]%_!c!}${#R#S${#T#o${~=PV!Q![${![!]%_!c!}${#R#S${#T#c${#c#d=f#d#o${~=iV!Q![${![!]%_!c!}${#R#S${#T#j${#j#k>O#k#o${~>TTs~!Q![${![!]%_!c!}${#R#S${#T#o${~>gV!Q![${![!]%_!c!}${#R#S${#T#c${#c#d>|#d#o${~?PX!Q![${![!]%_!c!}${#R#S${#T#d${#d#e?l#e#h${#h#i@Q#i#o${~?qTg~!Q![${![!]%_!c!}${#R#S${#T#o${~@VTn~!Q![${![!]%_!c!}${#R#S${#T#o${~@iV!Q![${![!]%_!c!}${#R#S${#T#f${#f#gAO#g#o${~ATTl~!Q![${![!]%_!c!}${#R#S${#T#o${~AgV!Q![${![!]%_!c!}${#R#S${#T#X${#X#YA|#Y#o${~BPV!Q![${![!]%_!c!}${#R#S${#T#h${#h#iBf#i#o${~BkTz~!Q![${![!]%_!c!}${#R#S${#T#o${~B}V!Q![${![!]%_!c!}${#R#S${#T#h${#h#iCd#i#o${~CiTr~!Q![${![!]%_!c!}${#R#S${#T#o${~C{V!Q![${![!]%_!c!}${#R#S${#T#c${#c#dDb#d#o${~DeV!Q![${![!]%_!c!}${#R#S${#T#f${#f#gDz#g#o${~EPTm~!Q![${![!]%_!c!}${#R#S${#T#o${", + tokenizers: [0, 1], + topRules: {"Program":[0,1]}, + tokenPrec: 0 +}) diff --git a/src/utils/parser.terms.js b/src/utils/parser.terms.js new file mode 100644 index 0000000..0f7b867 --- /dev/null +++ b/src/utils/parser.terms.js @@ -0,0 +1,20 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +export const + Program = 1, + Statement = 2, + Label = 3, + LabelToken = 4, + Mnemonic = 5, + Operand = 6, + Register = 7, + Immediate = 8, + ImmediateToken = 9, + Comment = 10, + CommentToken = 11, + Newline = 12, + NewlineToken = 13, + Db = 14, + NumberList = 15, + Dw = 16, + StringList = 17, + StringToken = 18 diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..6af53ad --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,6 @@ +/// <reference types="vite/client" /> +declare module '*.vue' { + import { ComponentOptions } from 'vue' + const componentOptions: ComponentOptions + export default componentOptions +} \ No newline at end of file diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..c692b24 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "allowSyntheticDefaultImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..abcd7f0 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..bbcf80c --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [vue()], +})