Refactor and rearrange modules a bit

This change refactors a few things:

* Eliminate the `mujs.il` package; instead, introduce `mujs.ast`.

* Split `mujs.ast` into many different files, to organize things a
  little more cleanly into expressions, nodes, sources, and statements.

* Move most definitions from the `mujs.pack` package into `mujs.ast`,
  into the definitions file.  This ensures that all definitions are true
  AST nodes, meaning they will preserve source location information.
This commit is contained in:
joeduffy 2016-12-31 12:22:22 -08:00
parent 4de470af46
commit 7fcb195366
10 changed files with 307 additions and 270 deletions

View file

@ -0,0 +1,95 @@
// Copyright 2016 Marapongo, Inc. All rights reserved.
import {Node} from "./nodes";
import * as symbols from "../symbols";
// TODO(joe): consider refactoring modifiers from booleans to enums.
export interface Definition extends Node {
description?: string; // an optional informative description.
}
export type Definitions = Map<symbols.Identifier, Definition>;
// A module contains other members, including submodules, variables, functions, and/or classes.
export interface Module extends Definition {
kind: ModuleKind;
access?: Accessibility;
}
export const moduleKind = "Module";
export type ModuleKind = "Module";
// A variable is a typed storage location.
export interface Variable extends Definition {
type: symbols.TypeToken;
default?: any;
readonly?: boolean;
}
// A parameter is a variable used for functions.
export interface Parameter extends Variable {
kind: ParameterKind;
name: symbols.Identifier;
}
export const parameterKind = "Parameter";
export type ParameterKind = "Parameter";
// A module property is like a variable but has an accessibility modifier.
export interface ModuleProperty extends Variable {
kind: SimpleVariableKind;
access?: Accessibility;
}
export const simpleVariableKind = "SimpleVariable";
export type SimpleVariableKind = "SimpleVariable";
// A class property is just like a module property with some extra attributes.
export interface ClassProperty extends Variable {
access?: ClassMemberAccessibility;
static?: boolean;
primary?: boolean;
}
export const classPropertyKind = "ClassProperty";
export type ClassPropertyKind = "ClassProperty";
// A function is an executable bit of code: a class function, class method, or a lambda (see il module).
export interface Function extends Definition {
parameters?: Parameter[];
returnType?: symbols.TypeToken;
body?: ast.Block;
}
// A module method is just a function with an accessibility.
export interface ModuleMethod extends Function {
kind: ModuleMethodKind;
access?: Accessibility;
}
export const moduleMethodKind = "ModuleMethod";
export type ModuleMethodKind = "ModuleMethod";
// A class method is just like a module method with some extra attributes.
export interface ClassMethod extends Function {
kind: ClassMethodKind;
access?: ClassMemberAccessibility;
static?: boolean;
sealed?: boolean;
abstract?: boolean;
}
export const classMethodKind = "ClassMethod";
export type ClassMethodKind = "ClassMethod";
// A class can be constructed to create an object, and exports properties, methods, and has a number of attributes.
export interface Class extends Definition {
kind: ClassKind;
access?: Accessibility;
extends?: symbols.TypeToken;
implements?: symbols.TypeToken[];
sealed?: boolean;
abstract?: boolean;
record?: boolean;
interface?: boolean;
properties?: ClassProperty[];
methods?: ClassMethod[];
}
export const classKind = "Class";
export type ClassKind = "Class";

View file

@ -2,177 +2,9 @@
import * as symbols from "../symbols";
// Node is a discriminated type for all serialized blocks and instructions.
export interface Node {
kind: NodeKind;
loc?: SourceLocation;
}
// NodeType contains all of the legal Node implementations. This effectively "seales" the discriminated node type,
// and makes constructing and inspecting nodes a little more bulletproof (i.e., they aren't arbitrary strings).
export type NodeKind =
// # Statements
// ## Blocks
BlockKind |
LocalVariableDeclarationKind |
TryCatchFinallyKind |
TryCatchBlockKind |
// ## Branches
BreakStatementKind |
ContinueStatementKind |
IfStatementKind |
LabeledStatementKind |
WhileStatementKind |
// ## Miscellaneous
ExpressionStatementKind |
// # Expressions
// ## Literals
NullLiteralExpressionKind |
BoolLiteralExpressionKind |
NumberLiteralExpressionKind |
StringLiteralExpressionKind |
ObjectLiteralExpressionKind |
ObjectLiteralInitializerKind |
// ## Loads
LoadVariableExpressionKind |
LoadFunctionExpressionKind |
LoadDynamicExpressionKind |
// ## Functions
InvokeFunctionExpressionKind |
LambdaExpressionKind |
// ## Operators
UnaryOperatorExpressionKind |
BinaryOperatorExpressionKind |
// ## Miscellaneous
CastExpressionKind |
ConditionalExpressionKind
;
// SourceLocation is a location, possibly a region, in the source code.
export interface SourceLocation {
file?: string; // an optional filename in which this location resides.
start: SourcePosition; // a starting position.
end?: SourcePosition; // an optional end position for a range (if empty, this represents just a point).
}
// SourcePosition consists of a 1-indexed `line` number and a 0-indexed `column` number.
export interface SourcePosition {
line: number; // >= 1
column: number; // >= 0
}
/** # Statements **/
export interface Statement extends Node {}
/** ## Blocks **/
export interface Block extends Statement {
kind: BlockKind;
locals: LocalVariableDeclaration[];
statements: Statement[];
}
export const blockKind = "Block";
export type BlockKind = "Block";
export interface LocalVariableDeclaration extends Node {
kind: LocalVariableDeclarationKind;
key: symbols.VariableToken; // the token used to reference this local variable.
type: symbols.TypeToken; // the static type of this local variable's slot.
}
export const localVariableDeclarationKind = "LocalVariableDeclaration";
export type LocalVariableDeclarationKind = "LocalVariableDeclaration";
/** ## Try/Catch/Finally **/
export interface TryCatchFinally extends Statement {
kind: TryCatchFinallyKind;
tryBlock: Block;
catchBlocks?: TryCatchBlock[];
finallyBlock?: Block;
}
export const tryCatchFinallyKind = "TryCatchFinally";
export type TryCatchFinallyKind = "TryCatchFinally";
export interface TryCatchBlock extends Node {
kind: TryCatchBlockKind;
exception: symbols.TypeToken;
block: Block;
}
export const tryCatchBlockKind = "TryCatchBlock";
export type TryCatchBlockKind = "TryCatchBlock";
/** ## Branches **/
// A `break` statement (valid only within loops).
export interface BreakStatement extends Statement {
kind: BreakStatementKind;
label?: symbols.Identifier;
}
export const breakStatementKind = "BreakStatement";
export type BreakStatementKind = "BreakStatement";
// A `continue` statement (valid only within loops).
export interface ContinueStatement extends Statement {
kind: ContinueStatementKind;
label?: symbols.Identifier;
}
export const continueStatementKind = "ContinueStatement";
export type ContinueStatementKind = "ContinueStatement";
// An `if` statement. To simplify the AST, this is the only conditional statement available. All higher-level
// conditional constructs such as `switch`, `if / else if / ...`, etc. must be desugared into it.
export interface IfStatement extends Statement {
kind: IfStatementKind;
condition: Expression; // a `bool` condition expression.
consequent: Statement; // the statement to execute if `true`.
alternate?: Statement; // the statement to execute if `false`.
}
export const ifStatementKind = "IfStatement";
export type IfStatementKind = "IfStatement";
// A labeled statement associates an identifier with a statement for purposes of labeled jumps.
export interface LabeledStatement extends Statement {
kind: LabeledStatementKind;
label: symbols.Identifier;
statement: Statement;
}
export const labeledStatementKind = "LabeledStatement";
export type LabeledStatementKind = "LabeledStatement";
// A `while` statement. To simplify the AST, this is the only looping statement available. All higher-level
// looping constructs such as `for`, `foreach`, `for in`, `for of`, `do / while`, etc. must be desugared into it.
export interface WhileStatement extends Statement {
kind: WhileStatementKind;
test: Expression; // a `bool` statement indicating whether to continue.
}
export const whileStatementKind = "WhileStatement";
export type WhileStatementKind = "WhileStatement";
/** ## Miscellaneous **/
// A statement that performs an expression, but ignores its result.
export interface ExpressionStatement extends Statement {
kind: ExpressionStatementKind;
expression: Expression;
}
export const expressionStatementKind = "ExpressionStatement";
export type ExpressionStatementKind = "ExpressionStatement";
/** # Expressions **/
export interface Expression extends Node {}
/** ## Literals **/
/** Literals **/
export interface LiteralExpression extends Expression {}
@ -226,7 +58,7 @@ export interface ObjectLiteralInitializer extends Node {
export const objectLiteralInitializerKind = "ObjectLiteralInitializer";
export type ObjectLiteralInitializerKind = "ObjectLiteralInitializer";
/** ## Loads **/
/** Loads **/
// TODO(joe): figure out how to load/store elements and maps. Possibly just use intrinsic functions.
@ -258,7 +90,7 @@ export interface LoadDynamicExpression extends Expression {
export const loadDynamicExpressionKind = "LoadDynamicExpression";
export type LoadDynamicExpressionKind = "LoadDynamicExpression";
/** ## Functions **/
/** Functions **/
// Invokes a function.
export interface InvokeFunctionExpression extends Expression {
@ -279,7 +111,7 @@ export interface LambdaExpression extends Expression {
export const lambdaExpressionKind = "LambdaExpression";
export type LambdaExpressionKind = "LambdaExpression";
/** ## Operators **/
/** Operators **/
// A unary operator expression.
export interface UnaryOperatorExpression extends Expression {
@ -349,7 +181,7 @@ export type BinaryOperator = BinaryArithmeticOperator |
BinaryConditionalOperator |
BinaryRelationalOperator ;
/** ## Miscellaneous **/
/** Miscellaneous **/
// A cast expression; this handles both nominal and structural casts, and will throw an exception upon failure.
export interface CastExpression extends Expression {

View file

@ -0,0 +1,8 @@
// Copyright 2016 Marapongo, Inc. All rights reserved.
export * from "./definitions";
export * from "./expressions";
export * from "./nodes";
export * from "./source";
export * from "./statements";

View file

@ -0,0 +1,60 @@
// Copyright 2016 Marapongo, Inc. All rights reserved.
import {Location} from "./source";
import * as symbols from "../symbols";
// Node is a discriminated type for all serialized blocks and instructions.
export interface Node {
kind: NodeKind;
loc?: Location;
}
// NodeType contains all of the legal Node implementations. This effectively "seales" the discriminated node type,
// and makes constructing and inspecting nodes a little more bulletproof (i.e., they aren't arbitrary strings).
export type NodeKind =
// # Statements
// ## Blocks
BlockKind |
LocalVariableDeclarationKind |
TryCatchFinallyKind |
TryCatchBlockKind |
// ## Branches
BreakStatementKind |
ContinueStatementKind |
IfStatementKind |
LabeledStatementKind |
WhileStatementKind |
// ## Miscellaneous
ExpressionStatementKind |
// # Expressions
// ## Literals
NullLiteralExpressionKind |
BoolLiteralExpressionKind |
NumberLiteralExpressionKind |
StringLiteralExpressionKind |
ObjectLiteralExpressionKind |
ObjectLiteralInitializerKind |
// ## Loads
LoadVariableExpressionKind |
LoadFunctionExpressionKind |
LoadDynamicExpressionKind |
// ## Functions
InvokeFunctionExpressionKind |
LambdaExpressionKind |
// ## Operators
UnaryOperatorExpressionKind |
BinaryOperatorExpressionKind |
// ## Miscellaneous
CastExpressionKind |
ConditionalExpressionKind
;

View file

@ -0,0 +1,15 @@
// Copyright 2016 Marapongo, Inc. All rights reserved.
// Location is a location, possibly a region, in the source code.
export interface Location {
file?: string; // an optional filename in which this location resides.
start: Position; // a starting position.
end?: Position; // an optional end position for a range (if empty, this represents just a point).
}
// Position consists of a 1-indexed `line` number and a 0-indexed `column` number.
export interface Position {
line: number; // >= 1
column: number; // >= 0
}

View file

@ -0,0 +1,101 @@
// Copyright 2016 Marapongo, Inc. All rights reserved.
import {Node} from "./node";
import * as symbols from "../symbols";
export interface Statement extends Node {}
/** Blocks **/
export interface Block extends Statement {
kind: BlockKind;
locals: LocalVariableDeclaration[];
statements: Statement[];
}
export const blockKind = "Block";
export type BlockKind = "Block";
export interface LocalVariableDeclaration extends Node {
kind: LocalVariableDeclarationKind;
key: symbols.VariableToken; // the token used to reference this local variable.
type: symbols.TypeToken; // the static type of this local variable's slot.
}
export const localVariableDeclarationKind = "LocalVariableDeclaration";
export type LocalVariableDeclarationKind = "LocalVariableDeclaration";
/** Try/Catch/Finally **/
export interface TryCatchFinally extends Statement {
kind: TryCatchFinallyKind;
tryBlock: Block;
catchBlocks?: TryCatchBlock[];
finallyBlock?: Block;
}
export const tryCatchFinallyKind = "TryCatchFinally";
export type TryCatchFinallyKind = "TryCatchFinally";
export interface TryCatchBlock extends Node {
kind: TryCatchBlockKind;
exception: symbols.TypeToken;
block: Block;
}
export const tryCatchBlockKind = "TryCatchBlock";
export type TryCatchBlockKind = "TryCatchBlock";
/** Branches **/
// A `break` statement (valid only within loops).
export interface BreakStatement extends Statement {
kind: BreakStatementKind;
label?: symbols.Identifier;
}
export const breakStatementKind = "BreakStatement";
export type BreakStatementKind = "BreakStatement";
// A `continue` statement (valid only within loops).
export interface ContinueStatement extends Statement {
kind: ContinueStatementKind;
label?: symbols.Identifier;
}
export const continueStatementKind = "ContinueStatement";
export type ContinueStatementKind = "ContinueStatement";
// An `if` statement. To simplify the AST, this is the only conditional statement available. All higher-level
// conditional constructs such as `switch`, `if / else if / ...`, etc. must be desugared into it.
export interface IfStatement extends Statement {
kind: IfStatementKind;
condition: Expression; // a `bool` condition expression.
consequent: Statement; // the statement to execute if `true`.
alternate?: Statement; // the statement to execute if `false`.
}
export const ifStatementKind = "IfStatement";
export type IfStatementKind = "IfStatement";
// A labeled statement associates an identifier with a statement for purposes of labeled jumps.
export interface LabeledStatement extends Statement {
kind: LabeledStatementKind;
label: symbols.Identifier;
statement: Statement;
}
export const labeledStatementKind = "LabeledStatement";
export type LabeledStatementKind = "LabeledStatement";
// A `while` statement. To simplify the AST, this is the only looping statement available. All higher-level
// looping constructs such as `for`, `foreach`, `for in`, `for of`, `do / while`, etc. must be desugared into it.
export interface WhileStatement extends Statement {
kind: WhileStatementKind;
test: Expression; // a `bool` statement indicating whether to continue.
}
export const whileStatementKind = "WhileStatement";
export type WhileStatementKind = "WhileStatement";
/** Miscellaneous **/
// A statement that performs an expression, but ignores its result.
export interface ExpressionStatement extends Statement {
kind: ExpressionStatementKind;
expression: Expression;
}
export const expressionStatementKind = "ExpressionStatement";
export type ExpressionStatementKind = "ExpressionStatement";

View file

@ -1,7 +1,8 @@
// Copyright 2016 Marapongo, Inc. All rights reserved.
import * as ast from "./ast";
import * as compiler from "./compiler";
import * as pack from "./pack";
import * as symbols from "./symbols";
export { compiler, pack, symbols };
export { ast, compiler, pack, symbols };

View file

@ -1,10 +1,8 @@
// Copyright 2016 Marapongo, Inc. All rights reserved.
import * as il from "../il";
import * as ast from "../ast";
import * as symbols from "../symbols";
// TODO(joe): consider refactoring modifiers from booleans to enums.
// A top-level package definition.
export interface Package {
name: string; // a required fully qualified name.
@ -15,97 +13,6 @@ export interface Package {
dependencies?: symbols.ModuleToken[];
definitions?: Definitions;
}
// A set of module definitions; every package has an implicit top-level one, as does each submodule.
export interface Definitions {
modules?: Modules; // submodules.
variables?: Variables; // module-scoped variables.
functions?: Functions; // module-scoped functions.
classes?: Classes; // classes.
}
export type Modules = Map<symbols.Identifier, Module>; // a map of modules keyed by unique identifier.
export type Variables = Map<symbols.Identifier, Variable>; // a map of variables keyed by unique identifier.
export type Functions = Map<symbols.Identifier, Function>; // a map of functions keyed by unique identifier.
export type Classes = Map<symbols.Identifier, Class>; // a map of classes keyed by unique identifier.
export type Accessibility = "public" | "private"; // accessibility modifiers common to all.
export type ClassMemberAccessibility = "public" | "private" | "protected"; // accessibility modifiers for class members.
export const specialFunctionEntryPoint = ".main"; // the special package entrypoint function.
export const specialFunctionInitializer = ".init"; // the special module/class initialize function.
export const specialFunctionConstructor = ".ctor"; // the special class instance constructor function.
// A module contains other members, including submodules, variables, functions, and/or classes.
export interface Module extends Definitions {
access?: Accessibility;
description?: string; // an optional informative description.
}
// A variable is a typed storage location.
export interface Variable {
type: symbols.TypeToken;
default?: any;
readonly?: boolean;
description?: string; // an optional informative description.
}
// A simple variable is one that isn't a member of a class.
export interface SimpleVariable extends Variable {
access?: Accessibility;
}
// A class property is just like a variable, but permits some extra attriubtes.
export interface ClassProperty extends Variable {
access?: ClassMemberAccessibility;
static?: boolean;
primary?: boolean;
}
// A function is an executable bit of code: a class function, class method, or a lambda (see il module).
export interface Function {
parameters?: Variable[];
returnType?: symbols.TypeToken;
body?: il.Block;
description?: string; // an optional informative description.
}
// A simple function is one that isn't a member of a class.
export interface SimpleFunction extends Function {
access?: Accessibility;
}
// A class method is just like a function, but permits some extra attributes.
export interface ClassMethod extends Function {
access?: ClassMemberAccessibility;
static?: boolean;
sealed?: boolean;
abstract?: boolean;
}
// A class can be constructed to create an object, and exports properties, methods, and has a number of attributes.
export interface Class {
access?: Accessibility;
extends?: symbols.TypeToken;
implements?: symbols.TypeToken[];
sealed?: boolean;
abstract?: boolean;
record?: boolean;
interface?: boolean;
properties?: ClassProperty[];
methods?: ClassMethod[];
description?: string; // an optional informative description.
definitions?: ast.Definitions;
}

View file

@ -10,3 +10,12 @@ export type FunctionToken = Token; // a symbol token that resolves to a function
// Identifiers.
export type Identifier = string; // a valid identifier: (letter|"_") (letter | digit | "_")*
// Accessibility modifiers.
export type Accessibility = "public" | "private"; // accessibility modifiers common to all.
export type ClassMemberAccessibility = "public" | "private" | "protected"; // accessibility modifiers for class members.
// Special function tokens.
export const specialFunctionEntryPoint = ".main"; // the special package entrypoint function.
export const specialFunctionInitializer = ".init"; // the special module/class initialize function.
export const specialFunctionConstructor = ".ctor"; // the special class instance constructor function.

View file

@ -21,10 +21,19 @@
"cmd/index.ts",
"lib/index.ts",
"lib/ast/index.ts",
"lib/ast/definitions.ts",
"lib/ast/expressions.ts",
"lib/ast/nodes.ts",
"lib/ast/source.ts",
"lib/ast/statements.ts",
"lib/compiler/index.ts",
"lib/compiler/compile.ts",
"lib/il/index.ts",
"lib/pack/index.ts",
"lib/symbols/index.ts"
]
}