Split Punctuated into subclasses for parser
This commit is contained in:
parent
96aa6b6991
commit
365de4e3f7
2 changed files with 227 additions and 28 deletions
227
src/ast.ts
227
src/ast.ts
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue