asherkin@263: /* asherkin@263: * Copyright (C) 2012 David Anderson asherkin@263: * asherkin@263: * This file is part of SourcePawn. asherkin@263: * asherkin@263: * SourcePawn is free software: you can redistribute it and/or modify it under asherkin@263: * the terms of the GNU General Public License as published by the Free asherkin@263: * Software Foundation, either version 3 of the License, or (at your option) asherkin@263: * any later version. asherkin@263: * asherkin@263: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY asherkin@263: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS asherkin@263: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. asherkin@263: * asherkin@263: * You should have received a copy of the GNU General Public License along with asherkin@263: * SourcePawn. If not, see http://www.gnu.org/licenses/. asherkin@263: */ asherkin@263: #ifndef _include_sp2_hir_h_ asherkin@263: #define _include_sp2_hir_h_ asherkin@263: asherkin@263: #include "../Types.h" asherkin@263: #include "../PoolAllocator.h" asherkin@263: #include "../Opcodes.h" asherkin@263: #include "Symbols.h" asherkin@263: asherkin@263: namespace ke { asherkin@263: asherkin@263: #define HIR_OPS(_) \ asherkin@263: _(Call) \ asherkin@263: _(Boolean) \ asherkin@263: _(Integer) \ asherkin@263: _(Float) \ asherkin@263: _(String) \ asherkin@263: _(Import) \ asherkin@263: _(Array) \ asherkin@263: _(Store) \ asherkin@263: _(ToRef) \ asherkin@263: _(NewDependentArray) \ asherkin@263: /* Special LValue types */ \ asherkin@263: _(Index) \ asherkin@263: _(Local) \ asherkin@263: _(Global) \ asherkin@263: _(Field) \ asherkin@263: /* End LValues */ \ asherkin@263: _(Unary) \ asherkin@263: _(Binary) \ asherkin@263: _(Convert) \ asherkin@263: _(PostIncDec) asherkin@263: asherkin@263: // Forward declarations. asherkin@263: #define _(name) class H##name; asherkin@263: HIR_OPS(_) asherkin@263: #undef _ asherkin@263: asherkin@263: class HIRVisitor; asherkin@263: class AstNode; asherkin@263: class HLValue; asherkin@263: class Array; asherkin@263: asherkin@263: class HIR : public PoolObject asherkin@263: { asherkin@263: public: asherkin@263: enum HOp { asherkin@263: #define _(name) k##name, asherkin@263: HIR_OPS(_) asherkin@263: #undef _ asherkin@263: kTotalOps asherkin@263: }; asherkin@263: asherkin@263: public: asherkin@263: HIR(AstNode *node, Type *type) asherkin@263: : node_(node), asherkin@263: type_(type) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: Handle type() { asherkin@263: return type_; asherkin@263: } asherkin@263: AstNode *node() const { asherkin@263: return node_; asherkin@263: } asherkin@263: asherkin@263: virtual bool isLValue() const { asherkin@263: return false; asherkin@263: } asherkin@263: asherkin@263: virtual HOp op() const = 0; asherkin@263: virtual void accept(HIRVisitor *visitor) = 0; asherkin@263: asherkin@263: #define _(name) \ asherkin@263: bool is##name() const { \ asherkin@263: return op() == k##name; \ asherkin@263: } \ asherkin@263: H##name *to##name() { \ asherkin@263: assert(is##name()); \ asherkin@263: return reinterpret_cast(this); \ asherkin@263: } asherkin@263: HIR_OPS(_) asherkin@263: #undef _ asherkin@263: asherkin@263: HLValue *toLValue() { asherkin@263: assert(isLValue()); asherkin@263: return reinterpret_cast(this); asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: AstNode *node_; asherkin@263: ScopedRoot type_; asherkin@263: }; asherkin@263: asherkin@263: class BytecodeEmitter; asherkin@263: asherkin@263: class HIRVisitor asherkin@263: { asherkin@263: public: asherkin@263: #define _(name) \ asherkin@263: virtual void visit##name(H##name *hir) { \ asherkin@263: assert(false); \ asherkin@263: } asherkin@263: HIR_OPS(_) asherkin@263: #undef _ asherkin@263: }; asherkin@263: asherkin@263: typedef PoolList HIRList; asherkin@263: asherkin@263: #define DEFINE_HIR(name) \ asherkin@263: virtual HOp op() const { \ asherkin@263: return k##name; \ asherkin@263: } \ asherkin@263: virtual void accept(HIRVisitor *visitor) { \ asherkin@263: visitor->visit##name(this); \ asherkin@263: } asherkin@263: asherkin@263: class HBoolean : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HBoolean(AstNode *node, Type *type, bool value) asherkin@263: : HIR(node, type), asherkin@263: value_(value) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Boolean); asherkin@263: bool value() const { asherkin@263: return value_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: bool value_; asherkin@263: }; asherkin@263: asherkin@263: class HInteger : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HInteger(AstNode *node, Type *type, int value) asherkin@263: : HIR(node, type), asherkin@263: value_(value) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Integer); asherkin@263: int value() const { asherkin@263: return value_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: int value_; asherkin@263: }; asherkin@263: asherkin@263: class HString : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HString(AstNode *node, Type *type, String *string) asherkin@263: : HIR(node, type), asherkin@263: string_(string) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(String); asherkin@263: Handle string() const { asherkin@263: return string_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: ScopedRoot string_; asherkin@263: }; asherkin@263: asherkin@263: class HImport : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HImport(AstNode *node, Type *type, unsigned index) asherkin@263: : HIR(node, type), asherkin@263: index_(index) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Import); asherkin@263: unsigned index() const { asherkin@263: return index_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: unsigned index_; asherkin@263: }; asherkin@263: asherkin@263: class HArray : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HArray(AstNode *node, Type *type, Array *array, bool duplicate) asherkin@263: : HIR(node, type), asherkin@263: array_(array), asherkin@263: duplicate_(duplicate) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Array); asherkin@263: Handle array() const { asherkin@263: return array_; asherkin@263: } asherkin@263: bool duplicate() const { asherkin@263: return duplicate_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: ScopedRoot array_; asherkin@263: bool duplicate_; asherkin@263: }; asherkin@263: asherkin@263: class HConvert : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HConvert(AstNode *node, Type *type, Opcode op, HIR *in) asherkin@263: : HIR(node, type), asherkin@263: op_(op), asherkin@263: in_(in) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Convert); asherkin@263: Opcode opcode() const { asherkin@263: return op_; asherkin@263: } asherkin@263: HIR *in() const { asherkin@263: return in_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: Opcode op_; asherkin@263: HIR *in_; asherkin@263: }; asherkin@263: asherkin@263: class HLValue : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HLValue(AstNode *node, Type *type) asherkin@263: : HIR(node, type) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: // Pushes a reference to the LValue on the stack. asherkin@263: virtual void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) = 0; asherkin@263: asherkin@263: // Duplicates a stack reference. asherkin@263: virtual void hold(BytecodeEmitter &emitter_) = 0; asherkin@263: asherkin@263: // Reorders the stack for a post-increment operation: asherkin@263: // REF VAL -> VAL REF VAL asherkin@263: virtual void swapAndPick(BytecodeEmitter &emitter_) = 0; asherkin@263: asherkin@263: // Given a stack layout of the form: asherkin@263: // [-1] value asherkin@263: // [-2..n] ref asherkin@263: // asherkin@263: // Emits a store to the reference. asherkin@263: virtual void store(BytecodeEmitter &emitter_) = 0; asherkin@263: virtual void load(BytecodeEmitter &emitter_) = 0; asherkin@263: asherkin@263: // Try to make a direct reference, if semantics allow it. False if the asherkin@263: // caller must allocate a reference to the stack. asherkin@263: virtual bool ref(BytecodeEmitter &emitter_) = 0; asherkin@263: asherkin@263: bool isLValue() const { asherkin@263: return true; asherkin@263: } asherkin@263: }; asherkin@263: asherkin@263: class HLocal : public HLValue asherkin@263: { asherkin@263: public: asherkin@263: HLocal(AstNode *node, VariableSymbol *sym); asherkin@263: asherkin@263: DEFINE_HIR(Local); asherkin@263: asherkin@263: // Pushes a reference to the LValue on the stack. asherkin@263: void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_); asherkin@263: void hold(BytecodeEmitter &emitter_); asherkin@263: void swapAndPick(BytecodeEmitter &emitter_); asherkin@263: void store(BytecodeEmitter &emitter_); asherkin@263: void load(BytecodeEmitter &emitter_); asherkin@263: bool ref(BytecodeEmitter &emitter_); asherkin@263: asherkin@263: VariableSymbol *sym() const { asherkin@263: return sym_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: VariableSymbol *sym_; asherkin@263: }; asherkin@263: asherkin@263: class HIndex : public HLValue asherkin@263: { asherkin@263: public: asherkin@263: HIndex(AstNode *node, Type *type, HIR *left, HIR *right) asherkin@263: : HLValue(node, type), asherkin@263: left_(left), asherkin@263: right_(right) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Index); asherkin@263: asherkin@263: void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_); asherkin@263: void hold(BytecodeEmitter &emitter_); asherkin@263: void swapAndPick(BytecodeEmitter &emitter_); asherkin@263: void store(BytecodeEmitter &emitter_); asherkin@263: void load(BytecodeEmitter &emitter_); asherkin@263: bool ref(BytecodeEmitter &emitter_); asherkin@263: asherkin@263: HIR *base() const { asherkin@263: return left_; asherkin@263: } asherkin@263: HIR *index() const { asherkin@263: return right_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: HIR *left_; asherkin@263: HIR *right_; asherkin@263: }; asherkin@263: asherkin@263: class HField : public HLValue asherkin@263: { asherkin@263: public: asherkin@263: HField(AstNode *node, HIR *left, Type *type, unsigned index) asherkin@263: : HLValue(node, type), asherkin@263: base_(left), asherkin@263: index_(index) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Field); asherkin@263: asherkin@263: void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_); asherkin@263: void hold(BytecodeEmitter &emitter_); asherkin@263: void swapAndPick(BytecodeEmitter &emitter_); asherkin@263: void store(BytecodeEmitter &emitter_); asherkin@263: void load(BytecodeEmitter &emitter_); asherkin@263: bool ref(BytecodeEmitter &emitter_); asherkin@263: asherkin@263: HIR *base() const { asherkin@263: return base_; asherkin@263: } asherkin@263: unsigned index() const { asherkin@263: return index_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: HIR *base_; asherkin@263: unsigned index_; asherkin@263: }; asherkin@263: asherkin@263: class HGlobal : public HLValue asherkin@263: { asherkin@263: public: asherkin@263: HGlobal(AstNode *node, Symbol *sym) asherkin@263: : HLValue(node, sym->type()), asherkin@263: sym_(sym) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Global); asherkin@263: asherkin@263: void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_); asherkin@263: void hold(BytecodeEmitter &emitter_); asherkin@263: void swapAndPick(BytecodeEmitter &emitter_); asherkin@263: void store(BytecodeEmitter &emitter_); asherkin@263: void load(BytecodeEmitter &emitter_); asherkin@263: bool ref(BytecodeEmitter &emitter_); asherkin@263: asherkin@263: Symbol *sym() const { asherkin@263: return sym_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: Symbol *sym_; asherkin@263: }; asherkin@263: asherkin@263: class HBinary : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HBinary(AstNode *node, Type *type, TokenKind token, HIR *left, HIR *right) asherkin@263: : HIR(node, type), asherkin@263: token_(token), asherkin@263: left_(left), asherkin@263: right_(right) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Binary); asherkin@263: TokenKind token() const { asherkin@263: return token_; asherkin@263: } asherkin@263: HIR *left() const { asherkin@263: return left_; asherkin@263: } asherkin@263: HIR *right() const { asherkin@263: return right_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: TokenKind token_; asherkin@263: HIR *left_; asherkin@263: HIR *right_; asherkin@263: }; asherkin@263: asherkin@263: class HFloat : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HFloat(AstNode *node, Type *type, float value) asherkin@263: : HIR(node, type), asherkin@263: value_(value) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Float); asherkin@263: float value() const { asherkin@263: return value_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: float value_; asherkin@263: }; asherkin@263: asherkin@263: class HUnary : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HUnary(AstNode *node, Type *type, TokenKind tok, HIR *in) asherkin@263: : HIR(node, type), asherkin@263: in_(in), asherkin@263: token_(tok) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Unary); asherkin@263: HIR *in() const { asherkin@263: return in_; asherkin@263: } asherkin@263: TokenKind token() const { asherkin@263: return token_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: HIR *in_; asherkin@263: TokenKind token_; asherkin@263: }; asherkin@263: asherkin@263: class HStore : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HStore(AstNode *node, HLValue *lval, HIR *rval) asherkin@263: : HIR(node, lval->type()), asherkin@263: kind_(TOK_ASSIGN), asherkin@263: lval_(lval), asherkin@263: rval_(rval) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: HStore(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval) asherkin@263: : HIR(node, lval->type()), asherkin@263: kind_(kind), asherkin@263: lval_(lval), asherkin@263: rval_(rval) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Store); asherkin@263: asherkin@263: HLValue *lval() const { asherkin@263: return lval_; asherkin@263: } asherkin@263: HIR *rval() const { asherkin@263: return rval_; asherkin@263: } asherkin@263: TokenKind kind() const { asherkin@263: return kind_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: TokenKind kind_; asherkin@263: HLValue *lval_; asherkin@263: HIR *rval_; asherkin@263: }; asherkin@263: asherkin@263: class HPostIncDec : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HPostIncDec(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval) asherkin@263: : HIR(node, lval->type()), asherkin@263: kind_(kind), asherkin@263: lval_(lval), asherkin@263: rval_(rval) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(PostIncDec); asherkin@263: asherkin@263: HLValue *lval() const { asherkin@263: return lval_; asherkin@263: } asherkin@263: HIR *rval() const { asherkin@263: return rval_; asherkin@263: } asherkin@263: TokenKind kind() const { asherkin@263: return kind_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: TokenKind kind_; asherkin@263: HLValue *lval_; asherkin@263: HIR *rval_; asherkin@263: }; asherkin@263: asherkin@263: class HCall : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HCall(AstNode *node, Type *type, HIR *callee, HIRList *args) asherkin@263: : HIR(node, type), asherkin@263: callee_(callee), asherkin@263: args_(args) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(Call); asherkin@263: asherkin@263: HIR *callee() const { asherkin@263: return callee_; asherkin@263: } asherkin@263: HIRList *args() const { asherkin@263: return args_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: HIR *callee_; asherkin@263: HIRList *args_; asherkin@263: }; asherkin@263: asherkin@263: class HToRef : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HToRef(AstNode *node, Type *type, HIR *in) asherkin@263: : HIR(node, type), asherkin@263: in_(in) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(ToRef); asherkin@263: asherkin@263: HIR *in() const { asherkin@263: return in_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: HIR *in_; asherkin@263: }; asherkin@263: asherkin@263: class HNewDependentArray : public HIR asherkin@263: { asherkin@263: public: asherkin@263: HNewDependentArray(AstNode *node, Type *type, HIR *base, HIR *index) asherkin@263: : HIR(node, type), asherkin@263: base_(base), asherkin@263: index_(index) asherkin@263: { asherkin@263: } asherkin@263: asherkin@263: DEFINE_HIR(NewDependentArray); asherkin@263: asherkin@263: HIR *base() const { asherkin@263: return base_; asherkin@263: } asherkin@263: HIR *index() const { asherkin@263: return index_; asherkin@263: } asherkin@263: asherkin@263: private: asherkin@263: HIR *base_; asherkin@263: HIR *index_; asherkin@263: }; asherkin@263: asherkin@263: #undef DEFINE_HIR asherkin@263: asherkin@263: void EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir); asherkin@263: asherkin@263: } asherkin@263: asherkin@263: #endif // _include_sp2_hir_h_