Add a first version of Lang.Bolt module

This commit is contained in:
Sam Vervaeck 2020-05-24 17:47:04 +02:00
parent 02b759a05b
commit 9b5cb6ad38
10 changed files with 265 additions and 196 deletions

View file

@ -180,6 +180,15 @@ node BoltReturnStatement > BoltStatement {
value: Option<BoltExpression>,
}
node BoltConditionalCase {
test: Option<BoltExpression>,
body: Vec<BoltFunctionBodyElement>,
}
node BoltConditionalStatement > BoltStatement {
cases: Vec<BoltConditionalCase>,
}
node BoltResumeStatement > BoltStatement {
value: BoltExpression,
}
@ -402,7 +411,9 @@ node JSReferenceExpression > JSExpression {
node JSSourceElement;
node JSStatement > JSSourceElement;
node JSFunctionBodyElement;
node JSStatement > JSSourceElement, JSFunctionBodyElement;
node JSCatchBlock {
bindings: Option<JSPattern>,
@ -419,10 +430,13 @@ node JSExpressionStatement > JSStatement {
expression: JSExpression,
}
node JSConditionalCase {
test: Option<JSExpression>,
body: Vec<JSFunctionBodyElement>,
}
node JSConditionalStatement > JSStatement {
test: JSExpression,
consequent: Vec<JSStatement>,
alternate: Vec<JSStatement>,
cases: Vec<JSConditionalCase>,
}
node JSReturnStatement > JSStatement {
@ -457,20 +471,20 @@ node JSImportDeclaration > JSDeclaration {
filename: JSString,
}
node JSFunctionDeclaration > JSDeclaration {
node JSFunctionDeclaration > JSDeclaration, JSFunctionBodyElement {
modifiers: JSDeclarationModifiers,
name: JSIdentifier,
params: Vec<JSParameter>,
body: Vec<JSStatement>,
}
node JSArrowFunctionDeclaration > JSDeclaration {
node JSArrowFunctionDeclaration > JSDeclaration, JSFunctionBodyElement {
name: JSIdentifier,
params: Vec<JSParameter>,
body: JSExpression,
}
node JSLetDeclaration > JSDeclaration {
node JSLetDeclaration > JSDeclaration, JSFunctionBodyElement {
bindings: JSPattern,
value: Option<JSExpression>,
}

203
src/ast.d.ts vendored
View file

@ -59,82 +59,85 @@ export const enum SyntaxKind {
BoltBlockExpression = 66,
BoltConstantExpression = 67,
BoltReturnStatement = 69,
BoltResumeStatement = 70,
BoltExpressionStatement = 71,
BoltParameter = 72,
BoltModule = 76,
BoltFunctionDeclaration = 78,
BoltVariableDeclaration = 79,
BoltPlainImportSymbol = 81,
BoltImportDeclaration = 82,
BoltTraitDeclaration = 83,
BoltImplDeclaration = 84,
BoltTypeAliasDeclaration = 85,
BoltRecordField = 87,
BoltRecordDeclaration = 88,
BoltMacroCall = 90,
JSOperator = 93,
JSIdentifier = 94,
JSString = 95,
JSInteger = 96,
JSFromKeyword = 97,
JSReturnKeyword = 98,
JSTryKeyword = 99,
JSFinallyKeyword = 100,
JSCatchKeyword = 101,
JSImportKeyword = 102,
JSAsKeyword = 103,
JSConstKeyword = 104,
JSLetKeyword = 105,
JSExportKeyword = 106,
JSFunctionKeyword = 107,
JSWhileKeyword = 108,
JSForKeyword = 109,
JSCloseBrace = 110,
JSCloseBracket = 111,
JSCloseParen = 112,
JSOpenBrace = 113,
JSOpenBracket = 114,
JSOpenParen = 115,
JSSemi = 116,
JSComma = 117,
JSDot = 118,
JSDotDotDot = 119,
JSMulOp = 120,
JSAddOp = 121,
JSDivOp = 122,
JSSubOp = 123,
JSLtOp = 124,
JSGtOp = 125,
JSBOrOp = 126,
JSBXorOp = 127,
JSBAndOp = 128,
JSBNotOp = 129,
JSNotOp = 130,
JSBindPattern = 132,
JSConstantExpression = 134,
JSMemberExpression = 135,
JSCallExpression = 136,
JSBinaryExpression = 137,
JSUnaryExpression = 138,
JSNewExpression = 139,
JSSequenceExpression = 140,
JSConditionalExpression = 141,
JSLiteralExpression = 143,
JSReferenceExpression = 144,
JSCatchBlock = 147,
JSTryCatchStatement = 148,
JSExpressionStatement = 149,
JSConditionalStatement = 150,
JSReturnStatement = 151,
JSParameter = 152,
JSImportStarBinding = 156,
JSImportAsBinding = 157,
JSImportDeclaration = 158,
JSFunctionDeclaration = 159,
JSArrowFunctionDeclaration = 160,
JSLetDeclaration = 161,
JSSourceFile = 162,
BoltConditionalCase = 70,
BoltConditionalStatement = 71,
BoltResumeStatement = 72,
BoltExpressionStatement = 73,
BoltParameter = 74,
BoltModule = 78,
BoltFunctionDeclaration = 80,
BoltVariableDeclaration = 81,
BoltPlainImportSymbol = 83,
BoltImportDeclaration = 84,
BoltTraitDeclaration = 85,
BoltImplDeclaration = 86,
BoltTypeAliasDeclaration = 87,
BoltRecordField = 89,
BoltRecordDeclaration = 90,
BoltMacroCall = 92,
JSOperator = 95,
JSIdentifier = 96,
JSString = 97,
JSInteger = 98,
JSFromKeyword = 99,
JSReturnKeyword = 100,
JSTryKeyword = 101,
JSFinallyKeyword = 102,
JSCatchKeyword = 103,
JSImportKeyword = 104,
JSAsKeyword = 105,
JSConstKeyword = 106,
JSLetKeyword = 107,
JSExportKeyword = 108,
JSFunctionKeyword = 109,
JSWhileKeyword = 110,
JSForKeyword = 111,
JSCloseBrace = 112,
JSCloseBracket = 113,
JSCloseParen = 114,
JSOpenBrace = 115,
JSOpenBracket = 116,
JSOpenParen = 117,
JSSemi = 118,
JSComma = 119,
JSDot = 120,
JSDotDotDot = 121,
JSMulOp = 122,
JSAddOp = 123,
JSDivOp = 124,
JSSubOp = 125,
JSLtOp = 126,
JSGtOp = 127,
JSBOrOp = 128,
JSBXorOp = 129,
JSBAndOp = 130,
JSBNotOp = 131,
JSNotOp = 132,
JSBindPattern = 134,
JSConstantExpression = 136,
JSMemberExpression = 137,
JSCallExpression = 138,
JSBinaryExpression = 139,
JSUnaryExpression = 140,
JSNewExpression = 141,
JSSequenceExpression = 142,
JSConditionalExpression = 143,
JSLiteralExpression = 145,
JSReferenceExpression = 146,
JSCatchBlock = 150,
JSTryCatchStatement = 151,
JSExpressionStatement = 152,
JSConditionalCase = 153,
JSConditionalStatement = 154,
JSReturnStatement = 155,
JSParameter = 156,
JSImportStarBinding = 160,
JSImportAsBinding = 161,
JSImportDeclaration = 162,
JSFunctionDeclaration = 163,
JSArrowFunctionDeclaration = 164,
JSLetDeclaration = 165,
JSSourceFile = 166,
}
@ -523,6 +526,7 @@ export interface BoltConstantExpression extends SyntaxBase<SyntaxKind.BoltConsta
export type BoltStatement
= BoltReturnStatement
| BoltConditionalStatement
| BoltResumeStatement
| BoltExpressionStatement
| BoltMacroCall
@ -533,6 +537,17 @@ export interface BoltReturnStatement extends SyntaxBase<SyntaxKind.BoltReturnSta
value: BoltExpression | null;
}
export interface BoltConditionalCase extends SyntaxBase<SyntaxKind.BoltConditionalCase> {
kind: SyntaxKind.BoltConditionalCase;
test: BoltExpression | null;
body: BoltFunctionBodyElement[];
}
export interface BoltConditionalStatement extends SyntaxBase<SyntaxKind.BoltConditionalStatement> {
kind: SyntaxKind.BoltConditionalStatement;
cases: BoltConditionalCase[];
}
export interface BoltResumeStatement extends SyntaxBase<SyntaxKind.BoltResumeStatement> {
kind: SyntaxKind.BoltResumeStatement;
value: BoltExpression;
@ -581,6 +596,7 @@ export interface BoltModule extends SyntaxBase<SyntaxKind.BoltModule> {
export type BoltFunctionBodyElement
= BoltReturnStatement
| BoltConditionalStatement
| BoltResumeStatement
| BoltExpressionStatement
| BoltMacroCall
@ -667,6 +683,7 @@ export interface BoltRecordDeclaration extends SyntaxBase<SyntaxKind.BoltRecordD
export type BoltSourceElement
= BoltReturnStatement
| BoltConditionalStatement
| BoltResumeStatement
| BoltExpressionStatement
| BoltMacroCall
@ -978,6 +995,15 @@ export type JSSourceElement
| JSLetDeclaration
export type JSFunctionBodyElement
= JSExpressionStatement
| JSConditionalStatement
| JSReturnStatement
| JSFunctionDeclaration
| JSArrowFunctionDeclaration
| JSLetDeclaration
export type JSStatement
= JSExpressionStatement
| JSConditionalStatement
@ -1002,11 +1028,15 @@ export interface JSExpressionStatement extends SyntaxBase<SyntaxKind.JSExpressio
expression: JSExpression;
}
export interface JSConditionalCase extends SyntaxBase<SyntaxKind.JSConditionalCase> {
kind: SyntaxKind.JSConditionalCase;
test: JSExpression | null;
body: JSFunctionBodyElement[];
}
export interface JSConditionalStatement extends SyntaxBase<SyntaxKind.JSConditionalStatement> {
kind: SyntaxKind.JSConditionalStatement;
test: JSExpression;
consequent: JSStatement[];
alternate: JSStatement[];
cases: JSConditionalCase[];
}
export interface JSReturnStatement extends SyntaxBase<SyntaxKind.JSReturnStatement> {
@ -1137,6 +1167,8 @@ export type BoltSyntax
| BoltBlockExpression
| BoltConstantExpression
| BoltReturnStatement
| BoltConditionalCase
| BoltConditionalStatement
| BoltResumeStatement
| BoltExpressionStatement
| BoltParameter
@ -1206,6 +1238,7 @@ export type JSSyntax
| JSCatchBlock
| JSTryCatchStatement
| JSExpressionStatement
| JSConditionalCase
| JSConditionalStatement
| JSReturnStatement
| JSParameter
@ -1278,6 +1311,8 @@ export type Syntax
| BoltBlockExpression
| BoltConstantExpression
| BoltReturnStatement
| BoltConditionalCase
| BoltConditionalStatement
| BoltResumeStatement
| BoltExpressionStatement
| BoltParameter
@ -1344,6 +1379,7 @@ export type Syntax
| JSCatchBlock
| JSTryCatchStatement
| JSExpressionStatement
| JSConditionalCase
| JSConditionalStatement
| JSReturnStatement
| JSParameter
@ -1417,6 +1453,8 @@ export function createBoltCaseExpression(cases: BoltCase[], span?: TextSpan | nu
export function createBoltBlockExpression(elements: BoltFunctionBodyElement[], span?: TextSpan | null): BoltBlockExpression;
export function createBoltConstantExpression(value: BoltValue, span?: TextSpan | null): BoltConstantExpression;
export function createBoltReturnStatement(value: BoltExpression | null, span?: TextSpan | null): BoltReturnStatement;
export function createBoltConditionalCase(test: BoltExpression | null, body: BoltFunctionBodyElement[], span?: TextSpan | null): BoltConditionalCase;
export function createBoltConditionalStatement(cases: BoltConditionalCase[], span?: TextSpan | null): BoltConditionalStatement;
export function createBoltResumeStatement(value: BoltExpression, span?: TextSpan | null): BoltResumeStatement;
export function createBoltExpressionStatement(expression: BoltExpression, span?: TextSpan | null): BoltExpressionStatement;
export function createBoltParameter(index: number, bindings: BoltPattern, type: BoltTypeExpression | null, defaultValue: BoltExpression | null, span?: TextSpan | null): BoltParameter;
@ -1483,7 +1521,8 @@ export function createJSReferenceExpression(name: string, span?: TextSpan | null
export function createJSCatchBlock(bindings: JSPattern | null, elements: JSSourceElement[], span?: TextSpan | null): JSCatchBlock;
export function createJSTryCatchStatement(tryBlock: JSSourceElement[], catchBlock: JSCatchBlock | null, finalBlock: JSSourceElement[] | null, span?: TextSpan | null): JSTryCatchStatement;
export function createJSExpressionStatement(expression: JSExpression, span?: TextSpan | null): JSExpressionStatement;
export function createJSConditionalStatement(test: JSExpression, consequent: JSStatement[], alternate: JSStatement[], span?: TextSpan | null): JSConditionalStatement;
export function createJSConditionalCase(test: JSExpression | null, body: JSFunctionBodyElement[], span?: TextSpan | null): JSConditionalCase;
export function createJSConditionalStatement(cases: JSConditionalCase[], span?: TextSpan | null): JSConditionalStatement;
export function createJSReturnStatement(value: JSExpression | null, span?: TextSpan | null): JSReturnStatement;
export function createJSParameter(index: number, bindings: JSPattern, defaultValue: JSExpression | null, span?: TextSpan | null): JSParameter;
export function createJSImportStarBinding(local: JSIdentifier, span?: TextSpan | null): JSImportStarBinding;
@ -1561,6 +1600,8 @@ export function isBoltBlockExpression(value: any): value is BoltBlockExpression;
export function isBoltConstantExpression(value: any): value is BoltConstantExpression;
export function isBoltStatement(value: any): value is BoltStatement;
export function isBoltReturnStatement(value: any): value is BoltReturnStatement;
export function isBoltConditionalCase(value: any): value is BoltConditionalCase;
export function isBoltConditionalStatement(value: any): value is BoltConditionalStatement;
export function isBoltResumeStatement(value: any): value is BoltResumeStatement;
export function isBoltExpressionStatement(value: any): value is BoltExpressionStatement;
export function isBoltParameter(value: any): value is BoltParameter;
@ -1634,10 +1675,12 @@ export function isJSConditionalExpression(value: any): value is JSConditionalExp
export function isJSLiteralExpression(value: any): value is JSLiteralExpression;
export function isJSReferenceExpression(value: any): value is JSReferenceExpression;
export function isJSSourceElement(value: any): value is JSSourceElement;
export function isJSFunctionBodyElement(value: any): value is JSFunctionBodyElement;
export function isJSStatement(value: any): value is JSStatement;
export function isJSCatchBlock(value: any): value is JSCatchBlock;
export function isJSTryCatchStatement(value: any): value is JSTryCatchStatement;
export function isJSExpressionStatement(value: any): value is JSExpressionStatement;
export function isJSConditionalCase(value: any): value is JSConditionalCase;
export function isJSConditionalStatement(value: any): value is JSConditionalStatement;
export function isJSReturnStatement(value: any): value is JSReturnStatement;
export function isJSParameter(value: any): value is JSParameter;

View file

@ -2,9 +2,15 @@ import {
BoltFunctionBodyElement,
BoltReturnStatement,
SyntaxKind,
BoltExpression
BoltExpression,
BoltSourceFile,
JSSourceFile
} from "./ast";
export type SourceFile
= BoltSourceFile
| JSSourceFile
export type BoltFunctionBody = BoltFunctionBodyElement[];
export function getReturnStatementsInFunctionBody(body: BoltFunctionBody): BoltReturnStatement[] {

View file

@ -104,7 +104,6 @@ export class Frontend {
case "JS":
const transforms = new TransformManager(this.container);
transforms.register(ExpandBoltTransform);
transforms.register(EliminateModulesTransform);
transforms.register(CompileBoltToJSTransform);
transforms.register(ConstFoldTransform);
transforms.apply(program);

View file

@ -1,11 +1,8 @@
import { BoltSourceFile, JSSourceFile } from "./ast"
import { SourceFile } from "./common"
import { BoltSourceFile } from "./ast"
import { FastStringMap } from "./util";
export type SourceFile
= BoltSourceFile
| JSSourceFile
export class Program {
private transformed = new FastStringMap<string, SourceFile>();

View file

@ -39,6 +39,7 @@ import {
isBoltStatement,
JSBindPattern,
BoltSourceElement,
createJSParameter,
} from "../ast"
import { hasPublicModifier, setOrigNodeRange } from "../util"
@ -69,7 +70,7 @@ class CompileContext {
private generatedNodes: JSSyntax[] = [];
constructor(public scope: Scope) {
constructor() {
}
@ -98,7 +99,7 @@ export class BoltToJSTransform implements Transformer {
}
public transform(sourceFile: BoltSourceFile): JSSourceFile {
const ctx = new CompileContext(this.checker.getScope(sourceFile))
const ctx = new CompileContext()
for (const element of sourceFile.elements) {
this.compileSourceElement(element, ctx);
}
@ -110,6 +111,7 @@ export class BoltToJSTransform implements Transformer {
switch (node.kind) {
case SyntaxKind.BoltCallExpression:
{
const compiledOperator = this.compileExpression(node.operator, ctx);
const compiledArgs = node.operands.map(arg => this.compileExpression(arg, ctx))
return createJSCallExpression(
@ -117,19 +119,22 @@ export class BoltToJSTransform implements Transformer {
compiledArgs,
node.span,
);
}
case SyntaxKind.BoltReferenceExpression:
{
assert(node.name.modulePath === null);
return createJSReferenceExpression(
node.name.name.text,
node.span,
);
const result = createJSReferenceExpression(node.name.name.text);
setOrigNodeRange(result, node, node);
return result;
}
case SyntaxKind.BoltConstantExpression:
return createJSConstantExpression(
node.value,
node.span,
);
{
const result = createJSConstantExpression(node.value);
setOrigNodeRange(result, node, node);
return result;
}
default:
throw new Error(`Could not compile expression node ${kindToString(node.kind)}`)
@ -147,7 +152,7 @@ export class BoltToJSTransform implements Transformer {
return jsBindPatt;
}
protected compileSourceElement(node: BoltSourceElement, ctx: CompileContext) {
private compileSourceElement(node: BoltSourceElement, ctx: CompileContext) {
switch (node.kind) {
@ -167,6 +172,7 @@ export class BoltToJSTransform implements Transformer {
break;
case SyntaxKind.BoltVariableDeclaration:
{
const jsValue = node.value !== null ? this.compileExpression(node.value, ctx) : null;
const jsValueBindPatt = this.convertPattern(node.bindings);
const jsValueDecl = createJSLetDeclaration(
@ -175,35 +181,50 @@ export class BoltToJSTransform implements Transformer {
);
ctx.appendNode(jsValueDecl);
break;
}
case SyntaxKind.BoltFunctionDeclaration:
{
if (node.body === null) {
break;
}
if (node.target === "JS") {
const params: JSParameter[] = [];
let body: JSStatement[] = [];
let modifiers = 0;
if (hasPublicModifier(node)) {
modifiers |= JSDeclarationModifiers.IsExported;;
}
let i = 0;
for (const param of node.params) {
assert(param.defaultValue === null);
const jsPatt = this.convertPattern(param.bindings)
params.push(jsPatt);
const jsParam = createJSParameter(i, jsPatt, null);
params.push(jsParam);
i++;
}
let result = createJSFunctionDeclaration(
0,
createJSIdentifier(node.name.text, node.name.span),
const name = createJSIdentifier(node.name.text)
setOrigNodeRange(name, node.name, node.name);
const bodyCtx = new CompileContext();
if (node.target === "JS") {
for (const element of node.body) {
this.compileJSStatement(element, bodyCtx);
}
} else {
for (const element of node.body) {
this.compileSourceElement(element, bodyCtx);
}
}
const result = createJSFunctionDeclaration(
modifiers,
name,
params,
body,
bodyCtx.getGeneratedNodes() as JSStatement[],
node.span,
);
if (hasPublicModifier(node)) {
result.modifiers |= JSDeclarationModifiers.IsExported;;
}
setOrigNodeRange(result, node, node);
ctx.appendNode(result)
} else {
// TODO
throw new Error(`Compiling native functions is not yet implemented.`);
}
break;
}
default:
throw new Error(`Could not compile node ${kindToString(node.kind)}`);

View file

@ -1,55 +0,0 @@
import {TransformManager} from ".";
import {SourceFile} from "../program";
import {isBoltSourceFile, createBoltSourceFile, BoltSourceElement, SyntaxKind, BoltModule, isBoltModule} from "../ast";
import {setOrigNodeRange} from "../util";
export class EliminateModulesTransform {
constructor(private transformers: TransformManager) {
}
public isApplicable(sourceFile: SourceFile) {
return isBoltSourceFile(sourceFile);
}
public transform(sourceFile: SourceFile): SourceFile {
let needsUpdate = false;
const elements: BoltSourceElement[] = [];
for (const element of sourceFile.elements) {
if (element.kind === SyntaxKind.BoltModule) {
this.extractModuleElements(element, elements);
needsUpdate = true;
} else {
elements.push(element);
}
}
if (!needsUpdate) {
return sourceFile;
}
const newSourceFile = createBoltSourceFile(elements);
setOrigNodeRange(newSourceFile, sourceFile, sourceFile);
return newSourceFile;
}
public extractModuleElements(node: BoltModule, out: BoltSourceElement[]) {
for (const element of node.elements) {
switch (element.kind) {
case SyntaxKind.BoltModule:
this.extractModuleElements(node, out);
break;
case SyntaxKind.BoltRecordDeclaration:
// TODO
break;
}
}
}
}
export default EliminateModulesTransform;

View file

@ -1,5 +1,5 @@
mod Lang.Bolt.AST {
mod Bolt.Lang {
pub struct Pos {
offset: Int,
@ -20,5 +20,55 @@ mod Lang.Bolt.AST {
parent: Option<Node>,
}
pub type Token
= Identifier
pub struct ConditionalCase {
test: Option<Expression>,
result: Vec<FunctionBodyElement>,
}
pub struct ConditionalStatement {
cases: Vec<ConditionalCase>,
}
pub type Statement
= ReturnStatement
| ConditionalStatement
pub type Expression
= ReferenceExpression
pub type Transformer = fn (node: Node) -> Node;
fn build_predicate_from_pattern(pattern: Pattern) -> Expression {
match pattern {
BindPattern { name } => quote(true).taint(pattern),
VariantPatten { elements } => quote(or($(elements),*)),
RecordPattern { members } => quote(and($elements),*)),
}
}
fn eliminate_match_rule(stx: Syntax) {
match stx {
quote {
match $value: Expression {
$patterns @ ( $pattern: Pattern => $expression: Expression ),* (,)?
}
} => {
let cases = patterns.map(|pattern| {
ConditionalCase::from_node(
pattern,
build_predicate_from_pattern(pattern),
value
)
});
return ConditionalStatement::from_node(stx, cases);
}
}
}
register_transformer!(elminate_match_rule);
}

View file

@ -1,11 +1,5 @@
syntax {
quote {
macro $name: QualName {
}
} => {
}
}
import "lang/bolt" (
Identifier,
Syntax,
);