Remove TAny; support operator declarations and arrow type expressions
This commit is contained in:
parent
843be74e48
commit
7b3f1948bb
5 changed files with 186 additions and 57 deletions
|
@ -1,5 +1,7 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import "source-map-support/register"
|
||||||
|
|
||||||
import * as commonmark from "commonmark"
|
import * as commonmark from "commonmark"
|
||||||
import { sync as globSync } from "glob"
|
import { sync as globSync } from "glob"
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
101
src/checker.ts
101
src/checker.ts
|
@ -4,6 +4,7 @@ import {
|
||||||
Pattern,
|
Pattern,
|
||||||
Scope,
|
Scope,
|
||||||
SourceFile,
|
SourceFile,
|
||||||
|
SourceFileElement,
|
||||||
StructDeclaration,
|
StructDeclaration,
|
||||||
Syntax,
|
Syntax,
|
||||||
SyntaxKind,
|
SyntaxKind,
|
||||||
|
@ -526,11 +527,15 @@ export interface InferContext {
|
||||||
returnType: Type | null;
|
returnType: Type | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isFunctionDeclarationLike(node: LetDeclaration): boolean {
|
||||||
|
return node.pattern.kind === SyntaxKind.BindPattern
|
||||||
|
&& (node.params.length > 0 || (node.body !== null && node.body.kind === SyntaxKind.BlockBody));
|
||||||
|
}
|
||||||
|
|
||||||
export class Checker {
|
export class Checker {
|
||||||
|
|
||||||
private nextTypeVarId = 0;
|
private nextTypeVarId = 0;
|
||||||
private nextConTypeId = 0;
|
private nextConTypeId = 0;
|
||||||
private nextRecordTypeId = 0;
|
|
||||||
|
|
||||||
//private graph?: Graph<Syntax>;
|
//private graph?: Graph<Syntax>;
|
||||||
//private currentCycle?: Map<Syntax, Type>;
|
//private currentCycle?: Map<Syntax, Type>;
|
||||||
|
@ -668,10 +673,16 @@ export class Checker {
|
||||||
|
|
||||||
case SyntaxKind.LetDeclaration:
|
case SyntaxKind.LetDeclaration:
|
||||||
{
|
{
|
||||||
if (node.pattern.kind === SyntaxKind.BindPattern) {
|
if (isFunctionDeclarationLike(node)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const type = this.inferBindings(node.pattern, [], []);
|
let type;
|
||||||
|
if (node.pattern.kind === SyntaxKind.WrappedOperator) {
|
||||||
|
type = this.createTypeVar();
|
||||||
|
this.addBinding(node.pattern.operator.text, new Forall([], [], type));
|
||||||
|
} else {
|
||||||
|
type = this.inferBindings(node.pattern, [], []);
|
||||||
|
}
|
||||||
if (node.typeAssert !== null) {
|
if (node.typeAssert !== null) {
|
||||||
this.addConstraint(
|
this.addConstraint(
|
||||||
new CEqual(
|
new CEqual(
|
||||||
|
@ -733,7 +744,7 @@ export class Checker {
|
||||||
const scheme = this.lookup(node.name.name.text);
|
const scheme = this.lookup(node.name.name.text);
|
||||||
if (scheme === null) {
|
if (scheme === null) {
|
||||||
this.diagnostics.add(new BindingNotFoudDiagnostic(node.name.name.text, node.name.name));
|
this.diagnostics.add(new BindingNotFoudDiagnostic(node.name.name.text, node.name.name));
|
||||||
return new TAny();
|
return this.createTypeVar();
|
||||||
}
|
}
|
||||||
const type = this.instantiate(scheme, node);
|
const type = this.instantiate(scheme, node);
|
||||||
type.node = node;
|
type.node = node;
|
||||||
|
@ -812,7 +823,7 @@ export class Checker {
|
||||||
const scheme = this.lookup(node.name.text);
|
const scheme = this.lookup(node.name.text);
|
||||||
if (scheme === null) {
|
if (scheme === null) {
|
||||||
this.diagnostics.add(new BindingNotFoudDiagnostic(node.name.text, node.name));
|
this.diagnostics.add(new BindingNotFoudDiagnostic(node.name.text, node.name));
|
||||||
return new TAny();
|
return this.createTypeVar();
|
||||||
}
|
}
|
||||||
const recordType = this.instantiate(scheme, node);
|
const recordType = this.instantiate(scheme, node);
|
||||||
assert(recordType.kind === TypeKind.Record);
|
assert(recordType.kind === TypeKind.Record);
|
||||||
|
@ -830,7 +841,7 @@ export class Checker {
|
||||||
let fieldType;
|
let fieldType;
|
||||||
if (scheme === null) {
|
if (scheme === null) {
|
||||||
this.diagnostics.add(new BindingNotFoudDiagnostic(member.name.text, member.name));
|
this.diagnostics.add(new BindingNotFoudDiagnostic(member.name.text, member.name));
|
||||||
fieldType = new TAny();
|
fieldType = this.createTypeVar();
|
||||||
} else {
|
} else {
|
||||||
fieldType = this.instantiate(scheme, member);
|
fieldType = this.instantiate(scheme, member);
|
||||||
}
|
}
|
||||||
|
@ -857,7 +868,7 @@ export class Checker {
|
||||||
const scheme = this.lookup(node.operator.text);
|
const scheme = this.lookup(node.operator.text);
|
||||||
if (scheme === null) {
|
if (scheme === null) {
|
||||||
this.diagnostics.add(new BindingNotFoudDiagnostic(node.operator.text, node.operator));
|
this.diagnostics.add(new BindingNotFoudDiagnostic(node.operator.text, node.operator));
|
||||||
return new TAny();
|
return this.createTypeVar();
|
||||||
}
|
}
|
||||||
const opType = this.instantiate(scheme, node.operator);
|
const opType = this.instantiate(scheme, node.operator);
|
||||||
const retType = this.createTypeVar();
|
const retType = this.createTypeVar();
|
||||||
|
@ -889,13 +900,23 @@ export class Checker {
|
||||||
const scheme = this.lookup(node.name.text);
|
const scheme = this.lookup(node.name.text);
|
||||||
if (scheme === null) {
|
if (scheme === null) {
|
||||||
this.diagnostics.add(new BindingNotFoudDiagnostic(node.name.text, node.name));
|
this.diagnostics.add(new BindingNotFoudDiagnostic(node.name.text, node.name));
|
||||||
return new TAny();
|
return this.createTypeVar();
|
||||||
}
|
}
|
||||||
const type = this.instantiate(scheme, node.name);
|
const type = this.instantiate(scheme, node.name);
|
||||||
type.node = node;
|
type.node = node;
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.ArrowTypeExpression:
|
||||||
|
{
|
||||||
|
const paramTypes = [];
|
||||||
|
for (const paramTypeExpr of node.paramTypeExprs) {
|
||||||
|
paramTypes.push(this.inferTypeExpression(paramTypeExpr));
|
||||||
|
}
|
||||||
|
const returnType = this.inferTypeExpression(node.returnTypeExpr);
|
||||||
|
return new TArrow(paramTypes, returnType, node);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unrecognised ${node}`);
|
throw new Error(`Unrecognised ${node}`);
|
||||||
|
|
||||||
|
@ -920,7 +941,7 @@ export class Checker {
|
||||||
let recordType;
|
let recordType;
|
||||||
if (scheme === null) {
|
if (scheme === null) {
|
||||||
this.diagnostics.add(new BindingNotFoudDiagnostic(pattern.name.text, pattern.name));
|
this.diagnostics.add(new BindingNotFoudDiagnostic(pattern.name.text, pattern.name));
|
||||||
recordType = new TAny();
|
recordType = this.createTypeVar();
|
||||||
} else {
|
} else {
|
||||||
recordType = this.instantiate(scheme, pattern.name);
|
recordType = this.instantiate(scheme, pattern.name);
|
||||||
}
|
}
|
||||||
|
@ -1258,6 +1279,10 @@ export class Checker {
|
||||||
|
|
||||||
assert(node.kind === SyntaxKind.LetDeclaration);
|
assert(node.kind === SyntaxKind.LetDeclaration);
|
||||||
|
|
||||||
|
if (!isFunctionDeclarationLike(node)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const env = node.typeEnv!;
|
const env = node.typeEnv!;
|
||||||
const context: InferContext = {
|
const context: InferContext = {
|
||||||
typeVars,
|
typeVars,
|
||||||
|
@ -1301,13 +1326,34 @@ export class Checker {
|
||||||
returnType: null,
|
returnType: null,
|
||||||
};
|
};
|
||||||
this.contexts.push(bindCtx)
|
this.contexts.push(bindCtx)
|
||||||
const ty2 = this.inferBindings(node.pattern, typeVars, constraints);
|
let ty2;
|
||||||
|
if (node.pattern.kind === SyntaxKind.WrappedOperator) {
|
||||||
|
ty2 = this.createTypeVar();
|
||||||
|
this.addBinding(node.pattern.operator.text, new Forall([], [], ty2));
|
||||||
|
} else {
|
||||||
|
ty2 = this.inferBindings(node.pattern, typeVars, constraints);
|
||||||
|
}
|
||||||
this.addConstraint(new CEqual(ty2, type, node));
|
this.addConstraint(new CEqual(ty2, type, node));
|
||||||
this.contexts.pop();
|
this.contexts.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const visitElements = (elements: Syntax[]) => {
|
||||||
|
for (const element of elements) {
|
||||||
|
if (element.kind === SyntaxKind.LetDeclaration
|
||||||
|
&& isFunctionDeclarationLike(element)
|
||||||
|
&& graph.hasEdge(node, element, false)) {
|
||||||
|
assert(element.pattern.kind === SyntaxKind.BindPattern);
|
||||||
|
const scheme = this.lookup(element.pattern.name.text);
|
||||||
|
assert(scheme !== null);
|
||||||
|
this.instantiate(scheme, null);
|
||||||
|
} else {
|
||||||
|
this.infer(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const nodes of sccs) {
|
for (const nodes of sccs) {
|
||||||
|
|
||||||
if (nodes.some(n => n.kind === SyntaxKind.SourceFile)) {
|
if (nodes.some(n => n.kind === SyntaxKind.SourceFile)) {
|
||||||
|
@ -1324,6 +1370,10 @@ export class Checker {
|
||||||
|
|
||||||
assert(node.kind === SyntaxKind.LetDeclaration);
|
assert(node.kind === SyntaxKind.LetDeclaration);
|
||||||
|
|
||||||
|
if (!isFunctionDeclarationLike(node)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const context = node.context!;
|
const context = node.context!;
|
||||||
const returnType = context.returnType!;
|
const returnType = context.returnType!;
|
||||||
this.contexts.push(context);
|
this.contexts.push(context);
|
||||||
|
@ -1343,17 +1393,7 @@ export class Checker {
|
||||||
}
|
}
|
||||||
case SyntaxKind.BlockBody:
|
case SyntaxKind.BlockBody:
|
||||||
{
|
{
|
||||||
for (const element of node.body.elements) {
|
visitElements(node.body.elements);
|
||||||
if (element.kind === SyntaxKind.LetDeclaration
|
|
||||||
&& element.pattern.kind === SyntaxKind.BindPattern
|
|
||||||
&& graph.hasEdge(node, element, false)) {
|
|
||||||
const scheme = this.lookup(element.pattern.name.text);
|
|
||||||
assert(scheme !== null);
|
|
||||||
this.instantiate(scheme, null);
|
|
||||||
} else {
|
|
||||||
this.infer(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1368,18 +1408,8 @@ export class Checker {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const element of node.elements) {
|
visitElements(node.elements);
|
||||||
if (element.kind === SyntaxKind.LetDeclaration
|
|
||||||
&& element.pattern.kind === SyntaxKind.BindPattern
|
|
||||||
&& graph.hasEdge(node, element, false)) {
|
|
||||||
const scheme = this.lookup(element.pattern.name.text);
|
|
||||||
assert(scheme !== null);
|
|
||||||
this.instantiate(scheme, null);
|
|
||||||
} else {
|
|
||||||
this.infer(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.contexts.pop();
|
this.contexts.pop();
|
||||||
this.popContext(context);
|
this.popContext(context);
|
||||||
|
@ -1447,11 +1477,6 @@ export class Checker {
|
||||||
return this.unify(right, left, solution, constraint);
|
return this.unify(right, left, solution, constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.kind === TypeKind.Any || right.kind === TypeKind.Any) {
|
|
||||||
TypeBase.join(left, right);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (left.kind === TypeKind.Arrow && right.kind === TypeKind.Arrow) {
|
if (left.kind === TypeKind.Arrow && right.kind === TypeKind.Arrow) {
|
||||||
if (left.paramTypes.length !== right.paramTypes.length) {
|
if (left.paramTypes.length !== right.paramTypes.length) {
|
||||||
this.diagnostics.add(new ArityMismatchDiagnostic(left, right));
|
this.diagnostics.add(new ArityMismatchDiagnostic(left, right));
|
||||||
|
|
76
src/cst.ts
76
src/cst.ts
|
@ -78,6 +78,7 @@ export const enum SyntaxKind {
|
||||||
RBrace,
|
RBrace,
|
||||||
LBracket,
|
LBracket,
|
||||||
RBracket,
|
RBracket,
|
||||||
|
RArrow,
|
||||||
Dot,
|
Dot,
|
||||||
DotDot,
|
DotDot,
|
||||||
Comma,
|
Comma,
|
||||||
|
@ -104,6 +105,7 @@ export const enum SyntaxKind {
|
||||||
|
|
||||||
// Type expressions
|
// Type expressions
|
||||||
ReferenceTypeExpression,
|
ReferenceTypeExpression,
|
||||||
|
ArrowTypeExpression,
|
||||||
|
|
||||||
// Patterns
|
// Patterns
|
||||||
BindPattern,
|
BindPattern,
|
||||||
|
@ -139,6 +141,9 @@ export const enum SyntaxKind {
|
||||||
ExpressionStatement,
|
ExpressionStatement,
|
||||||
IfStatement,
|
IfStatement,
|
||||||
|
|
||||||
|
// If statement elements
|
||||||
|
IfStatementCase,
|
||||||
|
|
||||||
// Declarations
|
// Declarations
|
||||||
VariableDeclaration,
|
VariableDeclaration,
|
||||||
PrefixFuncDecl,
|
PrefixFuncDecl,
|
||||||
|
@ -156,7 +161,7 @@ export const enum SyntaxKind {
|
||||||
StructDeclarationField,
|
StructDeclarationField,
|
||||||
|
|
||||||
// Other nodes
|
// Other nodes
|
||||||
IfStatementCase,
|
WrappedOperator,
|
||||||
Initializer,
|
Initializer,
|
||||||
QualifiedName,
|
QualifiedName,
|
||||||
TypeAssert,
|
TypeAssert,
|
||||||
|
@ -243,7 +248,11 @@ export class Scope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.scanPattern(node.pattern, node);
|
if (node.pattern.kind === SyntaxKind.WrappedOperator) {
|
||||||
|
this.mapping.set(node.pattern.operator.text, node);
|
||||||
|
} else {
|
||||||
|
this.scanPattern(node.pattern, node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -816,8 +825,19 @@ export class LetKeyword extends TokenBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RArrow extends TokenBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.RArrow;
|
||||||
|
|
||||||
|
public get text(): string {
|
||||||
|
return '->';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export type Token
|
export type Token
|
||||||
= LParen
|
= RArrow
|
||||||
|
| LParen
|
||||||
| RParen
|
| RParen
|
||||||
| LBrace
|
| LBrace
|
||||||
| RBrace
|
| RBrace
|
||||||
|
@ -854,6 +874,30 @@ export type Token
|
||||||
export type TokenKind
|
export type TokenKind
|
||||||
= Token['kind']
|
= Token['kind']
|
||||||
|
|
||||||
|
export class ArrowTypeExpression extends SyntaxBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.ArrowTypeExpression;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
public paramTypeExprs: TypeExpression[],
|
||||||
|
public returnTypeExpr: TypeExpression
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFirstToken(): Token {
|
||||||
|
if (this.paramTypeExprs.length > 0) {
|
||||||
|
return this.paramTypeExprs[0].getFirstToken();
|
||||||
|
}
|
||||||
|
return this.returnTypeExpr.getFirstToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastToken(): Token {
|
||||||
|
return this.returnTypeExpr.getLastToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class ReferenceTypeExpression extends SyntaxBase {
|
export class ReferenceTypeExpression extends SyntaxBase {
|
||||||
|
|
||||||
public readonly kind = SyntaxKind.ReferenceTypeExpression;
|
public readonly kind = SyntaxKind.ReferenceTypeExpression;
|
||||||
|
@ -880,6 +924,7 @@ export class ReferenceTypeExpression extends SyntaxBase {
|
||||||
|
|
||||||
export type TypeExpression
|
export type TypeExpression
|
||||||
= ReferenceTypeExpression
|
= ReferenceTypeExpression
|
||||||
|
| ArrowTypeExpression
|
||||||
|
|
||||||
export class BindPattern extends SyntaxBase {
|
export class BindPattern extends SyntaxBase {
|
||||||
|
|
||||||
|
@ -1632,6 +1677,29 @@ export class BlockBody extends SyntaxBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WrappedOperator extends SyntaxBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.WrappedOperator;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
public lparen: LParen,
|
||||||
|
public operator: CustomOperator,
|
||||||
|
public rparen: RParen,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFirstToken(): Token {
|
||||||
|
return this.lparen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastToken(): Token {
|
||||||
|
return this.rparen;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class LetDeclaration extends SyntaxBase {
|
export class LetDeclaration extends SyntaxBase {
|
||||||
|
|
||||||
public readonly kind = SyntaxKind.LetDeclaration;
|
public readonly kind = SyntaxKind.LetDeclaration;
|
||||||
|
@ -1646,7 +1714,7 @@ export class LetDeclaration extends SyntaxBase {
|
||||||
public pubKeyword: PubKeyword | null,
|
public pubKeyword: PubKeyword | null,
|
||||||
public letKeyword: LetKeyword,
|
public letKeyword: LetKeyword,
|
||||||
public mutKeyword: MutKeyword | null,
|
public mutKeyword: MutKeyword | null,
|
||||||
public pattern: Pattern,
|
public pattern: Pattern | WrappedOperator,
|
||||||
public params: Param[],
|
public params: Param[],
|
||||||
public typeAssert: TypeAssert | null,
|
public typeAssert: TypeAssert | null,
|
||||||
public body: Body | null,
|
public body: Body | null,
|
||||||
|
|
|
@ -46,6 +46,8 @@ import {
|
||||||
IfStatement,
|
IfStatement,
|
||||||
MemberExpression,
|
MemberExpression,
|
||||||
IdentifierAlt,
|
IdentifierAlt,
|
||||||
|
WrappedOperator,
|
||||||
|
ArrowTypeExpression,
|
||||||
} from "./cst"
|
} from "./cst"
|
||||||
import { Stream } from "./util";
|
import { Stream } from "./util";
|
||||||
|
|
||||||
|
@ -160,7 +162,7 @@ export class Parser {
|
||||||
return new ReferenceTypeExpression([], name);
|
return new ReferenceTypeExpression([], name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public parseTypeExpression(): TypeExpression {
|
public parsePrimitiveTypeExpression(): TypeExpression {
|
||||||
const t0 = this.peekToken();
|
const t0 = this.peekToken();
|
||||||
switch (t0.kind) {
|
switch (t0.kind) {
|
||||||
case SyntaxKind.IdentifierAlt:
|
case SyntaxKind.IdentifierAlt:
|
||||||
|
@ -170,6 +172,24 @@ export class Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public parseTypeExpression(): TypeExpression {
|
||||||
|
let returnType = this.parsePrimitiveTypeExpression();
|
||||||
|
const paramTypes = [];
|
||||||
|
for (;;) {
|
||||||
|
const t1 = this.peekToken();
|
||||||
|
if (t1.kind !== SyntaxKind.RArrow) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.getToken();
|
||||||
|
paramTypes.push(returnType);
|
||||||
|
returnType = this.parsePrimitiveTypeExpression();
|
||||||
|
}
|
||||||
|
if (paramTypes.length === 0) {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
return new ArrowTypeExpression(paramTypes, returnType);
|
||||||
|
}
|
||||||
|
|
||||||
public parseConstantExpression(): ConstantExpression {
|
public parseConstantExpression(): ConstantExpression {
|
||||||
const token = this.getToken()
|
const token = this.getToken()
|
||||||
if (token.kind !== SyntaxKind.StringLiteral
|
if (token.kind !== SyntaxKind.StringLiteral
|
||||||
|
@ -497,9 +517,9 @@ export class Parser {
|
||||||
switch (t0.kind) {
|
switch (t0.kind) {
|
||||||
case SyntaxKind.LParen:
|
case SyntaxKind.LParen:
|
||||||
{
|
{
|
||||||
this.getToken();
|
|
||||||
const t1 = this.peekToken();
|
const t1 = this.peekToken();
|
||||||
if (t1.kind === SyntaxKind.IdentifierAlt) {
|
if (t1.kind === SyntaxKind.IdentifierAlt) {
|
||||||
|
this.getToken();
|
||||||
return this.parsePatternStartingWithConstructor();
|
return this.parsePatternStartingWithConstructor();
|
||||||
} else {
|
} else {
|
||||||
return this.parseTuplePattern();
|
return this.parseTuplePattern();
|
||||||
|
@ -551,7 +571,18 @@ export class Parser {
|
||||||
this.getToken();
|
this.getToken();
|
||||||
mutKeyword = t1;
|
mutKeyword = t1;
|
||||||
}
|
}
|
||||||
const pattern = this.parsePattern();
|
const t2 = this.peekToken();
|
||||||
|
const t3 = this.peekToken(2);
|
||||||
|
const t4 = this.peekToken(3);
|
||||||
|
let pattern;
|
||||||
|
if (t2.kind === SyntaxKind.LParen && t3.kind === SyntaxKind.CustomOperator && t4.kind === SyntaxKind.RParen) {
|
||||||
|
this.getToken()
|
||||||
|
this.getToken();
|
||||||
|
this.getToken();
|
||||||
|
pattern = new WrappedOperator(t2, t3, t4);
|
||||||
|
} else {
|
||||||
|
pattern = this.parsePattern();
|
||||||
|
}
|
||||||
const params = [];
|
const params = [];
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const t2 = this.peekToken();
|
const t2 = this.peekToken();
|
||||||
|
@ -564,14 +595,14 @@ export class Parser {
|
||||||
params.push(this.parseParam());
|
params.push(this.parseParam());
|
||||||
}
|
}
|
||||||
let typeAssert = null;
|
let typeAssert = null;
|
||||||
let t3 = this.getToken();
|
let t5 = this.getToken();
|
||||||
if (t3.kind === SyntaxKind.Colon) {
|
if (t5.kind === SyntaxKind.Colon) {
|
||||||
const typeExpression = this.parseTypeExpression();
|
const typeExpression = this.parseTypeExpression();
|
||||||
typeAssert = new TypeAssert(t3, typeExpression);
|
typeAssert = new TypeAssert(t5, typeExpression);
|
||||||
t3 = this.getToken();
|
t5 = this.getToken();
|
||||||
}
|
}
|
||||||
let body = null;
|
let body = null;
|
||||||
switch (t3.kind) {
|
switch (t5.kind) {
|
||||||
case SyntaxKind.BlockStart:
|
case SyntaxKind.BlockStart:
|
||||||
{
|
{
|
||||||
const elements = [];
|
const elements = [];
|
||||||
|
@ -583,22 +614,22 @@ export class Parser {
|
||||||
}
|
}
|
||||||
elements.push(this.parseLetBodyElement());
|
elements.push(this.parseLetBodyElement());
|
||||||
}
|
}
|
||||||
body = new BlockBody(t3, elements);
|
body = new BlockBody(t5, elements);
|
||||||
t3 = this.getToken();
|
t5 = this.getToken();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.Equals:
|
case SyntaxKind.Equals:
|
||||||
{
|
{
|
||||||
const expression = this.parseExpression();
|
const expression = this.parseExpression();
|
||||||
body = new ExprBody(t3, expression);
|
body = new ExprBody(t5, expression);
|
||||||
t3 = this.getToken();
|
t5 = this.getToken();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.LineFoldEnd:
|
case SyntaxKind.LineFoldEnd:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (t3.kind !== SyntaxKind.LineFoldEnd) {
|
if (t5.kind !== SyntaxKind.LineFoldEnd) {
|
||||||
this.raiseParseError(t3, [ SyntaxKind.LineFoldEnd ]);
|
this.raiseParseError(t5, [ SyntaxKind.LineFoldEnd ]);
|
||||||
}
|
}
|
||||||
return new LetDeclaration(
|
return new LetDeclaration(
|
||||||
pubKeyword,
|
pubKeyword,
|
||||||
|
|
|
@ -35,6 +35,7 @@ import {
|
||||||
ElseKeyword,
|
ElseKeyword,
|
||||||
IfKeyword,
|
IfKeyword,
|
||||||
StructKeyword,
|
StructKeyword,
|
||||||
|
RArrow,
|
||||||
} 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";
|
||||||
|
@ -246,7 +247,9 @@ export class Scanner extends BufferedStream<Token> {
|
||||||
case '?':
|
case '?':
|
||||||
{
|
{
|
||||||
const text = c0 + this.takeWhile(isOperatorPart);
|
const text = c0 + this.takeWhile(isOperatorPart);
|
||||||
if (text === '=') {
|
if (text === '->') {
|
||||||
|
return new RArrow(startPos);
|
||||||
|
} 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] !== '=') {
|
||||||
return new Assignment(text, startPos);
|
return new Assignment(text, startPos);
|
||||||
|
|
Loading…
Reference in a new issue