Skip to content

Commit 02f4fb1

Browse files
authored
名前空間内において属性の値が評価されない問題を修正 (#1002)
1 parent 58ff36c commit 02f4fb1

3 files changed

Lines changed: 100 additions & 24 deletions

File tree

src/interpreter/index.ts

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ export class Interpreter {
258258

259259
const value = await this._eval(node.expr, nsScope, []);
260260
assertValue(value);
261+
262+
await this.evalAndSetAttr(node.attr, value, scope, []);
263+
261264
if (
262265
node.expr.type === 'fn'
263266
&& isFunction(value)
@@ -302,6 +305,9 @@ export class Interpreter {
302305

303306
const value = this._evalSync(node.expr, nsScope, []);
304307
assertValue(value);
308+
309+
this.evalAndSetAttrSync(node.attr, value, scope, []);
310+
305311
if (
306312
node.expr.type === 'fn'
307313
&& isFunction(value)
@@ -648,18 +654,7 @@ export class Interpreter {
648654
if (isControl(value)) {
649655
return value;
650656
}
651-
if (node.attr.length > 0) {
652-
const attrs: Value['attr'] = [];
653-
for (const nAttr of node.attr) {
654-
const value = await this._eval(nAttr.value, scope, callStack);
655-
assertValue(value);
656-
attrs.push({
657-
name: nAttr.name,
658-
value,
659-
});
660-
}
661-
value.attr = attrs;
662-
}
657+
await this.evalAndSetAttr(node.attr, value, scope, callStack);
663658
if (
664659
node.expr.type === 'fn'
665660
&& node.dest.type === 'identifier'
@@ -1192,18 +1187,7 @@ export class Interpreter {
11921187
if (isControl(value)) {
11931188
return value;
11941189
}
1195-
if (node.attr.length > 0) {
1196-
const attrs: Value['attr'] = [];
1197-
for (const nAttr of node.attr) {
1198-
const value = this._evalSync(nAttr.value, scope, callStack);
1199-
assertValue(value);
1200-
attrs.push({
1201-
name: nAttr.name,
1202-
value,
1203-
});
1204-
}
1205-
value.attr = attrs;
1206-
}
1190+
this.evalAndSetAttrSync(node.attr, value, scope, callStack);
12071191
if (
12081192
node.expr.type === 'fn'
12091193
&& node.dest.type === 'identifier'
@@ -1666,6 +1650,38 @@ export class Interpreter {
16661650
this.unpauseHandlers = [];
16671651
}
16681652

1653+
@autobind
1654+
private async evalAndSetAttr(attr: Ast.Attribute[], value: Value, scope: Scope, callStack: readonly CallInfo[]): Promise<void> {
1655+
if (attr.length > 0) {
1656+
const attrs: Value['attr'] = [];
1657+
for (const nAttr of attr) {
1658+
const value = await this._eval(nAttr.value, scope, callStack);
1659+
assertValue(value);
1660+
attrs.push({
1661+
name: nAttr.name,
1662+
value,
1663+
});
1664+
}
1665+
value.attr = attrs;
1666+
}
1667+
}
1668+
1669+
@autobind
1670+
private evalAndSetAttrSync(attr: Ast.Attribute[], value: Value, scope: Scope, callStack: readonly CallInfo[]): void {
1671+
if (attr.length > 0) {
1672+
const attrs: Value['attr'] = [];
1673+
for (const nAttr of attr) {
1674+
const value = this._evalSync(nAttr.value, scope, callStack);
1675+
assertValue(value);
1676+
attrs.push({
1677+
name: nAttr.name,
1678+
value,
1679+
});
1680+
}
1681+
value.attr = attrs;
1682+
}
1683+
}
1684+
16691685
@autobind
16701686
private define(scope: Scope, dest: Ast.Expression, value: Value, isMutable: boolean): void {
16711687
switch (dest.type) {

test/interpreter.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as assert from 'assert';
22
import { describe, expect, test, vi, beforeEach, afterEach } from 'vitest';
33
import { Parser, Interpreter, values, errors, utils, Ast } from '../src';
4+
import { FALSE, NUM, OBJ, STR, TRUE, Value } from '../src/interpreter/value';
45

56
let { FN_NATIVE } = values;
67
let { AiScriptRuntimeError, AiScriptIndexOutOfRangeError, AiScriptHostsideError } = errors;
@@ -324,3 +325,61 @@ describe('pause', () => {
324325
});
325326
});
326327
});
328+
329+
describe('Attribute', () => {
330+
const getAttr = async (name: string, script: string): Promise<Value['attr']> => {
331+
const parser = new Parser();
332+
const interpreter = new Interpreter({});
333+
const ast = parser.parse(script);
334+
await interpreter.exec(ast);
335+
const value = interpreter.scope.get(name);
336+
return value.attr;
337+
};
338+
339+
test.concurrent('no attribute', async () => {
340+
const attr = await getAttr('f', `
341+
@f() {}
342+
`);
343+
expect(attr).toBeUndefined();
344+
});
345+
346+
test.concurrent('single attribute', async () => {
347+
const attr = await getAttr('f', `
348+
#[x 42]
349+
@f() {}
350+
`);
351+
expect(attr).toStrictEqual([{ name: 'x', value: NUM(42) }]);
352+
});
353+
354+
test.concurrent('multiple attributes', async () => {
355+
const attr = await getAttr('f', `
356+
#[o { a: 1, b: 2 }]
357+
#[s "ai"]
358+
#[b false]
359+
@f() {}
360+
`);
361+
expect(attr).toStrictEqual([
362+
{ name: 'o', value: OBJ(new Map([['a', NUM(1)], ['b', NUM(2)]])) },
363+
{ name: 's', value: STR('ai') },
364+
{ name: 'b', value: FALSE },
365+
]);
366+
});
367+
368+
test.concurrent('single attribute without value', async () => {
369+
const attr = await getAttr('f', `
370+
#[x]
371+
@f() {}
372+
`);
373+
expect(attr).toStrictEqual([{ name: 'x', value: TRUE }]);
374+
});
375+
376+
test.concurrent('attribute under namespace', async () => {
377+
const attr = await getAttr('Ns:f', `
378+
:: Ns {
379+
#[x 42]
380+
@f() {}
381+
}
382+
`);
383+
expect(attr).toStrictEqual([{ name: 'x', value: NUM(42) }]);
384+
});
385+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fix: 名前空間内において属性の値が評価されない問題を修正

0 commit comments

Comments
 (0)