Skip to content

Commit

Permalink
属性名の予約語を禁止 (#863)
Browse files Browse the repository at this point in the history
  • Loading branch information
takejohn authored Nov 30, 2024
1 parent 952e921 commit 5654151
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/parser/visit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ function visitNodeInner(node: Ast.Node, fn: (node: Ast.Node, ancestors: Ast.Node
// nested nodes
switch (result.type) {
case 'def': {
result.attr = result.attr.map((attr) => visitNodeInner(attr, fn, ancestors) as Ast.Attribute);
result.expr = visitNodeInner(result.expr, fn, ancestors) as Ast.Definition['expr'];
break;
}
Expand Down
64 changes: 54 additions & 10 deletions test/keywords.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { describe, expect, test } from 'vitest';
import { Parser, Interpreter } from '../src';
import { Parser } from '../src';
import { AiScriptSyntaxError } from '../src/error';
import { exe } from './testutils';

const reservedWords = [
// 使用中の語
'null',
'true',
'false',
Expand All @@ -25,9 +25,55 @@ const reservedWords = [
'var',
'let',
'exists',

// 使用予定の語
// 文脈キーワードは識別子に利用できるため除外
'as',
'async',
'attr',
'attribute',
'await',
'catch',
'class',
// 'const',
'component',
'constructor',
// 'def',
'dictionary',
'enum',
'export',
'finally',
'fn',
// 'func',
// 'function',
'hash',
'in',
'interface',
'out',
'private',
'public',
'ref',
'static',
'struct',
'table',
'this',
'throw',
'trait',
'try',
'undefined',
'use',
'using',
'when',
'yield',
'import',
'is',
'meta',
'module',
'namespace',
'new',
] as const;

const sampleCodes = Object.entries({
const sampleCodes = Object.entries<(word: string) => string>({
variable: word =>
`
let ${word} = "ai"
Expand Down Expand Up @@ -66,24 +112,22 @@ const sampleCodes = Object.entries({
`,
});

function pickRandom<T>(arr: T[]): T {
return arr[Math.floor(Math.random() * arr.length)];
}
const parser = new Parser();

describe.each(
sampleCodes
)('reserved word validation on %s', (_, sampleCode) => {

test.concurrent.each(
[pickRandom(reservedWords)]
reservedWords
)('%s must be rejected', (word) => {
return expect(exe(sampleCode(word))).rejects.toThrow(AiScriptSyntaxError);
expect(() => parser.parse(sampleCode(word))).toThrow(AiScriptSyntaxError);
});

test.concurrent.each(
[pickRandom(reservedWords)]
reservedWords
)('%scat must be allowed', (word) => {
return exe(sampleCode(word+'cat'));
parser.parse(sampleCode(word+'cat'));
});

});

0 comments on commit 5654151

Please sign in to comment.