Move some declarations from src/util.ts to src/common.ts
This commit is contained in:
parent
1068dae5d6
commit
79f150bb4b
10 changed files with 275 additions and 287 deletions
|
@ -202,6 +202,13 @@ export class TypeChecker {
|
|||
|
||||
switch (node.kind) {
|
||||
|
||||
case SyntaxKind.BoltModule:
|
||||
{
|
||||
for (const element of node.elements) {
|
||||
visitSourceElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
case SyntaxKind.BoltRecordDeclaration:
|
||||
{
|
||||
if (node.members !== null) {
|
||||
|
|
258
src/common.ts
258
src/common.ts
|
@ -3,13 +3,56 @@ import {
|
|||
BoltReturnStatement,
|
||||
SyntaxKind,
|
||||
BoltExpression,
|
||||
BoltSourceFile,
|
||||
JSSourceFile
|
||||
BoltQualName,
|
||||
kindToString,
|
||||
Syntax,
|
||||
Token,
|
||||
isBoltPunctuated
|
||||
} from "./ast";
|
||||
import { BOLT_SUPPORTED_LANGUAGES } from "./constants"
|
||||
import {emit} from "./emitter";
|
||||
import {FastStringMap, enumerate, escapeChar} from "./util";
|
||||
import {TextSpan, TextPos, TextFile} from "./text";
|
||||
import {Scanner} from "./scanner";
|
||||
|
||||
export type SourceFile
|
||||
= BoltSourceFile
|
||||
| JSSourceFile
|
||||
export function getLanguage(node: Syntax): string {
|
||||
const kindStr = kindToString(node.kind);
|
||||
for (const prefix of BOLT_SUPPORTED_LANGUAGES) {
|
||||
if (kindStr.startsWith(prefix)) {
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
throw new Error(`Could not determine the language of ${kindStr}`);
|
||||
}
|
||||
|
||||
export function createTokenStream(node: Syntax) {
|
||||
if (isBoltPunctuated(node)) {
|
||||
const origPos = node.span!.start;
|
||||
const startPos = new TextPos(origPos.offset+1, origPos.line, origPos.column+1);
|
||||
return new Scanner(node.span!.file, node.text, startPos);
|
||||
} else {
|
||||
throw new Error(`Could not convert ${kindToString(node.kind)} to a token stream.`);
|
||||
}
|
||||
}
|
||||
|
||||
export const EOF = ''
|
||||
|
||||
export class ScanError extends Error {
|
||||
constructor(public file: TextFile, public position: TextPos, public char: string) {
|
||||
super(`${file.origPath}:${position.line}:${position.column}: unexpected char '${escapeChar(char)}'`)
|
||||
}
|
||||
}
|
||||
|
||||
export function cloneSpan(span: TextSpan | null) {
|
||||
if (span === null) {
|
||||
return null;
|
||||
}
|
||||
return span.clone();
|
||||
}
|
||||
|
||||
export function setOrigNodeRange(node: Syntax, startNode: Syntax, endNode: Syntax): void {
|
||||
node.span = new TextSpan(startNode.span!.file, startNode.span!.start.clone(), endNode.span!.end.clone());
|
||||
}
|
||||
|
||||
export type BoltFunctionBody = BoltFunctionBodyElement[];
|
||||
|
||||
|
@ -37,7 +80,7 @@ export function getReturnStatementsInFunctionBody(body: BoltFunctionBody): BoltR
|
|||
function visitExpression(node: BoltExpression) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.BoltBlockExpression:
|
||||
for (const element of node.statements) {
|
||||
for (const element of node.elements) {
|
||||
visit(element);
|
||||
}
|
||||
break;
|
||||
|
@ -57,3 +100,206 @@ export function getReturnStatementsInFunctionBody(body: BoltFunctionBody): BoltR
|
|||
|
||||
}
|
||||
|
||||
export function hasPublicModifier(node: BoltDeclaration) {
|
||||
return (node.modifiers & BoltDeclarationModifiers.Public) > 0;
|
||||
}
|
||||
|
||||
export enum OperatorKind {
|
||||
Prefix,
|
||||
InfixL,
|
||||
InfixR,
|
||||
Suffix,
|
||||
}
|
||||
|
||||
export function isRightAssoc(kind: OperatorKind) {
|
||||
return kind === OperatorKind.InfixR;
|
||||
}
|
||||
|
||||
export class ParseError extends Error {
|
||||
constructor(public actual: Syntax, public expected: SyntaxKind[]) {
|
||||
super(`${actual.span!.file.origPath}:${actual.span!.start.line}:${actual.span!.start.column}: expected ${enumerate(expected.map(e => describeKind(e)))} but got ${describeKind(actual.kind)}`)
|
||||
}
|
||||
}
|
||||
|
||||
export interface OperatorInfo {
|
||||
kind: OperatorKind;
|
||||
arity: number;
|
||||
name: string;
|
||||
precedence: number;
|
||||
}
|
||||
|
||||
export function assertToken(node: Token, kind: SyntaxKind) {
|
||||
if (node.kind !== kind) {
|
||||
throw new ParseError(node, [kind]);
|
||||
}
|
||||
}
|
||||
|
||||
type OperatorTableList = [OperatorKind, number, string][][];
|
||||
|
||||
export class OperatorTable {
|
||||
|
||||
private operatorsByName = new FastStringMap<string, OperatorInfo>();
|
||||
//private operatorsByPrecedence = FastStringMap<number, OperatorInfo>();
|
||||
|
||||
constructor(definitions: OperatorTableList) {
|
||||
let i = 0;
|
||||
for (const group of definitions) {
|
||||
for (const [kind, arity, name] of group) {
|
||||
const info = { kind, arity, name, precedence: i }
|
||||
this.operatorsByName.set(name, info);
|
||||
//this.operatorsByPrecedence[i] = info;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public lookup(name: string): OperatorInfo | null {
|
||||
if (!this.operatorsByName.has(name)) {
|
||||
return null;
|
||||
}
|
||||
return this.operatorsByName.get(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function describeKind(kind: SyntaxKind): string {
|
||||
switch (kind) {
|
||||
case SyntaxKind.BoltExMark:
|
||||
return "'!'";
|
||||
case SyntaxKind.JSIdentifier:
|
||||
return "a JavaScript identifier"
|
||||
case SyntaxKind.BoltIdentifier:
|
||||
return "an identifier"
|
||||
case SyntaxKind.BoltOperator:
|
||||
return "an operator"
|
||||
case SyntaxKind.BoltStringLiteral:
|
||||
return "a string"
|
||||
case SyntaxKind.BoltIntegerLiteral:
|
||||
return "an integer"
|
||||
case SyntaxKind.BoltFnKeyword:
|
||||
return "'fn'"
|
||||
case SyntaxKind.BoltQuoteKeyword:
|
||||
return "'quote'";
|
||||
case SyntaxKind.BoltModKeyword:
|
||||
return "'mod'";
|
||||
case SyntaxKind.BoltForeignKeyword:
|
||||
return "'foreign'"
|
||||
case SyntaxKind.BoltMatchKeyword:
|
||||
return "'match'";
|
||||
case SyntaxKind.BoltYieldKeyword:
|
||||
return "'yield'";
|
||||
case SyntaxKind.BoltReturnKeyword:
|
||||
return "'return'";
|
||||
case SyntaxKind.BoltPubKeyword:
|
||||
return "'pub'"
|
||||
case SyntaxKind.BoltLetKeyword:
|
||||
return "'let'"
|
||||
case SyntaxKind.BoltSemi:
|
||||
return "';'"
|
||||
case SyntaxKind.BoltColon:
|
||||
return "':'"
|
||||
case SyntaxKind.BoltColonColon:
|
||||
return "'::'";
|
||||
case SyntaxKind.BoltDot:
|
||||
return "'.'"
|
||||
case SyntaxKind.JSDot:
|
||||
return "'.'"
|
||||
case SyntaxKind.JSDotDotDot:
|
||||
return "'...'"
|
||||
case SyntaxKind.BoltRArrow:
|
||||
return "'->'"
|
||||
case SyntaxKind.BoltVBar:
|
||||
return "'|'";
|
||||
case SyntaxKind.BoltComma:
|
||||
return "','"
|
||||
case SyntaxKind.BoltModKeyword:
|
||||
return "'mod'"
|
||||
case SyntaxKind.BoltStructKeyword:
|
||||
return "'struct'"
|
||||
case SyntaxKind.BoltEnumKeyword:
|
||||
return "'enum'"
|
||||
case SyntaxKind.BoltTypeKeyword:
|
||||
return "'type'";
|
||||
case SyntaxKind.BoltBraced:
|
||||
return "'{' .. '}'"
|
||||
case SyntaxKind.BoltBracketed:
|
||||
return "'[' .. ']'"
|
||||
case SyntaxKind.BoltParenthesized:
|
||||
return "'(' .. ')'"
|
||||
case SyntaxKind.EndOfFile:
|
||||
return "'}', ')', ']' or end-of-file"
|
||||
case SyntaxKind.BoltLtSign:
|
||||
return "'<'";
|
||||
case SyntaxKind.BoltGtSign:
|
||||
return "'<'";
|
||||
case SyntaxKind.BoltEqSign:
|
||||
return "'='";
|
||||
case SyntaxKind.JSOpenBrace:
|
||||
return "'{'";
|
||||
case SyntaxKind.JSCloseBrace:
|
||||
return "'}'";
|
||||
case SyntaxKind.JSOpenBracket:
|
||||
return "'['";
|
||||
case SyntaxKind.JSCloseBracket:
|
||||
return "']'";
|
||||
case SyntaxKind.JSOpenParen:
|
||||
return "'('";
|
||||
case SyntaxKind.JSCloseParen:
|
||||
return "')'";
|
||||
case SyntaxKind.JSSemi:
|
||||
return "';'";
|
||||
case SyntaxKind.JSComma:
|
||||
return "','";
|
||||
case SyntaxKind.BoltTraitKeyword:
|
||||
return "'trait'";
|
||||
case SyntaxKind.BoltTraitKeyword:
|
||||
return "'impl'";
|
||||
case SyntaxKind.BoltImplKeyword:
|
||||
return "'trait'";
|
||||
case SyntaxKind.BoltForKeyword:
|
||||
return "'for'";
|
||||
case SyntaxKind.JSMulOp:
|
||||
return "'*'";
|
||||
case SyntaxKind.JSAddOp:
|
||||
return "'+'";
|
||||
case SyntaxKind.JSDivOp:
|
||||
return "'/'";
|
||||
case SyntaxKind.JSSubOp:
|
||||
return "'-'";
|
||||
case SyntaxKind.JSLtOp:
|
||||
return "'<'";
|
||||
case SyntaxKind.JSGtOp:
|
||||
return "'>'";
|
||||
case SyntaxKind.JSBOrOp:
|
||||
return "'|'";
|
||||
case SyntaxKind.JSBXorOp:
|
||||
return "'^'";
|
||||
case SyntaxKind.JSBAndOp:
|
||||
return "'&'";
|
||||
case SyntaxKind.JSBNotOp:
|
||||
return "'~'";
|
||||
case SyntaxKind.JSNotOp:
|
||||
return "'~'";
|
||||
case SyntaxKind.JSString:
|
||||
return "a JavaScript string"
|
||||
case SyntaxKind.JSReturnKeyword:
|
||||
return "'return'";
|
||||
case SyntaxKind.JSForKeyword:
|
||||
return "'for'";
|
||||
case SyntaxKind.JSTryKeyword:
|
||||
return "'try'";
|
||||
case SyntaxKind.BoltRArrowAlt:
|
||||
return "'=>'";
|
||||
default:
|
||||
throw new Error(`failed to describe ${kindToString(kind)}`)
|
||||
}
|
||||
}
|
||||
|
||||
export function toDeclarationPath(node: BoltQualName): string[] {
|
||||
const lastElement = emit(node.name);
|
||||
if (node.modulePath === null) {
|
||||
return [ lastElement ];
|
||||
}
|
||||
return [...node.modulePath.map(id => id.text), lastElement];
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
|
||||
export const BOLT_SUPPORTED_LANGUAGES = ['Bolt', 'JS'];
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import {
|
|||
BoltDeclarationModifiers,
|
||||
BoltStringLiteral,
|
||||
BoltImportSymbol,
|
||||
BoltCallExpression,
|
||||
BoltExpressionStatement,
|
||||
createBoltExpressionStatement,
|
||||
BoltVariableDeclaration,
|
||||
|
@ -37,7 +36,6 @@ import {
|
|||
createBoltVariableDeclaration,
|
||||
BoltReturnStatement,
|
||||
createBoltReturnStatement,
|
||||
BoltRecordMember,
|
||||
BoltModule,
|
||||
createBoltModule,
|
||||
BoltTypeAliasDeclaration,
|
||||
|
@ -47,17 +45,14 @@ import {
|
|||
createBoltCallExpression,
|
||||
BoltSymbol,
|
||||
BoltTypeParameter,
|
||||
createBoltTypePattern,
|
||||
createBoltTypeParameter,
|
||||
BoltTraitDeclaration,
|
||||
createBoltTraitKeyword,
|
||||
createBoltTraitDeclaration,
|
||||
createBoltImplDeclaration,
|
||||
BoltImplDeclaration,
|
||||
BoltSourceFile,
|
||||
BoltFunctionBodyElement,
|
||||
createBoltSourceFile,
|
||||
BoltRecordField,
|
||||
setParents,
|
||||
BoltMatchExpression,
|
||||
createBoltMatchArm,
|
||||
|
@ -70,7 +65,6 @@ import {
|
|||
BoltRecordPattern,
|
||||
createBoltRecordPattern,
|
||||
createBoltRecordFieldPattern,
|
||||
BoltQuoteKeyword,
|
||||
isBoltPunctuated,
|
||||
Token,
|
||||
createBoltQuoteExpression,
|
||||
|
@ -82,23 +76,20 @@ import {
|
|||
createBoltFunctionExpression,
|
||||
BoltMacroCall,
|
||||
createBoltMacroCall,
|
||||
BoltMemberExpression,
|
||||
createBoltMemberExpression,
|
||||
} from "./ast"
|
||||
|
||||
import { parseForeignLanguage } from "./foreign"
|
||||
|
||||
import {
|
||||
Stream,
|
||||
OperatorKind,
|
||||
OperatorTable,
|
||||
assertToken,
|
||||
ParseError,
|
||||
setOrigNodeRange,
|
||||
createTokenStream,
|
||||
uniq,
|
||||
assert,
|
||||
} from "./util"
|
||||
} from "./common"
|
||||
import { Stream, uniq } from "./util"
|
||||
|
||||
export type BoltTokenStream = Stream<BoltToken>;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
import { SourceFile } from "./common"
|
||||
import { BoltSourceFile } from "./ast"
|
||||
import { SourceFile } from "./ast"
|
||||
import { FastStringMap } from "./util";
|
||||
|
||||
export class Program {
|
||||
|
@ -8,7 +7,7 @@ export class Program {
|
|||
private transformed = new FastStringMap<string, SourceFile>();
|
||||
|
||||
constructor(
|
||||
sourceFiles: BoltSourceFile[]
|
||||
sourceFiles: SourceFile[]
|
||||
) {
|
||||
for (const sourceFile of sourceFiles) {
|
||||
this.transformed.set(sourceFile.span!.file.fullPath, sourceFile);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
import { EOF, ScanError } from "./util"
|
||||
import { EOF, ScanError } from "./common"
|
||||
|
||||
import {
|
||||
TextFile,
|
||||
|
@ -8,8 +8,6 @@ import {
|
|||
} from "./text"
|
||||
|
||||
import {
|
||||
setParents,
|
||||
SyntaxKind,
|
||||
BoltToken,
|
||||
createBoltRArrowAlt,
|
||||
createEndOfFile,
|
||||
|
@ -19,7 +17,6 @@ import {
|
|||
createBoltParenthesized,
|
||||
createBoltBraced,
|
||||
createBoltBracketed,
|
||||
createBoltSourceFile,
|
||||
createBoltSemi,
|
||||
createBoltComma,
|
||||
createBoltStringLiteral,
|
||||
|
|
|
@ -10,12 +10,12 @@ import {
|
|||
BoltMacroCall,
|
||||
} from "../ast"
|
||||
|
||||
import { TypeChecker, Scope } from "../checker"
|
||||
import { TypeChecker } from "../checker"
|
||||
import { BoltTokenStream, Parser, isModifierKeyword } from "../parser"
|
||||
import { Evaluator, TRUE, FALSE } from "../evaluator"
|
||||
import { Transformer, TransformManager } from "./index"
|
||||
import { inject } from "../di"
|
||||
import {SourceFile} from "../program"
|
||||
import { SourceFile } from "../ast"
|
||||
|
||||
interface SyntaxTransformer {
|
||||
pattern: BoltPattern;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
|
||||
import { SourceFile, Program } from "../program"
|
||||
import { Program } from "../program"
|
||||
import { Container, Newable } from "../di"
|
||||
import {Evaluator} from "../evaluator";
|
||||
import {TypeChecker} from "../checker";
|
||||
import {SourceFile} from "../ast";
|
||||
|
||||
export interface Transformer {
|
||||
isApplicable(node: SourceFile): boolean;
|
||||
|
|
|
@ -5,7 +5,7 @@ import * as path from "path"
|
|||
const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
|
||||
|
||||
import { Syntax, Declaration, NodeDeclaration, TypeDeclaration, EnumDeclaration, TypeNode, NodeField } from "./ast"
|
||||
import { FastStringMap } from "../util"
|
||||
import { MapLike } from "../util"
|
||||
import { FileWriter } from "./util"
|
||||
|
||||
export function generateAST(decls: Declaration[]) {
|
||||
|
@ -21,7 +21,7 @@ export function generateAST(decls: Declaration[]) {
|
|||
const enumDecls: EnumDeclaration[] = decls.filter(decl => decl.type === 'EnumDeclaration') as EnumDeclaration[];
|
||||
const langNames: string[] = decls.filter(decl => decl.type === 'LanguageDeclaration').map(decl => decl.name);
|
||||
|
||||
const declByName: FastStringMap<Declaration> = Object.create(null);
|
||||
const declByName: MapLike<Declaration> = Object.create(null);
|
||||
i = 0;
|
||||
for (const decl of decls) {
|
||||
decl.index = i++;
|
||||
|
@ -31,7 +31,7 @@ export function generateAST(decls: Declaration[]) {
|
|||
// Generate a mapping from parent node to child node
|
||||
// This makes it easy to generate union types for the intermediate nodes.
|
||||
|
||||
const childrenOf: FastStringMap<string[]> = Object.create(null);
|
||||
const childrenOf: MapLike<string[]> = Object.create(null);
|
||||
for (const nodeDecl of nodeDecls) {
|
||||
for (const parentName of nodeDecl.parents) {
|
||||
if (childrenOf[parentName] === undefined) {
|
||||
|
|
257
src/util.ts
257
src/util.ts
|
@ -4,31 +4,12 @@ import * as fs from "fs"
|
|||
import moment from "moment"
|
||||
import chalk from "chalk"
|
||||
|
||||
import { TextFile, TextSpan, TextPos } from "./text"
|
||||
import { Scanner } from "./scanner"
|
||||
import { kindToString, Syntax, BoltQualName, BoltDeclaration, BoltDeclarationModifiers, createEndOfFile, SyntaxKind, isBoltPunctuated } from "./ast"
|
||||
|
||||
export function assert(test: boolean): void {
|
||||
if (!test) {
|
||||
throw new Error(`Invariant violation: an internal sanity check failed.`);
|
||||
}
|
||||
}
|
||||
|
||||
export function createTokenStream(node: Syntax) {
|
||||
if (isBoltPunctuated(node)) {
|
||||
const origPos = node.span!.start;
|
||||
const startPos = new TextPos(origPos.offset+1, origPos.line, origPos.column+1);
|
||||
return new Scanner(node.span!.file, node.text, startPos);
|
||||
} else if (node.kind === SyntaxKind.BoltSentence) {
|
||||
return new StreamWrapper(
|
||||
node.tokens,
|
||||
() => createEndOfFile(new TextSpan(node.span!.file, node.span!.end.clone(), node.span!.end.clone()))
|
||||
);
|
||||
} else {
|
||||
throw new Error(`Could not convert ${kindToString(node.kind)} to a token stream.`);
|
||||
}
|
||||
}
|
||||
|
||||
export interface JsonArray extends Array<Json> { };
|
||||
export interface JsonObject { [key: string]: Json }
|
||||
export type Json = null | string | boolean | number | JsonArray | JsonObject;
|
||||
|
@ -146,40 +127,6 @@ export function memoize(hasher: (...args: any[]) => string) {
|
|||
}
|
||||
}
|
||||
|
||||
const supportedLanguages = ['Bolt', 'JS'];
|
||||
|
||||
export function getLanguage(node: Syntax): string {
|
||||
const kindStr = kindToString(node.kind);
|
||||
for (const prefix of supportedLanguages) {
|
||||
if (kindStr.startsWith(prefix)) {
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
throw new Error(`Could not determine the language of ${kindStr}`);
|
||||
}
|
||||
|
||||
export function cloneSpan(span: TextSpan | null) {
|
||||
if (span === null) {
|
||||
return null;
|
||||
}
|
||||
return span.clone();
|
||||
}
|
||||
|
||||
export function setOrigNodeRange(node: Syntax, startNode: Syntax, endNode: Syntax): void {
|
||||
node.span = new TextSpan(startNode.span!.file, startNode.span!.start.clone(), endNode.span!.end.clone());
|
||||
}
|
||||
|
||||
export function hasPublicModifier(node: BoltDeclaration) {
|
||||
return (node.modifiers & BoltDeclarationModifiers.Public) > 0;
|
||||
}
|
||||
|
||||
export function toDeclarationPath(node: BoltQualName): string[] {
|
||||
if (node.modulePath === null) {
|
||||
return [ node.name.text ];
|
||||
}
|
||||
return [...node.modulePath.map(id => id.text), node.name.text];
|
||||
}
|
||||
|
||||
export interface Stream<T> {
|
||||
get(): T;
|
||||
peek(count?: number): T;
|
||||
|
@ -235,140 +182,7 @@ export function getFileStem(filepath: string): string {
|
|||
return path.basename(filepath).split('.')[0];
|
||||
}
|
||||
|
||||
export function describeKind(kind: SyntaxKind): string {
|
||||
switch (kind) {
|
||||
case SyntaxKind.BoltExMark:
|
||||
return "'!'";
|
||||
case SyntaxKind.JSIdentifier:
|
||||
return "a JavaScript identifier"
|
||||
case SyntaxKind.BoltIdentifier:
|
||||
return "an identifier"
|
||||
case SyntaxKind.BoltOperator:
|
||||
return "an operator"
|
||||
case SyntaxKind.BoltStringLiteral:
|
||||
return "a string"
|
||||
case SyntaxKind.BoltIntegerLiteral:
|
||||
return "an integer"
|
||||
case SyntaxKind.BoltFnKeyword:
|
||||
return "'fn'"
|
||||
case SyntaxKind.BoltQuoteKeyword:
|
||||
return "'quote'";
|
||||
case SyntaxKind.BoltModKeyword:
|
||||
return "'mod'";
|
||||
case SyntaxKind.BoltForeignKeyword:
|
||||
return "'foreign'"
|
||||
case SyntaxKind.BoltMatchKeyword:
|
||||
return "'match'";
|
||||
case SyntaxKind.BoltYieldKeyword:
|
||||
return "'yield'";
|
||||
case SyntaxKind.BoltReturnKeyword:
|
||||
return "'return'";
|
||||
case SyntaxKind.BoltPubKeyword:
|
||||
return "'pub'"
|
||||
case SyntaxKind.BoltLetKeyword:
|
||||
return "'let'"
|
||||
case SyntaxKind.BoltSemi:
|
||||
return "';'"
|
||||
case SyntaxKind.BoltColon:
|
||||
return "':'"
|
||||
case SyntaxKind.BoltColonColon:
|
||||
return "'::'";
|
||||
case SyntaxKind.BoltDot:
|
||||
return "'.'"
|
||||
case SyntaxKind.JSDot:
|
||||
return "'.'"
|
||||
case SyntaxKind.JSDotDotDot:
|
||||
return "'...'"
|
||||
case SyntaxKind.BoltRArrow:
|
||||
return "'->'"
|
||||
case SyntaxKind.BoltVBar:
|
||||
return "'|'";
|
||||
case SyntaxKind.BoltComma:
|
||||
return "','"
|
||||
case SyntaxKind.BoltModKeyword:
|
||||
return "'mod'"
|
||||
case SyntaxKind.BoltStructKeyword:
|
||||
return "'struct'"
|
||||
case SyntaxKind.BoltEnumKeyword:
|
||||
return "'enum'"
|
||||
case SyntaxKind.BoltTypeKeyword:
|
||||
return "'type'";
|
||||
case SyntaxKind.BoltBraced:
|
||||
return "'{' .. '}'"
|
||||
case SyntaxKind.BoltBracketed:
|
||||
return "'[' .. ']'"
|
||||
case SyntaxKind.BoltParenthesized:
|
||||
return "'(' .. ')'"
|
||||
case SyntaxKind.EndOfFile:
|
||||
return "'}', ')', ']' or end-of-file"
|
||||
case SyntaxKind.BoltLtSign:
|
||||
return "'<'";
|
||||
case SyntaxKind.BoltGtSign:
|
||||
return "'<'";
|
||||
case SyntaxKind.BoltEqSign:
|
||||
return "'='";
|
||||
case SyntaxKind.JSOpenBrace:
|
||||
return "'{'";
|
||||
case SyntaxKind.JSCloseBrace:
|
||||
return "'}'";
|
||||
case SyntaxKind.JSOpenBracket:
|
||||
return "'['";
|
||||
case SyntaxKind.JSCloseBracket:
|
||||
return "']'";
|
||||
case SyntaxKind.JSOpenParen:
|
||||
return "'('";
|
||||
case SyntaxKind.JSCloseParen:
|
||||
return "')'";
|
||||
case SyntaxKind.JSSemi:
|
||||
return "';'";
|
||||
case SyntaxKind.JSComma:
|
||||
return "','";
|
||||
case SyntaxKind.BoltTraitKeyword:
|
||||
return "'trait'";
|
||||
case SyntaxKind.BoltTraitKeyword:
|
||||
return "'impl'";
|
||||
case SyntaxKind.BoltImplKeyword:
|
||||
return "'trait'";
|
||||
case SyntaxKind.BoltForKeyword:
|
||||
return "'for'";
|
||||
case SyntaxKind.JSMulOp:
|
||||
return "'*'";
|
||||
case SyntaxKind.JSAddOp:
|
||||
return "'+'";
|
||||
case SyntaxKind.JSDivOp:
|
||||
return "'/'";
|
||||
case SyntaxKind.JSSubOp:
|
||||
return "'-'";
|
||||
case SyntaxKind.JSLtOp:
|
||||
return "'<'";
|
||||
case SyntaxKind.JSGtOp:
|
||||
return "'>'";
|
||||
case SyntaxKind.JSBOrOp:
|
||||
return "'|'";
|
||||
case SyntaxKind.JSBXorOp:
|
||||
return "'^'";
|
||||
case SyntaxKind.JSBAndOp:
|
||||
return "'&'";
|
||||
case SyntaxKind.JSBNotOp:
|
||||
return "'~'";
|
||||
case SyntaxKind.JSNotOp:
|
||||
return "'~'";
|
||||
case SyntaxKind.JSString:
|
||||
return "a JavaScript string"
|
||||
case SyntaxKind.JSReturnKeyword:
|
||||
return "'return'";
|
||||
case SyntaxKind.JSForKeyword:
|
||||
return "'for'";
|
||||
case SyntaxKind.JSTryKeyword:
|
||||
return "'try'";
|
||||
case SyntaxKind.BoltRArrowAlt:
|
||||
return "'=>'";
|
||||
default:
|
||||
throw new Error(`failed to describe ${kindToString(kind)}`)
|
||||
}
|
||||
}
|
||||
|
||||
function enumerate(elements: string[]) {
|
||||
export function enumerate(elements: string[]) {
|
||||
if (elements.length === 1) {
|
||||
return elements[0]
|
||||
} else {
|
||||
|
@ -376,68 +190,7 @@ function enumerate(elements: string[]) {
|
|||
}
|
||||
}
|
||||
|
||||
export class ParseError extends Error {
|
||||
constructor(public actual: Syntax, public expected: SyntaxKind[]) {
|
||||
super(`${actual.span!.file.origPath}:${actual.span!.start.line}:${actual.span!.start.column}: expected ${enumerate(expected.map(e => describeKind(e)))} but got ${describeKind(actual.kind)}`)
|
||||
}
|
||||
}
|
||||
|
||||
export enum OperatorKind {
|
||||
Prefix,
|
||||
InfixL,
|
||||
InfixR,
|
||||
Suffix,
|
||||
}
|
||||
|
||||
export function isRightAssoc(kind: OperatorKind) {
|
||||
return kind === OperatorKind.InfixR;
|
||||
}
|
||||
|
||||
export interface OperatorInfo {
|
||||
kind: OperatorKind;
|
||||
arity: number;
|
||||
name: string;
|
||||
precedence: number;
|
||||
}
|
||||
|
||||
export function assertToken(node: Syntax, kind: SyntaxKind) {
|
||||
if (node.kind !== kind) {
|
||||
throw new ParseError(node, [kind]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type OperatorTableList = [OperatorKind, number, string][][];
|
||||
|
||||
export class OperatorTable {
|
||||
|
||||
private operatorsByName = new FastStringMap<string, OperatorInfo>();
|
||||
//private operatorsByPrecedence = FastStringMap<number, OperatorInfo>();
|
||||
|
||||
constructor(definitions: OperatorTableList) {
|
||||
let i = 0;
|
||||
for (const group of definitions) {
|
||||
for (const [kind, arity, name] of group) {
|
||||
const info = { kind, arity, name, precedence: i }
|
||||
this.operatorsByName.set(name, info);
|
||||
//this.operatorsByPrecedence[i] = info;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public lookup(name: string): OperatorInfo | null {
|
||||
if (!this.operatorsByName.has(name)) {
|
||||
return null;
|
||||
}
|
||||
return this.operatorsByName.get(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const EOF = ''
|
||||
|
||||
function escapeChar(ch: string) {
|
||||
export function escapeChar(ch: string) {
|
||||
switch (ch) {
|
||||
case '\a': return '\\a';
|
||||
case '\b': return '\\b';
|
||||
|
@ -460,12 +213,6 @@ function escapeChar(ch: string) {
|
|||
}
|
||||
}
|
||||
|
||||
export class ScanError extends Error {
|
||||
constructor(public file: TextFile, public position: TextPos, public char: string) {
|
||||
super(`${file.origPath}:${position.line}:${position.column}: unexpected char '${escapeChar(char)}'`)
|
||||
}
|
||||
}
|
||||
|
||||
export interface MapLike<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue