dvander@30: /* vim: set ts=4 sw=4 tw=99 et: dvander@30: * dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@0: * This file is part of JITCraft. dvander@0: * dvander@0: * JITCraft 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@0: * Foobar 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@0: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@0: */ dvander@0: #ifndef _include_semantic_analysis_h_ dvander@0: #define _include_semantic_analysis_h_ dvander@0: dvander@0: #include dvander@0: #include "AST.h" dvander@0: dvander@59: namespace ke { dvander@0: dvander@168: class Box; dvander@168: dvander@0: class SemanticAnalysis : public AstVisitor dvander@0: { dvander@30: Zone *zone_; dvander@25: CompileContext &cc_; dvander@0: ParseTree *tree_; dvander@12: Scope *scope_; dvander@137: NamedFunction *function_; dvander@0: dvander@71: enum ReturnStatus dvander@71: { dvander@71: Returns_Never, dvander@71: Returns_Sometimes, dvander@71: Returns_Always dvander@71: }; dvander@71: dvander@71: // Tuple that describes whether a path terminates control flow, and dvander@71: // if it is guaranteed to end in a return. dvander@71: class ControlStatus dvander@71: { dvander@71: bool terminates_; dvander@71: ReturnStatus returns_; dvander@71: dvander@71: public: dvander@71: ControlStatus(bool terminates, ReturnStatus returns) dvander@71: : terminates_(terminates), dvander@71: returns_(returns) dvander@71: { dvander@71: } dvander@71: dvander@71: bool terminates() const { dvander@71: return terminates_; dvander@71: } dvander@71: ReturnStatus returns() const { dvander@71: return returns_; dvander@71: } dvander@71: }; dvander@71: dvander@71: // Used to keep track of terminating control flow and return statements dvander@71: // inside control structures. dvander@71: class ControlScope dvander@71: { dvander@71: ReturnStatus returns_; dvander@71: ControlScope **prevp_; dvander@71: ControlScope *prev_; dvander@71: bool terminates_; dvander@71: dvander@71: public: dvander@71: ControlScope(ControlScope **prev) dvander@71: : returns_(Returns_Never), dvander@71: prevp_(prev), dvander@71: prev_(*prev), dvander@71: terminates_(false) dvander@71: { dvander@71: *prevp_ = this; dvander@71: } dvander@71: dvander@71: ControlStatus status() const { dvander@71: return ControlStatus(terminates_, returns_); dvander@71: } dvander@71: dvander@71: // We allow multiple terminators, but only the first one takes effect. dvander@71: // For example, |break; continue;| is legal but the continue is dvander@71: // unreachable. dvander@71: void returns(ReturnStatus status) { dvander@71: if (terminates_) dvander@71: return; dvander@71: if (status > returns_) dvander@71: returns_ = status; dvander@71: } dvander@71: void terminate(ReturnStatus status) { dvander@71: if (terminates_) dvander@71: return; dvander@71: terminates_ = true; dvander@71: returns_ = status; dvander@71: } dvander@71: void merge(const ControlStatus &left, const ControlStatus &right); dvander@71: dvander@71: ~ControlScope() dvander@71: { dvander@71: *prevp_ = prev_; dvander@71: } dvander@71: }; dvander@71: dvander@71: class LoopScope dvander@71: { dvander@71: LoopScope **prevp_; dvander@71: LoopScope *prev_; dvander@71: unsigned breaks_; dvander@71: unsigned continues_; dvander@71: dvander@71: public: dvander@71: LoopScope(LoopScope **prev) dvander@71: : prevp_(prev), dvander@71: prev_(*prev), dvander@71: breaks_(0), dvander@71: continues_(0) dvander@71: { dvander@71: *prevp_ = this; dvander@71: } dvander@71: dvander@71: ~LoopScope() dvander@71: { dvander@71: *prevp_ = prev_; dvander@71: } dvander@71: dvander@71: void addBreak() { dvander@71: breaks_++; dvander@71: } dvander@71: void addContinue() { dvander@71: continues_++; dvander@71: } dvander@71: unsigned breaks() const { dvander@71: return breaks_; dvander@71: } dvander@71: unsigned continues() const { dvander@71: return continues_; dvander@71: } dvander@71: }; dvander@71: dvander@71: ControlScope *control_; dvander@71: LoopScope *loop_; dvander@71: dvander@0: private: dvander@40: bool canTest(AstNode *node, Handle type); dvander@168: void typeMismatch(const SourcePosition &pos, Handle actual, Handle given); dvander@40: void unaryTypeError(AstNode *node, TokenKind token, Handle type); dvander@40: void binaryTypeError(AstNode *node, TokenKind token, Handle left, Handle right); dvander@40: Type *typeCheckBinary(AstNode *node, TokenKind token, Handle left, Handle right); dvander@25: dvander@145: Type *bindType(const SourcePosition &pos, BoundName *name); dvander@145: dvander@25: // These check if one type is compatible with another type, for various dvander@25: // purposes, like: dvander@25: // return (expr) matches function return type dvander@25: // call(a, b) matches expected arg type dvander@25: // a = b matches declared type dvander@25: // dvander@168: bool typeCheckArrayAssignment(const SourcePosition &pos, Handle given, Handle actual, bool forAssign); dvander@168: bool typeCheckAssignment(const SourcePosition &pos, Handle given, Handle actual, bool forAssign); dvander@40: bool typeCheckParameter(AstNode *node, Handle given, Handle actual); dvander@25: dvander@7: Type *visitForLoad(Expression *expression); dvander@14: bool preanalyze(FunctionStatement *node); dvander@23: Type *visitForLValue(Expression *expression); dvander@25: Type *visitAndApplyType(Expression *expression); dvander@71: ControlStatus visitForControl(Statement *statement); dvander@71: dvander@168: Box *evaluateDefaultParameter(Handle type, Parameter *parameter); dvander@168: bool checkArgumentCount(Handle type, unsigned actual); dvander@168: dvander@71: void markCallResultUsed(CallExpression *call); dvander@0: dvander@137: bool determineLiveFunctions(); dvander@137: dvander@0: public: dvander@30: SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree); dvander@0: bool analyze(); dvander@0: dvander@0: public: dvander@0: void visit(NameProxy *name); dvander@0: void visit(Assignment *node); dvander@0: void visit(BinaryExpression *node); dvander@0: void visit(ReturnStatement *node); dvander@0: void visit(ForStatement *node); dvander@0: void visit(BlockStatement *node); dvander@0: void visit(VariableDeclaration *node); dvander@4: void visit(IntegerLiteral *node); dvander@0: void visit(ExpressionStatement *node); dvander@0: void visit(FunctionStatement *node); dvander@0: void visit(CallExpression *node); dvander@0: void visit(IfStatement *node); dvander@0: void visit(IndexExpression *node); dvander@2: void visit(EnumStatement *node); dvander@4: void visit(FloatLiteral *node); dvander@9: void visit(WhileStatement *node); dvander@10: void visit(BreakStatement *node); dvander@10: void visit(ContinueStatement *node); dvander@21: void visit(StringLiteral *node); dvander@23: void visit(IncDecExpression *node); dvander@78: void visit(UnaryExpression *node); dvander@83: void visit(TernaryExpression *node); dvander@143: void visit(BooleanLiteral *node); dvander@146: void visit(StructureStatement *node); dvander@148: void visit(FieldExpression *node); dvander@0: }; dvander@0: dvander@145: const char *GetTypeName(Type *type); dvander@145: dvander@59: } // namespace ke dvander@0: dvander@0: #endif // _include_semantic_analysis_h_