dvander@30: /* vim: set ts=4 sw=4 tw=99 et: dvander@30: * 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: #include dvander@195: #include "../Zone.h" dvander@195: #include "../Strings.h" dvander@195: #include "../NativeTable.h" dvander@195: #include "../TypeManager.h" dvander@195: #include "../Modules.h" dvander@195: #include "../Code.h" dvander@0: #include "SemanticAnalysis.h" dvander@196: #include "../Heap-inl.h" dvander@0: dvander@59: using namespace ke; dvander@0: dvander@195: #define __ emitter_. dvander@2: dvander@195: typedef BytecodeEmitter::Label Label; dvander@2: dvander@195: class AutoEnterScope dvander@2: { dvander@195: public: dvander@195: AutoEnterScope(Scope **prevp, Scope *scope) dvander@195: : prevp_(prevp), dvander@195: prev_(*prevp), dvander@195: scope_(scope) dvander@195: { dvander@195: if (!scope_) dvander@195: return; dvander@195: prev_ = *prevp_; dvander@195: *prevp_ = scope; dvander@195: assert(prev_ == scope->enclosing()); dvander@195: } dvander@195: ~AutoEnterScope() dvander@195: { dvander@195: if (scope_) dvander@195: *prevp_ = prev_; dvander@195: } dvander@195: private: dvander@195: Scope **prevp_; dvander@195: Scope *prev_; dvander@195: Scope *scope_; dvander@195: }; dvander@144: dvander@195: SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit) dvander@30: : zone_(zone), dvander@195: pool_(zone->pool()), dvander@30: cc_(cc), dvander@195: unit_(unit), dvander@195: hir_(NULL), dvander@195: emitter_(pool_), dvander@195: module_(NULL), dvander@71: loop_(NULL) dvander@0: { dvander@0: } dvander@0: dvander@195: SemanticAnalysis::SemanticAnalysis(SemanticAnalysis *parent, Handle fun) dvander@195: : zone_(parent->zone_), dvander@195: pool_(parent->pool_), dvander@195: cc_(parent->cc_), dvander@195: unit_(parent->unit_), dvander@195: hir_(NULL), dvander@195: scope_(parent->scope_), dvander@195: emitter_(pool_), dvander@195: module_(parent->module_), dvander@195: fun_(fun), dvander@195: loop_(NULL) dvander@0: { dvander@137: dvander@4: } dvander@4: dvander@25: void dvander@195: SemanticAnalysis::analyze() dvander@21: { dvander@195: scope_ = unit_->globalScope(); dvander@195: dvander@195: module_ = Module::New(zone_); dvander@195: dvander@195: for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) { dvander@195: Statement *stmt = unit_->tree()->statements()->at(i); dvander@195: stmt->accept(this); dvander@195: } dvander@21: dvander@195: Local globals(zone_, unit_->globalScope()->build(zone_)); dvander@195: if (!globals) dvander@195: return; dvander@195: module_->setGlobals(globals); dvander@195: dvander@195: Local code(zone_, __ finish()); dvander@195: if (!code) dvander@195: return; dvander@195: code->setModule(module_); dvander@195: module_->setCode(code); dvander@195: dvander@195: #ifndef NDEBUG dvander@195: // Disassemble(code, stdout); dvander@195: #endif dvander@195: dvander@195: unit_->module_ = module_; dvander@21: } dvander@21: dvander@25: void dvander@195: SemanticAnalysis::visitFunctionStatement(FunctionStatement *stmt) dvander@25: { dvander@195: FunctionSymbol *sym = stmt->sym(); dvander@195: Local type(zone_, sym->type()); dvander@22: dvander@195: assert(scope_->kind() == Scope::GLOBAL); dvander@79: dvander@195: if (stmt->token() == TOK_NATIVE) { dvander@195: // Define the native now. dvander@195: size_t index; dvander@195: if (!zone_->nativeTable()->add(stmt->name(), &index)) dvander@195: return; dvander@22: dvander@195: Local native(zone_, Native::New(zone_, type, index)); dvander@195: if (!native) dvander@195: return; dvander@25: dvander@195: __ object(native); dvander@195: __ setglobal(sym); dvander@195: __ pop(); dvander@23: } dvander@23: dvander@195: // If the function is a forward or native, we don't have to do anything. dvander@195: if (stmt->token() == TOK_NATIVE || stmt->token() == TOK_FORWARD) dvander@23: return; dvander@4: dvander@195: SemanticAnalysis child(this, type); dvander@195: Local funobj(zone_, child.compile(stmt)); dvander@195: if (!funobj) dvander@25: return; dvander@25: dvander@195: __ object(funobj); dvander@195: __ setglobal(sym); dvander@195: __ public_(); dvander@0: } dvander@0: dvander@195: Function * dvander@195: SemanticAnalysis::compile(FunctionStatement *stmt) dvander@83: { dvander@195: __ setFirstLine(stmt->pos().line); dvander@83: dvander@195: AutoEnterScope argScope(&scope_, stmt->argScope()); dvander@195: AutoEnterScope varScope(&scope_, stmt->varScope()); dvander@4: dvander@195: stmt->body()->accept(this); dvander@71: dvander@195: Local code(zone_, __ finish()); dvander@195: if (!code) dvander@195: return NULL; dvander@195: code->setModule(module_); dvander@25: dvander@195: Local fun(zone_, Function::New(zone_, code, fun_, stmt->name(), stmt->pos())); dvander@195: if (!fun) dvander@195: return NULL; dvander@25: dvander@195: #ifndef NDEBUG dvander@195: // Disassemble(code, stdout); dvander@195: #endif dvander@71: dvander@195: return fun; dvander@0: } dvander@0: dvander@9: void dvander@195: SemanticAnalysis::visitBlockStatement(BlockStatement *node) dvander@9: { dvander@195: AutoEnterScope scope(&scope_, node->scope()); dvander@71: dvander@195: for (size_t i = 0; i < node->statements()->length(); i++) { dvander@195: Statement *stmt = node->statements()->at(i); dvander@195: stmt->accept(this); dvander@195: assert(__ stackDepth() == 0); dvander@71: } dvander@9: } dvander@9: dvander@0: void dvander@195: SemanticAnalysis::visitExpressionStatement(ExpressionStatement *node) dvander@145: { dvander@195: // While building HIR, we enter new pool and root scopes, since HIR dvander@195: // creation is purely temporary. dvander@195: PoolScope poolScope(zone_->pool()); dvander@195: RootScope rootScope(zone_); dvander@190: dvander@195: HIR *hir = eval(node->expression()); dvander@195: if (!hir) dvander@195: return; dvander@187: dvander@195: discharge(hir); dvander@195: __ pop(); dvander@187: } dvander@187: dvander@195: void dvander@208: SemanticAnalysis::visitIfStatement(IfStatement *node) dvander@208: { dvander@208: Label join; dvander@208: dvander@208: if (!node->ifFalse()) { dvander@208: Label success; dvander@208: dvander@208: visitForTest(node->condition(), &success, &join, &success); dvander@208: __ bind(&success); dvander@208: node->ifTrue()->accept(this); dvander@208: } else { dvander@208: Label success, next; dvander@208: dvander@208: visitForTest(node->condition(), &success, &next, &success); dvander@208: __ bind(&success); dvander@208: node->ifTrue()->accept(this); dvander@208: __ jump(&join); dvander@208: __ bind(&next); dvander@208: node->ifFalse()->accept(this); dvander@208: } dvander@208: dvander@208: __ bind(&join); dvander@208: } dvander@208: dvander@208: void dvander@195: SemanticAnalysis::visitForStatement(ForStatement *node) dvander@187: { dvander@195: AutoEnterScope scope(&scope_, node->scope()); dvander@195: PoolScope poolScope(zone_->pool()); dvander@195: RootScope rootScope(zone_); dvander@195: dvander@195: Label join, update; dvander@195: LoopScope loop(scope_, &join, &update, &loop_); dvander@195: dvander@195: if (node->initialization()) dvander@195: node->initialization()->accept(this); dvander@187: dvander@195: Label header, test; dvander@195: if (node->condition()) dvander@195: __ jump(&test); dvander@195: dvander@195: __ bind(&header); dvander@195: node->body()->accept(this); dvander@195: dvander@195: __ bind(&update); dvander@195: if (node->update()) dvander@195: node->update()->accept(this); dvander@195: dvander@195: if (node->condition()) { dvander@195: __ bind(&test); dvander@195: visitForTest(node->condition(), &header, &join, &join); dvander@187: } else { dvander@195: __ jump(&header); dvander@187: } dvander@187: dvander@195: __ bind(&join); dvander@187: dvander@195: assert(__ stackDepth() == 0); dvander@187: } dvander@187: dvander@0: void dvander@203: SemanticAnalysis::visitWhileStatement(WhileStatement *node) dvander@203: { dvander@203: PoolScope poolScope(zone_->pool()); dvander@203: RootScope rootScope(zone_); dvander@203: dvander@203: Label header, join; dvander@203: dvander@203: __ bind(&header); dvander@203: dvander@203: LoopScope loop(scope_, &join, &header, &loop_); dvander@203: if (node->token() == TOK_WHILE) { dvander@203: Label body; dvander@203: visitForTest(node->condition(), &body, &join, &body); dvander@203: node->body()->accept(this); dvander@203: __ jump(&header); dvander@203: } else { dvander@203: node->body()->accept(this); dvander@203: visitForTest(node->condition(), &header, &join, &join); dvander@203: } dvander@203: dvander@203: __ bind(&join); dvander@203: dvander@203: assert(__ stackDepth() == 0); dvander@203: } dvander@203: dvander@212: static inline Heap::Tenure dvander@212: InferTenure(Symbol *sym) dvander@212: { dvander@212: if (sym->scope()->kind() == Scope::GLOBAL) dvander@212: return Heap::Tenure_Old; dvander@212: // :TODO: need to use LIFO! dvander@212: return Heap::Tenure_Default; dvander@212: } dvander@212: dvander@203: void dvander@195: SemanticAnalysis::visitVariableDeclaration(VariableDeclaration *node) dvander@0: { dvander@195: PoolScope poolScope(zone_->pool()); dvander@195: RootScope rootScope(zone_); dvander@195: dvander@195: if (node->initialization()) { dvander@212: HIR *hir = NULL; dvander@212: dvander@195: if ((hir = eval(node->initialization())) == NULL) dvander@195: return; dvander@195: if ((hir = coerce(hir, node->sym()->type(), Coerce_Assign)) == NULL) dvander@195: return; dvander@212: dvander@212: discharge(hir); dvander@195: } else { dvander@212: if (node->sym()->type()->isInt32() || dvander@212: node->sym()->type()->isEnum() || dvander@212: node->sym()->type()->isChar() || dvander@212: node->sym()->type()->isBool()) dvander@212: { dvander@212: __ int_(0); dvander@212: } else if (node->sym()->type()->isFloat()) { dvander@212: __ float_(0); dvander@212: } else if (node->sym()->type()->isArray()) { dvander@212: Local type(zone_, ArrayType::cast(node->sym()->type())); dvander@212: Local map(zone_, ArrayMap::Attach(zone_, type)); dvander@212: if (!map) dvander@212: return; dvander@212: dvander@212: if (type->isFixedLength()) { dvander@212: __ newarray(OP_NEWFIXED, map, InferTenure(node->sym())); dvander@212: } else if (node->dims()) { dvander@212: assert(false); dvander@212: __ newarray(OP_NEWSIZED, map, InferTenure(node->sym())); dvander@212: } else { dvander@212: __ newarray(OP_NEWEMPTY, map, InferTenure(node->sym())); dvander@212: } dvander@212: } dvander@195: } dvander@195: dvander@195: if (!__ allocate(node->sym())) dvander@0: return; dvander@0: dvander@195: set(node->sym()); dvander@195: __ pop(); dvander@195: } dvander@195: dvander@195: void dvander@195: SemanticAnalysis::visitReturnStatement(ReturnStatement *node) dvander@195: { dvander@195: if (!node->expression()) { dvander@195: if (!fun_->returnType()->isVoid()) { dvander@195: cc_.reportError(node->pos(), Message_UsedVoidReturn); dvander@0: return; dvander@0: } dvander@0: dvander@195: __ returnvoid(); dvander@195: return; dvander@0: } dvander@0: dvander@195: PoolScope poolScope(zone_->pool()); dvander@195: RootScope rootScope(zone_); dvander@195: dvander@195: HIR *hir = eval(node->expression()); dvander@195: if (!hir) dvander@195: return; dvander@147: dvander@195: Local returnType(zone_, fun_->returnType()); dvander@195: if ((hir = coerce(hir, returnType, Coerce_Return)) == NULL) dvander@195: return; dvander@195: dvander@195: discharge(hir); dvander@195: __ return_(); dvander@0: } dvander@0: dvander@0: void dvander@195: SemanticAnalysis::visitBinaryExpression(BinaryExpression *node) dvander@143: { dvander@195: HIR *left = eval(node->left()); dvander@195: HIR *right = eval(node->right()); dvander@195: if (!left || !right) dvander@195: return; dvander@168: dvander@195: hir_ = binary(node->token(), left, right); dvander@168: } dvander@168: dvander@14: bool dvander@195: SemanticAnalysis::checkArgumentCount(Handle type, unsigned actual) dvander@168: { dvander@168: if (type->parameters()->length() == actual) dvander@168: return true; dvander@168: dvander@168: if (actual > type->parameters()->length()) { dvander@168: if (!type->isNative() || !type->isNativeVariadic()) dvander@168: return false; dvander@168: return true; dvander@168: } dvander@168: dvander@168: if (!type->defaults()) dvander@168: return false; dvander@168: dvander@168: // Missing arguments. See if there's a default argument for each missing dvander@168: // actual. dvander@168: for (unsigned i = actual; i < type->parameters()->length(); i++) { dvander@168: if (!type->defaults()->at(i)) dvander@168: return false; dvander@168: } dvander@168: dvander@168: return true; dvander@14: } dvander@14: dvander@0: void dvander@195: SemanticAnalysis::visitNameProxy(NameProxy *proxy) dvander@0: { dvander@195: Symbol *sym = proxy->sym(); dvander@195: VariableSymbol *var = sym->asVariable(); dvander@195: dvander@195: Scope *in = sym->scope(); dvander@195: switch (in->kind()) { dvander@195: case Scope::GLOBAL: dvander@195: hir_ = new (pool_) HGlobal(sym); dvander@14: return; dvander@14: dvander@195: default: dvander@195: assert(in->kind() == Scope::BLOCK); dvander@195: assert(var->storage() == VariableSymbol::Local); dvander@195: hir_ = new (pool_) HLocal(var); dvander@195: return; dvander@195: } dvander@195: } dvander@195: dvander@195: void dvander@195: SemanticAnalysis::visitIntegerLiteral(IntegerLiteral *lit) dvander@195: { dvander@195: Local type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32)); dvander@195: hir_ = new (pool_) HInteger(type, lit->value()); dvander@195: } dvander@195: dvander@195: void dvander@195: SemanticAnalysis::visitFloatLiteral(FloatLiteral *node) dvander@195: { dvander@195: Local type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float)); dvander@195: hir_ = new (pool_) HFloat(type, (float)node->value()); dvander@195: } dvander@195: dvander@195: void dvander@195: SemanticAnalysis::visitCallExpression(CallExpression *node) dvander@195: { dvander@195: HIR *callee = eval(node->callee()); dvander@195: if (!callee) dvander@195: return; dvander@195: dvander@195: if (!callee->type()->isFunction()) { dvander@25: cc_.reportError(node->pos(), Message_CalleeNotFunction); dvander@25: return; dvander@25: } dvander@168: dvander@195: Local fun(zone_, FunctionType::cast(callee->type())); dvander@195: dvander@195: if (!checkArgumentCount(fun, node->arguments()->length())) { dvander@168: cc_.reportError(node->pos(), Message_ArgumentCountMismatch); dvander@168: return; dvander@25: } dvander@14: dvander@195: if (fun->isForward()) { dvander@195: cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars()); dvander@195: return; dvander@195: } dvander@63: dvander@195: HIRList *args = new (pool_) HIRList; dvander@55: for (unsigned i = 0; i < node->arguments()->length(); i++) { dvander@14: Expression *expression = node->arguments()->at(i); dvander@195: HIR *arg = eval(expression); dvander@195: if (!arg) dvander@14: return; dvander@14: dvander@195: Handle given = arg->type(); dvander@71: dvander@68: bool mustComputeReference; dvander@195: if (i >= fun->parameters()->length()) { dvander@68: // Special handling for natives. Arguments past the formal must dvander@68: // always have references computed. However, arrays are already dvander@195: // references for natives. dvander@195: assert(fun->isNative() && fun->isNativeVariadic()); dvander@195: mustComputeReference = !given->isReference() && dvander@195: !given->isArray(); dvander@68: } else { dvander@195: Local actual(zone_, fun->parameterAt(i)); dvander@166: dvander@188: if (expression->isIndexExpression()) { dvander@195: // Temporarily disabled. dvander@195: assert(!actual->isArray()); dvander@188: if (actual->isReference()) { dvander@188: cc_.reportError(expression->pos(), Message_CannotComputeIndexRef); dvander@188: return; dvander@188: } dvander@166: } dvander@166: dvander@195: // When we start overloading, coercion will have to happen later. dvander@195: arg = coerce(arg, actual, Coerce_Arg); dvander@195: if (!arg) dvander@68: return; dvander@195: dvander@68: mustComputeReference = actual->isReference() && !given->isReference(); dvander@68: } dvander@14: dvander@195: // :TODO: handle mustComputeReference dvander@195: assert(!mustComputeReference); dvander@195: dvander@195: if (!args->append(arg)) dvander@195: return; dvander@14: } dvander@66: dvander@195: hir_ = new (pool_) HCall(fun->returnType(), callee, args); dvander@172: } dvander@172: dvander@172: void dvander@195: SemanticAnalysis::visitAssignment(Assignment *node) dvander@71: { dvander@195: HLValue *lval = lvalue(node->lvalue()); dvander@195: if (!lval) dvander@71: return; dvander@71: dvander@195: HIR *hir = eval(node->expression()); dvander@195: if ((hir = coerce(hir, lval->type(), Coerce_Assign)) == NULL) dvander@195: return; dvander@71: dvander@195: hir_ = new (pool_) HStore(lval, hir); dvander@71: } dvander@71: dvander@208: void dvander@208: SemanticAnalysis::visitBreakStatement(BreakStatement *node) dvander@208: { dvander@208: if (!loop_) { dvander@208: cc_.reportError(node->pos(), Message_BreakOutsideLoop); dvander@208: return; dvander@208: } dvander@208: dvander@208: // Note, if we re-introduce LIFO allocs, we need to unwind here. dvander@208: __ jump(loop_->break_()); dvander@208: } dvander@208: dvander@208: void dvander@208: SemanticAnalysis::visitContinueStatement(ContinueStatement *node) dvander@208: { dvander@208: if (!loop_) { dvander@208: cc_.reportError(node->pos(), Message_ContinueOutsideLoop); dvander@208: return; dvander@208: } dvander@208: dvander@208: // Note, if we re-introduce LIFO allocs, we need to unwind here. dvander@208: __ jump(loop_->continue_()); dvander@208: } dvander@208: dvander@212: void dvander@212: SemanticAnalysis::visitIndexExpression(IndexExpression *node) dvander@212: { dvander@212: HIR *left = eval(node->left()); dvander@212: if (!left) dvander@212: return; dvander@212: dvander@212: HIR *right = eval(node->right()); dvander@212: if (!right) dvander@212: return; dvander@212: dvander@212: // Hrm... yes, for now, let's coerce here. dvander@212: Local i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32)); dvander@212: if ((right = coerce(right, i32, Coerce_Arg)) == NULL) dvander@212: return; dvander@212: dvander@212: // Do not coerce here, there's no reason to yet. dvander@212: if (!left->type()->isArray()) { dvander@212: cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray); dvander@212: return; dvander@212: } dvander@212: dvander@212: hir_ = new (pool_) HIndex(ArrayType::cast(left->type())->contained(), dvander@212: left, dvander@212: right); dvander@212: } dvander@212: dvander@195: Type * dvander@195: SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right) dvander@0: { dvander@195: Handle l = left->type(); dvander@195: Handle r = right->type(); dvander@195: dvander@195: if (token >= TOK_PLUS && token <= TOK_SLASH) { dvander@195: // We allow: [float|int32] + [float|int32] dvander@195: if (l->isFloat() && r->isInt32()) dvander@195: return l; dvander@195: if (l->isInt32() && r->isFloat()) dvander@195: return r; dvander@195: if (l->isInt32() && r->isInt32()) dvander@195: return l; dvander@195: } dvander@25: dvander@195: assert(l == r); dvander@195: dvander@195: return left->type(); dvander@195: } dvander@25: dvander@195: HIR * dvander@195: SemanticAnalysis::coerce(HIR *hir, Handle to, CoercionKind kind) dvander@195: { dvander@195: Handle from = hir->type(); dvander@71: dvander@195: if (from->isInt32() && to->isFloat()) dvander@195: return new (pool_) HConvert(to, OP_CVT_I2F, hir); dvander@208: if (from->isInt32() && to->isBool()) dvander@208: return new (pool_) HConvert(to, OP_CVT_I2B, hir); dvander@195: dvander@195: assert(from == to); dvander@195: dvander@195: return hir; dvander@0: } dvander@0: dvander@0: void dvander@195: SemanticAnalysis::set(VariableSymbol *sym) dvander@0: { dvander@195: if (sym->scope()->kind() == Scope::GLOBAL) { dvander@195: __ setglobal(sym); dvander@195: } else { dvander@195: assert(sym->storage() == VariableSymbol::Local); dvander@195: __ setlocal(sym); dvander@0: } dvander@0: } dvander@2: dvander@195: HIR * dvander@195: SemanticAnalysis::binary(TokenKind token, HIR *left, HIR *right) dvander@148: { dvander@195: Local coercion(zone_, coercionType(token, left, right)); dvander@195: if (!coercion) dvander@195: return NULL; dvander@195: if ((left = coerce(left, coercion, Coerce_Arg)) == NULL) dvander@195: return NULL; dvander@195: if ((right = coerce(right, coercion, Coerce_Arg)) == NULL) dvander@195: return NULL; dvander@195: dvander@195: switch (token) { dvander@195: case TOK_PLUS: dvander@195: case TOK_MINUS: dvander@195: case TOK_STAR: dvander@195: case TOK_SLASH: dvander@195: case TOK_PERCENT: dvander@195: case TOK_AMPERSAND: dvander@195: case TOK_BITOR: dvander@195: case TOK_BITXOR: dvander@195: case TOK_SHR: dvander@195: case TOK_USHR: dvander@195: case TOK_SHL: dvander@195: return new (pool_) HBinary(left->type(), token, left, right); dvander@148: dvander@195: case TOK_EQUALS: dvander@195: case TOK_NOTEQUALS: dvander@195: case TOK_LT: dvander@195: case TOK_LE: dvander@195: case TOK_GT: dvander@195: case TOK_GE: dvander@195: case TOK_AND: dvander@195: case TOK_OR: dvander@195: { dvander@195: Local result(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool)); dvander@195: return new (pool_) HBinary(result, token, left, right); dvander@195: } dvander@148: dvander@195: default: dvander@195: assert(false); dvander@195: return NULL; dvander@148: } dvander@195: } dvander@148: dvander@195: static inline TokenKind dvander@195: ToCompare(Expression *expr) dvander@195: { dvander@195: if (expr->isBinaryExpression()) { dvander@195: BinaryExpression *b = expr->toBinaryExpression(); dvander@195: if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR) dvander@195: return b->token(); dvander@195: } else if (expr->isUnaryExpression()) { dvander@195: UnaryExpression *u = expr->toUnaryExpression(); dvander@195: if (u->token() == TOK_NOT) dvander@195: return TOK_NOT; dvander@195: } dvander@195: return TOK_EOF; dvander@148: } dvander@148: dvander@148: void dvander@195: SemanticAnalysis::visitForTest(Expression *expr, dvander@195: Label *trueBranch, dvander@195: Label *falseBranch, dvander@195: Label *fallthrough) dvander@2: { dvander@208: Local boolType(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool)); dvander@208: dvander@195: TokenKind token = ToCompare(expr); dvander@195: if (token == TOK_EOF || token == TOK_NOT) { dvander@208: HIR *hir; dvander@208: if (token == TOK_EOF) dvander@208: hir = eval(expr); dvander@208: else dvander@208: hir = eval(expr->toUnaryExpression()->expression()); dvander@208: if (!hir) dvander@208: return; dvander@208: if ((hir = coerce(hir, boolType, Coerce_Assign)) == NULL) dvander@208: return; dvander@208: dvander@208: discharge(hir); dvander@208: dvander@208: bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT); dvander@208: Opcode op = jumpOnTrue ? OP_JT : OP_JF; dvander@208: dvander@208: if (fallthrough == falseBranch) dvander@208: __ j(op, trueBranch); dvander@208: else dvander@208: __ j(op, falseBranch); dvander@172: return; dvander@172: } dvander@172: dvander@195: BinaryExpression *bin = expr->toBinaryExpression(); dvander@195: if (token == TOK_AND || token == TOK_OR) { dvander@195: assert(false); dvander@195: //visitForLogicTest(expr, trueBranch, falseBranch, fallthrough); dvander@195: return; dvander@172: } dvander@172: dvander@195: HIR *left = eval(bin->left()); dvander@195: HIR *right = eval(bin->right()); dvander@195: if (!left || !right) dvander@195: return; dvander@195: dvander@195: HIR *hir = binary(bin->token(), left, right); dvander@195: if (!hir) dvander@195: return; dvander@208: if ((hir = coerce(hir, boolType, Coerce_Assign)) == NULL) dvander@208: return; dvander@172: dvander@195: discharge(hir); dvander@195: if (fallthrough == trueBranch) dvander@195: __ j(OP_JF, falseBranch); dvander@195: else dvander@195: __ j(OP_JT, trueBranch); dvander@195: } dvander@195: dvander@195: HLValue * dvander@195: SemanticAnalysis::lvalue(Expression *expr) dvander@195: { dvander@195: HIR *hir = eval(expr); dvander@195: if (!hir) dvander@195: return NULL; dvander@195: dvander@195: if (!hir->isLValue()) { dvander@195: cc_.reportError(expr->pos(), Message_ExpectedLValue); dvander@195: return NULL; dvander@172: } dvander@172: dvander@195: return static_cast(hir); dvander@195: } dvander@172: dvander@195: HIR * dvander@195: SemanticAnalysis::eval(Expression *expr) dvander@195: { dvander@195: assert(!hir_); dvander@195: expr->accept(this); dvander@172: dvander@195: HIR *hir = hir_; dvander@195: hir_ = NULL; dvander@195: dvander@195: return hir; dvander@172: } dvander@172: dvander@4: void dvander@195: SemanticAnalysis::discharge(HIR *hir) dvander@146: { dvander@195: EmitHIR(zone_, emitter_, hir); dvander@146: }