dvander@137: /* vim: set ts=4 sw=4 tw=99 et: dvander@137: * dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@137: * This file is part of SourcePawn. dvander@0: * dvander@137: * 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@137: * 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@137: * SourcePawn. If not, see http://www.gnu.org/licenses/. dvander@0: */ dvander@195: #include "../Strings.h" dvander@195: #include "../Zone.h" dvander@195: #include "../TypeManager.h" dvander@0: #include "NameBinding.h" dvander@85: #include "Scopes.h" dvander@209: #include "ConstantEvaluator.h" dvander@195: #include "../Spaces-inl.h" dvander@195: #include "../Heap-inl.h" dvander@0: dvander@59: using namespace ke; dvander@0: dvander@195: // Create symbol tables and symbols for every scope and declaration. For type dvander@195: // declarations and methods, we also pre-allocate a Type object, so that dvander@195: // circular dependencies between types will work. dvander@195: class NamePopulator : public AstVisitor dvander@0: { dvander@195: private: dvander@195: // This class is analagous to a Scope, however, it allows us to create dvander@195: // scopes lazily. If a scope is requested, and the current environment dvander@195: // has no scope, then a scope is created. If no scope is ever requested, dvander@195: // a scope does not need to be created. dvander@195: class SymbolEnv dvander@195: { dvander@195: public: dvander@195: SymbolEnv(SymbolEnv **prevp, Scope *scope = NULL) dvander@195: : envp_(prevp), dvander@195: prev_(*prevp), dvander@195: scope_(scope) dvander@195: { dvander@195: *envp_ = this; dvander@195: } dvander@195: ~SymbolEnv() { dvander@195: *envp_ = prev_; dvander@195: } dvander@195: dvander@195: Scope *scope() { dvander@195: return scope_; dvander@195: } dvander@195: void setScope(Scope *scope) { dvander@195: assert(!scope_); dvander@195: scope_ = scope; dvander@195: } dvander@195: SymbolEnv *prev() const { dvander@195: return prev_; dvander@195: } dvander@195: dvander@195: private: dvander@195: SymbolEnv **envp_; dvander@195: SymbolEnv *prev_; dvander@195: Scope *scope_; dvander@195: }; dvander@195: dvander@195: enum ReturnStatus { dvander@195: NoReturn, dvander@195: VoidReturn, dvander@195: ValueReturn dvander@195: }; dvander@195: dvander@195: class FunctionScope dvander@195: { dvander@195: public: dvander@195: FunctionScope(FunctionScope **prevp) dvander@195: : prevp_(prevp), dvander@195: prev_(*prevp), dvander@195: status_(NoReturn) dvander@195: { dvander@195: *prevp_ = this; dvander@195: } dvander@195: ~FunctionScope() { dvander@195: *prevp_ = prev_; dvander@195: } dvander@195: ReturnStatus returns() const { dvander@195: return status_; dvander@195: } dvander@195: void returns(ReturnStatus status) { dvander@195: if (status > status_) dvander@195: status_ = status; dvander@195: } dvander@195: private: dvander@195: FunctionScope **prevp_; dvander@195: FunctionScope *prev_; dvander@195: ReturnStatus status_; dvander@195: }; dvander@195: dvander@195: public: dvander@195: NamePopulator(Zone *zone, CompileContext &cc, TranslationUnit *unit) dvander@195: : zone_(zone), dvander@195: pool_(zone->pool()), dvander@195: cc_(cc), dvander@195: unit_(unit), dvander@195: env_(NULL), dvander@195: fun_(NULL) dvander@195: { dvander@195: } dvander@195: dvander@195: bool analyze() { dvander@195: ImportScope *importScope = ImportScope::New(pool_); dvander@195: if (!importScope) dvander@195: return false; dvander@195: dvander@195: // At the import level, we declare system types. dvander@195: if (!declareSystemTypes(importScope)) dvander@195: return false; dvander@195: dvander@195: GlobalScope *globalScope = GlobalScope::New(pool_, importScope); dvander@195: if (!globalScope) dvander@195: return false; dvander@195: dvander@195: unit_->setImportScope(importScope); dvander@195: unit_->setGlobalScope(globalScope); dvander@195: dvander@195: SymbolEnv env(&env_, globalScope); 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@195: dvander@195: return true; dvander@195: } dvander@195: dvander@195: bool declareSystemType(ImportScope *scope, const char *name, Handle type) { dvander@195: Local tag(zone_, zone_->makeSymbol(name)); dvander@195: if (!tag) dvander@195: return false; dvander@195: dvander@195: TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type); dvander@195: return scope->addSymbol(sym); dvander@195: } dvander@195: dvander@195: bool declareSystemType(ImportScope *scope, const char *name, PrimitiveType prim) { dvander@195: Local primitive(zone_, zone_->types()->getPrimitive(prim)); dvander@195: assert(primitive); dvander@195: return declareSystemType(scope, name, primitive); dvander@195: } dvander@195: dvander@195: bool declareSystemTypes(ImportScope *scope) { dvander@195: if (!declareSystemType(scope, "float", PrimitiveType_Float)) dvander@195: return false; dvander@195: if (!declareSystemType(scope, "_", PrimitiveType_Int32)) dvander@195: return false; dvander@195: if (!declareSystemType(scope, "int", PrimitiveType_Int32)) dvander@195: return false; dvander@195: if (!declareSystemType(scope, "bool", PrimitiveType_Bool)) dvander@195: return false; dvander@195: if (!declareSystemType(scope, "char", PrimitiveType_Char)) dvander@195: return false; dvander@195: dvander@195: Local voidType(zone_, zone_->types()->getVoid()); dvander@195: if (!declareSystemType(scope, "void", voidType)) dvander@195: return false; dvander@195: dvander@195: return true; dvander@195: } dvander@195: dvander@195: void visitVariableDeclaration(VariableDeclaration *node) { dvander@195: Scope *scope = env_->scope(); dvander@195: if (!scope || scope->kind() != Scope::GLOBAL) { dvander@195: if ((scope = getOrCreateBlockScope()) == NULL) dvander@195: return; dvander@195: } dvander@195: dvander@195: if (scope->kind() == Scope::GLOBAL) { dvander@195: // The symbol must be added now, since it could be an export. dvander@195: VariableSymbol *sym = new (pool_) VariableSymbol(scope, node->name(), node->pos()); dvander@195: node->setSymbol(sym); dvander@195: dvander@195: if (!registerName(scope, sym)) dvander@195: return; dvander@195: } else { dvander@195: // We ensure the scope will exist at the name binding phase, but dvander@195: // we don't actually register the variable symbol yet. Otherwise, dvander@195: // when binding the initializer, we could encounter: dvander@195: // new x = x; dvander@195: // dvander@195: // And we don't necessarily want this to bind. dvander@195: } dvander@195: dvander@212: if (node->initialization()) dvander@212: node->initialization()->accept(this); dvander@195: } dvander@195: void visitEnumStatement(EnumStatement *node) { dvander@233: Local name(zone_, node->name()); dvander@233: Local type(zone_); dvander@233: if (name) dvander@233: type = zone_->types()->newEnum(name); dvander@233: else dvander@233: type = zone_->types()->getPrimitive(PrimitiveType_Int32); dvander@233: dvander@233: if (!type) dvander@233: return; dvander@233: dvander@233: Scope *scope = getGlobalOrCreateBlockScope(); dvander@233: if (!scope) dvander@233: return; dvander@233: dvander@233: if (name) { dvander@233: TypeSymbol *sym = new (pool_) TypeSymbol(scope, name, type); dvander@233: if (!registerName(scope, sym)) dvander@233: return; dvander@233: } dvander@233: dvander@233: int value = 0; dvander@233: for (size_t i = 0; i < node->entries()->length(); i++) { dvander@233: EnumStatement::Entry &entry = node->entries()->at(i); dvander@233: BoxedPrimitive box = BoxedPrimitive::Int(value); dvander@233: if (entry.expr) { dvander@233: if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) { dvander@233: cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant); dvander@233: return; dvander@233: } dvander@233: dvander@233: assert(box.type() == PrimitiveType_Int32); dvander@233: value = box.toInt(); dvander@233: } dvander@233: dvander@233: ConstantSymbol *sym = new (pool_) ConstantSymbol(scope, entry.name, entry.pos, type, box); dvander@233: if (!registerName(scope, sym)) dvander@233: return; dvander@233: dvander@233: value++; dvander@233: } dvander@195: } dvander@195: void visitFunctionStatement(FunctionStatement *node) { dvander@195: // We create function types ahead of time, not for any particular dvander@195: // reason. It makes things consistent with FunctionTypeStatement, dvander@195: // which actually does produce a type. dvander@233: Local type(zone_, FunctionType::New(zone_, node->name(), node->token())); dvander@195: if (!type) dvander@195: return; dvander@195: dvander@195: assert(env_->scope()); dvander@195: dvander@195: // Function statements are always named, so add the name to the outer scope. dvander@195: FunctionSymbol *sym = new (pool_) FunctionSymbol(env_->scope(), node->name(), node->pos(), type); dvander@195: if (!registerName(env_->scope(), sym)) dvander@195: return; dvander@195: dvander@195: if (node->token() == TOK_PUBLIC || dvander@195: node->token() == TOK_FORWARD || dvander@195: node->token() == TOK_NATIVE) dvander@195: { dvander@195: // We're in the global scope, for sure. dvander@195: assert(env_->scope()->kind() == Scope::GLOBAL); dvander@195: GlobalScope *globals = (GlobalScope *)env_->scope(); dvander@195: if (!globals->addPublic(sym)) dvander@195: return; dvander@195: } dvander@195: dvander@195: node->setSymbol(sym); dvander@195: dvander@195: // Scope for the function's arguments. dvander@195: SymbolEnv argEnv(&env_); dvander@195: if (!registerArguments(node->signature())) dvander@195: return; dvander@195: dvander@195: // Scope for function body. dvander@195: SymbolEnv localEnv(&env_); dvander@195: FunctionScope fun(&fun_); dvander@195: if (node->body()) dvander@195: node->body()->accept(this); dvander@195: dvander@195: // Function statements have quirky semantics around their return dvander@195: // type. For reasonable compatibility with SP1, we use the following dvander@195: // heuristics for when no explicit type is declared. dvander@195: if (!node->signature().returnType()) { dvander@195: Local type(zone_); dvander@195: if (node->token() == TOK_FORWARD || node->token() == TOK_NATIVE) { dvander@195: // If the function type is a native or forward, we always dvander@195: // assume it returns an int32. dvander@195: type = zone_->types()->getPrimitive(PrimitiveType_Int32); dvander@195: } else if (fun.returns() != ValueReturn) { dvander@195: // This function never returns a value, so mark it as dvander@195: // returning void. dvander@195: type = zone_->types()->getVoid(); dvander@195: } dvander@195: // No need to NULL check here, we'll catch OOM later. dvander@195: node->sym()->type()->setReturnType(type); dvander@195: } dvander@195: dvander@195: node->setScopes(argEnv.scope(), localEnv.scope()); dvander@195: } dvander@195: void visitStructureStatement(StructureStatement *node) { dvander@195: assert(false); dvander@195: } dvander@195: void visiFunctionTypeStatementt(FunctionTypeStatement *node) { dvander@195: assert(false); dvander@195: } dvander@195: dvander@195: void visitNameProxy(NameProxy *name) { dvander@195: } dvander@195: void visitAssignment(Assignment *node) { dvander@195: node->lvalue()->accept(this); dvander@195: node->expression()->accept(this); dvander@195: } dvander@195: void visitBinaryExpression(BinaryExpression *node) { dvander@195: node->left()->accept(this); dvander@195: node->right()->accept(this); dvander@195: } dvander@195: void visitReturnStatement(ReturnStatement *node) { dvander@195: if (node->expression()) dvander@195: fun_->returns(ValueReturn); dvander@195: else dvander@195: fun_->returns(VoidReturn); dvander@195: } dvander@195: void visitForStatement(ForStatement *node) { dvander@195: SymbolEnv env(&env_); dvander@195: dvander@195: if (node->initialization()) dvander@195: node->initialization()->accept(this); dvander@195: if (node->condition()) dvander@195: node->condition()->accept(this); dvander@195: if (node->update()) dvander@195: node->update()->accept(this); dvander@195: node->body()->accept(this); dvander@195: dvander@195: node->setScope(env.scope()); dvander@195: } dvander@195: void visitBlockStatement(BlockStatement *node) { dvander@195: SymbolEnv env(&env_); dvander@195: dvander@195: for (size_t i = 0; i < node->statements()->length(); i++) dvander@195: node->statements()->at(i)->accept(this); dvander@195: dvander@195: node->setScope(env.scope()); dvander@195: } dvander@195: void visitIntegerLiteral(IntegerLiteral *node) { dvander@195: } dvander@195: void visitExpressionStatement(ExpressionStatement *node) { dvander@195: node->expression()->accept(this); dvander@195: } dvander@195: void visitCallExpression(CallExpression *node) { dvander@195: node->callee()->accept(this); dvander@195: for (size_t i = 0; i < node->arguments()->length(); i++) dvander@195: node->arguments()->at(i)->accept(this); dvander@195: } dvander@195: void visitIfStatement(IfStatement *node) { dvander@195: node->ifTrue()->accept(this); dvander@195: if (node->ifFalse()) dvander@195: node->ifFalse()->accept(this); dvander@195: } dvander@195: void visitIndexExpression(IndexExpression *node) { dvander@212: node->left()->accept(this); dvander@212: node->right()->accept(this); dvander@195: } dvander@195: void visitFloatLiteral(FloatLiteral *node) { dvander@195: } dvander@195: void visitWhileStatement(WhileStatement *node) { dvander@195: node->condition()->accept(this); dvander@195: node->body()->accept(this); dvander@195: } dvander@195: void visitBreakStatement(BreakStatement *node) { dvander@195: } dvander@195: void visitContinueStatement(ContinueStatement *node) { dvander@195: } dvander@195: void visitStringLiteral(StringLiteral *node) { dvander@195: } dvander@195: void visitIncDecExpression(IncDecExpression *node) { dvander@217: node->expression()->accept(this); dvander@195: } dvander@195: void visitUnaryExpression(UnaryExpression *node) { dvander@195: assert(false); dvander@195: } dvander@195: void visitTernaryExpression(TernaryExpression *node) { dvander@195: assert(false); dvander@195: } dvander@195: void visitBooleanLiteral(BooleanLiteral *node) { dvander@195: } dvander@195: void visitFieldExpression(FieldExpression *node) { dvander@195: } dvander@195: void visitSwitchStatement(SwitchStatement *node) { dvander@195: if (node->defaultCase()) dvander@195: node->defaultCase()->accept(this); dvander@195: dvander@195: for (size_t i = 0; i < node->cases()->length(); i++) dvander@195: node->cases()->at(i)->statement()->accept(this); dvander@195: } dvander@195: void visitArrayLiteral(ArrayLiteral *node) { dvander@195: } dvander@195: void visitImportStatement(ImportStatement *node) { dvander@195: } dvander@195: dvander@195: private: dvander@233: Scope *getGlobalOrCreateBlockScope() { dvander@233: if (env_->scope()) { dvander@233: assert(env_->scope()->kind() == Scope::BLOCK || dvander@233: env_->scope()->kind() == Scope::GLOBAL); dvander@233: return env_->scope(); dvander@233: } dvander@233: return getOrCreateBlockScope(); dvander@233: } dvander@195: Scope *getOrCreateBlockScope() { dvander@195: if (env_->scope()) { dvander@195: assert(env_->scope()->kind() == Scope::BLOCK); dvander@195: return env_->scope(); dvander@195: } dvander@195: dvander@195: LocalScope *scope = LocalScope::New(pool_); dvander@195: if (!scope) dvander@195: return NULL; dvander@195: dvander@195: env_->setScope(scope); dvander@195: return scope; dvander@195: } dvander@195: dvander@195: bool registerName(Scope *scope, Symbol *sym) { dvander@195: if (!scope) dvander@195: return false; dvander@195: dvander@195: if (Symbol *other = scope->localLookup(sym->name())) { dvander@195: // Report, but allow errors to continue. dvander@195: cc_.reportError(sym->pos(), Message_RedeclaredName, dvander@195: sym->name()->chars(), dvander@195: other->pos().line, dvander@195: other->pos().col); dvander@195: return true; dvander@195: } dvander@195: dvander@195: return scope->addSymbol(sym); dvander@195: } dvander@195: dvander@195: bool registerArguments(const FunctionSignature &sig) { dvander@195: if (!sig.parameters()->length()) dvander@195: return true; dvander@195: dvander@195: ArgumentScope *argScope = ArgumentScope::New(pool_); dvander@195: if (!argScope) dvander@195: return false; dvander@195: env_->setScope(argScope); dvander@195: dvander@195: for (size_t i = 0; i < sig.parameters()->length(); i++) { dvander@195: Parameter *param = sig.parameters()->at(i); dvander@195: VariableSymbol *sym = new (pool_) VariableSymbol(argScope, param->name(), param->pos()); dvander@195: if (!registerName(env_->scope(), sym)) dvander@195: return false; dvander@195: param->setSymbol(sym); dvander@195: } dvander@195: dvander@195: return true; dvander@195: } dvander@195: dvander@195: private: dvander@195: Zone *zone_; dvander@195: PoolAllocator &pool_; dvander@195: CompileContext &cc_; dvander@195: TranslationUnit *unit_; dvander@195: SymbolEnv *env_; dvander@195: FunctionScope *fun_; dvander@195: }; dvander@195: dvander@195: bool dvander@195: ke::PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit) dvander@195: { dvander@195: NamePopulator populator(zone, cc, unit); dvander@195: return populator.analyze(); dvander@0: } dvander@0: dvander@212: static const int INFER_ARRAY_SIZE = 0; dvander@212: static const int EVAL_ARRAY_SIZE = -1; dvander@212: static const int DYNAMIC_ARRAY_SIZE = -2; dvander@212: dvander@195: class NameBinder : public AstVisitor dvander@0: { dvander@195: public: dvander@195: class AutoLinkScope dvander@195: { dvander@195: public: dvander@195: AutoLinkScope(AutoLinkScope **prevp, Scope *scope) dvander@195: : prevp_(prevp), dvander@195: prev_(*prevp), dvander@195: scope_(scope) dvander@195: { dvander@195: if (scope_) { dvander@195: *prevp_ = this; dvander@195: if (prev_) dvander@195: scope_->setParent(prev_->scope()); dvander@195: } dvander@195: } dvander@195: ~AutoLinkScope() { dvander@195: if (scope_) { dvander@195: assert(*prevp_ == this); dvander@195: *prevp_ = prev_; dvander@195: } dvander@195: } dvander@195: Scope *scope() const { dvander@195: return scope_; dvander@195: } dvander@195: dvander@195: private: dvander@195: AutoLinkScope **prevp_; dvander@195: AutoLinkScope *prev_; dvander@195: Scope *scope_; dvander@195: }; dvander@195: dvander@195: public: dvander@195: NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit) dvander@195: : zone_(zone), dvander@195: pool_(zone->pool()), dvander@195: cc_(cc), dvander@195: unit_(unit), dvander@195: link_(NULL) dvander@195: { dvander@195: } dvander@195: dvander@195: bool bind() { dvander@195: // Start with the import scope, and collect all imported names. dvander@195: AutoLinkScope importScope(&link_, unit_->importScope()); dvander@195: dvander@195: for (size_t i = 0; i < unit_->tree()->imports()->length(); i++) dvander@195: unit_->tree()->imports()->at(i)->accept(this); dvander@195: dvander@195: // Next, enter the global scope and walk all statements. dvander@195: AutoLinkScope globalScope(&link_, unit_->globalScope()); 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@195: dvander@195: return true; dvander@195: } dvander@195: dvander@195: void visitVariableDeclaration(VariableDeclaration *node) { dvander@195: // Bind the initializer before registering the declaration, so that we dvander@195: // can error on bogus initializers (new x = x). dvander@212: if (node->initialization()) dvander@212: node->initialization()->accept(this); dvander@195: dvander@241: Local type(zone_, bindType(node->type(), node->quals())); dvander@195: if (!type) dvander@195: return; dvander@195: dvander@241: // We don't allow array typedefs yet. dvander@241: assert(!type->isArray()); dvander@241: dvander@241: if (node->dims()) { dvander@212: int dims[MAX_ARRAY_DEPTH]; dvander@212: int levels = evaluateDimensions(node->pos(), type, node->dims(), dims); dvander@212: if (levels < 0) dvander@212: return; dvander@212: dvander@212: // Do some extra inference based on the initializer, if present. dvander@212: Expression *init = node->initialization(); dvander@212: if (init && dvander@212: init->isArrayLiteral() && dvander@212: init->toArrayLiteral()->isFixed()) dvander@212: { dvander@212: Local contained(zone_, type->isArray() dvander@212: ? ArrayType::cast(type)->contained() dvander@212: : type); dvander@212: if (!inferFixedArrayDimensions(init->toArrayLiteral(), contained, dims, levels)) dvander@212: return; dvander@212: } dvander@212: dvander@212: // If we got extra dimensions, we need to build a new type. dvander@212: if (node->dims()) { dvander@241: if ((type = buildArrayType(type, node->quals(), dims, node->dims()->length())) == NULL) dvander@212: return; dvander@212: } dvander@209: } dvander@209: dvander@241: // If we're in global scope, and we received a |const| qualifier, then dvander@242: // we extend this to array references as well. This is to sort of mimic dvander@241: // SP1 functionality, but also means that you cannot have changeable dvander@241: // const pointers in global scope. dvander@241: if ((node->quals() & TypeQual_Const) && dvander@241: type->isArray() && dvander@241: link_->scope()->kind() == Scope::GLOBAL) dvander@241: { dvander@241: if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL) dvander@241: return; dvander@241: } dvander@241: dvander@195: // If the node already has a symbol (meaning it was a global), then dvander@195: // we don't have to do anything more. dvander@195: if (node->sym()) { dvander@195: assert(node->sym()->scope()->kind() == Scope::GLOBAL); dvander@209: node->sym()->setType(type); dvander@195: return; dvander@195: } dvander@195: dvander@195: VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type); dvander@195: node->setSymbol(sym); dvander@195: dvander@195: if (Symbol *other = link_->scope()->localLookup(sym->name())) { dvander@195: // Report, but allow errors to continue. dvander@195: cc_.reportError(sym->pos(), Message_RedeclaredName, dvander@195: sym->name()->chars(), dvander@195: other->pos().line, dvander@195: other->pos().col); dvander@195: return; dvander@195: } dvander@195: dvander@233: link_->scope()->addSymbol(sym); dvander@195: } dvander@195: void visitEnumStatement(EnumStatement *node) { dvander@195: } dvander@195: void visitFunctionStatement(FunctionStatement *node) { dvander@195: AutoLinkScope argScope(&link_, node->argScope()); dvander@195: AutoLinkScope varScope(&link_, node->varScope()); dvander@195: dvander@195: Local type(zone_, node->sym()->type()); dvander@195: if (!fillFunctionType(type, node->signature())) dvander@195: return; dvander@195: dvander@195: if (node->body()) dvander@195: node->body()->accept(this); dvander@195: } dvander@195: void visitStructureStatement(StructureStatement *node) { dvander@195: assert(false); dvander@195: } dvander@195: void visitFunctionTypeStatement(FunctionTypeStatement *node) { dvander@195: assert(false); dvander@195: } dvander@195: dvander@195: void visitNameProxy(NameProxy *proxy) { dvander@195: Scope *scope = link_->scope(); dvander@195: Symbol *sym = scope->lookup(proxy->name()); dvander@195: if (!sym) dvander@195: cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars()); dvander@195: proxy->bind(sym); dvander@195: } dvander@195: void visitAssignment(Assignment *node) { dvander@195: node->lvalue()->accept(this); dvander@195: node->expression()->accept(this); dvander@195: } dvander@195: void visitBinaryExpression(BinaryExpression *node) { dvander@195: node->left()->accept(this); dvander@195: node->right()->accept(this); dvander@195: } dvander@195: void visitReturnStatement(ReturnStatement *node) { dvander@195: node->expression()->accept(this); dvander@195: } dvander@195: void visitForStatement(ForStatement *node) { dvander@195: AutoLinkScope scope(&link_, node->scope()); dvander@0: dvander@195: if (node->initialization()) dvander@195: node->initialization()->accept(this); dvander@195: if (node->condition()) dvander@195: node->condition()->accept(this); dvander@195: if (node->update()) dvander@195: node->update()->accept(this); dvander@195: node->body()->accept(this); dvander@195: } dvander@195: void visitBlockStatement(BlockStatement *node) { dvander@195: AutoLinkScope scope(&link_, node->scope()); dvander@195: for (size_t i = 0; i < node->statements()->length(); i++) dvander@195: node->statements()->at(i)->accept(this); dvander@195: } dvander@195: void visitIntegerLiteral(IntegerLiteral *node) { dvander@195: } dvander@195: void visitExpressionStatement(ExpressionStatement *node) { dvander@195: node->expression()->accept(this); dvander@195: } dvander@195: void visitCallExpression(CallExpression *node) { dvander@195: node->callee()->accept(this); dvander@195: for (size_t i = 0; i < node->arguments()->length(); i++) dvander@195: node->arguments()->at(i)->accept(this); dvander@195: } dvander@195: void visitIfStatement(IfStatement *node) { dvander@195: node->condition()->accept(this); dvander@195: node->ifTrue()->accept(this); dvander@208: if (node->ifFalse()) dvander@208: node->ifFalse()->accept(this); dvander@195: } dvander@195: void visitIndexExpression(IndexExpression *node) { dvander@195: node->left()->accept(this); dvander@195: node->right()->accept(this); dvander@195: } dvander@195: void visitFloatLiteral(FloatLiteral *node) { dvander@195: } dvander@195: void visitWhileStatement(WhileStatement *node) { dvander@195: node->condition()->accept(this); dvander@195: node->body()->accept(this); dvander@195: } dvander@195: void visitBreakStatement(BreakStatement *node) { dvander@195: } dvander@195: void visitContinueStatement(ContinueStatement *node) { dvander@195: } dvander@195: void visitStringLiteral(StringLiteral *node) { dvander@195: } dvander@195: void visitIncDecExpression(IncDecExpression *node) { dvander@195: node->expression()->accept(this); dvander@195: } dvander@195: void visitUnaryExpression(UnaryExpression *node) { dvander@195: if (node->tag()) dvander@195: node->tag()->accept(this); dvander@195: node->expression()->accept(this); dvander@195: } dvander@195: void visitTernaryExpression(TernaryExpression *node) { dvander@195: node->condition()->accept(this); dvander@195: node->left()->accept(this); dvander@195: node->right()->accept(this); dvander@195: } dvander@195: void visitBooleanLiteral(BooleanLiteral *node) { dvander@195: } dvander@195: void visitFieldExpression(FieldExpression *node) { dvander@195: node->left()->accept(this); dvander@195: } dvander@195: void visitSwitchStatement(SwitchStatement *node) { dvander@195: node->expression()->accept(this); dvander@195: node->defaultCase()->accept(this); dvander@195: for (size_t i = 0; i < node->cases()->length(); i++) { dvander@195: // We don't test case expressions because they are literals. dvander@195: Case *c = node->cases()->at(i); dvander@195: c->statement()->accept(this); dvander@195: } dvander@195: } dvander@195: void visitArrayLiteral(ArrayLiteral *node) { dvander@195: for (size_t i = 0; i < node->expressions()->length(); i++) dvander@195: node->expressions()->at(i)->accept(this); dvander@195: } dvander@195: void visitImportStatement(ImportStatement *node) { dvander@195: if (node->suffix() == TOK_STAR) { dvander@195: // Import every name. dvander@195: assert(false); dvander@195: } else { dvander@195: GlobalScope *other = node->source()->globalScope(); dvander@195: Symbol *sym = other->findPublic(node->name()); dvander@195: if (!sym) { dvander@195: cc_.reportError(node->pos(), Message_CannotResolveImport, node->name()->chars()); dvander@195: return; dvander@195: } dvander@195: link_->scope()->addSymbol(sym); dvander@195: } dvander@195: } dvander@195: dvander@195: private: dvander@212: int evaluateDimensions(const SourcePosition &pos, Handle typeArg, ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) { dvander@212: unsigned level = 0; dvander@212: Local type(zone_, typeArg); dvander@212: while (type->isArray()) { dvander@212: ArrayType *atype = ArrayType::cast(type); dvander@212: dims[level] = atype->isFixedLength() dvander@212: ? atype->fixedLength() dvander@212: : DYNAMIC_ARRAY_SIZE; dvander@212: type = atype->contained(); dvander@212: level++; dvander@212: } dvander@212: dvander@212: if (!exprs) dvander@212: return level; dvander@212: dvander@212: if (level + exprs->length() > MAX_ARRAY_DEPTH) { dvander@212: cc_.reportError(pos, Message_MaximumArrayDepth); dvander@212: return -1; dvander@212: } dvander@212: dvander@212: bool hadEmptySize = false; dvander@212: for (size_t i = 0; i < exprs->length(); i++) { dvander@212: Expression *expr = exprs->at(i); dvander@212: if (!expr) { dvander@212: dims[i] = INFER_ARRAY_SIZE; dvander@212: hadEmptySize = true; dvander@212: continue; dvander@212: } dvander@212: dvander@212: BoxedPrimitive box; dvander@212: if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) { dvander@212: int size = box.toInt(); dvander@212: if (size <= 0) { dvander@212: cc_.reportError(expr->pos(), Message_BadArraySize); dvander@212: return false; dvander@212: } dvander@212: dvander@212: dims[i] = size; dvander@212: continue; dvander@212: } dvander@212: dvander@212: if (hadEmptySize) { dvander@212: cc_.reportError(expr->pos(), Message_BadDynamicInitializer); dvander@212: return false; dvander@212: } dvander@212: dvander@212: dims[i] = EVAL_ARRAY_SIZE; dvander@212: } dvander@212: dvander@212: return level + exprs->length(); dvander@212: } dvander@212: dvander@212: // This function computes missing dimension sizes based on a literal dvander@212: // initializer. We don't really handle any size rules here; we just dvander@212: // do a really dumb inference. dvander@212: bool inferFixedArrayDimensions(ArrayLiteral *lit, Handle contained, int dims[MAX_ARRAY_DEPTH], int levels) { dvander@212: for (int i = 0; i < levels; i++) { dvander@212: if (dims[i] == EVAL_ARRAY_SIZE || dims[i] == DYNAMIC_ARRAY_SIZE) { dvander@212: // The following are invalid: dvander@212: // new x[] = {...} dvander@212: // new Type:x = {...} // where Type is a non-fixed array type dvander@212: cc_.reportError(lit->pos(), Message_CannotInitializeEvalArray); dvander@212: return false; dvander@212: } dvander@212: dvander@212: if (dims[i] == INFER_ARRAY_SIZE) { dvander@212: // Character arrays are always dynamic when inferred from string literals. dvander@212: if (i == levels - 1 && contained->isChar()) dvander@212: dims[i] = DYNAMIC_ARRAY_SIZE; dvander@212: else dvander@212: dims[i] = lit->expressions()->length(); dvander@212: } dvander@212: dvander@212: if (i != levels - 1) { dvander@212: // Fixed array literals are guaranteed to have at least one expression. dvander@212: Expression *next = lit->expressions()->at(0); dvander@212: if (!next->isArrayLiteral()) { dvander@212: // Whelp... this array is just malformed. Not the best error message dvander@212: // but whatever. dvander@212: cc_.reportError(next->pos(), Message_ArraySizeCannotBeDetermined); dvander@212: return false; dvander@212: } dvander@212: lit = next->toArrayLiteral(); dvander@212: } dvander@212: } dvander@212: dvander@212: return true; dvander@212: } dvander@212: dvander@241: ArrayType *buildArrayType(Handle contained, TypeQualifiers quals, int dims[MAX_ARRAY_DEPTH], size_t postlevels) { dvander@212: Local type(zone_, contained); dvander@241: dvander@212: for (size_t i = postlevels - 1; i < postlevels; i--) { dvander@212: int size = dims[i] > 0 dvander@212: ? dims[i] dvander@212: : ArrayType::DYNAMIC_ARRAY_SIZE; dvander@212: dvander@241: if ((type = zone_->types()->newArray(contained, size)) == NULL) dvander@241: return NULL; dvander@241: if ((type = zone_->types()->qualify(type, quals)) == NULL) dvander@212: return NULL; dvander@212: } dvander@212: return ArrayType::cast(type); dvander@212: } dvander@212: dvander@195: bool fillFunctionType(Handle fun, const FunctionSignature &sig) { dvander@195: Local type(zone_); dvander@195: if (!fun->returnType()) { dvander@241: if ((type = bindType(sig.returnType(), TypeQual_None)) == NULL) dvander@195: return false; dvander@195: fun->setReturnType(type); dvander@195: } dvander@195: dvander@195: Local params(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old)); dvander@195: if (!params) dvander@195: return false; dvander@195: dvander@195: for (size_t i = 0; i < sig.parameters()->length(); i++) { dvander@195: Parameter *param = sig.parameters()->at(i); dvander@241: if ((type = bindType(param->type(), param->quals())) == NULL) dvander@195: return false; dvander@220: dvander@241: assert(!type->isArray()); dvander@241: dvander@241: if (param->dims()) { dvander@220: int dims[MAX_ARRAY_DEPTH]; dvander@220: int levels = evaluateDimensions(param->pos(), type, param->dims(), dims); dvander@220: if (levels < 0) dvander@220: return false; dvander@220: dvander@220: // If we got extra dimensions, we need to build a new type. dvander@220: // Unlike variables, we do not infer anything about array dvander@220: // sizes from its default initializer. dvander@220: if (param->dims()) { dvander@241: if ((type = buildArrayType(type, param->quals(), dims, param->dims()->length())) == NULL) dvander@220: return false; dvander@220: } dvander@237: dvander@237: if (ArrayType::cast(type)->innermost()->isVoid()) { dvander@237: cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid); dvander@237: return false; dvander@237: } dvander@220: } dvander@220: dvander@224: if (param->reference()) { dvander@224: if (!type->isPod()) { dvander@224: cc_.reportError(param->pos(), Message_ArrayCantBeReference); dvander@224: return false; dvander@224: } dvander@241: if (param->quals() & TypeQual_Const) { dvander@241: cc_.reportError(param->pos(), Message_CannotConstReference); dvander@241: return false; dvander@241: } dvander@224: if ((type = zone_->types()->getReference(type, false)) == NULL) dvander@224: return false; dvander@224: } dvander@241: if (param->quals() & TypeQual_Const) { dvander@241: if (!type->isArray() && !type->isStruct()) { dvander@241: cc_.reportError(param->pos(), Message_InvalidConstOnFormal); dvander@241: return false; dvander@241: } dvander@241: } dvander@222: dvander@237: if (type->isVoid()) { dvander@237: cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid); dvander@237: return false; dvander@237: } dvander@237: dvander@195: params->set(zone_, i, type); dvander@220: param->sym()->setType(type); dvander@195: } dvander@195: dvander@195: fun->setParameterTypes(params); dvander@195: dvander@195: return true; dvander@195: } dvander@195: dvander@241: Type *bindType(Expression *expr, TypeQualifiers quals) { dvander@241: Local type(zone_); dvander@241: dvander@195: if (!expr) { dvander@195: // If no type was declared, we return int32. dvander@241: type = zone_->types()->getPrimitive(PrimitiveType_Int32); dvander@241: } else { dvander@241: expr->accept(this); dvander@195: dvander@241: NameProxy *proxy = expr->asNameProxy(); dvander@241: assert(proxy); dvander@195: dvander@241: Symbol *sym = proxy->sym(); dvander@241: if (!sym) dvander@241: return NULL; dvander@195: dvander@241: if (!sym->isType()) { dvander@241: cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars()); dvander@241: return NULL; dvander@241: } dvander@241: dvander@241: type = sym->type(); dvander@195: } dvander@195: dvander@241: return zone_->types()->qualify(type, quals); dvander@195: } dvander@195: dvander@195: private: dvander@195: Zone *zone_; dvander@195: PoolAllocator &pool_; dvander@195: CompileContext &cc_; dvander@195: TranslationUnit *unit_; dvander@195: AutoLinkScope *link_; dvander@195: }; dvander@85: dvander@85: bool dvander@195: ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit) dvander@85: { dvander@195: NameBinder binder(zone, cc, unit); dvander@195: return binder.bind(); dvander@85: }