66 <button :class =" [$style.playgroundButton]" :disabled =" loading" @click =" clearLog" >Clear</button >
77 </div >
88 <div :class =" $style.playgroundLogs" >
9- <div v-for =" log in logs" :key =" log" :class =" $style.playgroundLogItem" >{{ log }}</div >
9+ <div
10+ v-for =" log in logs"
11+ :key =" log.text"
12+ :class =" [
13+ $style.playgroundLogItem,
14+ {
15+ [$style.error]: log.type === 'error',
16+ [$style.info]: log.type === 'info',
17+ }
18+ ]"
19+ >{{ log.text }}</div >
1020 </div >
1121 </div >
1222</template >
1323
1424<script setup lang="ts">
1525import { ref } from ' vue' ;
16- import type { Interpreter , Parser , utils as aisUtils } from ' @syuilo/aiscript' ;
26+ import { utils , errors } from ' @syuilo/aiscript' ;
27+ import type { Interpreter , Parser } from ' @syuilo/aiscript' ;
1728
1829const props = defineProps <{
1930 code: string ;
2031}>();
2132
22- const logs = ref <string []>([]);
33+ const logs = ref <{
34+ text: string ;
35+ type? : ' error' | ' info' ;
36+ }[]>([]);
2337const loading = ref (false );
2438
2539let ParserClass: typeof Parser | null = null ;
2640let InterpreterClass: typeof Interpreter | null = null ;
27- let utils: typeof aisUtils | null = null ;
2841
2942let parser: Parser | null = null ;
3043let interpreter: Interpreter | null = null ;
3144
3245async function run() {
3346 loading .value = true ;
34- logs .value = [' [Playground] Loading...' ];
35- if (! ParserClass || ! InterpreterClass || ! utils ) {
47+
48+ if (logs .value .length > 0 ) {
49+ logs .value = [];
50+ await new Promise ((resolve ) => setTimeout (resolve , 100 ));
51+ }
52+
53+ logs .value = [{
54+ text: ` [Playground] Loading... ` ,
55+ type: ' info' ,
56+ }];
57+
58+ if (! ParserClass || ! InterpreterClass ) {
3659 const [
37- { Parser, Interpreter, utils : importedUtils },
60+ { Parser, Interpreter },
3861 ] = await Promise .all ([
3962 import (' @syuilo/aiscript' ),
4063 new Promise ((resolve ) => setTimeout (resolve , 250 )), // あまりにも高速に切り替わると実行できてるのかわかりにくいので、最低250msはロード画面を挟む
4164 ]);
4265 ParserClass = Parser ;
4366 InterpreterClass = Interpreter ;
44- utils = importedUtils ;
4567 } else {
4668 await new Promise ((resolve ) => setTimeout (resolve , 250 )); // あまりにも高速に切り替わると実行できてるのかわかりにくいので、最低250msはロード画面を挟む
4769 }
70+
4871 if (! parser ) {
4972 parser = new ParserClass ();
5073 }
5174 if (interpreter ) {
5275 interpreter .abort ();
5376 }
77+
5478 interpreter = new InterpreterClass ({}, {
5579 out : (value ) => {
56- logs .value .push (value .type === ' num' ? value .value .toString () : value .type === ' str' ? value .value : utils ?.valToString (value ) ?? ' ' );
80+ logs .value .push ({
81+ text: value .type === ' num' ? value .value .toString () : value .type === ' str' ? value .value : utils .valToString (value ) ?? ' ' ,
82+ });
5783 },
5884 });
5985
60- logs .value = [];
6186 loading .value = false ;
6287
63- const ast = parser .parse (props .code );
64- await interpreter .exec (ast );
88+ try {
89+ const ast = parser .parse (props .code );
90+ await interpreter .exec (ast );
91+ } catch (err ) {
92+ if (err instanceof errors .AiScriptError ) {
93+ let errorName = ' AiScriptError' ;
94+
95+ if (err instanceof errors .AiScriptSyntaxError ) {
96+ errorName = ' SyntaxError' ;
97+ } else if (err instanceof errors .AiScriptTypeError ) {
98+ errorName = ' TypeError' ;
99+ } else if (err instanceof errors .AiScriptRuntimeError ) {
100+ errorName = ' RuntimeError' ;
101+ } else if (err instanceof errors .AiScriptIndexOutOfRangeError ) {
102+ errorName = ' IndexOutOfRangeError' ;
103+ } else if (err instanceof errors .AiScriptUserError ) {
104+ errorName = ' UserError' ;
105+ }
106+
107+ logs .value .push ({
108+ text: ` [${errorName }] ${err .name }: ${err .message } ` ,
109+ type: ' error' ,
110+ });
111+ } else {
112+ logs .value .push ({
113+ text: ` [Error] ${err } ` ,
114+ type: ' error' ,
115+ });
116+ }
117+ }
65118}
66119
67120function stop() {
@@ -136,5 +189,18 @@ function clearLog() {
136189 font-family : var (--vp-font-family-mono );
137190 white-space : pre-wrap ;
138191 font-size : 14px ;
192+ padding : 0 8px ;
193+ border-radius : 4px ;
194+ }
195+
196+ .playgroundLogItem.error {
197+ background-color : var (--vp-c-danger-soft );
198+ color : var (--vp-c-danger-1 );
199+ }
200+
201+ .playgroundLogItem.info {
202+ background-color : var (--vp-c-tip-soft );
203+ color : var (--vp-c-tip-2 );
204+ font-style : italic ;
139205}
140206 </style >
0 commit comments