dvander@195: /* dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@195: * This file is part of SourcePawn. dvander@0: * dvander@195: * SourcePawn is free software: you can redistribute it and/or modify it under dvander@0: * the terms of the GNU General Public License as published by the Free dvander@0: * Software Foundation, either version 3 of the License, or (at your option) dvander@0: * any later version. dvander@0: * dvander@195: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY dvander@0: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@0: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@0: * dvander@0: * You should have received a copy of the GNU General Public License along with dvander@195: * SourcePawn. If not, see http://www.gnu.org/licenses/. dvander@0: */ dvander@195: #ifndef _include_sp2_sema_h_ dvander@195: #define _include_sp2_sema_h_ dvander@0: dvander@0: #include "AST.h" dvander@195: #include "HIR.h" dvander@195: #include "Scopes.h" dvander@195: #include "BytecodeEmitter.h" dvander@0: dvander@59: namespace ke { dvander@0: dvander@195: // Semantic analysis occurs after all names and types have been bound. It dvander@195: // performs the important task of validating the semantics and type safety dvander@195: // of a parse tree. dvander@195: // dvander@195: // The semantic analysis phase also produces bytecode. This occurs on a dvander@195: // statement-by-statement basis. The result of analyzing an expression is a dvander@195: // tree of operations which is then flattened. dvander@0: class SemanticAnalysis : public AstVisitor dvander@0: { dvander@195: public: dvander@195: SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit); dvander@195: dvander@195: void analyze(); dvander@195: dvander@195: private: dvander@195: SemanticAnalysis(SemanticAnalysis *parent, Handle fun); dvander@195: Function *compile(FunctionStatement *stmt); dvander@195: dvander@195: public: dvander@195: void visitFunctionStatement(FunctionStatement *node); dvander@195: void visitBlockStatement(BlockStatement *node); dvander@195: void visitExpressionStatement(ExpressionStatement *node); dvander@195: void visitReturnStatement(ReturnStatement *node); dvander@0: dvander@195: void visitCallExpression(CallExpression *node); dvander@195: void visitNameProxy(NameProxy *name); dvander@195: void visitIntegerLiteral(IntegerLiteral *node); dvander@195: void visitFloatLiteral(FloatLiteral *node); dvander@195: void visitVariableDeclaration(VariableDeclaration *node); dvander@195: void visitForStatement(ForStatement *node); dvander@203: void visitWhileStatement(WhileStatement *node); dvander@195: void visitAssignment(Assignment *node); dvander@195: void visitBinaryExpression(BinaryExpression *node); dvander@208: void visitBreakStatement(BreakStatement *node); dvander@208: void visitContinueStatement(ContinueStatement *node); dvander@208: void visitIfStatement(IfStatement *node); dvander@212: void visitIndexExpression(IndexExpression *node); dvander@217: void visitIncDecExpression(IncDecExpression *node); dvander@195: #if 0 dvander@195: void visitFunctionTypeStatement(FunctionTypeStatement *node); dvander@195: void visitImportStatement(ImportStatement *node); dvander@195: void visitEnumStatement(EnumStatement *node); dvander@195: void visitStructureStatement(StructureStatement *node); dvander@195: void visitSwitchStatement(SwitchStatement *node); dvander@195: dvander@195: void visitStringLiteral(StringLiteral *node); dvander@195: void visitUnaryExpression(UnaryExpression *node); dvander@195: void visitTernaryExpression(TernaryExpression *node); dvander@195: void visitBooleanLiteral(BooleanLiteral *node); dvander@195: void visitFieldExpression(FieldExpression *node); dvander@195: void visitArrayLiteral(ArrayLiteral *node); dvander@195: #endif dvander@195: dvander@195: private: dvander@195: bool checkArgumentCount(Handle type, unsigned actual); dvander@195: dvander@195: private: dvander@195: enum CoercionKind { dvander@195: Coerce_Arg, dvander@195: Coerce_Return, dvander@195: Coerce_Assign dvander@71: }; dvander@71: dvander@230: void requireLifoStack(); dvander@230: void visitLoopBody(Statement *stmt); dvander@195: void visitForTest(Expression *expr, dvander@195: BytecodeEmitter::Label *trueBranch, dvander@195: BytecodeEmitter::Label *falseBranch, dvander@195: BytecodeEmitter::Label *fallthrough); dvander@195: void set(VariableSymbol *sym); dvander@195: HIR *eval(Expression *expr); dvander@221: HIR *binary(AstNode *node, TokenKind token, HIR *left, HIR *right); dvander@195: HIR *coerce(HIR *from, Handle to, CoercionKind kind); dvander@195: Type *coercionType(TokenKind token, HIR *left, HIR *right); dvander@195: HLValue *lvalue(Expression *expr); dvander@195: void discharge(HIR *hir); dvander@71: dvander@220: bool typeCheckArray(const SourcePosition &pos, dvander@220: Handle argGiven, dvander@220: Handle argActual, dvander@220: CoercionKind kind); dvander@220: dvander@195: private: dvander@195: // Used to target break/catch statements. dvander@195: class LoopScope dvander@71: { dvander@195: Scope *scope_; dvander@195: BytecodeEmitter::Label *bk_; dvander@195: BytecodeEmitter::Label *ct_; dvander@195: LoopScope **prevp_; dvander@195: LoopScope *prev_; dvander@230: bool usesLifoStack_; dvander@71: dvander@71: public: dvander@195: LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct, dvander@195: LoopScope **prevp) dvander@195: : scope_(scope), dvander@195: bk_(bk), dvander@195: ct_(ct), dvander@195: prevp_(prevp), dvander@230: prev_(*prevp), dvander@230: usesLifoStack_(false) dvander@71: { dvander@71: *prevp_ = this; dvander@71: } dvander@71: dvander@71: ~LoopScope() dvander@71: { dvander@71: *prevp_ = prev_; dvander@71: } dvander@71: dvander@195: BytecodeEmitter::Label *break_() { dvander@195: return bk_; dvander@71: } dvander@195: BytecodeEmitter::Label *continue_() { dvander@195: return ct_; dvander@71: } dvander@195: Scope *scope() { dvander@195: return scope_; dvander@71: } dvander@230: void setUsesLifoStack() { dvander@230: usesLifoStack_ = true; dvander@230: } dvander@230: bool usesLifoStack() const { dvander@230: return usesLifoStack_; dvander@230: } dvander@71: }; dvander@195: dvander@0: private: dvander@195: Zone *zone_; dvander@195: PoolAllocator &pool_; dvander@195: CompileContext &cc_; dvander@195: TranslationUnit *unit_; dvander@195: HIR *hir_; dvander@195: Scope *scope_; dvander@195: BytecodeEmitter emitter_; dvander@195: ScopedRoot module_; dvander@195: ScopedRoot fun_; dvander@195: LoopScope *loop_; dvander@0: }; dvander@0: dvander@59: } // namespace ke dvander@0: dvander@195: #endif // _include_sp2_sema_h_