diff --git a/CHANGELOG.md b/CHANGELOG.md index 2758d8c0..c0abc1e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ [Read translated version (en)](./translations/en/CHANGELOG.md) +# 1.1.2 + +- Fix: 関数の引数の初期値内に不正なreturn文がある場合に文法エラーにならない問題を修正 + # 1.1.1 - Fix: オブジェクトリテラルのプロパティ名に一部の予約語を記述できなかった問題を修正 diff --git a/etc/aiscript.api.md b/etc/aiscript.api.md index 18d82220..3b9cb869 100644 --- a/etc/aiscript.api.md +++ b/etc/aiscript.api.md @@ -21,7 +21,7 @@ type AddAssign = NodeBase & { }; // @public (undocumented) -export const AISCRIPT_VERSION: "1.1.0"; +export const AISCRIPT_VERSION: "1.1.2"; // @public (undocumented) abstract class AiScriptError extends Error { diff --git a/package-lock.json b/package-lock.json index c0c9ef54..b837f9ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@syuilo/aiscript", - "version": "1.1.1", + "version": "1.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@syuilo/aiscript", - "version": "1.1.1", + "version": "1.1.2", "license": "MIT", "dependencies": { "seedrandom": "3.0.5", diff --git a/package.json b/package.json index b7c0cb0d..f81b5a34 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "@syuilo/aiscript", - "version": "1.1.1", + "version": "1.1.2", "description": "AiScript implementation", "author": "syuilo ", "license": "MIT", diff --git a/src/parser/plugins/validate-jump-statements.ts b/src/parser/plugins/validate-jump-statements.ts index 9828bca9..64fbe267 100644 --- a/src/parser/plugins/validate-jump-statements.ts +++ b/src/parser/plugins/validate-jump-statements.ts @@ -3,6 +3,19 @@ import { AiScriptSyntaxError } from '../../error.js'; import type * as Ast from '../../node.js'; +function getClosestAncestorFunction(node: Ast.Return, ancestors: Ast.Node[]): Ast.Fn | undefined { + let child: Ast.Node = node; + for (let i = ancestors.length - 1; i >= 0; i--) { + const ancestor = ancestors[i]!; + // return文が関数のデフォルト引数の中にある場合は、今見つかった関数ではなくさらに上の関数がこのreturn文に対応する。 + if (ancestor.type === 'fn' && !ancestor.params.some((param) => param.default != null && param.default === child)) { + return ancestor; + } + child = ancestor; + } + return; +} + function getCorrespondingBlock(ancestors: Ast.Node[], label?: string): Ast.Each | Ast.For | Ast.Loop | Ast.If | Ast.Match | Ast.Block | undefined { for (let i = ancestors.length - 1; i >= 0; i--) { const ancestor = ancestors[i]!; @@ -33,7 +46,8 @@ function getCorrespondingBlock(ancestors: Ast.Node[], label?: string): Ast.Each function validateNode(node: Ast.Node, ancestors: Ast.Node[]): Ast.Node { switch (node.type) { case 'return': { - if (!ancestors.some(({ type }) => type === 'fn')) { + const closestAncestorFunction = getClosestAncestorFunction(node, ancestors); + if (closestAncestorFunction === undefined) { throw new AiScriptSyntaxError('return must be inside function', node.loc.start); } break; diff --git a/test/jump-statements.ts b/test/jump-statements.ts index 905898dd..633474b6 100644 --- a/test/jump-statements.ts +++ b/test/jump-statements.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import { describe, test } from 'vitest'; -import { utils } from '../src'; +import { errors, utils } from '../src'; import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE, ERROR ,FN_NATIVE } from '../src/interpreter/value'; import { AiScriptRuntimeError, AiScriptSyntaxError } from '../src/error'; import { exe, getMeta, eq } from './testutils'; @@ -481,7 +481,8 @@ describe('return', () => { <: f() `); eq(res, NUM(1)); - await assert.rejects(() => exe('<: @(x = eval { return 1 }){}')); + await assert.rejects(() => exe('<: @(x = eval { return 1 }){}'), errors.AiScriptSyntaxError); + await assert.rejects(() => exe('<: @(a = @(b = eval { return 0 }){}){}'), errors.AiScriptSyntaxError); }); test.concurrent('in template', async () => {