Add support for paring sentences

This commit is contained in:
Sam Vervaeck 2020-02-24 19:16:33 +01:00
parent c68c6fdf1b
commit d06c8f577d
3 changed files with 183 additions and 53 deletions

View file

@ -13,16 +13,25 @@ export enum SyntaxKind {
Identifier, Identifier,
Operator, Operator,
Punctuated, Punctuated,
Semi,
// Special nodes
SourceFile, SourceFile,
QualName, QualName,
Sentence,
// Expressions // Expressions
ConstantExpr, ConstantExpr,
ReferenceExpr, ReferenceExpr,
// Statements
ReturnStatement,
// Type declarations // Type declarations
TypeReference, TypeReference,
@ -97,9 +106,14 @@ export class TextSpan {
} }
export class Literal { abstract class SyntaxBase {
abstract kind: SyntaxKind;
abstract parentNode: Syntax | null;
}
kind = SyntaxKind.Literal; export class Literal extends SyntaxBase {
kind: SyntaxKind.Literal = SyntaxKind.Literal;
static META = { static META = {
value: EdgeType.Primitive, value: EdgeType.Primitive,
@ -107,9 +121,10 @@ export class Literal {
constructor( constructor(
public value: string | bigint, public value: string | bigint,
public span: TextSpan public span: TextSpan,
public parentNode: Syntax | null = null
) { ) {
super();
} }
toJSON(): Json { toJSON(): Json {
@ -127,9 +142,9 @@ export enum PunctType {
Brace, Brace,
} }
export class Punctuated { export class Punctuated extends SyntaxBase {
kind = SyntaxKind.Punctuated kind: SyntaxKind.Punctuated = SyntaxKind.Punctuated
static META = { static META = {
punctuator: EdgeType.Primitive, punctuator: EdgeType.Primitive,
@ -139,9 +154,10 @@ export class Punctuated {
constructor( constructor(
public punctuator: PunctType, public punctuator: PunctType,
public elements: Token[], public elements: Token[],
public span: TextSpan public span: TextSpan,
public parentNode: Syntax | null = null
) { ) {
super();
} }
toJSON(): Json { toJSON(): Json {
@ -154,9 +170,9 @@ export class Punctuated {
} }
export class Identifier { export class Identifier extends SyntaxBase {
kind = SyntaxKind.Identifier; kind: SyntaxKind.Identifier = SyntaxKind.Identifier;
static META = { static META = {
text: EdgeType.Primitive text: EdgeType.Primitive
@ -164,9 +180,10 @@ export class Identifier {
constructor( constructor(
public text: string, public text: string,
public span: TextSpan public span: TextSpan,
public parentNode: Syntax | null = null
) { ) {
super();
} }
toJSON(): Json { toJSON(): Json {
@ -179,9 +196,9 @@ export class Identifier {
} }
export class Operator { export class Operator extends SyntaxBase {
kind = SyntaxKind.Operator; kind: SyntaxKind.Operator = SyntaxKind.Operator;
static META = { static META = {
text: EdgeType.Primitive text: EdgeType.Primitive
@ -192,7 +209,7 @@ export class Operator {
public span: TextSpan, public span: TextSpan,
public parentNode: Syntax | null = null public parentNode: Syntax | null = null
) { ) {
super();
} }
toJSON(): Json { toJSON(): Json {
@ -205,15 +222,58 @@ export class Operator {
} }
export class Semi extends SyntaxBase {
kind: SyntaxKind.Semi = SyntaxKind.Semi;
constructor(
public span: TextSpan,
public parentNode: Syntax | null = null
) {
super();
}
toJSON() {
return {
kind: 'Semi',
span: this.span.toJSON(),
}
}
}
export type Token export type Token
= Identifier = Semi
| Identifier
| Operator | Operator
| Literal | Literal
| Punctuated | Punctuated
export class Sentence extends SyntaxBase {
kind = SyntaxKind.Sentence;
constructor(
public tokens: Token[],
public span: TextSpan,
public parentNode: Syntax | null = null
) {
super();
}
toJSON(): Json {
return {
kind: 'Sentence',
tokens: this.tokens.map(token => token.toJSON()),
span: this.span.toJSON(),
}
}
}
export class QualName { export class QualName {
kind = SyntaxKind.QualName; kind: SyntaxKind.QualName = SyntaxKind.QualName;
static META = { static META = {
name: EdgeType.Node, name: EdgeType.Node,
@ -252,9 +312,25 @@ export class ConstantExpr {
export type Expr export type Expr
= ConstantExpr = ConstantExpr
class ReturnStatement extends SyntaxBase {
kind: SyntaxKind.ReturnStatement = SyntaxKind.ReturnStatement;
constructor(
public value: Expr | null,
public span: TextSpan,
public parentNode: Syntax | null = null
) {
super();
}
}
export type Statement
= ReturnStatement
export class TypeReference { export class TypeReference {
kind = SyntaxKind.TypeReference; kind: SyntaxKind.TypeReference = SyntaxKind.TypeReference;
static META = { static META = {
name: EdgeType.Node, name: EdgeType.Node,
@ -275,23 +351,23 @@ export class TypeReference {
export type TypeDecl export type TypeDecl
= TypeReference = TypeReference
export class Unexpanded { // export class Unexpanded {
//
// static META = {
// tokens: EdgeType.Node | EdgeType.List
// }
//
// constructor(
// public tokens: Token[],
// public span: TextSpan,
// public parentNode: Syntax | null = null
// ) {
//
// }
//
// }
static META = { export class FunctionDecl extends SyntaxBase {
tokens: EdgeType.Node | EdgeType.List
}
constructor(
public tokens: Token[],
public span: TextSpan,
public parentNode: Syntax | null = null
) {
}
}
export class FunctionDecl {
kind = SyntaxKind.FunctionDecl; kind = SyntaxKind.FunctionDecl;
@ -310,13 +386,13 @@ export class FunctionDecl {
public span: TextSpan, public span: TextSpan,
public parentNode: Syntax | null = null public parentNode: Syntax | null = null
) { ) {
super();
} }
} }
export class VariableDecl { export class VariableDecl extends SyntaxBase {
kind = SyntaxKind.VariableDecl; kind = SyntaxKind.VariableDecl;
@ -332,13 +408,13 @@ export class VariableDecl {
public value: Expr | null, public value: Expr | null,
public span: TextSpan public span: TextSpan
) { ) {
super();
} }
} }
export type Decl export type Decl
= Unexpanded = Sentence
| FunctionDecl | FunctionDecl
| VariableDecl | VariableDecl
@ -348,10 +424,23 @@ export type Syntax
| SourceFile | SourceFile
| QualName | QualName
export class SourceFile { export class SourceFile extends SyntaxBase {
constructor(public elements: Decl[], public span: TextSpan) { kind: SyntaxKind.SourceFile = SyntaxKind.SourceFile;
constructor(
public elements: (Decl | Statement)[],
public span: TextSpan,
public parentNode: Syntax | null = null
) {
super();
}
toJSON() {
return {
elements: this.elements.map(element => element.toJSON()),
span: this.span.toJSON(),
}
} }
} }

View file

@ -7,7 +7,7 @@ import * as fs from "fs"
import yargs from "yargs" import yargs from "yargs"
import { Scanner } from "../scanner" import { Scanner } from "../scanner"
import { Token, TextFile } from "../ast" import { Token, TextFile, SourceFile } from "../ast"
function toArray<T>(value: T): T extends Array<any> ? T : T[] { function toArray<T>(value: T): T extends Array<any> ? T : T[] {
if (Array.isArray(value)) { if (Array.isArray(value)) {
@ -63,13 +63,13 @@ yargs
args => { args => {
const hooks: Hook[] = toArray(args.hook as string[] | string).map(parseHook); const hooks: Hook[] = toArray(args.hook as string[] | string).map(parseHook);
const sourceFiles: SourceFile[] = [];
for (const filepath of toArray(args.files as string[] | string)) { for (const filepath of toArray(args.files as string[] | string)) {
const file = new TextFile(filepath); const file = new TextFile(filepath);
const content = fs.readFileSync(filepath, 'utf8') const content = fs.readFileSync(filepath, 'utf8')
const scanner = new Scanner(file, content) const scanner = new Scanner(file, content)
const tokens: Token[] = [];
for (const hook of hooks) { for (const hook of hooks) {
if (hook.name === 'scan' && hook.timing === 'before') { if (hook.name === 'scan' && hook.timing === 'before') {
@ -85,20 +85,21 @@ yargs
} }
} }
while (true) { const sourceFile = scanner.scan();
const token = scanner.scanToken() // while (true) {
if (token === null) { // const token = scanner.scanToken()
break; // if (token === null) {
} // break;
tokens.push(token); // }
} // tokens.push(token);
// }
for (const hook of hooks) { for (const hook of hooks) {
if (hook.name === 'scan' && hook.timing == 'after') { if (hook.name === 'scan' && hook.timing == 'after') {
for (const effect of hook.effects) { for (const effect of hook.effects) {
switch (effect) { switch (effect) {
case 'dump': case 'dump':
console.log(JSON.stringify(tokens.map(t => t.toJSON()), undefined, 2)); console.log(JSON.stringify(sourceFile.toJSON(), undefined, 2));
break; break;
case 'abort': case 'abort':
process.exit(0); process.exit(0);
@ -110,7 +111,10 @@ yargs
} }
} }
sourceFiles.push(sourceFile);
} }
}) })
.help() .help()

View file

@ -2,6 +2,7 @@
import XRegExp from "xregexp" import XRegExp from "xregexp"
import { import {
SyntaxKind,
TextFile, TextFile,
TextPos, TextPos,
TextSpan, TextSpan,
@ -9,7 +10,10 @@ import {
Operator, Operator,
PunctType, PunctType,
Token, Token,
Decl,
Punctuated, Punctuated,
Sentence,
SourceFile
} from "./ast" } from "./ast"
function escapeChar(ch: string) { function escapeChar(ch: string) {
@ -168,7 +172,7 @@ export class Scanner {
return text; return text;
} }
scanToken() { scanToken(): Token | null {
while (true) { while (true) {
@ -248,7 +252,40 @@ export class Scanner {
} }
scanTokenList() { scan() {
const elements: Decl[] = []
const startPos = this.currPos.clone()
while (true) {
const tokens: Token[] = [];
while (true) {
const token = this.scanToken();
if (token === null) {
break;
}
if (token.kind === SyntaxKind.Semi) {
break;
}
tokens.push(token)
if (token.kind === SyntaxKind.Punctuated && token.punctuator === PunctType.Brace) {
break;
}
}
if (tokens.length === 0) {
break;
}
elements.push(new Sentence(tokens, new TextSpan(this.file, tokens[0].span.start.clone(), tokens[tokens.length-1].span.end.clone())))
}
const endPos = this.currPos.clone();
return new SourceFile(elements, new TextSpan(this.file, startPos, endPos))
} }