Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions etc/aiscript.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ type Index = NodeBase & {

// @public (undocumented)
export class Interpreter {
constructor(consts: Record<string, Value>, opts?: {
constructor(globals: Record<string, Value>, opts?: {
in?(q: string): Promise<string>;
out?(value: Value): void;
err?(e: AiScriptError): void;
Expand Down Expand Up @@ -713,6 +713,9 @@ export class Scope {
// @public (undocumented)
type Statement = Definition | Return | Each | For | Loop | Break | Continue | Assign | AddAssign | SubAssign;

// @public (undocumented)
export const std: Record<string, Value>;

// @public (undocumented)
const STR: (str: VStr["value"]) => VStr;

Expand Down Expand Up @@ -918,7 +921,7 @@ type VUserFn = VFnBase & {

// Warnings were encountered during analysis:
//
// src/interpreter/index.ts:49:4 - (ae-forgotten-export) The symbol "LogObject" needs to be exported by the entry point index.d.ts
// src/interpreter/index.ts:50:4 - (ae-forgotten-export) The symbol "LogObject" needs to be exported by the entry point index.d.ts
// src/interpreter/value.ts:47:2 - (ae-forgotten-export) The symbol "Type" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//export * from './interpreter/index';
//export * as utils from './interpreter/util';
//export * as values from './interpreter/value';
import { Interpreter } from './interpreter/index.js';
import { Interpreter, std } from './interpreter/index.js';
import { Scope } from './interpreter/scope.js';
import * as utils from './interpreter/util.js';
import * as values from './interpreter/value.js';
Expand All @@ -12,7 +12,7 @@ import * as errors from './error.js';
import * as Ast from './node.js';
import { AISCRIPT_VERSION } from './constants.js';
import type { ParserPlugin, PluginType } from './parser/index.js';
export { Interpreter };
export { Interpreter, std };
export { Scope };
export { utils };
export { values };
Expand Down
20 changes: 10 additions & 10 deletions src/interpreter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@
import * as Ast from '../node.js';
import { nodeToJs } from '../utils/node-to-js.js';
import { Scope } from './scope.js';
import { std } from './lib/std.js';
import { RETURN, unWrapRet, BREAK, CONTINUE, assertValue, isControl, type Control, unWrapLabeledBreak } from './control.js';
import { assertNumber, assertString, assertFunction, assertBoolean, assertObject, assertArray, eq, isObject, isArray, expectAny, reprValue, isFunction } from './util.js';
import { NULL, FN_NATIVE, BOOL, NUM, STR, ARR, OBJ, FN, ERROR } from './value.js';
import { getPrimProp } from './primitive-props.js';
import { Variable } from './variable.js';
import { Reference } from './reference.js';
import { stdCore } from './lib/core.js';
import type { JsValue } from './util.js';
import type { Value, VFn, VUserFn } from './value.js';

export { std } from './lib/std.js';

export type LogObject = {
scope?: string;
var?: string;
Expand All @@ -36,12 +38,11 @@
private abortHandlers: (() => void)[] = [];
private pauseHandlers: (() => void)[] = [];
private unpauseHandlers: (() => void)[] = [];
private vars: Record<string, Variable> = {};
private irqRate: number;
private irqSleep: () => Promise<void>;

constructor(
consts: Record<string, Value>,
globals: Record<string, Value>,
private opts: {
in?(q: string): Promise<string>;
out?(value: Value): void;
Expand All @@ -67,13 +68,12 @@
}),
};

this.vars = Object.fromEntries(Object.entries({
...consts,
...std,
...io,
}).map(([k, v]) => [k, Variable.const(v)]));

this.scope = new Scope([new Map(Object.entries(this.vars))]);
this.scope = new Scope([
new Map(
Object.entries({ ...globals,...stdCore, ...io })
.map(([k, v]) => [k, Variable.const(v)]),
),
]);
this.scope.opts.log = (type, params): void => {
switch (type) {
case 'add': this.log('var:add', params); break;
Expand Down Expand Up @@ -548,7 +548,7 @@

case 'loop': {
// eslint-disable-next-line no-constant-condition
while (true) {

Check warning on line 551 in src/interpreter/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unnecessary conditional, value is always truthy
const v = await this._run(node.statements, scope.createChildScope(), callStack);
if (v.type === 'break') {
if (v.label != null && v.label !== node.label) {
Expand Down Expand Up @@ -1081,7 +1081,7 @@

case 'loop': {
// eslint-disable-next-line no-constant-condition
while (true) {

Check warning on line 1084 in src/interpreter/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unnecessary conditional, value is always truthy
const v = this._runSync(node.statements, scope.createChildScope(), callStack);
if (v.type === 'break') {
if (v.label != null && v.label !== node.label) {
Expand Down Expand Up @@ -1631,7 +1631,7 @@
public pause(): void {
if (this.pausing) return;
let resolve: () => void;
const promise = new Promise<void>(r => { resolve = () => r(); });

Check warning on line 1634 in src/interpreter/index.ts

View workflow job for this annotation

GitHub Actions / lint

Missing return type on function
this.pausing = { promise, resolve: resolve! };
for (const handler of this.pauseHandlers) {
handler();
Expand Down
138 changes: 138 additions & 0 deletions src/interpreter/lib/core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { NUM, STR, FN_NATIVE, FALSE, TRUE, ARR, NULL } from '../value.js';
import { assertNumber, assertString, assertBoolean, eq, expectAny, reprValue } from '../util.js';
import { AiScriptUserError } from '../../error.js';
import { AISCRIPT_VERSION } from '../../constants.js';
import type { Value } from '../value.js';

export const stdCore: Record<`Core:${string}`, Value> = {
'Core:v': STR(AISCRIPT_VERSION),

'Core:ai': STR('kawaii'),

'Core:not': FN_NATIVE(([a]) => {
assertBoolean(a);
return a.value ? FALSE : TRUE;
}),

'Core:eq': FN_NATIVE(([a, b]) => {
expectAny(a);
expectAny(b);
return eq(a, b) ? TRUE : FALSE;
}),

'Core:neq': FN_NATIVE(([a, b]) => {
expectAny(a);
expectAny(b);
return eq(a, b) ? FALSE : TRUE;
}),

'Core:and': FN_NATIVE(([a, b]) => {
assertBoolean(a);
if (!a.value) return FALSE;
assertBoolean(b);
return b.value ? TRUE : FALSE;
}),

'Core:or': FN_NATIVE(([a, b]) => {
assertBoolean(a);
if (a.value) return TRUE;
assertBoolean(b);
return b.value ? TRUE : FALSE;
}),

'Core:add': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
return NUM(a.value + b.value);
}),

'Core:sub': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
return NUM(a.value - b.value);
}),

'Core:mul': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
return NUM(a.value * b.value);
}),

'Core:pow': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
const res = a.value ** b.value;
return NUM(res);
}),

'Core:div': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
const res = a.value / b.value;
return NUM(res);
}),

'Core:mod': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
return NUM(a.value % b.value);
}),

'Core:gt': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
return a.value > b.value ? TRUE : FALSE;
}),

'Core:lt': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
return a.value < b.value ? TRUE : FALSE;
}),

'Core:gteq': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
return a.value >= b.value ? TRUE : FALSE;
}),

'Core:lteq': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
return a.value <= b.value ? TRUE : FALSE;
}),

'Core:type': FN_NATIVE(([v]) => {
expectAny(v);
return STR(v.type);
}),

'Core:to_str': FN_NATIVE(([v]) => {
expectAny(v);

return STR(reprValue(v));
}),

'Core:range': FN_NATIVE(([a, b]) => {
assertNumber(a);
assertNumber(b);
if (a.value < b.value) {
return ARR(Array.from({ length: (b.value - a.value) + 1 }, (_, i) => NUM(i + a.value)));
} else if (a.value > b.value) {
return ARR(Array.from({ length: (a.value - b.value) + 1 }, (_, i) => NUM(a.value - i)));
} else {
return ARR([a]);
}
}),

'Core:sleep': FN_NATIVE(async ([delay]) => {
assertNumber(delay);
await new Promise((r) => setTimeout(r, delay.value));
return NULL;
}),

'Core:abort': FN_NATIVE(async ([message]) => {
assertString(message);
throw new AiScriptUserError(message.value);
}),
};
Loading
Loading