Skip to content

Commit 8ab13f8

Browse files
committed
Merge branch 'master' into enhance/950_zero-part-ommitable-decimal-literal
2 parents ac8e903 + 008538a commit 8ab13f8

15 files changed

Lines changed: 861 additions & 266 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
[Read translated version (en)](./translations/en/CHANGELOG.md)
22

3+
# 1.1.1
4+
5+
- Fix: オブジェクトリテラルのプロパティ名に一部の予約語を記述できなかった問題を修正
6+
37
# 1.1.0
48

59
- オブジェクトリテラルのプロパティ名に予約語を直接記述できるようになりました。

src/interpreter/index.ts

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ export class Interpreter {
265265
) {
266266
value.name = nsScope.getNsPrefix() + node.dest.name;
267267
}
268-
await this.define(nsScope, node.dest, value, node.mut);
268+
this.define(nsScope, node.dest, value, node.mut);
269269

270270
break;
271271
}
@@ -309,7 +309,7 @@ export class Interpreter {
309309
) {
310310
value.name = nsScope.getNsPrefix() + node.dest.name;
311311
}
312-
this.defineSync(nsScope, node.dest, value, node.mut);
312+
this.define(nsScope, node.dest, value, node.mut);
313313

314314
break;
315315
}
@@ -668,7 +668,7 @@ export class Interpreter {
668668
) {
669669
value.name = node.dest.name;
670670
}
671-
await this.define(scope, node.dest, value, node.mut);
671+
this.define(scope, node.dest, value, node.mut);
672672
return NULL;
673673
}
674674

@@ -1212,7 +1212,7 @@ export class Interpreter {
12121212
) {
12131213
value.name = node.dest.name;
12141214
}
1215-
this.defineSync(scope, node.dest, value, node.mut);
1215+
this.define(scope, node.dest, value, node.mut);
12161216
return NULL;
12171217
}
12181218

@@ -1667,34 +1667,7 @@ export class Interpreter {
16671667
}
16681668

16691669
@autobind
1670-
private async define(scope: Scope, dest: Ast.Expression, value: Value, isMutable: boolean): Promise<void> {
1671-
switch (dest.type) {
1672-
case 'identifier': {
1673-
scope.add(dest.name, { isMutable, value });
1674-
break;
1675-
}
1676-
case 'arr': {
1677-
assertArray(value);
1678-
await Promise.all(dest.value.map(
1679-
(item, index) => this.define(scope, item, value.value[index] ?? NULL, isMutable),
1680-
));
1681-
break;
1682-
}
1683-
case 'obj': {
1684-
assertObject(value);
1685-
await Promise.all([...dest.value].map(
1686-
([key, item]) => this.define(scope, item, value.value.get(key) ?? NULL, isMutable),
1687-
));
1688-
break;
1689-
}
1690-
default: {
1691-
throw new AiScriptRuntimeError('The left-hand side of an definition expression must be a variable.');
1692-
}
1693-
}
1694-
}
1695-
1696-
@autobind
1697-
private defineSync(scope: Scope, dest: Ast.Expression, value: Value, isMutable: boolean): void {
1670+
private define(scope: Scope, dest: Ast.Expression, value: Value, isMutable: boolean): void {
16981671
switch (dest.type) {
16991672
case 'identifier': {
17001673
scope.add(dest.name, { isMutable, value });
@@ -1703,14 +1676,14 @@ export class Interpreter {
17031676
case 'arr': {
17041677
assertArray(value);
17051678
dest.value.map(
1706-
(item, index) => this.defineSync(scope, item, value.value[index] ?? NULL, isMutable),
1679+
(item, index) => this.define(scope, item, value.value[index] ?? NULL, isMutable),
17071680
);
17081681
break;
17091682
}
17101683
case 'obj': {
17111684
assertObject(value);
17121685
[...dest.value].map(
1713-
([key, item]) => this.defineSync(scope, item, value.value.get(key) ?? NULL, isMutable),
1686+
([key, item]) => this.define(scope, item, value.value.get(key) ?? NULL, isMutable),
17141687
);
17151688
break;
17161689
}

src/interpreter/lib/std.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,21 @@ export const std: Record<string, Value> = {
406406
})
407407
));
408408
}),
409+
410+
'Obj:from_kvs': FN_NATIVE(([kvs]) => {
411+
assertArray(kvs);
412+
return OBJ(new Map(
413+
kvs.value.map((kv) => {
414+
assertArray(kv);
415+
const [key, value] = kv.value;
416+
assertString(key);
417+
expectAny(value);
418+
return [key.value, value];
419+
}),
420+
));
421+
}),
409422
//#endregion
410-
423+
411424
//#region Error
412425
'Error:create': FN_NATIVE(([name, info]) => {
413426
assertString(name);

src/parser/plugins/validate-keyword.ts

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,34 @@ import { visitNode } from '../visit.js';
33
import type * as Ast from '../../node.js';
44

55
// 予約語となっている識別子があるかを確認する。
6-
// - キーワードは字句解析の段階でそれぞれのKeywordトークンとなるため除外
6+
// - キーワードは字句解析の段階でそれぞれのKeywordトークンとなるが、エスケープシーケンスを含む場合はIdentifierトークンとなるので検証を行う。
77
// - 文脈キーワードは識別子に利用できるため除外
88

99
const reservedWord = [
10+
// 使用中の語
11+
'null',
12+
'true',
13+
'false',
14+
'each',
15+
'for',
16+
'loop',
17+
'do',
18+
'while',
19+
'break',
20+
'continue',
21+
'match',
22+
'case',
23+
'default',
24+
'if',
25+
'elif',
26+
'else',
27+
'return',
28+
'eval',
29+
'var',
30+
'let',
31+
'exists',
32+
33+
// 使用予定の語
1034
'as',
1135
'async',
1236
'attr',
@@ -52,25 +76,36 @@ const reservedWord = [
5276
'new',
5377
];
5478

55-
function throwReservedWordError(name: string, loc: Ast.Loc): void {
56-
throw new AiScriptSyntaxError(`Reserved word "${name}" cannot be used as variable name.`, loc.start);
79+
function validateName(name: string, pos: Ast.Pos): void {
80+
if (reservedWord.includes(name)) {
81+
throwReservedWordError(name, pos);
82+
}
83+
}
84+
85+
function validateTypeName(name: string, pos: Ast.Pos): void {
86+
if (name === 'null') {
87+
return;
88+
}
89+
validateName(name, pos);
90+
}
91+
92+
function throwReservedWordError(name: string, pos: Ast.Pos): never {
93+
throw new AiScriptSyntaxError(`Reserved word "${name}" cannot be used as variable name.`, pos);
5794
}
5895

5996
function validateDest(node: Ast.Node): Ast.Node {
6097
return visitNode(node, node => {
6198
switch (node.type) {
6299
case 'null': {
63-
throwReservedWordError(node.type, node.loc);
100+
throwReservedWordError(node.type, node.loc.start);
64101
break;
65102
}
66103
case 'bool': {
67-
throwReservedWordError(`${node.value}`, node.loc);
104+
throwReservedWordError(`${node.value}`, node.loc.start);
68105
break;
69106
}
70107
case 'identifier': {
71-
if (reservedWord.includes(node.name)) {
72-
throwReservedWordError(node.name, node.loc);
73-
}
108+
validateName(node.name, node.loc.start);
74109
break;
75110
}
76111
}
@@ -81,9 +116,7 @@ function validateDest(node: Ast.Node): Ast.Node {
81116

82117
function validateTypeParams(node: Ast.Fn | Ast.FnTypeSource): void {
83118
for (const typeParam of node.typeParams) {
84-
if (reservedWord.includes(typeParam.name)) {
85-
throwReservedWordError(typeParam.name, node.loc);
86-
}
119+
validateTypeName(typeParam.name, node.loc.start);
87120
}
88121
}
89122

@@ -97,48 +130,46 @@ function validateNode(node: Ast.Node): Ast.Node {
97130
case 'attr':
98131
case 'identifier':
99132
case 'prop': {
100-
if (reservedWord.includes(node.name)) {
101-
throwReservedWordError(node.name, node.loc);
102-
}
133+
validateName(node.name, node.loc.start);
103134
break;
104135
}
105136
case 'meta': {
106-
if (node.name != null && reservedWord.includes(node.name)) {
107-
throwReservedWordError(node.name, node.loc);
137+
if (node.name != null) {
138+
validateName(node.name, node.loc.start);
108139
}
109140
break;
110141
}
111142
case 'each': {
112-
if (node.label != null && reservedWord.includes(node.label)) {
113-
throwReservedWordError(node.label, node.loc);
143+
if (node.label != null) {
144+
validateName(node.label, node.loc.start);
114145
}
115146
validateDest(node.var);
116147
break;
117148
}
118149
case 'for': {
119-
if (node.label != null && reservedWord.includes(node.label)) {
120-
throwReservedWordError(node.label, node.loc);
150+
if (node.label != null) {
151+
validateName(node.label, node.loc.start);
121152
}
122-
if (node.var != null && reservedWord.includes(node.var)) {
123-
throwReservedWordError(node.var, node.loc);
153+
if (node.var != null) {
154+
validateName(node.var, node.loc.start);
124155
}
125156
break;
126157
}
127158
case 'loop': {
128-
if (node.label != null && reservedWord.includes(node.label)) {
129-
throwReservedWordError(node.label, node.loc);
159+
if (node.label != null) {
160+
validateName(node.label, node.loc.start);
130161
}
131162
break;
132163
}
133164
case 'break': {
134-
if (node.label != null && reservedWord.includes(node.label)) {
135-
throwReservedWordError(node.label, node.loc);
165+
if (node.label != null) {
166+
validateName(node.label, node.loc.start);
136167
}
137168
break;
138169
}
139170
case 'continue': {
140-
if (node.label != null && reservedWord.includes(node.label)) {
141-
throwReservedWordError(node.label, node.loc);
171+
if (node.label != null) {
172+
validateName(node.label, node.loc.start);
142173
}
143174
break;
144175
}
@@ -149,18 +180,8 @@ function validateNode(node: Ast.Node): Ast.Node {
149180
}
150181
break;
151182
}
152-
case 'obj': {
153-
for (const name of node.value.keys()) {
154-
if (reservedWord.includes(name)) {
155-
throwReservedWordError(name, node.loc);
156-
}
157-
}
158-
break;
159-
}
160183
case 'namedTypeSource': {
161-
if (reservedWord.includes(node.name)) {
162-
throwReservedWordError(node.name, node.loc);
163-
}
184+
validateTypeName(node.name, node.loc.start);
164185
break;
165186
}
166187
case 'fnTypeSource': {

0 commit comments

Comments
 (0)