Add experimental support for match-expressions and some new patterns
This commit is contained in:
parent
bf6302b173
commit
6c29d49ac6
6 changed files with 284 additions and 15 deletions
|
@ -28,6 +28,14 @@ export class Analyser {
|
||||||
case SyntaxKind.ConstantExpression:
|
case SyntaxKind.ConstantExpression:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SyntaxKind.MatchExpression:
|
||||||
|
{
|
||||||
|
for (const arm of node.arms) {
|
||||||
|
visit(arm.expression, source);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SyntaxKind.SourceFile:
|
case SyntaxKind.SourceFile:
|
||||||
{
|
{
|
||||||
for (const element of node.elements) {
|
for (const element of node.elements) {
|
||||||
|
|
|
@ -786,13 +786,16 @@ export class Checker {
|
||||||
|
|
||||||
private createTypeVar(): TVar {
|
private createTypeVar(): TVar {
|
||||||
const typeVar = new TVar(this.nextTypeVarId++);
|
const typeVar = new TVar(this.nextTypeVarId++);
|
||||||
const context = this.contexts[this.contexts.length-1];
|
this.getContext().typeVars.add(typeVar);
|
||||||
context.typeVars.add(typeVar);
|
|
||||||
return typeVar;
|
return typeVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getContext(): InferContext {
|
||||||
|
return this.contexts[this.contexts.length-1];
|
||||||
|
}
|
||||||
|
|
||||||
private addConstraint(constraint: Constraint): void {
|
private addConstraint(constraint: Constraint): void {
|
||||||
this.contexts[this.contexts.length-1].constraints.push(constraint);
|
this.getContext().constraints.push(constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private pushContext(context: InferContext) {
|
private pushContext(context: InferContext) {
|
||||||
|
@ -805,13 +808,12 @@ export class Checker {
|
||||||
}
|
}
|
||||||
|
|
||||||
private lookup(name: string, kind: Symkind): Scheme | null {
|
private lookup(name: string, kind: Symkind): Scheme | null {
|
||||||
const context = this.contexts[this.contexts.length-1];
|
return this.getContext().env.lookup(name, kind);
|
||||||
return context.env.lookup(name, kind);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getReturnType(): Type {
|
private getReturnType(): Type {
|
||||||
const context = this.contexts[this.contexts.length-1];
|
const context = this.getContext();
|
||||||
assert(context && context.returnType !== null);
|
assert(context.returnType !== null);
|
||||||
return context.returnType;
|
return context.returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1209,6 +1211,47 @@ export class Checker {
|
||||||
case SyntaxKind.NestedExpression:
|
case SyntaxKind.NestedExpression:
|
||||||
return this.inferExpression(node.expression);
|
return this.inferExpression(node.expression);
|
||||||
|
|
||||||
|
case SyntaxKind.MatchExpression:
|
||||||
|
{
|
||||||
|
let exprType;
|
||||||
|
if (node.expression !== null) {
|
||||||
|
exprType = this.inferExpression(node.expression);
|
||||||
|
} else {
|
||||||
|
exprType = this.createTypeVar();
|
||||||
|
}
|
||||||
|
let resultType: Type = this.createTypeVar();
|
||||||
|
for (const arm of node.arms) {
|
||||||
|
const context = this.getContext();
|
||||||
|
const newEnv = new TypeEnv(context.env);
|
||||||
|
const newContext: InferContext = {
|
||||||
|
constraints: context.constraints,
|
||||||
|
typeVars: context.typeVars,
|
||||||
|
env: newEnv,
|
||||||
|
returnType: context.returnType,
|
||||||
|
};
|
||||||
|
this.pushContext(newContext);
|
||||||
|
this.addConstraint(
|
||||||
|
new CEqual(
|
||||||
|
this.inferBindings(arm.pattern, [], []),
|
||||||
|
exprType,
|
||||||
|
arm.pattern,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
this.addConstraint(
|
||||||
|
new CEqual(
|
||||||
|
resultType,
|
||||||
|
this.inferExpression(arm.expression),
|
||||||
|
arm.expression
|
||||||
|
)
|
||||||
|
);
|
||||||
|
this.popContext(newContext);
|
||||||
|
}
|
||||||
|
if (node === null) {
|
||||||
|
resultType = new TArrow([ exprType ], resultType);
|
||||||
|
}
|
||||||
|
return resultType;
|
||||||
|
}
|
||||||
|
|
||||||
case SyntaxKind.ReferenceExpression:
|
case SyntaxKind.ReferenceExpression:
|
||||||
{
|
{
|
||||||
assert(node.modulePath.length === 0);
|
assert(node.modulePath.length === 0);
|
||||||
|
@ -1430,6 +1473,42 @@ export class Checker {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.LiteralPattern:
|
||||||
|
{
|
||||||
|
let type;
|
||||||
|
switch (pattern.token.kind) {
|
||||||
|
case SyntaxKind.Integer:
|
||||||
|
type = this.getIntType();
|
||||||
|
break;
|
||||||
|
case SyntaxKind.StringLiteral:
|
||||||
|
type = this.getStringType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
type = type.shallowClone();
|
||||||
|
type.node = pattern;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.DisjunctivePattern:
|
||||||
|
{
|
||||||
|
const type = this.createTypeVar();
|
||||||
|
this.addConstraint(
|
||||||
|
new CEqual(
|
||||||
|
this.inferBindings(pattern.left, typeVars, constraints),
|
||||||
|
type,
|
||||||
|
pattern.left
|
||||||
|
)
|
||||||
|
);
|
||||||
|
this.addConstraint(
|
||||||
|
new CEqual(
|
||||||
|
this.inferBindings(pattern.right, typeVars, constraints),
|
||||||
|
type,
|
||||||
|
pattern.left
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
case SyntaxKind.StructPattern:
|
case SyntaxKind.StructPattern:
|
||||||
{
|
{
|
||||||
const scheme = this.lookup(pattern.name.text, Symkind.Type);
|
const scheme = this.lookup(pattern.name.text, Symkind.Type);
|
||||||
|
|
124
src/cst.ts
124
src/cst.ts
|
@ -79,6 +79,8 @@ export const enum SyntaxKind {
|
||||||
LBracket,
|
LBracket,
|
||||||
RBracket,
|
RBracket,
|
||||||
RArrow,
|
RArrow,
|
||||||
|
RArrowAlt,
|
||||||
|
VBar,
|
||||||
Dot,
|
Dot,
|
||||||
DotDot,
|
DotDot,
|
||||||
Comma,
|
Comma,
|
||||||
|
@ -117,6 +119,8 @@ export const enum SyntaxKind {
|
||||||
StructPattern,
|
StructPattern,
|
||||||
NestedPattern,
|
NestedPattern,
|
||||||
NamedTuplePattern,
|
NamedTuplePattern,
|
||||||
|
LiteralPattern,
|
||||||
|
DisjunctivePattern,
|
||||||
|
|
||||||
// Struct expression elements
|
// Struct expression elements
|
||||||
StructExpressionField,
|
StructExpressionField,
|
||||||
|
@ -128,6 +132,7 @@ export const enum SyntaxKind {
|
||||||
VariadicStructPatternElement,
|
VariadicStructPatternElement,
|
||||||
|
|
||||||
// Expressions
|
// Expressions
|
||||||
|
MatchExpression,
|
||||||
MemberExpression,
|
MemberExpression,
|
||||||
CallExpression,
|
CallExpression,
|
||||||
ReferenceExpression,
|
ReferenceExpression,
|
||||||
|
@ -168,6 +173,7 @@ export const enum SyntaxKind {
|
||||||
|
|
||||||
// Other nodes
|
// Other nodes
|
||||||
WrappedOperator,
|
WrappedOperator,
|
||||||
|
MatchArm,
|
||||||
Initializer,
|
Initializer,
|
||||||
QualifiedName,
|
QualifiedName,
|
||||||
TypeAssert,
|
TypeAssert,
|
||||||
|
@ -917,8 +923,30 @@ export class RArrow extends TokenBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RArrowAlt extends TokenBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.RArrowAlt;
|
||||||
|
|
||||||
|
public get text(): string {
|
||||||
|
return '=>';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VBar extends TokenBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.VBar;
|
||||||
|
|
||||||
|
public get text(): string {
|
||||||
|
return '|';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export type Token
|
export type Token
|
||||||
= RArrow
|
= RArrow
|
||||||
|
| RArrowAlt
|
||||||
|
| VBar
|
||||||
| LParen
|
| LParen
|
||||||
| RParen
|
| RParen
|
||||||
| LBrace
|
| LBrace
|
||||||
|
@ -1264,12 +1292,57 @@ export class NestedPattern extends SyntaxBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class DisjunctivePattern extends SyntaxBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.DisjunctivePattern;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
public left: Pattern,
|
||||||
|
public operator: VBar,
|
||||||
|
public right: Pattern,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFirstToken(): Token {
|
||||||
|
return this.left.getFirstToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastToken(): Token {
|
||||||
|
return this.right.getLastToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class LiteralPattern extends SyntaxBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.LiteralPattern;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
public token: StringLiteral | Integer
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFirstToken(): Token {
|
||||||
|
return this.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastToken(): Token {
|
||||||
|
return this.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export type Pattern
|
export type Pattern
|
||||||
= BindPattern
|
= BindPattern
|
||||||
| NestedPattern
|
| NestedPattern
|
||||||
| StructPattern
|
| StructPattern
|
||||||
| NamedTuplePattern
|
| NamedTuplePattern
|
||||||
| TuplePattern
|
| TuplePattern
|
||||||
|
| DisjunctivePattern
|
||||||
|
| LiteralPattern
|
||||||
|
|
||||||
export class TupleExpression extends SyntaxBase {
|
export class TupleExpression extends SyntaxBase {
|
||||||
|
|
||||||
|
@ -1475,6 +1548,56 @@ export class NamedTupleExpression extends SyntaxBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MatchArm extends SyntaxBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.MatchArm;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
public pattern: Pattern,
|
||||||
|
public rarrowAlt: RArrowAlt,
|
||||||
|
public expression: Expression,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFirstToken(): Token {
|
||||||
|
return this.pattern.getFirstToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastToken(): Token {
|
||||||
|
return this.expression.getLastToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MatchExpression extends SyntaxBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.MatchExpression;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
public matchKeyword: MatchKeyword,
|
||||||
|
public expression: Expression | null,
|
||||||
|
public arms: MatchArm[],
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFirstToken(): Token {
|
||||||
|
return this.matchKeyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastToken(): Token {
|
||||||
|
if (this.arms.length > 0) {
|
||||||
|
return this.arms[this.arms.length-1].getLastToken();
|
||||||
|
}
|
||||||
|
if (this.expression !== null) {
|
||||||
|
return this.expression.getLastToken();
|
||||||
|
}
|
||||||
|
return this.matchKeyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class ReferenceExpression extends SyntaxBase {
|
export class ReferenceExpression extends SyntaxBase {
|
||||||
|
|
||||||
public readonly kind = SyntaxKind.ReferenceExpression;
|
public readonly kind = SyntaxKind.ReferenceExpression;
|
||||||
|
@ -1592,6 +1715,7 @@ export type Expression
|
||||||
| ReferenceExpression
|
| ReferenceExpression
|
||||||
| ConstantExpression
|
| ConstantExpression
|
||||||
| TupleExpression
|
| TupleExpression
|
||||||
|
| MatchExpression
|
||||||
| NestedExpression
|
| NestedExpression
|
||||||
| PrefixExpression
|
| PrefixExpression
|
||||||
| InfixExpression
|
| InfixExpression
|
||||||
|
|
|
@ -87,6 +87,8 @@ const DESCRIPTIONS: Partial<Record<SyntaxKind, string>> = {
|
||||||
[SyntaxKind.BlockEnd]: 'the end of an indented block',
|
[SyntaxKind.BlockEnd]: 'the end of an indented block',
|
||||||
[SyntaxKind.LineFoldEnd]: 'the end of the current line-fold',
|
[SyntaxKind.LineFoldEnd]: 'the end of the current line-fold',
|
||||||
[SyntaxKind.EndOfFile]: 'end-of-file',
|
[SyntaxKind.EndOfFile]: 'end-of-file',
|
||||||
|
[SyntaxKind.RArrowAlt]: '"=>"',
|
||||||
|
[SyntaxKind.VBar]: "'|'",
|
||||||
}
|
}
|
||||||
|
|
||||||
function describeSyntaxKind(kind: SyntaxKind): string {
|
function describeSyntaxKind(kind: SyntaxKind): string {
|
||||||
|
|
|
@ -25,7 +25,6 @@ import {
|
||||||
TypeAssert,
|
TypeAssert,
|
||||||
ExprBody,
|
ExprBody,
|
||||||
BlockBody,
|
BlockBody,
|
||||||
QualifiedName,
|
|
||||||
NestedExpression,
|
NestedExpression,
|
||||||
NamedTuplePattern,
|
NamedTuplePattern,
|
||||||
StructPattern,
|
StructPattern,
|
||||||
|
@ -36,7 +35,6 @@ import {
|
||||||
InfixExpression,
|
InfixExpression,
|
||||||
TextFile,
|
TextFile,
|
||||||
CallExpression,
|
CallExpression,
|
||||||
NamedTupleExpression,
|
|
||||||
LetBodyElement,
|
LetBodyElement,
|
||||||
ReturnStatement,
|
ReturnStatement,
|
||||||
StructExpression,
|
StructExpression,
|
||||||
|
@ -56,6 +54,10 @@ import {
|
||||||
AppTypeExpression,
|
AppTypeExpression,
|
||||||
NestedPattern,
|
NestedPattern,
|
||||||
NestedTypeExpression,
|
NestedTypeExpression,
|
||||||
|
MatchArm,
|
||||||
|
MatchExpression,
|
||||||
|
LiteralPattern,
|
||||||
|
DisjunctivePattern,
|
||||||
} from "./cst"
|
} from "./cst"
|
||||||
import { Stream } from "./util";
|
import { Stream } from "./util";
|
||||||
|
|
||||||
|
@ -72,11 +74,13 @@ export class ParseError extends Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isBinaryOperatorLike(token: Token): boolean {
|
function isBinaryOperatorLike(token: Token): boolean {
|
||||||
return token.kind === SyntaxKind.CustomOperator;
|
return token.kind === SyntaxKind.CustomOperator
|
||||||
|
|| token.kind === SyntaxKind.VBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPrefixOperatorLike(token: Token): boolean {
|
function isPrefixOperatorLike(token: Token): boolean {
|
||||||
return token.kind === SyntaxKind.CustomOperator;
|
return token.kind === SyntaxKind.CustomOperator
|
||||||
|
|| token.kind === SyntaxKind.VBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
const enum OperatorMode {
|
const enum OperatorMode {
|
||||||
|
@ -295,6 +299,33 @@ export class Parser {
|
||||||
case SyntaxKind.Identifier:
|
case SyntaxKind.Identifier:
|
||||||
case SyntaxKind.IdentifierAlt:
|
case SyntaxKind.IdentifierAlt:
|
||||||
return this.parseReferenceExpression();
|
return this.parseReferenceExpression();
|
||||||
|
case SyntaxKind.Integer:
|
||||||
|
case SyntaxKind.StringLiteral:
|
||||||
|
return this.parseConstantExpression();
|
||||||
|
case SyntaxKind.MatchKeyword:
|
||||||
|
{
|
||||||
|
this.getToken();
|
||||||
|
let expression = null
|
||||||
|
const t1 = this.peekToken();
|
||||||
|
if (t1.kind !== SyntaxKind.BlockStart) {
|
||||||
|
expression = this.parseExpression();
|
||||||
|
}
|
||||||
|
this.expectToken(SyntaxKind.BlockStart);
|
||||||
|
const arms = [];
|
||||||
|
for (;;) {
|
||||||
|
const t2 = this.peekToken();
|
||||||
|
if (t2.kind === SyntaxKind.BlockEnd) {
|
||||||
|
this.getToken();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const pattern = this.parsePattern();
|
||||||
|
const rarrowAlt = this.expectToken(SyntaxKind.RArrowAlt);
|
||||||
|
const expression = this.parseExpression();
|
||||||
|
arms.push(new MatchArm(pattern, rarrowAlt, expression));
|
||||||
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
||||||
|
}
|
||||||
|
return new MatchExpression(t0, expression, arms);
|
||||||
|
}
|
||||||
case SyntaxKind.LBrace:
|
case SyntaxKind.LBrace:
|
||||||
{
|
{
|
||||||
this.getToken();
|
this.getToken();
|
||||||
|
@ -335,9 +366,6 @@ export class Parser {
|
||||||
}
|
}
|
||||||
return new StructExpression(t0, fields, rbrace);
|
return new StructExpression(t0, fields, rbrace);
|
||||||
}
|
}
|
||||||
case SyntaxKind.Integer:
|
|
||||||
case SyntaxKind.StringLiteral:
|
|
||||||
return this.parseConstantExpression();
|
|
||||||
default:
|
default:
|
||||||
this.raiseParseError(t0, [
|
this.raiseParseError(t0, [
|
||||||
SyntaxKind.NamedTupleExpression,
|
SyntaxKind.NamedTupleExpression,
|
||||||
|
@ -659,7 +687,7 @@ export class Parser {
|
||||||
return new TuplePattern(lparen, elements, rparen);
|
return new TuplePattern(lparen, elements, rparen);
|
||||||
}
|
}
|
||||||
|
|
||||||
public parsePattern(): Pattern {
|
public parsePrimitivePattern(): Pattern {
|
||||||
const t0 = this.peekToken();
|
const t0 = this.peekToken();
|
||||||
switch (t0.kind) {
|
switch (t0.kind) {
|
||||||
case SyntaxKind.LParen:
|
case SyntaxKind.LParen:
|
||||||
|
@ -684,11 +712,31 @@ export class Parser {
|
||||||
this.getToken();
|
this.getToken();
|
||||||
return new BindPattern(t0);
|
return new BindPattern(t0);
|
||||||
}
|
}
|
||||||
|
case SyntaxKind.StringLiteral:
|
||||||
|
case SyntaxKind.Integer:
|
||||||
|
{
|
||||||
|
this.getToken();
|
||||||
|
return new LiteralPattern(t0);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
this.raiseParseError(t0, [ SyntaxKind.Identifier ]);
|
this.raiseParseError(t0, [ SyntaxKind.Identifier ]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public parsePattern(): Pattern {
|
||||||
|
let result: Pattern = this.parsePrimitivePattern();
|
||||||
|
for (;;) {
|
||||||
|
const t1 = this.peekToken();
|
||||||
|
if (t1.kind !== SyntaxKind.VBar) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.getToken();
|
||||||
|
const right = this.parsePrimitivePattern();
|
||||||
|
result = new DisjunctivePattern(result, t1, right);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public parseParam(): Param {
|
public parseParam(): Param {
|
||||||
const pattern = this.parsePattern();
|
const pattern = this.parsePattern();
|
||||||
return new Param(pattern);
|
return new Param(pattern);
|
||||||
|
|
|
@ -37,6 +37,9 @@ import {
|
||||||
StructKeyword,
|
StructKeyword,
|
||||||
RArrow,
|
RArrow,
|
||||||
EnumKeyword,
|
EnumKeyword,
|
||||||
|
MatchKeyword,
|
||||||
|
RArrowAlt,
|
||||||
|
VBar,
|
||||||
} from "./cst"
|
} from "./cst"
|
||||||
import { Diagnostics, UnexpectedCharDiagnostic } from "./diagnostics"
|
import { Diagnostics, UnexpectedCharDiagnostic } from "./diagnostics"
|
||||||
import { Stream, BufferedStream, assert } from "./util";
|
import { Stream, BufferedStream, assert } from "./util";
|
||||||
|
@ -250,6 +253,10 @@ export class Scanner extends BufferedStream<Token> {
|
||||||
const text = c0 + this.takeWhile(isOperatorPart);
|
const text = c0 + this.takeWhile(isOperatorPart);
|
||||||
if (text === '->') {
|
if (text === '->') {
|
||||||
return new RArrow(startPos);
|
return new RArrow(startPos);
|
||||||
|
} else if (text === '=>') {
|
||||||
|
return new RArrowAlt(startPos);
|
||||||
|
} else if (text === '|') {
|
||||||
|
return new VBar(startPos);
|
||||||
} else if (text === '=') {
|
} else if (text === '=') {
|
||||||
return new Equals(startPos);
|
return new Equals(startPos);
|
||||||
} else if (text.endsWith('=') && text[text.length-2] !== '=') {
|
} else if (text.endsWith('=') && text[text.length-2] !== '=') {
|
||||||
|
@ -358,6 +365,7 @@ export class Scanner extends BufferedStream<Token> {
|
||||||
case 'elif': return new ElifKeyword(startPos);
|
case 'elif': return new ElifKeyword(startPos);
|
||||||
case 'struct': return new StructKeyword(startPos);
|
case 'struct': return new StructKeyword(startPos);
|
||||||
case 'enum': return new EnumKeyword(startPos);
|
case 'enum': return new EnumKeyword(startPos);
|
||||||
|
case 'match': return new MatchKeyword(startPos);
|
||||||
default:
|
default:
|
||||||
if (isUpper(text[0])) {
|
if (isUpper(text[0])) {
|
||||||
return new IdentifierAlt(text, startPos);
|
return new IdentifierAlt(text, startPos);
|
||||||
|
|
Loading…
Reference in a new issue