dvander@37: /* vim: set ts=4 sw=4 tw=99 et: dvander@37: * 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: #include "Scopes.h" dvander@12: #include "Zone.h" dvander@1: #include "Types.h" dvander@12: #include "TypeManager.h" dvander@54: #include "Strings.h" dvander@84: #include "CompileContext.h" dvander@85: #include "Environments.h" dvander@0: dvander@59: using namespace ke; dvander@0: dvander@0: Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing) dvander@0: : pool_(pool), dvander@0: locals_(0), dvander@0: maxContainedLocals_(0), dvander@12: numFunctions_(0), dvander@68: numNatives_(0), dvander@28: lifoSlot_(NULL), dvander@28: kind_(kind), dvander@28: enclosing_(enclosing) dvander@0: { dvander@0: } dvander@0: dvander@0: bool dvander@0: Scope::initialize() dvander@0: { dvander@58: if (enclosing_ && !enclosing_->children_.append(this)) dvander@58: return false; dvander@0: return true; dvander@0: } dvander@0: dvander@0: void dvander@0: Scope::unlink() dvander@0: { dvander@0: assert(empty()); dvander@0: dvander@58: assert(enclosing_->children_[enclosing_->children_.length() - 1] == this); dvander@58: enclosing_->children_.pop(); dvander@0: dvander@58: // OOM here is swallowed and checked after compilation. dvander@58: // :TODO: make the above true. dvander@58: for (size_t i = 0; i < children_.length(); i++) dvander@58: enclosing_->children_.append(children_[i]); dvander@0: } dvander@0: dvander@0: Scope * dvander@0: Scope::unlinkIfEmpty() dvander@0: { dvander@0: if (empty()) { dvander@0: unlink(); dvander@0: return NULL; dvander@0: } dvander@0: return this; dvander@0: } dvander@0: dvander@0: BoundName * dvander@54: Scope::localLookup(Handle name) dvander@0: { dvander@58: for (size_t i = 0; i < names_.length(); i++) { dvander@0: if (names_[i]->name() == name) dvander@0: return names_[i]; dvander@0: } dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: BoundName * dvander@54: Scope::lookup(Handle name) dvander@0: { dvander@0: for (Scope *scope = this; scope; scope = scope->enclosing()) { dvander@0: if (BoundName *bound = scope->localLookup(name)) dvander@0: return bound; dvander@0: } dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: Variable * dvander@54: Scope::declareVariable(Handle name, const SourcePosition &pos) dvander@0: { dvander@0: assert(!localLookup(name)); dvander@0: dvander@25: Variable *var = new (pool_) Variable(this, name, pos); dvander@58: if (!names_.append(var)) dvander@58: return NULL; dvander@0: return var; dvander@0: } dvander@0: dvander@0: Variable * dvander@54: Scope::declareArgument(Handle name, const SourcePosition &pos) dvander@0: { dvander@0: assert(kind() == FUNCTION); dvander@25: Variable *var = declareVariable(name, pos); dvander@58: if (!names_.append(var)) dvander@58: return NULL; dvander@58: if (!parameters_.append(var)) dvander@58: return NULL; dvander@0: return var; dvander@0: } dvander@0: dvander@0: NamedFunction * dvander@63: Scope::declareFunction(Handle name, const SourcePosition &pos, TokenKind token) dvander@0: { dvander@0: assert(!localLookup(name)); dvander@2: assert(kind() == GLOBAL); dvander@0: dvander@63: NamedFunction *fun = new (pool_) NamedFunction(this, name, pos, token); dvander@58: if (!names_.append(fun)) dvander@58: return NULL; dvander@0: return fun; dvander@0: } dvander@0: dvander@2: NamedEnum * dvander@54: Scope::declareEnum(Handle name, const SourcePosition &pos) dvander@2: { dvander@25: NamedEnum *e = new (pool_) NamedEnum(this, name, pos); dvander@58: if (!names_.append(e)) dvander@58: return NULL; dvander@2: return e; dvander@2: } dvander@2: dvander@2: NamedConstant * dvander@54: Scope::declareConstant(Handle name, const SourcePosition &pos) dvander@2: { dvander@25: NamedConstant *constant = new (pool_) NamedConstant(this, name, pos); dvander@58: if (!names_.append(constant)) dvander@58: return NULL; dvander@2: return constant; dvander@2: } dvander@2: dvander@0: void dvander@0: Scope::allocateGlobals() dvander@0: { dvander@0: assert(kind() == GLOBAL); dvander@0: dvander@58: for (size_t i = 0; i < children_.length(); i++) { dvander@0: assert(children_[i]->kind() == FUNCTION); dvander@0: children_[i]->allocate(); dvander@0: } dvander@0: dvander@85: Local type(ZONE()); dvander@58: for (size_t i = 0; i < names_.length(); i++) { dvander@0: BoundName *name = names_[i]; dvander@0: dvander@28: if (name->kind() == BoundName::FUNCTION) { dvander@2: NamedFunction *fun = name->toNamedFunction(); dvander@68: if (fun->isNative()) dvander@68: fun->allocate(numNatives_++); dvander@68: else dvander@68: fun->allocate(numFunctions_++); dvander@85: } else if (name->kind() == BoundName::VARIABLE) { dvander@85: allocate(name->toVariable()); dvander@2: } dvander@0: } dvander@0: } dvander@0: dvander@0: void dvander@12: Scope::allocate(Variable *var) dvander@12: { dvander@12: if (!var->unallocated()) dvander@12: return; dvander@12: dvander@85: if (kind() == GLOBAL) { dvander@85: var->allocate(Variable::ENVIRONMENT, envVars_.length()); dvander@85: envVars_.append(var); dvander@85: } else { dvander@85: var->allocate(Variable::STACK, maxContainedLocals_ + locals_); dvander@85: locals_++; dvander@85: } dvander@12: } dvander@12: dvander@12: void dvander@0: Scope::allocate() dvander@0: { dvander@0: maxContainedLocals_ = 0; dvander@58: for (size_t i = 0; i < children_.length(); i++) { dvander@0: Scope *scope = children_[i]; dvander@0: scope->allocate(); dvander@0: if (scope->maxContainedLocals() > maxContainedLocals_) dvander@0: maxContainedLocals_ = scope->maxContainedLocals(); dvander@0: } dvander@0: dvander@58: for (size_t i = 0; i < parameters_.length(); i++) dvander@0: parameters_[i]->allocate(Variable::PARAMETER, i); dvander@0: dvander@12: if (lifoSlot_) dvander@12: allocate(lifoSlot_); dvander@58: for (size_t i = 0; i < names_.length(); i++) { dvander@2: if (names_[i]->kind() != BoundName::VARIABLE) dvander@2: continue; dvander@0: dvander@12: allocate(names_[i]->toVariable()); dvander@0: } dvander@0: dvander@0: maxContainedLocals_ += locals_; dvander@0: } dvander@0: dvander@0: bool dvander@84: Scope::Bind(CompileContext &cc, ParseTree *tree) dvander@0: { dvander@54: Local name(ZONE()); dvander@57: for (size_t i = 0; i < tree->unbound()->length(); i++) { dvander@0: NameProxy *proxy = tree->unbound()->at(i); dvander@54: name = proxy->name(); dvander@54: BoundName *binding = tree->scope()->lookup(name); dvander@84: dvander@54: if (!binding) { dvander@84: cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars()); dvander@84: return false; dvander@84: } dvander@84: dvander@84: // We only allow global functions to be late-bound. dvander@84: if (binding->kind() != BoundName::FUNCTION || dvander@84: binding->scope()->kind() != Scope::GLOBAL) dvander@84: { dvander@84: cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars()); dvander@0: return false; dvander@2: } dvander@0: dvander@54: proxy->bind(binding); dvander@0: } dvander@0: return true; dvander@0: } dvander@1: dvander@12: void dvander@12: Scope::Allocate(ParseTree *tree) dvander@12: { dvander@12: tree->scope()->allocateGlobals(); dvander@12: } dvander@12: dvander@12: void dvander@12: Scope::setUsesLifoHeap() dvander@1: { dvander@12: // Only one lifo slot is needed per scope. dvander@12: if (lifoSlot_) dvander@12: return; dvander@12: dvander@12: // If the parent of this scope is the function scope, then this is the dvander@12: // function's block scope, and the lifo slot is part of the Frame instead. dvander@16: // Note we can get a function scope here if we're making a temporary in a dvander@16: // function with no local variables. dvander@16: if (kind() == FUNCTION || enclosing()->kind() == FUNCTION) dvander@12: return; dvander@12: dvander@37: Local type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native)); dvander@37: if (!type) dvander@37: return; dvander@37: dvander@54: Local name(ZONE()); dvander@54: lifoSlot_ = new (pool_) Variable(this, name, SourcePosition()); dvander@37: lifoSlot_->setType(type); dvander@1: } dvander@85: dvander@85: EnvironmentMap * dvander@85: Scope::createEnvironmentMap(Zone *zone) dvander@85: { dvander@85: return EnvironmentMap::New(zone, envVars_.length(), envVars_.buffer()); dvander@85: }