Split Punctuated into subclasses for parser

This commit is contained in:
Sam Vervaeck 2020-02-24 20:47:07 +01:00
parent 96aa6b6991
commit 365de4e3f7
2 changed files with 227 additions and 28 deletions

View file

@ -1,9 +1,13 @@
import "reflect-metadata" import "reflect-metadata"
import { Stream } from "./util"
interface JsonArray extends Array<Json> { }; interface JsonArray extends Array<Json> { };
interface JsonObject { [key: string]: Json } interface JsonObject { [key: string]: Json }
type Json = string | boolean | number | JsonArray | JsonObject; type Json = null | string | boolean | number | JsonArray | JsonObject;
export type TokenStream = Stream<Token>;
export enum SyntaxKind { export enum SyntaxKind {
@ -12,10 +16,15 @@ export enum SyntaxKind {
Literal, Literal,
Identifier, Identifier,
Operator, Operator,
Punctuated, Parenthesized,
Braced,
Bracketed,
Semi, Semi,
Comma, Comma,
Colon, Colon,
Dot,
RArrow,
EqSign,
// Special nodes // Special nodes
@ -25,9 +34,16 @@ export enum SyntaxKind {
Sentence, Sentence,
Param,
// Patterns
BindPatt,
ExprPatt,
// Expressions // Expressions
ConstantExpr, ConstExpr,
ReferenceExpr, ReferenceExpr,
// Statements // Statements
@ -144,17 +160,15 @@ export enum PunctType {
Brace, Brace,
} }
export class Punctuated extends SyntaxBase { export class Parenthesized extends SyntaxBase {
kind: SyntaxKind.Punctuated = SyntaxKind.Punctuated kind: SyntaxKind.Parenthesized = SyntaxKind.Parenthesized;
static META = { static META = {
punctuator: EdgeType.Primitive,
elements: EdgeType.Node | EdgeType.List elements: EdgeType.Node | EdgeType.List
} }
constructor( constructor(
public punctuator: PunctType,
public elements: Token[], public elements: Token[],
public span: TextSpan, public span: TextSpan,
public parentNode: Syntax | null = null public parentNode: Syntax | null = null
@ -164,8 +178,58 @@ export class Punctuated extends SyntaxBase {
toJSON(): Json { toJSON(): Json {
return { return {
kind: 'Punctuated', kind: 'Parenthesized',
punctuator: this.punctuator, elements: this.elements.map(element => element.toJSON()),
}
}
}
export class Braced extends SyntaxBase {
kind: SyntaxKind.Braced = SyntaxKind.Braced;
static META = {
elements: EdgeType.Node | EdgeType.List
}
constructor(
public elements: Token[],
public span: TextSpan,
public parentNode: Syntax | null = null
) {
super();
}
toJSON(): Json {
return {
kind: 'Braced',
elements: this.elements.map(element => element.toJSON()),
}
}
}
export class Bracketed extends SyntaxBase {
kind: SyntaxKind.Bracketed = SyntaxKind.Bracketed;
static META = {
elements: EdgeType.Node | EdgeType.List
}
constructor(
public elements: Token[],
public span: TextSpan,
public parentNode: Syntax | null = null
) {
super();
}
toJSON(): Json {
return {
kind: 'Bracketed',
elements: this.elements.map(element => element.toJSON()), elements: this.elements.map(element => element.toJSON()),
} }
} }
@ -209,6 +273,7 @@ export class Operator extends SyntaxBase {
constructor( constructor(
public text: string, public text: string,
public span: TextSpan, public span: TextSpan,
public origNode: Syntax | null = null,
public parentNode: Syntax | null = null public parentNode: Syntax | null = null
) { ) {
super(); super();
@ -218,7 +283,7 @@ export class Operator extends SyntaxBase {
return { return {
kind: 'Operator', kind: 'Operator',
text: this.text, text: this.text,
span: this.span.toJSON(), span: this.span !== null ? this.span.toJSON() : null,
} }
} }
@ -229,16 +294,17 @@ export class Semi extends SyntaxBase {
kind: SyntaxKind.Semi = SyntaxKind.Semi; kind: SyntaxKind.Semi = SyntaxKind.Semi;
constructor( constructor(
public span: TextSpan, public span: TextSpan | null = null,
public origNode: Syntax | null = null,
public parentNode: Syntax | null = null public parentNode: Syntax | null = null
) { ) {
super(); super();
} }
toJSON() { toJSON(): Json {
return { return {
kind: 'Semi', kind: 'Semi',
span: this.span.toJSON(), span: this.span !== null ? this.span.toJSON() : null,
} }
} }
@ -250,15 +316,16 @@ export class Colon extends SyntaxBase {
constructor( constructor(
public span: TextSpan, public span: TextSpan,
public origNode: Syntax | null = null,
public parentNode: Syntax | null = null public parentNode: Syntax | null = null
) { ) {
super(); super();
} }
toJSON() { toJSON(): Json {
return { return {
kind: 'Colon', kind: 'Colon',
span: this.span.toJSON(), span: this.span !== null ? this.span.toJSON() : null,
} }
} }
@ -269,7 +336,74 @@ export class Comma extends SyntaxBase {
kind: SyntaxKind.Comma = SyntaxKind.Comma; kind: SyntaxKind.Comma = SyntaxKind.Comma;
constructor( constructor(
public span: TextSpan, public span: TextSpan | null = null,
public origNode: Syntax | null = null,
public parentNode: Syntax | null = null
) {
super();
}
toJSON(): Json {
return {
kind: 'Comma',
span: this.span !== null ? this.span.toJSON() : null,
}
}
}
export class RArrow extends SyntaxBase {
kind: SyntaxKind.RArrow = SyntaxKind.RArrow;
constructor(
public span: TextSpan | null = null,
public origNode: Syntax | null = null,
public parentNode: Syntax | null = null
) {
super();
}
toJSON(): Json {
return {
kind: 'RArrow',
span: this.span !== null ? this.span.toJSON() : null,
}
}
}
export class EqSign extends SyntaxBase {
kind: SyntaxKind.EqSign = SyntaxKind.EqSign;
constructor(
public span: TextSpan | null = null,
public origNode: Syntax | null = null,
public parentNode: Syntax | null = null
) {
super();
}
toJSON(): Json {
return {
kind: 'EqSign',
span: this.span !== null ? this.span.toJSON() : null,
}
}
}
export class Dot extends SyntaxBase {
kind: SyntaxKind.Dot = SyntaxKind.Dot;
constructor(
public span: TextSpan | null = null,
public origNode: Syntax | null = null,
public parentNode: Syntax | null = null public parentNode: Syntax | null = null
) { ) {
super(); super();
@ -277,8 +411,8 @@ export class Comma extends SyntaxBase {
toJSON() { toJSON() {
return { return {
kind: 'Comma', kind: 'Dot',
span: this.span.toJSON(), span: this.span !== null ? this.span.toJSON() : null,
} }
} }
@ -286,10 +420,17 @@ export class Comma extends SyntaxBase {
export type Token export type Token
= Semi = Semi
| Comma
| Colon
| EqSign
| Dot
| RArrow
| Identifier | Identifier
| Operator | Operator
| Literal | Literal
| Punctuated | Parenthesized
| Braced
| Bracketed
export class Sentence extends SyntaxBase { export class Sentence extends SyntaxBase {
@ -323,7 +464,7 @@ export class QualName {
} }
constructor( constructor(
public name: string, public name: Identifier | Operator,
public path: Identifier[], public path: Identifier[],
public span: TextSpan, public span: TextSpan,
public parentNode: Syntax | null = null public parentNode: Syntax | null = null
@ -333,9 +474,48 @@ export class QualName {
} }
export class ConstantExpr { export class Param extends SyntaxBase {
kind = SyntaxKind.ConstantExpr; kind: SyntaxKind.Param = SyntaxKind.Param;
constructor(
public bindings: Pattern,
public typeDecl: TypeDecl | null,
public defaultValue: Expr | null,
public span: TextSpan | null = null,
public parentNode: Syntax | null = null,
) {
super();
}
}
export class BindPatt extends SyntaxBase {
kind: SyntaxKind.BindPatt = SyntaxKind.BindPatt;
constructor(
public name: Identifier,
public span: TextSpan | null = null,
public origNode: Syntax | null = null,
public parentNode: Syntax | null = null
) {
super();
}
toJSON() {
return {
kind: 'BindPatt',
name: this.name.toJSON(),
span: this.span !== null ? this.span.toJSON() : null,
}
}
}
export class ConstExpr {
kind = SyntaxKind.ConstExpr;
static META = { static META = {
value: EdgeType.Primitive, value: EdgeType.Primitive,
@ -352,7 +532,7 @@ export class ConstantExpr {
} }
export type Expr export type Expr
= ConstantExpr = ConstExpr
class ReturnStatement extends SyntaxBase { class ReturnStatement extends SyntaxBase {
@ -463,6 +643,7 @@ export type Decl
export type Syntax export type Syntax
= Decl = Decl
| Expr | Expr
| Token
| SourceFile | SourceFile
| QualName | QualName

View file

@ -7,11 +7,14 @@ import {
TextPos, TextPos,
TextSpan, TextSpan,
Identifier, Identifier,
RArrow,
Operator, Operator,
PunctType, PunctType,
Token, Token,
Decl, Decl,
Punctuated, Parenthesized,
Braced,
Bracketed,
Sentence, Sentence,
SourceFile, SourceFile,
Semi, Semi,
@ -192,6 +195,7 @@ export class Scanner {
const startPos = this.currPos.clone() const startPos = this.currPos.clone()
switch (c0) { switch (c0) {
case ';': case ';':
this.getChar(); this.getChar();
@ -202,7 +206,6 @@ export class Scanner {
case ':': case ':':
this.getChar(); this.getChar();
return new Colon(new TextSpan(this.file, startPos, this.currPos.clone())); return new Colon(new TextSpan(this.file, startPos, this.currPos.clone()));
} }
if (isOpenPunct(c0)) { if (isOpenPunct(c0)) {
@ -244,7 +247,16 @@ export class Scanner {
const endPos = this.currPos.clone(); const endPos = this.currPos.clone();
return new Punctuated(punctType, elements, new TextSpan(this.file, startPos, endPos)); switch (punctType) {
case PunctType.Brace:
return new Braced(elements, new TextSpan(this.file, startPos, endPos));
case PunctType.Paren:
return new Parenthesized(elements, new TextSpan(this.file, startPos, endPos));
case PunctType.Bracket:
return new Bracketed(elements, new TextSpan(this.file, startPos, endPos));
default:
throw new Error("Got an invalid state.")
}
} else if (isIdentStart(c0)) { } else if (isIdentStart(c0)) {
@ -256,7 +268,13 @@ export class Scanner {
const text = this.takeWhile(isOperatorPart) const text = this.takeWhile(isOperatorPart)
const endPos = this.currPos.clone() const endPos = this.currPos.clone()
return new Operator(text, new TextSpan(this.file, startPos, endPos)); const span = new TextSpan(this.file, startPos, endPos);
if (text === '->') {
return new RArrow(span);
} else {
return new Operator(text, span);
}
} else { } else {
@ -290,7 +308,7 @@ export class Scanner {
break; break;
} }
tokens.push(token) tokens.push(token)
if (token.kind === SyntaxKind.Punctuated && token.punctuator === PunctType.Brace) { if (token.kind === SyntaxKind.Braced) {
break; break;
} }
} }