Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/parser/syntaxes/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ function parseReference(s: ITokenStream): Ast.Identifier {

/**
* ```abnf
* Object = "{" [ObjectKey ":" Expr *(SEP IDENT ":" Expr) [SEP]] "}"
* Object = "{" [(ObjectKey ":" Expr / IDENT) *(SEP (ObjectKey ":" Expr / IDENT)) [SEP]] "}"
* ```
*/
function parseObject(s: ITokenStream, isStatic: boolean): Ast.Obj {
Expand All @@ -592,16 +592,25 @@ function parseObject(s: ITokenStream, isStatic: boolean): Ast.Obj {

const map = new Map<string, Ast.Expression>();
while (!s.is(TokenKind.CloseBrace)) {
const startPos = s.getPos();

const isIdentifierKey = s.is(TokenKind.Identifier);
const k = parseObjectKey(s);
if (map.has(k)) {
throw new AiScriptSyntaxError(`Key ${k} is duplicated.`, s.getPos());
}
s.next();

s.expect(TokenKind.Colon);
s.next();
let v: Ast.Expression;

const v = parseExpr(s, isStatic);
if (!isIdentifierKey || isStatic) s.expect(TokenKind.Colon);
if (s.is(TokenKind.Colon)) {
s.next();

v = parseExpr(s, isStatic);
} else {
v = NODE('identifier', { name: k }, startPos, s.getPos());
}

map.set(k, v);

Expand Down
4 changes: 4 additions & 0 deletions test/aison.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ greet()`)).toThrow();
expect(() => AiSON.parse('{key: (3 + 5)}')).toThrow();
});

test.concurrent('not allowed: object shorthand', () => {
expect(() => AiSON.parse('{key}')).toThrow();
});

test.concurrent('not allowed: labeled expression', () => {
expect(() => AiSON.parse('#label: eval { 1 }')).toThrow();
});
Expand Down
20 changes: 20 additions & 0 deletions test/literals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,26 @@ describe('literal', () => {
});
});

test.concurrent('obj (shorthand)', async () => {
const res = await exe(`
let a = 1
<: { a }
`);
eq(res, OBJ(new Map([['a', NUM(1)]])));
});

test.concurrent('obj (reserved word as shorthand)', async () => {
await expect(() => exe(`
<: { exists }
`)).rejects.toThrow(AiScriptSyntaxError);
});

test.concurrent('obj (string as shorthand)', async () => {
await expect(() => exe(`
<: { "hoge" }
`)).rejects.toThrow(AiScriptSyntaxError);
});

test.concurrent('obj (escaped reserved word as key)', async () => {
await expect(async () => await exe(`
<: {
Expand Down
7 changes: 7 additions & 0 deletions test/syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,13 @@ describe('Variable declaration', () => {
`);
eq(res, ARR([NUM(1), NUM(2)]));
});
test.concurrent('destructuring declaration with shorthand', async () => {
const res = await exe(`
let { value } = { value: 1 }
<: value
`);
eq(res, NUM(1));
});
test.concurrent('empty function', async () => {
const res = await exe(`
@hoge() { }
Expand Down
2 changes: 2 additions & 0 deletions unreleased/obj-shorthand-sugar-syntax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- オブジェクトリテラルとオブジェクトの分割代入構文内で、キーと同名の変数を参照する省略記法を使用できるようになりました。
- 例えば`{ hoge }`は`{ hoge: hoge }`と等価です。
Loading