Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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