Skip to content

Commit

Permalink
fix: ジャンプ文の挙動を変更 (#844)
Browse files Browse the repository at this point in the history
* return,break,continueをValueと別の扱いにする

* 配列や引数で最初にreturnなどが出た時点でリターン

* 不正な位置のreturn文などを文法エラーに

* テストの追加と実装の修正

* APIレポートの更新

* break,continueがループ内に見えても関数がより内側なら文法エラー

* CHANGELOG

* テンプレートリテラル内returnテスト

* Control系の型や関数の秘匿と名前変更

* 使用していない関数を削除

* APIレポートの更新

* APIレポートの修正
  • Loading branch information
takejohn authored Nov 13, 2024
1 parent 95f5f1f commit dff363b
Show file tree
Hide file tree
Showing 10 changed files with 1,098 additions and 205 deletions.
41 changes: 2 additions & 39 deletions etc/aiscript.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,6 @@ type Bool = NodeBase & {
value: boolean;
};

// @public (undocumented)
const BREAK: () => Value;

// @public (undocumented)
type Break = NodeBase & {
type: 'break';
Expand All @@ -233,9 +230,6 @@ type Call = NodeBase & {
args: Expression[];
};

// @public (undocumented)
const CONTINUE: () => Value;

// @public (undocumented)
type Continue = NodeBase & {
type: 'continue';
Expand Down Expand Up @@ -634,9 +628,6 @@ type Rem = NodeBase & {
// @public (undocumented)
function reprValue(value: Value, literalLike?: boolean, processedObjects?: Set<object>): string;

// @public (undocumented)
const RETURN: (v: VReturn["value"]) => Value;

// @public (undocumented)
type Return = NodeBase & {
type: 'return';
Expand Down Expand Up @@ -710,9 +701,6 @@ const TRUE: {
// @public (undocumented)
type TypeSource = NamedTypeSource | FnTypeSource;

// @public (undocumented)
const unWrapRet: (v: Value) => Value;

declare namespace utils {
export {
expectAny,
Expand Down Expand Up @@ -746,7 +734,7 @@ function valToJs(val: Value): JsValue;
function valToString(val: Value, simple?: boolean): string;

// @public (undocumented)
type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VReturn | VBreak | VContinue | VError) & Attr_2;
type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VError) & Attr_2;

declare namespace values {
export {
Expand All @@ -760,9 +748,6 @@ declare namespace values {
VUserFn,
VFnParam,
VNativeFn,
VReturn,
VBreak,
VContinue,
VError,
Attr_2 as Attr,
Value,
Expand All @@ -776,10 +761,6 @@ declare namespace values {
ARR,
FN,
FN_NATIVE,
RETURN,
BREAK,
CONTINUE,
unWrapRet,
ERROR
}
}
Expand All @@ -797,18 +778,6 @@ type VBool = {
value: boolean;
};

// @public (undocumented)
type VBreak = {
type: 'break';
value: null;
};

// @public (undocumented)
type VContinue = {
type: 'continue';
value: null;
};

// @public (undocumented)
type VError = {
type: 'error';
Expand Down Expand Up @@ -857,12 +826,6 @@ type VObj = {
value: Map<string, Value>;
};

// @public (undocumented)
type VReturn = {
type: 'return';
value: Value;
};

// @public (undocumented)
type VStr = {
type: 'str';
Expand All @@ -882,7 +845,7 @@ type VUserFn = VFnBase & {

// Warnings were encountered during analysis:
//
// src/interpreter/index.ts:47:4 - (ae-forgotten-export) The symbol "LogObject" needs to be exported by the entry point index.d.ts
// src/interpreter/index.ts:48: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
82 changes: 82 additions & 0 deletions src/interpreter/control.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { AiScriptRuntimeError } from '../error.js';
import type { Reference } from './reference.js';
import type { Value } from './value.js';

export type CReturn = {
type: 'return';
value: Value;
};

export type CBreak = {
type: 'break';
value: null;
};

export type CContinue = {
type: 'continue';
value: null;
};

export type Control = CReturn | CBreak | CContinue;

// Return文で値が返されたことを示すためのラッパー
export const RETURN = (v: CReturn['value']): CReturn => ({
type: 'return' as const,
value: v,
});

export const BREAK = (): CBreak => ({
type: 'break' as const,
value: null,
});

export const CONTINUE = (): CContinue => ({
type: 'continue' as const,
value: null,
});

export function unWrapRet(v: Value | Control): Value {
switch (v.type) {
case 'return':
return v.value;
default: {
assertValue(v);
return v;
}
}
}

export function assertValue(v: Value | Control): asserts v is Value {
switch (v.type) {
case 'return':
throw new AiScriptRuntimeError('Invalid return');
case 'break':
throw new AiScriptRuntimeError('Invalid break');
case 'continue':
throw new AiScriptRuntimeError('Invalid continue');
default:
v satisfies Value;
}
}

export function isControl(v: Value | Control | Reference): v is Control {
switch (v.type) {
case 'null':
case 'bool':
case 'num':
case 'str':
case 'arr':
case 'obj':
case 'fn':
case 'error':
case 'reference':
return false;
case 'return':
case 'break':
case 'continue':
return true;
}
// exhaustive check
v satisfies never;
throw new TypeError('expected value or control');
}
Loading

0 comments on commit dff363b

Please sign in to comment.