(
consts: Record<string, Value>,
private opts: {
in?(q: string): Promise<string>;
out?(value: Value): void;
err?(e: AiScriptError): void;
log?(type: string, params: LogObject): void;
maxStep?: number;
abortOnError?: boolean;
irqRate?: number;
irqSleep?: number | (() => Promise<void>);
} = {},
)
| 41 | private irqSleep: () => Promise<void>; |
| 42 | |
| 43 | constructor( |
| 44 | consts: Record<string, Value>, |
| 45 | private opts: { |
| 46 | in?(q: string): Promise<string>; |
| 47 | out?(value: Value): void; |
| 48 | err?(e: AiScriptError): void; |
| 49 | log?(type: string, params: LogObject): void; |
| 50 | maxStep?: number; |
| 51 | abortOnError?: boolean; |
| 52 | irqRate?: number; |
| 53 | irqSleep?: number | (() => Promise<void>); |
| 54 | } = {}, |
| 55 | ) { |
| 56 | const io = { |
| 57 | print: FN_NATIVE(([v]) => { |
| 58 | expectAny(v); |
| 59 | if (this.opts.out) this.opts.out(v); |
| 60 | }), |
| 61 | readline: FN_NATIVE(async args => { |
| 62 | const q = args[0]; |
| 63 | assertString(q); |
| 64 | if (this.opts.in == null) return NULL; |
| 65 | const a = await this.opts.in!(q.value); |
| 66 | return STR(a); |
| 67 | }), |
| 68 | }; |
| 69 | |
| 70 | this.vars = Object.fromEntries(Object.entries({ |
| 71 | ...consts, |
| 72 | ...std, |
| 73 | ...io, |
| 74 | }).map(([k, v]) => [k, Variable.const(v)])); |
| 75 | |
| 76 | this.scope = new Scope([new Map(Object.entries(this.vars))]); |
| 77 | this.scope.opts.log = (type, params): void => { |
| 78 | switch (type) { |
| 79 | case 'add': this.log('var:add', params); break; |
| 80 | case 'read': this.log('var:read', params); break; |
| 81 | case 'write': this.log('var:write', params); break; |
| 82 | default: break; |
| 83 | } |
| 84 | }; |
| 85 | |
| 86 | if (!((this.opts.irqRate ?? 300) >= 0)) { |
| 87 | throw new AiScriptHostsideError(`Invalid IRQ rate (${this.opts.irqRate}): must be non-negative number`); |
| 88 | } |
| 89 | this.irqRate = this.opts.irqRate ?? 300; |
| 90 | |
| 91 | const sleep = (time: number) => ( |
| 92 | (): Promise<void> => new Promise(resolve => setTimeout(resolve, time)) |
| 93 | ); |
| 94 | |
| 95 | if (typeof this.opts.irqSleep === 'function') { |
| 96 | this.irqSleep = this.opts.irqSleep; |
| 97 | } else if (this.opts.irqSleep === undefined) { |
| 98 | this.irqSleep = sleep(5); |
| 99 | } else if (this.opts.irqSleep >= 0) { |
| 100 | this.irqSleep = sleep(this.opts.irqSleep); |
nothing calls this directly
no test coverage detected