Skip to content

Instantly share code, notes, and snippets.

@rogerpoon
Created April 19, 2019 19:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rogerpoon/b7b63aecaf8e283172886aa98547fef2 to your computer and use it in GitHub Desktop.
Save rogerpoon/b7b63aecaf8e283172886aa98547fef2 to your computer and use it in GitHub Desktop.
abstract class Node {}
abstract class Statement : Node {}
abstract class Expression : Node {}
class Program : Node
{
Statement[] body;
Program() {
this.body = [];
}
Program(...Statement body) {
this.body = body;
}
void push(...Statement statements) {
body = body.concat(statements);
}
override string toString() {
return "!function(){%s}()".format(body.join(""));
}
}
class Identifier : Expression
{
string name;
Identifier(string name) {
this.name = name;
}
override string toString() {
return name.toString();
}
}
class BlockStatement : Statement
{
Statement[] body;
BlockStatement() {
this.body = [];
}
BlockStatement(...Statement body) {
this.body = body;
}
override string toString() {
return "{" + body.join("") + "}";
}
}
class EmptyStatement : Statement
{
override string toString() {
return ";";
}
}
class ExpressionStatement : Statement
{
Expression expression;
ExpressionStatement(Expression expression) {
this.expression = expression;
}
override string toString() {
return expression.toString() + ";";
}
}
class IfStatement : Statement
{
Expression condition;
Statement consequent;
Statement? alternate;
IfStatement(Expression condition, Statement consequent) {
this.condition = condition;
this.consequent = consequent;
this.alternate = null;
}
IfStatement(Expression condition,
Statement consequent,
Statement alternate)
{
this.condition = condition;
this.consequent = consequent;
this.alternate = alternate;
}
override string toString() {
if (alternate == null) {
return "if(%s)%s".format(condition.toString(), consequent.toString());
}
else {
return "if(%s)%selse %s".format( condition.toString(),
consequent.toString(),
(string) alternate?.toString());
}
}
}
class LabeledStatement : Statement
{
Identifier label;
Statement body;
LabeledStatement(Identifier label, Statement body) {
this.label = label;
this.body = body;
}
override string toString() {
return label.toString() + ":" + body.toString();
}
}
class BreakStatement : Statement
{
Identifier? label;
BreakStatement() {
this.label = null;
}
BreakStatement(Identifier label) {
this.label = label;
}
override string toString() {
return "break%s;".format(label?.toString()?.prepend(" ") ?? "");
}
}
class ContinueStatement : Statement
{
Identifier? label;
ContinueStatement() {
this.label = null;
}
ContinueStatement(Identifier label) {
this.label = label;
}
override string toString() {
return "continue%s;".format(label?.toString()?.prepend(" ") ?? "");
}
}
class WithStatement : Statement
{
Expression object;
Statement body;
WithStatement(Expression object, Statement body) {
this.object = object;
this.body = body;
}
override string toString() {
return "with(%s)%s".format(object.toString(), body.toString());
}
}
abstract class SwitchCondition : Node {}
class SwitchCase : SwitchCondition
{
Expression test;
Statement[] consequents;
SwitchCase(Expression test, ...Statement consequents) {
this.test = test;
this.consequents = consequents;
}
override string toString() {
return "case " + test.toString() + ":" + consequents.toString();
}
}
class SwitchDefault : SwitchCondition
{
Statement[] consequents;
SwitchDefault(...Statement consequents) {
this.consequents = consequents;
}
override string toString() {
return "default:" + consequents.toString();
}
}
class SwitchStatement : Statement
{
Expression discriminant;
SwitchCondition[] cases;
SwitchStatement(Expression discriminant, ...SwitchCondition cases) {
this.discriminant = discriminant;
this.cases = cases;
}
override string toString() {
return "switch(%s){%s}".format(discriminant.toString(), cases.join(""));
}
}
class ReturnStatement : Statement
{
Expression? argument;
ReturnStatement() {
this.argument = null;
}
ReturnStatement(Expression argument) {
this.argument = argument;
}
override string toString() {
return "return%s;".format(argument?.toString()?.prepend(" ") ?? "");
}
}
class ThrowStatement : Statement
{
Expression argument;
ThrowStatement(Expression argument) {
this.argument = argument;
}
override string toString() {
return "throw " + argument.toString() + ";";
}
}
class CatchClause : Node
{
Expression param;
BlockStatement body;
CatchClause(Expression param, BlockStatement body) {
this.param = param;
this.body = body;
}
override string toString() {
return "catch(" + param.toString() + ")" + body.toString();
}
}
class TryStatement : Statement
{
BlockStatement block;
CatchClause handler;
BlockStatement? finalizer;
TryStatement(BlockStatement block, CatchClause handler) {
this.block = block;
this.handler = handler;
this.finalizer = null;
}
TryStatement(BlockStatement block, CatchClause handler, BlockStatement finalizer) {
this.block = block;
this.handler = handler;
this.finalizer = finalizer;
}
override string toString() {
if (finalizer == null) {
return "try" + block.toString() + handler.toString();
}
else {
return "try%s%sfinally%s".format(block.toString(), handler.toString(), (string) finalizer?.toString());
}
}
}
class WhileStatement : Statement
{
Expression test;
Statement body;
WhileStatement(Expression test, Statement body) {
this.test = test;
this.body = body;
}
override string toString() {
return "while(%s)%s".format(test.toString(), body.toString());
}
}
class DoWhileStatement : Statement
{
Statement body;
Expression test;
DoWhileStatement(Statement body, Expression test) {
this.body = body;
this.test = test;
}
override string toString() {
return "do %s while(%s);".format(body.toString(), test.toString());
}
}
class ForStatement : Statement
{
Node? init;
Expression? test;
Expression? update;
Statement body;
ForStatement(VariableDeclaration? init, Expression? test, Expression? update, Statement body) {
this.init = init;
this.test = test;
this.update = update;
this.body = body;
}
ForStatement(Expression? init, Expression? test, Expression? update, Statement body) {
this.init = init;
this.test = test;
this.update = update;
this.body = body;
}
override string toString() {
return "for(%s;%s;%s)%s".format(init?.toString() ?? "",
test?.toString() ?? "",
update?.toString() ?? "",
body.toString());
}
}
class ForInStatement : Statement
{
Node left;
Expression right;
Statement body;
ForInStatement(VariableDeclaration left, Expression right, Statement body) {
this.left = left;
this.right = right;
this.body = body;
}
ForInStatement(Identifier left, Expression right, Statement body) {
this.left = left;
this.right = right;
this.body = body;
}
override string toString() {
return "for(%s in %s)%s".format(left.toString(), right.toString(), body.toString());
}
}
class DebuggerStatement : Statement
{
override string toString() {
return "debugger;";
}
}
class FunctionDeclaration : Statement
{
Identifier id;
Identifier[] params;
BlockStatement body;
FunctionDeclaration(Identifier id, ...Identifier params, BlockStatement body) {
this.id = id;
this.params = params;
this.body = body;
}
override string toString() {
return "function %s(%s)%s".format(id.toString(), params.join(","), body.toString());
}
}
class VariableDeclarator : Node
{
Identifier id;
Expression? init;
VariableDeclarator(Identifier id) {
this.id = id;
this.init = null;
}
VariableDeclarator(Identifier id, Expression init) {
this.id = id;
this.init = init;
}
override string toString() {
if (init == null) {
return id.toString();
}
else {
return id.toString() + "=" + (string) init?.toString();
}
}
}
class VariableDeclaration : Node
{
VariableDeclarator[] declarations;
VariableDeclaration(...VariableDeclarator declarations) {
this.declarations = declarations;
}
override string toString() {
return "var " + declarations.join(",");
}
}
class VariableStatement : Statement
{
VariableDeclaration declaration;
VariableStatement(VariableDeclaration declaration) {
this.declaration = declaration;
}
override string toString() {
return declaration.toString() + ";";
}
}
class ThisExpression : Expression
{
override string toString() {
return "this";
}
}
class ArrayExpression : Expression
{
Expression[] elements;
ArrayExpression() {
this.elements = [];
}
ArrayExpression(...Expression elements) {
this.elements = elements;
}
ArrayExpression(descend Expression[] elements) {
this.elements = [];
foreach(Expression e in elements) {
this.elements.push(e);
}
}
override string toString() {
return "[" + elements.join(",") + "]";
}
}
class ObjectProperty : Node
{
Expression key;
Expression value;
ObjectProperty(Identifier key, Expression value) {
this.key = key;
this.value = value;
}
ObjectProperty(StringLiteral key, Expression value) {
this.key = key;
this.value = value;
}
override string toString() {
return key.toString() + ":" + value.toString();
}
}
class ObjectExpression : Expression
{
ObjectProperty[] properties;
ObjectExpression(...ObjectProperty properties) {
this.properties = properties;
}
override string toString() {
return "{" + properties.join(",") + "}";
}
}
class FunctionExpression : Expression
{
Identifier? id;
Identifier[] params;
BlockStatement body;
FunctionExpression(...Identifier params, BlockStatement body) {
this.id = null;
this.params = params;
this.body = body;
}
FunctionExpression(Identifier id, ...Identifier params, BlockStatement body) {
this.id = id;
this.params = params;
this.body = body;
}
bool isAnonymous() {
return this.id == null;
}
override string toString() {
return "function%s(%s)%s".format(id?.toString()?.prepend(" ") ?? "", params.join(","), body.toString());
}
}
class GroupExpression : Expression
{
Expression expression;
GroupExpression(Expression expression) {
this.expression = expression;
}
override string toString() {
return "(" + expression.toString() + ")";
}
}
class SequenceExpression : Expression
{
Expression[] expressions;
SequenceExpression(...Expression expressions) {
this.expressions = expressions;
}
override string toString() {
return expressions.join(",");
}
}
class UnaryExpression : Expression
{
string operator;
Expression argument;
UnaryExpression(string operator, Expression argument) {
this.operator = operator;
this.argument = argument;
}
override string toString() {
bool isKeyword = operator.isLowerCase();
string spacer = isKeyword ? " " : "";
return operator.toString() + spacer + argument.toString();
}
}
class BinaryExpression : Expression
{
Expression left;
string operator;
Expression right;
BinaryExpression(Expression left, string operator, Expression right) {
this.left = left;
this.operator = operator;
this.right = right;
}
override string toString() {
return left.toString() + operator.toString() + right.toString();
}
}
class AssignmentExpression : Expression
{
Expression left;
string? operator;
Expression right;
AssignmentExpression(Identifier left, Expression right) {
this.left = left;
this.operator = null;
this.right = right;
}
AssignmentExpression(MemberExpression left, Expression right) {
this.left = left;
this.operator = null;
this.right = right;
}
AssignmentExpression(AssignmentExpression left, Expression right) {
this.left = left;
this.operator = null;
this.right = right;
}
AssignmentExpression(Identifier left, string operator, Expression right) {
this.left = left;
this.operator = operator;
this.right = right;
}
AssignmentExpression(MemberExpression left, string operator, Expression right) {
this.left = left;
this.operator = operator;
this.right = right;
}
AssignmentExpression(AssignmentExpression left, string operator, Expression right) {
this.left = left;
this.operator = operator;
this.right = right;
}
override string toString() {
string assignment = operator ?? "=";
return left.toString() + assignment + right.toString();
}
}
class UpdateExpression : Expression
{
string operator;
bool prefix;
Expression argument;
UpdateExpression(string operator, Expression argument, bool prefix) {
this.operator = operator;
this.argument = argument;
this.prefix = prefix;
}
override string toString() {
if (prefix) {
// Prefix with space to avoid generation of `a + ++b` as `a+++b`
return operator.prepend(" ") + argument.toString();
}
else {
// Append space to avoid generation of `a++ + b` as `a+++b`
return argument.toString() + operator.append(" ");
}
}
}
class LogicalExpression : Expression
{
Expression left;
string operator;
Expression right;
LogicalExpression(Expression left, string operator, Expression right) {
this.left = left;
this.operator = operator;
this.right = right;
}
override string toString() {
return left.toString() + operator.toString() + right.toString();
}
}
class ConditionalExpression : Expression
{
Expression test;
Expression consequent;
Expression alternate;
ConditionalExpression(Expression test, Expression consequent, Expression alternate) {
this.test = test;
this.consequent = consequent;
this.alternate = alternate;
}
override string toString() {
return "%s?%s:%s".format(test.toString(), consequent.toString(), alternate.toString());
}
}
class NewExpression : Expression
{
Expression callee;
Expression[] arguments;
NewExpression(Expression callee) {
this.callee = callee;
this.arguments = [];
}
NewExpression(Expression callee, ...Expression arguments) {
this.callee = callee;
this.arguments = arguments;
}
override string toString() {
return "new %s(%s)".format(callee.toString(), arguments.join(","));
}
}
class CallExpression : Expression
{
Expression callee;
Expression[] arguments;
CallExpression(Expression callee, ...Expression arguments) {
this.callee = callee;
this.arguments = arguments;
}
override string toString() {
return "%s(%s)".format(callee.toString(), arguments.join(","));
}
}
class MemberExpression : Expression
{
Expression object;
Expression prop;
bool computed;
MemberExpression(Expression object, Identifier prop) {
this.object = object;
this.prop = prop;
this.computed = false;
}
MemberExpression(Expression object, Identifier prop, bool computed) {
this.object = object;
this.prop = prop;
this.computed = computed;
}
MemberExpression(Expression object, Expression prop) {
this.object = object;
this.prop = prop;
this.computed = true;
}
override string toString() {
if (computed) {
return "%s[%s]".format(object.toString(), prop.toString());
}
else {
return object.toString() + "." + prop.toString();
}
}
}
abstract class Literal : Expression {}
class NullLiteral : Literal
{
override string toString() {
return "null";
}
}
class UndefinedLiteral : Literal
{
override string toString() {
return "undefined";
}
}
class StringLiteral : Literal
{
string value;
StringLiteral(string value) {
this.value = value;
}
override string toString() {
return '"' + value.toString() + '"';
}
}
class NumericLiteral : Literal
{
string value; // Use 'string' to deal with precision issues
NumericLiteral(string value) {
this.value = value;
}
override string toString() {
return value.toString();
}
}
class RegExpLiteral : Literal
{
string pattern;
char[] flags;
RegExpLiteral(string pattern) {
this.pattern = pattern;
this.flags = [];
}
RegExpLiteral(string pattern, char[] flags) {
this.pattern = pattern;
this.flags = flags;
}
override string toString() {
return "/" + pattern + "/" + flags.join("");
}
}
class BooleanLiteral : Literal
{
bool value;
BooleanLiteral(bool value) {
this.value = value;
}
override string toString() {
return value.toString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment