Add support for tuples
This commit is contained in:
parent
1ea65236a5
commit
cd357e03f5
5 changed files with 90 additions and 6 deletions
|
@ -59,6 +59,14 @@ export class Analyser {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.TupleExpression:
|
||||||
|
{
|
||||||
|
for (const element of node.elements) {
|
||||||
|
visit(element, source);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SyntaxKind.StructExpression:
|
case SyntaxKind.StructExpression:
|
||||||
{
|
{
|
||||||
for (const member of node.members) {
|
for (const member of node.members) {
|
||||||
|
|
|
@ -841,6 +841,14 @@ export class Checker {
|
||||||
private inferKindFromTypeExpression(node: TypeExpression, env: KindEnv): Kind {
|
private inferKindFromTypeExpression(node: TypeExpression, env: KindEnv): Kind {
|
||||||
let kind: Kind;
|
let kind: Kind;
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
case SyntaxKind.TupleTypeExpression:
|
||||||
|
{
|
||||||
|
for (const element of node.elements) {
|
||||||
|
this.unifyKind(this.inferKindFromTypeExpression(element, env), new KStar(), node);
|
||||||
|
}
|
||||||
|
kind = new KStar();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SyntaxKind.ArrowTypeExpression:
|
case SyntaxKind.ArrowTypeExpression:
|
||||||
{
|
{
|
||||||
for (const param of node.paramTypeExprs) {
|
for (const param of node.paramTypeExprs) {
|
||||||
|
@ -1250,6 +1258,9 @@ export class Checker {
|
||||||
return resultType;
|
return resultType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.TupleExpression:
|
||||||
|
return new TTuple(node.elements.map(el => this.inferExpression(el)), node);
|
||||||
|
|
||||||
case SyntaxKind.ReferenceExpression:
|
case SyntaxKind.ReferenceExpression:
|
||||||
{
|
{
|
||||||
assert(node.modulePath.length === 0);
|
assert(node.modulePath.length === 0);
|
||||||
|
@ -1407,6 +1418,12 @@ export class Checker {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.TupleTypeExpression:
|
||||||
|
{
|
||||||
|
type = new TTuple(node.elements.map(el => this.inferTypeExpression(el)), node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SyntaxKind.NestedTypeExpression:
|
case SyntaxKind.NestedTypeExpression:
|
||||||
return this.inferTypeExpression(node.typeExpr, introduceTypeVars);
|
return this.inferTypeExpression(node.typeExpr, introduceTypeVars);
|
||||||
|
|
||||||
|
@ -1969,8 +1986,20 @@ export class Checker {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (right.kind === TypeKind.Arrow) {
|
if (left.kind === TypeKind.Tuple && right.kind === TypeKind.Tuple) {
|
||||||
return unify(right, left);
|
if (left.elementTypes.length === right.elementTypes.length) {
|
||||||
|
let success = false;
|
||||||
|
const count = left.elementTypes.length;
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
if (!unify(left.elementTypes[i], right.elementTypes[i])) {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
TypeBase.join(left, right);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.kind === TypeKind.Con && right.kind === TypeKind.Con) {
|
if (left.kind === TypeKind.Con && right.kind === TypeKind.Con) {
|
||||||
|
|
24
src/cst.ts
24
src/cst.ts
|
@ -112,6 +112,7 @@ export const enum SyntaxKind {
|
||||||
VarTypeExpression,
|
VarTypeExpression,
|
||||||
AppTypeExpression,
|
AppTypeExpression,
|
||||||
NestedTypeExpression,
|
NestedTypeExpression,
|
||||||
|
TupleTypeExpression,
|
||||||
|
|
||||||
// Patterns
|
// Patterns
|
||||||
BindPattern,
|
BindPattern,
|
||||||
|
@ -1007,6 +1008,28 @@ export class ArrowTypeExpression extends SyntaxBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TupleTypeExpression extends SyntaxBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.TupleTypeExpression;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
public lparen: LParen,
|
||||||
|
public elements: TypeExpression[],
|
||||||
|
public rparen: RParen,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFirstToken(): Token {
|
||||||
|
return this.lparen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastToken(): Token {
|
||||||
|
return this.rparen;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class ReferenceTypeExpression extends SyntaxBase {
|
export class ReferenceTypeExpression extends SyntaxBase {
|
||||||
|
|
||||||
public readonly kind = SyntaxKind.ReferenceTypeExpression;
|
public readonly kind = SyntaxKind.ReferenceTypeExpression;
|
||||||
|
@ -1103,6 +1126,7 @@ export type TypeExpression
|
||||||
| VarTypeExpression
|
| VarTypeExpression
|
||||||
| AppTypeExpression
|
| AppTypeExpression
|
||||||
| NestedTypeExpression
|
| NestedTypeExpression
|
||||||
|
| TupleTypeExpression
|
||||||
|
|
||||||
export class BindPattern extends SyntaxBase {
|
export class BindPattern extends SyntaxBase {
|
||||||
|
|
||||||
|
|
|
@ -190,7 +190,7 @@ export function describeType(type: Type): string {
|
||||||
else out += ', ';
|
else out += ', ';
|
||||||
out += describeType(elementType);
|
out += describeType(elementType);
|
||||||
}
|
}
|
||||||
return out;
|
return out + ')';
|
||||||
}
|
}
|
||||||
case TypeKind.Nominal:
|
case TypeKind.Nominal:
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,6 +58,7 @@ import {
|
||||||
MatchExpression,
|
MatchExpression,
|
||||||
LiteralPattern,
|
LiteralPattern,
|
||||||
DisjunctivePattern,
|
DisjunctivePattern,
|
||||||
|
TupleTypeExpression,
|
||||||
} from "./cst"
|
} from "./cst"
|
||||||
import { Stream } from "./util";
|
import { Stream } from "./util";
|
||||||
|
|
||||||
|
@ -185,9 +186,30 @@ export class Parser {
|
||||||
case SyntaxKind.LParen:
|
case SyntaxKind.LParen:
|
||||||
{
|
{
|
||||||
this.getToken();
|
this.getToken();
|
||||||
const typeExpr = this.parseTypeExpression();
|
const elements = [];
|
||||||
const t2 = this.expectToken(SyntaxKind.RParen);
|
let rparen;
|
||||||
return new NestedTypeExpression(t0, typeExpr, t2);
|
for (;;) {
|
||||||
|
const t2 = this.peekToken();
|
||||||
|
if (t2.kind === SyntaxKind.RParen) {
|
||||||
|
rparen = t2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const typeExpr = this.parseTypeExpression();
|
||||||
|
elements.push(typeExpr);
|
||||||
|
const t3 = this.getToken();
|
||||||
|
if (t3.kind === SyntaxKind.RParen) {
|
||||||
|
rparen = t3;
|
||||||
|
break;
|
||||||
|
} else if (t3.kind === SyntaxKind.Comma) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
this.raiseParseError(t3, [ SyntaxKind.Comma, SyntaxKind.RParen ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (elements.length === 1) {
|
||||||
|
return new NestedTypeExpression(t0, elements[0], rparen);
|
||||||
|
}
|
||||||
|
return new TupleTypeExpression(t0, elements, rparen);
|
||||||
}
|
}
|
||||||
case SyntaxKind.IdentifierAlt:
|
case SyntaxKind.IdentifierAlt:
|
||||||
return this.parseReferenceTypeExpression();
|
return this.parseReferenceTypeExpression();
|
||||||
|
@ -204,6 +226,7 @@ export class Parser {
|
||||||
if (t1.kind === SyntaxKind.RParen
|
if (t1.kind === SyntaxKind.RParen
|
||||||
|| t1.kind === SyntaxKind.RBrace
|
|| t1.kind === SyntaxKind.RBrace
|
||||||
|| t1.kind === SyntaxKind.RBracket
|
|| t1.kind === SyntaxKind.RBracket
|
||||||
|
|| t1.kind === SyntaxKind.Comma
|
||||||
|| t1.kind === SyntaxKind.Equals
|
|| t1.kind === SyntaxKind.Equals
|
||||||
|| t1.kind === SyntaxKind.BlockStart
|
|| t1.kind === SyntaxKind.BlockStart
|
||||||
|| t1.kind === SyntaxKind.LineFoldEnd
|
|| t1.kind === SyntaxKind.LineFoldEnd
|
||||||
|
|
Loading…
Reference in a new issue