Fix parsing of 'impl' and 'trait'
This commit is contained in:
parent
930bc57bc3
commit
045f8a181f
1 changed files with 121 additions and 32 deletions
153
src/parser.ts
153
src/parser.ts
|
@ -77,11 +77,8 @@ import {
|
||||||
BoltMacroCall,
|
BoltMacroCall,
|
||||||
createBoltMacroCall,
|
createBoltMacroCall,
|
||||||
createBoltMemberExpression,
|
createBoltMemberExpression,
|
||||||
createBoltModulePath,
|
|
||||||
BoltModulePath,
|
|
||||||
isBoltSymbol,
|
|
||||||
BoltIdentifierChild,
|
|
||||||
BoltDeclarationLike,
|
BoltDeclarationLike,
|
||||||
|
BoltTraitOrImplElement,
|
||||||
} from "./ast"
|
} from "./ast"
|
||||||
|
|
||||||
import { parseForeignLanguage } from "./foreign"
|
import { parseForeignLanguage } from "./foreign"
|
||||||
|
@ -95,7 +92,7 @@ import {
|
||||||
createTokenStream,
|
createTokenStream,
|
||||||
Package,
|
Package,
|
||||||
} from "./common"
|
} from "./common"
|
||||||
import { Stream, uniq } from "./util"
|
import { Stream, uniq, assert } from "./util"
|
||||||
|
|
||||||
export type BoltTokenStream = Stream<BoltToken>;
|
export type BoltTokenStream = Stream<BoltToken>;
|
||||||
|
|
||||||
|
@ -1228,60 +1225,121 @@ export class Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
public parseTraitDeclaration(tokens: BoltTokenStream): BoltTraitDeclaration {
|
public parseTraitDeclaration(tokens: BoltTokenStream): BoltTraitDeclaration {
|
||||||
|
|
||||||
let modifiers = 0;
|
let modifiers = 0;
|
||||||
|
let typeParams = null;
|
||||||
|
let name;
|
||||||
|
let typeBoundExpr = null;
|
||||||
|
let elements = null;
|
||||||
|
|
||||||
|
// Parse the 'pub' keyword, if present
|
||||||
let t0 = tokens.get();
|
let t0 = tokens.get();
|
||||||
const firstToken = t0;
|
const firstToken = t0;
|
||||||
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
||||||
modifiers |= BoltModifiers.IsPublic;
|
modifiers |= BoltModifiers.IsPublic;
|
||||||
t0 = tokens.get();
|
t0 = tokens.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// By now, we should encounter the 'trait' keyword'
|
||||||
assertToken(t0, SyntaxKind.BoltTraitKeyword);
|
assertToken(t0, SyntaxKind.BoltTraitKeyword);
|
||||||
|
|
||||||
|
// Type parameters are introduced by '<' and end with '>'
|
||||||
|
const t2 = tokens.peek();
|
||||||
|
if (t2.kind === SyntaxKind.BoltLtSign) {
|
||||||
|
tokens.get();
|
||||||
|
typeParams = this.parseGenericTypeParameters(tokens);
|
||||||
|
const t2 = tokens.get();
|
||||||
|
assertToken(t2, SyntaxKind.BoltGtSign);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A trait must be named by an identifier
|
||||||
const t1 = tokens.get();
|
const t1 = tokens.get();
|
||||||
assertToken(t1, SyntaxKind.BoltIdentifier);
|
assertToken(t1, SyntaxKind.BoltIdentifier);
|
||||||
|
name = t1 as BoltIdentifier;
|
||||||
|
|
||||||
let lastToken = t1;
|
let lastToken = t1;
|
||||||
const t2 = tokens.peek();
|
|
||||||
let typeParams = null
|
if (tokens.peek().kind === SyntaxKind.BoltColon) {
|
||||||
let elements = null;
|
tokens.get();
|
||||||
if (t2.kind === SyntaxKind.BoltLtSign || t2.kind === SyntaxKind.BoltBraced) {
|
typeBoundExpr = this.parseTypeExpression(tokens);
|
||||||
if (t2.kind === SyntaxKind.BoltLtSign) {
|
|
||||||
tokens.get();
|
|
||||||
typeParams = this.parseGenericTypeParameters(tokens);
|
|
||||||
tokens.get();
|
|
||||||
}
|
|
||||||
const t3 = tokens.get();
|
|
||||||
assertToken(t3, SyntaxKind.BoltBraced);
|
|
||||||
elements = this.parseSourceElements(createTokenStream(t3));
|
|
||||||
lastToken = t3;
|
|
||||||
}
|
}
|
||||||
const result = createBoltTraitDeclaration(modifiers, t1 as BoltIdentifier, typeParams, elements as BoltDeclaration[]);
|
|
||||||
|
// The trait may optionally have 'fn ...' and 'type ..' elements wrapped in braces.
|
||||||
|
const t3 = tokens.peek();
|
||||||
|
if (t2.kind === SyntaxKind.BoltBraced) {
|
||||||
|
const t3 = tokens.get();
|
||||||
|
lastToken = t3;
|
||||||
|
const innerTokens = createTokenStream(t3);
|
||||||
|
elements = this.parseTraitOrImplElements(innerTokens);
|
||||||
|
assertNoTokens(innerTokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and return the resulting AST node
|
||||||
|
const result = createBoltTraitDeclaration(modifiers, typeParams, name, typeBoundExpr, elements);
|
||||||
setOrigNodeRange(result, firstToken, lastToken);
|
setOrigNodeRange(result, firstToken, lastToken);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public parseImplDeclaration(tokens: BoltTokenStream): BoltImplDeclaration {
|
public parseImplDeclaration(tokens: BoltTokenStream): BoltImplDeclaration {
|
||||||
|
|
||||||
let modifiers = 0;
|
let modifiers = 0;
|
||||||
|
let typeParams = null;
|
||||||
|
let traitTypeExpr = null;
|
||||||
|
let name;
|
||||||
|
|
||||||
|
// Parse the 'pub' keyword
|
||||||
let t0 = tokens.get();
|
let t0 = tokens.get();
|
||||||
const firstToken = t0;
|
const firstToken = t0;
|
||||||
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
||||||
modifiers |= BoltModifiers.IsPublic;
|
modifiers |= BoltModifiers.IsPublic;
|
||||||
t0 = tokens.get();
|
t0 = tokens.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// By now, we should encounter the 'impl' keyword
|
||||||
assertToken(t0, SyntaxKind.BoltImplKeyword);
|
assertToken(t0, SyntaxKind.BoltImplKeyword);
|
||||||
const t1 = tokens.get();
|
|
||||||
assertToken(t1, SyntaxKind.BoltIdentifier);
|
// Type parameters are introduced by '<' and end with '>'
|
||||||
const t2 = tokens.get();
|
const t1 = tokens.peek();
|
||||||
assertToken(t2, SyntaxKind.BoltForKeyword);
|
if (t1.kind === SyntaxKind.BoltLtSign) {
|
||||||
const typeExpr = this.parseTypeExpression(tokens);
|
|
||||||
let typeParams = null
|
|
||||||
const t3 = tokens.peek();
|
|
||||||
if (t3.kind === SyntaxKind.BoltLtSign) {
|
|
||||||
typeParams = this.parseGenericTypeParameters(tokens);
|
typeParams = this.parseGenericTypeParameters(tokens);
|
||||||
|
const t2 = tokens.get();
|
||||||
|
assertToken(t2, SyntaxKind.BoltGtSign);
|
||||||
}
|
}
|
||||||
const t4 = tokens.get();
|
|
||||||
assertToken(t4, SyntaxKind.BoltBraced);
|
// Check for the 'for' keyword occuring before '{' .. '}'
|
||||||
const elements = this.parseSourceElements(createTokenStream(t4));
|
let i = 2;
|
||||||
const result = createBoltImplDeclaration(modifiers, t1 as BoltIdentifier, typeExpr, typeParams, elements as BoltDeclaration[]);
|
let foundForKeyword = false;
|
||||||
setOrigNodeRange(result, firstToken, t4);
|
while (true) {
|
||||||
|
const tn = tokens.peek(i++);
|
||||||
|
if (tn.kind === SyntaxKind.BoltBraced || tn.kind === SyntaxKind.EndOfFile) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tn.kind === SyntaxKind.BoltForKeyword) {
|
||||||
|
foundForKeyword = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundForKeyword) {
|
||||||
|
|
||||||
|
traitTypeExpr = this.parseTypeExpression(tokens);
|
||||||
|
|
||||||
|
// Skip the 'for' keyword itself
|
||||||
|
tokens.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the name of the type that this implementation is for
|
||||||
|
const t3 = tokens.get();
|
||||||
|
assertToken(t3, SyntaxKind.BoltIdentifier);
|
||||||
|
name = t3 as BoltIdentifier;
|
||||||
|
|
||||||
|
// Parse all 'fn ...' and 'type ...' elements
|
||||||
|
const t5 = tokens.get();
|
||||||
|
assertToken(t5, SyntaxKind.BoltBraced);
|
||||||
|
const elements = this.parseSourceElements(createTokenStream(t5));
|
||||||
|
|
||||||
|
// Create and return the result
|
||||||
|
const result = createBoltImplDeclaration(modifiers, typeParams, name, traitTypeExpr, elements as BoltDeclaration[]);
|
||||||
|
setOrigNodeRange(result, firstToken, t5);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1471,6 +1529,37 @@ export class Parser {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public parseTraitOrImplElements(tokens: BoltTokenStream): BoltTraitOrImplElement[] {
|
||||||
|
const elements: BoltTraitOrImplElement[] = [];
|
||||||
|
while (true) {
|
||||||
|
const t0 = tokens.peek();
|
||||||
|
if (t0.kind === SyntaxKind.EndOfFile) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (t0.kind === SyntaxKind.BoltSemi) {
|
||||||
|
tokens.get();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
elements.push(this.parseTraitOrImplElement(tokens))
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public parseTraitOrImplElement(tokens: BoltTokenStream): BoltTraitOrImplElement {
|
||||||
|
if (this.lookaheadIsMacroCall(tokens)) {
|
||||||
|
return this.parseMacroCall(tokens);
|
||||||
|
}
|
||||||
|
const t0 = tokens.peek();
|
||||||
|
switch (t0.kind) {
|
||||||
|
case SyntaxKind.BoltFnKeyword:
|
||||||
|
return this.parseFunctionDeclaration(tokens);
|
||||||
|
case SyntaxKind.BoltTypeKeyword:
|
||||||
|
return this.parseTypeAliasDeclaration(tokens);
|
||||||
|
default:
|
||||||
|
throw new ParseError(t0, [SyntaxKind.BoltFnKeyword, SyntaxKind.BoltTypeAliasDeclaration, SyntaxKind.BoltMacroCall])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private canParseExpression(tokens: BoltTokenStream): boolean {
|
private canParseExpression(tokens: BoltTokenStream): boolean {
|
||||||
// TODO
|
// TODO
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue