1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/SemanticAnalysis.h Tue Jul 24 23:53:34 2012 -0700
1.3 @@ -0,0 +1,204 @@
1.4 +/* vim: set ts=4 sw=4 tw=99 et:
1.5 + *
1.6 + * Copyright (C) 2012 David Anderson
1.7 + *
1.8 + * This file is part of JITCraft.
1.9 + *
1.10 + * JITCraft is free software: you can redistribute it and/or modify it under
1.11 + * the terms of the GNU General Public License as published by the Free
1.12 + * Software Foundation, either version 3 of the License, or (at your option)
1.13 + * any later version.
1.14 + *
1.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
1.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License along with
1.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
1.21 + */
1.22 +#ifndef _include_semantic_analysis_h_
1.23 +#define _include_semantic_analysis_h_
1.24 +
1.25 +#include <assert.h>
1.26 +#include "AST.h"
1.27 +
1.28 +namespace ke {
1.29 +
1.30 +class SemanticAnalysis : public AstVisitor
1.31 +{
1.32 + Zone *zone_;
1.33 + CompileContext &cc_;
1.34 + ParseTree *tree_;
1.35 + Scope *scope_;
1.36 + ScopedRoot<Type> function_;
1.37 +
1.38 + enum ReturnStatus
1.39 + {
1.40 + Returns_Never,
1.41 + Returns_Sometimes,
1.42 + Returns_Always
1.43 + };
1.44 +
1.45 + // Tuple that describes whether a path terminates control flow, and
1.46 + // if it is guaranteed to end in a return.
1.47 + class ControlStatus
1.48 + {
1.49 + bool terminates_;
1.50 + ReturnStatus returns_;
1.51 +
1.52 + public:
1.53 + ControlStatus(bool terminates, ReturnStatus returns)
1.54 + : terminates_(terminates),
1.55 + returns_(returns)
1.56 + {
1.57 + }
1.58 +
1.59 + bool terminates() const {
1.60 + return terminates_;
1.61 + }
1.62 + ReturnStatus returns() const {
1.63 + return returns_;
1.64 + }
1.65 + };
1.66 +
1.67 + // Used to keep track of terminating control flow and return statements
1.68 + // inside control structures.
1.69 + class ControlScope
1.70 + {
1.71 + ReturnStatus returns_;
1.72 + ControlScope **prevp_;
1.73 + ControlScope *prev_;
1.74 + bool terminates_;
1.75 +
1.76 + public:
1.77 + ControlScope(ControlScope **prev)
1.78 + : returns_(Returns_Never),
1.79 + prevp_(prev),
1.80 + prev_(*prev),
1.81 + terminates_(false)
1.82 + {
1.83 + *prevp_ = this;
1.84 + }
1.85 +
1.86 + ControlStatus status() const {
1.87 + return ControlStatus(terminates_, returns_);
1.88 + }
1.89 +
1.90 + // We allow multiple terminators, but only the first one takes effect.
1.91 + // For example, |break; continue;| is legal but the continue is
1.92 + // unreachable.
1.93 + void returns(ReturnStatus status) {
1.94 + if (terminates_)
1.95 + return;
1.96 + if (status > returns_)
1.97 + returns_ = status;
1.98 + }
1.99 + void terminate(ReturnStatus status) {
1.100 + if (terminates_)
1.101 + return;
1.102 + terminates_ = true;
1.103 + returns_ = status;
1.104 + }
1.105 + void merge(const ControlStatus &left, const ControlStatus &right);
1.106 +
1.107 + ~ControlScope()
1.108 + {
1.109 + *prevp_ = prev_;
1.110 + }
1.111 + };
1.112 +
1.113 + class LoopScope
1.114 + {
1.115 + LoopScope **prevp_;
1.116 + LoopScope *prev_;
1.117 + unsigned breaks_;
1.118 + unsigned continues_;
1.119 +
1.120 + public:
1.121 + LoopScope(LoopScope **prev)
1.122 + : prevp_(prev),
1.123 + prev_(*prev),
1.124 + breaks_(0),
1.125 + continues_(0)
1.126 + {
1.127 + *prevp_ = this;
1.128 + }
1.129 +
1.130 + ~LoopScope()
1.131 + {
1.132 + *prevp_ = prev_;
1.133 + }
1.134 +
1.135 + void addBreak() {
1.136 + breaks_++;
1.137 + }
1.138 + void addContinue() {
1.139 + continues_++;
1.140 + }
1.141 + unsigned breaks() const {
1.142 + return breaks_;
1.143 + }
1.144 + unsigned continues() const {
1.145 + return continues_;
1.146 + }
1.147 + };
1.148 +
1.149 + ControlScope *control_;
1.150 + LoopScope *loop_;
1.151 +
1.152 + private:
1.153 + bool canTest(AstNode *node, Handle<Type> type);
1.154 + void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
1.155 + void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
1.156 + Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
1.157 +
1.158 + // These check if one type is compatible with another type, for various
1.159 + // purposes, like:
1.160 + // return (expr) matches function return type
1.161 + // call(a, b) matches expected arg type
1.162 + // a = b matches declared type
1.163 + //
1.164 + bool typeCheckArrayAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
1.165 + bool typeCheckAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
1.166 + bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
1.167 +
1.168 + Type *visitForLoad(Expression *expression);
1.169 + bool preanalyze(FunctionStatement *node);
1.170 + Type *visitForLValue(Expression *expression);
1.171 + Type *visitAndApplyType(Expression *expression);
1.172 + ControlStatus visitForControl(Statement *statement);
1.173 +
1.174 + void markCallResultUsed(CallExpression *call);
1.175 +
1.176 + public:
1.177 + SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
1.178 + bool analyze();
1.179 +
1.180 + public:
1.181 + void visit(NameProxy *name);
1.182 + void visit(Assignment *node);
1.183 + void visit(BinaryExpression *node);
1.184 + void visit(ReturnStatement *node);
1.185 + void visit(ForStatement *node);
1.186 + void visit(BlockStatement *node);
1.187 + void visit(VariableDeclaration *node);
1.188 + void visit(IntegerLiteral *node);
1.189 + void visit(ExpressionStatement *node);
1.190 + void visit(FunctionStatement *node);
1.191 + void visit(CallExpression *node);
1.192 + void visit(IfStatement *node);
1.193 + void visit(IndexExpression *node);
1.194 + void visit(EnumStatement *node);
1.195 + void visit(FloatLiteral *node);
1.196 + void visit(WhileStatement *node);
1.197 + void visit(BreakStatement *node);
1.198 + void visit(ContinueStatement *node);
1.199 + void visit(StringLiteral *node);
1.200 + void visit(IncDecExpression *node);
1.201 + void visit(UnaryExpression *node);
1.202 + void visit(TernaryExpression *node);
1.203 +};
1.204 +
1.205 +} // namespace ke
1.206 +
1.207 +#endif // _include_semantic_analysis_h_