Files
2013-04-25 09:59:27 -07:00

1432 lines
42 KiB
C++

/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This file is included into eval.h
namespace avmplus {
namespace RTC {
// Constants and bindings
// The parser parses constants and adds lists of constant definitions with
// unresolved RHS values to lists in the program and function nodes.
//
// The code generator resolves those constants. Values that either must be constants
// (identifiers used in 'namespace', 'const', and 'use namespace' definitions)
// or can be constants (identifiers used as the namespace value in qualified
// identifiers) are looked up during code generation by searching the context.
// The 'Program' and 'Function' (and probably 'Package', when we have that)
// ribs have separate lists of constant bindings with their values. Those value
// lists are populated in a prepass when code generation enters a Program or
// Function, since a statement can reference a later constant binding at the
// same or outer scope.
/*
enum CVTag {
TAG_cvValue,
TAG_cvAnonNS,
TAG_cvNamespace
};
class ConstValue {
public:
virtual ~ConstValue();
virtual CVTag tag() const = 0;
};
class CVValue : public ConstValue {
public:
CVValue(Expr* expr) : expr(expr) {}
virtual CVTag tag() const { return TAG_cvValue; }
Expr * const expr;
};
class CVAnonNS : public ConstValue {
public:
virtual CVTag tag() const { return TAG_cvAnonNS; }
};
class CVNamespace : public ConstValue {
public:
CVNamespace(Expr* expr) : expr(expr) {}
virtual CVTag tag() const { return TAG_cvNamespace; }
Expr * const expr;
};
*/
enum BindingKind {
TAG_varBinding, // also used for function (though not for class methods)
TAG_constBinding,
TAG_methodBinding, // methods in classes and interfaces
TAG_namespaceBinding,
TAG_classBinding,
TAG_interfaceBinding
};
enum QualifierTag {
QUAL_none,
QUAL_private,
QUAL_protected,
QUAL_public,
QUAL_internal,
QUAL_name
};
class Qualifier {
public:
Qualifier()
: tag(QUAL_none)
, is_dynamic(0)
, is_final(0)
, is_native(0)
, is_override(0)
, is_static(0)
, name(NULL)
, metadata(NULL)
{
}
QualifierTag tag;
uint32_t is_dynamic;
uint32_t is_final;
uint32_t is_native;
uint32_t is_override;
uint32_t is_static;
QualifiedName* name;
Seq<Expr*>* metadata;
};
class Binding {
public:
Binding(NameComponent* ns, Str* name, Type* type_name, BindingKind kind)
: ns(ns)
, name(name)
, type_name(type_name)
, kind(kind)
{
}
NameComponent* const ns;
Str* const name;
Type* const type_name;
const BindingKind kind;
};
// Program, class, interface, etc nodes
enum CodeType {
CODE_Program,
CODE_Class,
CODE_Function
};
// Information about the body of a program or function, built up during parsing.
// This is never stored in the AST, its contents are copied into CodeBlock,
// Program, or FunctionDefn.
class BodyInfo
{
public:
BodyInfo(Allocator* allocator)
: bindings(allocator)
, functionDefinitions(allocator)
, namespaces(allocator)
, openNamespaces(allocator)
, stmts(allocator)
, uses_finally(false)
, uses_catch(false)
, uses_goto(false)
, uses_arguments(false)
, uses_dxns(false)
, uses_super(false)
, empty_body(false)
{
}
SeqBuilder<Binding*> bindings;
SeqBuilder<FunctionDefn*> functionDefinitions;
SeqBuilder<NamespaceDefn*> namespaces;
SeqBuilder<Namespace*> openNamespaces;
SeqBuilder<Stmt*> stmts;
bool uses_finally;
bool uses_catch;
bool uses_goto;
bool uses_arguments;
bool uses_dxns;
bool uses_super; // True only for super /statements/, as in constructors
bool empty_body;
};
// Information about the interface of a function, built up during parsing.
// This is never stored in the AST, its contents are copied into CodeBlock
// or FunctionDefn.
class SignatureInfo
{
public:
SignatureInfo(Allocator* allocator)
: ns(NULL)
, name(NULL)
, params(allocator)
, rest_param(NULL)
, numparams(0)
, optional_arguments(false)
, isVoid(false)
, isGetter(false)
, isSetter(false)
, return_type_name(NULL)
{
}
NameComponent* ns;
Str* name;
SeqBuilder<FunctionParam*> params;
FunctionParam* rest_param;
uint32_t numparams;
bool optional_arguments;
bool isVoid;
bool isGetter;
bool isSetter;
Type* return_type_name;
};
// Base class for Program and FunctionDefn, holds information about the "body"
// of whatever we're compiling.
class CodeBlock {
public:
CodeBlock(CodeType tag, BodyInfo& body)
: tag(tag)
, bindings(body.bindings.get())
, functions(body.functionDefinitions.get())
, namespaces(body.namespaces.get())
, openNamespaces(body.openNamespaces.get())
, stmts(body.stmts.get())
, uses_finally(body.uses_finally)
, uses_catch(body.uses_catch)
, uses_goto(body.uses_goto)
, uses_arguments(body.uses_arguments)
, uses_dxns(body.uses_dxns)
, uses_super(body.uses_super)
, empty_body(body.empty_body)
{
}
virtual ~CodeBlock();
virtual void cogenBody(Cogen* cogen, Ctx* ctx, uint32_t activation) = 0;
void cogen(Cogen* cogen, Ctx* ctx);
const CodeType tag;
Seq<Binding*>* const bindings;
Seq<FunctionDefn*>* const functions;
Seq<NamespaceDefn*>* const namespaces;
Seq<Namespace*>* const openNamespaces;
Seq<Stmt*>* stmts; // Not const because sometimes altered after the fact
const bool uses_finally;
const bool uses_catch;
const bool uses_goto;
const bool uses_arguments;
const bool uses_dxns;
const bool uses_super; // True only for super /statements/, as in constructors
const bool empty_body; // True for all interface methods
};
class Program : public CodeBlock {
public:
Program(BodyInfo& body, Seq<TypeDefn*>* classes)
: CodeBlock(CODE_Program, body)
, classes(classes)
{
}
virtual void cogenBody(Cogen* cogen, Ctx* ctx, uint32_t activation);
void cogenTypes(Cogen* cogen, Ctx* ctx, ABCTraitsTable* global_traits, Seq<TypeDefn*>* classes);
void cogenTypeHierarchy(Cogen* cogen, Ctx* ctx, ABCTraitsTable* global_traits, TypeDefn* cls);
void cogenType(Cogen* cogen, Ctx* ctx, ABCTraitsTable* global_traits, ClassDefn* cls);
void cogenType(Cogen* cogen, Ctx* ctx, ABCTraitsTable* global_traits, InterfaceDefn* cls);
ABCTraitsTable* cogenClassTraits(Cogen* cogen, Ctx* ctx, Seq<FunctionDefn*>* inst_methods, Seq<Binding*>* inst_vars);
uint32_t cogenConstructor(Cogen* cogen, Ctx* ctx, FunctionDefn* constructor);
ClassDefn* findClass(Cogen* cogen, uint32_t pos, Str* name);
InterfaceDefn* findInterface(Cogen* cogen, uint32_t pos, Str* name);
int pushBaseClasses(Cogen* cogen, ClassDefn* currcls);
uint32_t* interfaceRefs(Cogen* cogen, Seq<Str*>* ifaces, uint32_t* interface_count);
Seq<TypeDefn*>* const classes;
};
class TypeDefn {
public:
TypeDefn(uint32_t pos, NameComponent* ns, Str* name, bool is_interface)
: pos(pos)
, ns(ns)
, name(name)
, is_interface(is_interface)
, is_generated(false)
, is_searching(false)
{
}
uint32_t pos;
NameComponent* const ns;
Str* const name;
const bool is_interface;
bool is_generated;
bool is_searching; // A mark used during class hierarchy traversal indicating that the class has already been visited
};
class ClassDefn : public TypeDefn {
public:
ClassDefn(uint32_t pos,
NameComponent* ns, Str* name, bool is_final, bool is_dynamic, Str* extends, Seq<Str*>* implements,
Seq<FunctionDefn*>* cls_methods, Seq<Binding*>* cls_vars, Seq<NamespaceDefn*>* cls_namespaces,
FunctionDefn* cls_init,
Seq<FunctionDefn*>* inst_methods, Seq<Binding*>* inst_vars, FunctionDefn* inst_init);
const bool is_final;
const bool is_dynamic;
Str* const extends;
Seq<Str*>* const implements;
Seq<FunctionDefn*>* const cls_methods;
Seq<Binding*>* const cls_vars;
Seq<NamespaceDefn*>* const cls_namespaces;
FunctionDefn* const cls_init;
Seq<FunctionDefn*>* const inst_methods; // Does not contain the constructor
Seq<Binding*>* const inst_vars;
FunctionDefn* const inst_init;
};
class InterfaceDefn : public TypeDefn {
public:
InterfaceDefn(uint32_t pos, NameComponent* ns, Str* name, Seq<Str*>* extends, Seq<FunctionDefn*>* inst_methods)
: TypeDefn(pos, ns, name, true)
, extends(extends)
, inst_methods(inst_methods)
{
}
Seq<Str*>* const extends;
Seq<FunctionDefn*>* const inst_methods;
};
class FunctionParam {
public:
FunctionParam(Str* name, Type* type_name, Expr* default_value)
: name(name)
, type_name(type_name)
, default_value(default_value)
{
}
Str * const name;
Type * const type_name;
Expr * const default_value;
};
// Somewhat mis-named, also used for function expressions (see LiteralFunction below), where name may be NULL
class FunctionDefn : public CodeBlock {
public:
FunctionDefn(SignatureInfo& signature, BodyInfo& body, Seq<Stmt*>* inits=NULL)
: CodeBlock(CODE_Function, body)
, ns(signature.ns)
, name(signature.name)
, params(signature.params.get())
, numparams(signature.numparams)
, rest_param(signature.rest_param)
, return_type_name(signature.return_type_name)
, optional_arguments(signature.optional_arguments)
, isGetter(signature.isGetter)
, isSetter(signature.isSetter)
, inits(inits)
{
}
virtual void cogenBody(Cogen* cogen, Ctx* ctx, uint32_t activation);
// Common code for function code generation. Create MethodInfo and MethodBodyInfo;
// generate code for the function; set the function's flags properly.
void cogenGuts(Compiler* compiler, Ctx* ctx, ABCMethodInfo** info, ABCMethodBodyInfo** body);
void cogenGuts(Compiler* compiler, Ctx* ctx, bool isMethod, ABCMethodInfo** info, ABCMethodBodyInfo** body);
NameComponent* ns; // Namespace of function or NULL.
Str* name; // Name of function or NULL. Not const because we sometimes need to set it to NULL.
Seq<FunctionParam*>* const params; // List of fixed parameters
const uint32_t numparams; // Number of fixed parameters
FunctionParam* rest_param; // non-NULL iff we have a ... rest argument; name+type of that argument
Type* return_type_name; // may be NULL
const bool optional_arguments; // true iff any of the parameters have default values
const bool isGetter; // true iff this is a getter function
const bool isSetter; // true iff this is a setter function
Seq<Stmt*>* inits; // initializing statements executed in the outer scope on entry
};
class NamespaceDefn {
public:
NamespaceDefn(NameComponent* ns, Str* name, Expr* value) : ns(ns), name(name), value(value) {}
NameComponent* const ns;
Str* const name;
Expr* const value; // NULL for anonymous ones; TAG_literalString for string values; otherwise a NameExpr
};
// Tags returned from Expr::tag()
enum Tag {
TAG_expr, // generic expr
TAG_objectRef, // instance of ObjectRef
TAG_qualifiedName, // instance of QualifiedName
TAG_instantiatedTypeRef,
TAG_literalString, // instance of LiteralString
TAG_literalUndefined,
TAG_literalNull,
TAG_literalBoolean,
TAG_literalInt,
TAG_literalUInt,
TAG_literalDouble,
TAG_literalFloat,
TAG_literalRegExp,
TAG_literalFunction,
TAG_commonNamespace,
TAG_namespaceRef,
TAG_literalArray,
TAG_literalVector,
TAG_literalObject,
TAG_literalXml,
TAG_binaryExpr,
TAG_unaryExpr,
TAG_conditionalExpr,
TAG_type, // generic type
TAG_simpleType, // type name
TAG_instantiatedType // instantiation of parameterized type
};
// Tags returned from NameComponent::tag()
enum NameTag {
TAG_simpleName, // instance of SimpleName
TAG_wildcardName, // instance of WildcardName
TAG_computedName, // instance of ComputedName
TAG_builtinNamespace, // instance of BuiltinNamespace
};
// Expression nodes
// Binary operators are used in the table binopMapping in eval-cogen.cpp.
// So keep these in order, and if you add any you *must* add entries to
// that table.
enum Binop {
// 0 is not used
OPR_as=1,
OPR_plus,
OPR_assign,
OPR_init,
OPR_comma,
OPR_minus,
OPR_multiply,
OPR_divide,
OPR_remainder,
OPR_leftShift,
OPR_rightShift,
OPR_rightShiftUnsigned,
OPR_instanceof,
OPR_in,
OPR_is,
OPR_bitwiseAnd,
OPR_bitwiseOr,
OPR_bitwiseXor,
OPR_logicalAnd,
OPR_logicalOr,
OPR_less,
OPR_lessOrEqual,
OPR_greater,
OPR_greaterOrEqual,
OPR_equal,
OPR_notEqual,
OPR_strictEqual,
OPR_strictNotEqual
};
enum Unop {
// 0 is not used
OPR_deleteVar=1,
OPR_delete,
OPR_typeofVar,
OPR_typeof,
OPR_postIncr,
OPR_preIncr,
OPR_postDecr,
OPR_preDecr,
OPR_postIncrVar,
OPR_preIncrVar,
OPR_postDecrVar,
OPR_preDecrVar,
OPR_bitwiseNot,
OPR_unminus,
OPR_unplus,
OPR_not,
OPR_void
};
class Type {
public:
Type(uint32_t pos=0) : pos(pos) {}
virtual ~Type() {} // Not really, but otherwise gcc drowns us in warnings
virtual Tag tag() const { return TAG_type; }
virtual void cogen(Cogen* cogen, Ctx* ctx) = 0; // Generates a reference to the type
const uint32_t pos;
};
class SimpleType : public Type {
public:
SimpleType(QualifiedName* name, uint32_t pos=0)
: Type(pos)
, name(name)
{
}
QualifiedName* const name;
virtual Tag tag() const { return TAG_simpleType; }
virtual void cogen(Cogen* cogen, Ctx* ctx);
};
class InstantiatedType : public Type {
public:
InstantiatedType(QualifiedName* basename, Type* tparam, uint32_t pos=0)
: Type(pos)
, basename(basename)
, tparam(tparam)
{
}
QualifiedName* const basename;
Type* const tparam;
virtual Tag tag() const { return TAG_instantiatedType; }
virtual void cogen(Cogen* cogen, Ctx* ctx);
};
class Expr {
public:
Expr(uint32_t pos=0) : pos(pos) {}
virtual ~Expr() {} // Not really, but otherwise gcc drowns us in warnings
virtual void cogen(Cogen* cogen, Ctx* ctx) = 0; // override for value computation
virtual Tag tag() const { return TAG_expr; }
const uint32_t pos;
};
class LiteralObject : public Expr {
public:
LiteralObject(Seq<LiteralField*>* fields, uint32_t pos) : Expr(pos), fields(fields) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Seq<LiteralField*>* const fields;
virtual Tag tag() const { return TAG_literalObject; }
};
class LiteralField {
public:
LiteralField(Str* name, Expr* value) : name(name), value(value) {}
Str* const name;
Expr* const value;
};
class LiteralArray : public Expr {
public:
LiteralArray(Seq<Expr*>* elements, uint32_t pos) : Expr(pos), elements(elements) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Seq<Expr*>* const elements;
virtual Tag tag() const { return TAG_literalArray; }
};
class LiteralVector : public Expr {
public:
LiteralVector(Type* type, Seq<Expr*>* elements, uint32_t pos) : Expr(pos), type(type), elements(elements) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Type* const type;
Seq<Expr*>* const elements;
virtual Tag tag() const { return TAG_literalVector; }
};
class LiteralUndefined : public Expr {
public:
LiteralUndefined(uint32_t pos) : Expr(pos) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalUndefined; }
};
class LiteralNull : public Expr {
public:
LiteralNull(uint32_t pos) : Expr(pos) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalNull; }
};
class LiteralInt : public Expr {
public:
LiteralInt(int32_t value, uint32_t pos) : Expr(pos), value(value) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalInt; }
const int32_t value;
};
class LiteralUInt : public Expr {
public:
LiteralUInt(uint32_t value, uint32_t pos) : Expr(pos), value(value) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalUInt; }
const uint32_t value;
};
class LiteralDouble : public Expr {
public:
LiteralDouble(double value, uint32_t pos) : Expr(pos), value(value) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalDouble; }
const double value;
};
#ifdef VMCFG_FLOAT
class LiteralFloat : public Expr {
public:
LiteralFloat(float value, uint32_t pos) : Expr(pos), value(value) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalFloat; }
const float value;
};
#endif
class LiteralBoolean : public Expr {
public:
LiteralBoolean(bool value, uint32_t pos) : Expr(pos), value(value) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalBoolean; }
const bool value;
};
class LiteralString : public Expr {
public:
LiteralString(Str* value, uint32_t pos) : Expr(pos), value(value) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalString; }
Str* const value;
};
class LiteralRegExp : public Expr {
public:
LiteralRegExp(Str* value, uint32_t pos) : Expr(pos), value(value) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalRegExp; }
Str* const value;
};
class LiteralFunction : public Expr {
public:
LiteralFunction(FunctionDefn* function) : function(function) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalFunction; }
FunctionDefn* const function;
};
class XmlInitializer : public Expr {
public:
XmlInitializer(Seq<Expr*>* exprs, bool is_list, uint32_t pos)
: Expr(pos)
, exprs(exprs)
, is_list(is_list)
{
}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_literalXml; }
Seq<Expr*>* const exprs;
const bool is_list;
};
class ThisExpr : public Expr {
public:
virtual void cogen(Cogen* cogen, Ctx* ctx);
};
class NewExpr : public Expr {
public:
NewExpr(Expr* fn, Seq<Expr*>* arguments) : fn(fn), arguments(arguments) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const fn;
Seq<Expr*>* const arguments;
};
class CallExpr : public Expr {
public:
CallExpr(Expr* fn, Seq<Expr*>* arguments, uint32_t pos) : Expr(pos), fn(fn), arguments(arguments) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const fn;
Seq<Expr*>* const arguments;
};
class SuperExpr : public Expr {
public:
SuperExpr(Expr* obj) : obj(obj) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const obj;
};
class ConditionalExpr : public Expr {
public:
ConditionalExpr(Expr* e1, Expr* e2, Expr* e3) : e1(e1), e2(e2), e3(e3) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_conditionalExpr; }
Expr* const e1;
Expr* const e2;
Expr* const e3;
};
class AssignExpr : public Expr {
public:
AssignExpr(Binop op, Expr* lhs, Expr* rhs) : op(op), lhs(lhs), rhs(rhs) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
const Binop op;
Expr* const lhs;
Expr* const rhs;
};
class BinaryExpr : public Expr {
public:
BinaryExpr(Binop op, Expr* lhs, Expr* rhs) : op(op), lhs(lhs), rhs(rhs) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_binaryExpr; }
const Binop op;
Expr* const lhs;
Expr* const rhs;
};
class UnaryExpr : public Expr {
public:
UnaryExpr(Unop op, Expr* expr) : op(op), expr(expr) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_unaryExpr; }
void incdec(Cogen* cogen, Ctx* ctx, bool pre, bool inc);
Unop const op;
Expr* const expr;
};
class RefLocalExpr : public Expr {
public:
RefLocalExpr(uint32_t local) : local(local) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
const uint32_t local;
};
class FilterExpr : public Expr {
public:
FilterExpr(Expr* obj, Expr* filter, uint32_t pos) : Expr(pos), obj(obj), filter(filter) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr * const obj;
Expr * const filter;
};
class DescendantsExpr : public Expr {
public:
DescendantsExpr(Expr* obj, QualifiedName* name, uint32_t pos) : Expr(pos), obj(obj), name(name) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr * const obj;
QualifiedName * const name;
};
enum Escapement {
ESC_none,
ESC_elementValue,
ESC_attributeValue
};
class EscapeExpr : public Expr {
public:
EscapeExpr(Expr* expr, Escapement esc) : Expr(0), expr(expr), esc(esc) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr * const expr;
const Escapement esc;
};
// Anything that is a name is a NameExpr. There are three kinds:
//
// QualifiedName for id, ns::id, ns::[E], ditto with '@' prefix
//
// ObjectRef for obj.<QualifiedName>
//
// InstantiatedTypeRef for Vector.<T>
//
// Notes:
// ns::@... is not legal syntax and need not be supported
class NameExpr : public Expr {
public:
NameExpr(uint32_t pos) : Expr(pos) {}
};
class QualifiedName : public NameExpr {
public:
QualifiedName(NameComponent* qualifier, NameComponent* name, bool is_attr, uint32_t pos)
: NameExpr(pos)
, qualifier(qualifier)
, name(name)
, is_attr(is_attr)
{
AvmAssert(name != NULL);
}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_qualifiedName; }
NameComponent * const qualifier;
NameComponent * const name;
const bool is_attr;
};
class ObjectRef : public NameExpr {
public:
ObjectRef(Expr* obj, QualifiedName* name, uint32_t pos)
: NameExpr(pos)
, obj(obj)
, name(name)
{
AvmAssert(obj != NULL && name != NULL);
}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_objectRef; }
Expr * const obj;
QualifiedName * const name;
};
class InstantiatedTypeRef : public NameExpr {
public:
InstantiatedTypeRef(InstantiatedType* type, uint32_t pos)
: NameExpr(pos)
, type(type)
{
}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual Tag tag() const { return TAG_instantiatedTypeRef; }
InstantiatedType * const type;
};
class NameComponent {
public:
virtual ~NameComponent();
virtual NameTag tag() const = 0;
};
// simple identifier
class SimpleName : public NameComponent {
public:
SimpleName(Str* name) : name(name) { AvmAssert(name != NULL); }
virtual NameTag tag() const { return TAG_simpleName; }
Str* const name;
};
// the '*' identifier
class WildcardName : public NameComponent {
public:
WildcardName() {}
virtual NameTag tag() const { return TAG_wildcardName; }
};
// a [E] name
class ComputedName : public NameComponent {
public:
ComputedName(Expr* expr) : expr(expr) {}
virtual NameTag tag() const { return TAG_computedName; }
Expr* const expr;
};
// private, protected, public, internal
class BuiltinNamespace : public NameComponent {
public:
BuiltinNamespace(Token t) : t(t) {}
virtual NameTag tag() const { return TAG_builtinNamespace; }
const Token t;
};
// Statement nodes
class Stmt {
public:
Stmt(uint32_t pos=0) : pos(pos) {}
virtual ~Stmt() {}
virtual void cogen(Cogen* cogen, Ctx*) = 0;
virtual bool isLabeledStmt() { return false; }
virtual bool isLabelSetStmt() { return false; }
virtual bool isVardefStmt() { return false; }
uint32_t pos;
static void cogenProgramBody(Cogen* cogen, Seq<Stmt*>* stmts);
static void cogenFunctionBody(Cogen* cogen, Seq<Stmt*>* stmts);
};
class EmptyStmt : public Stmt {
public:
virtual void cogen(Cogen* cogen, Ctx* ctx);
};
class BlockStmt : public Stmt {
public:
BlockStmt(Seq<Stmt*>* stmts) : stmts(stmts) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Seq<Stmt*>* const stmts;
};
class ExprStmt : public Stmt {
public:
ExprStmt(uint32_t pos, Expr* expr) : Stmt(pos), expr(expr) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const expr;
};
class VardefStmt: public ExprStmt {
public:
VardefStmt(uint32_t pos, Expr* expr) : ExprStmt(pos, expr) {}
virtual bool isVardefStmt() { return true; }
};
class LabeledStmt : public Stmt {
public:
LabeledStmt(Str* label, Stmt* stmt) : label(label), stmt(stmt), address(NULL) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
virtual bool isLabeledStmt() { return true; }
Str* const label;
Stmt* const stmt;
Label* address; // Used for "goto" processing; updated by a prepass
};
class ReturnStmt : public Stmt {
public:
ReturnStmt(uint32_t pos, Expr* expr) : Stmt(pos), expr(expr) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const expr; // or NULL
};
class BreakStmt : public Stmt {
public:
BreakStmt(uint32_t pos, Str* label) : Stmt(pos), label(label) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Str* const label; // or NULL
};
class ContinueStmt : public Stmt {
public:
ContinueStmt(uint32_t pos, Str* label) : Stmt(pos), label(label) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Str* const label; // or NULL
};
class GotoStmt : public Stmt {
public:
GotoStmt(uint32_t pos, Str* label) : Stmt(pos), label(label) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Str* const label; // never NULL
};
class IfStmt : public Stmt {
public:
IfStmt(uint32_t pos, Expr* expr, Stmt* consequent, Stmt* alternate)
: Stmt(pos)
, expr(expr)
, consequent(consequent)
, alternate(alternate)
{
}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const expr;
Stmt* const consequent;
Stmt* const alternate; // or NULL
};
class LabelSetStmt : public Stmt {
public:
LabelSetStmt(uint32_t pos=0) : Stmt(pos), labels(NULL) {}
virtual bool isLabelSetStmt() { return true; }
Seq<Str*>* labels;
};
class WhileStmt : public LabelSetStmt {
public:
WhileStmt(uint32_t pos, Expr* expr, Stmt* body) : LabelSetStmt(pos), expr(expr), body(body) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const expr;
Stmt* const body;
};
class DoWhileStmt : public LabelSetStmt {
public:
// pos should be the position of the "while" keyword, roughly, because it's the expression
// that will go wrong if anything
DoWhileStmt(uint32_t pos, Expr* expr, Stmt* body) : LabelSetStmt(pos), expr(expr), body(body) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const expr;
Stmt* const body;
};
class ForStmt : public LabelSetStmt {
public:
ForStmt(uint32_t pos, Expr* init, Expr* test, Expr* update, Stmt* body)
: LabelSetStmt(pos)
, init(init)
, test(test)
, update(update)
, body(body)
{
}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr * const init;
Expr * const test;
Expr * const update;
Stmt * const body;
};
class ForInStmt : public LabelSetStmt {
public:
ForInStmt(uint32_t pos, Expr* lhs, Expr* init, Expr* obj, Stmt* body, bool is_each)
: LabelSetStmt(pos)
, is_each(is_each)
, lhs(lhs)
, init(init)
, obj(obj)
, body(body)
{
}
virtual void cogen(Cogen* cogen, Ctx* ctx);
const bool is_each;
Expr * const lhs;
Expr * const init;
Expr * const obj;
Stmt * const body;
};
class SwitchStmt : public Stmt {
public:
SwitchStmt(uint32_t pos, Expr* expr, Seq<CaseClause*>* cases) : Stmt(pos), expr(expr), cases(cases) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
bool analyze(int32_t* low, int32_t* high);
void cogenFast(Cogen* cogen, Ctx* ctx, int32_t low, int32_t high);
void cogenSlow(Cogen* cogen, Ctx* ctx);
Expr* const expr;
Seq<CaseClause*>* const cases;
};
class CaseClause {
public:
CaseClause(uint32_t pos, Expr* expr) : pos(pos), expr(expr), stmts(NULL) {}
uint32_t pos;
Expr* const expr; // NULL denotes a default clause
Seq<Stmt*>* stmts;
};
class ThrowStmt : public Stmt {
public:
ThrowStmt(uint32_t pos, Expr* expr) : Stmt(pos), expr(expr) {};
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const expr;
};
class TryStmt : public Stmt {
public:
TryStmt(Seq<Stmt*>* tryblock, Seq<CatchClause*>* catches, Seq<Stmt*>* finallyblock) : tryblock(tryblock), catches(catches), finallyblock(finallyblock) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
void cogenWithFinally(Cogen* cogen, Ctx* ctx);
void cogenNoFinally(Cogen* cogen, Ctx* ctx);
void cgCatch(Cogen* cogen, Ctx* ctx, uint32_t code_start, uint32_t code_end, Label* Lend, CatchClause* catchClause);
Seq<Stmt*>* const tryblock;
Seq<CatchClause*>* const catches;
Seq<Stmt*>* const finallyblock;
};
class CatchClause {
public:
CatchClause(Str* name, Type* type_name, Seq<Stmt*>* stmts) : name(name), type_name(type_name), stmts(stmts) {}
Str* const name;
Type* const type_name;
Seq<Stmt*>* const stmts;
};
class WithStmt : public Stmt {
public:
WithStmt(uint32_t pos, Expr* expr, Stmt* body) : Stmt(pos), expr(expr), body(body) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const expr;
Stmt* const body;
};
// This is for base class constructor calls; base class method calls are represented
// as ExprStmts containing ObjectRef nodes with a SuperExpr left-hand-side and a CallExpr
// right-hand-side.
class SuperStmt : public Stmt {
public:
SuperStmt(uint32_t pos, Seq<Expr*>* arguments) : Stmt(pos), arguments(arguments) {}
virtual void cogen(Cogen* cogen, Ctx* ctx);
Seq<Expr*>* const arguments;
};
class DefaultXmlNamespaceStmt : public Stmt {
public:
DefaultXmlNamespaceStmt(uint32_t pos, Expr* expr) : Stmt(pos), expr(expr) {};
virtual void cogen(Cogen* cogen, Ctx* ctx);
Expr* const expr;
};
// Base class for various kinds of namespace values
class Namespace {
public:
virtual ~Namespace() {}
virtual Tag tag() const = 0;
};
// A string-based namespace.
class CommonNamespace : public Namespace {
public:
CommonNamespace(Str* name) : name(name) {}
virtual Tag tag() const { return TAG_commonNamespace; }
Str* const name;
};
// A reference to a namespace binding, must be resolved at compile time
class NamespaceRef : public Namespace {
public:
NamespaceRef(Str* id) : id(id) {}
virtual Tag tag() const { return TAG_namespaceRef; }
Str* const id;
};
class Parser {
public:
Parser(Compiler* compiler, Lexer* lexer, bool public_by_default, uint32_t first_line=1);
Program* parse();
Token onEOS(uint32_t* , TokenValue* valuep);
// Utilities shared with AST node constructors
// Return a value representing the internal namespace in an AST.
BuiltinNamespace* internalNamespace();
// Return a value representing the default namespace in an AST. What it is,
// public or internal, depends on "public_by_default".
BuiltinNamespace* defaultNamespace();
private:
Compiler * const compiler;
Allocator * const allocator;
const bool public_by_default;
const uint32_t line_offset;
// Parser attributes as bit vectors. A bit vector of all 0s is the "normal"
// case, the flags modify that.
enum {
EFLAG_NoIn = 1, // Expression parsing: do not allow the use of the "in" operator
};
enum {
SFLAG_Toplevel = 1, // Statement and directive parsing: at top level
SFLAG_Package = 2, // Statement and directive parsing: at package level
SFLAG_Function = 4, // Statement and directive parsing: at function level
SFLAG_Class = 8,
SFLAG_Interface = 16,
SFLAG_Block = 32, // Statement and directive parsing: at block level inside one of the above
};
// Program, etc parser
Program* program();
void package();
void directives(int flags);
void includeDirective();
void classDefinition(bool config, int flags, Qualifier* qual);
void interfaceDefinition(bool config, int flags, Qualifier* qual);
void namespaceDefinition(bool config, int flags, Qualifier* qualifier);
void configNamespaceDefinition(int flags, bool config);
void functionDefinition(bool config, Qualifier* qualifier, bool getters_and_setters, bool require_body);
Stmt* variableDefinition(bool config, Qualifier* qualifier);
FunctionDefn* functionGuts(Qualifier* qual, bool require_name, bool getters_and_setters, bool require_body);
Expr* varBindings(uint32_t* pos, NameComponent* ns, bool is_const, bool is_static, int flags=0, uint32_t* numbindings=NULL, Expr** firstName=NULL);
void checkSimpleAttributes(Qualifier* qual);
Seq<Stmt*>* statementBlock(bool config=true);
// Expression parser
//
// OPTIMIZEME: Make the parser work by operator precedence so that we have only
// a small number of recursive levels from "commaExpression" to "nameExpression"
// or "primaryExpression" (the common paths).
Type* typeExpression();
Expr* functionExpression();
QualifiedName* nameExpression(bool is_attr=false);
Expr* propertyOperator(Expr* obj);
Expr* objectInitializer();
Seq<LiteralField*>* fieldList();
LiteralField* literalField() ;
Expr* arrayInitializer();
Seq<Expr*>* elementList();
Expr* vectorInitializer(uint32_t pos);
Expr* primaryExpression();
QualifiedName* attributeIdentifier();
QualifiedName* propertyIdentifier();
Seq<Expr*>* argumentList();
Expr* memberExpression();
Expr* memberExpressionPrime(Expr* expr);
Expr* superExpression();
Expr* callExpression();
Expr* callExpressionPrime(Expr* call_expr);
Expr* newExpression (int new_count=0);
Expr* leftHandSideExpression();
Expr* postfixExpression();
Expr* unaryExpression();
Expr* multiplicativeExpression();
Expr* additiveExpression();
Expr* shiftExpression();
Expr* relationalExpression(int flags);
Expr* equalityExpression(int flags);
Expr* bitwiseAndExpression(int flags);
Expr* bitwiseXorExpression(int flags);
Expr* bitwiseOrExpression(int flags);
Expr* logicalAndExpression(int flags);
Expr* logicalOrExpression(int flags);
Expr* nonAssignmentExpression(int flags);
Expr* conditionalExpression(int flags);
Expr* assignmentExpression(int flags);
Expr* commaExpression(int flags);
Expr* exprListToCommaExpr(Seq<Expr*>* es);
Expr* parenExpression();
// Statement parser
Stmt* statement(bool config=true);
Stmt* labeledStatement();
Stmt* returnStatement();
Stmt* breakStatement();
Stmt* continueStatement();
Stmt* gotoStatement();
Str* breakOrContinueLabel(Token t);
Stmt* defaultXmlNamespaceStatement();
Stmt* ifStatement();
Stmt* whileStatement();
Stmt* doStatement();
Stmt* forStatement();
Stmt* switchStatement();
Seq<CaseClause*>* caseElements();
Stmt* throwStatement();
Stmt* tryStatement();
Seq<CatchClause*>* catches();
CatchClause* catchClause();
Stmt* useStatement();
Stmt* importStatement();
Stmt* varStatement(NameComponent* ns, bool is_const, bool is_static);
Stmt* withStatement();
Stmt* superStatement();
// Xml initializers
Expr* xmlInitializer();
void xmlListInitializer(XmlContext* ctx);
void xmlMarkup(XmlContext* ctx);
void xmlElement(XmlContext* ctx);
void xmlTagName(XmlContext* ctx);
void xmlAttributes(XmlContext* ctx);
void xmlElementContent(XmlContext* ctx);
void xmlExpression(XmlContext* ctx, Escapement esc);
void xmlAssert(XmlContext* ctx, Token t, Escapement esc=ESC_none);
void xmlEscape(XmlContext* ctx, const wchar* cs, const wchar* limit, bool is_attr);
void xmlPushback(wchar c);
void xmlAtom();
void xmlAtomSkipSpace();
// Sundry low-level parsers
Str* identifier();
void semicolon();
bool noNewline();
bool newline();
uint32_t position();
// Sundry utilities
bool isAdditive(Token t);
bool isRelational(Token t, bool in_allowed);
bool isShift(Token t);
bool isRelationalType(Token t);
bool isOpAssign(Token t);
bool isMultiplicative(Token t);
bool isEquality(Token t);
Unop tokenToUnaryOperator(Token t);
Binop tokenToBinaryOperator(Token t);
Str* doubleToStr(double d);
double strToDouble(Str* s);
bool isNamespaceReference(Expr* e);
void addExprStatements(SeqBuilder<Stmt*>* stmts, Seq<Expr*>* exprs);
Seq<Binding*>* bindingsToVars(Seq<Binding*>* bindings);
Seq<FunctionDefn*>* filterConstructor(Str* name, Seq<FunctionDefn*>* fns, FunctionDefn** constructor);
Seq<Stmt*>* filterStatements(Seq<Stmt*>* stmts, Seq<Stmt*>** nonDefinitionStmts);
FunctionDefn* constructClassConstructor(uint32_t pos, Str* name, BodyInfo* old_body, Seq<Stmt*>* init_stmts, Seq<Stmt*>* static_stmts);
FunctionDefn* constructInstanceConstructor(uint32_t pos, Str* name, Seq<Stmt*>* init_stmts, FunctionDefn* constructor);
NameComponent* qualToNamespace(Qualifier* qual);
BuiltinNamespace* const internalNS;
BuiltinNamespace* const privateNS;
BuiltinNamespace* const protectedNS;
BuiltinNamespace* const publicNS;
// Binding management
enum RibType {
RIB_Program,
RIB_Class,
RIB_Instance,
RIB_Function
};
class BindingRib {
public:
BindingRib(Allocator* allocator, BindingRib* next, RibType tag);
const RibType tag;
SignatureInfo* signature; // NULL unless tag == RIB_Function
BodyInfo body;
BindingRib* next;
};
BindingRib* topRib;
SeqBuilder<TypeDefn*> classes;
Binding* findBinding(NameComponent* ns, Str* name, BindingKind kind, BindingRib* rib=NULL);
void pushBindingRib(RibType tag);
void popBindingRib();
void addBinding(Str* name, BindingKind kind);
void addVarBinding(NameComponent* ns, Str* name, Type* type_name, BindingRib* rib=NULL);
void addConstBinding(NameComponent* ns, Str* name, Type* type_name, BindingRib* rib=NULL);
void addNamespaceBinding(NameComponent* ns, Str* name, Expr* expr);
void addFunctionBinding(NameComponent* ns, FunctionDefn* fn);
void addMethodBinding(NameComponent* ns, FunctionDefn* fn, BindingRib* rib);
void addClass(ClassDefn* cls);
void addInterface(InterfaceDefn* iface);
void addOpenNamespace(Namespace* ns);
void addUnqualifiedImport(Seq<Str*>* name); // import a.b.*; name would have length 2
void addQualifiedImport(Seq<Str*>* name); // import a.b.c; name would have length 3
void setUsesFinally();
void setUsesCatch();
void setUsesArguments();
void setUsesDefaultXmlNamespace();
void setUsesGoto();
void setUsesSuper();
// Program configuration management
class ConfigBinding {
public:
ConfigBinding(Str* ns, Str* name, Expr* value);
Str* ns; // Will be found among the configNamespaces
Str* name; // Unique within ns
Expr* value; // LiteralUndefined, LiteralNull, LiteralBoolean, LiteralString, LiteralInt, LiteralUInt, LiteralDouble
};
Seq<Str*>* configNamespaces;
Seq<ConfigBinding*>* configBindings;
void addConfigNamespace(Str* ns);
void checkNoShadowingOfConfigNamespaces(uint32_t pos, Str* s);
void addConfigBinding(Str* ns, Str* name, Expr* value);
bool isConfigReference(Expr* e); // e is a QualifiedName with non-NULL SimpleName parts, and the ns names a known config ns
bool findConfigNamespace(Str* ns);
Expr* findConfigBinding(Str* ns, Str* name);
bool evaluateConfigReference(QualifiedName* e);
// Constant evaluator, used by program configuration management.
// Could fairly easily be generalized into its own class, parameterized
// by an environment abstraction.
Expr* evaluateConfigDefinition(Str* ns, Expr* e);
uint32_t evaluateToUInt32(Expr* e);
int32_t evaluateToInt32(Expr* e);
double evaluateToNumber(Expr* e);
bool evaluateToBoolean(Expr* e);
Str* evaluateToString(Expr* e);
int evaluateRelational(Expr* lhs, Expr* rhs);
void failNonConstant(Expr* e);
// Utilities used by constant evaluator, pretty general but not used elsewhere.
Expr* boxDouble(double n);
Expr* boxFloat(float n);
Expr* boxUInt(uint32_t n);
Expr* boxInt(int32_t n);
Expr* boxBoolean(bool b);
Expr* boxString(const char* s);
Expr* boxString(Str* s);
Expr* boxUndefined();
// Lexer can be updated by "include" processing, suspended lexers are
// pushed onto the lexerStack.
class LexerState {
public:
Lexer* lexer;
Token T0, T1;
TokenValue V0, V1;
uint32_t LP, L0, L1;
const wchar* included_input;
LexerState* next;
};
void pushLexerState();
void popLexerState();
LexerState* lexerStack;
// Token queue, see implementation for extensive comments
Lexer * lexer;
Token T0, T1;
TokenValue V0, V1;
uint32_t LP;
uint32_t L0;
uint32_t L1;
const wchar* included_input;
void start();
Token divideOperator();
Token regexp();
Token rightAngle();
Token leftAngle();
Token rightShiftOrRelationalOperator();
Token leftShiftOrRelationalOperator();
Token hd();
Token hd2();
void next();
void eat(Token t);
bool match(Token t);
Str* xmlValue();
Str* stringValue();
Str* identValue();
Str* regexValue();
int32_t intValue();
uint32_t uintValue();
double doubleValue();
float floatValue();
// Mapping from subset of tokens to attributes and operator values
static const struct TokenMapping {
unsigned isOpAssign:1;
unsigned isMultiplicative:1;
unsigned isAdditive:1;
unsigned isRelational:1;
unsigned isEquality:1;
unsigned isShift:1;
unsigned unaryOp:8;
unsigned binaryOp:8;
} tokenMapping[];
};
}}