dvander@195: /* vim: set ts=4 sw=4 tw=99 et: dvander@195: * dvander@195: * Copyright (C) 2012 David Anderson dvander@195: * dvander@195: * This file is part of JITCraft. dvander@195: * dvander@195: * JITCraft is free software: you can redistribute it and/or modify it under dvander@195: * the terms of the GNU General Public License as published by the Free dvander@195: * Software Foundation, either version 3 of the License, or (at your option) dvander@195: * any later version. dvander@195: * dvander@195: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@195: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@195: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@195: * dvander@195: * You should have received a copy of the GNU General Public License along with dvander@195: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@195: */ dvander@195: #ifndef _include_semantic_analysis_h_ dvander@195: #define _include_semantic_analysis_h_ dvander@195: dvander@195: #include dvander@195: #include "AST.h" dvander@195: #include "../Types.h" dvander@195: dvander@195: namespace ke { dvander@195: dvander@195: class Box; dvander@195: dvander@195: class SemanticAnalysis : public AstVisitor dvander@195: { dvander@195: Zone *zone_; dvander@195: CompileContext &cc_; dvander@195: ParseTree *tree_; dvander@195: Scope *scope_; dvander@195: NamedFunction *function_; dvander@195: dvander@195: enum ReturnStatus dvander@195: { dvander@195: Returns_Never, dvander@195: Returns_Sometimes, dvander@195: Returns_Always dvander@195: }; dvander@195: dvander@195: // Tuple that describes whether a path terminates control flow, and dvander@195: // if it is guaranteed to end in a return. dvander@195: class ControlStatus dvander@195: { dvander@195: bool terminates_; dvander@195: ReturnStatus returns_; dvander@195: dvander@195: public: dvander@195: ControlStatus(bool terminates, ReturnStatus returns) dvander@195: : terminates_(terminates), dvander@195: returns_(returns) dvander@195: { dvander@195: } dvander@195: dvander@195: bool terminates() const { dvander@195: return terminates_; dvander@195: } dvander@195: ReturnStatus returns() const { dvander@195: return returns_; dvander@195: } dvander@195: }; dvander@195: dvander@195: // Used to keep track of terminating control flow and return statements dvander@195: // inside control structures. dvander@195: class ControlScope dvander@195: { dvander@195: ReturnStatus returns_; dvander@195: ControlScope **prevp_; dvander@195: ControlScope *prev_; dvander@195: bool terminates_; dvander@195: dvander@195: public: dvander@195: ControlScope(ControlScope **prev) dvander@195: : returns_(Returns_Never), dvander@195: prevp_(prev), dvander@195: prev_(*prev), dvander@195: terminates_(false) dvander@195: { dvander@195: *prevp_ = this; dvander@195: } dvander@195: dvander@195: ControlStatus status() const { dvander@195: return ControlStatus(terminates_, returns_); dvander@195: } dvander@195: dvander@195: // We allow multiple terminators, but only the first one takes effect. dvander@195: // For example, |break; continue;| is legal but the continue is dvander@195: // unreachable. dvander@195: void returns(ReturnStatus status) { dvander@195: if (terminates_) dvander@195: return; dvander@195: if (status > returns_) dvander@195: returns_ = status; dvander@195: } dvander@195: void terminate(ReturnStatus status) { dvander@195: if (terminates_) dvander@195: return; dvander@195: terminates_ = true; dvander@195: returns_ = status; dvander@195: } dvander@195: void merge(const ControlStatus &left, const ControlStatus &right); dvander@195: void inherit(const ControlStatus &other); dvander@195: dvander@195: ~ControlScope() dvander@195: { dvander@195: *prevp_ = prev_; dvander@195: } dvander@195: }; dvander@195: dvander@195: class LoopScope dvander@195: { dvander@195: LoopScope **prevp_; dvander@195: LoopScope *prev_; dvander@195: unsigned breaks_; dvander@195: unsigned continues_; dvander@195: dvander@195: public: dvander@195: LoopScope(LoopScope **prev) dvander@195: : prevp_(prev), dvander@195: prev_(*prev), dvander@195: breaks_(0), dvander@195: continues_(0) dvander@195: { dvander@195: *prevp_ = this; dvander@195: } dvander@195: dvander@195: ~LoopScope() dvander@195: { dvander@195: *prevp_ = prev_; dvander@195: } dvander@195: dvander@195: void addBreak() { dvander@195: breaks_++; dvander@195: } dvander@195: void addContinue() { dvander@195: continues_++; dvander@195: } dvander@195: unsigned breaks() const { dvander@195: return breaks_; dvander@195: } dvander@195: unsigned continues() const { dvander@195: return continues_; dvander@195: } dvander@195: }; dvander@195: dvander@195: ControlScope *control_; dvander@195: LoopScope *loop_; dvander@195: dvander@195: private: dvander@195: bool canTest(AstNode *node, Handle type); dvander@195: void typeMismatch(const SourcePosition &pos, Handle actual, Handle given); dvander@195: void unaryTypeError(AstNode *node, TokenKind token, Handle type); dvander@195: void binaryTypeError(AstNode *node, TokenKind token, Handle left, Handle right); dvander@195: Type *typeCheckBinary(AstNode *node, TokenKind token, Handle left, Handle right); dvander@195: dvander@195: Type *bindType(const SourcePosition &pos, BoundName *name); dvander@195: dvander@195: // These check if one type is compatible with another type, for various dvander@195: // purposes, like: dvander@195: // return (expr) matches function return type dvander@195: // call(a, b) matches expected arg type dvander@195: // a = b matches declared type dvander@195: // dvander@195: bool typeCheckArrayAssignment(const SourcePosition &pos, Handle given, Handle actual, bool forAssign); dvander@195: bool typeCheckAssignment(const SourcePosition &pos, Handle given, Handle actual, bool forAssign); dvander@195: bool typeCheckParameter(AstNode *node, Handle given, Handle actual); dvander@195: dvander@195: Type *visitForLoad(Expression *expression); dvander@195: bool preanalyze(FunctionStatement *node); dvander@195: Type *visitForLValue(Expression *expression); dvander@195: Type *visitAndApplyType(Expression *expression); dvander@195: ControlStatus visitForControl(Statement *statement); dvander@195: dvander@195: bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]); dvander@195: bool inferFixedArrayLiteral(ArrayLiteral *literal, dvander@195: Handle type, dvander@195: int dims[MAX_ARRAY_DEPTH], dvander@195: unsigned dimcount, dvander@195: unsigned level); dvander@195: dvander@195: // Builds an array type used for parameters, returns, or field entries. dvander@195: Type *buildArrayType(Handle type, ExpressionList *dimensions, bool isConst); dvander@195: dvander@195: Box *evaluateDefaultParameter(Handle type, Parameter *parameter); dvander@195: bool checkArgumentCount(Handle type, unsigned actual); dvander@195: bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig, dvander@195: FixedArray **args, FixedArray **defaults); dvander@195: dvander@195: void markCallResultUsed(CallExpression *call); dvander@195: dvander@195: bool determineLiveFunctions(); dvander@195: dvander@195: public: dvander@195: SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree); dvander@195: bool analyze(); dvander@195: dvander@195: public: dvander@195: void visit(NameProxy *name); dvander@195: void visit(Assignment *node); dvander@195: void visit(BinaryExpression *node); dvander@195: void visit(ReturnStatement *node); dvander@195: void visit(ForStatement *node); dvander@195: void visit(BlockStatement *node); dvander@195: void visit(VariableDeclaration *node); dvander@195: void visit(IntegerLiteral *node); dvander@195: void visit(ExpressionStatement *node); dvander@195: void visit(FunctionStatement *node); dvander@195: void visit(CallExpression *node); dvander@195: void visit(IfStatement *node); dvander@195: void visit(IndexExpression *node); dvander@195: void visit(EnumStatement *node); dvander@195: void visit(FloatLiteral *node); dvander@195: void visit(WhileStatement *node); dvander@195: void visit(BreakStatement *node); dvander@195: void visit(ContinueStatement *node); dvander@195: void visit(StringLiteral *node); dvander@195: void visit(IncDecExpression *node); dvander@195: void visit(UnaryExpression *node); dvander@195: void visit(TernaryExpression *node); dvander@195: void visit(BooleanLiteral *node); dvander@195: void visit(StructureStatement *node); dvander@195: void visit(FieldExpression *node); dvander@195: void visit(SwitchStatement *node); dvander@195: void visit(FunctionTypeStatement *node); dvander@195: void visit(ArrayLiteral *node); dvander@195: void visit(ImportStatement *node); dvander@195: }; dvander@195: dvander@195: const char *GetTypeName(Type *type); dvander@195: dvander@195: } // namespace ke dvander@195: dvander@195: #endif // _include_semantic_analysis_h_