diff --git a/.vitepress/pages/Playground.vue b/.vitepress/pages/Playground.vue index 012f52b..2e82ba5 100644 --- a/.vitepress/pages/Playground.vue +++ b/.vitepress/pages/Playground.vue @@ -2,8 +2,14 @@
-
Playground (v{{ AISCRIPT_VERSION }})
-
+
Playground (v{{ runner?.version ?? "???" }})
+
+ +
@@ -83,7 +89,6 @@ @@ -420,8 +421,10 @@ onUnmounted(() => { .playgroundHeaderInner { margin: 0 auto; - padding: 0.5em 36px; + padding: 0 36px; + min-height: 40px; display: flex; + align-items: center; } .playgroundOptions { @@ -629,6 +632,28 @@ onUnmounted(() => { background-color: var(--vp-button-brand-hover-bg); } +.playgroundSelect { + background-color: var(--vp-button-alt-bg); + transition: background-color 0.25s; + padding: 3px 36px 3px 16px; + border-radius: 8px; + font-family: var(--vp-font-family-base); + font-size: 80%; + + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right .75em center; + background-size: 16px 12px; +} + +:global(html.dark) .playgroundSelect { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23fffff5db' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); +} + +.playgroundSelect:hover { + background-color: var(--vp-button-alt-hover-bg); +} + @media (max-width: 768px) { .playgroundEditorScroller, .playgroundEditorTextarea { @@ -636,7 +661,7 @@ onUnmounted(() => { } .playgroundHeaderInner { - padding: 0.5em 24px; + padding: 0 24px; } .playgroundResultActionsLeft { diff --git a/.vitepress/scripts/runner.ts b/.vitepress/scripts/runner.ts new file mode 100644 index 0000000..04bec34 --- /dev/null +++ b/.vitepress/scripts/runner.ts @@ -0,0 +1,16 @@ +export abstract class Runner { + abstract version: string; + + protected print: (text: string) => void; + constructor({ print }: { + print(text: string): void; + }) { + this.print = print; + } + + abstract parse(code: string): readonly [unknown, Map | undefined]; + abstract exec(node: unknown): Promise; + abstract isAiScriptError(error: unknown): error is Error; + abstract getErrorName(error: Error): string | undefined; + abstract dispose(): void; +} diff --git a/.vitepress/scripts/versions/0.14.1.ts b/.vitepress/scripts/versions/0.14.1.ts new file mode 100644 index 0000000..b36d23e --- /dev/null +++ b/.vitepress/scripts/versions/0.14.1.ts @@ -0,0 +1,51 @@ +import { Parser, Interpreter, utils, errors, type Ast, values } from 'aiscript0_14'; +import { Runner } from '../runner'; + +export default class extends Runner { + version = '0.14.1'; + + parse(code: string) { + const ast = Parser.parse(code); + const metadata = Interpreter.collectMetadata(ast); + return [ast, metadata] as const; + } + + private interpreter = new Interpreter({}, { + out: (value: values.Value) => { + this.print( + value.type === 'num' ? value.value.toString() + : value.type === 'str' ? `"${value.value}"` + : JSON.stringify(utils.valToJs(value), null, 2) ?? '', + ); + }, + log: (type: string, params: { val?: values.Value }) => { + if (type === 'end' && params.val != null && 'type' in params.val) { + this.print(utils.valToString(params.val, true)); + } + }, + }); + async exec(node: unknown): Promise { + await this.interpreter.exec(node as Ast.Node[]); + } + isAiScriptError(error: unknown): error is errors.AiScriptError { + return error instanceof errors.AiScriptError; + } + getErrorName(error: errors.AiScriptError): string | undefined { + if (error instanceof errors.SyntaxError) { + return 'SyntaxError'; + } + if (error instanceof errors.TypeError) { + return 'TypeError'; + } + if (error instanceof errors.RuntimeError) { + return 'RuntimeError'; + } + if (error instanceof errors.IndexOutOfRangeError) { + return 'IndexOutOfRangeError'; + } + return 'AiScriptError'; + } + dispose() { + this.interpreter.abort(); + } +} diff --git a/.vitepress/scripts/versions/0.15.0.ts b/.vitepress/scripts/versions/0.15.0.ts new file mode 100644 index 0000000..5ed56e2 --- /dev/null +++ b/.vitepress/scripts/versions/0.15.0.ts @@ -0,0 +1,51 @@ +import { Parser, Interpreter, values, utils, errors, type Ast } from 'aiscript0_15'; +import { Runner } from '../runner'; + +export default class extends Runner { + version = '0.15.0'; + + parse(code: string) { + const ast = Parser.parse(code); + const metadata = Interpreter.collectMetadata(ast); + return [ast, metadata] as const; + } + + private interpreter = new Interpreter({}, { + out: (value: values.Value) => { + this.print( + value.type === 'num' ? value.value.toString() + : value.type === 'str' ? `"${value.value}"` + : JSON.stringify(utils.valToJs(value), null, 2) ?? '', + ); + }, + log: (type: string, params: { val?: values.Value }) => { + if (type === 'end' && params.val != null && 'type' in params.val) { + this.print(utils.valToString(params.val, true)); + } + }, + }); + async exec(node: unknown): Promise { + await this.interpreter.exec(node as Ast.Node[]); + } + isAiScriptError(error: unknown): error is errors.AiScriptError { + return error instanceof errors.AiScriptError; + } + getErrorName(error: errors.AiScriptError): string | undefined { + if (error instanceof errors.SyntaxError) { + return 'SyntaxError'; + } + if (error instanceof errors.TypeError) { + return 'TypeError'; + } + if (error instanceof errors.RuntimeError) { + return 'RuntimeError'; + } + if (error instanceof errors.IndexOutOfRangeError) { + return 'IndexOutOfRangeError'; + } + return 'AiScriptError'; + } + dispose() { + this.interpreter.abort(); + } +} diff --git a/.vitepress/scripts/versions/0.16.0.ts b/.vitepress/scripts/versions/0.16.0.ts new file mode 100644 index 0000000..52b4468 --- /dev/null +++ b/.vitepress/scripts/versions/0.16.0.ts @@ -0,0 +1,51 @@ +import { Parser, Interpreter, utils, errors, type Ast } from 'aiscript0_16/index.js'; +import { Runner } from '../runner'; + +export default class extends Runner { + version = '0.16.0'; + + parse(code: string) { + const ast = Parser.parse(code); + const metadata = Interpreter.collectMetadata(ast); + return [ast, metadata] as const; + } + + private interpreter = new Interpreter({}, { + out: (value) => { + this.print( + value.type === 'num' ? value.value.toString() + : value.type === 'str' ? `"${value.value}"` + : JSON.stringify(utils.valToJs(value), null, 2) ?? '', + ); + }, + log: (type, params) => { + if (type === 'end' && params.val != null && 'type' in params.val) { + this.print(utils.valToString(params.val, true)); + } + }, + }); + async exec(node: unknown): Promise { + await this.interpreter.exec(node as Ast.Node[]); + } + isAiScriptError(error: unknown): error is errors.AiScriptError { + return error instanceof errors.AiScriptError; + } + getErrorName(error: errors.AiScriptError): string | undefined { + if (error instanceof errors.AiScriptSyntaxError) { + return 'SyntaxError'; + } + if (error instanceof errors.AiScriptTypeError) { + return 'TypeError'; + } + if (error instanceof errors.AiScriptRuntimeError) { + return 'RuntimeError'; + } + if (error instanceof errors.AiScriptIndexOutOfRangeError) { + return 'IndexOutOfRangeError'; + } + return 'AiScriptError'; + } + dispose() { + this.interpreter.abort(); + } +} diff --git a/.vitepress/scripts/versions/0.17.0.ts b/.vitepress/scripts/versions/0.17.0.ts new file mode 100644 index 0000000..98b6d43 --- /dev/null +++ b/.vitepress/scripts/versions/0.17.0.ts @@ -0,0 +1,51 @@ +import { AISCRIPT_VERSION, Parser, Interpreter, utils, errors, type Ast } from 'aiscript0_17'; +import { Runner } from '../runner'; + +export default class extends Runner { + version = AISCRIPT_VERSION; + + parse(code: string) { + const ast = Parser.parse(code); + const metadata = Interpreter.collectMetadata(ast); + return [ast, metadata] as const; + } + + private interpreter = new Interpreter({}, { + out: (value) => { + this.print( + value.type === 'num' ? value.value.toString() + : value.type === 'str' ? `"${value.value}"` + : JSON.stringify(utils.valToJs(value), null, 2) ?? '', + ); + }, + log: (type, params) => { + if (type === 'end' && params.val != null && 'type' in params.val) { + this.print(utils.valToString(params.val, true)); + } + }, + }); + async exec(node: unknown): Promise { + await this.interpreter.exec(node as Ast.Node[]); + } + isAiScriptError(error: unknown): error is errors.AiScriptError { + return error instanceof errors.AiScriptError; + } + getErrorName(error: errors.AiScriptError): string | undefined { + if (error instanceof errors.AiScriptSyntaxError) { + return 'SyntaxError'; + } + if (error instanceof errors.AiScriptTypeError) { + return 'TypeError'; + } + if (error instanceof errors.AiScriptRuntimeError) { + return 'RuntimeError'; + } + if (error instanceof errors.AiScriptIndexOutOfRangeError) { + return 'IndexOutOfRangeError'; + } + return 'AiScriptError'; + } + dispose() { + this.interpreter.abort(); + } +} diff --git a/.vitepress/scripts/versions/0.18.0.ts b/.vitepress/scripts/versions/0.18.0.ts new file mode 100644 index 0000000..496e3d0 --- /dev/null +++ b/.vitepress/scripts/versions/0.18.0.ts @@ -0,0 +1,54 @@ +import { AISCRIPT_VERSION, Parser, Interpreter, utils, errors, type Ast } from 'aiscript0_18'; +import { Runner } from '../runner'; + +export default class extends Runner { + version = AISCRIPT_VERSION; + + parse(code: string) { + const ast = Parser.parse(code); + const metadata = Interpreter.collectMetadata(ast); + return [ast, metadata] as const; + } + + private interpreter = new Interpreter({}, { + out: (value) => { + this.print( + value.type === 'num' ? value.value.toString() + : value.type === 'str' ? `"${value.value}"` + : JSON.stringify(utils.valToJs(value), null, 2) ?? '', + ); + }, + log: (type, params) => { + if (type === 'end' && params.val != null && 'type' in params.val) { + this.print(utils.valToString(params.val, true)); + } + }, + }); + async exec(node: unknown): Promise { + await this.interpreter.exec(node as Ast.Node[]); + } + isAiScriptError(error: unknown): error is errors.AiScriptError { + return error instanceof errors.AiScriptError; + } + getErrorName(error: errors.AiScriptError): string | undefined { + if (error instanceof errors.AiScriptSyntaxError) { + return 'SyntaxError'; + } + if (error instanceof errors.AiScriptTypeError) { + return 'TypeError'; + } + if (error instanceof errors.AiScriptRuntimeError) { + return 'RuntimeError'; + } + if (error instanceof errors.AiScriptIndexOutOfRangeError) { + return 'IndexOutOfRangeError'; + } + if (error instanceof errors.AiScriptUserError) { + return 'UserError'; + } + return 'AiScriptError'; + } + dispose() { + this.interpreter.abort(); + } +} diff --git a/.vitepress/scripts/versions/0.19.0.ts b/.vitepress/scripts/versions/0.19.0.ts new file mode 100644 index 0000000..5bc94a6 --- /dev/null +++ b/.vitepress/scripts/versions/0.19.0.ts @@ -0,0 +1,54 @@ +import { AISCRIPT_VERSION, Parser, Interpreter, utils, errors, type Ast } from 'aiscript0_19'; +import { Runner } from '../runner'; + +export default class extends Runner { + version = AISCRIPT_VERSION; + + parse(code: string) { + const ast = Parser.parse(code); + const metadata = Interpreter.collectMetadata(ast); + return [ast, metadata] as const; + } + + private interpreter = new Interpreter({}, { + out: (value) => { + this.print( + value.type === 'num' ? value.value.toString() + : value.type === 'str' ? `"${value.value}"` + : JSON.stringify(utils.valToJs(value), null, 2) ?? '', + ); + }, + log: (type, params) => { + if (type === 'end' && params.val != null && 'type' in params.val) { + this.print(utils.valToString(params.val, true)); + } + }, + }); + async exec(node: unknown): Promise { + await this.interpreter.exec(node as Ast.Node[]); + } + isAiScriptError(error: unknown): error is errors.AiScriptError { + return error instanceof errors.AiScriptError; + } + getErrorName(error: errors.AiScriptError): string | undefined { + if (error instanceof errors.AiScriptSyntaxError) { + return 'SyntaxError'; + } + if (error instanceof errors.AiScriptTypeError) { + return 'TypeError'; + } + if (error instanceof errors.AiScriptRuntimeError) { + return 'RuntimeError'; + } + if (error instanceof errors.AiScriptIndexOutOfRangeError) { + return 'IndexOutOfRangeError'; + } + if (error instanceof errors.AiScriptUserError) { + return 'UserError'; + } + return 'AiScriptError'; + } + dispose() { + this.interpreter.abort(); + } +} diff --git a/.vitepress/scripts/versions/dev.ts b/.vitepress/scripts/versions/dev.ts new file mode 100644 index 0000000..db42275 --- /dev/null +++ b/.vitepress/scripts/versions/dev.ts @@ -0,0 +1,54 @@ +import { AISCRIPT_VERSION, Parser, Interpreter, utils, errors, type Ast } from '@syuilo/aiscript'; +import { Runner } from '../runner'; + +export default class extends Runner { + version = AISCRIPT_VERSION; + + parse(code: string) { + const ast = Parser.parse(code); + const metadata = Interpreter.collectMetadata(ast); + return [ast, metadata] as const; + } + + private interpreter = new Interpreter({}, { + out: (value) => { + this.print( + value.type === 'num' ? value.value.toString() + : value.type === 'str' ? `"${value.value}"` + : JSON.stringify(utils.valToJs(value), null, 2) ?? '', + ); + }, + log: (type, params) => { + if (type === 'end' && params.val != null && 'type' in params.val) { + this.print(utils.valToString(params.val, true)); + } + }, + }); + async exec(node: unknown): Promise { + await this.interpreter.exec(node as Ast.Node[]); + } + isAiScriptError(error: unknown): error is errors.AiScriptError { + return error instanceof errors.AiScriptError; + } + getErrorName(error: errors.AiScriptError): string | undefined { + if (error instanceof errors.AiScriptSyntaxError) { + return 'SyntaxError'; + } + if (error instanceof errors.AiScriptTypeError) { + return 'TypeError'; + } + if (error instanceof errors.AiScriptRuntimeError) { + return 'RuntimeError'; + } + if (error instanceof errors.AiScriptIndexOutOfRangeError) { + return 'IndexOutOfRangeError'; + } + if (error instanceof errors.AiScriptUserError) { + return 'UserError'; + } + return 'AiScriptError'; + } + dispose() { + this.interpreter.abort(); + } +} diff --git a/.vitepress/scripts/versions/index.ts b/.vitepress/scripts/versions/index.ts new file mode 100644 index 0000000..402f846 --- /dev/null +++ b/.vitepress/scripts/versions/index.ts @@ -0,0 +1,17 @@ +import { Runner } from '../runner'; + +interface VersionModule { + default: new (...args: ConstructorParameters) => Runner; +} + +export const versionModules = new Map Promise>([ + ['dev', () => import('./dev')], + ['0.19.0', () => import('./0.19.0')], + ['0.18.0', () => import('./0.18.0')], + ['0.17.0', () => import('./0.17.0')], + ['0.16.0', () => import('./0.16.0')], + ['0.15.0', () => import('./0.15.0')], + ['0.14.1', () => import('./0.14.1')], +]); + +export const latestVersion = [...versionModules.keys()][1]!; diff --git a/package.json b/package.json index 449971d..aaecdae 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,12 @@ "packageManager": "pnpm@9.14.3", "devDependencies": { "@syuilo/aiscript": "dev", + "aiscript0_19": "npm:@syuilo/aiscript@0.19.0", + "aiscript0_18": "npm:@syuilo/aiscript@0.18.0", + "aiscript0_17": "npm:@syuilo/aiscript@0.17.0", + "aiscript0_16": "npm:@syuilo/aiscript@0.16.0", + "aiscript0_15": "npm:@syuilo/aiscript@0.15.0", + "aiscript0_14": "npm:@syuilo/aiscript@0.14.1", "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.15", "lz-string": "^1.5.0", "markdown-it-mathjax3": "^4.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8d77907..a66c14d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,24 @@ importers: aiscript-vscode: specifier: github:aiscript-dev/aiscript-vscode#v0.1.15 version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/c3cde89e79a41d93540cf8a48cd619c3f2dcb1b7 + aiscript0_14: + specifier: npm:@syuilo/aiscript@0.14.1 + version: '@syuilo/aiscript@0.14.1' + aiscript0_15: + specifier: npm:@syuilo/aiscript@0.15.0 + version: '@syuilo/aiscript@0.15.0' + aiscript0_16: + specifier: npm:@syuilo/aiscript@0.16.0 + version: '@syuilo/aiscript@0.16.0' + aiscript0_17: + specifier: npm:@syuilo/aiscript@0.17.0 + version: '@syuilo/aiscript@0.17.0' + aiscript0_18: + specifier: npm:@syuilo/aiscript@0.18.0 + version: '@syuilo/aiscript@0.18.0' + aiscript0_19: + specifier: npm:@syuilo/aiscript@0.19.0 + version: '@syuilo/aiscript@0.19.0' lz-string: specifier: ^1.5.0 version: 1.5.0 @@ -562,6 +580,24 @@ packages: '@shikijs/vscode-textmate@9.3.1': resolution: {integrity: sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==} + '@syuilo/aiscript@0.14.1': + resolution: {integrity: sha512-zyX+QWdE/PtEjem+15uPd1J43JIOfaRziGrkwUx+BU/dB9yJADkbwzH9ZkVr2Jzi56TYE4p3Xs5y2Kp+Z6/34A==} + + '@syuilo/aiscript@0.15.0': + resolution: {integrity: sha512-vauMbqacuHufE4W7bAm5BDWlci3mWg1ZaerPNHKBMrRXDjEfvBkBGZNXKSWvi+zmhiYAbWyozPIlV6byttYpCw==} + + '@syuilo/aiscript@0.16.0': + resolution: {integrity: sha512-CXvoWOq6kmOSUQtKv0IEf7Ebfkk5PO1LxAgLqgRRPgssPvDvINCXu/gFNXKdapkFMkmX+Gj8qjemKR1vnUS4ZA==} + + '@syuilo/aiscript@0.17.0': + resolution: {integrity: sha512-3JtQ1rWJHMxQ3153zLCXMUOwrOgjPPYGBl0dPHhR0ohm4tn7okMQRugxMCT0t3YxByemb9FfiM6TUjd0tEGxdA==} + + '@syuilo/aiscript@0.18.0': + resolution: {integrity: sha512-/iY9Vv4LLjtW/KUzId1QwXC4BlpIEPCMcoT7dyRhYdyxtwhS3Hx4b/4j1HYP+n3Pq9XKyW5zvkY72/+DNu4g6Q==} + + '@syuilo/aiscript@0.19.0': + resolution: {integrity: sha512-ZWG4s1m6RrFjE7NeIMaxFz769YO1jW5ReTrOROrEO4IHheOrjxxJ/Ffe2TUNqX9/XxDloMwfWplKhfSzx8LGMA==} + '@syuilo/aiscript@1.0.0-dev.20241226': resolution: {integrity: sha512-pRX7Mmu2RDWHFaSI6emW0coCq6IAXxYX9Z6E2DNfgpc/UZFzVeIeSRt7WI3cfKWOgNyIumr77TCG0hMXeksycA==} @@ -700,6 +736,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + autobind-decorator@2.4.0: + resolution: {integrity: sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw==} + engines: {node: '>=8.10', npm: '>=6.4.1'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1037,6 +1077,10 @@ packages: resolution: {integrity: sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==} hasBin: true + uuid@9.0.0: + resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} + hasBin: true + uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true @@ -1586,6 +1630,44 @@ snapshots: '@shikijs/vscode-textmate@9.3.1': {} + '@syuilo/aiscript@0.14.1': + dependencies: + autobind-decorator: 2.4.0 + seedrandom: 3.0.5 + stringz: 2.1.0 + uuid: 9.0.0 + + '@syuilo/aiscript@0.15.0': + dependencies: + autobind-decorator: 2.4.0 + seedrandom: 3.0.5 + stringz: 2.1.0 + uuid: 9.0.0 + + '@syuilo/aiscript@0.16.0': + dependencies: + seedrandom: 3.0.5 + stringz: 2.1.0 + uuid: 9.0.1 + + '@syuilo/aiscript@0.17.0': + dependencies: + seedrandom: 3.0.5 + stringz: 2.1.0 + uuid: 9.0.1 + + '@syuilo/aiscript@0.18.0': + dependencies: + seedrandom: 3.0.5 + stringz: 2.1.0 + uuid: 9.0.1 + + '@syuilo/aiscript@0.19.0': + dependencies: + seedrandom: 3.0.5 + stringz: 2.1.0 + uuid: 9.0.1 + '@syuilo/aiscript@1.0.0-dev.20241226': dependencies: seedrandom: 3.0.5 @@ -1747,6 +1829,8 @@ snapshots: ansi-colors@4.1.3: {} + autobind-decorator@2.4.0: {} + balanced-match@1.0.2: {} birpc@0.2.19: {} @@ -2170,6 +2254,8 @@ snapshots: uuid@11.0.3: {} + uuid@9.0.0: {} + uuid@9.0.1: {} valid-data-url@3.0.1: {}