From 87fe3d0205ab887af57b003f8f40d93e79d56d77 Mon Sep 17 00:00:00 2001 From: FineArchs <133759614+FineArchs@users.noreply.github.com> Date: Sat, 9 Sep 2023 17:07:48 +0900 Subject: [PATCH] =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E5=9E=8B=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=20(#323)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * in progress * update test * change error name * update docs * api extraction --- CHANGELOG.md | 2 + docs/get-started.md | 14 +- docs/std.md | 12 +- etc/aiscript.api.md | 2084 ++++++++++++++-------------- src/interpreter/lib/std.ts | 8 +- src/interpreter/primitive-props.ts | 10 +- src/interpreter/value.ts | 14 +- test/index.ts | 43 +- 8 files changed, 1122 insertions(+), 1065 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c814152f..0df3fc63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - 指定時間待機する関数`Core:sleep`を追加 - `exists 変数名` の構文で変数が存在するか判定できるように - オブジェクトを添字で参照できるように(`object['index']`のように) +- 「エラー型(`error`)」を導入 +- `Json:parse`がパース失敗時にエラー型の値を返すように # 0.15.0 - Mathを強化 diff --git a/docs/get-started.md b/docs/get-started.md index bd70436c..e20816d4 100644 --- a/docs/get-started.md +++ b/docs/get-started.md @@ -51,6 +51,7 @@ this is a comment オブジェクトobj{ foo: "bar"; a: 42; } nullnullnull 関数fn@(x) { x } + エラーerror(TODO) ## 変数 @@ -256,4 +257,15 @@ AiScriptファイルにメタデータを埋め込める機能です。 version: 42 keywords: ["foo" "bar" "baz"] } -``` \ No newline at end of file +``` + +## エラー型 +一部の標準関数は実行失敗時にエラー型の値を返します。 +これによりエラー処理を行うことができます。 +``` +@validate(str){ + let v=Json:parse(str) + if (Core:type(v)=='error') print(v.name) + else print('successful') +} +``` diff --git a/docs/std.md b/docs/std.md index 7d4bfe15..ed87a68e 100644 --- a/docs/std.md +++ b/docs/std.md @@ -33,10 +33,10 @@ AiScriptのバージョンです。 JSONを生成します。 ### @Json:parse(_json_: str): value -JSONをパースします。 +JSONをパースします。 引数がJSONとしてパース可能性でない場合、エラー型の値(`name`=`'not_json'`)を返します。 ### @Json:parsable(_str_: str): bool -文字列がJSONとしてパース可能であるかの判定を行います。 +文字列がJSONとしてパース可能であるかの判定を行います。歴史的理由により存在しています ## :: Date @@ -236,6 +236,14 @@ _codepoint_ は 0 以上、10FFFF16 以下である必要がありま ### @Obj:copy(_v_: obj): obj オブジェクトのコピーを生成します。 +## :: Error + +### @(_v_: error).name(): str +エラーの識別子となる文字列を返します。 + +### @(_v_: error).info(): value +エラーに付加情報がある場合、それを返します。 + ## :: Async ### @Async:interval(_interval_: num, _callback_: fn, _immediate_?: bool): fn diff --git a/etc/aiscript.api.md b/etc/aiscript.api.md index 5cc949b2..f5c4ff08 100644 --- a/etc/aiscript.api.md +++ b/etc/aiscript.api.md @@ -1,1036 +1,1048 @@ -## API Report File for "@syuilo/aiscript" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -// Warning: (ae-forgotten-export) The symbol "NodeBase" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -type AddAssign = NodeBase & { - type: 'addAssign'; - dest: Expression; - expr: Expression; -}; - -// Warning: (ae-forgotten-export) The symbol "NodeBase_2" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -type AddAssign_2 = NodeBase_2 & { - type: 'addAssign'; - dest: Expression_2; - expr: Expression_2; -}; - -// @public (undocumented) -abstract class AiScriptError extends Error { - constructor(message: string, info?: any); - // (undocumented) - info?: any; -} - -// @public (undocumented) -type And = NodeBase & { - type: 'and'; - left: Expression; - right: Expression; -}; - -// @public (undocumented) -type And_2 = NodeBase_2 & { - type: 'and'; - left: Expression_2; - right: Expression_2; -}; - -// @public (undocumented) -const ARR: (arr: VArr['value']) => VArr; - -// @public (undocumented) -type Arr = NodeBase & { - type: 'arr'; - value: Expression[]; -}; - -// Warning: (ae-forgotten-export) The symbol "ChainProp" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -type Arr_2 = NodeBase_2 & ChainProp & { - type: 'arr'; - value: Expression_2[]; -}; - -// @public (undocumented) -function assertArray(val: Value | null | undefined): asserts val is VArr; - -// @public (undocumented) -function assertBoolean(val: Value | null | undefined): asserts val is VBool; - -// @public (undocumented) -function assertFunction(val: Value | null | undefined): asserts val is VFn; - -// @public (undocumented) -function assertNumber(val: Value | null | undefined): asserts val is VNum; - -// @public (undocumented) -function assertObject(val: Value | null | undefined): asserts val is VObj; - -// @public (undocumented) -function assertString(val: Value | null | undefined): asserts val is VStr; - -// @public (undocumented) -type Assign = NodeBase & { - type: 'assign'; - dest: Expression; - expr: Expression; -}; - -// @public (undocumented) -type Assign_2 = NodeBase_2 & { - type: 'assign'; - dest: Expression_2; - expr: Expression_2; -}; - -declare namespace Ast { - export { - isStatement, - isExpression, - Loc, - Node_2 as Node, - Statement, - Expression, - Namespace, - Meta, - Definition, - Attribute, - Return, - Each, - For, - Loop, - Break, - Continue, - AddAssign, - SubAssign, - Assign, - Not, - And, - Or, - If, - Fn, - Match, - Block, - Exists, - Tmpl, - Str, - Num, - Bool, - Null, - Obj, - Arr, - Identifier, - Call, - Index, - Prop, - TypeSource, - NamedTypeSource, - FnTypeSource - } -} -export { Ast } - -// @public (undocumented) -type Attr_2 = { - attr?: { - name: string; - value: Value; - }[]; -}; - -// @public (undocumented) -type Attribute = NodeBase & { - type: 'attr'; - name: string; - value: Expression; -}; - -// @public (undocumented) -type Attribute_2 = NodeBase_2 & { - type: 'attr'; - name: string; - value: Expression_2; -}; - -// @public (undocumented) -type Block = NodeBase & { - type: 'block'; - statements: (Statement | Expression)[]; -}; - -// @public (undocumented) -type Block_2 = NodeBase_2 & ChainProp & { - type: 'block'; - statements: (Statement_2 | Expression_2)[]; -}; - -// @public (undocumented) -const BOOL: (bool: VBool['value']) => VBool; - -// @public (undocumented) -type Bool = NodeBase & { - type: 'bool'; - value: boolean; -}; - -// @public (undocumented) -type Bool_2 = NodeBase_2 & ChainProp & { - type: 'bool'; - value: boolean; -}; - -// @public (undocumented) -const BREAK: () => Value; - -// @public (undocumented) -type Break = NodeBase & { - type: 'break'; -}; - -// @public (undocumented) -type Break_2 = NodeBase_2 & { - type: 'break'; -}; - -// @public (undocumented) -function CALL(target: Call_2['target'], args: Call_2['args'], loc?: { - start: number; - end: number; -}): Call_2; - -// @public (undocumented) -type Call = NodeBase & { - type: 'call'; - target: Expression; - args: Expression[]; -}; - -// @public (undocumented) -type Call_2 = NodeBase_2 & { - type: 'call'; - target: Expression_2; - args: Expression_2[]; -}; - -// @public (undocumented) -type CallChain = NodeBase_2 & { - type: 'callChain'; - args: Expression_2[]; -}; - -// @public (undocumented) -type ChainMember = CallChain | IndexChain | PropChain; - -// @public (undocumented) -const CONTINUE: () => Value; - -// @public (undocumented) -type Continue = NodeBase & { - type: 'continue'; -}; - -// @public (undocumented) -type Continue_2 = NodeBase_2 & { - type: 'continue'; -}; - -declare namespace Cst { - export { - isStatement_2 as isStatement, - isExpression_2 as isExpression, - hasChainProp, - CALL, - INDEX, - PROP, - Node_3 as Node, - Statement_2 as Statement, - Expression_2 as Expression, - Namespace_2 as Namespace, - Meta_2 as Meta, - Definition_2 as Definition, - Attribute_2 as Attribute, - Return_2 as Return, - Each_2 as Each, - For_2 as For, - Loop_2 as Loop, - Break_2 as Break, - Continue_2 as Continue, - AddAssign_2 as AddAssign, - SubAssign_2 as SubAssign, - Assign_2 as Assign, - InfixOperator, - Infix, - Not_2 as Not, - And_2 as And, - Or_2 as Or, - If_2 as If, - Fn_2 as Fn, - Match_2 as Match, - Block_2 as Block, - Exists_2 as Exists, - Tmpl_2 as Tmpl, - Str_2 as Str, - Num_2 as Num, - Bool_2 as Bool, - Null_2 as Null, - Obj_2 as Obj, - Arr_2 as Arr, - Identifier_2 as Identifier, - ChainMember, - CallChain, - IndexChain, - PropChain, - Call_2 as Call, - Index_2 as Index, - Prop_2 as Prop, - TypeSource_2 as TypeSource, - NamedTypeSource_2 as NamedTypeSource, - FnTypeSource_2 as FnTypeSource - } -} -export { Cst } - -// @public (undocumented) -type Definition = NodeBase & { - type: 'def'; - name: string; - varType?: TypeSource; - expr: Expression; - mut: boolean; - attr: Attribute[]; -}; - -// @public (undocumented) -type Definition_2 = NodeBase_2 & { - type: 'def'; - name: string; - varType?: TypeSource_2; - expr: Expression_2; - mut: boolean; - attr?: Attribute_2[]; -}; - -// @public (undocumented) -type Each = NodeBase & { - type: 'each'; - var: string; - items: Expression; - for: Statement | Expression; -}; - -// @public (undocumented) -type Each_2 = NodeBase_2 & { - type: 'each'; - var: string; - items: Expression_2; - for: Statement_2 | Expression_2; -}; - -// @public (undocumented) -function eq(a: Value, b: Value): boolean; - -declare namespace errors { - export { - AiScriptError, - SyntaxError_2 as SyntaxError, - TypeError_2 as TypeError, - RuntimeError, - IndexOutOfRangeError - } -} -export { errors } - -// @public (undocumented) -type Exists = NodeBase & { - type: 'exists'; - identifier: Identifier; -}; - -// @public (undocumented) -type Exists_2 = NodeBase_2 & ChainProp & { - type: 'exists'; - identifier: Identifier_2; -}; - -// @public (undocumented) -function expectAny(val: Value | null | undefined): asserts val is Value; - -// @public (undocumented) -type Expression = If | Fn | Match | Block | Exists | Tmpl | Str | Num | Bool | Null | Obj | Arr | Not | And | Or | Identifier | Call | Index | Prop; - -// @public (undocumented) -type Expression_2 = Infix | Not_2 | And_2 | Or_2 | If_2 | Fn_2 | Match_2 | Block_2 | Exists_2 | Tmpl_2 | Str_2 | Num_2 | Bool_2 | Null_2 | Obj_2 | Arr_2 | Identifier_2 | Call_2 | // IR -Index_2 | // IR -Prop_2; - -// @public (undocumented) -const FALSE: { - type: "bool"; - value: boolean; -}; - -// @public (undocumented) -const FN: (args: VFn['args'], statements: VFn['statements'], scope: VFn['scope']) => VFn; - -// @public (undocumented) -type Fn = NodeBase & { - type: 'fn'; - args: { - name: string; - argType?: TypeSource; - }[]; - retType?: TypeSource; - children: (Statement | Expression)[]; -}; - -// @public (undocumented) -type Fn_2 = NodeBase_2 & ChainProp & { - type: 'fn'; - args: { - name: string; - argType?: TypeSource_2; - }[]; - retType?: TypeSource_2; - children: (Statement_2 | Expression_2)[]; -}; - -// @public (undocumented) -const FN_NATIVE: (fn: VFn['native']) => VFn; - -// @public (undocumented) -type FnTypeSource = NodeBase & { - type: 'fnTypeSource'; - args: TypeSource[]; - result: TypeSource; -}; - -// @public (undocumented) -type FnTypeSource_2 = NodeBase_2 & { - type: 'fnTypeSource'; - args: TypeSource_2[]; - result: TypeSource_2; -}; - -// @public (undocumented) -type For = NodeBase & { - type: 'for'; - var?: string; - from?: Expression; - to?: Expression; - times?: Expression; - for: Statement | Expression; -}; - -// @public (undocumented) -type For_2 = NodeBase_2 & { - type: 'for'; - var?: string; - from?: Expression_2; - to?: Expression_2; - times?: Expression_2; - for: Statement_2 | Expression_2; -}; - -// @public (undocumented) -function getLangVersion(input: string): string | null; - -// @public (undocumented) -function hasChainProp(x: T): x is T & ChainProp; - -// @public (undocumented) -type Identifier = NodeBase & { - type: 'identifier'; - name: string; -}; - -// @public (undocumented) -type Identifier_2 = NodeBase_2 & ChainProp & { - type: 'identifier'; - name: string; -}; - -// @public (undocumented) -type If = NodeBase & { - type: 'if'; - cond: Expression; - then: Statement | Expression; - elseif: { - cond: Expression; - then: Statement | Expression; - }[]; - else?: Statement | Expression; -}; - -// @public (undocumented) -type If_2 = NodeBase_2 & { - type: 'if'; - cond: Expression_2; - then: Statement_2 | Expression_2; - elseif: { - cond: Expression_2; - then: Statement_2 | Expression_2; - }[]; - else?: Statement_2 | Expression_2; -}; - -// @public (undocumented) -function INDEX(target: Index_2['target'], index: Index_2['index'], loc?: { - start: number; - end: number; -}): Index_2; - -// @public (undocumented) -type Index = NodeBase & { - type: 'index'; - target: Expression; - index: Expression; -}; - -// @public (undocumented) -type Index_2 = NodeBase_2 & { - type: 'index'; - target: Expression_2; - index: Expression_2; -}; - -// @public (undocumented) -type IndexChain = NodeBase_2 & { - type: 'indexChain'; - index: Expression_2; -}; - -// @public (undocumented) -class IndexOutOfRangeError extends RuntimeError { - constructor(message: string, info?: any); -} - -// @public (undocumented) -type Infix = NodeBase_2 & { - type: 'infix'; - operands: Expression_2[]; - operators: InfixOperator[]; -}; - -// @public (undocumented) -type InfixOperator = '||' | '&&' | '==' | '!=' | '<=' | '>=' | '<' | '>' | '+' | '-' | '*' | '^' | '/' | '%'; - -// @public (undocumented) -export class Interpreter { - constructor(vars: Record, opts?: { - in?(q: string): Promise; - out?(value: Value): void; - log?(type: string, params: Record): void; - maxStep?: number; - }); - // (undocumented) - abort(): void; - // (undocumented) - static collectMetadata(script?: Ast.Node[]): Map | undefined; - // (undocumented) - exec(script?: Ast.Node[]): Promise; - // (undocumented) - execFn(fn: VFn, args: Value[]): Promise; - // (undocumented) - registerAbortHandler(handler: () => void): void; - // (undocumented) - scope: Scope; - // (undocumented) - stepCount: number; - // (undocumented) - unregisterAbortHandler(handler: () => void): void; -} - -// @public (undocumented) -function isArray(val: Value): val is VArr; - -// @public (undocumented) -function isBoolean(val: Value): val is VBool; - -// @public (undocumented) -function isExpression(x: Node_2): x is Expression; - -// @public (undocumented) -function isExpression_2(x: Node_3): x is Expression_2; - -// @public (undocumented) -function isFunction(val: Value): val is VFn; - -// @public (undocumented) -function isNumber(val: Value): val is VNum; - -// @public (undocumented) -function isObject(val: Value): val is VObj; - -// @public (undocumented) -function isStatement(x: Node_2): x is Statement; - -// @public (undocumented) -function isStatement_2(x: Node_3): x is Statement_2; - -// @public (undocumented) -function isString(val: Value): val is VStr; - -// @public (undocumented) -function jsToVal(val: any): Value; - -// @public -type Loc = { - start: number; - end: number; -}; - -// @public (undocumented) -type Loop = NodeBase & { - type: 'loop'; - statements: (Statement | Expression)[]; -}; - -// @public (undocumented) -type Loop_2 = NodeBase_2 & { - type: 'loop'; - statements: (Statement_2 | Expression_2)[]; -}; - -// @public (undocumented) -type Match = NodeBase & { - type: 'match'; - about: Expression; - qs: { - q: Expression; - a: Statement | Expression; - }[]; - default?: Statement | Expression; -}; - -// @public (undocumented) -type Match_2 = NodeBase_2 & ChainProp & { - type: 'match'; - about: Expression_2; - qs: { - q: Expression_2; - a: Statement_2 | Expression_2; - }[]; - default?: Statement_2 | Expression_2; -}; - -// @public (undocumented) -type Meta = NodeBase & { - type: 'meta'; - name: string | null; - value: Expression; -}; - -// @public (undocumented) -type Meta_2 = NodeBase_2 & { - type: 'meta'; - name: string | null; - value: Expression_2; -}; - -// @public (undocumented) -type NamedTypeSource = NodeBase & { - type: 'namedTypeSource'; - name: string; - inner?: TypeSource; -}; - -// @public (undocumented) -type NamedTypeSource_2 = NodeBase_2 & { - type: 'namedTypeSource'; - name: string; - inner?: TypeSource_2; -}; - -// @public (undocumented) -type Namespace = NodeBase & { - type: 'ns'; - name: string; - members: (Definition | Namespace)[]; -}; - -// @public (undocumented) -type Namespace_2 = NodeBase_2 & { - type: 'ns'; - name: string; - members: (Definition_2 | Namespace_2)[]; -}; - -// @public (undocumented) -type Node_2 = Namespace | Meta | Statement | Expression | TypeSource; - -// @public -type Node_3 = Namespace_2 | Meta_2 | Statement_2 | Expression_2 | ChainMember | TypeSource_2; - -// @public (undocumented) -type Not = NodeBase & { - type: 'not'; - expr: Expression; -}; - -// @public (undocumented) -type Not_2 = NodeBase_2 & { - type: 'not'; - expr: Expression_2; -}; - -// @public (undocumented) -const NULL: { - type: "null"; -}; - -// @public (undocumented) -type Null = NodeBase & { - type: 'null'; -}; - -// @public (undocumented) -type Null_2 = NodeBase_2 & ChainProp & { - type: 'null'; -}; - -// @public (undocumented) -const NUM: (num: VNum['value']) => VNum; - -// @public (undocumented) -type Num = NodeBase & { - type: 'num'; - value: number; -}; - -// @public (undocumented) -type Num_2 = NodeBase_2 & ChainProp & { - type: 'num'; - value: number; -}; - -// @public (undocumented) -const OBJ: (obj: VObj['value']) => VObj; - -// @public (undocumented) -type Obj = NodeBase & { - type: 'obj'; - value: Map; -}; - -// @public (undocumented) -type Obj_2 = NodeBase_2 & ChainProp & { - type: 'obj'; - value: Map; -}; - -// @public (undocumented) -type Or = NodeBase & { - type: 'or'; - left: Expression; - right: Expression; -}; - -// @public (undocumented) -type Or_2 = NodeBase_2 & { - type: 'or'; - left: Expression_2; - right: Expression_2; -}; - -// @public (undocumented) -export class Parser { - constructor(); - // (undocumented) - addPlugin(type: PluginType, plugin: ParserPlugin): void; - // (undocumented) - static parse(input: string): Ast.Node[]; - // (undocumented) - parse(input: string): Ast.Node[]; -} - -// @public (undocumented) -export type ParserPlugin = (nodes: Cst.Node[]) => Cst.Node[]; - -// @public (undocumented) -export type PluginType = 'validate' | 'transform'; - -// @public (undocumented) -function PROP(target: Prop_2['target'], name: Prop_2['name'], loc?: { - start: number; - end: number; -}): Prop_2; - -// @public (undocumented) -type Prop = NodeBase & { - type: 'prop'; - target: Expression; - name: string; -}; - -// @public (undocumented) -type Prop_2 = NodeBase_2 & { - type: 'prop'; - target: Expression_2; - name: string; -}; - -// @public (undocumented) -type PropChain = NodeBase_2 & { - type: 'propChain'; - name: string; -}; - -// @public (undocumented) -function reprValue(value: Value, literalLike?: boolean, processedObjects?: Set): string; - -// @public (undocumented) -const RETURN: (v: VReturn['value']) => Value; - -// @public (undocumented) -type Return = NodeBase & { - type: 'return'; - expr: Expression; -}; - -// @public (undocumented) -type Return_2 = NodeBase_2 & { - type: 'return'; - expr: Expression_2; -}; - -// @public (undocumented) -class RuntimeError extends AiScriptError { - constructor(message: string, info?: any); -} - -// @public (undocumented) -export class Scope { - constructor(layerdStates?: Scope['layerdStates'], parent?: Scope, name?: Scope['name']); - add(name: string, val: Value): void; - assign(name: string, val: Value): void; - // (undocumented) - createChildScope(states?: Map, name?: Scope['name']): Scope; - exists(name: string): boolean; - get(name: string): Value; - getAll(): Map; - // (undocumented) - name: string; - // (undocumented) - opts: { - log?(type: string, params: Record): void; - onUpdated?(name: string, value: Value): void; - }; -} - -// @public (undocumented) -type Statement = Definition | Return | Each | For | Loop | Break | Continue | Assign | AddAssign | SubAssign; - -// @public (undocumented) -type Statement_2 = Definition_2 | Return_2 | Attribute_2 | // AST -Each_2 | For_2 | Loop_2 | Break_2 | Continue_2 | Assign_2 | AddAssign_2 | SubAssign_2; - -// @public (undocumented) -const STR: (str: VStr['value']) => VStr; - -// @public (undocumented) -type Str = NodeBase & { - type: 'str'; - value: string; -}; - -// @public (undocumented) -type Str_2 = NodeBase_2 & ChainProp & { - type: 'str'; - value: string; -}; - -// @public (undocumented) -type SubAssign = NodeBase & { - type: 'subAssign'; - dest: Expression; - expr: Expression; -}; - -// @public (undocumented) -type SubAssign_2 = NodeBase_2 & { - type: 'subAssign'; - dest: Expression_2; - expr: Expression_2; -}; - -// @public (undocumented) -class SyntaxError_2 extends AiScriptError { - constructor(message: string, info?: any); -} - -// @public (undocumented) -type Tmpl = NodeBase & { - type: 'tmpl'; - tmpl: (string | Expression)[]; -}; - -// @public (undocumented) -type Tmpl_2 = NodeBase_2 & ChainProp & { - type: 'tmpl'; - tmpl: (string | Expression_2)[]; -}; - -// @public (undocumented) -const TRUE: { - type: "bool"; - value: boolean; -}; - -// @public (undocumented) -class TypeError_2 extends AiScriptError { - constructor(message: string, info?: any); -} - -// @public (undocumented) -type TypeSource = NamedTypeSource | FnTypeSource; - -// @public (undocumented) -type TypeSource_2 = NamedTypeSource_2 | FnTypeSource_2; - -// @public (undocumented) -const unWrapRet: (v: Value) => Value; - -declare namespace utils { - export { - expectAny, - assertBoolean, - assertFunction, - assertString, - assertNumber, - assertObject, - assertArray, - isBoolean, - isFunction, - isString, - isNumber, - isObject, - isArray, - eq, - valToString, - valToJs, - jsToVal, - getLangVersion, - reprValue - } -} -export { utils } - -// @public (undocumented) -function valToJs(val: Value): any; - -// @public (undocumented) -function valToString(val: Value, simple?: boolean): string; - -// @public (undocumented) -type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VReturn | VBreak | VContinue) & Attr_2; - -declare namespace values { - export { - VNull, - VBool, - VNum, - VStr, - VArr, - VObj, - VFn, - VReturn, - VBreak, - VContinue, - Attr_2 as Attr, - Value, - NULL, - TRUE, - FALSE, - NUM, - STR, - BOOL, - OBJ, - ARR, - FN, - FN_NATIVE, - RETURN, - BREAK, - CONTINUE, - unWrapRet - } -} -export { values } - -// @public (undocumented) -type VArr = { - type: 'arr'; - value: Value[]; -}; - -// @public (undocumented) -type VBool = { - type: 'bool'; - value: boolean; -}; - -// @public (undocumented) -type VBreak = { - type: 'break'; - value: null; -}; - -// @public (undocumented) -type VContinue = { - type: 'continue'; - value: null; -}; - -// @public (undocumented) -type VFn = { - type: 'fn'; - args?: string[]; - statements?: Node_2[]; - native?: (args: (Value | undefined)[], opts: { - call: (fn: VFn, args: Value[]) => Promise; - registerAbortHandler: (handler: () => void) => void; - unregisterAbortHandler: (handler: () => void) => void; - }) => Value | Promise | void; - scope?: Scope; -}; - -// @public (undocumented) -type VNull = { - type: 'null'; -}; - -// @public (undocumented) -type VNum = { - type: 'num'; - value: number; -}; - -// @public (undocumented) -type VObj = { - type: 'obj'; - value: Map; -}; - -// @public (undocumented) -type VReturn = { - type: 'return'; - value: Value; -}; - -// @public (undocumented) -type VStr = { - type: 'str'; - value: string; -}; - -// (No @packageDocumentation comment for this package) - -``` +## API Report File for "@syuilo/aiscript" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// Warning: (ae-forgotten-export) The symbol "NodeBase" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +type AddAssign = NodeBase & { + type: 'addAssign'; + dest: Expression; + expr: Expression; +}; + +// Warning: (ae-forgotten-export) The symbol "NodeBase_2" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +type AddAssign_2 = NodeBase_2 & { + type: 'addAssign'; + dest: Expression_2; + expr: Expression_2; +}; + +// @public (undocumented) +abstract class AiScriptError extends Error { + constructor(message: string, info?: any); + // (undocumented) + info?: any; +} + +// @public (undocumented) +type And = NodeBase & { + type: 'and'; + left: Expression; + right: Expression; +}; + +// @public (undocumented) +type And_2 = NodeBase_2 & { + type: 'and'; + left: Expression_2; + right: Expression_2; +}; + +// @public (undocumented) +const ARR: (arr: VArr['value']) => VArr; + +// @public (undocumented) +type Arr = NodeBase & { + type: 'arr'; + value: Expression[]; +}; + +// Warning: (ae-forgotten-export) The symbol "ChainProp" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +type Arr_2 = NodeBase_2 & ChainProp & { + type: 'arr'; + value: Expression_2[]; +}; + +// @public (undocumented) +function assertArray(val: Value | null | undefined): asserts val is VArr; + +// @public (undocumented) +function assertBoolean(val: Value | null | undefined): asserts val is VBool; + +// @public (undocumented) +function assertFunction(val: Value | null | undefined): asserts val is VFn; + +// @public (undocumented) +function assertNumber(val: Value | null | undefined): asserts val is VNum; + +// @public (undocumented) +function assertObject(val: Value | null | undefined): asserts val is VObj; + +// @public (undocumented) +function assertString(val: Value | null | undefined): asserts val is VStr; + +// @public (undocumented) +type Assign = NodeBase & { + type: 'assign'; + dest: Expression; + expr: Expression; +}; + +// @public (undocumented) +type Assign_2 = NodeBase_2 & { + type: 'assign'; + dest: Expression_2; + expr: Expression_2; +}; + +declare namespace Ast { + export { + isStatement, + isExpression, + Loc, + Node_2 as Node, + Statement, + Expression, + Namespace, + Meta, + Definition, + Attribute, + Return, + Each, + For, + Loop, + Break, + Continue, + AddAssign, + SubAssign, + Assign, + Not, + And, + Or, + If, + Fn, + Match, + Block, + Exists, + Tmpl, + Str, + Num, + Bool, + Null, + Obj, + Arr, + Identifier, + Call, + Index, + Prop, + TypeSource, + NamedTypeSource, + FnTypeSource + } +} +export { Ast } + +// @public (undocumented) +type Attr_2 = { + attr?: { + name: string; + value: Value; + }[]; +}; + +// @public (undocumented) +type Attribute = NodeBase & { + type: 'attr'; + name: string; + value: Expression; +}; + +// @public (undocumented) +type Attribute_2 = NodeBase_2 & { + type: 'attr'; + name: string; + value: Expression_2; +}; + +// @public (undocumented) +type Block = NodeBase & { + type: 'block'; + statements: (Statement | Expression)[]; +}; + +// @public (undocumented) +type Block_2 = NodeBase_2 & ChainProp & { + type: 'block'; + statements: (Statement_2 | Expression_2)[]; +}; + +// @public (undocumented) +const BOOL: (bool: VBool['value']) => VBool; + +// @public (undocumented) +type Bool = NodeBase & { + type: 'bool'; + value: boolean; +}; + +// @public (undocumented) +type Bool_2 = NodeBase_2 & ChainProp & { + type: 'bool'; + value: boolean; +}; + +// @public (undocumented) +const BREAK: () => Value; + +// @public (undocumented) +type Break = NodeBase & { + type: 'break'; +}; + +// @public (undocumented) +type Break_2 = NodeBase_2 & { + type: 'break'; +}; + +// @public (undocumented) +function CALL(target: Call_2['target'], args: Call_2['args'], loc?: { + start: number; + end: number; +}): Call_2; + +// @public (undocumented) +type Call = NodeBase & { + type: 'call'; + target: Expression; + args: Expression[]; +}; + +// @public (undocumented) +type Call_2 = NodeBase_2 & { + type: 'call'; + target: Expression_2; + args: Expression_2[]; +}; + +// @public (undocumented) +type CallChain = NodeBase_2 & { + type: 'callChain'; + args: Expression_2[]; +}; + +// @public (undocumented) +type ChainMember = CallChain | IndexChain | PropChain; + +// @public (undocumented) +const CONTINUE: () => Value; + +// @public (undocumented) +type Continue = NodeBase & { + type: 'continue'; +}; + +// @public (undocumented) +type Continue_2 = NodeBase_2 & { + type: 'continue'; +}; + +declare namespace Cst { + export { + isStatement_2 as isStatement, + isExpression_2 as isExpression, + hasChainProp, + CALL, + INDEX, + PROP, + Node_3 as Node, + Statement_2 as Statement, + Expression_2 as Expression, + Namespace_2 as Namespace, + Meta_2 as Meta, + Definition_2 as Definition, + Attribute_2 as Attribute, + Return_2 as Return, + Each_2 as Each, + For_2 as For, + Loop_2 as Loop, + Break_2 as Break, + Continue_2 as Continue, + AddAssign_2 as AddAssign, + SubAssign_2 as SubAssign, + Assign_2 as Assign, + InfixOperator, + Infix, + Not_2 as Not, + And_2 as And, + Or_2 as Or, + If_2 as If, + Fn_2 as Fn, + Match_2 as Match, + Block_2 as Block, + Exists_2 as Exists, + Tmpl_2 as Tmpl, + Str_2 as Str, + Num_2 as Num, + Bool_2 as Bool, + Null_2 as Null, + Obj_2 as Obj, + Arr_2 as Arr, + Identifier_2 as Identifier, + ChainMember, + CallChain, + IndexChain, + PropChain, + Call_2 as Call, + Index_2 as Index, + Prop_2 as Prop, + TypeSource_2 as TypeSource, + NamedTypeSource_2 as NamedTypeSource, + FnTypeSource_2 as FnTypeSource + } +} +export { Cst } + +// @public (undocumented) +type Definition = NodeBase & { + type: 'def'; + name: string; + varType?: TypeSource; + expr: Expression; + mut: boolean; + attr: Attribute[]; +}; + +// @public (undocumented) +type Definition_2 = NodeBase_2 & { + type: 'def'; + name: string; + varType?: TypeSource_2; + expr: Expression_2; + mut: boolean; + attr?: Attribute_2[]; +}; + +// @public (undocumented) +type Each = NodeBase & { + type: 'each'; + var: string; + items: Expression; + for: Statement | Expression; +}; + +// @public (undocumented) +type Each_2 = NodeBase_2 & { + type: 'each'; + var: string; + items: Expression_2; + for: Statement_2 | Expression_2; +}; + +// @public (undocumented) +function eq(a: Value, b: Value): boolean; + +// @public (undocumented) +const ERROR: (name: string, info?: Value) => Value; + +declare namespace errors { + export { + AiScriptError, + SyntaxError_2 as SyntaxError, + TypeError_2 as TypeError, + RuntimeError, + IndexOutOfRangeError + } +} +export { errors } + +// @public (undocumented) +type Exists = NodeBase & { + type: 'exists'; + identifier: Identifier; +}; + +// @public (undocumented) +type Exists_2 = NodeBase_2 & ChainProp & { + type: 'exists'; + identifier: Identifier_2; +}; + +// @public (undocumented) +function expectAny(val: Value | null | undefined): asserts val is Value; + +// @public (undocumented) +type Expression = If | Fn | Match | Block | Exists | Tmpl | Str | Num | Bool | Null | Obj | Arr | Not | And | Or | Identifier | Call | Index | Prop; + +// @public (undocumented) +type Expression_2 = Infix | Not_2 | And_2 | Or_2 | If_2 | Fn_2 | Match_2 | Block_2 | Exists_2 | Tmpl_2 | Str_2 | Num_2 | Bool_2 | Null_2 | Obj_2 | Arr_2 | Identifier_2 | Call_2 | // IR +Index_2 | // IR +Prop_2; + +// @public (undocumented) +const FALSE: { + type: "bool"; + value: boolean; +}; + +// @public (undocumented) +const FN: (args: VFn['args'], statements: VFn['statements'], scope: VFn['scope']) => VFn; + +// @public (undocumented) +type Fn = NodeBase & { + type: 'fn'; + args: { + name: string; + argType?: TypeSource; + }[]; + retType?: TypeSource; + children: (Statement | Expression)[]; +}; + +// @public (undocumented) +type Fn_2 = NodeBase_2 & ChainProp & { + type: 'fn'; + args: { + name: string; + argType?: TypeSource_2; + }[]; + retType?: TypeSource_2; + children: (Statement_2 | Expression_2)[]; +}; + +// @public (undocumented) +const FN_NATIVE: (fn: VFn['native']) => VFn; + +// @public (undocumented) +type FnTypeSource = NodeBase & { + type: 'fnTypeSource'; + args: TypeSource[]; + result: TypeSource; +}; + +// @public (undocumented) +type FnTypeSource_2 = NodeBase_2 & { + type: 'fnTypeSource'; + args: TypeSource_2[]; + result: TypeSource_2; +}; + +// @public (undocumented) +type For = NodeBase & { + type: 'for'; + var?: string; + from?: Expression; + to?: Expression; + times?: Expression; + for: Statement | Expression; +}; + +// @public (undocumented) +type For_2 = NodeBase_2 & { + type: 'for'; + var?: string; + from?: Expression_2; + to?: Expression_2; + times?: Expression_2; + for: Statement_2 | Expression_2; +}; + +// @public (undocumented) +function getLangVersion(input: string): string | null; + +// @public (undocumented) +function hasChainProp(x: T): x is T & ChainProp; + +// @public (undocumented) +type Identifier = NodeBase & { + type: 'identifier'; + name: string; +}; + +// @public (undocumented) +type Identifier_2 = NodeBase_2 & ChainProp & { + type: 'identifier'; + name: string; +}; + +// @public (undocumented) +type If = NodeBase & { + type: 'if'; + cond: Expression; + then: Statement | Expression; + elseif: { + cond: Expression; + then: Statement | Expression; + }[]; + else?: Statement | Expression; +}; + +// @public (undocumented) +type If_2 = NodeBase_2 & { + type: 'if'; + cond: Expression_2; + then: Statement_2 | Expression_2; + elseif: { + cond: Expression_2; + then: Statement_2 | Expression_2; + }[]; + else?: Statement_2 | Expression_2; +}; + +// @public (undocumented) +function INDEX(target: Index_2['target'], index: Index_2['index'], loc?: { + start: number; + end: number; +}): Index_2; + +// @public (undocumented) +type Index = NodeBase & { + type: 'index'; + target: Expression; + index: Expression; +}; + +// @public (undocumented) +type Index_2 = NodeBase_2 & { + type: 'index'; + target: Expression_2; + index: Expression_2; +}; + +// @public (undocumented) +type IndexChain = NodeBase_2 & { + type: 'indexChain'; + index: Expression_2; +}; + +// @public (undocumented) +class IndexOutOfRangeError extends RuntimeError { + constructor(message: string, info?: any); +} + +// @public (undocumented) +type Infix = NodeBase_2 & { + type: 'infix'; + operands: Expression_2[]; + operators: InfixOperator[]; +}; + +// @public (undocumented) +type InfixOperator = '||' | '&&' | '==' | '!=' | '<=' | '>=' | '<' | '>' | '+' | '-' | '*' | '^' | '/' | '%'; + +// @public (undocumented) +export class Interpreter { + constructor(vars: Record, opts?: { + in?(q: string): Promise; + out?(value: Value): void; + log?(type: string, params: Record): void; + maxStep?: number; + }); + // (undocumented) + abort(): void; + // (undocumented) + static collectMetadata(script?: Ast.Node[]): Map | undefined; + // (undocumented) + exec(script?: Ast.Node[]): Promise; + // (undocumented) + execFn(fn: VFn, args: Value[]): Promise; + // (undocumented) + registerAbortHandler(handler: () => void): void; + // (undocumented) + scope: Scope; + // (undocumented) + stepCount: number; + // (undocumented) + unregisterAbortHandler(handler: () => void): void; +} + +// @public (undocumented) +function isArray(val: Value): val is VArr; + +// @public (undocumented) +function isBoolean(val: Value): val is VBool; + +// @public (undocumented) +function isExpression(x: Node_2): x is Expression; + +// @public (undocumented) +function isExpression_2(x: Node_3): x is Expression_2; + +// @public (undocumented) +function isFunction(val: Value): val is VFn; + +// @public (undocumented) +function isNumber(val: Value): val is VNum; + +// @public (undocumented) +function isObject(val: Value): val is VObj; + +// @public (undocumented) +function isStatement(x: Node_2): x is Statement; + +// @public (undocumented) +function isStatement_2(x: Node_3): x is Statement_2; + +// @public (undocumented) +function isString(val: Value): val is VStr; + +// @public (undocumented) +function jsToVal(val: any): Value; + +// @public +type Loc = { + start: number; + end: number; +}; + +// @public (undocumented) +type Loop = NodeBase & { + type: 'loop'; + statements: (Statement | Expression)[]; +}; + +// @public (undocumented) +type Loop_2 = NodeBase_2 & { + type: 'loop'; + statements: (Statement_2 | Expression_2)[]; +}; + +// @public (undocumented) +type Match = NodeBase & { + type: 'match'; + about: Expression; + qs: { + q: Expression; + a: Statement | Expression; + }[]; + default?: Statement | Expression; +}; + +// @public (undocumented) +type Match_2 = NodeBase_2 & ChainProp & { + type: 'match'; + about: Expression_2; + qs: { + q: Expression_2; + a: Statement_2 | Expression_2; + }[]; + default?: Statement_2 | Expression_2; +}; + +// @public (undocumented) +type Meta = NodeBase & { + type: 'meta'; + name: string | null; + value: Expression; +}; + +// @public (undocumented) +type Meta_2 = NodeBase_2 & { + type: 'meta'; + name: string | null; + value: Expression_2; +}; + +// @public (undocumented) +type NamedTypeSource = NodeBase & { + type: 'namedTypeSource'; + name: string; + inner?: TypeSource; +}; + +// @public (undocumented) +type NamedTypeSource_2 = NodeBase_2 & { + type: 'namedTypeSource'; + name: string; + inner?: TypeSource_2; +}; + +// @public (undocumented) +type Namespace = NodeBase & { + type: 'ns'; + name: string; + members: (Definition | Namespace)[]; +}; + +// @public (undocumented) +type Namespace_2 = NodeBase_2 & { + type: 'ns'; + name: string; + members: (Definition_2 | Namespace_2)[]; +}; + +// @public (undocumented) +type Node_2 = Namespace | Meta | Statement | Expression | TypeSource; + +// @public +type Node_3 = Namespace_2 | Meta_2 | Statement_2 | Expression_2 | ChainMember | TypeSource_2; + +// @public (undocumented) +type Not = NodeBase & { + type: 'not'; + expr: Expression; +}; + +// @public (undocumented) +type Not_2 = NodeBase_2 & { + type: 'not'; + expr: Expression_2; +}; + +// @public (undocumented) +const NULL: { + type: "null"; +}; + +// @public (undocumented) +type Null = NodeBase & { + type: 'null'; +}; + +// @public (undocumented) +type Null_2 = NodeBase_2 & ChainProp & { + type: 'null'; +}; + +// @public (undocumented) +const NUM: (num: VNum['value']) => VNum; + +// @public (undocumented) +type Num = NodeBase & { + type: 'num'; + value: number; +}; + +// @public (undocumented) +type Num_2 = NodeBase_2 & ChainProp & { + type: 'num'; + value: number; +}; + +// @public (undocumented) +const OBJ: (obj: VObj['value']) => VObj; + +// @public (undocumented) +type Obj = NodeBase & { + type: 'obj'; + value: Map; +}; + +// @public (undocumented) +type Obj_2 = NodeBase_2 & ChainProp & { + type: 'obj'; + value: Map; +}; + +// @public (undocumented) +type Or = NodeBase & { + type: 'or'; + left: Expression; + right: Expression; +}; + +// @public (undocumented) +type Or_2 = NodeBase_2 & { + type: 'or'; + left: Expression_2; + right: Expression_2; +}; + +// @public (undocumented) +export class Parser { + constructor(); + // (undocumented) + addPlugin(type: PluginType, plugin: ParserPlugin): void; + // (undocumented) + static parse(input: string): Ast.Node[]; + // (undocumented) + parse(input: string): Ast.Node[]; +} + +// @public (undocumented) +export type ParserPlugin = (nodes: Cst.Node[]) => Cst.Node[]; + +// @public (undocumented) +export type PluginType = 'validate' | 'transform'; + +// @public (undocumented) +function PROP(target: Prop_2['target'], name: Prop_2['name'], loc?: { + start: number; + end: number; +}): Prop_2; + +// @public (undocumented) +type Prop = NodeBase & { + type: 'prop'; + target: Expression; + name: string; +}; + +// @public (undocumented) +type Prop_2 = NodeBase_2 & { + type: 'prop'; + target: Expression_2; + name: string; +}; + +// @public (undocumented) +type PropChain = NodeBase_2 & { + type: 'propChain'; + name: string; +}; + +// @public (undocumented) +function reprValue(value: Value, literalLike?: boolean, processedObjects?: Set): string; + +// @public (undocumented) +const RETURN: (v: VReturn['value']) => Value; + +// @public (undocumented) +type Return = NodeBase & { + type: 'return'; + expr: Expression; +}; + +// @public (undocumented) +type Return_2 = NodeBase_2 & { + type: 'return'; + expr: Expression_2; +}; + +// @public (undocumented) +class RuntimeError extends AiScriptError { + constructor(message: string, info?: any); +} + +// @public (undocumented) +export class Scope { + constructor(layerdStates?: Scope['layerdStates'], parent?: Scope, name?: Scope['name']); + add(name: string, val: Value): void; + assign(name: string, val: Value): void; + // (undocumented) + createChildScope(states?: Map, name?: Scope['name']): Scope; + exists(name: string): boolean; + get(name: string): Value; + getAll(): Map; + // (undocumented) + name: string; + // (undocumented) + opts: { + log?(type: string, params: Record): void; + onUpdated?(name: string, value: Value): void; + }; +} + +// @public (undocumented) +type Statement = Definition | Return | Each | For | Loop | Break | Continue | Assign | AddAssign | SubAssign; + +// @public (undocumented) +type Statement_2 = Definition_2 | Return_2 | Attribute_2 | // AST +Each_2 | For_2 | Loop_2 | Break_2 | Continue_2 | Assign_2 | AddAssign_2 | SubAssign_2; + +// @public (undocumented) +const STR: (str: VStr['value']) => VStr; + +// @public (undocumented) +type Str = NodeBase & { + type: 'str'; + value: string; +}; + +// @public (undocumented) +type Str_2 = NodeBase_2 & ChainProp & { + type: 'str'; + value: string; +}; + +// @public (undocumented) +type SubAssign = NodeBase & { + type: 'subAssign'; + dest: Expression; + expr: Expression; +}; + +// @public (undocumented) +type SubAssign_2 = NodeBase_2 & { + type: 'subAssign'; + dest: Expression_2; + expr: Expression_2; +}; + +// @public (undocumented) +class SyntaxError_2 extends AiScriptError { + constructor(message: string, info?: any); +} + +// @public (undocumented) +type Tmpl = NodeBase & { + type: 'tmpl'; + tmpl: (string | Expression)[]; +}; + +// @public (undocumented) +type Tmpl_2 = NodeBase_2 & ChainProp & { + type: 'tmpl'; + tmpl: (string | Expression_2)[]; +}; + +// @public (undocumented) +const TRUE: { + type: "bool"; + value: boolean; +}; + +// @public (undocumented) +class TypeError_2 extends AiScriptError { + constructor(message: string, info?: any); +} + +// @public (undocumented) +type TypeSource = NamedTypeSource | FnTypeSource; + +// @public (undocumented) +type TypeSource_2 = NamedTypeSource_2 | FnTypeSource_2; + +// @public (undocumented) +const unWrapRet: (v: Value) => Value; + +declare namespace utils { + export { + expectAny, + assertBoolean, + assertFunction, + assertString, + assertNumber, + assertObject, + assertArray, + isBoolean, + isFunction, + isString, + isNumber, + isObject, + isArray, + eq, + valToString, + valToJs, + jsToVal, + getLangVersion, + reprValue + } +} +export { utils } + +// @public (undocumented) +function valToJs(val: Value): any; + +// @public (undocumented) +function valToString(val: Value, simple?: boolean): string; + +// @public (undocumented) +type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VReturn | VBreak | VContinue | VError) & Attr_2; + +declare namespace values { + export { + VNull, + VBool, + VNum, + VStr, + VArr, + VObj, + VFn, + VReturn, + VBreak, + VContinue, + VError, + Attr_2 as Attr, + Value, + NULL, + TRUE, + FALSE, + NUM, + STR, + BOOL, + OBJ, + ARR, + FN, + FN_NATIVE, + RETURN, + BREAK, + CONTINUE, + unWrapRet, + ERROR + } +} +export { values } + +// @public (undocumented) +type VArr = { + type: 'arr'; + value: Value[]; +}; + +// @public (undocumented) +type VBool = { + type: 'bool'; + value: boolean; +}; + +// @public (undocumented) +type VBreak = { + type: 'break'; + value: null; +}; + +// @public (undocumented) +type VContinue = { + type: 'continue'; + value: null; +}; + +// @public (undocumented) +type VError = { + type: 'error'; + value: string; + info?: Value; +}; + +// @public (undocumented) +type VFn = { + type: 'fn'; + args?: string[]; + statements?: Node_2[]; + native?: (args: (Value | undefined)[], opts: { + call: (fn: VFn, args: Value[]) => Promise; + registerAbortHandler: (handler: () => void) => void; + unregisterAbortHandler: (handler: () => void) => void; + }) => Value | Promise | void; + scope?: Scope; +}; + +// @public (undocumented) +type VNull = { + type: 'null'; +}; + +// @public (undocumented) +type VNum = { + type: 'num'; + value: number; +}; + +// @public (undocumented) +type VObj = { + type: 'obj'; + value: Map; +}; + +// @public (undocumented) +type VReturn = { + type: 'return'; + value: Value; +}; + +// @public (undocumented) +type VStr = { + type: 'str'; + value: string; +}; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts index a7ffea54..f46e20b3 100644 --- a/src/interpreter/lib/std.ts +++ b/src/interpreter/lib/std.ts @@ -1,7 +1,7 @@ /* eslint-disable no-empty-pattern */ import { v4 as uuid } from 'uuid'; import seedrandom from 'seedrandom'; -import { NUM, STR, FN_NATIVE, FALSE, TRUE, ARR, NULL, BOOL, OBJ } from '../value.js'; +import { NUM, STR, FN_NATIVE, FALSE, TRUE, ARR, NULL, BOOL, OBJ, ERROR } from '../value.js'; import { assertNumber, assertString, assertBoolean, valToJs, jsToVal, assertFunction, assertObject, eq, expectAny, assertArray, reprValue } from '../util.js'; import { RuntimeError } from '../../error.js'; import type { Value } from '../value.js'; @@ -152,7 +152,11 @@ export const std: Record = { 'Json:parse': FN_NATIVE(([json]) => { assertString(json); - return jsToVal(JSON.parse(json.value)); + try { + return jsToVal(JSON.parse(json.value)); + } catch (e) { + return ERROR('not_json'); + } }), 'Json:parsable': FN_NATIVE(([str]) => { diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts index fdd51b22..3784f8d0 100644 --- a/src/interpreter/primitive-props.ts +++ b/src/interpreter/primitive-props.ts @@ -2,9 +2,9 @@ import { substring, length, indexOf, toArray } from 'stringz'; import { RuntimeError } from '../error.js'; import { assertArray, assertBoolean, assertFunction, assertNumber, assertString, expectAny } from './util.js'; import { ARR, FALSE, FN_NATIVE, NULL, NUM, STR, TRUE } from './value.js'; -import type { Value, VArr, VFn, VNum, VStr } from './value.js'; +import type { Value, VArr, VFn, VNum, VStr, VError } from './value.js'; -type VWithPP = VNum|VStr|VArr; +type VWithPP = VNum|VStr|VArr|VError; const PRIMITIVE_PROPS: { [key in VWithPP['type']]: { [key: string]: (target: Value) => Value } @@ -221,6 +221,12 @@ const PRIMITIVE_PROPS: { return target; }), }, + + error: { + name: (target: VError): VStr => STR(target.value), + + info: (target: VError): Value => target.info ?? NULL, + }, } as const; export function getPrimProp(target: Value, name: string): Value { diff --git a/src/interpreter/value.ts b/src/interpreter/value.ts index 44db6d51..420ccfb7 100644 --- a/src/interpreter/value.ts +++ b/src/interpreter/value.ts @@ -57,6 +57,12 @@ export type VContinue = { value: null; }; +export type VError = { + type: 'error'; + value: string; + info?: Value; +}; + export type Attr = { attr?: { name: string; @@ -64,7 +70,7 @@ export type Attr = { }[]; }; -export type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VReturn | VBreak | VContinue) & Attr; +export type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VReturn | VBreak | VContinue | VError) & Attr; export const NULL = { type: 'null' as const, @@ -134,3 +140,9 @@ export const CONTINUE = (): Value => ({ }); export const unWrapRet = (v: Value): Value => v.type === 'return' ? v.value : v; + +export const ERROR = (name: string, info?: Value): Value => ({ + type: 'error' as const, + value: name, + info: info, +}); diff --git a/test/index.ts b/test/index.ts index 6e4c977c..2da98120 100644 --- a/test/index.ts +++ b/test/index.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { Parser, Interpreter, utils, errors, Ast } from '../src'; -import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE } from '../src/interpreter/value'; +import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE, ERROR } from '../src/interpreter/value'; import { RuntimeError } from '../src/error'; const exe = (program: string): Promise => new Promise((ok, err) => { @@ -2762,32 +2762,33 @@ describe('std', () => { test.concurrent('parsable', async () => { [ - '', 'null', - 'hoge', '"hoge"', - '[', '[]', - '{}' + '{}', ].forEach(async (str) => { const res = await exe(` - <: Json:parsable('${str}') + <: [ + Json:parsable('${str}') + Json:stringify(Json:parse('${str}')) + ] `); - assert.deepEqual(res.type, 'bool'); - if (res.value) { - await exe(` - <: Json:parse('${str}') - `); - } else { - try { - await exe(` - <: Json:parse('${str}') - `); - } catch (e) { - if (e instanceof SyntaxError) return; - } - assert.fail() - } + eq(res, ARR([TRUE, STR(str)])); + }); + }); + test.concurrent('unparsable', async () => { + [ + '', + 'hoge', + '[', + ].forEach(async (str) => { + const res = await exe(` + <: [ + Json:parsable('${str}') + Json:parse('${str}') + ] + `); + eq(res, ARR([FALSE, ERROR('not_json')])); }); }); });