Skip to content
Merged
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
70 changes: 50 additions & 20 deletions src/parser/syntaxes/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,19 @@ import type * as Ast from '../../node.js';

/**
* ```abnf
* Params = "(" [IDENT *(("," / SPACE) IDENT)] ")"
* Params = "(" [IDENT [":" Type] *(SEP IDENT [":" Type])] ")"
* ```
*/
export function parseParams(s: ITokenStream): { name: string, argType?: Ast.Node }[] {
const items: { name: string, argType?: Ast.Node }[] = [];

s.nextWith(TokenKind.OpenParen);

while (s.kind !== TokenKind.CloseParen) {
// separator
if (items.length > 0) {
if (s.kind === TokenKind.Comma) {
s.next();
} else if (!s.token.hasLeftSpacing) {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}
}
if (s.kind === TokenKind.NewLine) {
s.next();
}

while (s.kind !== TokenKind.CloseParen) {
s.expect(TokenKind.Identifier);
const name = s.token.value!;
s.next();
Expand All @@ -37,6 +32,27 @@ export function parseParams(s: ITokenStream): { name: string, argType?: Ast.Node
}

items.push({ name, argType: type });

// separator
switch (s.kind as TokenKind) {
case TokenKind.NewLine: {
s.next();
break;
}
case TokenKind.Comma: {
s.next();
if (s.kind === TokenKind.NewLine) {
s.next();
}
break;
}
case TokenKind.CloseParen: {
break;
}
default: {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}
}
}

s.nextWith(TokenKind.CloseParen);
Expand All @@ -60,11 +76,21 @@ export function parseBlock(s: ITokenStream): Ast.Node[] {
while (s.kind !== TokenKind.CloseBrace) {
steps.push(parseStatement(s));

if ((s.kind as TokenKind) !== TokenKind.NewLine && (s.kind as TokenKind) !== TokenKind.CloseBrace) {
throw new AiScriptSyntaxError('Multiple statements cannot be placed on a single line.', s.token.loc);
}
while ((s.kind as TokenKind) === TokenKind.NewLine) {
s.next();
// terminator
switch (s.kind as TokenKind) {
case TokenKind.NewLine:
case TokenKind.SemiColon: {
while ([TokenKind.NewLine, TokenKind.SemiColon].includes(s.kind)) {
s.next();
}
break;
}
case TokenKind.CloseBrace: {
break;
}
default: {
throw new AiScriptSyntaxError('Multiple statements cannot be placed on a single line.', s.token.loc);
}
}
}

Expand All @@ -86,7 +112,7 @@ export function parseType(s: ITokenStream): Ast.Node {
/**
* ```abnf
* FnType = "@" "(" ParamTypes ")" "=>" Type
* ParamTypes = [Type *(("," / SPACE) Type)]
* ParamTypes = [Type *(SEP Type)]
* ```
*/
function parseFnType(s: ITokenStream): Ast.Node {
Expand All @@ -98,10 +124,14 @@ function parseFnType(s: ITokenStream): Ast.Node {
const params: Ast.Node[] = [];
while (s.kind !== TokenKind.CloseParen) {
if (params.length > 0) {
if (s.kind === TokenKind.Comma) {
s.next();
} else if (!s.token.hasLeftSpacing) {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
switch (s.kind as TokenKind) {
case TokenKind.Comma: {
s.next();
break;
}
default: {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}
}
}
const type = parseType(s);
Expand Down
143 changes: 105 additions & 38 deletions src/parser/syntaxes/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,25 +287,41 @@ function parseAtom(s: ITokenStream, isStatic: boolean): Ast.Node {
}

/**
* Call = "(" [Expr *(("," / SPACE) Expr)] ")"
* Call = "(" [Expr *(SEP Expr) [SEP]] ")"
*/
function parseCall(s: ITokenStream, target: Ast.Node): Ast.Node {
const loc = s.token.loc;
const items: Ast.Node[] = [];

s.nextWith(TokenKind.OpenParen);

if (s.kind === TokenKind.NewLine) {
s.next();
}

while (s.kind !== TokenKind.CloseParen) {
items.push(parseExpr(s, false));

// separator
if (items.length > 0) {
if (s.kind === TokenKind.Comma) {
switch (s.kind as TokenKind) {
case TokenKind.NewLine: {
s.next();
} else if (!s.token.hasLeftSpacing) {
break;
}
case TokenKind.Comma: {
s.next();
if (s.kind === TokenKind.NewLine) {
s.next();
}
break;
}
case TokenKind.CloseParen: {
break;
}
default: {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}
}

items.push(parseExpr(s, false));
}

s.nextWith(TokenKind.CloseParen);
Expand Down Expand Up @@ -377,7 +393,8 @@ function parseFnExpr(s: ITokenStream): Ast.Node {

/**
* ```abnf
* Match = "match" Expr "{" *("case" Expr "=>" BlockOrStatement) ["default" "=>" BlockOrStatement] "}"
* Match = "match" Expr "{" [MatchCases] ["default" "=>" BlockOrStatement [SEP]] "}"
* MatchCases = "case" Expr "=>" BlockOrStatement *(SEP "case" Expr "=>" BlockOrStatement) [SEP]
* ```
*/
function parseMatch(s: ITokenStream): Ast.Node {
Expand All @@ -387,24 +404,68 @@ function parseMatch(s: ITokenStream): Ast.Node {
const about = parseExpr(s, false);

s.nextWith(TokenKind.OpenBrace);
s.nextWith(TokenKind.NewLine);

if (s.kind === TokenKind.NewLine) {
s.next();
}

const qs: { q: Ast.Node, a: Ast.Node }[] = [];
while (s.kind !== TokenKind.DefaultKeyword && s.kind !== TokenKind.CloseBrace) {
s.nextWith(TokenKind.CaseKeyword);
const q = parseExpr(s, false);
s.nextWith(TokenKind.Arrow);
const a = parseBlockOrStatement(s);
s.nextWith(TokenKind.NewLine);
qs.push({ q, a });

// separator
switch (s.kind as TokenKind) {
case TokenKind.NewLine: {
s.next();
break;
}
case TokenKind.Comma: {
s.next();
if (s.kind === TokenKind.NewLine) {
s.next();
}
break;
}
case TokenKind.DefaultKeyword:
case TokenKind.CloseBrace: {
break;
}
default: {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}
}
}

let x;
if (s.kind === TokenKind.DefaultKeyword) {
s.next();
s.nextWith(TokenKind.Arrow);
x = parseBlockOrStatement(s);
s.nextWith(TokenKind.NewLine);

// separator
switch (s.kind as TokenKind) {
case TokenKind.NewLine: {
s.next();
break;
}
case TokenKind.Comma: {
s.next();
if ((s.kind as TokenKind) === TokenKind.NewLine) {
s.next();
}
break;
}
case TokenKind.CloseBrace: {
break;
}
default: {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}
}
}

s.nextWith(TokenKind.CloseBrace);
Expand Down Expand Up @@ -470,7 +531,7 @@ function parseReference(s: ITokenStream): Ast.Node {

/**
* ```abnf
* Object = "{" [IDENT ":" Expr *(("," / ";" / SPACE) IDENT ":" Expr) ["," / ";"]] "}"
* Object = "{" [IDENT ":" Expr *(SEP IDENT ":" Expr) [SEP]] "}"
* ```
*/
function parseObject(s: ITokenStream, isStatic: boolean): Ast.Node {
Expand All @@ -495,23 +556,25 @@ function parseObject(s: ITokenStream, isStatic: boolean): Ast.Node {
map.set(k, v);

// separator
if ((s.kind as TokenKind) === TokenKind.CloseBrace) {
break;
} else if (s.kind === TokenKind.Comma) {
s.next();
} else if (s.kind === TokenKind.SemiColon) {
s.next();
} else if (s.kind === TokenKind.NewLine) {
// noop
} else {
if (!s.token.hasLeftSpacing) {
switch (s.kind as TokenKind) {
case TokenKind.NewLine: {
s.next();
break;
}
case TokenKind.Comma: {
s.next();
if (s.kind === TokenKind.NewLine) {
s.next();
}
break;
}
case TokenKind.CloseBrace: {
break;
}
default: {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}
}

if (s.kind === TokenKind.NewLine) {
s.next();
}
}

s.nextWith(TokenKind.CloseBrace);
Expand All @@ -521,7 +584,7 @@ function parseObject(s: ITokenStream, isStatic: boolean): Ast.Node {

/**
* ```abnf
* Array = "[" [Expr *(("," / SPACE) Expr) [","]] "]"
* Array = "[" [Expr *(SEP Expr) [SEP]] "]"
* ```
*/
function parseArray(s: ITokenStream, isStatic: boolean): Ast.Node {
Expand All @@ -538,21 +601,25 @@ function parseArray(s: ITokenStream, isStatic: boolean): Ast.Node {
value.push(parseExpr(s, isStatic));

// separator
if ((s.kind as TokenKind) === TokenKind.CloseBracket) {
break;
} else if (s.kind === TokenKind.Comma) {
s.next();
} else if (s.kind === TokenKind.NewLine) {
// noop
} else {
if (!s.token.hasLeftSpacing) {
switch (s.kind as TokenKind) {
case TokenKind.NewLine: {
s.next();
break;
}
case TokenKind.Comma: {
s.next();
if (s.kind === TokenKind.NewLine) {
s.next();
}
break;
}
case TokenKind.CloseBracket: {
break;
}
default: {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}
}

if (s.kind === TokenKind.NewLine) {
s.next();
}
}

s.nextWith(TokenKind.CloseBracket);
Expand Down
4 changes: 2 additions & 2 deletions src/parser/syntaxes/statements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ function parseEach(s: ITokenStream): Ast.Node {

if (s.kind === TokenKind.Comma) {
s.next();
} else if (!s.token.hasLeftSpacing) {
} else {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}

Expand Down Expand Up @@ -262,7 +262,7 @@ function parseFor(s: ITokenStream): Ast.Node {

if ((s.kind as TokenKind) === TokenKind.Comma) {
s.next();
} else if (!s.token.hasLeftSpacing) {
} else {
throw new AiScriptSyntaxError('separator expected', s.token.loc);
}

Expand Down
Loading