Added global variable support.
1 /* vim: set ts=4 sw=4 tw=99 et:
3 * Copyright (C) 2012 David Anderson
5 * This file is part of JITCraft.
7 * JITCraft is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation, either version 3 of the License, or (at your option)
12 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with
17 * JITCraft. If not, see http://www.gnu.org/licenses/.
22 #include "TypeManager.h"
24 #include "CompileContext.h"
25 #include "Environments.h"
29 Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
32 maxContainedLocals_(0),
44 if (enclosing_ && !enclosing_->children_.append(this))
54 assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
55 enclosing_->children_.pop();
57 // OOM here is swallowed and checked after compilation.
58 // :TODO: make the above true.
59 for (size_t i = 0; i < children_.length(); i++)
60 enclosing_->children_.append(children_[i]);
64 Scope::unlinkIfEmpty()
74 Scope::localLookup(Handle<String> name)
76 for (size_t i = 0; i < names_.length(); i++) {
77 if (names_[i]->name() == name)
84 Scope::lookup(Handle<String> name)
86 for (Scope *scope = this; scope; scope = scope->enclosing()) {
87 if (BoundName *bound = scope->localLookup(name))
94 Scope::declareVariable(Handle<String> name, const SourcePosition &pos)
96 assert(!localLookup(name));
98 Variable *var = new (pool_) Variable(this, name, pos);
99 if (!names_.append(var))
105 Scope::declareArgument(Handle<String> name, const SourcePosition &pos)
107 assert(kind() == FUNCTION);
108 Variable *var = declareVariable(name, pos);
109 if (!names_.append(var))
111 if (!parameters_.append(var))
117 Scope::declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token)
119 assert(!localLookup(name));
120 assert(kind() == GLOBAL);
122 NamedFunction *fun = new (pool_) NamedFunction(this, name, pos, token);
123 if (!names_.append(fun))
129 Scope::declareEnum(Handle<String> name, const SourcePosition &pos)
131 NamedEnum *e = new (pool_) NamedEnum(this, name, pos);
132 if (!names_.append(e))
138 Scope::declareConstant(Handle<String> name, const SourcePosition &pos)
140 NamedConstant *constant = new (pool_) NamedConstant(this, name, pos);
141 if (!names_.append(constant))
147 Scope::allocateGlobals()
149 assert(kind() == GLOBAL);
151 for (size_t i = 0; i < children_.length(); i++) {
152 assert(children_[i]->kind() == FUNCTION);
153 children_[i]->allocate();
156 Local<Type> type(ZONE());
157 for (size_t i = 0; i < names_.length(); i++) {
158 BoundName *name = names_[i];
160 if (name->kind() == BoundName::FUNCTION) {
161 NamedFunction *fun = name->toNamedFunction();
163 fun->allocate(numNatives_++);
165 fun->allocate(numFunctions_++);
166 } else if (name->kind() == BoundName::VARIABLE) {
167 allocate(name->toVariable());
173 Scope::allocate(Variable *var)
175 if (!var->unallocated())
178 if (kind() == GLOBAL) {
179 var->allocate(Variable::ENVIRONMENT, envVars_.length());
180 envVars_.append(var);
182 var->allocate(Variable::STACK, maxContainedLocals_ + locals_);
190 maxContainedLocals_ = 0;
191 for (size_t i = 0; i < children_.length(); i++) {
192 Scope *scope = children_[i];
194 if (scope->maxContainedLocals() > maxContainedLocals_)
195 maxContainedLocals_ = scope->maxContainedLocals();
198 for (size_t i = 0; i < parameters_.length(); i++)
199 parameters_[i]->allocate(Variable::PARAMETER, i);
203 for (size_t i = 0; i < names_.length(); i++) {
204 if (names_[i]->kind() != BoundName::VARIABLE)
207 allocate(names_[i]->toVariable());
210 maxContainedLocals_ += locals_;
214 Scope::Bind(CompileContext &cc, ParseTree *tree)
216 Local<String> name(ZONE());
217 for (size_t i = 0; i < tree->unbound()->length(); i++) {
218 NameProxy *proxy = tree->unbound()->at(i);
219 name = proxy->name();
220 BoundName *binding = tree->scope()->lookup(name);
223 cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
227 // We only allow global functions to be late-bound.
228 if (binding->kind() != BoundName::FUNCTION ||
229 binding->scope()->kind() != Scope::GLOBAL)
231 cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
235 proxy->bind(binding);
241 Scope::Allocate(ParseTree *tree)
243 tree->scope()->allocateGlobals();
247 Scope::setUsesLifoHeap()
249 // Only one lifo slot is needed per scope.
253 // If the parent of this scope is the function scope, then this is the
254 // function's block scope, and the lifo slot is part of the Frame instead.
255 // Note we can get a function scope here if we're making a temporary in a
256 // function with no local variables.
257 if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
260 Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
264 Local<String> name(ZONE());
265 lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
266 lifoSlot_->setType(type);
270 Scope::createEnvironmentMap(Zone *zone)
272 return EnvironmentMap::New(zone, envVars_.length(), envVars_.buffer());