Normalise line endings.
authorAsher Baker <asherkin@gmail.com>
Mon Jun 10 01:04:43 2013 +0100 (2013-06-10)
changeset 263ba85a47ee414
parent 262 c4b1341297e5
child 264 70b8f318c379
Normalise line endings.
jitcraft.sln
product.version
src/Array.cpp
src/Array.h
src/Code.h
src/CompactBuffer.h
src/Environments.cpp
src/Environments.h
src/Exception.cpp
src/FixedArray.cpp
src/FixedArray.h
src/Functions.cpp
src/Functions.h
src/Interpreter.cpp
src/Interpreter.h
src/Messages.h
src/Modules.cpp
src/Modules.h
src/NativeTable.cpp
src/NativeTable.h
src/OldByCo.cpp
src/OldByCo.h
src/OldSema.cpp
src/OldSema.h
src/Opcodes.cpp
src/Opcodes.h
src/Packages.cpp
src/Packages.h
src/PoolAllocator.cpp
src/PoolAllocator.h
src/Reference.cpp
src/Reference.h
src/RootScopes.h
src/Stack.h
src/StringPool.cpp
src/StringPool.h
src/Strings.cpp
src/Strings.h
src/Structures.cpp
src/Structures.h
src/TypeManager.cpp
src/TypeManager.h
src/Types.cpp
src/Zone.cpp
src/Zone.h
src/compiler/AST.h
src/compiler/BytecodeEmitter.cpp
src/compiler/BytecodeEmitter.h
src/compiler/CompileContext.h
src/compiler/ConstantEvaluator.cpp
src/compiler/ConstantEvaluator.h
src/compiler/HIR.cpp
src/compiler/HIR.h
src/compiler/NameBinding.cpp
src/compiler/NameBinding.h
src/compiler/Parser.cpp
src/compiler/Parser.h
src/compiler/Scanner.cpp
src/compiler/Scanner.h
src/compiler/Scopes.cpp
src/compiler/Scopes.h
src/compiler/SemanticAnalysis.cpp
src/compiler/SemanticAnalysis.h
src/compiler/Symbols.cpp
src/compiler/Symbols.h
src/compiler/Token.h
tests/basic/assignadd.out
tests/basic/assignadd.sp
tests/basic/bitops.out
tests/basic/bitops.sp
tests/basic/break-continue-in-for.out
tests/basic/break-continue-in-for.sp
tests/basic/const-arg-1.err
tests/basic/const-arg-1.sp
tests/basic/const-arg-2.err
tests/basic/const-arg-2.sp
tests/basic/const-arg-3.err
tests/basic/const-arg-3.sp
tests/basic/const-arg-4.err
tests/basic/const-arg-4.sp
tests/basic/const-arg-5.out
tests/basic/const-arg-5.sp
tests/basic/const-global-1.err
tests/basic/const-global-1.sp
tests/basic/const-global-2.err
tests/basic/const-global-2.sp
tests/basic/const-global-3.err
tests/basic/const-global-3.sp
tests/basic/const-local-1.err
tests/basic/const-local-1.sp
tests/basic/const-local-2.err
tests/basic/const-local-2.sp
tests/basic/const-local-3.out
tests/basic/const-local-3.sp
tests/basic/continue-in-while.out
tests/basic/continue-in-while.sp
tests/basic/decl-void.err
tests/basic/decl-void.sp
tests/basic/dependent-strings.out
tests/basic/dependent-strings.sp
tests/basic/divide-by-zero.err
tests/basic/divide-by-zero.sp
tests/basic/do.out
tests/basic/do.sp
tests/basic/enum-bad.err
tests/basic/enum-bad.sp
tests/basic/enum-redecl.err
tests/basic/enum-redecl.sp
tests/basic/enum-use.out
tests/basic/enum-use.sp
tests/basic/float-arrays.out
tests/basic/float-arrays.sp
tests/basic/floats.out
tests/basic/floats.sp
tests/basic/import-sysroot-all.out
tests/basic/import-sysroot-all.sp
tests/basic/import-sysroot-module.out
tests/basic/import-sysroot-module.sp
tests/basic/import-sysroot-select.out
tests/basic/import-sysroot-select.sp
tests/basic/import_enum_a.out
tests/basic/import_enum_a.sp
tests/basic/import_enum_b.sp
tests/basic/passarray.out
tests/basic/passarray.sp
tests/basic/postinc-array.out
tests/basic/postinc-array.sp
tests/basic/postinc-local.out
tests/basic/postinc-local.sp
tests/basic/postinc-ref.out
tests/basic/postinc-ref.sp
tests/basic/precall-void-used.out
tests/basic/precall-void-used.sp
tests/basic/preinc-array.out
tests/basic/preinc-array.sp
tests/basic/preinc-local.out
tests/basic/preinc-local.sp
tests/basic/preinc-ref.out
tests/basic/preinc-ref.sp
tests/basic/recursive_import_1_a.out
tests/basic/recursive_import_1_a.sp
tests/basic/recursive_import_1_b.sp
tests/basic/ref-arg.out
tests/basic/ref-arg.sp
tests/basic/ref-expr.out
tests/basic/ref-expr.sp
tests/basic/ref-var.out
tests/basic/ref-var.sp
tests/basic/return-analyze-for-1.sp
tests/basic/return-analyze-for-2.out
tests/basic/return-analyze-for-2.sp
tests/basic/return-analyze-for-3.err
tests/basic/return-analyze-for-3.sp
tests/basic/return-analyze-for-4.err
tests/basic/return-analyze-for-4.sp
tests/basic/return-analyze-for-5.out
tests/basic/return-analyze-for-5.sp
tests/basic/return-analyze-if-1.out
tests/basic/return-analyze-if-1.sp
tests/basic/return-analyze-if-2.err
tests/basic/return-analyze-if-2.sp
tests/basic/return-analyze-if-3.out
tests/basic/return-analyze-if-3.sp
tests/basic/return-analyze-if-4.err
tests/basic/return-analyze-if-4.sp
tests/basic/return-analyze-if-5.out
tests/basic/return-analyze-if-5.sp
tests/basic/shell.sp
tests/basic/string-lit-1.out
tests/basic/string-lit-1.sp
tests/basic/string-lit-2.out
tests/basic/string-lit-2.sp
tests/basic/while.out
tests/basic/while.sp
tests/display.py
tests/harness.py
tests/prototype/string-1.sp
tests/ref-array.sp
tests/test.py
     1.1 --- a/jitcraft.sln	Mon Jun 10 00:46:29 2013 +0100
     1.2 +++ b/jitcraft.sln	Mon Jun 10 01:04:43 2013 +0100
     1.3 @@ -1,23 +1,23 @@
     1.4 -
     1.5 -Microsoft Visual Studio Solution File, Format Version 11.00
     1.6 -# Visual C++ Express 2010
     1.7 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jitcraft", "src\jitcraft.vcxproj", "{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}"
     1.8 -EndProject
     1.9 -Global
    1.10 -	GlobalSection(SolutionConfigurationPlatforms) = preSolution
    1.11 -		Debug - Library|Win32 = Debug - Library|Win32
    1.12 -		Debug|Win32 = Debug|Win32
    1.13 -		Release|Win32 = Release|Win32
    1.14 -	EndGlobalSection
    1.15 -	GlobalSection(ProjectConfigurationPlatforms) = postSolution
    1.16 -		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug - Library|Win32.ActiveCfg = Debug - Library|Win32
    1.17 -		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug - Library|Win32.Build.0 = Debug - Library|Win32
    1.18 -		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug|Win32.ActiveCfg = Debug|Win32
    1.19 -		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug|Win32.Build.0 = Debug|Win32
    1.20 -		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Release|Win32.ActiveCfg = Release|Win32
    1.21 -		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Release|Win32.Build.0 = Release|Win32
    1.22 -	EndGlobalSection
    1.23 -	GlobalSection(SolutionProperties) = preSolution
    1.24 -		HideSolutionNode = FALSE
    1.25 -	EndGlobalSection
    1.26 -EndGlobal
    1.27 +
    1.28 +Microsoft Visual Studio Solution File, Format Version 11.00
    1.29 +# Visual C++ Express 2010
    1.30 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jitcraft", "src\jitcraft.vcxproj", "{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}"
    1.31 +EndProject
    1.32 +Global
    1.33 +	GlobalSection(SolutionConfigurationPlatforms) = preSolution
    1.34 +		Debug - Library|Win32 = Debug - Library|Win32
    1.35 +		Debug|Win32 = Debug|Win32
    1.36 +		Release|Win32 = Release|Win32
    1.37 +	EndGlobalSection
    1.38 +	GlobalSection(ProjectConfigurationPlatforms) = postSolution
    1.39 +		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug - Library|Win32.ActiveCfg = Debug - Library|Win32
    1.40 +		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug - Library|Win32.Build.0 = Debug - Library|Win32
    1.41 +		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug|Win32.ActiveCfg = Debug|Win32
    1.42 +		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug|Win32.Build.0 = Debug|Win32
    1.43 +		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Release|Win32.ActiveCfg = Release|Win32
    1.44 +		{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Release|Win32.Build.0 = Release|Win32
    1.45 +	EndGlobalSection
    1.46 +	GlobalSection(SolutionProperties) = preSolution
    1.47 +		HideSolutionNode = FALSE
    1.48 +	EndGlobalSection
    1.49 +EndGlobal
     2.1 --- a/product.version	Mon Jun 10 00:46:29 2013 +0100
     2.2 +++ b/product.version	Mon Jun 10 01:04:43 2013 +0100
     2.3 @@ -1,1 +1,1 @@
     2.4 -0.0.2-alpha
     2.5 +0.0.2-alpha
     3.1 --- a/src/Array.cpp	Mon Jun 10 00:46:29 2013 +0100
     3.2 +++ b/src/Array.cpp	Mon Jun 10 01:04:43 2013 +0100
     3.3 @@ -1,378 +1,378 @@
     3.4 -/* vim: set ts=4 sw=4 tw=99 et:
     3.5 - *
     3.6 - * Copyright (C) 2012 David Anderson
     3.7 - *
     3.8 - * This file is part of SourcePawn.
     3.9 - *
    3.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
    3.11 - * the terms of the GNU General Public License as published by the Free
    3.12 - * Software Foundation, either version 3 of the License, or (at your option)
    3.13 - * any later version.
    3.14 - * 
    3.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    3.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    3.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    3.18 - *
    3.19 - * You should have received a copy of the GNU General Public License along with
    3.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
    3.21 - */
    3.22 -#include <string.h>
    3.23 -#include "Array.h"
    3.24 -#include "FixedArray.h"
    3.25 -#include "Heap.h"
    3.26 -#include "Zone.h"
    3.27 -#include "Structures.h"
    3.28 -#include "Heap-inl.h"
    3.29 -
    3.30 -using namespace ke;
    3.31 -
    3.32 -ArrayMap *
    3.33 -ArrayMap::New(Zone *zone, Handle<ArrayType> type)
    3.34 -{
    3.35 -    Local<Map> obj(zone, zone->allocateMap(MapKind_Array, sizeof(ArrayMap), MapKind_MetaArray));
    3.36 -    if (!obj)
    3.37 -        return NULL;
    3.38 -
    3.39 -    Local<ArrayMap> map(zone, ArrayMap::cast(obj));
    3.40 -    map->type_ = type;
    3.41 -    return map;
    3.42 -}
    3.43 -
    3.44 -ArrayMap *
    3.45 -ArrayMap::NewDependent(Zone *zone, Handle<ArrayType> type)
    3.46 -{
    3.47 -    Local<Map> obj(zone, zone->allocateMap(MapKind_DependentArray, sizeof(ArrayMap), MapKind_MetaArray));
    3.48 -    if (!obj)
    3.49 -        return NULL;
    3.50 -
    3.51 -    Local<ArrayMap> map(zone, ArrayMap::cast(obj));
    3.52 -    map->type_ = type;
    3.53 -    return map;
    3.54 -}
    3.55 -
    3.56 -Array *
    3.57 -Array::NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure)
    3.58 -{
    3.59 -    assert(!map->type()->isFixedLength() || nelements == map->type()->fixedLength());
    3.60 -
    3.61 -    if (nelements > (INT_MAX / SizeForElement(map->type()))) {
    3.62 -        zone->reportError(Message_ArraySizeTooBig);
    3.63 -        return NULL;
    3.64 -    }
    3.65 -
    3.66 -    size_t bytes = sizeof(Array);
    3.67 -    if (map->type()->hasInlineElements())
    3.68 -        bytes += SizeForElement(map->type()) * nelements;
    3.69 -
    3.70 -    Local<Array> array(zone, Array::cast(zone->allocate(map, bytes, tenure)));
    3.71 -    if (!array)
    3.72 -        return NULL;
    3.73 -
    3.74 -    array->length_ = 0;
    3.75 -    array->elements_ = NULL;
    3.76 -
    3.77 -    if (map->type()->hasInlineElements()) {
    3.78 -        // This must be a fixed array containing no traceables.
    3.79 -        assert(nelements > 0);
    3.80 -        assert(map->type()->isFixedLength());
    3.81 -        assert(!map->type()->contained()->isTraceable());
    3.82 -
    3.83 -        // Compute an interior |elements_| pointer, such that if elements_
    3.84 -        // is accessed like a FixedArray, we reach the appropriate vector.
    3.85 -        array->elements_ = Address((Array *)array + 1) - ByteArray::offsetToElements();
    3.86 -        array->length_ = nelements;
    3.87 -        memset(array->bytes(), 0, SizeForElement(map->type()) * nelements);
    3.88 -        return array;
    3.89 -    }
    3.90 -
    3.91 -    // If there is nothing to allocate, we don't bother creating elements yet.
    3.92 -    if (!nelements)
    3.93 -        return array;
    3.94 -
    3.95 -    if (!map->type()->contained()->isTraceable()) {
    3.96 -        size_t nbytes = SizeForElement(map->type()) * nelements;
    3.97 -        Local<ByteArray> elements(zone, ByteArray::New(zone, nbytes, tenure));
    3.98 -        if (!elements)
    3.99 -            return NULL;
   3.100 -
   3.101 -        array->updateLengthAndElements(zone, nelements, elements);
   3.102 -        return array;
   3.103 -    }
   3.104 -
   3.105 -    Local<FixedArray> elements(zone, FixedArray::New(zone, nelements, tenure));
   3.106 -    if (!elements)
   3.107 -        return NULL;
   3.108 -
   3.109 -    array->updateLengthAndElements(zone, nelements, elements);
   3.110 -
   3.111 -    // If this is an array of structs, we're required to allocate those structs now.
   3.112 -    if (map->type()->contained()->isStruct()) {
   3.113 -        Local<StructType> childType(zone, StructType::cast(map->type()->contained()));
   3.114 -        Local<StructMap> childMap(zone, childType->newMap());
   3.115 -        Local<Struct> child(zone);
   3.116 -        for (unsigned i = 0; i < nelements; i++) {
   3.117 -            child = Struct::New(zone, childMap, tenure);
   3.118 -            if (!child)
   3.119 -                return NULL;
   3.120 -
   3.121 -            elements->set(zone, i, child);
   3.122 -        }
   3.123 -    }
   3.124 -
   3.125 -    return array;
   3.126 -}
   3.127 -
   3.128 -static Array *
   3.129 -ConstructSizedArray(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH],
   3.130 -                    unsigned level, Heap::Tenure tenure)
   3.131 -{
   3.132 -    Local<Array> array(zone, Array::NewRaw(zone, map, dims[level], tenure));
   3.133 -    if (!array)
   3.134 -        return NULL;
   3.135 -
   3.136 -    if (map->type()->contained()->isArray()) {
   3.137 -        Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
   3.138 -        Local<ArrayMap> childMap(zone, childType->newMap());
   3.139 -        Local<Array> child(zone);
   3.140 -
   3.141 -        for (unsigned i = 0; i < unsigned(dims[level]); i++) {
   3.142 -            child = ConstructSizedArray(zone, childMap, dims, level + 1, tenure);
   3.143 -            if (!child)
   3.144 -                return NULL;
   3.145 -
   3.146 -            array->writeObject(zone, i, child);
   3.147 -        }
   3.148 -    }
   3.149 -
   3.150 -    return array;
   3.151 -}
   3.152 -
   3.153 -Array *
   3.154 -Array::NewSized(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH], Heap::Tenure tenure)
   3.155 -{
   3.156 -    for (size_t i = 0; i < map->type()->levels(); i++) {
   3.157 -        if (dims[i] < 0) {
   3.158 -            zone->reportError(Message_InvalidDimensionSize, dims[i], i);
   3.159 -            return NULL;
   3.160 -        }
   3.161 -    }
   3.162 -
   3.163 -    return ConstructSizedArray(zone, map, dims, 0, tenure);
   3.164 -}
   3.165 -
   3.166 -static Array *
   3.167 -ConstructFixedArray(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   3.168 -{
   3.169 -    unsigned length = map->type()->fixedLength();
   3.170 -    Local<Array> array(zone, Array::NewRaw(zone, map, length, tenure));
   3.171 -    if (!array)
   3.172 -        return NULL;
   3.173 -
   3.174 -    if (map->type()->contained()->isArray()) {
   3.175 -        Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
   3.176 -        Local<ArrayMap> childMap(zone, childType->newMap());
   3.177 -        Local<Array> child(zone);
   3.178 -
   3.179 -        if (childMap->type()->isFixedLength()) {
   3.180 -            for (unsigned i = 0; i < length; i++) {
   3.181 -                child = ConstructFixedArray(zone, childMap, tenure);
   3.182 -                if (!child)
   3.183 -                    return NULL;
   3.184 -
   3.185 -                array->writeObject(zone, i, child);
   3.186 -            }
   3.187 -        } else {
   3.188 -            for (unsigned i = 0; i < length; i++) {
   3.189 -                child = Array::NewRaw(zone, childMap, 0, tenure);
   3.190 -                if (!child)
   3.191 -                    return NULL;
   3.192 -
   3.193 -                array->writeObject(zone, i, child);
   3.194 -            }
   3.195 -        }
   3.196 -    }
   3.197 -
   3.198 -    return array;
   3.199 -}
   3.200 -
   3.201 -Array *
   3.202 -Array::NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   3.203 -{
   3.204 -    return ConstructFixedArray(zone, map, tenure);
   3.205 -}
   3.206 -
   3.207 -Array *
   3.208 -Array::NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure tenure)
   3.209 -{
   3.210 -    assert(map->type()->isCharArray());
   3.211 -
   3.212 -    Local<Array> array(zone);
   3.213 -    
   3.214 -    if (map->type()->isFixedLength())
   3.215 -        array = Array::NewFixed(zone, map, tenure);
   3.216 -    else
   3.217 -        array = Array::New1D(zone, map, length + 1, tenure);
   3.218 -    if (!array)
   3.219 -        return NULL;
   3.220 -
   3.221 -    assert(array->length() >= length + 1);
   3.222 -    memcpy(array->chars(), buffer, length + 1);
   3.223 -    return array;
   3.224 -}
   3.225 -
   3.226 -Array *
   3.227 -Array::New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure)
   3.228 -{
   3.229 -    assert(map->type()->levels());
   3.230 -    return Array::NewRaw(zone, map, elements, tenure);
   3.231 -}
   3.232 -
   3.233 -Array *
   3.234 -Array::NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   3.235 -{
   3.236 -    assert(!map->type()->isFixedLength());
   3.237 -
   3.238 -    return Array::NewRaw(zone, map, 0, tenure);
   3.239 -}
   3.240 -
   3.241 -Array *
   3.242 -Array::NewExternal(Zone *zone, Handle<ArrayMap> map, void *buffer, unsigned length,
   3.243 -                   Heap::Tenure tenure)
   3.244 -{
   3.245 -    Local<Array> array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure)));
   3.246 -    if (!array)
   3.247 -        return NULL;
   3.248 -
   3.249 -    array->length_ = length;
   3.250 -    array->elements_ = Address(buffer) - ByteArray::offsetToElements();
   3.251 -    return array;
   3.252 -}
   3.253 -
   3.254 -static bool
   3.255 -CopyArrayElements(Zone *zone, Handle<Type> contained, Handle<Array> dest, Handle<Array> source)
   3.256 -{
   3.257 -    if (contained->isTraceable()) {
   3.258 -        if (contained->isStruct()) {
   3.259 -            assert(dest->type()->contained() == contained);
   3.260 -            assert(source->length() == dest->length());
   3.261 -
   3.262 -            Local<Struct> left(zone);
   3.263 -            Local<Struct> right(zone);
   3.264 -            for (unsigned i = 0; i < source->length(); i++) {
   3.265 -                left = Struct::cast(dest->readObject(i));
   3.266 -                right = Struct::cast(source->readObject(i));
   3.267 -                if (!Struct::Copy(zone, left, right))
   3.268 -                    return false;
   3.269 -            }
   3.270 -        } else if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) {
   3.271 -            assert(ArrayType::cast(source->type())->fixedLength() ==
   3.272 -                   ArrayType::cast(contained)->fixedLength());
   3.273 -
   3.274 -            Local<Array> left(zone);
   3.275 -            Local<Array> right(zone);
   3.276 -            for (unsigned i = 0; i < source->length(); i++) {
   3.277 -                left = Array::cast(dest->readObject(i));
   3.278 -                right = Array::cast(source->readObject(i));
   3.279 -                if (!Array::ShallowCopy(zone, left, right))
   3.280 -                    return false;
   3.281 -            }
   3.282 -        } else {
   3.283 -            assert(dest->length() == source->length());
   3.284 -            for (unsigned i = 0; i < source->length(); i++)
   3.285 -                dest->writeObject(zone, i, source->readObject(i));
   3.286 -        }
   3.287 -    } else {
   3.288 -        assert(contained->pod() == dest->type()->contained()->pod());
   3.289 -        assert(contained->pod() == PrimitiveType_Char
   3.290 -               ? source->length() <= dest->length()
   3.291 -               : source->length() == dest->length());
   3.292 -    
   3.293 -        assert(dest->length());
   3.294 -        memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
   3.295 -    }
   3.296 -    return true;
   3.297 -}
   3.298 -
   3.299 -// Shallow copy an array. Fixed slots in the destination are copied from
   3.300 -// the source, but otherwise, references are assigned.
   3.301 -bool
   3.302 -Array::ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source)
   3.303 -{
   3.304 -    Local<Type> contained(zone, dest->type()->contained());
   3.305 -
   3.306 -    return CopyArrayElements(zone, contained, dest, source);
   3.307 -}
   3.308 -
   3.309 -Array *
   3.310 -Array::DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure)
   3.311 -{
   3.312 -    Local<ArrayMap> map(zone, ArrayMap::cast(source->map()));
   3.313 -
   3.314 -    Local<Array> dest(zone, Array::NewRaw(zone, map, source->length(), tenure));
   3.315 -    if (!dest)
   3.316 -        return NULL;
   3.317 -
   3.318 -    Local<Type> contained(zone, source->type()->contained());
   3.319 -    if (contained->isArray()) {
   3.320 -        assert(false);
   3.321 -        Local<Array> sub(zone);
   3.322 -        for (size_t i = 0; i < source->length(); i++) {
   3.323 -            sub = Array::cast(source->readObject(i));
   3.324 -            sub = DeepCopy(zone, sub, tenure);
   3.325 -            if (!sub)
   3.326 -                return NULL;
   3.327 -            dest->writeObject(zone, i, sub);
   3.328 -        }
   3.329 -    } else {
   3.330 -        if (!CopyArrayElements(zone, contained, dest, source))
   3.331 -            return NULL;
   3.332 -    }
   3.333 -
   3.334 -    return dest;
   3.335 -}
   3.336 -
   3.337 -Array *
   3.338 -DependentArray::New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index)
   3.339 -{
   3.340 -    Local<ArrayType> sourcetype(zone, source->type());
   3.341 -
   3.342 -    // Right now we only support char arrays, to avoid nasty deep cloning
   3.343 -    // and to maybe cut off this feature as far as we can.
   3.344 -    assert(sourcetype->isCharArray());
   3.345 -    assert(map->type()->isCharArray());
   3.346 -
   3.347 -    // We allow taking 0-length dependent strings. It's safe because any reads
   3.348 -    // or writes will fail.
   3.349 -    assert(index <= source->length());
   3.350 -
   3.351 -    unsigned newlen = source->length() - index;
   3.352 -    unsigned eltsize = SizeForElement(sourcetype);
   3.353 -    
   3.354 -    if (!sourcetype->isFixedLength()) {
   3.355 -        // Simple case, just copy the array.
   3.356 -        Local<ArrayMap> map(zone, sourcetype->newMap());
   3.357 -        
   3.358 -        Local<Array> dest(zone, Array::NewRaw(zone, map, newlen, Heap::Tenure_Default));
   3.359 -        if (!dest)
   3.360 -            return NULL;
   3.361 -
   3.362 -        memcpy(dest->bytes(),
   3.363 -               (Address)source->bytes() + (index * eltsize),
   3.364 -               newlen * eltsize);
   3.365 -        return dest;
   3.366 -    }
   3.367 -
   3.368 -    Local<DependentArray> array(zone, DependentArray::cast(zone->allocate(map, sizeof(DependentArray), Heap::Tenure_Default)));
   3.369 -    if (!array)
   3.370 -        return NULL;
   3.371 -
   3.372 -    // :GC: This is currently not safe for moving GC! Although we will mark
   3.373 -    // the object owning the interior pointer, the interior pointer could be
   3.374 -    // moved later. We will eventually need some way of dealing with this.
   3.375 -    Address elements = Address(source->bytes()) + (index * eltsize);
   3.376 -
   3.377 -    array->root_ = source;
   3.378 -    array->length_ = newlen;
   3.379 -    array->elements_ = elements - ByteArray::offsetToElements();
   3.380 -    return array;
   3.381 -}
   3.382 +/* vim: set ts=4 sw=4 tw=99 et:
   3.383 + *
   3.384 + * Copyright (C) 2012 David Anderson
   3.385 + *
   3.386 + * This file is part of SourcePawn.
   3.387 + *
   3.388 + * SourcePawn is free software: you can redistribute it and/or modify it under
   3.389 + * the terms of the GNU General Public License as published by the Free
   3.390 + * Software Foundation, either version 3 of the License, or (at your option)
   3.391 + * any later version.
   3.392 + * 
   3.393 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   3.394 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   3.395 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   3.396 + *
   3.397 + * You should have received a copy of the GNU General Public License along with
   3.398 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   3.399 + */
   3.400 +#include <string.h>
   3.401 +#include "Array.h"
   3.402 +#include "FixedArray.h"
   3.403 +#include "Heap.h"
   3.404 +#include "Zone.h"
   3.405 +#include "Structures.h"
   3.406 +#include "Heap-inl.h"
   3.407 +
   3.408 +using namespace ke;
   3.409 +
   3.410 +ArrayMap *
   3.411 +ArrayMap::New(Zone *zone, Handle<ArrayType> type)
   3.412 +{
   3.413 +    Local<Map> obj(zone, zone->allocateMap(MapKind_Array, sizeof(ArrayMap), MapKind_MetaArray));
   3.414 +    if (!obj)
   3.415 +        return NULL;
   3.416 +
   3.417 +    Local<ArrayMap> map(zone, ArrayMap::cast(obj));
   3.418 +    map->type_ = type;
   3.419 +    return map;
   3.420 +}
   3.421 +
   3.422 +ArrayMap *
   3.423 +ArrayMap::NewDependent(Zone *zone, Handle<ArrayType> type)
   3.424 +{
   3.425 +    Local<Map> obj(zone, zone->allocateMap(MapKind_DependentArray, sizeof(ArrayMap), MapKind_MetaArray));
   3.426 +    if (!obj)
   3.427 +        return NULL;
   3.428 +
   3.429 +    Local<ArrayMap> map(zone, ArrayMap::cast(obj));
   3.430 +    map->type_ = type;
   3.431 +    return map;
   3.432 +}
   3.433 +
   3.434 +Array *
   3.435 +Array::NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure)
   3.436 +{
   3.437 +    assert(!map->type()->isFixedLength() || nelements == map->type()->fixedLength());
   3.438 +
   3.439 +    if (nelements > (INT_MAX / SizeForElement(map->type()))) {
   3.440 +        zone->reportError(Message_ArraySizeTooBig);
   3.441 +        return NULL;
   3.442 +    }
   3.443 +
   3.444 +    size_t bytes = sizeof(Array);
   3.445 +    if (map->type()->hasInlineElements())
   3.446 +        bytes += SizeForElement(map->type()) * nelements;
   3.447 +
   3.448 +    Local<Array> array(zone, Array::cast(zone->allocate(map, bytes, tenure)));
   3.449 +    if (!array)
   3.450 +        return NULL;
   3.451 +
   3.452 +    array->length_ = 0;
   3.453 +    array->elements_ = NULL;
   3.454 +
   3.455 +    if (map->type()->hasInlineElements()) {
   3.456 +        // This must be a fixed array containing no traceables.
   3.457 +        assert(nelements > 0);
   3.458 +        assert(map->type()->isFixedLength());
   3.459 +        assert(!map->type()->contained()->isTraceable());
   3.460 +
   3.461 +        // Compute an interior |elements_| pointer, such that if elements_
   3.462 +        // is accessed like a FixedArray, we reach the appropriate vector.
   3.463 +        array->elements_ = Address((Array *)array + 1) - ByteArray::offsetToElements();
   3.464 +        array->length_ = nelements;
   3.465 +        memset(array->bytes(), 0, SizeForElement(map->type()) * nelements);
   3.466 +        return array;
   3.467 +    }
   3.468 +
   3.469 +    // If there is nothing to allocate, we don't bother creating elements yet.
   3.470 +    if (!nelements)
   3.471 +        return array;
   3.472 +
   3.473 +    if (!map->type()->contained()->isTraceable()) {
   3.474 +        size_t nbytes = SizeForElement(map->type()) * nelements;
   3.475 +        Local<ByteArray> elements(zone, ByteArray::New(zone, nbytes, tenure));
   3.476 +        if (!elements)
   3.477 +            return NULL;
   3.478 +
   3.479 +        array->updateLengthAndElements(zone, nelements, elements);
   3.480 +        return array;
   3.481 +    }
   3.482 +
   3.483 +    Local<FixedArray> elements(zone, FixedArray::New(zone, nelements, tenure));
   3.484 +    if (!elements)
   3.485 +        return NULL;
   3.486 +
   3.487 +    array->updateLengthAndElements(zone, nelements, elements);
   3.488 +
   3.489 +    // If this is an array of structs, we're required to allocate those structs now.
   3.490 +    if (map->type()->contained()->isStruct()) {
   3.491 +        Local<StructType> childType(zone, StructType::cast(map->type()->contained()));
   3.492 +        Local<StructMap> childMap(zone, childType->newMap());
   3.493 +        Local<Struct> child(zone);
   3.494 +        for (unsigned i = 0; i < nelements; i++) {
   3.495 +            child = Struct::New(zone, childMap, tenure);
   3.496 +            if (!child)
   3.497 +                return NULL;
   3.498 +
   3.499 +            elements->set(zone, i, child);
   3.500 +        }
   3.501 +    }
   3.502 +
   3.503 +    return array;
   3.504 +}
   3.505 +
   3.506 +static Array *
   3.507 +ConstructSizedArray(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH],
   3.508 +                    unsigned level, Heap::Tenure tenure)
   3.509 +{
   3.510 +    Local<Array> array(zone, Array::NewRaw(zone, map, dims[level], tenure));
   3.511 +    if (!array)
   3.512 +        return NULL;
   3.513 +
   3.514 +    if (map->type()->contained()->isArray()) {
   3.515 +        Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
   3.516 +        Local<ArrayMap> childMap(zone, childType->newMap());
   3.517 +        Local<Array> child(zone);
   3.518 +
   3.519 +        for (unsigned i = 0; i < unsigned(dims[level]); i++) {
   3.520 +            child = ConstructSizedArray(zone, childMap, dims, level + 1, tenure);
   3.521 +            if (!child)
   3.522 +                return NULL;
   3.523 +
   3.524 +            array->writeObject(zone, i, child);
   3.525 +        }
   3.526 +    }
   3.527 +
   3.528 +    return array;
   3.529 +}
   3.530 +
   3.531 +Array *
   3.532 +Array::NewSized(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH], Heap::Tenure tenure)
   3.533 +{
   3.534 +    for (size_t i = 0; i < map->type()->levels(); i++) {
   3.535 +        if (dims[i] < 0) {
   3.536 +            zone->reportError(Message_InvalidDimensionSize, dims[i], i);
   3.537 +            return NULL;
   3.538 +        }
   3.539 +    }
   3.540 +
   3.541 +    return ConstructSizedArray(zone, map, dims, 0, tenure);
   3.542 +}
   3.543 +
   3.544 +static Array *
   3.545 +ConstructFixedArray(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   3.546 +{
   3.547 +    unsigned length = map->type()->fixedLength();
   3.548 +    Local<Array> array(zone, Array::NewRaw(zone, map, length, tenure));
   3.549 +    if (!array)
   3.550 +        return NULL;
   3.551 +
   3.552 +    if (map->type()->contained()->isArray()) {
   3.553 +        Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
   3.554 +        Local<ArrayMap> childMap(zone, childType->newMap());
   3.555 +        Local<Array> child(zone);
   3.556 +
   3.557 +        if (childMap->type()->isFixedLength()) {
   3.558 +            for (unsigned i = 0; i < length; i++) {
   3.559 +                child = ConstructFixedArray(zone, childMap, tenure);
   3.560 +                if (!child)
   3.561 +                    return NULL;
   3.562 +
   3.563 +                array->writeObject(zone, i, child);
   3.564 +            }
   3.565 +        } else {
   3.566 +            for (unsigned i = 0; i < length; i++) {
   3.567 +                child = Array::NewRaw(zone, childMap, 0, tenure);
   3.568 +                if (!child)
   3.569 +                    return NULL;
   3.570 +
   3.571 +                array->writeObject(zone, i, child);
   3.572 +            }
   3.573 +        }
   3.574 +    }
   3.575 +
   3.576 +    return array;
   3.577 +}
   3.578 +
   3.579 +Array *
   3.580 +Array::NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   3.581 +{
   3.582 +    return ConstructFixedArray(zone, map, tenure);
   3.583 +}
   3.584 +
   3.585 +Array *
   3.586 +Array::NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure tenure)
   3.587 +{
   3.588 +    assert(map->type()->isCharArray());
   3.589 +
   3.590 +    Local<Array> array(zone);
   3.591 +    
   3.592 +    if (map->type()->isFixedLength())
   3.593 +        array = Array::NewFixed(zone, map, tenure);
   3.594 +    else
   3.595 +        array = Array::New1D(zone, map, length + 1, tenure);
   3.596 +    if (!array)
   3.597 +        return NULL;
   3.598 +
   3.599 +    assert(array->length() >= length + 1);
   3.600 +    memcpy(array->chars(), buffer, length + 1);
   3.601 +    return array;
   3.602 +}
   3.603 +
   3.604 +Array *
   3.605 +Array::New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure)
   3.606 +{
   3.607 +    assert(map->type()->levels());
   3.608 +    return Array::NewRaw(zone, map, elements, tenure);
   3.609 +}
   3.610 +
   3.611 +Array *
   3.612 +Array::NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   3.613 +{
   3.614 +    assert(!map->type()->isFixedLength());
   3.615 +
   3.616 +    return Array::NewRaw(zone, map, 0, tenure);
   3.617 +}
   3.618 +
   3.619 +Array *
   3.620 +Array::NewExternal(Zone *zone, Handle<ArrayMap> map, void *buffer, unsigned length,
   3.621 +                   Heap::Tenure tenure)
   3.622 +{
   3.623 +    Local<Array> array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure)));
   3.624 +    if (!array)
   3.625 +        return NULL;
   3.626 +
   3.627 +    array->length_ = length;
   3.628 +    array->elements_ = Address(buffer) - ByteArray::offsetToElements();
   3.629 +    return array;
   3.630 +}
   3.631 +
   3.632 +static bool
   3.633 +CopyArrayElements(Zone *zone, Handle<Type> contained, Handle<Array> dest, Handle<Array> source)
   3.634 +{
   3.635 +    if (contained->isTraceable()) {
   3.636 +        if (contained->isStruct()) {
   3.637 +            assert(dest->type()->contained() == contained);
   3.638 +            assert(source->length() == dest->length());
   3.639 +
   3.640 +            Local<Struct> left(zone);
   3.641 +            Local<Struct> right(zone);
   3.642 +            for (unsigned i = 0; i < source->length(); i++) {
   3.643 +                left = Struct::cast(dest->readObject(i));
   3.644 +                right = Struct::cast(source->readObject(i));
   3.645 +                if (!Struct::Copy(zone, left, right))
   3.646 +                    return false;
   3.647 +            }
   3.648 +        } else if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) {
   3.649 +            assert(ArrayType::cast(source->type())->fixedLength() ==
   3.650 +                   ArrayType::cast(contained)->fixedLength());
   3.651 +
   3.652 +            Local<Array> left(zone);
   3.653 +            Local<Array> right(zone);
   3.654 +            for (unsigned i = 0; i < source->length(); i++) {
   3.655 +                left = Array::cast(dest->readObject(i));
   3.656 +                right = Array::cast(source->readObject(i));
   3.657 +                if (!Array::ShallowCopy(zone, left, right))
   3.658 +                    return false;
   3.659 +            }
   3.660 +        } else {
   3.661 +            assert(dest->length() == source->length());
   3.662 +            for (unsigned i = 0; i < source->length(); i++)
   3.663 +                dest->writeObject(zone, i, source->readObject(i));
   3.664 +        }
   3.665 +    } else {
   3.666 +        assert(contained->pod() == dest->type()->contained()->pod());
   3.667 +        assert(contained->pod() == PrimitiveType_Char
   3.668 +               ? source->length() <= dest->length()
   3.669 +               : source->length() == dest->length());
   3.670 +    
   3.671 +        assert(dest->length());
   3.672 +        memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
   3.673 +    }
   3.674 +    return true;
   3.675 +}
   3.676 +
   3.677 +// Shallow copy an array. Fixed slots in the destination are copied from
   3.678 +// the source, but otherwise, references are assigned.
   3.679 +bool
   3.680 +Array::ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source)
   3.681 +{
   3.682 +    Local<Type> contained(zone, dest->type()->contained());
   3.683 +
   3.684 +    return CopyArrayElements(zone, contained, dest, source);
   3.685 +}
   3.686 +
   3.687 +Array *
   3.688 +Array::DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure)
   3.689 +{
   3.690 +    Local<ArrayMap> map(zone, ArrayMap::cast(source->map()));
   3.691 +
   3.692 +    Local<Array> dest(zone, Array::NewRaw(zone, map, source->length(), tenure));
   3.693 +    if (!dest)
   3.694 +        return NULL;
   3.695 +
   3.696 +    Local<Type> contained(zone, source->type()->contained());
   3.697 +    if (contained->isArray()) {
   3.698 +        assert(false);
   3.699 +        Local<Array> sub(zone);
   3.700 +        for (size_t i = 0; i < source->length(); i++) {
   3.701 +            sub = Array::cast(source->readObject(i));
   3.702 +            sub = DeepCopy(zone, sub, tenure);
   3.703 +            if (!sub)
   3.704 +                return NULL;
   3.705 +            dest->writeObject(zone, i, sub);
   3.706 +        }
   3.707 +    } else {
   3.708 +        if (!CopyArrayElements(zone, contained, dest, source))
   3.709 +            return NULL;
   3.710 +    }
   3.711 +
   3.712 +    return dest;
   3.713 +}
   3.714 +
   3.715 +Array *
   3.716 +DependentArray::New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index)
   3.717 +{
   3.718 +    Local<ArrayType> sourcetype(zone, source->type());
   3.719 +
   3.720 +    // Right now we only support char arrays, to avoid nasty deep cloning
   3.721 +    // and to maybe cut off this feature as far as we can.
   3.722 +    assert(sourcetype->isCharArray());
   3.723 +    assert(map->type()->isCharArray());
   3.724 +
   3.725 +    // We allow taking 0-length dependent strings. It's safe because any reads
   3.726 +    // or writes will fail.
   3.727 +    assert(index <= source->length());
   3.728 +
   3.729 +    unsigned newlen = source->length() - index;
   3.730 +    unsigned eltsize = SizeForElement(sourcetype);
   3.731 +    
   3.732 +    if (!sourcetype->isFixedLength()) {
   3.733 +        // Simple case, just copy the array.
   3.734 +        Local<ArrayMap> map(zone, sourcetype->newMap());
   3.735 +        
   3.736 +        Local<Array> dest(zone, Array::NewRaw(zone, map, newlen, Heap::Tenure_Default));
   3.737 +        if (!dest)
   3.738 +            return NULL;
   3.739 +
   3.740 +        memcpy(dest->bytes(),
   3.741 +               (Address)source->bytes() + (index * eltsize),
   3.742 +               newlen * eltsize);
   3.743 +        return dest;
   3.744 +    }
   3.745 +
   3.746 +    Local<DependentArray> array(zone, DependentArray::cast(zone->allocate(map, sizeof(DependentArray), Heap::Tenure_Default)));
   3.747 +    if (!array)
   3.748 +        return NULL;
   3.749 +
   3.750 +    // :GC: This is currently not safe for moving GC! Although we will mark
   3.751 +    // the object owning the interior pointer, the interior pointer could be
   3.752 +    // moved later. We will eventually need some way of dealing with this.
   3.753 +    Address elements = Address(source->bytes()) + (index * eltsize);
   3.754 +
   3.755 +    array->root_ = source;
   3.756 +    array->length_ = newlen;
   3.757 +    array->elements_ = elements - ByteArray::offsetToElements();
   3.758 +    return array;
   3.759 +}
     4.1 --- a/src/Array.h	Mon Jun 10 00:46:29 2013 +0100
     4.2 +++ b/src/Array.h	Mon Jun 10 01:04:43 2013 +0100
     4.3 @@ -1,244 +1,244 @@
     4.4 -/* vim: set ts=4 sw=4 tw=99 et:
     4.5 - *
     4.6 - * Copyright (C) 2012 David Anderson
     4.7 - *
     4.8 - * This file is part of SourcePawn.
     4.9 - *
    4.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
    4.11 - * the terms of the GNU General Public License as published by the Free
    4.12 - * Software Foundation, either version 3 of the License, or (at your option)
    4.13 - * any later version.
    4.14 - * 
    4.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    4.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    4.18 - *
    4.19 - * You should have received a copy of the GNU General Public License along with
    4.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
    4.21 - */
    4.22 -#ifndef _include_jitcraft_array_h_
    4.23 -#define _include_jitcraft_array_h_
    4.24 -
    4.25 -#include "Heap.h"
    4.26 -#include "Handles.h"
    4.27 -#include "Types.h"
    4.28 -#include "FixedArray.h"
    4.29 -
    4.30 -namespace ke {
    4.31 -
    4.32 -class ArrayMap;
    4.33 -
    4.34 -class Array : public Object
    4.35 -{
    4.36 -    friend class ArrayMap;
    4.37 -
    4.38 -  protected:
    4.39 -    // Note: we do not write barrier |elements_|, since it can be set to
    4.40 -    // arbitrary pointers.
    4.41 -    uint32 length_;
    4.42 -    union {
    4.43 -        void *elements_;
    4.44 -        Object *objelements_;
    4.45 -    };
    4.46 -
    4.47 -  protected:
    4.48 -    void updateLengthAndElements(Zone *zone, unsigned length, Object *array) {
    4.49 -        length_ = length;
    4.50 -        write(zone, &objelements_, array);
    4.51 -    }
    4.52 -
    4.53 -  public:
    4.54 -    static Array *NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure = Heap::Tenure_Default);
    4.55 -    static Array *NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
    4.56 -    static Array *NewSized(Zone *zone, Handle<ArrayMap> map, int sizes[MAX_ARRAY_DEPTH], Heap::Tenure = Heap::Tenure_Default);
    4.57 -
    4.58 -    static Array *New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure = Heap::Tenure_Default);
    4.59 -    static Array *NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
    4.60 -    static Array *NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure);
    4.61 -
    4.62 -    static Array *NewExternal(Zone *zone,
    4.63 -                              Handle<ArrayMap> map,
    4.64 -                              void *buffer,
    4.65 -                              unsigned length,
    4.66 -                              Heap::Tenure tenure = Heap::Tenure_Default);
    4.67 -
    4.68 -    // Copies an array from one reference to another, obeying language semantics.
    4.69 -    static bool ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source);
    4.70 -
    4.71 -    // Creates a full duplicate of an array, following all array references as if
    4.72 -    // they were fixed. Array references inside structs or objects use ShallowCopy
    4.73 -    // semantics, as this is only intended for duplicating array literals, which
    4.74 -    // cannot contain structs.
    4.75 -    static Array *DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure);
    4.76 -
    4.77 -    uint32 length() {
    4.78 -        return length_;
    4.79 -    }
    4.80 -
    4.81 -    inline ArrayType *type();
    4.82 -
    4.83 -    inline int *int32Vec();
    4.84 -    inline float *floatVec();
    4.85 -    inline char *chars();
    4.86 -    inline void *bytes();
    4.87 -
    4.88 -    bool resize(Zone *zone, size_t newLength);
    4.89 -
    4.90 -    static inline size_t SizeForElement(ArrayType *type) {
    4.91 -        if (type->contained()->isTraceable())
    4.92 -            return sizeof(ke::Object *);
    4.93 -        if (type->contained()->isInt32())
    4.94 -            return sizeof(int);
    4.95 -        if (type->contained()->primitive() == PrimitiveType_Char)
    4.96 -            return sizeof(char);
    4.97 -        assert(type->contained()->isFloat());
    4.98 -        return sizeof(float);
    4.99 -    }
   4.100 -
   4.101 -    inline size_t objSize(ArrayMap *map);
   4.102 -
   4.103 -    int readInt32(size_t index) {
   4.104 -        assert(index < length());
   4.105 -        return int32Vec()[index];
   4.106 -    }
   4.107 -    void writeInt32(size_t index, int i) {
   4.108 -        assert(index < length());
   4.109 -        int32Vec()[index] = i;
   4.110 -    }
   4.111 -    char readChar(size_t index) {
   4.112 -        assert(index < length());
   4.113 -        return chars()[index];
   4.114 -    }
   4.115 -    void writeChar(size_t index, char c) {
   4.116 -        assert(index < length());
   4.117 -        chars()[index] = c;
   4.118 -    }
   4.119 -    float readFloat(size_t index) {
   4.120 -        assert(index < length());
   4.121 -        return floatVec()[index];
   4.122 -    }
   4.123 -    void writeFloat(size_t index, float f) {
   4.124 -        assert(index < length());
   4.125 -        floatVec()[index] = f;
   4.126 -    }
   4.127 -    Object *readObject(size_t index) {
   4.128 -        return FixedArray::cast(objelements_)->at(index);
   4.129 -    }
   4.130 -    void writeObject(Zone *zone, size_t index, Object *ptr) {
   4.131 -        FixedArray::cast(objelements_)->set(zone, index, ptr);
   4.132 -    }
   4.133 -
   4.134 -    // GC Descriptor.
   4.135 -    static inline size_t offsetOfElements() {
   4.136 -        return offsetof(Array, objelements_);
   4.137 -    }
   4.138 -    // End GC Descriptor.
   4.139 -
   4.140 -    static Array *cast(Object *obj) {
   4.141 -        assert(!obj ||
   4.142 -               obj->is(MapKind_Array) ||
   4.143 -               obj->is(MapKind_DependentArray));
   4.144 -        return reinterpret_cast<Array *>(obj);
   4.145 -    }
   4.146 -};
   4.147 -
   4.148 -class DependentArray : public Array
   4.149 -{
   4.150 -    Barriered<Array> root_;
   4.151 -
   4.152 -  public:
   4.153 -    static Array *New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index);
   4.154 -
   4.155 -    // GC Descriptor.
   4.156 -    static inline size_t offsetOfRoot() {
   4.157 -        return offsetof(DependentArray, root_);
   4.158 -    }
   4.159 -    // End GC Descriptor.
   4.160 -
   4.161 -    static DependentArray *cast(Object *obj) {
   4.162 -        assert(!obj || obj->is(MapKind_DependentArray));
   4.163 -        return reinterpret_cast<DependentArray *>(obj);
   4.164 -    }
   4.165 -};
   4.166 -
   4.167 -class ArrayMap : public Map
   4.168 -{
   4.169 -    Barriered<ArrayType> type_;
   4.170 -
   4.171 -  public:
   4.172 -    static ArrayMap *New(Zone *zone, Handle<ArrayType> type);
   4.173 -
   4.174 -    // DependentArray maps are never attached, and are just free-floating,
   4.175 -    // rooted ultimately by the bytecode. A :TODO: that we might need to
   4.176 -    // cache these, or attach them somewhere saner like ArrayType, which
   4.177 -    // itself will eventually be cached.
   4.178 -    static ArrayMap *NewDependent(Zone *zone, Handle<ArrayType> type);
   4.179 -
   4.180 -    ArrayType *type() {
   4.181 -        return type_;
   4.182 -    }
   4.183 -
   4.184 -    // GC Descriptor.
   4.185 -    static inline size_t offsetOfType() {
   4.186 -        return OFFSETOF(ArrayMap, type_);
   4.187 -    }
   4.188 -    // End GC Descriptor.
   4.189 -    
   4.190 -    static ArrayMap *cast(Object *obj) {
   4.191 -        assert(!obj || obj->is(MapKind_MetaArray));
   4.192 -        return reinterpret_cast<ArrayMap *>(obj);
   4.193 -    }
   4.194 -};
   4.195 -
   4.196 -inline void *
   4.197 -Array::bytes()
   4.198 -{
   4.199 -    assert(!type()->contained()->isTraceable());
   4.200 -    assert(type()->hasInlineElements() ||
   4.201 -           type()->isExternalArray() ||
   4.202 -           is(MapKind_DependentArray) ||
   4.203 -           !length() ||
   4.204 -           ByteArray::cast((Object *)elements_));
   4.205 -
   4.206 -    return Address(elements_) + ByteArray::offsetToElements();
   4.207 -}
   4.208 -
   4.209 -inline int *
   4.210 -Array::int32Vec()
   4.211 -{
   4.212 -    assert(type()->contained()->isInt32());
   4.213 -    return reinterpret_cast<int *>(bytes());
   4.214 -}
   4.215 -
   4.216 -inline float *
   4.217 -Array::floatVec()
   4.218 -{
   4.219 -    assert(type()->contained()->isFloat());
   4.220 -    return reinterpret_cast<float *>(bytes());
   4.221 -}
   4.222 -
   4.223 -inline char *
   4.224 -Array::chars()
   4.225 -{
   4.226 -    assert(type()->isCharArray());
   4.227 -    return reinterpret_cast<char *>(bytes());
   4.228 -}
   4.229 -
   4.230 -inline ArrayType *
   4.231 -Array::type()
   4.232 -{
   4.233 -    return ArrayMap::cast(map())->type();
   4.234 -}
   4.235 -
   4.236 -inline size_t
   4.237 -Array::objSize(ArrayMap *map)
   4.238 -{
   4.239 -    assert(this->map() == map);
   4.240 -    if (map->type()->hasInlineElements())
   4.241 -        return sizeof(Array) + Array::SizeForElement(map->type()) * length();
   4.242 -    return sizeof(Array);
   4.243 -}
   4.244 -
   4.245 -}
   4.246 -
   4.247 -#endif // _include_jitcraft_array_h_
   4.248 +/* vim: set ts=4 sw=4 tw=99 et:
   4.249 + *
   4.250 + * Copyright (C) 2012 David Anderson
   4.251 + *
   4.252 + * This file is part of SourcePawn.
   4.253 + *
   4.254 + * SourcePawn is free software: you can redistribute it and/or modify it under
   4.255 + * the terms of the GNU General Public License as published by the Free
   4.256 + * Software Foundation, either version 3 of the License, or (at your option)
   4.257 + * any later version.
   4.258 + * 
   4.259 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   4.260 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   4.261 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   4.262 + *
   4.263 + * You should have received a copy of the GNU General Public License along with
   4.264 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   4.265 + */
   4.266 +#ifndef _include_jitcraft_array_h_
   4.267 +#define _include_jitcraft_array_h_
   4.268 +
   4.269 +#include "Heap.h"
   4.270 +#include "Handles.h"
   4.271 +#include "Types.h"
   4.272 +#include "FixedArray.h"
   4.273 +
   4.274 +namespace ke {
   4.275 +
   4.276 +class ArrayMap;
   4.277 +
   4.278 +class Array : public Object
   4.279 +{
   4.280 +    friend class ArrayMap;
   4.281 +
   4.282 +  protected:
   4.283 +    // Note: we do not write barrier |elements_|, since it can be set to
   4.284 +    // arbitrary pointers.
   4.285 +    uint32 length_;
   4.286 +    union {
   4.287 +        void *elements_;
   4.288 +        Object *objelements_;
   4.289 +    };
   4.290 +
   4.291 +  protected:
   4.292 +    void updateLengthAndElements(Zone *zone, unsigned length, Object *array) {
   4.293 +        length_ = length;
   4.294 +        write(zone, &objelements_, array);
   4.295 +    }
   4.296 +
   4.297 +  public:
   4.298 +    static Array *NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure = Heap::Tenure_Default);
   4.299 +    static Array *NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
   4.300 +    static Array *NewSized(Zone *zone, Handle<ArrayMap> map, int sizes[MAX_ARRAY_DEPTH], Heap::Tenure = Heap::Tenure_Default);
   4.301 +
   4.302 +    static Array *New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure = Heap::Tenure_Default);
   4.303 +    static Array *NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
   4.304 +    static Array *NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure);
   4.305 +
   4.306 +    static Array *NewExternal(Zone *zone,
   4.307 +                              Handle<ArrayMap> map,
   4.308 +                              void *buffer,
   4.309 +                              unsigned length,
   4.310 +                              Heap::Tenure tenure = Heap::Tenure_Default);
   4.311 +
   4.312 +    // Copies an array from one reference to another, obeying language semantics.
   4.313 +    static bool ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source);
   4.314 +
   4.315 +    // Creates a full duplicate of an array, following all array references as if
   4.316 +    // they were fixed. Array references inside structs or objects use ShallowCopy
   4.317 +    // semantics, as this is only intended for duplicating array literals, which
   4.318 +    // cannot contain structs.
   4.319 +    static Array *DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure);
   4.320 +
   4.321 +    uint32 length() {
   4.322 +        return length_;
   4.323 +    }
   4.324 +
   4.325 +    inline ArrayType *type();
   4.326 +
   4.327 +    inline int *int32Vec();
   4.328 +    inline float *floatVec();
   4.329 +    inline char *chars();
   4.330 +    inline void *bytes();
   4.331 +
   4.332 +    bool resize(Zone *zone, size_t newLength);
   4.333 +
   4.334 +    static inline size_t SizeForElement(ArrayType *type) {
   4.335 +        if (type->contained()->isTraceable())
   4.336 +            return sizeof(ke::Object *);
   4.337 +        if (type->contained()->isInt32())
   4.338 +            return sizeof(int);
   4.339 +        if (type->contained()->primitive() == PrimitiveType_Char)
   4.340 +            return sizeof(char);
   4.341 +        assert(type->contained()->isFloat());
   4.342 +        return sizeof(float);
   4.343 +    }
   4.344 +
   4.345 +    inline size_t objSize(ArrayMap *map);
   4.346 +
   4.347 +    int readInt32(size_t index) {
   4.348 +        assert(index < length());
   4.349 +        return int32Vec()[index];
   4.350 +    }
   4.351 +    void writeInt32(size_t index, int i) {
   4.352 +        assert(index < length());
   4.353 +        int32Vec()[index] = i;
   4.354 +    }
   4.355 +    char readChar(size_t index) {
   4.356 +        assert(index < length());
   4.357 +        return chars()[index];
   4.358 +    }
   4.359 +    void writeChar(size_t index, char c) {
   4.360 +        assert(index < length());
   4.361 +        chars()[index] = c;
   4.362 +    }
   4.363 +    float readFloat(size_t index) {
   4.364 +        assert(index < length());
   4.365 +        return floatVec()[index];
   4.366 +    }
   4.367 +    void writeFloat(size_t index, float f) {
   4.368 +        assert(index < length());
   4.369 +        floatVec()[index] = f;
   4.370 +    }
   4.371 +    Object *readObject(size_t index) {
   4.372 +        return FixedArray::cast(objelements_)->at(index);
   4.373 +    }
   4.374 +    void writeObject(Zone *zone, size_t index, Object *ptr) {
   4.375 +        FixedArray::cast(objelements_)->set(zone, index, ptr);
   4.376 +    }
   4.377 +
   4.378 +    // GC Descriptor.
   4.379 +    static inline size_t offsetOfElements() {
   4.380 +        return offsetof(Array, objelements_);
   4.381 +    }
   4.382 +    // End GC Descriptor.
   4.383 +
   4.384 +    static Array *cast(Object *obj) {
   4.385 +        assert(!obj ||
   4.386 +               obj->is(MapKind_Array) ||
   4.387 +               obj->is(MapKind_DependentArray));
   4.388 +        return reinterpret_cast<Array *>(obj);
   4.389 +    }
   4.390 +};
   4.391 +
   4.392 +class DependentArray : public Array
   4.393 +{
   4.394 +    Barriered<Array> root_;
   4.395 +
   4.396 +  public:
   4.397 +    static Array *New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index);
   4.398 +
   4.399 +    // GC Descriptor.
   4.400 +    static inline size_t offsetOfRoot() {
   4.401 +        return offsetof(DependentArray, root_);
   4.402 +    }
   4.403 +    // End GC Descriptor.
   4.404 +
   4.405 +    static DependentArray *cast(Object *obj) {
   4.406 +        assert(!obj || obj->is(MapKind_DependentArray));
   4.407 +        return reinterpret_cast<DependentArray *>(obj);
   4.408 +    }
   4.409 +};
   4.410 +
   4.411 +class ArrayMap : public Map
   4.412 +{
   4.413 +    Barriered<ArrayType> type_;
   4.414 +
   4.415 +  public:
   4.416 +    static ArrayMap *New(Zone *zone, Handle<ArrayType> type);
   4.417 +
   4.418 +    // DependentArray maps are never attached, and are just free-floating,
   4.419 +    // rooted ultimately by the bytecode. A :TODO: that we might need to
   4.420 +    // cache these, or attach them somewhere saner like ArrayType, which
   4.421 +    // itself will eventually be cached.
   4.422 +    static ArrayMap *NewDependent(Zone *zone, Handle<ArrayType> type);
   4.423 +
   4.424 +    ArrayType *type() {
   4.425 +        return type_;
   4.426 +    }
   4.427 +
   4.428 +    // GC Descriptor.
   4.429 +    static inline size_t offsetOfType() {
   4.430 +        return OFFSETOF(ArrayMap, type_);
   4.431 +    }
   4.432 +    // End GC Descriptor.
   4.433 +    
   4.434 +    static ArrayMap *cast(Object *obj) {
   4.435 +        assert(!obj || obj->is(MapKind_MetaArray));
   4.436 +        return reinterpret_cast<ArrayMap *>(obj);
   4.437 +    }
   4.438 +};
   4.439 +
   4.440 +inline void *
   4.441 +Array::bytes()
   4.442 +{
   4.443 +    assert(!type()->contained()->isTraceable());
   4.444 +    assert(type()->hasInlineElements() ||
   4.445 +           type()->isExternalArray() ||
   4.446 +           is(MapKind_DependentArray) ||
   4.447 +           !length() ||
   4.448 +           ByteArray::cast((Object *)elements_));
   4.449 +
   4.450 +    return Address(elements_) + ByteArray::offsetToElements();
   4.451 +}
   4.452 +
   4.453 +inline int *
   4.454 +Array::int32Vec()
   4.455 +{
   4.456 +    assert(type()->contained()->isInt32());
   4.457 +    return reinterpret_cast<int *>(bytes());
   4.458 +}
   4.459 +
   4.460 +inline float *
   4.461 +Array::floatVec()
   4.462 +{
   4.463 +    assert(type()->contained()->isFloat());
   4.464 +    return reinterpret_cast<float *>(bytes());
   4.465 +}
   4.466 +
   4.467 +inline char *
   4.468 +Array::chars()
   4.469 +{
   4.470 +    assert(type()->isCharArray());
   4.471 +    return reinterpret_cast<char *>(bytes());
   4.472 +}
   4.473 +
   4.474 +inline ArrayType *
   4.475 +Array::type()
   4.476 +{
   4.477 +    return ArrayMap::cast(map())->type();
   4.478 +}
   4.479 +
   4.480 +inline size_t
   4.481 +Array::objSize(ArrayMap *map)
   4.482 +{
   4.483 +    assert(this->map() == map);
   4.484 +    if (map->type()->hasInlineElements())
   4.485 +        return sizeof(Array) + Array::SizeForElement(map->type()) * length();
   4.486 +    return sizeof(Array);
   4.487 +}
   4.488 +
   4.489 +}
   4.490 +
   4.491 +#endif // _include_jitcraft_array_h_
     5.1 --- a/src/Code.h	Mon Jun 10 00:46:29 2013 +0100
     5.2 +++ b/src/Code.h	Mon Jun 10 01:04:43 2013 +0100
     5.3 @@ -1,140 +1,140 @@
     5.4 -/* vim: set ts=4 sw=4 tw=99 et:
     5.5 - *
     5.6 - * Copyright (C) 2012 David Anderson
     5.7 - *
     5.8 - * This file is part of JITCraft.
     5.9 - *
    5.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    5.11 - * the terms of the GNU General Public License as published by the Free
    5.12 - * Software Foundation, either version 3 of the License, or (at your option)
    5.13 - * any later version.
    5.14 - * 
    5.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    5.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    5.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    5.18 - *
    5.19 - * You should have received a copy of the GNU General Public License along with
    5.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    5.21 - */
    5.22 -#ifndef _include_jc_code_h_
    5.23 -#define _include_jc_code_h_
    5.24 -
    5.25 -#include "Opcodes.h"
    5.26 -#include "Barriers.h"
    5.27 -#include "Heap.h"
    5.28 -#include "Types.h"
    5.29 -#include "FixedArray.h"
    5.30 -
    5.31 -namespace ke {
    5.32 -
    5.33 -class Module;
    5.34 -class Type;
    5.35 -
    5.36 -// A code object contains the bytecode compiled from a function (or global
    5.37 -// script), as well as all information needed to interpret or JIT-compile
    5.38 -// the bytecode.
    5.39 -class Code : public Object
    5.40 -{
    5.41 -    Barriered<Module> module_;
    5.42 -    Barriered<ByteArray> bytecode_;
    5.43 -    Barriered<FixedArray> locals_;
    5.44 -    Barriered<FixedArray> objects_;
    5.45 -    Barriered<FixedArray> strings_;
    5.46 -    Barriered<ByteArray> safepoints_;
    5.47 -    Barriered<ByteArray> sourcemap_;
    5.48 -    unsigned maxStackDepth_;
    5.49 -    unsigned lineNumber_;
    5.50 -    unsigned maxLoopDepth_;
    5.51 -
    5.52 -  public:
    5.53 -    static inline size_t BytesPerSafepoint(size_t stackDepth) {
    5.54 -        return (Align(stackDepth, 8) / 8) + sizeof(unsigned);
    5.55 -    }
    5.56 -
    5.57 -  public:
    5.58 -    static Code *New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
    5.59 -                     Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
    5.60 -                     unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap);
    5.61 -
    5.62 -    Module *module() {
    5.63 -        return module_;
    5.64 -    }
    5.65 -    bytecode *start() {
    5.66 -        return bytecode_->raw();
    5.67 -    }
    5.68 -    unsigned length() {
    5.69 -        return bytecode_->length();
    5.70 -    }
    5.71 -    Type *localType(size_t index) {
    5.72 -        return Type::cast(locals_->at(index));
    5.73 -    }
    5.74 -    unsigned nlocals() {
    5.75 -        return locals_ ? locals_->length() : 0;
    5.76 -    }
    5.77 -    unsigned maxStackDepth() {
    5.78 -        return maxStackDepth_;
    5.79 -    }
    5.80 -    unsigned maxLoopDepth() {
    5.81 -        return maxLoopDepth_;
    5.82 -    }
    5.83 -    Map *map(size_t index) {
    5.84 -        return Map::cast(objects_->at(index));
    5.85 -    }
    5.86 -    Object *object(size_t index) {
    5.87 -        return objects_->at(index);
    5.88 -    }
    5.89 -    ByteArray *safepoints() {
    5.90 -        return safepoints_;
    5.91 -    }
    5.92 -    FixedArray *strings() {
    5.93 -        return strings_;
    5.94 -    }
    5.95 -    uint8 *safepointAt(unsigned pcOffset);
    5.96 -
    5.97 -    void setModule(Handle<Module> module) {
    5.98 -        module_ = module;
    5.99 -    }
   5.100 -
   5.101 -    unsigned pcToOffset(bytecode *pc) {
   5.102 -        assert(pc >= start() && pc < start() + length());
   5.103 -        return unsigned(pc - start());
   5.104 -    }
   5.105 -
   5.106 -    SourcePosition pcToSource(unsigned pc);
   5.107 -    unsigned lineNumber() {
   5.108 -        return lineNumber_;
   5.109 -    }
   5.110 -
   5.111 -    // GC Descriptor.
   5.112 -    static inline size_t offsetOfModule() {
   5.113 -        return OFFSETOF(Code, module_);
   5.114 -    }
   5.115 -    static inline size_t offsetOfBytecode() {
   5.116 -        return OFFSETOF(Code, bytecode_);
   5.117 -    }
   5.118 -    static inline size_t offsetOfLocals() {
   5.119 -        return OFFSETOF(Code, locals_);
   5.120 -    }
   5.121 -    static inline size_t offsetOfObjects() {
   5.122 -        return OFFSETOF(Code, objects_);
   5.123 -    }
   5.124 -    static inline size_t offsetOfStrings() {
   5.125 -        return OFFSETOF(Code, strings_);
   5.126 -    }
   5.127 -    static inline size_t offsetOfSafepoints() {
   5.128 -        return OFFSETOF(Code, safepoints_);
   5.129 -    }
   5.130 -    static inline size_t offsetOfSourceMap() {
   5.131 -        return OFFSETOF(Code, sourcemap_);
   5.132 -    }
   5.133 -    // End GC Descriptor.
   5.134 -
   5.135 -    static Code *cast(Object *obj) {
   5.136 -        assert(!obj || obj->is(MapKind_Code));
   5.137 -        return reinterpret_cast<Code *>(obj);
   5.138 -    }
   5.139 -};
   5.140 -
   5.141 -}
   5.142 -
   5.143 -#endif // _include_jc_code_h_
   5.144 +/* vim: set ts=4 sw=4 tw=99 et:
   5.145 + *
   5.146 + * Copyright (C) 2012 David Anderson
   5.147 + *
   5.148 + * This file is part of JITCraft.
   5.149 + *
   5.150 + * JITCraft is free software: you can redistribute it and/or modify it under
   5.151 + * the terms of the GNU General Public License as published by the Free
   5.152 + * Software Foundation, either version 3 of the License, or (at your option)
   5.153 + * any later version.
   5.154 + * 
   5.155 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   5.156 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   5.157 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   5.158 + *
   5.159 + * You should have received a copy of the GNU General Public License along with
   5.160 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   5.161 + */
   5.162 +#ifndef _include_jc_code_h_
   5.163 +#define _include_jc_code_h_
   5.164 +
   5.165 +#include "Opcodes.h"
   5.166 +#include "Barriers.h"
   5.167 +#include "Heap.h"
   5.168 +#include "Types.h"
   5.169 +#include "FixedArray.h"
   5.170 +
   5.171 +namespace ke {
   5.172 +
   5.173 +class Module;
   5.174 +class Type;
   5.175 +
   5.176 +// A code object contains the bytecode compiled from a function (or global
   5.177 +// script), as well as all information needed to interpret or JIT-compile
   5.178 +// the bytecode.
   5.179 +class Code : public Object
   5.180 +{
   5.181 +    Barriered<Module> module_;
   5.182 +    Barriered<ByteArray> bytecode_;
   5.183 +    Barriered<FixedArray> locals_;
   5.184 +    Barriered<FixedArray> objects_;
   5.185 +    Barriered<FixedArray> strings_;
   5.186 +    Barriered<ByteArray> safepoints_;
   5.187 +    Barriered<ByteArray> sourcemap_;
   5.188 +    unsigned maxStackDepth_;
   5.189 +    unsigned lineNumber_;
   5.190 +    unsigned maxLoopDepth_;
   5.191 +
   5.192 +  public:
   5.193 +    static inline size_t BytesPerSafepoint(size_t stackDepth) {
   5.194 +        return (Align(stackDepth, 8) / 8) + sizeof(unsigned);
   5.195 +    }
   5.196 +
   5.197 +  public:
   5.198 +    static Code *New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
   5.199 +                     Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
   5.200 +                     unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap);
   5.201 +
   5.202 +    Module *module() {
   5.203 +        return module_;
   5.204 +    }
   5.205 +    bytecode *start() {
   5.206 +        return bytecode_->raw();
   5.207 +    }
   5.208 +    unsigned length() {
   5.209 +        return bytecode_->length();
   5.210 +    }
   5.211 +    Type *localType(size_t index) {
   5.212 +        return Type::cast(locals_->at(index));
   5.213 +    }
   5.214 +    unsigned nlocals() {
   5.215 +        return locals_ ? locals_->length() : 0;
   5.216 +    }
   5.217 +    unsigned maxStackDepth() {
   5.218 +        return maxStackDepth_;
   5.219 +    }
   5.220 +    unsigned maxLoopDepth() {
   5.221 +        return maxLoopDepth_;
   5.222 +    }
   5.223 +    Map *map(size_t index) {
   5.224 +        return Map::cast(objects_->at(index));
   5.225 +    }
   5.226 +    Object *object(size_t index) {
   5.227 +        return objects_->at(index);
   5.228 +    }
   5.229 +    ByteArray *safepoints() {
   5.230 +        return safepoints_;
   5.231 +    }
   5.232 +    FixedArray *strings() {
   5.233 +        return strings_;
   5.234 +    }
   5.235 +    uint8 *safepointAt(unsigned pcOffset);
   5.236 +
   5.237 +    void setModule(Handle<Module> module) {
   5.238 +        module_ = module;
   5.239 +    }
   5.240 +
   5.241 +    unsigned pcToOffset(bytecode *pc) {
   5.242 +        assert(pc >= start() && pc < start() + length());
   5.243 +        return unsigned(pc - start());
   5.244 +    }
   5.245 +
   5.246 +    SourcePosition pcToSource(unsigned pc);
   5.247 +    unsigned lineNumber() {
   5.248 +        return lineNumber_;
   5.249 +    }
   5.250 +
   5.251 +    // GC Descriptor.
   5.252 +    static inline size_t offsetOfModule() {
   5.253 +        return OFFSETOF(Code, module_);
   5.254 +    }
   5.255 +    static inline size_t offsetOfBytecode() {
   5.256 +        return OFFSETOF(Code, bytecode_);
   5.257 +    }
   5.258 +    static inline size_t offsetOfLocals() {
   5.259 +        return OFFSETOF(Code, locals_);
   5.260 +    }
   5.261 +    static inline size_t offsetOfObjects() {
   5.262 +        return OFFSETOF(Code, objects_);
   5.263 +    }
   5.264 +    static inline size_t offsetOfStrings() {
   5.265 +        return OFFSETOF(Code, strings_);
   5.266 +    }
   5.267 +    static inline size_t offsetOfSafepoints() {
   5.268 +        return OFFSETOF(Code, safepoints_);
   5.269 +    }
   5.270 +    static inline size_t offsetOfSourceMap() {
   5.271 +        return OFFSETOF(Code, sourcemap_);
   5.272 +    }
   5.273 +    // End GC Descriptor.
   5.274 +
   5.275 +    static Code *cast(Object *obj) {
   5.276 +        assert(!obj || obj->is(MapKind_Code));
   5.277 +        return reinterpret_cast<Code *>(obj);
   5.278 +    }
   5.279 +};
   5.280 +
   5.281 +}
   5.282 +
   5.283 +#endif // _include_jc_code_h_
     6.1 --- a/src/CompactBuffer.h	Mon Jun 10 00:46:29 2013 +0100
     6.2 +++ b/src/CompactBuffer.h	Mon Jun 10 01:04:43 2013 +0100
     6.3 @@ -1,100 +1,100 @@
     6.4 -/* vim: set ts=4 sw=4 tw=99 et:
     6.5 - *
     6.6 - * Copyright (C) 2012 David Anderson
     6.7 - *
     6.8 - * This file is part of JITCraft.
     6.9 - *
    6.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    6.11 - * the terms of the GNU General Public License as published by the Free
    6.12 - * Software Foundation, either version 3 of the License, or (at your option)
    6.13 - * any later version.
    6.14 - * 
    6.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    6.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    6.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    6.18 - *
    6.19 - * You should have received a copy of the GNU General Public License along with
    6.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    6.21 - */
    6.22 -#ifndef _include_jc_compact_buffer_h_
    6.23 -#define _include_jc_compact_buffer_h_
    6.24 -
    6.25 -#include "AllocatorPolicies.h"
    6.26 -#include "Utility.h"
    6.27 -#include "Vector.h"
    6.28 -
    6.29 -namespace ke {
    6.30 -
    6.31 -class CompactBufferReader
    6.32 -{
    6.33 -    const uint8 *pos_;
    6.34 -    const uint8 *end_;
    6.35 -
    6.36 -  public:
    6.37 -    CompactBufferReader(const uint8 *start, const uint8 *end)
    6.38 -      : pos_(start),
    6.39 -        end_(end)
    6.40 -    {
    6.41 -    }
    6.42 -
    6.43 -    uint8 readUint8() {
    6.44 -        assert(pos_ < end_);
    6.45 -        return *pos_++;
    6.46 -    }
    6.47 -
    6.48 -    uint32 readUint32() {
    6.49 -        uint32 value = 0;
    6.50 -        uint32 shift = 0;
    6.51 -
    6.52 -        uint8 byte;
    6.53 -        do {
    6.54 -            byte = readUint8();
    6.55 -            value |= (byte >> 1) << shift;
    6.56 -            shift += 7;
    6.57 -        } while (byte & 1);
    6.58 -
    6.59 -        assert(shift < 32);
    6.60 -        return value;
    6.61 -    }
    6.62 -
    6.63 -    bool done() const {
    6.64 -        return pos_ == end_;
    6.65 -    }
    6.66 -};
    6.67 -
    6.68 -class CompactBufferWriter
    6.69 -{
    6.70 -    Vector<uint8, ZoneAllocatorPolicy> buffer_;
    6.71 -    bool enoughMemory_;
    6.72 -
    6.73 -  public:
    6.74 -    CompactBufferWriter()
    6.75 -      : enoughMemory_(true)
    6.76 -    {
    6.77 -    }
    6.78 -
    6.79 -    void writeUint8(unsigned value) {
    6.80 -        enoughMemory_ &= buffer_.append(value);
    6.81 -    }
    6.82 -    void writeUint32(unsigned value) {
    6.83 -        do {
    6.84 -            writeUint8(((value & 0x7F) << 1) | (value > 0x7F));
    6.85 -            value >>= 7;
    6.86 -        } while (value);
    6.87 -    }
    6.88 -
    6.89 -    uint8 *buffer() const {
    6.90 -        return buffer_.buffer();
    6.91 -    }
    6.92 -    size_t length() const {
    6.93 -        return buffer_.length();
    6.94 -    }
    6.95 -
    6.96 -    bool oom() const {
    6.97 -        return !enoughMemory_;
    6.98 -    }
    6.99 -};
   6.100 -
   6.101 -}
   6.102 -
   6.103 -#endif // _include_jc_compact_buffer_h_
   6.104 +/* vim: set ts=4 sw=4 tw=99 et:
   6.105 + *
   6.106 + * Copyright (C) 2012 David Anderson
   6.107 + *
   6.108 + * This file is part of JITCraft.
   6.109 + *
   6.110 + * JITCraft is free software: you can redistribute it and/or modify it under
   6.111 + * the terms of the GNU General Public License as published by the Free
   6.112 + * Software Foundation, either version 3 of the License, or (at your option)
   6.113 + * any later version.
   6.114 + * 
   6.115 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   6.116 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   6.117 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   6.118 + *
   6.119 + * You should have received a copy of the GNU General Public License along with
   6.120 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   6.121 + */
   6.122 +#ifndef _include_jc_compact_buffer_h_
   6.123 +#define _include_jc_compact_buffer_h_
   6.124 +
   6.125 +#include "AllocatorPolicies.h"
   6.126 +#include "Utility.h"
   6.127 +#include "Vector.h"
   6.128 +
   6.129 +namespace ke {
   6.130 +
   6.131 +class CompactBufferReader
   6.132 +{
   6.133 +    const uint8 *pos_;
   6.134 +    const uint8 *end_;
   6.135 +
   6.136 +  public:
   6.137 +    CompactBufferReader(const uint8 *start, const uint8 *end)
   6.138 +      : pos_(start),
   6.139 +        end_(end)
   6.140 +    {
   6.141 +    }
   6.142 +
   6.143 +    uint8 readUint8() {
   6.144 +        assert(pos_ < end_);
   6.145 +        return *pos_++;
   6.146 +    }
   6.147 +
   6.148 +    uint32 readUint32() {
   6.149 +        uint32 value = 0;
   6.150 +        uint32 shift = 0;
   6.151 +
   6.152 +        uint8 byte;
   6.153 +        do {
   6.154 +            byte = readUint8();
   6.155 +            value |= (byte >> 1) << shift;
   6.156 +            shift += 7;
   6.157 +        } while (byte & 1);
   6.158 +
   6.159 +        assert(shift < 32);
   6.160 +        return value;
   6.161 +    }
   6.162 +
   6.163 +    bool done() const {
   6.164 +        return pos_ == end_;
   6.165 +    }
   6.166 +};
   6.167 +
   6.168 +class CompactBufferWriter
   6.169 +{
   6.170 +    Vector<uint8, ZoneAllocatorPolicy> buffer_;
   6.171 +    bool enoughMemory_;
   6.172 +
   6.173 +  public:
   6.174 +    CompactBufferWriter()
   6.175 +      : enoughMemory_(true)
   6.176 +    {
   6.177 +    }
   6.178 +
   6.179 +    void writeUint8(unsigned value) {
   6.180 +        enoughMemory_ &= buffer_.append(value);
   6.181 +    }
   6.182 +    void writeUint32(unsigned value) {
   6.183 +        do {
   6.184 +            writeUint8(((value & 0x7F) << 1) | (value > 0x7F));
   6.185 +            value >>= 7;
   6.186 +        } while (value);
   6.187 +    }
   6.188 +
   6.189 +    uint8 *buffer() const {
   6.190 +        return buffer_.buffer();
   6.191 +    }
   6.192 +    size_t length() const {
   6.193 +        return buffer_.length();
   6.194 +    }
   6.195 +
   6.196 +    bool oom() const {
   6.197 +        return !enoughMemory_;
   6.198 +    }
   6.199 +};
   6.200 +
   6.201 +}
   6.202 +
   6.203 +#endif // _include_jc_compact_buffer_h_
     7.1 --- a/src/Environments.cpp	Mon Jun 10 00:46:29 2013 +0100
     7.2 +++ b/src/Environments.cpp	Mon Jun 10 01:04:43 2013 +0100
     7.3 @@ -1,102 +1,102 @@
     7.4 -/*
     7.5 - * Copyright (C) 2012 David Anderson
     7.6 - *
     7.7 - * This file is part of SourcePawn.
     7.8 - *
     7.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
    7.10 - * the terms of the GNU General Public License as published by the Free
    7.11 - * Software Foundation, either version 3 of the License, or (at your option)
    7.12 - * any later version.
    7.13 - * 
    7.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    7.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    7.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    7.17 - *
    7.18 - * You should have received a copy of the GNU General Public License along with
    7.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
    7.20 - */
    7.21 -#include <string.h>
    7.22 -#include "Utility.h"
    7.23 -#include "Environments.h"
    7.24 -#include "Structures.h"
    7.25 -#include "FixedArray.h"
    7.26 -#include "Zone.h"
    7.27 -#include "compiler/NameBinding.h"
    7.28 -#include "Spaces-inl.h"
    7.29 -#include "Heap-inl.h"
    7.30 -
    7.31 -using namespace ke;
    7.32 -
    7.33 -EnvironmentSlotDescriptorArray *
    7.34 -EnvironmentSlotDescriptorArray::New(Zone *zone, unsigned nslots)
    7.35 -{
    7.36 -    size_t bytesNeeded = sizeof(EnvironmentSlotDescriptorArray) +
    7.37 -                         sizeof(EnvironmentSlotDescriptor) * nslots;
    7.38 -
    7.39 -    Local<EnvironmentSlotDescriptorArray> array(zone);
    7.40 -    Local<Map> map(zone, zone->getMap(MapKind_EnvironmentSlotDescriptorArray));
    7.41 -
    7.42 -    array = EnvironmentSlotDescriptorArray::cast(zone->allocate(map, bytesNeeded, Heap::Tenure_Old));
    7.43 -    if (!array)
    7.44 -        return NULL;
    7.45 -
    7.46 -    // We zero the array for safety, since we could GC or fail before initialization.
    7.47 -    array->length_ = nslots;
    7.48 -    memset(array->slots(), 0, sizeof(EnvironmentSlotDescriptor) * nslots);
    7.49 -    return array;
    7.50 -}
    7.51 -
    7.52 -Environment *
    7.53 -Environment::New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure)
    7.54 -{
    7.55 -    size_t bytesNeeded = sizeof(Environment) + map->structureSize();
    7.56 -    Local<Environment> env(zone, Environment::cast(zone->allocate(map, bytesNeeded, tenure)));
    7.57 -    if (!env)
    7.58 -        return NULL;
    7.59 -
    7.60 -    // Initialize when called from C++, to make sure object slots are NULL.
    7.61 -    memset((Object *)env + 1, 0, map->structureSize());
    7.62 -    return env;
    7.63 -}
    7.64 -
    7.65 -#if 0
    7.66 -EnvironmentMap *
    7.67 -EnvironmentMap::New(Zone *zone, unsigned nvars, Variable **vars)
    7.68 -{
    7.69 -    StructureBufferBuilder structure;
    7.70 -
    7.71 -    Local<EnvironmentSlotDescriptorArray> slots(zone);
    7.72 -    slots = EnvironmentSlotDescriptorArray::New(zone, nvars);
    7.73 -    if (!slots)
    7.74 -        return NULL;
    7.75 -
    7.76 -    // Build the descriptor table, mapping each slot to an offset and type.
    7.77 -    Local<Type> type(zone);
    7.78 -    for (unsigned i = 0; i < nvars; i++) {
    7.79 -        assert(vars[i]->slot() == i);
    7.80 -        type = vars[i]->type();
    7.81 -
    7.82 -        EnvironmentSlotDescriptor &desc = slots->slots()[i];
    7.83 -        if (!structure.add(type, &desc.offset))
    7.84 -            return NULL;
    7.85 -
    7.86 -        desc.type = type;
    7.87 -    }
    7.88 -
    7.89 -    // Allocate the actual map now.
    7.90 -    size_t bytesNeeded = sizeof(EnvironmentMap) + structure.traceableOffsetCount() * sizeof(unsigned);
    7.91 -
    7.92 -    Local<EnvironmentMap> map(zone);
    7.93 -    map = EnvironmentMap::cast(zone->allocateMap(MapKind_Environment, bytesNeeded, MapKind_MetaEnvironment));
    7.94 -    if (!map)
    7.95 -        return NULL;
    7.96 -    
    7.97 -    // Fill in the map fields, and copy the traceable offsets structure.
    7.98 -    map->structureSize_ = structure.structureSize();
    7.99 -    map->traceOffsetCount_ = structure.traceableOffsetCount();
   7.100 -    map->slots_ = slots;
   7.101 -    memcpy(const_cast<unsigned *>(map->traceOffsets()), structure.offsets(), sizeof(unsigned) * structure.traceableOffsetCount());
   7.102 -
   7.103 -    return map;
   7.104 -}
   7.105 +/*
   7.106 + * Copyright (C) 2012 David Anderson
   7.107 + *
   7.108 + * This file is part of SourcePawn.
   7.109 + *
   7.110 + * SourcePawn is free software: you can redistribute it and/or modify it under
   7.111 + * the terms of the GNU General Public License as published by the Free
   7.112 + * Software Foundation, either version 3 of the License, or (at your option)
   7.113 + * any later version.
   7.114 + * 
   7.115 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   7.116 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   7.117 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   7.118 + *
   7.119 + * You should have received a copy of the GNU General Public License along with
   7.120 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   7.121 + */
   7.122 +#include <string.h>
   7.123 +#include "Utility.h"
   7.124 +#include "Environments.h"
   7.125 +#include "Structures.h"
   7.126 +#include "FixedArray.h"
   7.127 +#include "Zone.h"
   7.128 +#include "compiler/NameBinding.h"
   7.129 +#include "Spaces-inl.h"
   7.130 +#include "Heap-inl.h"
   7.131 +
   7.132 +using namespace ke;
   7.133 +
   7.134 +EnvironmentSlotDescriptorArray *
   7.135 +EnvironmentSlotDescriptorArray::New(Zone *zone, unsigned nslots)
   7.136 +{
   7.137 +    size_t bytesNeeded = sizeof(EnvironmentSlotDescriptorArray) +
   7.138 +                         sizeof(EnvironmentSlotDescriptor) * nslots;
   7.139 +
   7.140 +    Local<EnvironmentSlotDescriptorArray> array(zone);
   7.141 +    Local<Map> map(zone, zone->getMap(MapKind_EnvironmentSlotDescriptorArray));
   7.142 +
   7.143 +    array = EnvironmentSlotDescriptorArray::cast(zone->allocate(map, bytesNeeded, Heap::Tenure_Old));
   7.144 +    if (!array)
   7.145 +        return NULL;
   7.146 +
   7.147 +    // We zero the array for safety, since we could GC or fail before initialization.
   7.148 +    array->length_ = nslots;
   7.149 +    memset(array->slots(), 0, sizeof(EnvironmentSlotDescriptor) * nslots);
   7.150 +    return array;
   7.151 +}
   7.152 +
   7.153 +Environment *
   7.154 +Environment::New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure)
   7.155 +{
   7.156 +    size_t bytesNeeded = sizeof(Environment) + map->structureSize();
   7.157 +    Local<Environment> env(zone, Environment::cast(zone->allocate(map, bytesNeeded, tenure)));
   7.158 +    if (!env)
   7.159 +        return NULL;
   7.160 +
   7.161 +    // Initialize when called from C++, to make sure object slots are NULL.
   7.162 +    memset((Object *)env + 1, 0, map->structureSize());
   7.163 +    return env;
   7.164 +}
   7.165 +
   7.166 +#if 0
   7.167 +EnvironmentMap *
   7.168 +EnvironmentMap::New(Zone *zone, unsigned nvars, Variable **vars)
   7.169 +{
   7.170 +    StructureBufferBuilder structure;
   7.171 +
   7.172 +    Local<EnvironmentSlotDescriptorArray> slots(zone);
   7.173 +    slots = EnvironmentSlotDescriptorArray::New(zone, nvars);
   7.174 +    if (!slots)
   7.175 +        return NULL;
   7.176 +
   7.177 +    // Build the descriptor table, mapping each slot to an offset and type.
   7.178 +    Local<Type> type(zone);
   7.179 +    for (unsigned i = 0; i < nvars; i++) {
   7.180 +        assert(vars[i]->slot() == i);
   7.181 +        type = vars[i]->type();
   7.182 +
   7.183 +        EnvironmentSlotDescriptor &desc = slots->slots()[i];
   7.184 +        if (!structure.add(type, &desc.offset))
   7.185 +            return NULL;
   7.186 +
   7.187 +        desc.type = type;
   7.188 +    }
   7.189 +
   7.190 +    // Allocate the actual map now.
   7.191 +    size_t bytesNeeded = sizeof(EnvironmentMap) + structure.traceableOffsetCount() * sizeof(unsigned);
   7.192 +
   7.193 +    Local<EnvironmentMap> map(zone);
   7.194 +    map = EnvironmentMap::cast(zone->allocateMap(MapKind_Environment, bytesNeeded, MapKind_MetaEnvironment));
   7.195 +    if (!map)
   7.196 +        return NULL;
   7.197 +    
   7.198 +    // Fill in the map fields, and copy the traceable offsets structure.
   7.199 +    map->structureSize_ = structure.structureSize();
   7.200 +    map->traceOffsetCount_ = structure.traceableOffsetCount();
   7.201 +    map->slots_ = slots;
   7.202 +    memcpy(const_cast<unsigned *>(map->traceOffsets()), structure.offsets(), sizeof(unsigned) * structure.traceableOffsetCount());
   7.203 +
   7.204 +    return map;
   7.205 +}
   7.206  #endif
   7.207 \ No newline at end of file
     8.1 --- a/src/Environments.h	Mon Jun 10 00:46:29 2013 +0100
     8.2 +++ b/src/Environments.h	Mon Jun 10 01:04:43 2013 +0100
     8.3 @@ -1,169 +1,169 @@
     8.4 -/*
     8.5 - * Copyright (C) 2012 David Anderson
     8.6 - *
     8.7 - * This file is part of JITCraft.
     8.8 - *
     8.9 - * JITCraft is free software: you can redistribute it and/or modify it under
    8.10 - * the terms of the GNU General Public License as published by the Free
    8.11 - * Software Foundation, either version 3 of the License, or (at your option)
    8.12 - * any later version.
    8.13 - * 
    8.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    8.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    8.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    8.17 - *
    8.18 - * You should have received a copy of the GNU General Public License along with
    8.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    8.20 - */
    8.21 -#ifndef _include_ke_environment_h_
    8.22 -#define _include_ke_environment_h_
    8.23 -
    8.24 -#include "Objects.h"
    8.25 -#include "Handles.h"
    8.26 -#include "Heap.h"
    8.27 -#include "FixedArray.h"
    8.28 -
    8.29 -namespace ke {
    8.30 -
    8.31 -class EnvironmentMap;
    8.32 -class Variable;
    8.33 -class ByteArray;
    8.34 -class Type;
    8.35 -
    8.36 -// An environment represents the lexical environment of a code or function
    8.37 -// object. It used for variables which may be accessed outside a function's
    8.38 -// normal activation (i.e., upvars).
    8.39 -//
    8.40 -// A module uses an Environment to store its global variables.
    8.41 -class Environment : public Object
    8.42 -{
    8.43 -    template <typename T>
    8.44 -    inline T *pointerToSlot(unsigned slot);
    8.45 -
    8.46 -  public:
    8.47 -    static Environment *New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
    8.48 -
    8.49 -    inline EnvironmentMap *map();
    8.50 -    inline size_t objSize();
    8.51 -
    8.52 -    float getFloat(unsigned slot) {
    8.53 -        return *pointerToSlot<float>(slot);
    8.54 -    }
    8.55 -    int getInt32(unsigned slot) {
    8.56 -        return *pointerToSlot<int>(slot);
    8.57 -    }
    8.58 -    Object *getObject(unsigned slot) {
    8.59 -        return *pointerToSlot<Object *>(slot);
    8.60 -    }
    8.61 -    void setFloat(unsigned slot, float f) {
    8.62 -        *pointerToSlot<float>(slot) = f;
    8.63 -    }
    8.64 -    void setInt32(unsigned slot, int i) {
    8.65 -        *pointerToSlot<int>(slot) = i;
    8.66 -    }
    8.67 -    void setObject(unsigned slot, Object *obj) {
    8.68 -        // :TODO: write barrier
    8.69 -        *pointerToSlot<Object *>(slot) = obj;
    8.70 -    }
    8.71 -
    8.72 -    static inline size_t offsetOfSlotOffset(unsigned offset) {
    8.73 -        return sizeof(Environment) + offset;
    8.74 -    }
    8.75 -
    8.76 -    static inline Environment *cast(Object *obj) {
    8.77 -        assert(!obj || obj->is(MapKind_Environment));
    8.78 -        return reinterpret_cast<Environment *>(obj);
    8.79 -    }
    8.80 -};
    8.81 -
    8.82 -struct EnvironmentSlotDescriptor
    8.83 -{
    8.84 -    Barriered<Type> type;
    8.85 -    unsigned offset;
    8.86 -};
    8.87 -
    8.88 -class EnvironmentSlotDescriptorArray : public Object
    8.89 -{
    8.90 -    unsigned length_;
    8.91 -
    8.92 -  public:
    8.93 -    static EnvironmentSlotDescriptorArray *New(Zone *zone, unsigned length);
    8.94 -
    8.95 -    EnvironmentSlotDescriptor *slots() {
    8.96 -        return reinterpret_cast<EnvironmentSlotDescriptor *>(this + 1);
    8.97 -    }
    8.98 -    EnvironmentSlotDescriptor &at(unsigned slot) {
    8.99 -        assert(slot < length_);
   8.100 -        return slots()[slot];
   8.101 -    }
   8.102 -    unsigned length() {
   8.103 -        return length_;
   8.104 -    }
   8.105 -    unsigned objSize() {
   8.106 -        return sizeof(*this) + length() * sizeof(EnvironmentSlotDescriptorArray);
   8.107 -    }
   8.108 -
   8.109 -    static inline EnvironmentSlotDescriptorArray *cast(Object *obj) {
   8.110 -        assert(!obj || obj->is(MapKind_EnvironmentSlotDescriptorArray));
   8.111 -        return reinterpret_cast<EnvironmentSlotDescriptorArray *>(obj);
   8.112 -    }
   8.113 -};
   8.114 -
   8.115 -class EnvironmentMap : public Map
   8.116 -{
   8.117 -    unsigned structureSize_;
   8.118 -    unsigned traceOffsetCount_;
   8.119 -    Barriered<EnvironmentSlotDescriptorArray> slots_;
   8.120 -
   8.121 -  public:
   8.122 -    static EnvironmentMap *New(Zone *zone, unsigned nvars, Variable **vars);
   8.123 -
   8.124 -    unsigned structureSize() {
   8.125 -        return structureSize_;
   8.126 -    }
   8.127 -    unsigned traceOffsetCount() {
   8.128 -        return traceOffsetCount_;
   8.129 -    }
   8.130 -    const unsigned *traceOffsets() {
   8.131 -        return reinterpret_cast<unsigned *>(this + 1);
   8.132 -    }
   8.133 -    size_t objSize() {
   8.134 -        return sizeof(EnvironmentMap) + sizeof(unsigned) * traceOffsetCount();
   8.135 -    }
   8.136 -    EnvironmentSlotDescriptor &slotDescriptor(unsigned slot) {
   8.137 -        return slots_->at(slot);
   8.138 -    }
   8.139 -
   8.140 -    // Begin GC descriptors.
   8.141 -    static inline size_t offsetOfSlots() {
   8.142 -        return OFFSETOF(EnvironmentMap, slots_);
   8.143 -    }
   8.144 -    // End GC descriptors.
   8.145 -
   8.146 -    static inline EnvironmentMap *cast(Object *obj) {
   8.147 -        assert(!obj || obj->is(MapKind_MetaEnvironment));
   8.148 -        return reinterpret_cast<EnvironmentMap *>(obj);
   8.149 -    }
   8.150 -};
   8.151 -
   8.152 -size_t
   8.153 -Environment::objSize()
   8.154 -{
   8.155 -    return sizeof(Environment) + map()->structureSize();
   8.156 -}
   8.157 -
   8.158 -EnvironmentMap *
   8.159 -Environment::map()
   8.160 -{
   8.161 -    return EnvironmentMap::cast(Object::map());
   8.162 -}
   8.163 -
   8.164 -template <typename T> T *
   8.165 -Environment::pointerToSlot(unsigned slot)
   8.166 -{
   8.167 -    return reinterpret_cast<T *>(reinterpret_cast<char *>(this + 1) + map()->slotDescriptor(slot).offset);
   8.168 -}
   8.169 -
   8.170 -}
   8.171 -
   8.172 -#endif // _include_ke_environment_h_
   8.173 +/*
   8.174 + * Copyright (C) 2012 David Anderson
   8.175 + *
   8.176 + * This file is part of JITCraft.
   8.177 + *
   8.178 + * JITCraft is free software: you can redistribute it and/or modify it under
   8.179 + * the terms of the GNU General Public License as published by the Free
   8.180 + * Software Foundation, either version 3 of the License, or (at your option)
   8.181 + * any later version.
   8.182 + * 
   8.183 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   8.184 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   8.185 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   8.186 + *
   8.187 + * You should have received a copy of the GNU General Public License along with
   8.188 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   8.189 + */
   8.190 +#ifndef _include_ke_environment_h_
   8.191 +#define _include_ke_environment_h_
   8.192 +
   8.193 +#include "Objects.h"
   8.194 +#include "Handles.h"
   8.195 +#include "Heap.h"
   8.196 +#include "FixedArray.h"
   8.197 +
   8.198 +namespace ke {
   8.199 +
   8.200 +class EnvironmentMap;
   8.201 +class Variable;
   8.202 +class ByteArray;
   8.203 +class Type;
   8.204 +
   8.205 +// An environment represents the lexical environment of a code or function
   8.206 +// object. It used for variables which may be accessed outside a function's
   8.207 +// normal activation (i.e., upvars).
   8.208 +//
   8.209 +// A module uses an Environment to store its global variables.
   8.210 +class Environment : public Object
   8.211 +{
   8.212 +    template <typename T>
   8.213 +    inline T *pointerToSlot(unsigned slot);
   8.214 +
   8.215 +  public:
   8.216 +    static Environment *New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
   8.217 +
   8.218 +    inline EnvironmentMap *map();
   8.219 +    inline size_t objSize();
   8.220 +
   8.221 +    float getFloat(unsigned slot) {
   8.222 +        return *pointerToSlot<float>(slot);
   8.223 +    }
   8.224 +    int getInt32(unsigned slot) {
   8.225 +        return *pointerToSlot<int>(slot);
   8.226 +    }
   8.227 +    Object *getObject(unsigned slot) {
   8.228 +        return *pointerToSlot<Object *>(slot);
   8.229 +    }
   8.230 +    void setFloat(unsigned slot, float f) {
   8.231 +        *pointerToSlot<float>(slot) = f;
   8.232 +    }
   8.233 +    void setInt32(unsigned slot, int i) {
   8.234 +        *pointerToSlot<int>(slot) = i;
   8.235 +    }
   8.236 +    void setObject(unsigned slot, Object *obj) {
   8.237 +        // :TODO: write barrier
   8.238 +        *pointerToSlot<Object *>(slot) = obj;
   8.239 +    }
   8.240 +
   8.241 +    static inline size_t offsetOfSlotOffset(unsigned offset) {
   8.242 +        return sizeof(Environment) + offset;
   8.243 +    }
   8.244 +
   8.245 +    static inline Environment *cast(Object *obj) {
   8.246 +        assert(!obj || obj->is(MapKind_Environment));
   8.247 +        return reinterpret_cast<Environment *>(obj);
   8.248 +    }
   8.249 +};
   8.250 +
   8.251 +struct EnvironmentSlotDescriptor
   8.252 +{
   8.253 +    Barriered<Type> type;
   8.254 +    unsigned offset;
   8.255 +};
   8.256 +
   8.257 +class EnvironmentSlotDescriptorArray : public Object
   8.258 +{
   8.259 +    unsigned length_;
   8.260 +
   8.261 +  public:
   8.262 +    static EnvironmentSlotDescriptorArray *New(Zone *zone, unsigned length);
   8.263 +
   8.264 +    EnvironmentSlotDescriptor *slots() {
   8.265 +        return reinterpret_cast<EnvironmentSlotDescriptor *>(this + 1);
   8.266 +    }
   8.267 +    EnvironmentSlotDescriptor &at(unsigned slot) {
   8.268 +        assert(slot < length_);
   8.269 +        return slots()[slot];
   8.270 +    }
   8.271 +    unsigned length() {
   8.272 +        return length_;
   8.273 +    }
   8.274 +    unsigned objSize() {
   8.275 +        return sizeof(*this) + length() * sizeof(EnvironmentSlotDescriptorArray);
   8.276 +    }
   8.277 +
   8.278 +    static inline EnvironmentSlotDescriptorArray *cast(Object *obj) {
   8.279 +        assert(!obj || obj->is(MapKind_EnvironmentSlotDescriptorArray));
   8.280 +        return reinterpret_cast<EnvironmentSlotDescriptorArray *>(obj);
   8.281 +    }
   8.282 +};
   8.283 +
   8.284 +class EnvironmentMap : public Map
   8.285 +{
   8.286 +    unsigned structureSize_;
   8.287 +    unsigned traceOffsetCount_;
   8.288 +    Barriered<EnvironmentSlotDescriptorArray> slots_;
   8.289 +
   8.290 +  public:
   8.291 +    static EnvironmentMap *New(Zone *zone, unsigned nvars, Variable **vars);
   8.292 +
   8.293 +    unsigned structureSize() {
   8.294 +        return structureSize_;
   8.295 +    }
   8.296 +    unsigned traceOffsetCount() {
   8.297 +        return traceOffsetCount_;
   8.298 +    }
   8.299 +    const unsigned *traceOffsets() {
   8.300 +        return reinterpret_cast<unsigned *>(this + 1);
   8.301 +    }
   8.302 +    size_t objSize() {
   8.303 +        return sizeof(EnvironmentMap) + sizeof(unsigned) * traceOffsetCount();
   8.304 +    }
   8.305 +    EnvironmentSlotDescriptor &slotDescriptor(unsigned slot) {
   8.306 +        return slots_->at(slot);
   8.307 +    }
   8.308 +
   8.309 +    // Begin GC descriptors.
   8.310 +    static inline size_t offsetOfSlots() {
   8.311 +        return OFFSETOF(EnvironmentMap, slots_);
   8.312 +    }
   8.313 +    // End GC descriptors.
   8.314 +
   8.315 +    static inline EnvironmentMap *cast(Object *obj) {
   8.316 +        assert(!obj || obj->is(MapKind_MetaEnvironment));
   8.317 +        return reinterpret_cast<EnvironmentMap *>(obj);
   8.318 +    }
   8.319 +};
   8.320 +
   8.321 +size_t
   8.322 +Environment::objSize()
   8.323 +{
   8.324 +    return sizeof(Environment) + map()->structureSize();
   8.325 +}
   8.326 +
   8.327 +EnvironmentMap *
   8.328 +Environment::map()
   8.329 +{
   8.330 +    return EnvironmentMap::cast(Object::map());
   8.331 +}
   8.332 +
   8.333 +template <typename T> T *
   8.334 +Environment::pointerToSlot(unsigned slot)
   8.335 +{
   8.336 +    return reinterpret_cast<T *>(reinterpret_cast<char *>(this + 1) + map()->slotDescriptor(slot).offset);
   8.337 +}
   8.338 +
   8.339 +}
   8.340 +
   8.341 +#endif // _include_ke_environment_h_
     9.1 --- a/src/Exception.cpp	Mon Jun 10 00:46:29 2013 +0100
     9.2 +++ b/src/Exception.cpp	Mon Jun 10 01:04:43 2013 +0100
     9.3 @@ -1,31 +1,31 @@
     9.4 -/* vim: set ts=4 sw=4 tw=99 et:
     9.5 - *
     9.6 - * Copyright (C) 2012 David Anderson
     9.7 - *
     9.8 - * This file is part of SourcePawn.
     9.9 - *
    9.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
    9.11 - * the terms of the GNU General Public License as published by the Free
    9.12 - * Software Foundation, either version 3 of the License, or (at your option)
    9.13 - * any later version.
    9.14 - * 
    9.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    9.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    9.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    9.18 - *
    9.19 - * You should have received a copy of the GNU General Public License along with
    9.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
    9.21 - */
    9.22 -#include "Utility.h"
    9.23 -#include "Messages.h"
    9.24 -
    9.25 -using namespace ke;
    9.26 -
    9.27 -const MessageInfo ke::Messages[] =
    9.28 -{
    9.29 -#define MSG(Name, Type, String) \
    9.30 -    { MessageType_##Type, String },
    9.31 -# include "Messages.tbl"
    9.32 -#undef MSG
    9.33 -    { MessageType_SyntaxError, NULL }
    9.34 -};
    9.35 +/* vim: set ts=4 sw=4 tw=99 et:
    9.36 + *
    9.37 + * Copyright (C) 2012 David Anderson
    9.38 + *
    9.39 + * This file is part of SourcePawn.
    9.40 + *
    9.41 + * SourcePawn is free software: you can redistribute it and/or modify it under
    9.42 + * the terms of the GNU General Public License as published by the Free
    9.43 + * Software Foundation, either version 3 of the License, or (at your option)
    9.44 + * any later version.
    9.45 + * 
    9.46 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    9.47 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    9.48 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    9.49 + *
    9.50 + * You should have received a copy of the GNU General Public License along with
    9.51 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
    9.52 + */
    9.53 +#include "Utility.h"
    9.54 +#include "Messages.h"
    9.55 +
    9.56 +using namespace ke;
    9.57 +
    9.58 +const MessageInfo ke::Messages[] =
    9.59 +{
    9.60 +#define MSG(Name, Type, String) \
    9.61 +    { MessageType_##Type, String },
    9.62 +# include "Messages.tbl"
    9.63 +#undef MSG
    9.64 +    { MessageType_SyntaxError, NULL }
    9.65 +};
    10.1 --- a/src/FixedArray.cpp	Mon Jun 10 00:46:29 2013 +0100
    10.2 +++ b/src/FixedArray.cpp	Mon Jun 10 01:04:43 2013 +0100
    10.3 @@ -1,78 +1,78 @@
    10.4 -/*
    10.5 - * Copyright (C) 2012 David Anderson
    10.6 - *
    10.7 - * This file is part of SourcePawn.
    10.8 - *
    10.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   10.10 - * the terms of the GNU General Public License as published by the Free
   10.11 - * Software Foundation, either version 3 of the License, or (at your option)
   10.12 - * any later version.
   10.13 - * 
   10.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   10.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   10.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   10.17 - *
   10.18 - * You should have received a copy of the GNU General Public License along with
   10.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   10.20 - */
   10.21 -#include <limits.h>
   10.22 -#include <string.h>
   10.23 -#include "FixedArray.h"
   10.24 -#include "Zone.h"
   10.25 -#include "Heap-inl.h"
   10.26 -
   10.27 -using namespace ke;
   10.28 -
   10.29 -static const unsigned kMaxFixedArrayLength = ((INT_MAX - sizeof(FixedArray)) / sizeof(ke::Object *));
   10.30 -
   10.31 -FixedArray *
   10.32 -FixedArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
   10.33 -{
   10.34 -    if (length >= kMaxFixedArrayLength) {
   10.35 -        zone->reportError(Message_ArrayTooBig);
   10.36 -        return NULL;
   10.37 -    }
   10.38 -
   10.39 -    Local<FixedArray> array(zone, FixedArray::cast(zone->allocate(MapKind_FixedArray, SizeFor(length), tenure)));
   10.40 -    if (!array)
   10.41 -        return NULL;
   10.42 -
   10.43 -    array->length_ = length;
   10.44 -    memset(array->vec(), 0, length * sizeof(Object *));
   10.45 -    return array;
   10.46 -}
   10.47 -
   10.48 -ByteArray *
   10.49 -ByteArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
   10.50 -{
   10.51 -    if (length >= kMaxFixedArrayLength) {
   10.52 -        zone->reportError(Message_ArrayTooBig);
   10.53 -        return NULL;
   10.54 -    }
   10.55 -
   10.56 -    Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(MapKind_ByteArray, SizeFor(length), tenure)));
   10.57 -    if (!array)
   10.58 -        return NULL;
   10.59 -
   10.60 -    array->length_ = length;
   10.61 -    memset(array->raw(), 0, length);
   10.62 -    return array;
   10.63 -}
   10.64 -
   10.65 -ByteArray *
   10.66 -ByteArray::New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure)
   10.67 -{
   10.68 -    if (length >= kMaxFixedArrayLength) {
   10.69 -        zone->reportError(Message_ArrayTooBig);
   10.70 -        return NULL;
   10.71 -    }
   10.72 -
   10.73 -    Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(map, SizeFor(length), tenure)));
   10.74 -    if (!array)
   10.75 -        return NULL;
   10.76 -
   10.77 -    array->length_ = length;
   10.78 -    memset(array->raw(), 0, length);
   10.79 -    return array;
   10.80 -}
   10.81 -
   10.82 +/*
   10.83 + * Copyright (C) 2012 David Anderson
   10.84 + *
   10.85 + * This file is part of SourcePawn.
   10.86 + *
   10.87 + * SourcePawn is free software: you can redistribute it and/or modify it under
   10.88 + * the terms of the GNU General Public License as published by the Free
   10.89 + * Software Foundation, either version 3 of the License, or (at your option)
   10.90 + * any later version.
   10.91 + * 
   10.92 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   10.93 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   10.94 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   10.95 + *
   10.96 + * You should have received a copy of the GNU General Public License along with
   10.97 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   10.98 + */
   10.99 +#include <limits.h>
  10.100 +#include <string.h>
  10.101 +#include "FixedArray.h"
  10.102 +#include "Zone.h"
  10.103 +#include "Heap-inl.h"
  10.104 +
  10.105 +using namespace ke;
  10.106 +
  10.107 +static const unsigned kMaxFixedArrayLength = ((INT_MAX - sizeof(FixedArray)) / sizeof(ke::Object *));
  10.108 +
  10.109 +FixedArray *
  10.110 +FixedArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
  10.111 +{
  10.112 +    if (length >= kMaxFixedArrayLength) {
  10.113 +        zone->reportError(Message_ArrayTooBig);
  10.114 +        return NULL;
  10.115 +    }
  10.116 +
  10.117 +    Local<FixedArray> array(zone, FixedArray::cast(zone->allocate(MapKind_FixedArray, SizeFor(length), tenure)));
  10.118 +    if (!array)
  10.119 +        return NULL;
  10.120 +
  10.121 +    array->length_ = length;
  10.122 +    memset(array->vec(), 0, length * sizeof(Object *));
  10.123 +    return array;
  10.124 +}
  10.125 +
  10.126 +ByteArray *
  10.127 +ByteArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
  10.128 +{
  10.129 +    if (length >= kMaxFixedArrayLength) {
  10.130 +        zone->reportError(Message_ArrayTooBig);
  10.131 +        return NULL;
  10.132 +    }
  10.133 +
  10.134 +    Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(MapKind_ByteArray, SizeFor(length), tenure)));
  10.135 +    if (!array)
  10.136 +        return NULL;
  10.137 +
  10.138 +    array->length_ = length;
  10.139 +    memset(array->raw(), 0, length);
  10.140 +    return array;
  10.141 +}
  10.142 +
  10.143 +ByteArray *
  10.144 +ByteArray::New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure)
  10.145 +{
  10.146 +    if (length >= kMaxFixedArrayLength) {
  10.147 +        zone->reportError(Message_ArrayTooBig);
  10.148 +        return NULL;
  10.149 +    }
  10.150 +
  10.151 +    Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(map, SizeFor(length), tenure)));
  10.152 +    if (!array)
  10.153 +        return NULL;
  10.154 +
  10.155 +    array->length_ = length;
  10.156 +    memset(array->raw(), 0, length);
  10.157 +    return array;
  10.158 +}
  10.159 +
    11.1 --- a/src/FixedArray.h	Mon Jun 10 00:46:29 2013 +0100
    11.2 +++ b/src/FixedArray.h	Mon Jun 10 01:04:43 2013 +0100
    11.3 @@ -1,99 +1,99 @@
    11.4 -/* vim: set ts=4 sw=4 tw=99 et:
    11.5 - *
    11.6 - * Copyright (C) 2012 David Anderson
    11.7 - *
    11.8 - * This file is part of SourcePawn.
    11.9 - *
   11.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   11.11 - * the terms of the GNU General Public License as published by the Free
   11.12 - * Software Foundation, either version 3 of the License, or (at your option)
   11.13 - * any later version.
   11.14 - * 
   11.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   11.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   11.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   11.18 - *
   11.19 - * You should have received a copy of the GNU General Public License along with
   11.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   11.21 - */
   11.22 -#ifndef _include_jitcraft_fixedarray_h_
   11.23 -#define _include_jitcraft_fixedarray_h_
   11.24 -
   11.25 -#include "Heap.h"
   11.26 -
   11.27 -namespace ke {
   11.28 -
   11.29 -// A fixed-length array that contains Object * slots.
   11.30 -class FixedArray : public Object
   11.31 -{
   11.32 -    uint32 length_;
   11.33 -
   11.34 -  private:
   11.35 -    Object **vec() {
   11.36 -        return reinterpret_cast<Object **>(this + 1);
   11.37 -    }
   11.38 -
   11.39 -  public:
   11.40 -    static FixedArray *New(Zone *zone, unsigned length, Heap::Tenure tenure);
   11.41 -
   11.42 -    unsigned length() {
   11.43 -        return length_;
   11.44 -    }
   11.45 -    Object *at(size_t i) {
   11.46 -        assert(i < length());
   11.47 -        return vec()[i];
   11.48 -    }
   11.49 -    void set(Zone *zone, size_t i, Object *obj) {
   11.50 -        assert(i < length());
   11.51 -        write(zone, &vec()[i], obj);
   11.52 -    }
   11.53 -    size_t objSize() {
   11.54 -        return SizeFor(length());
   11.55 -    }
   11.56 -
   11.57 -    static inline size_t SizeFor(unsigned length) {
   11.58 -        return sizeof(FixedArray) + sizeof(Object *) * length;
   11.59 -    }
   11.60 -
   11.61 -    static inline FixedArray *cast(Object *obj) {
   11.62 -        assert(!obj || obj->is(MapKind_FixedArray));
   11.63 -        return reinterpret_cast<FixedArray *>(obj);
   11.64 -    }
   11.65 -};
   11.66 -
   11.67 -// A fixed-length array containing raw bytes.
   11.68 -class ByteArray : public Object
   11.69 -{
   11.70 -    uint32 length_;
   11.71 -
   11.72 -  public:
   11.73 -    static ByteArray *New(Zone *zone, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
   11.74 -    static ByteArray *New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
   11.75 -
   11.76 -    unsigned length() {
   11.77 -        return length_;
   11.78 -    }
   11.79 -    Address raw() {
   11.80 -        return Address(this) + offsetToElements();
   11.81 -    }
   11.82 -    size_t objSize() {
   11.83 -        return SizeFor(length());
   11.84 -    }
   11.85 -
   11.86 -    static inline size_t offsetToElements() {
   11.87 -        return sizeof(ByteArray);
   11.88 -    }
   11.89 -
   11.90 -    static inline size_t SizeFor(unsigned length) {
   11.91 -        return sizeof(ByteArray) + sizeof(uint8) * length;
   11.92 -    }
   11.93 -
   11.94 -    static inline ByteArray *cast(Object *obj) {
   11.95 -        assert(!obj || obj->is(MapKind_ByteArray));
   11.96 -        return reinterpret_cast<ByteArray *>(obj);
   11.97 -    }
   11.98 -};
   11.99 -
  11.100 -}
  11.101 -
  11.102 -#endif // _include_jitcraft_fixedarray_h_
  11.103 +/* vim: set ts=4 sw=4 tw=99 et:
  11.104 + *
  11.105 + * Copyright (C) 2012 David Anderson
  11.106 + *
  11.107 + * This file is part of SourcePawn.
  11.108 + *
  11.109 + * SourcePawn is free software: you can redistribute it and/or modify it under
  11.110 + * the terms of the GNU General Public License as published by the Free
  11.111 + * Software Foundation, either version 3 of the License, or (at your option)
  11.112 + * any later version.
  11.113 + * 
  11.114 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  11.115 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11.116 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  11.117 + *
  11.118 + * You should have received a copy of the GNU General Public License along with
  11.119 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  11.120 + */
  11.121 +#ifndef _include_jitcraft_fixedarray_h_
  11.122 +#define _include_jitcraft_fixedarray_h_
  11.123 +
  11.124 +#include "Heap.h"
  11.125 +
  11.126 +namespace ke {
  11.127 +
  11.128 +// A fixed-length array that contains Object * slots.
  11.129 +class FixedArray : public Object
  11.130 +{
  11.131 +    uint32 length_;
  11.132 +
  11.133 +  private:
  11.134 +    Object **vec() {
  11.135 +        return reinterpret_cast<Object **>(this + 1);
  11.136 +    }
  11.137 +
  11.138 +  public:
  11.139 +    static FixedArray *New(Zone *zone, unsigned length, Heap::Tenure tenure);
  11.140 +
  11.141 +    unsigned length() {
  11.142 +        return length_;
  11.143 +    }
  11.144 +    Object *at(size_t i) {
  11.145 +        assert(i < length());
  11.146 +        return vec()[i];
  11.147 +    }
  11.148 +    void set(Zone *zone, size_t i, Object *obj) {
  11.149 +        assert(i < length());
  11.150 +        write(zone, &vec()[i], obj);
  11.151 +    }
  11.152 +    size_t objSize() {
  11.153 +        return SizeFor(length());
  11.154 +    }
  11.155 +
  11.156 +    static inline size_t SizeFor(unsigned length) {
  11.157 +        return sizeof(FixedArray) + sizeof(Object *) * length;
  11.158 +    }
  11.159 +
  11.160 +    static inline FixedArray *cast(Object *obj) {
  11.161 +        assert(!obj || obj->is(MapKind_FixedArray));
  11.162 +        return reinterpret_cast<FixedArray *>(obj);
  11.163 +    }
  11.164 +};
  11.165 +
  11.166 +// A fixed-length array containing raw bytes.
  11.167 +class ByteArray : public Object
  11.168 +{
  11.169 +    uint32 length_;
  11.170 +
  11.171 +  public:
  11.172 +    static ByteArray *New(Zone *zone, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
  11.173 +    static ByteArray *New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
  11.174 +
  11.175 +    unsigned length() {
  11.176 +        return length_;
  11.177 +    }
  11.178 +    Address raw() {
  11.179 +        return Address(this) + offsetToElements();
  11.180 +    }
  11.181 +    size_t objSize() {
  11.182 +        return SizeFor(length());
  11.183 +    }
  11.184 +
  11.185 +    static inline size_t offsetToElements() {
  11.186 +        return sizeof(ByteArray);
  11.187 +    }
  11.188 +
  11.189 +    static inline size_t SizeFor(unsigned length) {
  11.190 +        return sizeof(ByteArray) + sizeof(uint8) * length;
  11.191 +    }
  11.192 +
  11.193 +    static inline ByteArray *cast(Object *obj) {
  11.194 +        assert(!obj || obj->is(MapKind_ByteArray));
  11.195 +        return reinterpret_cast<ByteArray *>(obj);
  11.196 +    }
  11.197 +};
  11.198 +
  11.199 +}
  11.200 +
  11.201 +#endif // _include_jitcraft_fixedarray_h_
    12.1 --- a/src/Functions.cpp	Mon Jun 10 00:46:29 2013 +0100
    12.2 +++ b/src/Functions.cpp	Mon Jun 10 01:04:43 2013 +0100
    12.3 @@ -1,50 +1,50 @@
    12.4 -/*
    12.5 - * Copyright (C) 2012 David Anderson
    12.6 - *
    12.7 - * This file is part of SourcePawn.
    12.8 - *
    12.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   12.10 - * the terms of the GNU General Public License as published by the Free
   12.11 - * Software Foundation, either version 3 of the License, or (at your option)
   12.12 - * any later version.
   12.13 - * 
   12.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   12.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   12.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   12.17 - *
   12.18 - * You should have received a copy of the GNU General Public License along with
   12.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   12.20 - */
   12.21 -#include "Functions.h"
   12.22 -#include "Modules.h"
   12.23 -#include "Zone.h"
   12.24 -#include "Heap-inl.h"
   12.25 -
   12.26 -using namespace ke;
   12.27 -
   12.28 -Function *
   12.29 -Function::New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
   12.30 -              const SourcePosition &pos)
   12.31 -{
   12.32 -    Function *fun = Function::cast(zone->allocate(MapKind_Function, sizeof(Function), Heap::Tenure_Old));
   12.33 -    if (!fun)
   12.34 -        return NULL;
   12.35 -
   12.36 -    fun->code_ = code;
   12.37 -    fun->pos_ = pos;
   12.38 -    fun->type_ = type;
   12.39 -    fun->name_ = name;
   12.40 -    return fun;
   12.41 -}
   12.42 -
   12.43 -Native *
   12.44 -Native::New(Zone *zone, Handle<FunctionType> type, size_t index)
   12.45 -{
   12.46 -    Native *fun = Native::cast(zone->allocate(MapKind_Native, sizeof(Native), Heap::Tenure_Old));
   12.47 -    if (!fun)
   12.48 -        return NULL;
   12.49 -
   12.50 -    fun->type_ = type;
   12.51 -    fun->index_ = index;
   12.52 -    return fun;
   12.53 -}
   12.54 +/*
   12.55 + * Copyright (C) 2012 David Anderson
   12.56 + *
   12.57 + * This file is part of SourcePawn.
   12.58 + *
   12.59 + * SourcePawn is free software: you can redistribute it and/or modify it under
   12.60 + * the terms of the GNU General Public License as published by the Free
   12.61 + * Software Foundation, either version 3 of the License, or (at your option)
   12.62 + * any later version.
   12.63 + * 
   12.64 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   12.65 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   12.66 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   12.67 + *
   12.68 + * You should have received a copy of the GNU General Public License along with
   12.69 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   12.70 + */
   12.71 +#include "Functions.h"
   12.72 +#include "Modules.h"
   12.73 +#include "Zone.h"
   12.74 +#include "Heap-inl.h"
   12.75 +
   12.76 +using namespace ke;
   12.77 +
   12.78 +Function *
   12.79 +Function::New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
   12.80 +              const SourcePosition &pos)
   12.81 +{
   12.82 +    Function *fun = Function::cast(zone->allocate(MapKind_Function, sizeof(Function), Heap::Tenure_Old));
   12.83 +    if (!fun)
   12.84 +        return NULL;
   12.85 +
   12.86 +    fun->code_ = code;
   12.87 +    fun->pos_ = pos;
   12.88 +    fun->type_ = type;
   12.89 +    fun->name_ = name;
   12.90 +    return fun;
   12.91 +}
   12.92 +
   12.93 +Native *
   12.94 +Native::New(Zone *zone, Handle<FunctionType> type, size_t index)
   12.95 +{
   12.96 +    Native *fun = Native::cast(zone->allocate(MapKind_Native, sizeof(Native), Heap::Tenure_Old));
   12.97 +    if (!fun)
   12.98 +        return NULL;
   12.99 +
  12.100 +    fun->type_ = type;
  12.101 +    fun->index_ = index;
  12.102 +    return fun;
  12.103 +}
    13.1 --- a/src/Functions.h	Mon Jun 10 00:46:29 2013 +0100
    13.2 +++ b/src/Functions.h	Mon Jun 10 01:04:43 2013 +0100
    13.3 @@ -1,113 +1,113 @@
    13.4 -/*
    13.5 - * Copyright (C) 2012 David Anderson
    13.6 - *
    13.7 - * This file is part of SourcePawn.
    13.8 - *
    13.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   13.10 - * the terms of the GNU General Public License as published by the Free
   13.11 - * Software Foundation, either version 3 of the License, or (at your option)
   13.12 - * any later version.
   13.13 - * 
   13.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   13.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   13.17 - *
   13.18 - * You should have received a copy of the GNU General Public License along with
   13.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   13.20 - */
   13.21 -#ifndef _include_jitcraft_function_h_
   13.22 -#define _include_jitcraft_function_h_
   13.23 -
   13.24 -#include "Heap.h"
   13.25 -#include "Barriers.h"
   13.26 -#include "Types.h"
   13.27 -#include "Opcodes.h"
   13.28 -
   13.29 -namespace ke {
   13.30 -
   13.31 -class Code;
   13.32 -class Module;
   13.33 -class String;
   13.34 -
   13.35 -class Function : public Object
   13.36 -{
   13.37 -    Barriered<Code> code_;
   13.38 -    Barriered<FunctionType> type_;
   13.39 -    Barriered<String> name_;
   13.40 -    SourcePosition pos_;
   13.41 -
   13.42 - public:
   13.43 -    static Function *New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
   13.44 -                         const SourcePosition &pos);
   13.45 -
   13.46 -    Code *code() const {
   13.47 -        return code_;
   13.48 -    }
   13.49 -    FunctionType *type() const {
   13.50 -        return type_;
   13.51 -    }
   13.52 -    String *name() const {
   13.53 -        return name_;
   13.54 -    }
   13.55 -    const SourcePosition &pos() {
   13.56 -        return pos_;
   13.57 -    }
   13.58 -    unsigned nargs() {
   13.59 -        return type()->parameters()->length();
   13.60 -    }
   13.61 -    Type *argType(size_t index) {
   13.62 -        return type()->parameterAt(index);
   13.63 -    }
   13.64 -
   13.65 -    // Begin GC Descriptor.
   13.66 -    static inline size_t offsetOfCode() {
   13.67 -        return OFFSETOF(Function, code_);
   13.68 -    }
   13.69 -    static inline size_t offsetOfType() {
   13.70 -        return OFFSETOF(Function, type_);
   13.71 -    }
   13.72 -    static inline size_t offsetOfName() {
   13.73 -        return OFFSETOF(Function, name_);
   13.74 -    }
   13.75 -    // End GC Descriptor.
   13.76 -
   13.77 -    static inline Function *cast(Object *obj) {
   13.78 -        assert(!obj || obj->is(MapKind_Function));
   13.79 -        return reinterpret_cast<Function *>(obj);
   13.80 -    }
   13.81 -};
   13.82 -
   13.83 -// A Native is a function with a very specialized calling convention, intended
   13.84 -// for earlier ISourcePawnEngine API compatibility.
   13.85 -class Native : public Object
   13.86 -{
   13.87 -    Barriered<FunctionType> type_;
   13.88 -
   13.89 -    // Index into the Zone's native table.
   13.90 -    size_t index_;
   13.91 -
   13.92 -  public:
   13.93 -    static Native *New(Zone *zone, Handle<FunctionType> type, size_t index);
   13.94 -
   13.95 -    FunctionType *type() {
   13.96 -        return type_;
   13.97 -    }
   13.98 -    size_t index() const {
   13.99 -        return index_;
  13.100 -    }
  13.101 -
  13.102 -    // Begin GC Descriptor.
  13.103 -    static inline size_t offsetOfType() {
  13.104 -        return OFFSETOF(Native, type_);
  13.105 -    }
  13.106 -    // End GC Descriptor.
  13.107 -
  13.108 -    static inline Native *cast(Object *obj) {
  13.109 -        assert(!obj || obj->is(MapKind_Native));
  13.110 -        return reinterpret_cast<Native *>(obj);
  13.111 -    }
  13.112 -};
  13.113 -
  13.114 -}
  13.115 -
  13.116 -#endif // _include_jitcraft_function_h_
  13.117 +/*
  13.118 + * Copyright (C) 2012 David Anderson
  13.119 + *
  13.120 + * This file is part of SourcePawn.
  13.121 + *
  13.122 + * SourcePawn is free software: you can redistribute it and/or modify it under
  13.123 + * the terms of the GNU General Public License as published by the Free
  13.124 + * Software Foundation, either version 3 of the License, or (at your option)
  13.125 + * any later version.
  13.126 + * 
  13.127 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  13.128 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13.129 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13.130 + *
  13.131 + * You should have received a copy of the GNU General Public License along with
  13.132 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  13.133 + */
  13.134 +#ifndef _include_jitcraft_function_h_
  13.135 +#define _include_jitcraft_function_h_
  13.136 +
  13.137 +#include "Heap.h"
  13.138 +#include "Barriers.h"
  13.139 +#include "Types.h"
  13.140 +#include "Opcodes.h"
  13.141 +
  13.142 +namespace ke {
  13.143 +
  13.144 +class Code;
  13.145 +class Module;
  13.146 +class String;
  13.147 +
  13.148 +class Function : public Object
  13.149 +{
  13.150 +    Barriered<Code> code_;
  13.151 +    Barriered<FunctionType> type_;
  13.152 +    Barriered<String> name_;
  13.153 +    SourcePosition pos_;
  13.154 +
  13.155 + public:
  13.156 +    static Function *New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
  13.157 +                         const SourcePosition &pos);
  13.158 +
  13.159 +    Code *code() const {
  13.160 +        return code_;
  13.161 +    }
  13.162 +    FunctionType *type() const {
  13.163 +        return type_;
  13.164 +    }
  13.165 +    String *name() const {
  13.166 +        return name_;
  13.167 +    }
  13.168 +    const SourcePosition &pos() {
  13.169 +        return pos_;
  13.170 +    }
  13.171 +    unsigned nargs() {
  13.172 +        return type()->parameters()->length();
  13.173 +    }
  13.174 +    Type *argType(size_t index) {
  13.175 +        return type()->parameterAt(index);
  13.176 +    }
  13.177 +
  13.178 +    // Begin GC Descriptor.
  13.179 +    static inline size_t offsetOfCode() {
  13.180 +        return OFFSETOF(Function, code_);
  13.181 +    }
  13.182 +    static inline size_t offsetOfType() {
  13.183 +        return OFFSETOF(Function, type_);
  13.184 +    }
  13.185 +    static inline size_t offsetOfName() {
  13.186 +        return OFFSETOF(Function, name_);
  13.187 +    }
  13.188 +    // End GC Descriptor.
  13.189 +
  13.190 +    static inline Function *cast(Object *obj) {
  13.191 +        assert(!obj || obj->is(MapKind_Function));
  13.192 +        return reinterpret_cast<Function *>(obj);
  13.193 +    }
  13.194 +};
  13.195 +
  13.196 +// A Native is a function with a very specialized calling convention, intended
  13.197 +// for earlier ISourcePawnEngine API compatibility.
  13.198 +class Native : public Object
  13.199 +{
  13.200 +    Barriered<FunctionType> type_;
  13.201 +
  13.202 +    // Index into the Zone's native table.
  13.203 +    size_t index_;
  13.204 +
  13.205 +  public:
  13.206 +    static Native *New(Zone *zone, Handle<FunctionType> type, size_t index);
  13.207 +
  13.208 +    FunctionType *type() {
  13.209 +        return type_;
  13.210 +    }
  13.211 +    size_t index() const {
  13.212 +        return index_;
  13.213 +    }
  13.214 +
  13.215 +    // Begin GC Descriptor.
  13.216 +    static inline size_t offsetOfType() {
  13.217 +        return OFFSETOF(Native, type_);
  13.218 +    }
  13.219 +    // End GC Descriptor.
  13.220 +
  13.221 +    static inline Native *cast(Object *obj) {
  13.222 +        assert(!obj || obj->is(MapKind_Native));
  13.223 +        return reinterpret_cast<Native *>(obj);
  13.224 +    }
  13.225 +};
  13.226 +
  13.227 +}
  13.228 +
  13.229 +#endif // _include_jitcraft_function_h_
    14.1 --- a/src/Interpreter.cpp	Mon Jun 10 00:46:29 2013 +0100
    14.2 +++ b/src/Interpreter.cpp	Mon Jun 10 01:04:43 2013 +0100
    14.3 @@ -1,1041 +1,1041 @@
    14.4 -/* vim: set ts=4 sw=4 tw=99 et:
    14.5 - *
    14.6 - * Copyright (C) 2012 David Anderson
    14.7 - *
    14.8 - * This file is part of JITCraft.
    14.9 - *
   14.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   14.11 - * the terms of the GNU General Public License as published by the Free
   14.12 - * Software Foundation, either version 3 of the License, or (at your option)
   14.13 - * any later version.
   14.14 - * 
   14.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   14.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   14.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   14.18 - *
   14.19 - * You should have received a copy of the GNU General Public License along with
   14.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   14.21 - */
   14.22 -#include <string.h>
   14.23 -#include "Interpreter.h"
   14.24 -#include "Modules.h"
   14.25 -#include "Zone.h"
   14.26 -#include "Types.h"
   14.27 -#include "Array.h"
   14.28 -#include "Reference.h"
   14.29 -#include "Strings.h"
   14.30 -#include "Environments.h"
   14.31 -#include "Structures.h"
   14.32 -#include "NativeTable.h"
   14.33 -#include "Packages.h"
   14.34 -#include "Heap-inl.h"
   14.35 -
   14.36 -using namespace ke;
   14.37 -
   14.38 -#define PUSH_I32(top, value)    \
   14.39 -    do {                        \
   14.40 -        top.sp->i32 = value;    \
   14.41 -        top.sp++;               \
   14.42 -   } while (0)
   14.43 -
   14.44 -#define PUSH_F(top, value)      \
   14.45 -    do {                        \
   14.46 -        top.sp->f = value;      \
   14.47 -        top.sp++;               \
   14.48 -   } while (0)
   14.49 -
   14.50 -static inline int
   14.51 -POP_I32(Top &top)
   14.52 -{
   14.53 -    int value = top.sp[-1].i32;
   14.54 -    top.sp--;
   14.55 -    return value;
   14.56 -}
   14.57 -
   14.58 -static inline float
   14.59 -POP_F(Top &top)
   14.60 -{
   14.61 -    float value = top.sp[-1].f;
   14.62 -    top.sp--;
   14.63 -    return value;
   14.64 -}
   14.65 -
   14.66 -// Pawn's original semantics specify some kind of floor operation, so
   14.67 -// (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
   14.68 -// the upstream algorithm when constant folding. However the SourcePawn 1 JIT
   14.69 -// does not. My guess is that Borja freaked out seeing the 13-instruction x86
   14.70 -// sequence necessary to get this functionality (I vaguely recall a thread
   14.71 -// where we discussed this with Mark Peter? But the ITB forums are gone...),
   14.72 -// and we just decided to break the damn thing. So SP1 was inconsistent, but
   14.73 -// we are not. And for completeness, we assert that the C compiler does the
   14.74 -// right thing, since C89 leaves it unspecified.
   14.75 -STATIC_ASSERT(8 / -3 == -2);
   14.76 -STATIC_ASSERT(-8 / 3 == -2);
   14.77 -
   14.78 -static inline bool
   14.79 -PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
   14.80 -{
   14.81 -    Reference *ref = Reference::NewStack(zone, location, tenure);
   14.82 -    if (!ref)
   14.83 -        return false;
   14.84 -    top.sp->ref = ref;
   14.85 -    top.sp++;
   14.86 -    return true;
   14.87 -}
   14.88 -
   14.89 -static void
   14.90 -GetElement(Array *array, int index, LocalSlot *vp)
   14.91 -{
   14.92 -    if (array->type()->contained()->isTraceable()) {
   14.93 -        vp->obj = array->readObject(index);
   14.94 -        return;
   14.95 -    }
   14.96 -
   14.97 -    switch (array->type()->contained()->pod()) {
   14.98 -      case PrimitiveType_Float:
   14.99 -        vp->f = array->readFloat(index);
  14.100 -        break;
  14.101 -
  14.102 -      case PrimitiveType_Char:
  14.103 -        vp->i32 = array->readChar(index);
  14.104 -        break;
  14.105 -
  14.106 -      default:
  14.107 -        assert(array->type()->contained()->pod() == PrimitiveType_Int32);
  14.108 -        vp->i32 = array->readInt32(index);
  14.109 -        break;
  14.110 -    }
  14.111 -}
  14.112 -
  14.113 -static void
  14.114 -SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
  14.115 -{
  14.116 -    if (array->type()->contained()->isTraceable()) {
  14.117 -        array->writeObject(zone, index, v.obj);
  14.118 -        return;
  14.119 -    }
  14.120 -
  14.121 -    switch (array->type()->contained()->pod()) {
  14.122 -      case PrimitiveType_Float:
  14.123 -        array->writeFloat(index, v.f);
  14.124 -        break;
  14.125 -
  14.126 -      case PrimitiveType_Char:
  14.127 -        array->writeChar(index, v.i32);
  14.128 -        break;
  14.129 -
  14.130 -      default:
  14.131 -        assert(array->type()->contained()->pod() == PrimitiveType_Int32);
  14.132 -        array->writeInt32(index, v.i32);
  14.133 -        break;
  14.134 -    }
  14.135 -}
  14.136 -
  14.137 -static void
  14.138 -FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp)
  14.139 -{
  14.140 -    // :TODO: assert no GC.
  14.141 -    if (desc->type()->isTraceable()) {
  14.142 -        vp->obj = obj->get<Object *>(desc);
  14.143 -        return;
  14.144 -    }
  14.145 -
  14.146 -    switch (desc->type()->pod()) {
  14.147 -      case PrimitiveType_Float:
  14.148 -        vp->f = obj->get<float>(desc);
  14.149 -        break;
  14.150 -
  14.151 -      default:
  14.152 -        assert(desc->type()->pod() == PrimitiveType_Int32);
  14.153 -        vp->i32 = obj->get<int>(desc);
  14.154 -        break;
  14.155 -    }
  14.156 -}
  14.157 -
  14.158 -static void
  14.159 -GetField(Struct *obj, unsigned index, LocalSlot *vp)
  14.160 -{
  14.161 -    StructType *type = StructType::cast(obj->map()->type());
  14.162 -    Descriptor *desc = Descriptor::cast(type->fields()->at(index));
  14.163 -    FetchField(obj, desc, vp);
  14.164 -}
  14.165 -
  14.166 -static void
  14.167 -GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
  14.168 -{
  14.169 -    Local<StructType> type(zone, StructType::cast(obj->map()->type()));
  14.170 -    Local<Descriptor> desc(zone, type->lookupField(name, NULL));
  14.171 -    FetchField(obj, desc, vp);
  14.172 -}
  14.173 -
  14.174 -static void
  14.175 -StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
  14.176 -{
  14.177 -    // :TODO: assert no GC.
  14.178 -    if (desc->type()->isTraceable()) {
  14.179 -        obj->set(zone, desc, v.obj);
  14.180 -        return;
  14.181 -    }
  14.182 -
  14.183 -    switch (desc->type()->pod()) {
  14.184 -      case PrimitiveType_Float:
  14.185 -        obj->set<float>(desc, v.f);
  14.186 -        break;
  14.187 -
  14.188 -      default:
  14.189 -        assert(desc->type()->pod() == PrimitiveType_Int32);
  14.190 -        obj->set<int>(desc, v.i32);
  14.191 -        break;
  14.192 -    }
  14.193 -}
  14.194 -
  14.195 -static void
  14.196 -SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
  14.197 -{
  14.198 -    StructType *type = StructType::cast(obj->map()->type());
  14.199 -    Descriptor *desc = Descriptor::cast(type->fields()->at(index));
  14.200 -    StoreField(zone, obj, desc, v);
  14.201 -}
  14.202 -
  14.203 -static void
  14.204 -SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
  14.205 -{
  14.206 -    Local<StructType> type(zone, StructType::cast(obj->map()->type()));
  14.207 -    Local<Descriptor> desc(zone, type->lookupField(name, NULL));
  14.208 -    StoreField(zone, obj, desc, v);
  14.209 -}
  14.210 -
  14.211 -static bool
  14.212 -InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
  14.213 -             int *result)
  14.214 -{
  14.215 -    NativeArgs guard;
  14.216 -
  14.217 -    void *address = zone->nativeTable()->address(native->index());
  14.218 -    if (!address) {
  14.219 -        Local<String> name(zone, zone->nativeTable()->name(native->index()));
  14.220 -        zone->reportError(Message_NativeNotBound, name->chars());
  14.221 -        return false;
  14.222 -    }
  14.223 -
  14.224 -    if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
  14.225 -        return false;
  14.226 -
  14.227 -    intptr_t *cells = guard.args();
  14.228 -
  14.229 -    // params[0] == argc, in ISPE
  14.230 -    cells[0] = argc;
  14.231 -
  14.232 -    // Pass the formal arguments.
  14.233 -    Local<FunctionType> type(zone, native->type());
  14.234 -    Local<Type> param(zone);
  14.235 -    for (unsigned i = 0; i < type->parameters()->length(); i++) {
  14.236 -        param = type->parameterAt(i);
  14.237 -        
  14.238 -        // For floats, we rely on the aliasing of |i32| and |f|.
  14.239 -        LocalSlot &arg = args[-int(i) - 1];
  14.240 -        if (param->isInt32() || param->isFloat()) {
  14.241 -            cells[i + 1] = arg.i32;
  14.242 -        } else if (param->isReference()) {
  14.243 -            cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
  14.244 -        } else {
  14.245 -            assert(param->isArray());
  14.246 -            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
  14.247 -        }
  14.248 -    }
  14.249 -
  14.250 -    // For variadic arguments, the compiler left either arrays or references.
  14.251 -    for (unsigned i = type->parameters()->length(); i < argc; i++) {
  14.252 -        LocalSlot &arg = args[-int(i) - 1];
  14.253 -
  14.254 -        if (arg.obj->is(MapKind_Reference)) {
  14.255 -            cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
  14.256 -        } else {
  14.257 -            assert(arg.obj->is(MapKind_Array));
  14.258 -            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
  14.259 -        }
  14.260 -    }
  14.261 -
  14.262 -    typedef intptr_t (*INVOKE)(void *, intptr_t *);
  14.263 -    INVOKE invoke = (INVOKE)address;
  14.264 -    *result = invoke(identity, cells);
  14.265 -
  14.266 -    return !zone->hasPendingException();
  14.267 -}
  14.268 -
  14.269 -bool
  14.270 -ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
  14.271 -{
  14.272 -    Top &top = *zone->stack().top();
  14.273 -    if (!entryFrame)
  14.274 -        entryFrame = top.fp;
  14.275 -
  14.276 -    LocalSlot *locals = entryFrame->locals();
  14.277 -
  14.278 -    for (;;) {
  14.279 -        Opcode op = Opcode(*top.pc);
  14.280 -
  14.281 -        if (OpcodeInfo[op].nuses > 0)
  14.282 -            assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
  14.283 -
  14.284 -        switch (op) {
  14.285 -
  14.286 -case OP_NOP:
  14.287 -    break;
  14.288 -
  14.289 -case OP_INT:
  14.290 -    PUSH_I32(top, READ_INT32(top.pc));
  14.291 -    break;
  14.292 -
  14.293 -case OP_FLOAT:
  14.294 -    PUSH_F(top, READ_FLOAT(top.pc));
  14.295 -    break;
  14.296 -
  14.297 -case OP_RETURN:
  14.298 -case OP_RETURNVOID:
  14.299 -case OP_STOP:
  14.300 -{
  14.301 -    if (op == OP_RETURN)
  14.302 -        *result = *--top.sp;
  14.303 -
  14.304 -    if (top.fp == entryFrame)
  14.305 -        goto done;
  14.306 -
  14.307 -    // This must not GC.
  14.308 -    zone->stack().popInlineFrame();
  14.309 -    locals = top.fp->locals();
  14.310 -
  14.311 -    if (op == OP_RETURN)
  14.312 -        *top.sp++ = *result;
  14.313 -
  14.314 -    top.pc += OpcodeInfo[*top.pc].length;
  14.315 -    continue;
  14.316 -}
  14.317 -
  14.318 -case OP_POP:
  14.319 -{
  14.320 -    top.sp--;
  14.321 -    break;
  14.322 -}
  14.323 -
  14.324 -case OP_JT:
  14.325 -{
  14.326 -    int value = POP_I32(top);
  14.327 -    if (value) {
  14.328 -        top.pc += READ_INT32(top.pc);
  14.329 -        continue;
  14.330 -    }
  14.331 -    break;
  14.332 -}
  14.333 -
  14.334 -case OP_JF:
  14.335 -{
  14.336 -    int value = POP_I32(top);
  14.337 -    if (!value) {
  14.338 -        top.pc += READ_INT32(top.pc);
  14.339 -        continue;
  14.340 -    }
  14.341 -    break;
  14.342 -}
  14.343 -
  14.344 -case OP_JUMP:
  14.345 -{
  14.346 -    top.pc += READ_INT32(top.pc);
  14.347 -    continue;
  14.348 -}
  14.349 -
  14.350 -case OP_BREAK:
  14.351 -case OP_CONTINUE:
  14.352 -{
  14.353 -    top.fp->leaveLoop(zone);
  14.354 -    top.pc += READ_INT32(top.pc);
  14.355 -    continue;
  14.356 -}
  14.357 -
  14.358 -case OP_GETLOCAL:
  14.359 -{
  14.360 -    unsigned slot = READ_UINT32(top.pc);
  14.361 -    assert(slot < top.fp->code()->nlocals());
  14.362 -    *top.sp++ = locals[slot];
  14.363 -    break;
  14.364 -}
  14.365 -
  14.366 -case OP_SETLOCAL:
  14.367 -{
  14.368 -    unsigned slot = READ_UINT32(top.pc);
  14.369 -    assert(slot < top.fp->code()->nlocals());
  14.370 -    locals[slot] = top.sp[-1];
  14.371 -    break;
  14.372 -}
  14.373 -
  14.374 -case OP_ADD:
  14.375 -{
  14.376 -    top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
  14.377 -    top.sp--;
  14.378 -    break;
  14.379 -}
  14.380 -
  14.381 -case OP_SUB:
  14.382 -{
  14.383 -    top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
  14.384 -    top.sp--;
  14.385 -    break;
  14.386 -}
  14.387 -
  14.388 -case OP_MUL:
  14.389 -{
  14.390 -    top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
  14.391 -    top.sp--;
  14.392 -    break;
  14.393 -}
  14.394 -
  14.395 -case OP_DIV:
  14.396 -{
  14.397 -    if (top.sp[-1].i32 == 0) {
  14.398 -        zone->reportError(Message_IntegerDivideByZero);
  14.399 -        goto error;
  14.400 -    }
  14.401 -    top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
  14.402 -    top.sp--;
  14.403 -    break;
  14.404 -}
  14.405 -
  14.406 -case OP_MOD:
  14.407 -{
  14.408 -    if (top.sp[-1].i32 == 0) {
  14.409 -        zone->reportError(Message_IntegerDivideByZero);
  14.410 -        goto error;
  14.411 -    }
  14.412 -    top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
  14.413 -    top.sp--;
  14.414 -    break;
  14.415 -}
  14.416 -
  14.417 -case OP_LT:
  14.418 -{
  14.419 -    top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
  14.420 -    top.sp--;
  14.421 -    break;
  14.422 -}
  14.423 -
  14.424 -case OP_LE:
  14.425 -{
  14.426 -    top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
  14.427 -    top.sp--;
  14.428 -    break;
  14.429 -}
  14.430 -
  14.431 -case OP_GT:
  14.432 -{
  14.433 -    top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
  14.434 -    top.sp--;
  14.435 -    break;
  14.436 -}
  14.437 -
  14.438 -case OP_GE:
  14.439 -{
  14.440 -    top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
  14.441 -    top.sp--;
  14.442 -    break;
  14.443 -}
  14.444 -
  14.445 -case OP_EQ:
  14.446 -{
  14.447 -    top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
  14.448 -    top.sp--;
  14.449 -    break;
  14.450 -}
  14.451 -
  14.452 -case OP_NE:
  14.453 -{
  14.454 -    top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
  14.455 -    top.sp--;
  14.456 -    break;
  14.457 -}
  14.458 -
  14.459 -case OP_ADD_F:
  14.460 -{
  14.461 -    top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
  14.462 -    top.sp--;
  14.463 -    break;
  14.464 -}
  14.465 -
  14.466 -case OP_SUB_F:
  14.467 -{
  14.468 -    top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
  14.469 -    top.sp--;
  14.470 -    break;
  14.471 -}
  14.472 -
  14.473 -case OP_MUL_F:
  14.474 -{
  14.475 -    top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
  14.476 -    top.sp--;
  14.477 -    break;
  14.478 -}
  14.479 -
  14.480 -case OP_DIV_F:
  14.481 -{
  14.482 -    top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
  14.483 -    top.sp--;
  14.484 -    break;
  14.485 -}
  14.486 -
  14.487 -case OP_LT_F:
  14.488 -{
  14.489 -    top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
  14.490 -    top.sp--;
  14.491 -    break;
  14.492 -}
  14.493 -
  14.494 -case OP_LE_F:
  14.495 -{
  14.496 -    top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
  14.497 -    top.sp--;
  14.498 -    break;
  14.499 -}
  14.500 -
  14.501 -case OP_GT_F:
  14.502 -{
  14.503 -    top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
  14.504 -    top.sp--;
  14.505 -    break;
  14.506 -}
  14.507 -
  14.508 -case OP_GE_F:
  14.509 -{
  14.510 -    top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
  14.511 -    top.sp--;
  14.512 -    break;
  14.513 -}
  14.514 -
  14.515 -case OP_EQ_F:
  14.516 -{
  14.517 -    top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
  14.518 -    top.sp--;
  14.519 -    break;
  14.520 -}
  14.521 -
  14.522 -case OP_NE_F:
  14.523 -{
  14.524 -    top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
  14.525 -    top.sp--;
  14.526 -    break;
  14.527 -}
  14.528 -
  14.529 -case OP_SHL:
  14.530 -{
  14.531 -    top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
  14.532 -    top.sp--;
  14.533 -    break;
  14.534 -}
  14.535 -
  14.536 -case OP_SHR:
  14.537 -{
  14.538 -    top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
  14.539 -    top.sp--;
  14.540 -    break;
  14.541 -}
  14.542 -
  14.543 -case OP_USHR:
  14.544 -{
  14.545 -    top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32);
  14.546 -    top.sp--;
  14.547 -    break;
  14.548 -}
  14.549 -
  14.550 -case OP_BITAND:
  14.551 -{
  14.552 -    top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
  14.553 -    top.sp--;
  14.554 -    break;
  14.555 -}
  14.556 -
  14.557 -case OP_BITOR:
  14.558 -{
  14.559 -    top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
  14.560 -    top.sp--;
  14.561 -    break;
  14.562 -}
  14.563 -
  14.564 -case OP_BITXOR:
  14.565 -{
  14.566 -    top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
  14.567 -    top.sp--;
  14.568 -    break;
  14.569 -}
  14.570 -
  14.571 -case OP_BITNOT:
  14.572 -{
  14.573 -    top.sp[-1].i32 = ~top.sp[-1].i32;
  14.574 -    break;
  14.575 -}
  14.576 -
  14.577 -case OP_NOT:
  14.578 -{
  14.579 -    top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
  14.580 -    break;
  14.581 -}
  14.582 -
  14.583 -case OP_NOT_F:
  14.584 -{
  14.585 -    top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
  14.586 -    break;
  14.587 -}
  14.588 -
  14.589 -case OP_NEG:
  14.590 -{
  14.591 -    top.sp[-1].i32 = -top.sp[-1].i32;
  14.592 -    break;
  14.593 -}
  14.594 -
  14.595 -case OP_NEG_F:
  14.596 -{
  14.597 -    top.sp[-1].f = -top.sp[-1].f;
  14.598 -    break;
  14.599 -}
  14.600 -
  14.601 -case OP_CALL:
  14.602 -{
  14.603 -    Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
  14.604 -    top.sp--;
  14.605 -
  14.606 -    if (!zone->stack().pushInlineFrame(newFun))
  14.607 -        goto error;
  14.608 -
  14.609 -    locals = top.fp->locals();
  14.610 -    continue;
  14.611 -}
  14.612 -
  14.613 -case OP_GETARG:
  14.614 -{
  14.615 -    unsigned slot = READ_UINT32(top.pc);
  14.616 -    *top.sp++ = top.fp->arg(slot);
  14.617 -    break;
  14.618 -}
  14.619 -
  14.620 -case OP_SETARG:
  14.621 -{
  14.622 -    unsigned slot = READ_UINT32(top.pc);
  14.623 -    top.fp->arg(slot) = top.sp[-1];
  14.624 -    break;
  14.625 -}
  14.626 -
  14.627 -case OP_GETELEM:
  14.628 -{
  14.629 -    Array *array = Array::cast(top.sp[-2].obj);
  14.630 -    int index = top.sp[-1].i32;
  14.631 -
  14.632 -    if (index < 0 || unsigned(index) >= array->length()) {
  14.633 -        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
  14.634 -        goto error;
  14.635 -    }
  14.636 -
  14.637 -    GetElement(array, index, &top.sp[-2]);
  14.638 -    top.sp--;
  14.639 -    break;
  14.640 -}
  14.641 -
  14.642 -case OP_SETELEM:
  14.643 -{
  14.644 -    Array *array = Array::cast(top.sp[-3].obj);
  14.645 -    int index = top.sp[-2].i32;
  14.646 -
  14.647 -    if (index < 0 || unsigned(index) >= array->length()) {
  14.648 -        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
  14.649 -        goto error;
  14.650 -    }
  14.651 -
  14.652 -    SetElement(zone, array, index, top.sp[-1]);
  14.653 -    top.sp[-3] = top.sp[-1];
  14.654 -    top.sp -= 2;
  14.655 -    break;
  14.656 -}
  14.657 -
  14.658 -case OP_CVT_I2F:
  14.659 -{
  14.660 -    int ival = POP_I32(top);
  14.661 -    float fval = (float)ival;
  14.662 -    PUSH_F(top, fval);
  14.663 -    break;
  14.664 -}
  14.665 -
  14.666 -case OP_CVT_I2B:
  14.667 -{
  14.668 -    top.sp[-1].i32 = !!top.sp[-1].i32;
  14.669 -    break;
  14.670 -}
  14.671 -
  14.672 -case OP_DUPARRAY:
  14.673 -{
  14.674 -    Local<Array> src(zone, Array::cast(top.sp[-1].obj));
  14.675 -    top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
  14.676 -    if (!top.sp[-1].obj)
  14.677 -        goto error;
  14.678 -    break;
  14.679 -}
  14.680 -
  14.681 -case OP_NEWFIXED:
  14.682 -{
  14.683 -    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
  14.684 -    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
  14.685 -    Array *array = Array::NewFixed(zone, map, tenure);
  14.686 -    if (!array)
  14.687 -        goto error;
  14.688 -    top.sp->obj = array;
  14.689 -    top.sp++;
  14.690 -    break;
  14.691 -}
  14.692 -
  14.693 -case OP_NEWEMPTY:
  14.694 -{
  14.695 -    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
  14.696 -    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
  14.697 -    Array *array = Array::NewEmpty(zone, map, tenure);
  14.698 -    if (!array)
  14.699 -        goto error;
  14.700 -    top.sp->obj = array;
  14.701 -    top.sp++;
  14.702 -    break;
  14.703 -}
  14.704 -
  14.705 -case OP_NEWSIZED:
  14.706 -{
  14.707 -    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
  14.708 -    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
  14.709 -    assert(map->type()->levels() < MAX_ARRAY_DEPTH);
  14.710 -
  14.711 -    int dims[MAX_ARRAY_DEPTH];
  14.712 -    for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
  14.713 -        dims[i] = POP_I32(top);
  14.714 -
  14.715 -    Array *array = Array::NewSized(zone, map, dims, tenure);
  14.716 -    if (!array)
  14.717 -        goto error;
  14.718 -    top.sp->obj = array;
  14.719 -    top.sp++;
  14.720 -    break;
  14.721 -}
  14.722 -
  14.723 -case OP_NEWSTRUCT:
  14.724 -{
  14.725 -    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
  14.726 -    Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
  14.727 -    top.sp->obj = Struct::New(zone, map, tenure);
  14.728 -    if (!top.sp->obj)
  14.729 -        goto error;
  14.730 -    top.sp++;
  14.731 -    break;
  14.732 -}
  14.733 -
  14.734 -case OP_SAVELIFO:
  14.735 -{
  14.736 -    unsigned slot = READ_UINT32(top.pc);
  14.737 -    locals[slot].address = zone->heap().lifoPosition();
  14.738 -    break;
  14.739 -}
  14.740 -
  14.741 -case OP_UNWINDLIFO:
  14.742 -{
  14.743 -    unsigned slot = READ_UINT32(top.pc);
  14.744 -    zone->heap().unwindLifo(locals[slot].address);
  14.745 -    break;
  14.746 -}
  14.747 -
  14.748 -case OP_VARREF_LIFO:
  14.749 -{
  14.750 -    unsigned slot = READ_UINT32(top.pc);
  14.751 -    if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
  14.752 -        goto error;
  14.753 -    break;
  14.754 -}
  14.755 -
  14.756 -case OP_ARGREF_LIFO:
  14.757 -{
  14.758 -    unsigned slot = READ_UINT32(top.pc);
  14.759 -    if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
  14.760 -        goto error;
  14.761 -    break;
  14.762 -}
  14.763 -
  14.764 -case OP_SLOTREF_LIFO:
  14.765 -{
  14.766 -    Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
  14.767 -    if (!ref)
  14.768 -        goto error;
  14.769 -    top.sp[-1].ref = ref;
  14.770 -    break;
  14.771 -}
  14.772 -
  14.773 -case OP_GETREF_I:
  14.774 -{
  14.775 -    top.sp[-1].i32 = top.sp[-1].ref->getInt();
  14.776 -    break;
  14.777 -}
  14.778 -
  14.779 -case OP_SETREF_I:
  14.780 -{
  14.781 -    top.sp[-2].ref->setInt(top.sp[-1].i32);
  14.782 -    top.sp[-2].i32 = top.sp[-1].i32;
  14.783 -    top.sp--;
  14.784 -    break;
  14.785 -}
  14.786 -
  14.787 -case OP_GETREF_F:
  14.788 -{
  14.789 -    top.sp[-1].f = top.sp[-1].ref->getFloat();
  14.790 -    break;
  14.791 -}
  14.792 -
  14.793 -case OP_SETREF_F:
  14.794 -{
  14.795 -    top.sp[-2].ref->setFloat(top.sp[-1].f);
  14.796 -    top.sp[-2].f = top.sp[-1].f;
  14.797 -    break;
  14.798 -}
  14.799 -
  14.800 -case OP_OBJECT:
  14.801 -{
  14.802 -    top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
  14.803 -    top.sp++;
  14.804 -    break;
  14.805 -}
  14.806 -
  14.807 -case OP_COPYARRAY:
  14.808 -{
  14.809 -    // Note for this assignment opcode, we return the left-hand side, not the
  14.810 -    // right, since in this case the result of the expression could be different.
  14.811 -    Local<Array> left(zone, Array::cast(top.sp[-2].array));
  14.812 -    Local<Array> right(zone, Array::cast(top.sp[-1].array));
  14.813 -    if (!Array::ShallowCopy(zone, left, right))
  14.814 -        goto error;
  14.815 -    top.sp--;
  14.816 -    break;
  14.817 -}
  14.818 -
  14.819 -case OP_DUP:
  14.820 -{
  14.821 -    top.sp++;
  14.822 -    top.sp[-1] = top.sp[-2];
  14.823 -    break;
  14.824 -}
  14.825 -
  14.826 -case OP_DUP2:
  14.827 -{
  14.828 -    top.sp += 2;
  14.829 -    top.sp[-2] = top.sp[-4];
  14.830 -    top.sp[-1] = top.sp[-3];
  14.831 -    break;
  14.832 -}
  14.833 -
  14.834 -case OP_SWAP:
  14.835 -{
  14.836 -    LocalSlot slot = top.sp[-2];
  14.837 -    top.sp[-2] = top.sp[-1];
  14.838 -    top.sp[-1] = slot;
  14.839 -    break;
  14.840 -}
  14.841 -
  14.842 -case OP_ROLL3:
  14.843 -{
  14.844 -    LocalSlot slot = top.sp[-3];
  14.845 -    top.sp[-3] = top.sp[-2];
  14.846 -    top.sp[-2] = top.sp[-1];
  14.847 -    top.sp[-1] = slot;
  14.848 -    break;
  14.849 -}
  14.850 -
  14.851 -case OP_PICK2:
  14.852 -{
  14.853 -    top.sp++;
  14.854 -    top.sp[-1] = top.sp[-3];
  14.855 -    break;
  14.856 -}
  14.857 -
  14.858 -case OP_PICK3:
  14.859 -{
  14.860 -    top.sp++;
  14.861 -    top.sp[-1] = top.sp[-4];
  14.862 -    break;
  14.863 -}
  14.864 -
  14.865 -case OP_CALLNATIVE:
  14.866 -{
  14.867 -    unsigned argc = READ_UINT32(top.pc);
  14.868 -
  14.869 -    Local<Native> native(zone, Native::cast(top.sp[-1].obj));
  14.870 -    top.sp--;
  14.871 -
  14.872 -    int result;
  14.873 -    void *nativeIdentity = top.fp->code()->module()->parent()->getNativeIdentity();
  14.874 -    if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
  14.875 -        goto error;
  14.876 -
  14.877 -    top.sp -= argc;
  14.878 -    PUSH_I32(top, result);
  14.879 -    break;
  14.880 -}
  14.881 -
  14.882 -case OP_BITCAST:
  14.883 -{
  14.884 -    // Because the stack is a union, this is a no-op.
  14.885 -    break;
  14.886 -}
  14.887 -
  14.888 -case OP_TRUE:
  14.889 -{
  14.890 -    top.sp++;
  14.891 -    top.sp[-1].i32 = 1;
  14.892 -    break;
  14.893 -}
  14.894 -
  14.895 -case OP_FALSE:
  14.896 -{
  14.897 -    top.sp++;
  14.898 -    top.sp[-1].i32 = 0;
  14.899 -    break;
  14.900 -}
  14.901 -
  14.902 -case OP_GETFIELD:
  14.903 -{
  14.904 -    Struct *obj;
  14.905 -    if (top.sp[-1].obj->is(MapKind_Module))
  14.906 -        obj = Module::cast(top.sp[-1].obj)->globals();
  14.907 -    else
  14.908 -        obj = Struct::cast(top.sp[-1].obj);
  14.909 -    GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
  14.910 -    break;
  14.911 -}
  14.912 -
  14.913 -case OP_SETFIELD:
  14.914 -{
  14.915 -    Struct *obj = Struct::cast(top.sp[-2].obj);
  14.916 -    SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
  14.917 -    top.sp[-2] = top.sp[-1];
  14.918 -    top.sp--;
  14.919 -    break;
  14.920 -}
  14.921 -
  14.922 -case OP_COPYSTRUCT:
  14.923 -{
  14.924 -    Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
  14.925 -    Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
  14.926 -    if (!Struct::Copy(zone, left, right))
  14.927 -        goto error;
  14.928 -    top.sp[-2].obj = top.sp[-1].obj;
  14.929 -    top.sp--;
  14.930 -    break;
  14.931 -}
  14.932 -
  14.933 -case OP_TABLESWITCH:
  14.934 -{
  14.935 -    int value = top.sp[-1].i32;
  14.936 -    int low = READ_TABLESWITCH_LOW(top.pc);
  14.937 -    int high = READ_TABLESWITCH_HIGH(top.pc);
  14.938 -
  14.939 -    top.sp--;
  14.940 -
  14.941 -    unsigned index = unsigned(value - low);
  14.942 -    unsigned tablesize = TableSwitchEntries(low, high);
  14.943 -    if (index < tablesize) {
  14.944 -        top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
  14.945 -        top.pc += index * OP_JUMP_LENGTH;
  14.946 -        continue;
  14.947 -    }
  14.948 -    break;
  14.949 -}
  14.950 -
  14.951 -case OP_SIZEOF:
  14.952 -{
  14.953 -    Array *array = Array::cast(top.sp[-1].obj);
  14.954 -    top.sp[-1].i32 = array->length();
  14.955 -    break;
  14.956 -}
  14.957 -
  14.958 -case OP_PUBLIC:
  14.959 -{
  14.960 -    Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
  14.961 -    zone->registerPublic(fun);
  14.962 -    top.sp--;
  14.963 -    break;
  14.964 -}
  14.965 -
  14.966 -case OP_SETGLOBAL:
  14.967 -{
  14.968 -    Local<Code> code(zone, top.fp->code());
  14.969 -    Local<Struct> obj(zone, code->module()->globals());
  14.970 -    Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
  14.971 -    SetGlobal(zone, obj, name, top.sp[-1]);
  14.972 -    break;
  14.973 -}
  14.974 -
  14.975 -case OP_GETGLOBAL:
  14.976 -{
  14.977 -    Local<Code> code(zone, top.fp->code());
  14.978 -    Local<Struct> obj(zone, code->module()->globals());
  14.979 -    Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
  14.980 -    GetGlobal(zone, obj, name, top.sp);
  14.981 -    top.sp++;
  14.982 -    break;
  14.983 -}
  14.984 -
  14.985 -case OP_ENTERLOOP:
  14.986 -{
  14.987 -    top.fp->enterLoop(zone);
  14.988 -    break;
  14.989 -}
  14.990 -
  14.991 -case OP_LEAVELOOP:
  14.992 -{
  14.993 -    top.fp->leaveLoop(zone);
  14.994 -    break;
  14.995 -}
  14.996 -
  14.997 -case OP_DEPARRAY:
  14.998 -{
  14.999 -    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->object(READ_UINT32(top.pc))));
 14.1000 -    Local<Array> array(zone, Array::cast(top.sp[-2].obj));
 14.1001 -    int index = top.sp[-1].i32;
 14.1002 -
 14.1003 -    // We allow taking 0-length dependent arrays.
 14.1004 -    if (index < 0 || unsigned(index) > array->length()) {
 14.1005 -        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
 14.1006 -        goto error;
 14.1007 -    }
 14.1008 -
 14.1009 -    top.sp[-2].obj = DependentArray::New(zone, array, map, index);
 14.1010 -    if (!top.sp[-2].obj)
 14.1011 -        goto error;
 14.1012 -
 14.1013 -    top.sp--;
 14.1014 -    break;
 14.1015 -}
 14.1016 -
 14.1017 -case OP_IMPORT:
 14.1018 -{
 14.1019 -    unsigned index = READ_UINT32(top.pc);
 14.1020 -
 14.1021 -    top.sp++;
 14.1022 -    top.sp[-1].obj = top.fp->code()->module()->getImportAt(index);
 14.1023 -    break;
 14.1024 -}
 14.1025 -
 14.1026 -default:
 14.1027 -    assert(false);
 14.1028 -    return false;
 14.1029 -
 14.1030 -        }
 14.1031 -
 14.1032 -        top.pc += OpcodeInfo[op].length;
 14.1033 -        assert(top.sp >= top.fp->stackBase());
 14.1034 -    }
 14.1035 -
 14.1036 -done:
 14.1037 -    return true;
 14.1038 -
 14.1039 -error:
 14.1040 -    // Unwind frames until we can continue.
 14.1041 -    while (top.fp != entryFrame)
 14.1042 -        zone->stack().popInlineFrame();
 14.1043 -    return false;
 14.1044 -}
 14.1045 +/* vim: set ts=4 sw=4 tw=99 et:
 14.1046 + *
 14.1047 + * Copyright (C) 2012 David Anderson
 14.1048 + *
 14.1049 + * This file is part of JITCraft.
 14.1050 + *
 14.1051 + * JITCraft is free software: you can redistribute it and/or modify it under
 14.1052 + * the terms of the GNU General Public License as published by the Free
 14.1053 + * Software Foundation, either version 3 of the License, or (at your option)
 14.1054 + * any later version.
 14.1055 + * 
 14.1056 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
 14.1057 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 14.1058 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 14.1059 + *
 14.1060 + * You should have received a copy of the GNU General Public License along with
 14.1061 + * JITCraft. If not, see http://www.gnu.org/licenses/.
 14.1062 + */
 14.1063 +#include <string.h>
 14.1064 +#include "Interpreter.h"
 14.1065 +#include "Modules.h"
 14.1066 +#include "Zone.h"
 14.1067 +#include "Types.h"
 14.1068 +#include "Array.h"
 14.1069 +#include "Reference.h"
 14.1070 +#include "Strings.h"
 14.1071 +#include "Environments.h"
 14.1072 +#include "Structures.h"
 14.1073 +#include "NativeTable.h"
 14.1074 +#include "Packages.h"
 14.1075 +#include "Heap-inl.h"
 14.1076 +
 14.1077 +using namespace ke;
 14.1078 +
 14.1079 +#define PUSH_I32(top, value)    \
 14.1080 +    do {                        \
 14.1081 +        top.sp->i32 = value;    \
 14.1082 +        top.sp++;               \
 14.1083 +   } while (0)
 14.1084 +
 14.1085 +#define PUSH_F(top, value)      \
 14.1086 +    do {                        \
 14.1087 +        top.sp->f = value;      \
 14.1088 +        top.sp++;               \
 14.1089 +   } while (0)
 14.1090 +
 14.1091 +static inline int
 14.1092 +POP_I32(Top &top)
 14.1093 +{
 14.1094 +    int value = top.sp[-1].i32;
 14.1095 +    top.sp--;
 14.1096 +    return value;
 14.1097 +}
 14.1098 +
 14.1099 +static inline float
 14.1100 +POP_F(Top &top)
 14.1101 +{
 14.1102 +    float value = top.sp[-1].f;
 14.1103 +    top.sp--;
 14.1104 +    return value;
 14.1105 +}
 14.1106 +
 14.1107 +// Pawn's original semantics specify some kind of floor operation, so
 14.1108 +// (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
 14.1109 +// the upstream algorithm when constant folding. However the SourcePawn 1 JIT
 14.1110 +// does not. My guess is that Borja freaked out seeing the 13-instruction x86
 14.1111 +// sequence necessary to get this functionality (I vaguely recall a thread
 14.1112 +// where we discussed this with Mark Peter? But the ITB forums are gone...),
 14.1113 +// and we just decided to break the damn thing. So SP1 was inconsistent, but
 14.1114 +// we are not. And for completeness, we assert that the C compiler does the
 14.1115 +// right thing, since C89 leaves it unspecified.
 14.1116 +STATIC_ASSERT(8 / -3 == -2);
 14.1117 +STATIC_ASSERT(-8 / 3 == -2);
 14.1118 +
 14.1119 +static inline bool
 14.1120 +PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
 14.1121 +{
 14.1122 +    Reference *ref = Reference::NewStack(zone, location, tenure);
 14.1123 +    if (!ref)
 14.1124 +        return false;
 14.1125 +    top.sp->ref = ref;
 14.1126 +    top.sp++;
 14.1127 +    return true;
 14.1128 +}
 14.1129 +
 14.1130 +static void
 14.1131 +GetElement(Array *array, int index, LocalSlot *vp)
 14.1132 +{
 14.1133 +    if (array->type()->contained()->isTraceable()) {
 14.1134 +        vp->obj = array->readObject(index);
 14.1135 +        return;
 14.1136 +    }
 14.1137 +
 14.1138 +    switch (array->type()->contained()->pod()) {
 14.1139 +      case PrimitiveType_Float:
 14.1140 +        vp->f = array->readFloat(index);
 14.1141 +        break;
 14.1142 +
 14.1143 +      case PrimitiveType_Char:
 14.1144 +        vp->i32 = array->readChar(index);
 14.1145 +        break;
 14.1146 +
 14.1147 +      default:
 14.1148 +        assert(array->type()->contained()->pod() == PrimitiveType_Int32);
 14.1149 +        vp->i32 = array->readInt32(index);
 14.1150 +        break;
 14.1151 +    }
 14.1152 +}
 14.1153 +
 14.1154 +static void
 14.1155 +SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
 14.1156 +{
 14.1157 +    if (array->type()->contained()->isTraceable()) {
 14.1158 +        array->writeObject(zone, index, v.obj);
 14.1159 +        return;
 14.1160 +    }
 14.1161 +
 14.1162 +    switch (array->type()->contained()->pod()) {
 14.1163 +      case PrimitiveType_Float:
 14.1164 +        array->writeFloat(index, v.f);
 14.1165 +        break;
 14.1166 +
 14.1167 +      case PrimitiveType_Char:
 14.1168 +        array->writeChar(index, v.i32);
 14.1169 +        break;
 14.1170 +
 14.1171 +      default:
 14.1172 +        assert(array->type()->contained()->pod() == PrimitiveType_Int32);
 14.1173 +        array->writeInt32(index, v.i32);
 14.1174 +        break;
 14.1175 +    }
 14.1176 +}
 14.1177 +
 14.1178 +static void
 14.1179 +FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp)
 14.1180 +{
 14.1181 +    // :TODO: assert no GC.
 14.1182 +    if (desc->type()->isTraceable()) {
 14.1183 +        vp->obj = obj->get<Object *>(desc);
 14.1184 +        return;
 14.1185 +    }
 14.1186 +
 14.1187 +    switch (desc->type()->pod()) {
 14.1188 +      case PrimitiveType_Float:
 14.1189 +        vp->f = obj->get<float>(desc);
 14.1190 +        break;
 14.1191 +
 14.1192 +      default:
 14.1193 +        assert(desc->type()->pod() == PrimitiveType_Int32);
 14.1194 +        vp->i32 = obj->get<int>(desc);
 14.1195 +        break;
 14.1196 +    }
 14.1197 +}
 14.1198 +
 14.1199 +static void
 14.1200 +GetField(Struct *obj, unsigned index, LocalSlot *vp)
 14.1201 +{
 14.1202 +    StructType *type = StructType::cast(obj->map()->type());
 14.1203 +    Descriptor *desc = Descriptor::cast(type->fields()->at(index));
 14.1204 +    FetchField(obj, desc, vp);
 14.1205 +}
 14.1206 +
 14.1207 +static void
 14.1208 +GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
 14.1209 +{
 14.1210 +    Local<StructType> type(zone, StructType::cast(obj->map()->type()));
 14.1211 +    Local<Descriptor> desc(zone, type->lookupField(name, NULL));
 14.1212 +    FetchField(obj, desc, vp);
 14.1213 +}
 14.1214 +
 14.1215 +static void
 14.1216 +StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
 14.1217 +{
 14.1218 +    // :TODO: assert no GC.
 14.1219 +    if (desc->type()->isTraceable()) {
 14.1220 +        obj->set(zone, desc, v.obj);
 14.1221 +        return;
 14.1222 +    }
 14.1223 +
 14.1224 +    switch (desc->type()->pod()) {
 14.1225 +      case PrimitiveType_Float:
 14.1226 +        obj->set<float>(desc, v.f);
 14.1227 +        break;
 14.1228 +
 14.1229 +      default:
 14.1230 +        assert(desc->type()->pod() == PrimitiveType_Int32);
 14.1231 +        obj->set<int>(desc, v.i32);
 14.1232 +        break;
 14.1233 +    }
 14.1234 +}
 14.1235 +
 14.1236 +static void
 14.1237 +SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
 14.1238 +{
 14.1239 +    StructType *type = StructType::cast(obj->map()->type());
 14.1240 +    Descriptor *desc = Descriptor::cast(type->fields()->at(index));
 14.1241 +    StoreField(zone, obj, desc, v);
 14.1242 +}
 14.1243 +
 14.1244 +static void
 14.1245 +SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
 14.1246 +{
 14.1247 +    Local<StructType> type(zone, StructType::cast(obj->map()->type()));
 14.1248 +    Local<Descriptor> desc(zone, type->lookupField(name, NULL));
 14.1249 +    StoreField(zone, obj, desc, v);
 14.1250 +}
 14.1251 +
 14.1252 +static bool
 14.1253 +InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
 14.1254 +             int *result)
 14.1255 +{
 14.1256 +    NativeArgs guard;
 14.1257 +
 14.1258 +    void *address = zone->nativeTable()->address(native->index());
 14.1259 +    if (!address) {
 14.1260 +        Local<String> name(zone, zone->nativeTable()->name(native->index()));
 14.1261 +        zone->reportError(Message_NativeNotBound, name->chars());
 14.1262 +        return false;
 14.1263 +    }
 14.1264 +
 14.1265 +    if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
 14.1266 +        return false;
 14.1267 +
 14.1268 +    intptr_t *cells = guard.args();
 14.1269 +
 14.1270 +    // params[0] == argc, in ISPE
 14.1271 +    cells[0] = argc;
 14.1272 +
 14.1273 +    // Pass the formal arguments.
 14.1274 +    Local<FunctionType> type(zone, native->type());
 14.1275 +    Local<Type> param(zone);
 14.1276 +    for (unsigned i = 0; i < type->parameters()->length(); i++) {
 14.1277 +        param = type->parameterAt(i);
 14.1278 +        
 14.1279 +        // For floats, we rely on the aliasing of |i32| and |f|.
 14.1280 +        LocalSlot &arg = args[-int(i) - 1];
 14.1281 +        if (param->isInt32() || param->isFloat()) {
 14.1282 +            cells[i + 1] = arg.i32;
 14.1283 +        } else if (param->isReference()) {
 14.1284 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
 14.1285 +        } else {
 14.1286 +            assert(param->isArray());
 14.1287 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
 14.1288 +        }
 14.1289 +    }
 14.1290 +
 14.1291 +    // For variadic arguments, the compiler left either arrays or references.
 14.1292 +    for (unsigned i = type->parameters()->length(); i < argc; i++) {
 14.1293 +        LocalSlot &arg = args[-int(i) - 1];
 14.1294 +
 14.1295 +        if (arg.obj->is(MapKind_Reference)) {
 14.1296 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
 14.1297 +        } else {
 14.1298 +            assert(arg.obj->is(MapKind_Array));
 14.1299 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
 14.1300 +        }
 14.1301 +    }
 14.1302 +
 14.1303 +    typedef intptr_t (*INVOKE)(void *, intptr_t *);
 14.1304 +    INVOKE invoke = (INVOKE)address;
 14.1305 +    *result = invoke(identity, cells);
 14.1306 +
 14.1307 +    return !zone->hasPendingException();
 14.1308 +}
 14.1309 +
 14.1310 +bool
 14.1311 +ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
 14.1312 +{
 14.1313 +    Top &top = *zone->stack().top();
 14.1314 +    if (!entryFrame)
 14.1315 +        entryFrame = top.fp;
 14.1316 +
 14.1317 +    LocalSlot *locals = entryFrame->locals();
 14.1318 +
 14.1319 +    for (;;) {
 14.1320 +        Opcode op = Opcode(*top.pc);
 14.1321 +
 14.1322 +        if (OpcodeInfo[op].nuses > 0)
 14.1323 +            assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
 14.1324 +
 14.1325 +        switch (op) {
 14.1326 +
 14.1327 +case OP_NOP:
 14.1328 +    break;
 14.1329 +
 14.1330 +case OP_INT:
 14.1331 +    PUSH_I32(top, READ_INT32(top.pc));
 14.1332 +    break;
 14.1333 +
 14.1334 +case OP_FLOAT:
 14.1335 +    PUSH_F(top, READ_FLOAT(top.pc));
 14.1336 +    break;
 14.1337 +
 14.1338 +case OP_RETURN:
 14.1339 +case OP_RETURNVOID:
 14.1340 +case OP_STOP:
 14.1341 +{
 14.1342 +    if (op == OP_RETURN)
 14.1343 +        *result = *--top.sp;
 14.1344 +
 14.1345 +    if (top.fp == entryFrame)
 14.1346 +        goto done;
 14.1347 +
 14.1348 +    // This must not GC.
 14.1349 +    zone->stack().popInlineFrame();
 14.1350 +    locals = top.fp->locals();
 14.1351 +
 14.1352 +    if (op == OP_RETURN)
 14.1353 +        *top.sp++ = *result;
 14.1354 +
 14.1355 +    top.pc += OpcodeInfo[*top.pc].length;
 14.1356 +    continue;
 14.1357 +}
 14.1358 +
 14.1359 +case OP_POP:
 14.1360 +{
 14.1361 +    top.sp--;
 14.1362 +    break;
 14.1363 +}
 14.1364 +
 14.1365 +case OP_JT:
 14.1366 +{
 14.1367 +    int value = POP_I32(top);
 14.1368 +    if (value) {
 14.1369 +        top.pc += READ_INT32(top.pc);
 14.1370 +        continue;
 14.1371 +    }
 14.1372 +    break;
 14.1373 +}
 14.1374 +
 14.1375 +case OP_JF:
 14.1376 +{
 14.1377 +    int value = POP_I32(top);
 14.1378 +    if (!value) {
 14.1379 +        top.pc += READ_INT32(top.pc);
 14.1380 +        continue;
 14.1381 +    }
 14.1382 +    break;
 14.1383 +}
 14.1384 +
 14.1385 +case OP_JUMP:
 14.1386 +{
 14.1387 +    top.pc += READ_INT32(top.pc);
 14.1388 +    continue;
 14.1389 +}
 14.1390 +
 14.1391 +case OP_BREAK:
 14.1392 +case OP_CONTINUE:
 14.1393 +{
 14.1394 +    top.fp->leaveLoop(zone);
 14.1395 +    top.pc += READ_INT32(top.pc);
 14.1396 +    continue;
 14.1397 +}
 14.1398 +
 14.1399 +case OP_GETLOCAL:
 14.1400 +{
 14.1401 +    unsigned slot = READ_UINT32(top.pc);
 14.1402 +    assert(slot < top.fp->code()->nlocals());
 14.1403 +    *top.sp++ = locals[slot];
 14.1404 +    break;
 14.1405 +}
 14.1406 +
 14.1407 +case OP_SETLOCAL:
 14.1408 +{
 14.1409 +    unsigned slot = READ_UINT32(top.pc);
 14.1410 +    assert(slot < top.fp->code()->nlocals());
 14.1411 +    locals[slot] = top.sp[-1];
 14.1412 +    break;
 14.1413 +}
 14.1414 +
 14.1415 +case OP_ADD:
 14.1416 +{
 14.1417 +    top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
 14.1418 +    top.sp--;
 14.1419 +    break;
 14.1420 +}
 14.1421 +
 14.1422 +case OP_SUB:
 14.1423 +{
 14.1424 +    top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
 14.1425 +    top.sp--;
 14.1426 +    break;
 14.1427 +}
 14.1428 +
 14.1429 +case OP_MUL:
 14.1430 +{
 14.1431 +    top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
 14.1432 +    top.sp--;
 14.1433 +    break;
 14.1434 +}
 14.1435 +
 14.1436 +case OP_DIV:
 14.1437 +{
 14.1438 +    if (top.sp[-1].i32 == 0) {
 14.1439 +        zone->reportError(Message_IntegerDivideByZero);
 14.1440 +        goto error;
 14.1441 +    }
 14.1442 +    top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
 14.1443 +    top.sp--;
 14.1444 +    break;
 14.1445 +}
 14.1446 +
 14.1447 +case OP_MOD:
 14.1448 +{
 14.1449 +    if (top.sp[-1].i32 == 0) {
 14.1450 +        zone->reportError(Message_IntegerDivideByZero);
 14.1451 +        goto error;
 14.1452 +    }
 14.1453 +    top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
 14.1454 +    top.sp--;
 14.1455 +    break;
 14.1456 +}
 14.1457 +
 14.1458 +case OP_LT:
 14.1459 +{
 14.1460 +    top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
 14.1461 +    top.sp--;
 14.1462 +    break;
 14.1463 +}
 14.1464 +
 14.1465 +case OP_LE:
 14.1466 +{
 14.1467 +    top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
 14.1468 +    top.sp--;
 14.1469 +    break;
 14.1470 +}
 14.1471 +
 14.1472 +case OP_GT:
 14.1473 +{
 14.1474 +    top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
 14.1475 +    top.sp--;
 14.1476 +    break;
 14.1477 +}
 14.1478 +
 14.1479 +case OP_GE:
 14.1480 +{
 14.1481 +    top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
 14.1482 +    top.sp--;
 14.1483 +    break;
 14.1484 +}
 14.1485 +
 14.1486 +case OP_EQ:
 14.1487 +{
 14.1488 +    top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
 14.1489 +    top.sp--;
 14.1490 +    break;
 14.1491 +}
 14.1492 +
 14.1493 +case OP_NE:
 14.1494 +{
 14.1495 +    top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
 14.1496 +    top.sp--;
 14.1497 +    break;
 14.1498 +}
 14.1499 +
 14.1500 +case OP_ADD_F:
 14.1501 +{
 14.1502 +    top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
 14.1503 +    top.sp--;
 14.1504 +    break;
 14.1505 +}
 14.1506 +
 14.1507 +case OP_SUB_F:
 14.1508 +{
 14.1509 +    top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
 14.1510 +    top.sp--;
 14.1511 +    break;
 14.1512 +}
 14.1513 +
 14.1514 +case OP_MUL_F:
 14.1515 +{
 14.1516 +    top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
 14.1517 +    top.sp--;
 14.1518 +    break;
 14.1519 +}
 14.1520 +
 14.1521 +case OP_DIV_F:
 14.1522 +{
 14.1523 +    top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
 14.1524 +    top.sp--;
 14.1525 +    break;
 14.1526 +}
 14.1527 +
 14.1528 +case OP_LT_F:
 14.1529 +{
 14.1530 +    top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
 14.1531 +    top.sp--;
 14.1532 +    break;
 14.1533 +}
 14.1534 +
 14.1535 +case OP_LE_F:
 14.1536 +{
 14.1537 +    top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
 14.1538 +    top.sp--;
 14.1539 +    break;
 14.1540 +}
 14.1541 +
 14.1542 +case OP_GT_F:
 14.1543 +{
 14.1544 +    top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
 14.1545 +    top.sp--;
 14.1546 +    break;
 14.1547 +}
 14.1548 +
 14.1549 +case OP_GE_F:
 14.1550 +{
 14.1551 +    top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
 14.1552 +    top.sp--;
 14.1553 +    break;
 14.1554 +}
 14.1555 +
 14.1556 +case OP_EQ_F:
 14.1557 +{
 14.1558 +    top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
 14.1559 +    top.sp--;
 14.1560 +    break;
 14.1561 +}
 14.1562 +
 14.1563 +case OP_NE_F:
 14.1564 +{
 14.1565 +    top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
 14.1566 +    top.sp--;
 14.1567 +    break;
 14.1568 +}
 14.1569 +
 14.1570 +case OP_SHL:
 14.1571 +{
 14.1572 +    top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
 14.1573 +    top.sp--;
 14.1574 +    break;
 14.1575 +}
 14.1576 +
 14.1577 +case OP_SHR:
 14.1578 +{
 14.1579 +    top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
 14.1580 +    top.sp--;
 14.1581 +    break;
 14.1582 +}
 14.1583 +
 14.1584 +case OP_USHR:
 14.1585 +{
 14.1586 +    top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32);
 14.1587 +    top.sp--;
 14.1588 +    break;
 14.1589 +}
 14.1590 +
 14.1591 +case OP_BITAND:
 14.1592 +{
 14.1593 +    top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
 14.1594 +    top.sp--;
 14.1595 +    break;
 14.1596 +}
 14.1597 +
 14.1598 +case OP_BITOR:
 14.1599 +{
 14.1600 +    top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
 14.1601 +    top.sp--;
 14.1602 +    break;
 14.1603 +}
 14.1604 +
 14.1605 +case OP_BITXOR:
 14.1606 +{
 14.1607 +    top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
 14.1608 +    top.sp--;
 14.1609 +    break;
 14.1610 +}
 14.1611 +
 14.1612 +case OP_BITNOT:
 14.1613 +{
 14.1614 +    top.sp[-1].i32 = ~top.sp[-1].i32;
 14.1615 +    break;
 14.1616 +}
 14.1617 +
 14.1618 +case OP_NOT:
 14.1619 +{
 14.1620 +    top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
 14.1621 +    break;
 14.1622 +}
 14.1623 +
 14.1624 +case OP_NOT_F:
 14.1625 +{
 14.1626 +    top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
 14.1627 +    break;
 14.1628 +}
 14.1629 +
 14.1630 +case OP_NEG:
 14.1631 +{
 14.1632 +    top.sp[-1].i32 = -top.sp[-1].i32;
 14.1633 +    break;
 14.1634 +}
 14.1635 +
 14.1636 +case OP_NEG_F:
 14.1637 +{
 14.1638 +    top.sp[-1].f = -top.sp[-1].f;
 14.1639 +    break;
 14.1640 +}
 14.1641 +
 14.1642 +case OP_CALL:
 14.1643 +{
 14.1644 +    Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
 14.1645 +    top.sp--;
 14.1646 +
 14.1647 +    if (!zone->stack().pushInlineFrame(newFun))
 14.1648 +        goto error;
 14.1649 +
 14.1650 +    locals = top.fp->locals();
 14.1651 +    continue;
 14.1652 +}
 14.1653 +
 14.1654 +case OP_GETARG:
 14.1655 +{
 14.1656 +    unsigned slot = READ_UINT32(top.pc);
 14.1657 +    *top.sp++ = top.fp->arg(slot);
 14.1658 +    break;
 14.1659 +}
 14.1660 +
 14.1661 +case OP_SETARG:
 14.1662 +{
 14.1663 +    unsigned slot = READ_UINT32(top.pc);
 14.1664 +    top.fp->arg(slot) = top.sp[-1];
 14.1665 +    break;
 14.1666 +}
 14.1667 +
 14.1668 +case OP_GETELEM:
 14.1669 +{
 14.1670 +    Array *array = Array::cast(top.sp[-2].obj);
 14.1671 +    int index = top.sp[-1].i32;
 14.1672 +
 14.1673 +    if (index < 0 || unsigned(index) >= array->length()) {
 14.1674 +        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
 14.1675 +        goto error;
 14.1676 +    }
 14.1677 +
 14.1678 +    GetElement(array, index, &top.sp[-2]);
 14.1679 +    top.sp--;
 14.1680 +    break;
 14.1681 +}
 14.1682 +
 14.1683 +case OP_SETELEM:
 14.1684 +{
 14.1685 +    Array *array = Array::cast(top.sp[-3].obj);
 14.1686 +    int index = top.sp[-2].i32;
 14.1687 +
 14.1688 +    if (index < 0 || unsigned(index) >= array->length()) {
 14.1689 +        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
 14.1690 +        goto error;
 14.1691 +    }
 14.1692 +
 14.1693 +    SetElement(zone, array, index, top.sp[-1]);
 14.1694 +    top.sp[-3] = top.sp[-1];
 14.1695 +    top.sp -= 2;
 14.1696 +    break;
 14.1697 +}
 14.1698 +
 14.1699 +case OP_CVT_I2F:
 14.1700 +{
 14.1701 +    int ival = POP_I32(top);
 14.1702 +    float fval = (float)ival;
 14.1703 +    PUSH_F(top, fval);
 14.1704 +    break;
 14.1705 +}
 14.1706 +
 14.1707 +case OP_CVT_I2B:
 14.1708 +{
 14.1709 +    top.sp[-1].i32 = !!top.sp[-1].i32;
 14.1710 +    break;
 14.1711 +}
 14.1712 +
 14.1713 +case OP_DUPARRAY:
 14.1714 +{
 14.1715 +    Local<Array> src(zone, Array::cast(top.sp[-1].obj));
 14.1716 +    top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
 14.1717 +    if (!top.sp[-1].obj)
 14.1718 +        goto error;
 14.1719 +    break;
 14.1720 +}
 14.1721 +
 14.1722 +case OP_NEWFIXED:
 14.1723 +{
 14.1724 +    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
 14.1725 +    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
 14.1726 +    Array *array = Array::NewFixed(zone, map, tenure);
 14.1727 +    if (!array)
 14.1728 +        goto error;
 14.1729 +    top.sp->obj = array;
 14.1730 +    top.sp++;
 14.1731 +    break;
 14.1732 +}
 14.1733 +
 14.1734 +case OP_NEWEMPTY:
 14.1735 +{
 14.1736 +    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
 14.1737 +    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
 14.1738 +    Array *array = Array::NewEmpty(zone, map, tenure);
 14.1739 +    if (!array)
 14.1740 +        goto error;
 14.1741 +    top.sp->obj = array;
 14.1742 +    top.sp++;
 14.1743 +    break;
 14.1744 +}
 14.1745 +
 14.1746 +case OP_NEWSIZED:
 14.1747 +{
 14.1748 +    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
 14.1749 +    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
 14.1750 +    assert(map->type()->levels() < MAX_ARRAY_DEPTH);
 14.1751 +
 14.1752 +    int dims[MAX_ARRAY_DEPTH];
 14.1753 +    for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
 14.1754 +        dims[i] = POP_I32(top);
 14.1755 +
 14.1756 +    Array *array = Array::NewSized(zone, map, dims, tenure);
 14.1757 +    if (!array)
 14.1758 +        goto error;
 14.1759 +    top.sp->obj = array;
 14.1760 +    top.sp++;
 14.1761 +    break;
 14.1762 +}
 14.1763 +
 14.1764 +case OP_NEWSTRUCT:
 14.1765 +{
 14.1766 +    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
 14.1767 +    Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
 14.1768 +    top.sp->obj = Struct::New(zone, map, tenure);
 14.1769 +    if (!top.sp->obj)
 14.1770 +        goto error;
 14.1771 +    top.sp++;
 14.1772 +    break;
 14.1773 +}
 14.1774 +
 14.1775 +case OP_SAVELIFO:
 14.1776 +{
 14.1777 +    unsigned slot = READ_UINT32(top.pc);
 14.1778 +    locals[slot].address = zone->heap().lifoPosition();
 14.1779 +    break;
 14.1780 +}
 14.1781 +
 14.1782 +case OP_UNWINDLIFO:
 14.1783 +{
 14.1784 +    unsigned slot = READ_UINT32(top.pc);
 14.1785 +    zone->heap().unwindLifo(locals[slot].address);
 14.1786 +    break;
 14.1787 +}
 14.1788 +
 14.1789 +case OP_VARREF_LIFO:
 14.1790 +{
 14.1791 +    unsigned slot = READ_UINT32(top.pc);
 14.1792 +    if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
 14.1793 +        goto error;
 14.1794 +    break;
 14.1795 +}
 14.1796 +
 14.1797 +case OP_ARGREF_LIFO:
 14.1798 +{
 14.1799 +    unsigned slot = READ_UINT32(top.pc);
 14.1800 +    if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
 14.1801 +        goto error;
 14.1802 +    break;
 14.1803 +}
 14.1804 +
 14.1805 +case OP_SLOTREF_LIFO:
 14.1806 +{
 14.1807 +    Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
 14.1808 +    if (!ref)
 14.1809 +        goto error;
 14.1810 +    top.sp[-1].ref = ref;
 14.1811 +    break;
 14.1812 +}
 14.1813 +
 14.1814 +case OP_GETREF_I:
 14.1815 +{
 14.1816 +    top.sp[-1].i32 = top.sp[-1].ref->getInt();
 14.1817 +    break;
 14.1818 +}
 14.1819 +
 14.1820 +case OP_SETREF_I:
 14.1821 +{
 14.1822 +    top.sp[-2].ref->setInt(top.sp[-1].i32);
 14.1823 +    top.sp[-2].i32 = top.sp[-1].i32;
 14.1824 +    top.sp--;
 14.1825 +    break;
 14.1826 +}
 14.1827 +
 14.1828 +case OP_GETREF_F:
 14.1829 +{
 14.1830 +    top.sp[-1].f = top.sp[-1].ref->getFloat();
 14.1831 +    break;
 14.1832 +}
 14.1833 +
 14.1834 +case OP_SETREF_F:
 14.1835 +{
 14.1836 +    top.sp[-2].ref->setFloat(top.sp[-1].f);
 14.1837 +    top.sp[-2].f = top.sp[-1].f;
 14.1838 +    break;
 14.1839 +}
 14.1840 +
 14.1841 +case OP_OBJECT:
 14.1842 +{
 14.1843 +    top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
 14.1844 +    top.sp++;
 14.1845 +    break;
 14.1846 +}
 14.1847 +
 14.1848 +case OP_COPYARRAY:
 14.1849 +{
 14.1850 +    // Note for this assignment opcode, we return the left-hand side, not the
 14.1851 +    // right, since in this case the result of the expression could be different.
 14.1852 +    Local<Array> left(zone, Array::cast(top.sp[-2].array));
 14.1853 +    Local<Array> right(zone, Array::cast(top.sp[-1].array));
 14.1854 +    if (!Array::ShallowCopy(zone, left, right))
 14.1855 +        goto error;
 14.1856 +    top.sp--;
 14.1857 +    break;
 14.1858 +}
 14.1859 +
 14.1860 +case OP_DUP:
 14.1861 +{
 14.1862 +    top.sp++;
 14.1863 +    top.sp[-1] = top.sp[-2];
 14.1864 +    break;
 14.1865 +}
 14.1866 +
 14.1867 +case OP_DUP2:
 14.1868 +{
 14.1869 +    top.sp += 2;
 14.1870 +    top.sp[-2] = top.sp[-4];
 14.1871 +    top.sp[-1] = top.sp[-3];
 14.1872 +    break;
 14.1873 +}
 14.1874 +
 14.1875 +case OP_SWAP:
 14.1876 +{
 14.1877 +    LocalSlot slot = top.sp[-2];
 14.1878 +    top.sp[-2] = top.sp[-1];
 14.1879 +    top.sp[-1] = slot;
 14.1880 +    break;
 14.1881 +}
 14.1882 +
 14.1883 +case OP_ROLL3:
 14.1884 +{
 14.1885 +    LocalSlot slot = top.sp[-3];
 14.1886 +    top.sp[-3] = top.sp[-2];
 14.1887 +    top.sp[-2] = top.sp[-1];
 14.1888 +    top.sp[-1] = slot;
 14.1889 +    break;
 14.1890 +}
 14.1891 +
 14.1892 +case OP_PICK2:
 14.1893 +{
 14.1894 +    top.sp++;
 14.1895 +    top.sp[-1] = top.sp[-3];
 14.1896 +    break;
 14.1897 +}
 14.1898 +
 14.1899 +case OP_PICK3:
 14.1900 +{
 14.1901 +    top.sp++;
 14.1902 +    top.sp[-1] = top.sp[-4];
 14.1903 +    break;
 14.1904 +}
 14.1905 +
 14.1906 +case OP_CALLNATIVE:
 14.1907 +{
 14.1908 +    unsigned argc = READ_UINT32(top.pc);
 14.1909 +
 14.1910 +    Local<Native> native(zone, Native::cast(top.sp[-1].obj));
 14.1911 +    top.sp--;
 14.1912 +
 14.1913 +    int result;
 14.1914 +    void *nativeIdentity = top.fp->code()->module()->parent()->getNativeIdentity();
 14.1915 +    if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
 14.1916 +        goto error;
 14.1917 +
 14.1918 +    top.sp -= argc;
 14.1919 +    PUSH_I32(top, result);
 14.1920 +    break;
 14.1921 +}
 14.1922 +
 14.1923 +case OP_BITCAST:
 14.1924 +{
 14.1925 +    // Because the stack is a union, this is a no-op.
 14.1926 +    break;
 14.1927 +}
 14.1928 +
 14.1929 +case OP_TRUE:
 14.1930 +{
 14.1931 +    top.sp++;
 14.1932 +    top.sp[-1].i32 = 1;
 14.1933 +    break;
 14.1934 +}
 14.1935 +
 14.1936 +case OP_FALSE:
 14.1937 +{
 14.1938 +    top.sp++;
 14.1939 +    top.sp[-1].i32 = 0;
 14.1940 +    break;
 14.1941 +}
 14.1942 +
 14.1943 +case OP_GETFIELD:
 14.1944 +{
 14.1945 +    Struct *obj;
 14.1946 +    if (top.sp[-1].obj->is(MapKind_Module))
 14.1947 +        obj = Module::cast(top.sp[-1].obj)->globals();
 14.1948 +    else
 14.1949 +        obj = Struct::cast(top.sp[-1].obj);
 14.1950 +    GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
 14.1951 +    break;
 14.1952 +}
 14.1953 +
 14.1954 +case OP_SETFIELD:
 14.1955 +{
 14.1956 +    Struct *obj = Struct::cast(top.sp[-2].obj);
 14.1957 +    SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
 14.1958 +    top.sp[-2] = top.sp[-1];
 14.1959 +    top.sp--;
 14.1960 +    break;
 14.1961 +}
 14.1962 +
 14.1963 +case OP_COPYSTRUCT:
 14.1964 +{
 14.1965 +    Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
 14.1966 +    Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
 14.1967 +    if (!Struct::Copy(zone, left, right))
 14.1968 +        goto error;
 14.1969 +    top.sp[-2].obj = top.sp[-1].obj;
 14.1970 +    top.sp--;
 14.1971 +    break;
 14.1972 +}
 14.1973 +
 14.1974 +case OP_TABLESWITCH:
 14.1975 +{
 14.1976 +    int value = top.sp[-1].i32;
 14.1977 +    int low = READ_TABLESWITCH_LOW(top.pc);
 14.1978 +    int high = READ_TABLESWITCH_HIGH(top.pc);
 14.1979 +
 14.1980 +    top.sp--;
 14.1981 +
 14.1982 +    unsigned index = unsigned(value - low);
 14.1983 +    unsigned tablesize = TableSwitchEntries(low, high);
 14.1984 +    if (index < tablesize) {
 14.1985 +        top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
 14.1986 +        top.pc += index * OP_JUMP_LENGTH;
 14.1987 +        continue;
 14.1988 +    }
 14.1989 +    break;
 14.1990 +}
 14.1991 +
 14.1992 +case OP_SIZEOF:
 14.1993 +{
 14.1994 +    Array *array = Array::cast(top.sp[-1].obj);
 14.1995 +    top.sp[-1].i32 = array->length();
 14.1996 +    break;
 14.1997 +}
 14.1998 +
 14.1999 +case OP_PUBLIC:
 14.2000 +{
 14.2001 +    Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
 14.2002 +    zone->registerPublic(fun);
 14.2003 +    top.sp--;
 14.2004 +    break;
 14.2005 +}
 14.2006 +
 14.2007 +case OP_SETGLOBAL:
 14.2008 +{
 14.2009 +    Local<Code> code(zone, top.fp->code());
 14.2010 +    Local<Struct> obj(zone, code->module()->globals());
 14.2011 +    Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
 14.2012 +    SetGlobal(zone, obj, name, top.sp[-1]);
 14.2013 +    break;
 14.2014 +}
 14.2015 +
 14.2016 +case OP_GETGLOBAL:
 14.2017 +{
 14.2018 +    Local<Code> code(zone, top.fp->code());
 14.2019 +    Local<Struct> obj(zone, code->module()->globals());
 14.2020 +    Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
 14.2021 +    GetGlobal(zone, obj, name, top.sp);
 14.2022 +    top.sp++;
 14.2023 +    break;
 14.2024 +}
 14.2025 +
 14.2026 +case OP_ENTERLOOP:
 14.2027 +{
 14.2028 +    top.fp->enterLoop(zone);
 14.2029 +    break;
 14.2030 +}
 14.2031 +
 14.2032 +case OP_LEAVELOOP:
 14.2033 +{
 14.2034 +    top.fp->leaveLoop(zone);
 14.2035 +    break;
 14.2036 +}
 14.2037 +
 14.2038 +case OP_DEPARRAY:
 14.2039 +{
 14.2040 +    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->object(READ_UINT32(top.pc))));
 14.2041 +    Local<Array> array(zone, Array::cast(top.sp[-2].obj));
 14.2042 +    int index = top.sp[-1].i32;
 14.2043 +
 14.2044 +    // We allow taking 0-length dependent arrays.
 14.2045 +    if (index < 0 || unsigned(index) > array->length()) {
 14.2046 +        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
 14.2047 +        goto error;
 14.2048 +    }
 14.2049 +
 14.2050 +    top.sp[-2].obj = DependentArray::New(zone, array, map, index);
 14.2051 +    if (!top.sp[-2].obj)
 14.2052 +        goto error;
 14.2053 +
 14.2054 +    top.sp--;
 14.2055 +    break;
 14.2056 +}
 14.2057 +
 14.2058 +case OP_IMPORT:
 14.2059 +{
 14.2060 +    unsigned index = READ_UINT32(top.pc);
 14.2061 +
 14.2062 +    top.sp++;
 14.2063 +    top.sp[-1].obj = top.fp->code()->module()->getImportAt(index);
 14.2064 +    break;
 14.2065 +}
 14.2066 +
 14.2067 +default:
 14.2068 +    assert(false);
 14.2069 +    return false;
 14.2070 +
 14.2071 +        }
 14.2072 +
 14.2073 +        top.pc += OpcodeInfo[op].length;
 14.2074 +        assert(top.sp >= top.fp->stackBase());
 14.2075 +    }
 14.2076 +
 14.2077 +done:
 14.2078 +    return true;
 14.2079 +
 14.2080 +error:
 14.2081 +    // Unwind frames until we can continue.
 14.2082 +    while (top.fp != entryFrame)
 14.2083 +        zone->stack().popInlineFrame();
 14.2084 +    return false;
 14.2085 +}
    15.1 --- a/src/Interpreter.h	Mon Jun 10 00:46:29 2013 +0100
    15.2 +++ b/src/Interpreter.h	Mon Jun 10 01:04:43 2013 +0100
    15.3 @@ -1,29 +1,29 @@
    15.4 -/*
    15.5 - * Copyright (C) 2012 David Anderson
    15.6 - *
    15.7 - * This file is part of JITCraft.
    15.8 - *
    15.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   15.10 - * the terms of the GNU General Public License as published by the Free
   15.11 - * Software Foundation, either version 3 of the License, or (at your option)
   15.12 - * any later version.
   15.13 - * 
   15.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   15.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   15.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   15.17 - *
   15.18 - * You should have received a copy of the GNU General Public License along with
   15.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   15.20 - */
   15.21 -#ifndef _include_jc_interpreter_h_
   15.22 -#define _include_jc_interpreter_h_
   15.23 -
   15.24 -#include "Stack.h"
   15.25 -
   15.26 -namespace ke {
   15.27 -
   15.28 -bool Interpret(Zone *zone, Frame *frame, LocalSlot *result);
   15.29 -
   15.30 -}
   15.31 -
   15.32 -#endif // _include_jc_interpreter_h_
   15.33 +/*
   15.34 + * Copyright (C) 2012 David Anderson
   15.35 + *
   15.36 + * This file is part of JITCraft.
   15.37 + *
   15.38 + * JITCraft is free software: you can redistribute it and/or modify it under
   15.39 + * the terms of the GNU General Public License as published by the Free
   15.40 + * Software Foundation, either version 3 of the License, or (at your option)
   15.41 + * any later version.
   15.42 + * 
   15.43 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   15.44 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   15.45 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   15.46 + *
   15.47 + * You should have received a copy of the GNU General Public License along with
   15.48 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   15.49 + */
   15.50 +#ifndef _include_jc_interpreter_h_
   15.51 +#define _include_jc_interpreter_h_
   15.52 +
   15.53 +#include "Stack.h"
   15.54 +
   15.55 +namespace ke {
   15.56 +
   15.57 +bool Interpret(Zone *zone, Frame *frame, LocalSlot *result);
   15.58 +
   15.59 +}
   15.60 +
   15.61 +#endif // _include_jc_interpreter_h_
    16.1 --- a/src/Messages.h	Mon Jun 10 00:46:29 2013 +0100
    16.2 +++ b/src/Messages.h	Mon Jun 10 01:04:43 2013 +0100
    16.3 @@ -1,48 +1,48 @@
    16.4 -/*
    16.5 - * Copyright (C) 2012 David Anderson
    16.6 - *
    16.7 - * This file is part of JITCraft.
    16.8 - *
    16.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   16.10 - * the terms of the GNU General Public License as published by the Free
   16.11 - * Software Foundation, either version 3 of the License, or (at your option)
   16.12 - * any later version.
   16.13 - * 
   16.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   16.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   16.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   16.17 - *
   16.18 - * You should have received a copy of the GNU General Public License along with
   16.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   16.20 - */
   16.21 -#ifndef _include_jitcraft_messages_h_
   16.22 -#define _include_jitcraft_messages_h_
   16.23 -
   16.24 -namespace ke {
   16.25 -
   16.26 -enum MessageType
   16.27 -{
   16.28 -    MessageType_SyntaxError,
   16.29 -    MessageType_TypeError,
   16.30 -    MessageType_SystemError
   16.31 -};
   16.32 -
   16.33 -enum Message
   16.34 -{
   16.35 -#define MSG(Name, Type, String)     Message_##Name,
   16.36 -# include "Messages.tbl"
   16.37 -#undef MSG
   16.38 -    MessageType_Total
   16.39 -};
   16.40 -
   16.41 -struct MessageInfo
   16.42 -{
   16.43 -    MessageType type;
   16.44 -    const char *format;
   16.45 -};
   16.46 -
   16.47 -extern const MessageInfo Messages[];
   16.48 -
   16.49 -}
   16.50 -
   16.51 -#endif // _include_jitcraft_messages_h_
   16.52 +/*
   16.53 + * Copyright (C) 2012 David Anderson
   16.54 + *
   16.55 + * This file is part of JITCraft.
   16.56 + *
   16.57 + * JITCraft is free software: you can redistribute it and/or modify it under
   16.58 + * the terms of the GNU General Public License as published by the Free
   16.59 + * Software Foundation, either version 3 of the License, or (at your option)
   16.60 + * any later version.
   16.61 + * 
   16.62 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   16.63 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   16.64 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   16.65 + *
   16.66 + * You should have received a copy of the GNU General Public License along with
   16.67 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   16.68 + */
   16.69 +#ifndef _include_jitcraft_messages_h_
   16.70 +#define _include_jitcraft_messages_h_
   16.71 +
   16.72 +namespace ke {
   16.73 +
   16.74 +enum MessageType
   16.75 +{
   16.76 +    MessageType_SyntaxError,
   16.77 +    MessageType_TypeError,
   16.78 +    MessageType_SystemError
   16.79 +};
   16.80 +
   16.81 +enum Message
   16.82 +{
   16.83 +#define MSG(Name, Type, String)     Message_##Name,
   16.84 +# include "Messages.tbl"
   16.85 +#undef MSG
   16.86 +    MessageType_Total
   16.87 +};
   16.88 +
   16.89 +struct MessageInfo
   16.90 +{
   16.91 +    MessageType type;
   16.92 +    const char *format;
   16.93 +};
   16.94 +
   16.95 +extern const MessageInfo Messages[];
   16.96 +
   16.97 +}
   16.98 +
   16.99 +#endif // _include_jitcraft_messages_h_
    17.1 --- a/src/Modules.cpp	Mon Jun 10 00:46:29 2013 +0100
    17.2 +++ b/src/Modules.cpp	Mon Jun 10 01:04:43 2013 +0100
    17.3 @@ -1,40 +1,40 @@
    17.4 -/*
    17.5 - * Copyright (C) 2012 David Anderson
    17.6 - *
    17.7 - * This file is part of JITCraft.
    17.8 - *
    17.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   17.10 - * the terms of the GNU General Public License as published by the Free
   17.11 - * Software Foundation, either version 3 of the License, or (at your option)
   17.12 - * any later version.
   17.13 - * 
   17.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   17.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   17.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   17.17 - *
   17.18 - * You should have received a copy of the GNU General Public License along with
   17.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   17.20 - */
   17.21 -#include "Modules.h"
   17.22 -#include "Zone.h"
   17.23 -#include "Heap.h"
   17.24 -#include "Heap-inl.h"
   17.25 -
   17.26 -using namespace ke;
   17.27 -
   17.28 -Module *
   17.29 -Module::New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name)
   17.30 -{
   17.31 -    Local<Module> module(zone, Module::cast(zone->allocate(MapKind_Module, sizeof(Module), Heap::Tenure_Old)));
   17.32 -    if (!module)
   17.33 -        return NULL;
   17.34 -
   17.35 -    module->parent_ = package;
   17.36 -    module->path_ = path;
   17.37 -    module->name_ = name;
   17.38 -    module->globals_ = NULL;
   17.39 -    module->nativeIdentity_ = NULL;
   17.40 -    module->globals_ = NULL;
   17.41 -    module->unit_ = NULL;
   17.42 -    return module;
   17.43 -}
   17.44 +/*
   17.45 + * Copyright (C) 2012 David Anderson
   17.46 + *
   17.47 + * This file is part of JITCraft.
   17.48 + *
   17.49 + * JITCraft is free software: you can redistribute it and/or modify it under
   17.50 + * the terms of the GNU General Public License as published by the Free
   17.51 + * Software Foundation, either version 3 of the License, or (at your option)
   17.52 + * any later version.
   17.53 + * 
   17.54 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   17.55 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   17.56 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   17.57 + *
   17.58 + * You should have received a copy of the GNU General Public License along with
   17.59 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   17.60 + */
   17.61 +#include "Modules.h"
   17.62 +#include "Zone.h"
   17.63 +#include "Heap.h"
   17.64 +#include "Heap-inl.h"
   17.65 +
   17.66 +using namespace ke;
   17.67 +
   17.68 +Module *
   17.69 +Module::New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name)
   17.70 +{
   17.71 +    Local<Module> module(zone, Module::cast(zone->allocate(MapKind_Module, sizeof(Module), Heap::Tenure_Old)));
   17.72 +    if (!module)
   17.73 +        return NULL;
   17.74 +
   17.75 +    module->parent_ = package;
   17.76 +    module->path_ = path;
   17.77 +    module->name_ = name;
   17.78 +    module->globals_ = NULL;
   17.79 +    module->nativeIdentity_ = NULL;
   17.80 +    module->globals_ = NULL;
   17.81 +    module->unit_ = NULL;
   17.82 +    return module;
   17.83 +}
    18.1 --- a/src/Modules.h	Mon Jun 10 00:46:29 2013 +0100
    18.2 +++ b/src/Modules.h	Mon Jun 10 01:04:43 2013 +0100
    18.3 @@ -1,107 +1,107 @@
    18.4 -/*
    18.5 - * Copyright (C) 2012 David Anderson
    18.6 - *
    18.7 - * This file is part of SourcePawn.
    18.8 - *
    18.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   18.10 - * the terms of the GNU General Public License as published by the Free
   18.11 - * Software Foundation, either version 3 of the License, or (at your option)
   18.12 - * any later version.
   18.13 - * 
   18.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   18.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   18.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   18.17 - *
   18.18 - * You should have received a copy of the GNU General Public License along with
   18.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   18.20 - */
   18.21 -#ifndef _include_jc_module_h_
   18.22 -#define _include_jc_module_h_
   18.23 -
   18.24 -#include "Heap.h"
   18.25 -#include "Code.h"
   18.26 -#include "Functions.h"
   18.27 -#include "FixedArray.h"
   18.28 -#include "Packages.h"
   18.29 -
   18.30 -namespace ke {
   18.31 -
   18.32 -class Environment;
   18.33 -class Struct;
   18.34 -class Package;
   18.35 -struct TranslationUnit;
   18.36 -
   18.37 -class Module : public Importable
   18.38 -{
   18.39 -    Barriered<Code> code_;
   18.40 -    Barriered<Struct> globals_;
   18.41 -    void *nativeIdentity_;
   18.42 -    TranslationUnit *unit_;
   18.43 -    Barriered<FixedArray> imports_;
   18.44 -
   18.45 -  public:
   18.46 -    static Module *New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name);
   18.47 -    
   18.48 -    Code *code() {
   18.49 -        return code_;
   18.50 -    }
   18.51 -    Struct *globals() {
   18.52 -        return globals_;
   18.53 -    }
   18.54 -
   18.55 -    bool compiled() {
   18.56 -        return !!code_;
   18.57 -    }
   18.58 -
   18.59 -    // Modules are pre-created, and may have their intermediate compilation
   18.60 -    // data attached while they are being compiled.
   18.61 -    bool compiling() {
   18.62 -        return !!unit_;
   18.63 -    }
   18.64 -    TranslationUnit *translationUnit() {
   18.65 -        return unit_;
   18.66 -    }
   18.67 -    void setTranslationUnit(TranslationUnit *unit) {
   18.68 -        unit_ = unit;
   18.69 -    }
   18.70 -
   18.71 -    unsigned imports() {
   18.72 -        return imports_ ? imports_->length() / 2 : 0;
   18.73 -    }
   18.74 -    Importable *getImportAt(unsigned index) {
   18.75 -        return Importable::cast(imports_->at(index * 2));
   18.76 -    }
   18.77 -    FixedArray *importPathAt(unsigned index) {
   18.78 -        return FixedArray::cast(imports_->at(index * 2 + 1));
   18.79 -    }
   18.80 -    void setImports(Handle<FixedArray> imports) {
   18.81 -        imports_ = imports;
   18.82 -    }
   18.83 -    void setCode(Handle<Code> code) {
   18.84 -        code_ = code;
   18.85 -    }
   18.86 -    void setGlobals(Handle<Struct> globals) {
   18.87 -        globals_ = globals;
   18.88 -    }
   18.89 -
   18.90 -    // Begin GC Descriptor.
   18.91 -    static inline size_t offsetOfCode() {
   18.92 -        return OFFSETOF(Module, code_);
   18.93 -    }
   18.94 -    static inline size_t offsetOfGlobals() {
   18.95 -        return OFFSETOF(Module, globals_);
   18.96 -    }
   18.97 -    static inline size_t offsetOfImports() {
   18.98 -        return OFFSETOF(Module, imports_);
   18.99 -    }
  18.100 -    // End GC Descriptor.
  18.101 -
  18.102 -    static inline Module *cast(Object *obj) {
  18.103 -        assert(!obj || obj->is(MapKind_Module));
  18.104 -        return reinterpret_cast<Module *>(obj);
  18.105 -    }
  18.106 -};
  18.107 -
  18.108 -}
  18.109 -
  18.110 -#endif // _include_jc_module_h_
  18.111 +/*
  18.112 + * Copyright (C) 2012 David Anderson
  18.113 + *
  18.114 + * This file is part of SourcePawn.
  18.115 + *
  18.116 + * SourcePawn is free software: you can redistribute it and/or modify it under
  18.117 + * the terms of the GNU General Public License as published by the Free
  18.118 + * Software Foundation, either version 3 of the License, or (at your option)
  18.119 + * any later version.
  18.120 + * 
  18.121 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  18.122 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  18.123 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  18.124 + *
  18.125 + * You should have received a copy of the GNU General Public License along with
  18.126 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  18.127 + */
  18.128 +#ifndef _include_jc_module_h_
  18.129 +#define _include_jc_module_h_
  18.130 +
  18.131 +#include "Heap.h"
  18.132 +#include "Code.h"
  18.133 +#include "Functions.h"
  18.134 +#include "FixedArray.h"
  18.135 +#include "Packages.h"
  18.136 +
  18.137 +namespace ke {
  18.138 +
  18.139 +class Environment;
  18.140 +class Struct;
  18.141 +class Package;
  18.142 +struct TranslationUnit;
  18.143 +
  18.144 +class Module : public Importable
  18.145 +{
  18.146 +    Barriered<Code> code_;
  18.147 +    Barriered<Struct> globals_;
  18.148 +    void *nativeIdentity_;
  18.149 +    TranslationUnit *unit_;
  18.150 +    Barriered<FixedArray> imports_;
  18.151 +
  18.152 +  public:
  18.153 +    static Module *New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name);
  18.154 +    
  18.155 +    Code *code() {
  18.156 +        return code_;
  18.157 +    }
  18.158 +    Struct *globals() {
  18.159 +        return globals_;
  18.160 +    }
  18.161 +
  18.162 +    bool compiled() {
  18.163 +        return !!code_;
  18.164 +    }
  18.165 +
  18.166 +    // Modules are pre-created, and may have their intermediate compilation
  18.167 +    // data attached while they are being compiled.
  18.168 +    bool compiling() {
  18.169 +        return !!unit_;
  18.170 +    }
  18.171 +    TranslationUnit *translationUnit() {
  18.172 +        return unit_;
  18.173 +    }
  18.174 +    void setTranslationUnit(TranslationUnit *unit) {
  18.175 +        unit_ = unit;
  18.176 +    }
  18.177 +
  18.178 +    unsigned imports() {
  18.179 +        return imports_ ? imports_->length() / 2 : 0;
  18.180 +    }
  18.181 +    Importable *getImportAt(unsigned index) {
  18.182 +        return Importable::cast(imports_->at(index * 2));
  18.183 +    }
  18.184 +    FixedArray *importPathAt(unsigned index) {
  18.185 +        return FixedArray::cast(imports_->at(index * 2 + 1));
  18.186 +    }
  18.187 +    void setImports(Handle<FixedArray> imports) {
  18.188 +        imports_ = imports;
  18.189 +    }
  18.190 +    void setCode(Handle<Code> code) {
  18.191 +        code_ = code;
  18.192 +    }
  18.193 +    void setGlobals(Handle<Struct> globals) {
  18.194 +        globals_ = globals;
  18.195 +    }
  18.196 +
  18.197 +    // Begin GC Descriptor.
  18.198 +    static inline size_t offsetOfCode() {
  18.199 +        return OFFSETOF(Module, code_);
  18.200 +    }
  18.201 +    static inline size_t offsetOfGlobals() {
  18.202 +        return OFFSETOF(Module, globals_);
  18.203 +    }
  18.204 +    static inline size_t offsetOfImports() {
  18.205 +        return OFFSETOF(Module, imports_);
  18.206 +    }
  18.207 +    // End GC Descriptor.
  18.208 +
  18.209 +    static inline Module *cast(Object *obj) {
  18.210 +        assert(!obj || obj->is(MapKind_Module));
  18.211 +        return reinterpret_cast<Module *>(obj);
  18.212 +    }
  18.213 +};
  18.214 +
  18.215 +}
  18.216 +
  18.217 +#endif // _include_jc_module_h_
    19.1 --- a/src/NativeTable.cpp	Mon Jun 10 00:46:29 2013 +0100
    19.2 +++ b/src/NativeTable.cpp	Mon Jun 10 01:04:43 2013 +0100
    19.3 @@ -1,97 +1,97 @@
    19.4 -/* vim: set ts=4 sw=4 tw=99 et:
    19.5 - *
    19.6 - * Copyright (C) 2012 David Anderson
    19.7 - *
    19.8 - * This file is part of SourcePawn.
    19.9 - *
   19.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   19.11 - * the terms of the GNU General Public License as published by the Free
   19.12 - * Software Foundation, either version 3 of the License, or (at your option)
   19.13 - * any later version.
   19.14 - * 
   19.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   19.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   19.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   19.18 - *
   19.19 - * You should have received a copy of the GNU General Public License along with
   19.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   19.21 - */
   19.22 -#include "Zone.h"
   19.23 -#include "NativeTable.h"
   19.24 -#include "StringPool.h"
   19.25 -#include "Heap-inl.h"
   19.26 -
   19.27 -using namespace ke;
   19.28 -
   19.29 -NativeTable::NativeTable(Zone *zone)
   19.30 -  : zone_(zone),
   19.31 -    nativeMap_(ZoneAllocatorPolicy())
   19.32 -{
   19.33 -}
   19.34 -
   19.35 -NativeTable::~NativeTable()
   19.36 -{
   19.37 -    for (size_t i = 0; i < natives_.length(); i++)
   19.38 -        delete natives_[i];
   19.39 -}
   19.40 -
   19.41 -bool
   19.42 -NativeTable::initialize()
   19.43 -{
   19.44 -    return nativeMap_.init(16);
   19.45 -}
   19.46 -
   19.47 -bool
   19.48 -NativeTable::add(Handle<String> name, size_t *indexp)
   19.49 -{
   19.50 -    // :TODO: assert no GC
   19.51 -    CharsAndLength key(name->chars(), name->length());
   19.52 -    NativeMap::Insert p = nativeMap_.findForAdd(key);
   19.53 -    if (p.found()) {
   19.54 -        *indexp = (*p)->index;
   19.55 -        return true;
   19.56 -    }
   19.57 -
   19.58 -    NativeInfo *info = new NativeInfo(name, NULL, natives_.length());
   19.59 -    if (!info || !natives_.append(info))
   19.60 -        return false;
   19.61 -
   19.62 -    if (!nativeMap_.add(p, info))
   19.63 -        return false;
   19.64 -
   19.65 -    *indexp = info->index;
   19.66 -
   19.67 -    return true;
   19.68 -}
   19.69 -
   19.70 -bool
   19.71 -NativeTable::bind(const char *name, void *address)
   19.72 -{
   19.73 -    CharsAndLength key(name, strlen(name));
   19.74 -    NativeMap::Insert p = nativeMap_.findForAdd(key);
   19.75 -    if (p.found()) {
   19.76 -        (*p)->address = address;
   19.77 -        return true;
   19.78 -    }
   19.79 -
   19.80 -    Local<String> str(zone_, zone_->symbols()->add(key.str(), key.length()));
   19.81 -    if (!str)
   19.82 -        return false;
   19.83 -
   19.84 -    // :TODO: assert no GC
   19.85 -    NativeInfo *info = new NativeInfo(str, address, natives_.length());
   19.86 -    if (!info || !natives_.append(info))
   19.87 -        return false;
   19.88 -
   19.89 -    if (!nativeMap_.add(p, info))
   19.90 -        return false;
   19.91 -
   19.92 -    return true;
   19.93 -}
   19.94 -
   19.95 -void
   19.96 -NativeTable::accept(VirtualObjectVisitor *visitor)
   19.97 -{
   19.98 -    for (size_t i = 0; i < natives_.length(); i++)
   19.99 -        visitor->visit(natives_[i]->name.address());
  19.100 -}
  19.101 +/* vim: set ts=4 sw=4 tw=99 et:
  19.102 + *
  19.103 + * Copyright (C) 2012 David Anderson
  19.104 + *
  19.105 + * This file is part of SourcePawn.
  19.106 + *
  19.107 + * SourcePawn is free software: you can redistribute it and/or modify it under
  19.108 + * the terms of the GNU General Public License as published by the Free
  19.109 + * Software Foundation, either version 3 of the License, or (at your option)
  19.110 + * any later version.
  19.111 + * 
  19.112 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  19.113 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  19.114 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  19.115 + *
  19.116 + * You should have received a copy of the GNU General Public License along with
  19.117 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  19.118 + */
  19.119 +#include "Zone.h"
  19.120 +#include "NativeTable.h"
  19.121 +#include "StringPool.h"
  19.122 +#include "Heap-inl.h"
  19.123 +
  19.124 +using namespace ke;
  19.125 +
  19.126 +NativeTable::NativeTable(Zone *zone)
  19.127 +  : zone_(zone),
  19.128 +    nativeMap_(ZoneAllocatorPolicy())
  19.129 +{
  19.130 +}
  19.131 +
  19.132 +NativeTable::~NativeTable()
  19.133 +{
  19.134 +    for (size_t i = 0; i < natives_.length(); i++)
  19.135 +        delete natives_[i];
  19.136 +}
  19.137 +
  19.138 +bool
  19.139 +NativeTable::initialize()
  19.140 +{
  19.141 +    return nativeMap_.init(16);
  19.142 +}
  19.143 +
  19.144 +bool
  19.145 +NativeTable::add(Handle<String> name, size_t *indexp)
  19.146 +{
  19.147 +    // :TODO: assert no GC
  19.148 +    CharsAndLength key(name->chars(), name->length());
  19.149 +    NativeMap::Insert p = nativeMap_.findForAdd(key);
  19.150 +    if (p.found()) {
  19.151 +        *indexp = (*p)->index;
  19.152 +        return true;
  19.153 +    }
  19.154 +
  19.155 +    NativeInfo *info = new NativeInfo(name, NULL, natives_.length());
  19.156 +    if (!info || !natives_.append(info))
  19.157 +        return false;
  19.158 +
  19.159 +    if (!nativeMap_.add(p, info))
  19.160 +        return false;
  19.161 +
  19.162 +    *indexp = info->index;
  19.163 +
  19.164 +    return true;
  19.165 +}
  19.166 +
  19.167 +bool
  19.168 +NativeTable::bind(const char *name, void *address)
  19.169 +{
  19.170 +    CharsAndLength key(name, strlen(name));
  19.171 +    NativeMap::Insert p = nativeMap_.findForAdd(key);
  19.172 +    if (p.found()) {
  19.173 +        (*p)->address = address;
  19.174 +        return true;
  19.175 +    }
  19.176 +
  19.177 +    Local<String> str(zone_, zone_->symbols()->add(key.str(), key.length()));
  19.178 +    if (!str)
  19.179 +        return false;
  19.180 +
  19.181 +    // :TODO: assert no GC
  19.182 +    NativeInfo *info = new NativeInfo(str, address, natives_.length());
  19.183 +    if (!info || !natives_.append(info))
  19.184 +        return false;
  19.185 +
  19.186 +    if (!nativeMap_.add(p, info))
  19.187 +        return false;
  19.188 +
  19.189 +    return true;
  19.190 +}
  19.191 +
  19.192 +void
  19.193 +NativeTable::accept(VirtualObjectVisitor *visitor)
  19.194 +{
  19.195 +    for (size_t i = 0; i < natives_.length(); i++)
  19.196 +        visitor->visit(natives_[i]->name.address());
  19.197 +}
    20.1 --- a/src/NativeTable.h	Mon Jun 10 00:46:29 2013 +0100
    20.2 +++ b/src/NativeTable.h	Mon Jun 10 01:04:43 2013 +0100
    20.3 @@ -1,90 +1,90 @@
    20.4 -/* vim: set ts=4 sw=4 tw=99 et:
    20.5 - *
    20.6 - * Copyright (C) 2012 David Anderson
    20.7 - *
    20.8 - * This file is part of SourcePawn.
    20.9 - *
   20.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   20.11 - * the terms of the GNU General Public License as published by the Free
   20.12 - * Software Foundation, either version 3 of the License, or (at your option)
   20.13 - * any later version.
   20.14 - * 
   20.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   20.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   20.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   20.18 - *
   20.19 - * You should have received a copy of the GNU General Public License along with
   20.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   20.21 - */
   20.22 -#ifndef _include_sp2_native_table_h_
   20.23 -#define _include_sp2_native_table_h_
   20.24 -
   20.25 -#include <string.h>
   20.26 -#include "AllocatorPolicies.h"
   20.27 -#include "Strings.h"
   20.28 -#include "HashTable.h"
   20.29 -#include "Vector.h"
   20.30 -#include "VirtualObjectVisitor.h"
   20.31 -
   20.32 -namespace ke {
   20.33 -
   20.34 -class NativeTable
   20.35 -{
   20.36 -  public:
   20.37 -    NativeTable(Zone *zone);
   20.38 -    ~NativeTable();
   20.39 -
   20.40 -  private:
   20.41 -    struct NativeInfo {
   20.42 -        Unbarriered<String> name;
   20.43 -        void *address;
   20.44 -        size_t index;
   20.45 -
   20.46 -        NativeInfo(String *name, void *address, size_t index)
   20.47 -          : address(address),
   20.48 -            index(index)
   20.49 -        {
   20.50 -            this->name = name;
   20.51 -        }
   20.52 -    };
   20.53 -
   20.54 -    struct Policy
   20.55 -    {
   20.56 -        typedef NativeInfo * Payload;
   20.57 -
   20.58 -        static uint32 hash(const CharsAndLength &key) {
   20.59 -            return HashCharSequence(key.str(), key.length());
   20.60 -        }
   20.61 -        
   20.62 -        static bool matches(const CharsAndLength &key, NativeInfo *info) {
   20.63 -            if (info->name->length() != key.length())
   20.64 -                return false;
   20.65 -            return memcmp(info->name->chars(), key.str(), key.length() * sizeof(char)) == 0;
   20.66 -        }
   20.67 -    };
   20.68 -
   20.69 -    typedef HashTable<Policy, ZoneAllocatorPolicy> NativeMap;
   20.70 -
   20.71 -  public:
   20.72 -    bool initialize();
   20.73 -
   20.74 -    bool bind(const char *name, void *address);
   20.75 -    bool add(Handle<String> name, size_t *indexp);
   20.76 -    String *name(size_t index) const {
   20.77 -        return natives_[index]->name;
   20.78 -    }
   20.79 -    void *address(size_t index) const {
   20.80 -        return natives_[index]->address;
   20.81 -    }
   20.82 -
   20.83 -    void accept(VirtualObjectVisitor *visitor);
   20.84 -
   20.85 -  private:
   20.86 -    Zone *zone_;
   20.87 -    NativeMap nativeMap_;
   20.88 -    Vector<NativeInfo *> natives_;
   20.89 -};
   20.90 -
   20.91 -}
   20.92 -
   20.93 -#endif // _include_sp2_native_table_h_
   20.94 +/* vim: set ts=4 sw=4 tw=99 et:
   20.95 + *
   20.96 + * Copyright (C) 2012 David Anderson
   20.97 + *
   20.98 + * This file is part of SourcePawn.
   20.99 + *
  20.100 + * SourcePawn is free software: you can redistribute it and/or modify it under
  20.101 + * the terms of the GNU General Public License as published by the Free
  20.102 + * Software Foundation, either version 3 of the License, or (at your option)
  20.103 + * any later version.
  20.104 + * 
  20.105 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  20.106 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  20.107 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  20.108 + *
  20.109 + * You should have received a copy of the GNU General Public License along with
  20.110 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  20.111 + */
  20.112 +#ifndef _include_sp2_native_table_h_
  20.113 +#define _include_sp2_native_table_h_
  20.114 +
  20.115 +#include <string.h>
  20.116 +#include "AllocatorPolicies.h"
  20.117 +#include "Strings.h"
  20.118 +#include "HashTable.h"
  20.119 +#include "Vector.h"
  20.120 +#include "VirtualObjectVisitor.h"
  20.121 +
  20.122 +namespace ke {
  20.123 +
  20.124 +class NativeTable
  20.125 +{
  20.126 +  public:
  20.127 +    NativeTable(Zone *zone);
  20.128 +    ~NativeTable();
  20.129 +
  20.130 +  private:
  20.131 +    struct NativeInfo {
  20.132 +        Unbarriered<String> name;
  20.133 +        void *address;
  20.134 +        size_t index;
  20.135 +
  20.136 +        NativeInfo(String *name, void *address, size_t index)
  20.137 +          : address(address),
  20.138 +            index(index)
  20.139 +        {
  20.140 +            this->name = name;
  20.141 +        }
  20.142 +    };
  20.143 +
  20.144 +    struct Policy
  20.145 +    {
  20.146 +        typedef NativeInfo * Payload;
  20.147 +
  20.148 +        static uint32 hash(const CharsAndLength &key) {
  20.149 +            return HashCharSequence(key.str(), key.length());
  20.150 +        }
  20.151 +        
  20.152 +        static bool matches(const CharsAndLength &key, NativeInfo *info) {
  20.153 +            if (info->name->length() != key.length())
  20.154 +                return false;
  20.155 +            return memcmp(info->name->chars(), key.str(), key.length() * sizeof(char)) == 0;
  20.156 +        }
  20.157 +    };
  20.158 +
  20.159 +    typedef HashTable<Policy, ZoneAllocatorPolicy> NativeMap;
  20.160 +
  20.161 +  public:
  20.162 +    bool initialize();
  20.163 +
  20.164 +    bool bind(const char *name, void *address);
  20.165 +    bool add(Handle<String> name, size_t *indexp);
  20.166 +    String *name(size_t index) const {
  20.167 +        return natives_[index]->name;
  20.168 +    }
  20.169 +    void *address(size_t index) const {
  20.170 +        return natives_[index]->address;
  20.171 +    }
  20.172 +
  20.173 +    void accept(VirtualObjectVisitor *visitor);
  20.174 +
  20.175 +  private:
  20.176 +    Zone *zone_;
  20.177 +    NativeMap nativeMap_;
  20.178 +    Vector<NativeInfo *> natives_;
  20.179 +};
  20.180 +
  20.181 +}
  20.182 +
  20.183 +#endif // _include_sp2_native_table_h_
    21.1 --- a/src/OldByCo.cpp	Mon Jun 10 00:46:29 2013 +0100
    21.2 +++ b/src/OldByCo.cpp	Mon Jun 10 01:04:43 2013 +0100
    21.3 @@ -1,1585 +1,1585 @@
    21.4 -/* vim: set ts=4 sw=4 tw=99 et:
    21.5 - *
    21.6 - * Copyright (C) 2012 David Anderson
    21.7 - *
    21.8 - * This file is part of JITCraft.
    21.9 - *
   21.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   21.11 - * the terms of the GNU General Public License as published by the Free
   21.12 - * Software Foundation, either version 3 of the License, or (at your option)
   21.13 - * any later version.
   21.14 - * 
   21.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   21.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   21.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   21.18 - *
   21.19 - * You should have received a copy of the GNU General Public License along with
   21.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   21.21 - */
   21.22 -#include <string.h>
   21.23 -#include "../Modules.h"
   21.24 -#include "../Types.h"
   21.25 -#include "../Array.h"
   21.26 -#include "../Strings.h"
   21.27 -#include "../Zone.h"
   21.28 -#include "../Environments.h"
   21.29 -#include "../Box.h"
   21.30 -#include "../Heap-inl.h"
   21.31 -#include "BytecodeCompiler.h"
   21.32 -#include "Scopes.h"
   21.33 -
   21.34 -using namespace ke;
   21.35 -
   21.36 -typedef BytecodeEmitter::Label Label;
   21.37 -
   21.38 -#define __ emitter_.
   21.39 -
   21.40 -BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
   21.41 -  : zone_(zone),
   21.42 -    tree_(tree),
   21.43 -    emitter_(zone->pool()),
   21.44 -    locals_(NULL),
   21.45 -    scope_(NULL),
   21.46 -    moduleData_(module),
   21.47 -    loop_(NULL)
   21.48 -{
   21.49 -}
   21.50 -
   21.51 -static inline TokenKind
   21.52 -ToCompare(Expression *expr)
   21.53 -{
   21.54 -    if (expr->isBinaryExpression()) {
   21.55 -        BinaryExpression *b = expr->toBinaryExpression();
   21.56 -        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
   21.57 -            return b->token();
   21.58 -    } else if (expr->isUnaryExpression()) {
   21.59 -        UnaryExpression *u = expr->toUnaryExpression();
   21.60 -        if (u->token() == TOK_NOT)
   21.61 -            return TOK_NOT;
   21.62 -    }
   21.63 -    return TOK_EOF;
   21.64 -}
   21.65 -
   21.66 -static inline Opcode
   21.67 -CompareTokenToJump(TokenKind kind)
   21.68 -{
   21.69 -    switch (kind) {
   21.70 -      case TOK_EQUALS:
   21.71 -        return OP_JEQ;
   21.72 -      case TOK_NOTEQUALS:
   21.73 -        return OP_JNE;
   21.74 -      case TOK_GT:
   21.75 -        return OP_JG;
   21.76 -      case TOK_GE:
   21.77 -        return OP_JGE;
   21.78 -      case TOK_LT:
   21.79 -        return OP_JL;
   21.80 -      default:
   21.81 -        assert(kind == TOK_LE);
   21.82 -        return OP_JLE;
   21.83 -    }
   21.84 -}
   21.85 -
   21.86 -static inline Opcode
   21.87 -TokenToOpcode(TokenKind kind)
   21.88 -{
   21.89 -    switch (kind) {
   21.90 -      case TOK_PLUS:
   21.91 -        return OP_ADD;
   21.92 -      case TOK_MINUS:
   21.93 -        return OP_SUB;
   21.94 -      case TOK_STAR:
   21.95 -        return OP_MUL;
   21.96 -      case TOK_SLASH:
   21.97 -        return OP_DIV;
   21.98 -      case TOK_PERCENT:
   21.99 -        return OP_MOD;
  21.100 -      case TOK_SHR:
  21.101 -        return OP_SHR;
  21.102 -      case TOK_USHR:
  21.103 -        return OP_USHR;
  21.104 -      case TOK_SHL:
  21.105 -        return OP_SHL;
  21.106 -      case TOK_BITAND:
  21.107 -        return OP_BITAND;
  21.108 -      case TOK_BITOR:
  21.109 -        return OP_BITOR;
  21.110 -      case TOK_GT:
  21.111 -          return OP_GT;
  21.112 -      case TOK_GE:
  21.113 -          return OP_GE;
  21.114 -      case TOK_LT:
  21.115 -          return OP_LT;
  21.116 -      case TOK_LE:
  21.117 -          return OP_LE;
  21.118 -      case TOK_EQUALS:
  21.119 -          return OP_EQ;
  21.120 -      case TOK_NOTEQUALS:
  21.121 -          return OP_NE;
  21.122 -      default:
  21.123 -        assert(kind == TOK_BITXOR);
  21.124 -        return OP_BITXOR;
  21.125 -    }
  21.126 -}
  21.127 -
  21.128 -void
  21.129 -BytecodeCompiler::recordLifoSlot(Scope *scope)
  21.130 -{
  21.131 -    if (!scope)
  21.132 -        return;
  21.133 -
  21.134 -    if (Variable *var = scope->lifoSlot()) {
  21.135 -        locals_->set(zone_, var->slot(), var->type());
  21.136 -        __ savelifo(var->slot());
  21.137 -    }
  21.138 -}
  21.139 -
  21.140 -void
  21.141 -BytecodeCompiler::unwindTo(Scope *scope)
  21.142 -{
  21.143 -    // Note: we only need to unwind to the outermost scope's LIFO slot.
  21.144 -    Variable *var = NULL;
  21.145 -    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
  21.146 -        if (Variable *slot = current->lifoSlot())
  21.147 -            var = slot;
  21.148 -    }
  21.149 -
  21.150 -    if (var)
  21.151 -        __ unwindlifo(var->slot());
  21.152 -}
  21.153 -
  21.154 -void
  21.155 -BytecodeCompiler::visit(NameProxy *name)
  21.156 -{
  21.157 -    switch (name->binding()->kind()) {
  21.158 -      case BoundName::VARIABLE:
  21.159 -      {
  21.160 -        Variable *var = name->binding()->toVariable();
  21.161 -
  21.162 -        if (var->location() == Variable::STACK) {
  21.163 -            __ getlocal(var);
  21.164 -            assert(!name->type()->isReference());
  21.165 -        } else if (var->location() == Variable::ENVIRONMENT) {
  21.166 -            getEnvSlot(var);
  21.167 -        } else {
  21.168 -            assert(var->location() == Variable::PARAMETER);
  21.169 -            __ getarg(var);
  21.170 -
  21.171 -            // If this argument is actually a reference, dereference it now.
  21.172 -            if (var->type()->isReference())
  21.173 -                __ getref(var->type()->contained());
  21.174 -        }
  21.175 -        break;
  21.176 -      }
  21.177 -
  21.178 -      case BoundName::FUNCTION:
  21.179 -      {
  21.180 -        NamedFunction *fun = name->binding()->toNamedFunction();
  21.181 -        __ module();
  21.182 -        __ getmodule_fn(fun->slot());
  21.183 -        break;
  21.184 -      }
  21.185 -
  21.186 -      default:
  21.187 -      {
  21.188 -        NamedConstant *constant = name->binding()->toNamedConstant();
  21.189 -        __ int_(constant->value().toInt());
  21.190 -        break;
  21.191 -      }
  21.192 -    }
  21.193 -}
  21.194 -
  21.195 -void
  21.196 -BytecodeCompiler::visit(ExpressionStatement *node)
  21.197 -{
  21.198 -    // Expressions leave their value on the top of the stack, so we make sure
  21.199 -    // to balance the stack if they're used as a statement.
  21.200 -    node->expression()->accept(this);
  21.201 -    if (!node->expression()->type()->isVoid())
  21.202 -        __ pop();
  21.203 -}
  21.204 -
  21.205 -static inline bool
  21.206 -IsCompositeValueType(Type *type)
  21.207 -{
  21.208 -    return type->isStruct() ||
  21.209 -           (type->isArray() && type->isFixedLength());
  21.210 -}
  21.211 -
  21.212 -static inline Array *
  21.213 -StringLiteralToArray(Zone *zone, StringLiteral *node)
  21.214 -{
  21.215 -    Local<Type> type(zone, node->type());
  21.216 -    Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
  21.217 -    if (!map)
  21.218 -        return NULL;
  21.219 -
  21.220 -    return Array::NewString(zone,
  21.221 -                            map,
  21.222 -                            node->string()->raw(),
  21.223 -                            node->string()->length(),
  21.224 -                            Heap::Tenure_Old);
  21.225 -}
  21.226 -
  21.227 -void
  21.228 -BytecodeCompiler::visit(Assignment *node)
  21.229 -{
  21.230 -    Local<Type> left(zone_, node->type());
  21.231 -    Local<Type> right(zone_, node->expression()->type());
  21.232 -
  21.233 -    // The first step is three sub-steps:
  21.234 -    //
  21.235 -    //   (1) Bind the left-hand side.
  21.236 -    //   -- If a cumulative operation (+=, etc):
  21.237 -    //   (2) Save a copy of the binding on the stack.
  21.238 -    //   (3) Dereference the binding to get a value.
  21.239 -    //
  21.240 -    if (node->lvalue()->isNameProxy()) {
  21.241 -        NameProxy *proxy = node->lvalue()->toNameProxy();
  21.242 -        Variable *var = proxy->binding()->toVariable();
  21.243 -
  21.244 -        // We need to fetch the variable under the following circumstances:
  21.245 -        //  (1) The variable is a reference, since we'll store into the ref.
  21.246 -        //  (2) The variable is a fixed array, since we need to copy into it.
  21.247 -        //  (3) The variable is a struct, since we need to copy into it.
  21.248 -        if (var->type()->isReference() || IsCompositeValueType(var->type()))
  21.249 -            __ get(var);
  21.250 -
  21.251 -        // Get the value if needed.
  21.252 -        if (node->token() != TOK_ASSIGN) {
  21.253 -            // += etc is not allowed on arrays.
  21.254 -            assert(!var->type()->isArray());
  21.255 -
  21.256 -            if (var->location() == Variable::ENVIRONMENT)
  21.257 -                getEnvSlot(var);
  21.258 -
  21.259 -            if (var->type()->isReference()) {
  21.260 -                __ dup();
  21.261 -                __ getref(var->type()->contained());
  21.262 -            } else if (var->location() != Variable::ENVIRONMENT) {
  21.263 -                __ get(var);
  21.264 -            }
  21.265 -        }
  21.266 -    } else if (node->lvalue()->isFieldExpression()) {
  21.267 -        FieldExpression *expr = node->lvalue()->toFieldExpression();
  21.268 -        __ note_position(expr->pos());
  21.269 -
  21.270 -        expr->left()->accept(this);
  21.271 -
  21.272 -        if (node->token() != TOK_ASSIGN)
  21.273 -            __ dup();
  21.274 -
  21.275 -        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
  21.276 -            __ getfield(expr->fieldIndex(), left);
  21.277 -    } else {
  21.278 -        IndexExpression *index = node->lvalue()->toIndexExpression();
  21.279 -        __ note_position(index->pos());
  21.280 -
  21.281 -        index->left()->accept(this);
  21.282 -        index->right()->accept(this);
  21.283 -
  21.284 -        if (node->token() != TOK_ASSIGN)
  21.285 -            __ dup2();
  21.286 -
  21.287 -        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
  21.288 -            __ getelem(left);
  21.289 -    }
  21.290 -
  21.291 -    if (node->token() == TOK_ASSIGN) {
  21.292 -        // Special case: if the left-hand side is a string literal, we must
  21.293 -        // spawn a new copy (:TODO: something about const?)
  21.294 -        if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
  21.295 -            Local<Array> string(zone_,
  21.296 -                    StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
  21.297 -            if (!string)
  21.298 -                return;
  21.299 -
  21.300 -            Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
  21.301 -            __ note_position(node->expression()->pos());
  21.302 -            __ int_(string->length());
  21.303 -            __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
  21.304 -            __ object(string);
  21.305 -            __ copyarray();
  21.306 -        } else {
  21.307 -            node->expression()->accept(this);
  21.308 -        }
  21.309 -    } else {
  21.310 -        visitForALU(left, node->expression());
  21.311 -
  21.312 -        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
  21.313 -        __ note_position(node->pos());
  21.314 -        __ binary(TokenToOpcode(alu));
  21.315 -    }
  21.316 -
  21.317 -    // Emit the store.
  21.318 -    if (left->isArray() && left->isFixedLength()) {
  21.319 -        // (x = y) returns the left-hand side; if |x| is a fixed-length array,
  21.320 -        // then |y| is as well, and we perform a deep copy.
  21.321 -        assert(right->isFixedLength());
  21.322 -        __ note_position(node->pos());
  21.323 -        __ copyarray();
  21.324 -    } else if (left->isStruct()) {
  21.325 -        // Structs have value semantics, so emit a full copy. We don't break
  21.326 -        // this down into u-ops, to avoid unnecessary bytecode explosion.
  21.327 -        assert(right->isStruct());
  21.328 -        __ note_position(node->pos());
  21.329 -        __ copystruct();
  21.330 -    } else if (node->lvalue()->isNameProxy()) {
  21.331 -        NameProxy *proxy = node->lvalue()->toNameProxy();
  21.332 -        Variable *var = proxy->binding()->toVariable();
  21.333 -
  21.334 -        if (var->type()->isReference())
  21.335 -            __ setref(var->type()->contained());
  21.336 -        else if (var->location() == Variable::ENVIRONMENT)
  21.337 -            setEnvSlot(var);
  21.338 -        else
  21.339 -            __ set(var);
  21.340 -    } else if (node->lvalue()->isFieldExpression()) {
  21.341 -        FieldExpression *expr = node->lvalue()->toFieldExpression();
  21.342 -        __ setfield(expr->fieldIndex(), left);
  21.343 -    } else {
  21.344 -        __ setelem(left);
  21.345 -    }
  21.346 -}
  21.347 -
  21.348 -void
  21.349 -BytecodeCompiler::visit(IncDecExpression *node)
  21.350 -{
  21.351 -    // In the postfix case, the logic looks like:
  21.352 -    //      (1) Bind       -> REF
  21.353 -    //      (2) Dup        -> REF REF
  21.354 -    //      (3) Fetch      -> REF VAL
  21.355 -    //      (4) Swap       -> VAL REF
  21.356 -    //      (5) Pick       -> VAL REF VAL
  21.357 -    //      (6) Add        -> VAL REF VAL+1
  21.358 -    //      (7) Store      -> VAL VAL+1
  21.359 -    //      (8) Drop       -> VAL
  21.360 -    //
  21.361 -    // In the prefix case, the logic looks like:
  21.362 -    //      (1) Bind       -> REF
  21.363 -    //      (2) Dup        -> REF REF
  21.364 -    //      (3) Fetch      -> REF VAL
  21.365 -    //      --
  21.366 -    //      --
  21.367 -    //      (6) Add        -> REF VAL+1
  21.368 -    //      (7) Store      -> VAL+1
  21.369 -    //      --
  21.370 -    //
  21.371 -    // This is squirrely enough such that we don't bother sharing too much
  21.372 -    // with the above.
  21.373 -    // 
  21.374 -    // Note: We simulate a "Pick" operation with a dup2+pop.
  21.375 -
  21.376 -    // This is steps (1) to (5).
  21.377 -    Expression *expr = node->expression();
  21.378 -    if (expr->isNameProxy()) {
  21.379 -        NameProxy *proxy = expr->toNameProxy();
  21.380 -        Variable *var = proxy->binding()->toVariable();
  21.381 -
  21.382 -        // Bind.
  21.383 -        if (var->location() == Variable::ENVIRONMENT)
  21.384 -            getEnvSlot(var);
  21.385 -        else if (var->type()->isReference() || var->type()->isArray())
  21.386 -            __ get(var);
  21.387 -
  21.388 -        // Dup and fetch.
  21.389 -        if (var->type()->isReference()) {
  21.390 -            __ dup();
  21.391 -            __ getref(node->type());
  21.392 -            if (node->postfix()) {
  21.393 -                __ swap();
  21.394 -                __ pick2();
  21.395 -            }
  21.396 -        } else {
  21.397 -            assert(!var->type()->isArray());
  21.398 -            if (var->location() != Variable::ENVIRONMENT)
  21.399 -                __ get(var);
  21.400 -            if (node->postfix())
  21.401 -                __ dup();
  21.402 -        }
  21.403 -    } else if (expr->isFieldExpression()) {
  21.404 -        FieldExpression *field = expr->toFieldExpression();
  21.405 -
  21.406 -        field->left()->accept(this);
  21.407 -        __ dup();
  21.408 -        __ getfield(field->fieldIndex(), field->type());
  21.409 -
  21.410 -        if (node->postfix()) {
  21.411 -            // The stack looks like this now:
  21.412 -            // OBJECT VALUE
  21.413 -            __ swap();          // VALUE OBJECT
  21.414 -            __ pick2();         // VALUE OBJECT VALUE
  21.415 -        }
  21.416 -    } else {
  21.417 -        IndexExpression *index = expr->toIndexExpression();
  21.418 -        __ note_position(index->pos());
  21.419 -
  21.420 -        index->left()->accept(this);
  21.421 -        index->right()->accept(this);
  21.422 -
  21.423 -        assert(!node->type()->isArray());
  21.424 -        __ dup2();
  21.425 -        __ getelem(node->type());
  21.426 -
  21.427 -        if (node->postfix()) {
  21.428 -            // The stack looks like this now:
  21.429 -            // ARRAY INDEX VALUE
  21.430 -            //
  21.431 -            // So we must use a PICK operation to rotate the stack into position.
  21.432 -            __ roll3();         // INDEX VALUE ARRAY
  21.433 -            __ roll3();         // VALUE ARRAY INDEX
  21.434 -            __ pick3();         // VALUE ARRAY INDEX VALUE
  21.435 -        }
  21.436 -    }
  21.437 -
  21.438 -    // Perform step (6).
  21.439 -    if (node->type()->isFloat()) {
  21.440 -        __ float_(1.0);
  21.441 -    } else {
  21.442 -        assert(node->type()->isInt32());
  21.443 -        __ int_(1);
  21.444 -    }
  21.445 -
  21.446 -    __ note_position(node->pos());
  21.447 -    if (node->token() == TOK_INCREMENT)
  21.448 -        __ binary(OP_ADD);
  21.449 -    else
  21.450 -        __ binary(OP_SUB);
  21.451 -
  21.452 -    // Perform step (7).
  21.453 -    if (expr->isNameProxy()) {
  21.454 -        NameProxy *proxy = expr->toNameProxy();
  21.455 -        Variable *var = proxy->binding()->toVariable();
  21.456 -
  21.457 -        if (var->type()->isReference())
  21.458 -            __ setref(node->type());
  21.459 -        else if (var->location() == Variable::ENVIRONMENT)
  21.460 -            setEnvSlot(var);
  21.461 -        else
  21.462 -            __ set(var);
  21.463 -    } else if (expr->isFieldExpression()) {
  21.464 -        FieldExpression *field = expr->toFieldExpression();
  21.465 -        __ setfield(field->fieldIndex(), field->type());
  21.466 -    } else {
  21.467 -        assert(expr->isIndexExpression());
  21.468 -        __ setelem(node->type());
  21.469 -    }
  21.470 -
  21.471 -    // Perform step (8).
  21.472 -    if (node->postfix())
  21.473 -        __ pop();
  21.474 -}
  21.475 -
  21.476 -void
  21.477 -BytecodeCompiler::visitForALU(Type *needed, Expression *node)
  21.478 -{
  21.479 -    node->accept(this);
  21.480 -    if (needed->isFloat() && !node->type()->isFloat())
  21.481 -        __ cvt_i2f();
  21.482 -    else
  21.483 -        assert(needed->primitive() == node->type()->primitive());
  21.484 -}
  21.485 -
  21.486 -static inline Type *
  21.487 -GetCoercionType(TokenKind tok, Type *left, Type *right)
  21.488 -{
  21.489 -    if (left->isFloat())
  21.490 -        return left;
  21.491 -    return right;
  21.492 -}
  21.493 -
  21.494 -void
  21.495 -BytecodeCompiler::visit(UnaryExpression *node)
  21.496 -{
  21.497 -    Local<Type> out(zone_, ((Expression *)node)->type());
  21.498 -
  21.499 -    switch (node->token()) {
  21.500 -      case TOK_MINUS:
  21.501 -      {
  21.502 -        Local<Type> type(zone_, node->expression()->type());
  21.503 -        node->expression()->accept(this);
  21.504 -        
  21.505 -        if (out->isFloat())
  21.506 -            __ neg_f();
  21.507 -        else
  21.508 -            __ neg();
  21.509 -        break;
  21.510 -      }
  21.511 -
  21.512 -      case TOK_NOT:
  21.513 -      {
  21.514 -        Local<Type> type(zone_, node->expression()->type());
  21.515 -        node->expression()->accept(this);
  21.516 -        
  21.517 -        if (out->isFloat())
  21.518 -            __ not_f();
  21.519 -        else
  21.520 -            __ not_();
  21.521 -        break;
  21.522 -      }
  21.523 -
  21.524 -      case TOK_LABEL:
  21.525 -      {
  21.526 -        Local<Type> from(zone_, node->expression()->type());
  21.527 -
  21.528 -        node->expression()->accept(this);
  21.529 -        if (!from->isFloat() && out->isFloat())
  21.530 -            __ bits_f2i();
  21.531 -        else if (from->isFloat() && !out->isFloat())
  21.532 -            __ bits_i2f();
  21.533 -        break;
  21.534 -      }
  21.535 -
  21.536 -      case TOK_SIZEOF:
  21.537 -      {
  21.538 -        Local<Type> type(zone_, node->expression()->type());
  21.539 -        if (type->isFixedLength()) {
  21.540 -            __ int_(type->fixedLength());
  21.541 -        } else {
  21.542 -            node->expression()->accept(this);
  21.543 -            __ sizeof_();
  21.544 -        }
  21.545 -        break;
  21.546 -      }
  21.547 -
  21.548 -      default:
  21.549 -        assert(node->token() == TOK_TILDE);
  21.550 -        node->expression()->accept(this);
  21.551 -        __ bitnot();
  21.552 -        break;
  21.553 -    }
  21.554 -}
  21.555 -
  21.556 -void
  21.557 -BytecodeCompiler::visit(BinaryExpression *node)
  21.558 -{
  21.559 -    if (node->token() == TOK_AND || node->token() == TOK_OR) {
  21.560 -        Label success, failure, done;
  21.561 -        visitForTest(node, &success, &failure, &success);
  21.562 -        __ bind(&success);
  21.563 -        __ int_(1);
  21.564 -        __ drop(1);         // Otherwise, the stack depth will be +1 too much.
  21.565 -        __ jump(&done);
  21.566 -        __ bind(&failure);
  21.567 -        __ int_(0);
  21.568 -        __ bind(&done);
  21.569 -        return;
  21.570 -    }
  21.571 -
  21.572 -    Local<Type> leftType(zone_, node->left()->type());
  21.573 -    Local<Type> rightType(zone_, node->right()->type());
  21.574 -    Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
  21.575 -
  21.576 -    visitForALU(coerce, node->left());
  21.577 -    visitForALU(coerce, node->right());
  21.578 -
  21.579 -    Opcode op = TokenToOpcode(node->token());
  21.580 -    if (node->type()->isFloat())
  21.581 -        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
  21.582 -
  21.583 -    __ note_position(node->pos());
  21.584 -    __ binary(op);
  21.585 -}
  21.586 -
  21.587 -void
  21.588 -BytecodeCompiler::visit(IndexExpression *node)
  21.589 -{
  21.590 -    node->left()->accept(this);
  21.591 -    node->right()->accept(this);
  21.592 -    __ note_position(node->pos());
  21.593 -    __ getelem(node->type());
  21.594 -}
  21.595 -
  21.596 -void
  21.597 -BytecodeCompiler::visit(FieldExpression *node)
  21.598 -{
  21.599 -    node->left()->accept(this);
  21.600 -    __ getfield(node->fieldIndex(), node->type());
  21.601 -}
  21.602 -
  21.603 -void
  21.604 -BytecodeCompiler::visit(ReturnStatement *node)
  21.605 -{
  21.606 -    if (node->expression()) {
  21.607 -        node->expression()->accept(this);
  21.608 -        __ return_();
  21.609 -    } else {
  21.610 -        __ returnvoid();
  21.611 -    }
  21.612 -}
  21.613 -
  21.614 -void
  21.615 -BytecodeCompiler::visitForTest(Expression *expression,
  21.616 -                               Label *trueBranch,
  21.617 -                               Label *falseBranch,
  21.618 -                               Label *fallthrough)
  21.619 -{
  21.620 -    TokenKind token = ToCompare(expression);
  21.621 -    if (token == TOK_EOF || token == TOK_NOT) {
  21.622 -        if (token == TOK_EOF)
  21.623 -            expression->accept(this);
  21.624 -        else
  21.625 -            expression->toUnaryExpression()->expression()->accept(this);
  21.626 -        
  21.627 -        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
  21.628 -
  21.629 -        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
  21.630 -        if (expression->type()->isFloat())
  21.631 -            op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
  21.632 -
  21.633 -        if (fallthrough == falseBranch)
  21.634 -            __ j(op, trueBranch);
  21.635 -        else
  21.636 -            __ j(op, falseBranch); 
  21.637 -        return;
  21.638 -    }
  21.639 -
  21.640 -    BinaryExpression *binary = expression->toBinaryExpression();
  21.641 -
  21.642 -    if (token == TOK_AND || token == TOK_OR) {
  21.643 -        Label next;
  21.644 -        if (token == TOK_AND)
  21.645 -            visitForTest(binary->left(), &next, falseBranch, &next);
  21.646 -        else
  21.647 -            visitForTest(binary->left(), trueBranch, &next, &next);
  21.648 -        __ bind(&next);
  21.649 -        visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
  21.650 -        return;
  21.651 -    }
  21.652 -
  21.653 -    Opcode op = CompareTokenToJump(token);
  21.654 -    if (fallthrough == trueBranch)
  21.655 -        op = Invert(op);
  21.656 -
  21.657 -    Local<Type> leftType(zone_, binary->left()->type());
  21.658 -    Local<Type> rightType(zone_, binary->right()->type());
  21.659 -    Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
  21.660 -
  21.661 -    visitForALU(coerce, binary->left());
  21.662 -    visitForALU(coerce, binary->right());
  21.663 -    if (coerce->isFloat())
  21.664 -        op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
  21.665 -
  21.666 -    if (fallthrough == trueBranch)
  21.667 -        __ j(op, falseBranch);
  21.668 -    else
  21.669 -        __ j(op, trueBranch);
  21.670 -}
  21.671 -
  21.672 -void
  21.673 -BytecodeCompiler::visit(ForStatement *node)
  21.674 -{
  21.675 -    AutoEnterScope forScope(this, node->scope());
  21.676 -
  21.677 -    recordLifoSlot(node->scope());
  21.678 -
  21.679 -    Label join, update;
  21.680 -    LoopScope loop(scope_, &join, &update, &loop_);
  21.681 -
  21.682 -    if (node->initialization())
  21.683 -        node->initialization()->accept(this);
  21.684 -
  21.685 -    Label header, test;
  21.686 -    if (node->condition())
  21.687 -        __ jump(&test);
  21.688 -
  21.689 -    __ bind(&header);
  21.690 -    node->body()->accept(this);
  21.691 -
  21.692 -    __ bind(&update);
  21.693 -    if (node->update())
  21.694 -        node->update()->accept(this);
  21.695 -
  21.696 -    if (node->condition()) {
  21.697 -        __ bind(&test);
  21.698 -        visitForTest(node->condition(), &header, &join, &join);
  21.699 -    } else {
  21.700 -        __ jump(&header);
  21.701 -    }
  21.702 -
  21.703 -    __ bind(&join);
  21.704 -
  21.705 -    if (node->scope())
  21.706 -        unwindTo(node->scope()->enclosing());
  21.707 -    assert(__ stackDepth() == 0);
  21.708 -}
  21.709 -
  21.710 -void
  21.711 -BytecodeCompiler::visit(WhileStatement *node)
  21.712 -{
  21.713 -    Label header, join;
  21.714 -
  21.715 -    __ bind(&header);
  21.716 -
  21.717 -    LoopScope loop(scope_, &join, &header, &loop_);
  21.718 -
  21.719 -    if (node->token() == TOK_WHILE) {
  21.720 -        Label body;
  21.721 -
  21.722 -        visitForTest(node->condition(), &body, &join, &body);
  21.723 -        __ bind(&body);
  21.724 -        node->body()->accept(this);
  21.725 -        __ jump(&header);
  21.726 -    } else {
  21.727 -        node->body()->accept(this);
  21.728 -        visitForTest(node->condition(), &header, &join, &join);
  21.729 -    }
  21.730 -
  21.731 -    __ bind(&join);
  21.732 -}
  21.733 -
  21.734 -void
  21.735 -BytecodeCompiler::visit(BreakStatement *node)
  21.736 -{
  21.737 -    unwindTo(loop_->scope());
  21.738 -    __ jump(loop_->break_());
  21.739 -}
  21.740 -
  21.741 -void
  21.742 -BytecodeCompiler::visit(ContinueStatement *node)
  21.743 -{
  21.744 -    unwindTo(loop_->scope());
  21.745 -    __ jump(loop_->continue_());
  21.746 -}
  21.747 -
  21.748 -void
  21.749 -BytecodeCompiler::visit(BlockStatement *node)
  21.750 -{
  21.751 -    AutoEnterScope blockScope(this, node->scope());
  21.752 -
  21.753 -    recordLifoSlot(node->scope());
  21.754 -
  21.755 -    for (size_t i = 0; i < node->statements()->length(); i++) {
  21.756 -        Statement *statement = node->statements()->at(i);
  21.757 -        statement->accept(this);
  21.758 -        assert(__ stackDepth() == 0);
  21.759 -    }
  21.760 -
  21.761 -    // We don't bother emitting an "unwind" instruction for function scopes,
  21.762 -    // since this is taken care of by the calling convention.
  21.763 -    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
  21.764 -        unwindTo(node->scope()->enclosing());
  21.765 -}
  21.766 -
  21.767 -void
  21.768 -BytecodeCompiler::visit(IntegerLiteral *node)
  21.769 -{
  21.770 -    __ int_(node->value());
  21.771 -}
  21.772 -
  21.773 -void
  21.774 -BytecodeCompiler::visit(BooleanLiteral *node)
  21.775 -{
  21.776 -    if (node->token() == TOK_TRUE)
  21.777 -        __ true_();
  21.778 -    else
  21.779 -        __ false_();
  21.780 -}
  21.781 -
  21.782 -void
  21.783 -BytecodeCompiler::visit(FloatLiteral *node)
  21.784 -{
  21.785 -    __ float_((float)node->value());
  21.786 -}
  21.787 -
  21.788 -void
  21.789 -BytecodeCompiler::visit(StringLiteral *node)
  21.790 -{
  21.791 -    Local<Array> array(zone_, StringLiteralToArray(zone_, node));
  21.792 -    if (!array)
  21.793 -        return;
  21.794 -
  21.795 -    __ note_position(node->pos());
  21.796 -    __ object(array);
  21.797 -}
  21.798 -
  21.799 -void
  21.800 -BytecodeCompiler::getEnvSlot(Variable *var)
  21.801 -{
  21.802 -    assert(var->scope()->kind() == Scope::GLOBAL);
  21.803 -    __ getglobal(var);
  21.804 -}
  21.805 -
  21.806 -void
  21.807 -BytecodeCompiler::setEnvSlot(Variable *var)
  21.808 -{
  21.809 -    assert(var->scope()->kind() == Scope::GLOBAL);
  21.810 -    __ setglobal(var);
  21.811 -}
  21.812 -
  21.813 -static bool
  21.814 -FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
  21.815 -{
  21.816 -    Local<Array> string(zone);
  21.817 -    for (size_t i = 0; i < literal->expressions()->length(); i++) {
  21.818 -        Expression *expr = literal->expressions()->at(i);
  21.819 -        StringLiteral *lit = expr->toStringLiteral();
  21.820 -        if ((string = StringLiteralToArray(zone, lit)) == NULL)
  21.821 -            return false;
  21.822 -
  21.823 -        array->writeObject(zone, i, string);
  21.824 -
  21.825 -        if (string->length() > *maxsize)
  21.826 -            *maxsize = string->length();
  21.827 -
  21.828 -        assert(!array->type()->contained()->isFixedLength() ||
  21.829 -                array->type()->contained()->fixedLength() >= string->length());
  21.830 -    }
  21.831 -
  21.832 -    return true;
  21.833 -}
  21.834 -
  21.835 -static bool
  21.836 -FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
  21.837 -{
  21.838 -    assert(array->type()->fixedLength() == literal->expressions()->length());
  21.839 -
  21.840 -    for (size_t i = 0; i < literal->expressions()->length(); i++) {
  21.841 -        Expression *expr = literal->expressions()->at(i);
  21.842 -        if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
  21.843 -            array->writeInt32(i, lit->value());
  21.844 -            continue;
  21.845 -        }
  21.846 -        if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
  21.847 -            if (lit->token() == TOK_TRUE)
  21.848 -                array->writeInt32(i, 1);
  21.849 -            else
  21.850 -                array->writeInt32(i, 0);
  21.851 -            continue;
  21.852 -        }
  21.853 -        if (FloatLiteral *lit = expr->asFloatLiteral()) {
  21.854 -            array->writeFloat(i, (float)lit->value());
  21.855 -            continue;
  21.856 -        }
  21.857 -
  21.858 -        // Unrecognized literal type.
  21.859 -        assert(false);
  21.860 -    }
  21.861 -
  21.862 -    return true;
  21.863 -}
  21.864 -
  21.865 -static bool
  21.866 -TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
  21.867 -                     unsigned *maxsize)
  21.868 -{
  21.869 -    assert(type->fixedLength() == literal->expressions()->length());
  21.870 -
  21.871 -    Local<Type> contained(zone, type->contained());
  21.872 -    if (contained->isCharArray())
  21.873 -        return FillArrayLiteral_String(zone, array, literal, maxsize);
  21.874 -
  21.875 -    if (!contained->isArray())
  21.876 -        return FillArrayLiteral_Primitive(zone, array, literal);
  21.877 -
  21.878 -    Local<Array> subarray(zone);
  21.879 -    for (size_t i = 0; i < literal->expressions()->length(); i++) {
  21.880 -        Expression *expr = literal->expressions()->at(i);
  21.881 -        subarray = Array::cast(array->readObject(i));
  21.882 -        if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
  21.883 -            return false;
  21.884 -    }
  21.885 -
  21.886 -    return true;
  21.887 -}
  21.888 -
  21.889 -static Array *
  21.890 -BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
  21.891 -{
  21.892 -    Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
  21.893 -    if (!root)
  21.894 -        return NULL;
  21.895 -
  21.896 -    // This should have allocated everything in the array, so all we need to
  21.897 -    // do is traverse down to the lowest levels and copy things.
  21.898 -    Local<Type> type(zone, map->type());
  21.899 -    if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
  21.900 -        return NULL;
  21.901 -
  21.902 -    return root;
  21.903 -}
  21.904 -
  21.905 -static inline bool
  21.906 -ArrayContainsCharBuffers(Type *type)
  21.907 -{
  21.908 -    if (type->contained()->isArray())
  21.909 -        return ArrayContainsCharBuffers(type->contained());
  21.910 -    return type->isCharArray();
  21.911 -}
  21.912 -
  21.913 -void
  21.914 -BytecodeCompiler::visit(VariableDeclaration *node)
  21.915 -{
  21.916 -    Variable *var = node->variable();
  21.917 -    
  21.918 -    Local<Type> type(zone_, var->type());
  21.919 -    if (type->isArray()) {
  21.920 -        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
  21.921 -        __ note_position(node->pos());
  21.922 -
  21.923 -        Local<Type> right(zone_);
  21.924 -        if (node->initialization())
  21.925 -            right = node->initialization()->type();
  21.926 -
  21.927 -        // There are a few methods for allocating, here:
  21.928 -        // (1) If the array is fixed,
  21.929 -        //    (a) Initializer not present,
  21.930 -        //              NEWFIXED
  21.931 -        //    (b) Left is const non-string:
  21.932 -        //              <nothing>
  21.933 -        //    (b) Otherwise:
  21.934 -        //              NEWFIXED
  21.935 -        //              COPYARRAY
  21.936 -        // (2) If the array is not fixed,
  21.937 -        //    (a) Initializer is not present,
  21.938 -        //              NEWEMPTY
  21.939 -        //    (b) Initializer is not a string literal,
  21.940 -        //        or left is const:
  21.941 -        //              <nothing>
  21.942 -        //    (c) Initializer is a string literal,
  21.943 -        //              NEWSIZED
  21.944 -        //              COPYARRAY
  21.945 -        //
  21.946 -
  21.947 -        Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
  21.948 -                              ? Heap::Tenure_Old
  21.949 -                              : Heap::Tenure_Default;
  21.950 -
  21.951 -        if (Expression *init = node->initialization()) {
  21.952 -            if (init->isArrayLiteral()) {
  21.953 -                unsigned maxsize = 0;
  21.954 -                Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
  21.955 -                if (!array)
  21.956 -                    return;
  21.957 -
  21.958 -                assert(type->isFixedLength());
  21.959 -
  21.960 -                if (type->isConst()) {
  21.961 -                    __ object(array);
  21.962 -                } else if (ArrayContainsCharBuffers(type)) {
  21.963 -                    // This array contains mutable char buffers, so
  21.964 -                    // unfortunately this gets a little more complicated. We
  21.965 -                    // compute the maximum size needed for the innermost
  21.966 -                    // string, which is similar to SP1. This means we can use
  21.967 -                    // CopyArray rather than individually emit opcodes to clone
  21.968 -                    // every string.
  21.969 -                    Local<Type> child(zone_, type);
  21.970 -                    for (size_t i = 0; i < type->levels() - 1; i++) {
  21.971 -                        __ int_(child->fixedLength());
  21.972 -                        child = child->contained();
  21.973 -                    }
  21.974 -                    __ int_(maxsize);
  21.975 -                    __ newarray(OP_NEWSIZED, map, tenure);
  21.976 -                    __ object(array);
  21.977 -                    __ copyarray();
  21.978 -                } else {
  21.979 -                    __ newarray(OP_NEWFIXED, map, tenure);
  21.980 -                    __ object(array);
  21.981 -                    __ copyarray();
  21.982 -                }
  21.983 -            } else if (type->isFixedLength()) {
  21.984 -                // Note in the case of:
  21.985 -                // const String:buffer[50] = "hello";
  21.986 -                //
  21.987 -                // We want to preserve sizeof(buffer) == 50.
  21.988 -                if (type->isConst() && !type->isCharArray()) {
  21.989 -                    init->accept(this);
  21.990 -                } else {
  21.991 -                    __ newarray(OP_NEWFIXED, map, tenure);
  21.992 -                    init->accept(this);
  21.993 -                    __ copyarray();
  21.994 -                }
  21.995 -            } else if (!type->isConst() && init->isStringLiteral()) {
  21.996 -                // This is a degenerate case of ArrayLiteral.
  21.997 -                __ int_(right->fixedLength());
  21.998 -                __ newarray(OP_NEWSIZED, map, tenure);
  21.999 -                init->accept(this);
 21.1000 -                __ copyarray();
 21.1001 -            } else if (type->isConst()) {
 21.1002 -                init->accept(this);
 21.1003 -            }
 21.1004 -        } else if (type->isFixedLength()) {
 21.1005 -            __ newarray(OP_NEWFIXED, map, tenure);
 21.1006 -        } else {
 21.1007 -#if 0
 21.1008 -            if (node->postDimensions()) {
 21.1009 -                for (size_t i = 0; i < node->postDimensions()->length(); i++) {
 21.1010 -                    Expression *expr = node->postDimensions()->at(i);
 21.1011 -                    if (expr)
 21.1012 -                        expr->accept(this);
 21.1013 -                    else
 21.1014 -                        __ int_(0);
 21.1015 -                }
 21.1016 -                __ newarray(OP_NEWSIZED, map, tenure);
 21.1017 -            } else {
 21.1018 -                __ newarray(OP_NEWEMPTY, map, tenure);
 21.1019 -            }
 21.1020 -#endif
 21.1021 -        }
 21.1022 -    } else if (type->isStruct()) {
 21.1023 -        Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
 21.1024 -
 21.1025 -        // Because structs can contain arrays, any sort of composition
 21.1026 -        // triggers non-LIFO allocation. This is just for correctness.
 21.1027 -        // We could do better by:
 21.1028 -        //  (1) Limiting to structs that just (recursively) contain arrays,
 21.1029 -        //  (2) Swap Stack for Default tenure in Struct::New
 21.1030 -        //  (3) JIT analysis
 21.1031 -        if (var->scope()->kind() == Scope::GLOBAL)
 21.1032 -            __ newstruct(map, Heap::Tenure_Old);
 21.1033 -        else if (var->needsHeapAllocation() || map->composed())
 21.1034 -            __ newstruct(map, Heap::Tenure_Default);
 21.1035 -        else
 21.1036 -            __ newstruct(map, Heap::Tenure_Stack);
 21.1037 -    } else {
 21.1038 -        if (node->initialization()) {
 21.1039 -            node->initialization()->accept(this);
 21.1040 -        } else {
 21.1041 -            if (type->isInt32OrEnum() || type->isBool()) {
 21.1042 -                __ int_(0);
 21.1043 -            } else {
 21.1044 -                assert(type->isFloat());
 21.1045 -                __ float_(0);
 21.1046 -            }
 21.1047 -        }
 21.1048 -    }
 21.1049 -
 21.1050 -    if (var->location() == Variable::STACK) {
 21.1051 -        __ setlocal(var);
 21.1052 -        locals_->set(zone_, var->slot(), var->type());
 21.1053 -    } else {
 21.1054 -        assert(var->location() == Variable::ENVIRONMENT);
 21.1055 -        setEnvSlot(var);
 21.1056 -    }
 21.1057 -
 21.1058 -    __ pop();
 21.1059 -}
 21.1060 -
 21.1061 -void
 21.1062 -BytecodeCompiler::visit(CallExpression *node)
 21.1063 -{
 21.1064 -#if 0
 21.1065 -    Local<Type> funType(zone_, node->callee()->type());
 21.1066 -
 21.1067 -    // Sniff out natives, which have a specific opcode and are guaranteed to
 21.1068 -    // be called via name proxy.
 21.1069 -    NamedFunction *native = NULL;
 21.1070 -    if (funType->isNative())
 21.1071 -        native = node->callee()->toNameProxy()->binding()->toNamedFunction();
 21.1072 -
 21.1073 -    Local<Type> given(zone_);
 21.1074 -    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
 21.1075 -        Expression *arg = node->arguments()->at(i);
 21.1076 -
 21.1077 -        given = arg->type();
 21.1078 -
 21.1079 -        // We need to compute a reference if the parameter was in the form:
 21.1080 -        //  f(&a)
 21.1081 -        // Note this form does not allow: f({})
 21.1082 -        // 
 21.1083 -        // We also need to compute references for all variadic native
 21.1084 -        // arguments, but arrays and references are already in the
 21.1085 -        // appropriate form.
 21.1086 -        bool mustPushReference = false;
 21.1087 -        if (i >= funType->parameters()->length()) {
 21.1088 -            assert(funType->isNative() && funType->isNativeVariadic());
 21.1089 -            mustPushReference = !given->isArray() && !given->isReference();
 21.1090 -        } else if (funType->parameterAt(i)->isReference()) {
 21.1091 -            mustPushReference = !given->isReference();
 21.1092 -        }
 21.1093 -
 21.1094 -        // If a native is passed to a native, it must only be one level deep.
 21.1095 -        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
 21.1096 -
 21.1097 -        if (mustPushReference) {
 21.1098 -            if (arg->isNameProxy()) {
 21.1099 -                // :TODO: test with functions and globals
 21.1100 -                // Compute a reference to the name.
 21.1101 -                Variable *var = arg->toNameProxy()->binding()->toVariable();
 21.1102 -                __ note_position(node->pos());
 21.1103 -                __ newref(var);
 21.1104 -            } else if (arg->isFieldExpression()) {
 21.1105 -                FieldExpression *expr = arg->toFieldExpression();
 21.1106 -                expr->left()->accept(this);
 21.1107 -                __ note_position(expr->pos());
 21.1108 -                __ fieldref_lifo(expr->fieldIndex());
 21.1109 -            } else {
 21.1110 -                // We don't know how to, or can't, build a direct reference to
 21.1111 -                // this type. Make an indirect one, by taking the top of the
 21.1112 -                // stack and boxing it up.
 21.1113 -                arg->accept(this);
 21.1114 -                __ note_position(node->pos());
 21.1115 -                __ slotref_lifo();
 21.1116 -            }
 21.1117 -        } else {
 21.1118 -            arg->accept(this);
 21.1119 -        }
 21.1120 -    }
 21.1121 -
 21.1122 -    unsigned argc = node->arguments()->length();
 21.1123 -
 21.1124 -    // If there are missing arguments, then we're not done and have to push
 21.1125 -    // default parameters.
 21.1126 -    Local<Box> box(zone_);
 21.1127 -    Local<Array> array(zone_);
 21.1128 -    Local<ArrayMap> map(zone_);
 21.1129 -    for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
 21.1130 -        box = Box::cast(funType->defaults()->at(i));
 21.1131 -
 21.1132 -        if (box->type()->isPod()) {
 21.1133 -            if (box->type()->pod() == PrimitiveType_Int32)
 21.1134 -                __ int_(box->toInt32());
 21.1135 -            else if (box->type()->pod() == PrimitiveType_Float)
 21.1136 -                __ float_(box->toFloat());
 21.1137 -            else
 21.1138 -                assert(false);
 21.1139 -
 21.1140 -            if (funType->parameterAt(i)->isReference()) {
 21.1141 -                __ note_position(node->pos());
 21.1142 -                __ slotref_lifo();
 21.1143 -            }
 21.1144 -        } else {
 21.1145 -            assert(box->type()->isArray());
 21.1146 -
 21.1147 -            array = Array::cast(box->toObject());
 21.1148 -            if (funType->parameterAt(i)->isConst()) {
 21.1149 -                __ object(array);
 21.1150 -            } else {
 21.1151 -                // We need to copy the array since it's mutable. Note that
 21.1152 -                // although COPYARRAY returns its left-hand side, this may
 21.1153 -                // change in the future, we do the same thing and dupe the
 21.1154 -                // newly allocated array.
 21.1155 -                map = ArrayMap::cast(array->map());
 21.1156 -                
 21.1157 -                // Natives cannot escape array references, so we can allocate
 21.1158 -                // them on the LIFO stack.
 21.1159 -                if (funType->isNative())
 21.1160 -                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
 21.1161 -                else
 21.1162 -                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
 21.1163 -                __ dup();
 21.1164 -                __ object(array);
 21.1165 -                __ copyarray();
 21.1166 -                __ pop();
 21.1167 -            }
 21.1168 -        }
 21.1169 -
 21.1170 -        argc++;
 21.1171 -    }
 21.1172 -
 21.1173 -    __ note_position(node->pos());
 21.1174 -    if (native) {
 21.1175 -        __ callnative(native->slot(), argc);
 21.1176 -        __ drop(argc);
 21.1177 -    } else {
 21.1178 -        node->callee()->accept(this);
 21.1179 -        __ call(funType);
 21.1180 -        __ drop(argc + 1);
 21.1181 -    }
 21.1182 -#endif
 21.1183 -}
 21.1184 -
 21.1185 -void
 21.1186 -BytecodeCompiler::visit(TernaryExpression *node)
 21.1187 -{
 21.1188 -    Label success, failure, join;
 21.1189 -
 21.1190 -    visitForTest(node->condition(), &success, &failure, &success);
 21.1191 -    __ bind(&success);
 21.1192 -    node->left()->accept(this);
 21.1193 -    __ drop(1);
 21.1194 -    __ jump(&join);
 21.1195 -    __ bind(&failure);
 21.1196 -    node->right()->accept(this);
 21.1197 -    __ bind(&join);
 21.1198 -}
 21.1199 -
 21.1200 -void
 21.1201 -BytecodeCompiler::visit(IfStatement *node)
 21.1202 -{
 21.1203 -    Label join;
 21.1204 -    if (!node->ifFalse()) {
 21.1205 -        Label success;
 21.1206 -
 21.1207 -        visitForTest(node->condition(), &success, &join, &success);
 21.1208 -        __ bind(&success);
 21.1209 -        node->ifTrue()->accept(this);
 21.1210 -    } else {
 21.1211 -        Label success, next;
 21.1212 -
 21.1213 -        visitForTest(node->condition(), &success, &next, &success);
 21.1214 -        __ bind(&success);
 21.1215 -        node->ifTrue()->accept(this);
 21.1216 -        __ jump(&join);
 21.1217 -        __ bind(&next);
 21.1218 -        node->ifFalse()->accept(this);
 21.1219 -    }
 21.1220 -
 21.1221 -    __ bind(&join);
 21.1222 -}
 21.1223 -
 21.1224 -bool
 21.1225 -BytecodeCompiler::tableswitch(SwitchStatement *node)
 21.1226 -{
 21.1227 -    CaseValueList *values = node->caseValueList();
 21.1228 -
 21.1229 -    if (values->length() < 3)
 21.1230 -        return false;
 21.1231 -
 21.1232 -    // Find the delta between the largest and smallest value.
 21.1233 -    int hi = values->at(values->length() - 1).box.toInt();
 21.1234 -    int lo = values->at(0).box.toInt();
 21.1235 -    assert(hi > lo);
 21.1236 -
 21.1237 -    unsigned tablesize = TableSwitchEntries(lo, hi);
 21.1238 -    if (tablesize > MAX_TABLESWITCH_ENTRIES)
 21.1239 -        return false;
 21.1240 -
 21.1241 -    Label def, join;
 21.1242 -
 21.1243 -    // Create the list of labels that each statement will bind to.
 21.1244 -    Label *labels = new Label[node->cases()->length()];
 21.1245 -
 21.1246 -    // Create the table of labels we'll use for each case.
 21.1247 -    Label **table = new Label *[tablesize];
 21.1248 -
 21.1249 -    // Link all cases, by default, to the default label.
 21.1250 -    for (size_t i = 0; i < tablesize; i++)
 21.1251 -        table[i] = &def;
 21.1252 -
 21.1253 -    // Now patch actual cases to their correct labels.
 21.1254 -    for (size_t i = 0; i < values->length(); i++) {
 21.1255 -        CaseValue &v = values->at(i);
 21.1256 -        assert(v.statement < node->cases()->length());
 21.1257 -
 21.1258 -        unsigned index = unsigned(v.box.toInt() - lo);
 21.1259 -        assert(index < tablesize);
 21.1260 -
 21.1261 -        table[index] = &labels[v.statement];
 21.1262 -    }
 21.1263 -
 21.1264 -    // Emit the tableswitch opcode and the jump table.
 21.1265 -    __ tableswitch(lo, hi, &def, table);
 21.1266 -
 21.1267 -    // We're done with the jump table now.
 21.1268 -    delete [] table;
 21.1269 -
 21.1270 -    // Emit each statement.
 21.1271 -    for (size_t i = 0; i < node->cases()->length(); i++) {
 21.1272 -        Statement *stmt = node->cases()->at(i)->statement();
 21.1273 -
 21.1274 -        __ bind(&labels[i]);
 21.1275 -        stmt->accept(this);
 21.1276 -        __ jump(&join);
 21.1277 -    }
 21.1278 -
 21.1279 -    // We're done with the statement labels.
 21.1280 -    delete [] labels;
 21.1281 -
 21.1282 -    // Emit the default case.
 21.1283 -    __ bind(&def);
 21.1284 -    if (node->defaultCase())
 21.1285 -        node->defaultCase()->accept(this);
 21.1286 -
 21.1287 -    __ bind(&join);
 21.1288 -
 21.1289 -    return true;
 21.1290 -}
 21.1291 -
 21.1292 -void
 21.1293 -BytecodeCompiler::visit(SwitchStatement *node)
 21.1294 -{
 21.1295 -    node->expression()->accept(this);
 21.1296 -
 21.1297 -    if (tableswitch(node))
 21.1298 -        return;
 21.1299 -
 21.1300 -    Label join;
 21.1301 -
 21.1302 -    for (size_t i = 0; i < node->cases()->length(); i++) {
 21.1303 -        Case *c = node->cases()->at(i);
 21.1304 -
 21.1305 -        Label success, fail;
 21.1306 -        if (c->others()) {
 21.1307 -            for (size_t j = 0; j < c->others()->length(); j++) {
 21.1308 -                Expression *expr = c->others()->at(j);
 21.1309 -
 21.1310 -                __ dup();
 21.1311 -                expr->accept(this);
 21.1312 -                __ j(OP_JEQ, &success);
 21.1313 -            }
 21.1314 -        }
 21.1315 -
 21.1316 -        // The final test.
 21.1317 -        __ dup();
 21.1318 -        c->expression()->accept(this);
 21.1319 -        __ j(OP_JNE, &fail);
 21.1320 -        __ bind(&success);
 21.1321 -        c->statement()->accept(this);
 21.1322 -        __ jump(&join);
 21.1323 -        __ bind(&fail);
 21.1324 -    }
 21.1325 -
 21.1326 -    if (node->defaultCase())
 21.1327 -        node->defaultCase()->accept(this);
 21.1328 -
 21.1329 -    __ pop();
 21.1330 -    __ bind(&join);
 21.1331 -}
 21.1332 -
 21.1333 -void
 21.1334 -BytecodeCompiler::visit(FunctionStatement *node)
 21.1335 -{
 21.1336 -    if (!node->fun()->used())
 21.1337 -        return;
 21.1338 -
 21.1339 -    if (node->fun()->isNative()) {
 21.1340 -        assert(!moduleData_->natives->at(node->fun()->slot()));
 21.1341 -
 21.1342 -        Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
 21.1343 -        Local<String> name(zone_, node->fun()->name());
 21.1344 -        Local<Native> native(zone_, Native::New(zone_, type, name));
 21.1345 -        if (!native)
 21.1346 -            return;
 21.1347 -
 21.1348 -        moduleData_->natives->set(zone_, node->fun()->slot(), native);
 21.1349 -        return;
 21.1350 -    }
 21.1351 -
 21.1352 -    // If the function has no body, then it's just a declaration.
 21.1353 -    if (!node->body()) {
 21.1354 -        assert(node->fun()->isForward() || node->fun()->isPublic());
 21.1355 -        return;
 21.1356 -    }
 21.1357 -
 21.1358 -    BytecodeCompiler child(zone_, tree_, moduleData_);
 21.1359 -    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
 21.1360 -    if (!fun)
 21.1361 -        return;
 21.1362 -    
 21.1363 -    assert(!moduleData_->module->getFunction(node->fun()->slot()));
 21.1364 -    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
 21.1365 -}
 21.1366 -
 21.1367 -void
 21.1368 -BytecodeCompiler::visit(FunctionTypeStatement *node)
 21.1369 -{
 21.1370 -}
 21.1371 -
 21.1372 -void
 21.1373 -BytecodeCompiler::visit(EnumStatement *node)
 21.1374 -{
 21.1375 -}
 21.1376 -
 21.1377 -void
 21.1378 -BytecodeCompiler::visit(StructureStatement *node)
 21.1379 -{
 21.1380 -}
 21.1381 -
 21.1382 -void
 21.1383 -BytecodeCompiler::visit(ArrayLiteral *node)
 21.1384 -{
 21.1385 -    // We shouldn't reach these; they're handled manually when initializing
 21.1386 -    // declared arrays.
 21.1387 -    assert(false);
 21.1388 -}
 21.1389 -
 21.1390 -void
 21.1391 -BytecodeCompiler::visit(ImportStatement *node)
 21.1392 -{
 21.1393 -}
 21.1394 -
 21.1395 -Code *
 21.1396 -BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
 21.1397 -{
 21.1398 -    // STOP doubles as RETURNVOID.
 21.1399 -    __ stop();
 21.1400 -
 21.1401 -    if (__ oom() || zone_->hasPendingException())
 21.1402 -        return NULL;
 21.1403 -
 21.1404 -    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
 21.1405 -    if (!bytes)
 21.1406 -        return NULL;
 21.1407 -    memcpy(bytes->raw(), __ buffer(), __ length());
 21.1408 -
 21.1409 -    for (size_t i = 0; i < scope->maxContainedLocals(); i++)
 21.1410 -        assert(locals_->at(i));
 21.1411 -
 21.1412 -    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
 21.1413 -    if (!objects)
 21.1414 -        return NULL;
 21.1415 -
 21.1416 -    for (size_t i = 0; i < __ objects()->length(); i++)
 21.1417 -        objects->set(zone_, i, *(__ objects()->at(i)));
 21.1418 -
 21.1419 -    Local<ByteArray> safepoints(zone_);
 21.1420 -
 21.1421 -    // If any stack slots hold gc pointers at potential failure points in the
 21.1422 -    // bytecode, record them now. We do this by building a list of tuples;
 21.1423 -    // each tuple contains the pc offset, and a bitset containing which stack
 21.1424 -    // slots must be scanned by the gc.
 21.1425 -    if (__ oopRecords()->length()) {
 21.1426 -        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
 21.1427 -        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
 21.1428 -        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
 21.1429 -        if (!safepoints)
 21.1430 -            return NULL;
 21.1431 -
 21.1432 -        Address cursor = safepoints->raw();
 21.1433 -        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
 21.1434 -            OopRecord *record = __ oopRecords()->at(i);
 21.1435 -            assert(record->depth <= __ maxStackDepth());
 21.1436 -
 21.1437 -            *reinterpret_cast<unsigned *>(cursor) = record->offset;
 21.1438 -
 21.1439 -            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
 21.1440 -            for (unsigned i = 0; i < record->depth; i++)
 21.1441 -                bits[i / 8] |= (1 << (i % 8));
 21.1442 -
 21.1443 -            cursor += bytesPerSafepoint;
 21.1444 -        }
 21.1445 -
 21.1446 -        assert(cursor == safepoints->raw() + gcmapSize);
 21.1447 -    }
 21.1448 -
 21.1449 -    Local<ByteArray> sourcemap(zone_);
 21.1450 -    if (__ sourcemapLength()) {
 21.1451 -        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
 21.1452 -        if (!sourcemap)
 21.1453 -            return NULL;
 21.1454 -
 21.1455 -        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
 21.1456 -    }
 21.1457 -
 21.1458 -    Local<Code> code(zone_);
 21.1459 -
 21.1460 -    code = Code::New(zone_,
 21.1461 -                     bytes,
 21.1462 -                     locals_,
 21.1463 -                     objects,
 21.1464 -                     __ maxStackDepth(),
 21.1465 -                     moduleData_->module,
 21.1466 -                     safepoints,
 21.1467 -                     sourcemap,
 21.1468 -                     lineno);
 21.1469 -    return code;
 21.1470 -}
 21.1471 -
 21.1472 -Function *
 21.1473 -BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
 21.1474 -{
 21.1475 -    // Note: No need to record a life slot here, since it's part of the Frame.
 21.1476 -    AutoEnterScope functionScope(this, node->scope());
 21.1477 -
 21.1478 -    // Set the initial line, because line mappings are deltas.
 21.1479 -    __ setFirstLine(node->pos().line);
 21.1480 -    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
 21.1481 -
 21.1482 -    node->body()->accept(this);
 21.1483 -
 21.1484 -    unsigned nargs = node->scope()->numArguments();
 21.1485 -    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
 21.1486 -    if (!args)
 21.1487 -        return NULL;
 21.1488 -
 21.1489 -    for (size_t i = 0; i < node->scope()->numArguments(); i++)
 21.1490 -        args->set(zone_, i, node->scope()->getArgument(i)->type());
 21.1491 -
 21.1492 -
 21.1493 -    Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
 21.1494 -    if (!code)
 21.1495 -        return NULL;
 21.1496 -
 21.1497 -    Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
 21.1498 -    Local<String> name(zone_, node->fun()->name());
 21.1499 -    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
 21.1500 -    if (!fun)
 21.1501 -        return NULL;
 21.1502 -
 21.1503 -    // If this function had a forward, export it as a named public.
 21.1504 -    if (node->fun()->isPublic()) {
 21.1505 -        assert(node->fun()->isPublic());
 21.1506 -        ScopedRoot<Function> root(fun);
 21.1507 -        if (!root)
 21.1508 -            return NULL;
 21.1509 -        if (!moduleData_->publics.append(root))
 21.1510 -            return NULL;
 21.1511 -    }
 21.1512 -
 21.1513 -#ifndef NDEBUG
 21.1514 -    Disassemble(code, stdout);
 21.1515 -#endif
 21.1516 -    
 21.1517 -    return fun;
 21.1518 -}
 21.1519 -
 21.1520 -Module *
 21.1521 -BytecodeCompiler::compile()
 21.1522 -{
 21.1523 -    AutoEnterScope scope(this, tree_->globalScope());
 21.1524 -
 21.1525 -    ModuleData moduleData;
 21.1526 -
 21.1527 -    moduleData_ = &moduleData;
 21.1528 -    moduleData_->module = Module::New(zone_, tree_->globalScope()->numFunctions());
 21.1529 -
 21.1530 -    if (!moduleData_)
 21.1531 -        return NULL;
 21.1532 -    
 21.1533 -    moduleData_->natives = FixedArray::New(zone_, tree_->globalScope()->numNatives(), Heap::Tenure_Old);
 21.1534 -    if (!moduleData_->natives)
 21.1535 -        return NULL;
 21.1536 -
 21.1537 -    for (size_t i = 0; i < tree_->statements()->length(); i++) {
 21.1538 -        Statement *statement = tree_->statements()->at(i);
 21.1539 -        statement->accept(this);
 21.1540 -    }
 21.1541 -
 21.1542 -    if (zone_->hasPendingException())
 21.1543 -        return NULL;
 21.1544 -
 21.1545 -#ifndef NDEBUG
 21.1546 -    for (size_t i = 0; i < tree_->globalScope()->numFunctions(); i++)
 21.1547 -        assert(moduleData_->module->getFunction(i));
 21.1548 -    for (size_t i = 0; i < tree_->globalScope()->numNatives(); i++)
 21.1549 -        assert(moduleData_->natives->at(i));
 21.1550 -#endif
 21.1551 -
 21.1552 -    if (moduleData_->publics.length()) {
 21.1553 -        Local<Function> fun(zone_);
 21.1554 -        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
 21.1555 -                               Heap::Tenure_Old));
 21.1556 -        if (!list)
 21.1557 -            return NULL;
 21.1558 -
 21.1559 -        for (size_t i = 0; i < moduleData_->publics.length(); i++)
 21.1560 -            list->set(zone_, i, moduleData_->publics[i]);
 21.1561 -
 21.1562 -        moduleData_->module->setPublics(list);
 21.1563 -    }
 21.1564 -
 21.1565 -    moduleData_->module->setNatives(moduleData_->natives);
 21.1566 -
 21.1567 -    if (scope_->numEnvironmentVars()) {
 21.1568 -        Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
 21.1569 -        if (!globalMap)
 21.1570 -            return NULL;
 21.1571 -
 21.1572 -        Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
 21.1573 -        if (!environment)
 21.1574 -            return NULL;
 21.1575 -
 21.1576 -        moduleData_->module->setEnvironment(environment);
 21.1577 -    }
 21.1578 -
 21.1579 -    Local<Code> code(zone_, compileCode(tree_->globalScope(), 1));
 21.1580 -    if (!code)
 21.1581 -        return NULL;
 21.1582 -
 21.1583 -    Disassemble(code, stdout);
 21.1584 -
 21.1585 -    moduleData_->module->setCode(code);
 21.1586 -
 21.1587 -    return moduleData_->module;
 21.1588 -}
 21.1589 +/* vim: set ts=4 sw=4 tw=99 et:
 21.1590 + *
 21.1591 + * Copyright (C) 2012 David Anderson
 21.1592 + *
 21.1593 + * This file is part of JITCraft.
 21.1594 + *
 21.1595 + * JITCraft is free software: you can redistribute it and/or modify it under
 21.1596 + * the terms of the GNU General Public License as published by the Free
 21.1597 + * Software Foundation, either version 3 of the License, or (at your option)
 21.1598 + * any later version.
 21.1599 + * 
 21.1600 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
 21.1601 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 21.1602 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 21.1603 + *
 21.1604 + * You should have received a copy of the GNU General Public License along with
 21.1605 + * JITCraft. If not, see http://www.gnu.org/licenses/.
 21.1606 + */
 21.1607 +#include <string.h>
 21.1608 +#include "../Modules.h"
 21.1609 +#include "../Types.h"
 21.1610 +#include "../Array.h"
 21.1611 +#include "../Strings.h"
 21.1612 +#include "../Zone.h"
 21.1613 +#include "../Environments.h"
 21.1614 +#include "../Box.h"
 21.1615 +#include "../Heap-inl.h"
 21.1616 +#include "BytecodeCompiler.h"
 21.1617 +#include "Scopes.h"
 21.1618 +
 21.1619 +using namespace ke;
 21.1620 +
 21.1621 +typedef BytecodeEmitter::Label Label;
 21.1622 +
 21.1623 +#define __ emitter_.
 21.1624 +
 21.1625 +BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
 21.1626 +  : zone_(zone),
 21.1627 +    tree_(tree),
 21.1628 +    emitter_(zone->pool()),
 21.1629 +    locals_(NULL),
 21.1630 +    scope_(NULL),
 21.1631 +    moduleData_(module),
 21.1632 +    loop_(NULL)
 21.1633 +{
 21.1634 +}
 21.1635 +
 21.1636 +static inline TokenKind
 21.1637 +ToCompare(Expression *expr)
 21.1638 +{
 21.1639 +    if (expr->isBinaryExpression()) {
 21.1640 +        BinaryExpression *b = expr->toBinaryExpression();
 21.1641 +        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
 21.1642 +            return b->token();
 21.1643 +    } else if (expr->isUnaryExpression()) {
 21.1644 +        UnaryExpression *u = expr->toUnaryExpression();
 21.1645 +        if (u->token() == TOK_NOT)
 21.1646 +            return TOK_NOT;
 21.1647 +    }
 21.1648 +    return TOK_EOF;
 21.1649 +}
 21.1650 +
 21.1651 +static inline Opcode
 21.1652 +CompareTokenToJump(TokenKind kind)
 21.1653 +{
 21.1654 +    switch (kind) {
 21.1655 +      case TOK_EQUALS:
 21.1656 +        return OP_JEQ;
 21.1657 +      case TOK_NOTEQUALS:
 21.1658 +        return OP_JNE;
 21.1659 +      case TOK_GT:
 21.1660 +        return OP_JG;
 21.1661 +      case TOK_GE:
 21.1662 +        return OP_JGE;
 21.1663 +      case TOK_LT:
 21.1664 +        return OP_JL;
 21.1665 +      default:
 21.1666 +        assert(kind == TOK_LE);
 21.1667 +        return OP_JLE;
 21.1668 +    }
 21.1669 +}
 21.1670 +
 21.1671 +static inline Opcode
 21.1672 +TokenToOpcode(TokenKind kind)
 21.1673 +{
 21.1674 +    switch (kind) {
 21.1675 +      case TOK_PLUS:
 21.1676 +        return OP_ADD;
 21.1677 +      case TOK_MINUS:
 21.1678 +        return OP_SUB;
 21.1679 +      case TOK_STAR:
 21.1680 +        return OP_MUL;
 21.1681 +      case TOK_SLASH:
 21.1682 +        return OP_DIV;
 21.1683 +      case TOK_PERCENT:
 21.1684 +        return OP_MOD;
 21.1685 +      case TOK_SHR:
 21.1686 +        return OP_SHR;
 21.1687 +      case TOK_USHR:
 21.1688 +        return OP_USHR;
 21.1689 +      case TOK_SHL:
 21.1690 +        return OP_SHL;
 21.1691 +      case TOK_BITAND:
 21.1692 +        return OP_BITAND;
 21.1693 +      case TOK_BITOR:
 21.1694 +        return OP_BITOR;
 21.1695 +      case TOK_GT:
 21.1696 +          return OP_GT;
 21.1697 +      case TOK_GE:
 21.1698 +          return OP_GE;
 21.1699 +      case TOK_LT:
 21.1700 +          return OP_LT;
 21.1701 +      case TOK_LE:
 21.1702 +          return OP_LE;
 21.1703 +      case TOK_EQUALS:
 21.1704 +          return OP_EQ;
 21.1705 +      case TOK_NOTEQUALS:
 21.1706 +          return OP_NE;
 21.1707 +      default:
 21.1708 +        assert(kind == TOK_BITXOR);
 21.1709 +        return OP_BITXOR;
 21.1710 +    }
 21.1711 +}
 21.1712 +
 21.1713 +void
 21.1714 +BytecodeCompiler::recordLifoSlot(Scope *scope)
 21.1715 +{
 21.1716 +    if (!scope)
 21.1717 +        return;
 21.1718 +
 21.1719 +    if (Variable *var = scope->lifoSlot()) {
 21.1720 +        locals_->set(zone_, var->slot(), var->type());
 21.1721 +        __ savelifo(var->slot());
 21.1722 +    }
 21.1723 +}
 21.1724 +
 21.1725 +void
 21.1726 +BytecodeCompiler::unwindTo(Scope *scope)
 21.1727 +{
 21.1728 +    // Note: we only need to unwind to the outermost scope's LIFO slot.
 21.1729 +    Variable *var = NULL;
 21.1730 +    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
 21.1731 +        if (Variable *slot = current->lifoSlot())
 21.1732 +            var = slot;
 21.1733 +    }
 21.1734 +
 21.1735 +    if (var)
 21.1736 +        __ unwindlifo(var->slot());
 21.1737 +}
 21.1738 +
 21.1739 +void
 21.1740 +BytecodeCompiler::visit(NameProxy *name)
 21.1741 +{
 21.1742 +    switch (name->binding()->kind()) {
 21.1743 +      case BoundName::VARIABLE:
 21.1744 +      {
 21.1745 +        Variable *var = name->binding()->toVariable();
 21.1746 +
 21.1747 +        if (var->location() == Variable::STACK) {
 21.1748 +            __ getlocal(var);
 21.1749 +            assert(!name->type()->isReference());
 21.1750 +        } else if (var->location() == Variable::ENVIRONMENT) {
 21.1751 +            getEnvSlot(var);
 21.1752 +        } else {
 21.1753 +            assert(var->location() == Variable::PARAMETER);
 21.1754 +            __ getarg(var);
 21.1755 +
 21.1756 +            // If this argument is actually a reference, dereference it now.
 21.1757 +            if (var->type()->isReference())
 21.1758 +                __ getref(var->type()->contained());
 21.1759 +        }
 21.1760 +        break;
 21.1761 +      }
 21.1762 +
 21.1763 +      case BoundName::FUNCTION:
 21.1764 +      {
 21.1765 +        NamedFunction *fun = name->binding()->toNamedFunction();
 21.1766 +        __ module();
 21.1767 +        __ getmodule_fn(fun->slot());
 21.1768 +        break;
 21.1769 +      }
 21.1770 +
 21.1771 +      default:
 21.1772 +      {
 21.1773 +        NamedConstant *constant = name->binding()->toNamedConstant();
 21.1774 +        __ int_(constant->value().toInt());
 21.1775 +        break;
 21.1776 +      }
 21.1777 +    }
 21.1778 +}
 21.1779 +
 21.1780 +void
 21.1781 +BytecodeCompiler::visit(ExpressionStatement *node)
 21.1782 +{
 21.1783 +    // Expressions leave their value on the top of the stack, so we make sure
 21.1784 +    // to balance the stack if they're used as a statement.
 21.1785 +    node->expression()->accept(this);
 21.1786 +    if (!node->expression()->type()->isVoid())
 21.1787 +        __ pop();
 21.1788 +}
 21.1789 +
 21.1790 +static inline bool
 21.1791 +IsCompositeValueType(Type *type)
 21.1792 +{
 21.1793 +    return type->isStruct() ||
 21.1794 +           (type->isArray() && type->isFixedLength());
 21.1795 +}
 21.1796 +
 21.1797 +static inline Array *
 21.1798 +StringLiteralToArray(Zone *zone, StringLiteral *node)
 21.1799 +{
 21.1800 +    Local<Type> type(zone, node->type());
 21.1801 +    Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
 21.1802 +    if (!map)
 21.1803 +        return NULL;
 21.1804 +
 21.1805 +    return Array::NewString(zone,
 21.1806 +                            map,
 21.1807 +                            node->string()->raw(),
 21.1808 +                            node->string()->length(),
 21.1809 +                            Heap::Tenure_Old);
 21.1810 +}
 21.1811 +
 21.1812 +void
 21.1813 +BytecodeCompiler::visit(Assignment *node)
 21.1814 +{
 21.1815 +    Local<Type> left(zone_, node->type());
 21.1816 +    Local<Type> right(zone_, node->expression()->type());
 21.1817 +
 21.1818 +    // The first step is three sub-steps:
 21.1819 +    //
 21.1820 +    //   (1) Bind the left-hand side.
 21.1821 +    //   -- If a cumulative operation (+=, etc):
 21.1822 +    //   (2) Save a copy of the binding on the stack.
 21.1823 +    //   (3) Dereference the binding to get a value.
 21.1824 +    //
 21.1825 +    if (node->lvalue()->isNameProxy()) {
 21.1826 +        NameProxy *proxy = node->lvalue()->toNameProxy();
 21.1827 +        Variable *var = proxy->binding()->toVariable();
 21.1828 +
 21.1829 +        // We need to fetch the variable under the following circumstances:
 21.1830 +        //  (1) The variable is a reference, since we'll store into the ref.
 21.1831 +        //  (2) The variable is a fixed array, since we need to copy into it.
 21.1832 +        //  (3) The variable is a struct, since we need to copy into it.
 21.1833 +        if (var->type()->isReference() || IsCompositeValueType(var->type()))
 21.1834 +            __ get(var);
 21.1835 +
 21.1836 +        // Get the value if needed.
 21.1837 +        if (node->token() != TOK_ASSIGN) {
 21.1838 +            // += etc is not allowed on arrays.
 21.1839 +            assert(!var->type()->isArray());
 21.1840 +
 21.1841 +            if (var->location() == Variable::ENVIRONMENT)
 21.1842 +                getEnvSlot(var);
 21.1843 +
 21.1844 +            if (var->type()->isReference()) {
 21.1845 +                __ dup();
 21.1846 +                __ getref(var->type()->contained());
 21.1847 +            } else if (var->location() != Variable::ENVIRONMENT) {
 21.1848 +                __ get(var);
 21.1849 +            }
 21.1850 +        }
 21.1851 +    } else if (node->lvalue()->isFieldExpression()) {
 21.1852 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
 21.1853 +        __ note_position(expr->pos());
 21.1854 +
 21.1855 +        expr->left()->accept(this);
 21.1856 +
 21.1857 +        if (node->token() != TOK_ASSIGN)
 21.1858 +            __ dup();
 21.1859 +
 21.1860 +        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
 21.1861 +            __ getfield(expr->fieldIndex(), left);
 21.1862 +    } else {
 21.1863 +        IndexExpression *index = node->lvalue()->toIndexExpression();
 21.1864 +        __ note_position(index->pos());
 21.1865 +
 21.1866 +        index->left()->accept(this);
 21.1867 +        index->right()->accept(this);
 21.1868 +
 21.1869 +        if (node->token() != TOK_ASSIGN)
 21.1870 +            __ dup2();
 21.1871 +
 21.1872 +        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
 21.1873 +            __ getelem(left);
 21.1874 +    }
 21.1875 +
 21.1876 +    if (node->token() == TOK_ASSIGN) {
 21.1877 +        // Special case: if the left-hand side is a string literal, we must
 21.1878 +        // spawn a new copy (:TODO: something about const?)
 21.1879 +        if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
 21.1880 +            Local<Array> string(zone_,
 21.1881 +                    StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
 21.1882 +            if (!string)
 21.1883 +                return;
 21.1884 +
 21.1885 +            Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
 21.1886 +            __ note_position(node->expression()->pos());
 21.1887 +            __ int_(string->length());
 21.1888 +            __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
 21.1889 +            __ object(string);
 21.1890 +            __ copyarray();
 21.1891 +        } else {
 21.1892 +            node->expression()->accept(this);
 21.1893 +        }
 21.1894 +    } else {
 21.1895 +        visitForALU(left, node->expression());
 21.1896 +
 21.1897 +        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
 21.1898 +        __ note_position(node->pos());
 21.1899 +        __ binary(TokenToOpcode(alu));
 21.1900 +    }
 21.1901 +
 21.1902 +    // Emit the store.
 21.1903 +    if (left->isArray() && left->isFixedLength()) {
 21.1904 +        // (x = y) returns the left-hand side; if |x| is a fixed-length array,
 21.1905 +        // then |y| is as well, and we perform a deep copy.
 21.1906 +        assert(right->isFixedLength());
 21.1907 +        __ note_position(node->pos());
 21.1908 +        __ copyarray();
 21.1909 +    } else if (left->isStruct()) {
 21.1910 +        // Structs have value semantics, so emit a full copy. We don't break
 21.1911 +        // this down into u-ops, to avoid unnecessary bytecode explosion.
 21.1912 +        assert(right->isStruct());
 21.1913 +        __ note_position(node->pos());
 21.1914 +        __ copystruct();
 21.1915 +    } else if (node->lvalue()->isNameProxy()) {
 21.1916 +        NameProxy *proxy = node->lvalue()->toNameProxy();
 21.1917 +        Variable *var = proxy->binding()->toVariable();
 21.1918 +
 21.1919 +        if (var->type()->isReference())
 21.1920 +            __ setref(var->type()->contained());
 21.1921 +        else if (var->location() == Variable::ENVIRONMENT)
 21.1922 +            setEnvSlot(var);
 21.1923 +        else
 21.1924 +            __ set(var);
 21.1925 +    } else if (node->lvalue()->isFieldExpression()) {
 21.1926 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
 21.1927 +        __ setfield(expr->fieldIndex(), left);
 21.1928 +    } else {
 21.1929 +        __ setelem(left);
 21.1930 +    }
 21.1931 +}
 21.1932 +
 21.1933 +void
 21.1934 +BytecodeCompiler::visit(IncDecExpression *node)
 21.1935 +{
 21.1936 +    // In the postfix case, the logic looks like:
 21.1937 +    //      (1) Bind       -> REF
 21.1938 +    //      (2) Dup        -> REF REF
 21.1939 +    //      (3) Fetch      -> REF VAL
 21.1940 +    //      (4) Swap       -> VAL REF
 21.1941 +    //      (5) Pick       -> VAL REF VAL
 21.1942 +    //      (6) Add        -> VAL REF VAL+1
 21.1943 +    //      (7) Store      -> VAL VAL+1
 21.1944 +    //      (8) Drop       -> VAL
 21.1945 +    //
 21.1946 +    // In the prefix case, the logic looks like:
 21.1947 +    //      (1) Bind       -> REF
 21.1948 +    //      (2) Dup        -> REF REF
 21.1949 +    //      (3) Fetch      -> REF VAL
 21.1950 +    //      --
 21.1951 +    //      --
 21.1952 +    //      (6) Add        -> REF VAL+1
 21.1953 +    //      (7) Store      -> VAL+1
 21.1954 +    //      --
 21.1955 +    //
 21.1956 +    // This is squirrely enough such that we don't bother sharing too much
 21.1957 +    // with the above.
 21.1958 +    // 
 21.1959 +    // Note: We simulate a "Pick" operation with a dup2+pop.
 21.1960 +
 21.1961 +    // This is steps (1) to (5).
 21.1962 +    Expression *expr = node->expression();
 21.1963 +    if (expr->isNameProxy()) {
 21.1964 +        NameProxy *proxy = expr->toNameProxy();
 21.1965 +        Variable *var = proxy->binding()->toVariable();
 21.1966 +
 21.1967 +        // Bind.
 21.1968 +        if (var->location() == Variable::ENVIRONMENT)
 21.1969 +            getEnvSlot(var);
 21.1970 +        else if (var->type()->isReference() || var->type()->isArray())
 21.1971 +            __ get(var);
 21.1972 +
 21.1973 +        // Dup and fetch.
 21.1974 +        if (var->type()->isReference()) {
 21.1975 +            __ dup();
 21.1976 +            __ getref(node->type());
 21.1977 +            if (node->postfix()) {
 21.1978 +                __ swap();
 21.1979 +                __ pick2();
 21.1980 +            }
 21.1981 +        } else {
 21.1982 +            assert(!var->type()->isArray());
 21.1983 +            if (var->location() != Variable::ENVIRONMENT)
 21.1984 +                __ get(var);
 21.1985 +            if (node->postfix())
 21.1986 +                __ dup();
 21.1987 +        }
 21.1988 +    } else if (expr->isFieldExpression()) {
 21.1989 +        FieldExpression *field = expr->toFieldExpression();
 21.1990 +
 21.1991 +        field->left()->accept(this);
 21.1992 +        __ dup();
 21.1993 +        __ getfield(field->fieldIndex(), field->type());
 21.1994 +
 21.1995 +        if (node->postfix()) {
 21.1996 +            // The stack looks like this now:
 21.1997 +            // OBJECT VALUE
 21.1998 +            __ swap();          // VALUE OBJECT
 21.1999 +            __ pick2();         // VALUE OBJECT VALUE
 21.2000 +        }
 21.2001 +    } else {
 21.2002 +        IndexExpression *index = expr->toIndexExpression();
 21.2003 +        __ note_position(index->pos());
 21.2004 +
 21.2005 +        index->left()->accept(this);
 21.2006 +        index->right()->accept(this);
 21.2007 +
 21.2008 +        assert(!node->type()->isArray());
 21.2009 +        __ dup2();
 21.2010 +        __ getelem(node->type());
 21.2011 +
 21.2012 +        if (node->postfix()) {
 21.2013 +            // The stack looks like this now:
 21.2014 +            // ARRAY INDEX VALUE
 21.2015 +            //
 21.2016 +            // So we must use a PICK operation to rotate the stack into position.
 21.2017 +            __ roll3();         // INDEX VALUE ARRAY
 21.2018 +            __ roll3();         // VALUE ARRAY INDEX
 21.2019 +            __ pick3();         // VALUE ARRAY INDEX VALUE
 21.2020 +        }
 21.2021 +    }
 21.2022 +
 21.2023 +    // Perform step (6).
 21.2024 +    if (node->type()->isFloat()) {
 21.2025 +        __ float_(1.0);
 21.2026 +    } else {
 21.2027 +        assert(node->type()->isInt32());
 21.2028 +        __ int_(1);
 21.2029 +    }
 21.2030 +
 21.2031 +    __ note_position(node->pos());
 21.2032 +    if (node->token() == TOK_INCREMENT)
 21.2033 +        __ binary(OP_ADD);
 21.2034 +    else
 21.2035 +        __ binary(OP_SUB);
 21.2036 +
 21.2037 +    // Perform step (7).
 21.2038 +    if (expr->isNameProxy()) {
 21.2039 +        NameProxy *proxy = expr->toNameProxy();
 21.2040 +        Variable *var = proxy->binding()->toVariable();
 21.2041 +
 21.2042 +        if (var->type()->isReference())
 21.2043 +            __ setref(node->type());
 21.2044 +        else if (var->location() == Variable::ENVIRONMENT)
 21.2045 +            setEnvSlot(var);
 21.2046 +        else
 21.2047 +            __ set(var);
 21.2048 +    } else if (expr->isFieldExpression()) {
 21.2049 +        FieldExpression *field = expr->toFieldExpression();
 21.2050 +        __ setfield(field->fieldIndex(), field->type());
 21.2051 +    } else {
 21.2052 +        assert(expr->isIndexExpression());
 21.2053 +        __ setelem(node->type());
 21.2054 +    }
 21.2055 +
 21.2056 +    // Perform step (8).
 21.2057 +    if (node->postfix())
 21.2058 +        __ pop();
 21.2059 +}
 21.2060 +
 21.2061 +void
 21.2062 +BytecodeCompiler::visitForALU(Type *needed, Expression *node)
 21.2063 +{
 21.2064 +    node->accept(this);
 21.2065 +    if (needed->isFloat() && !node->type()->isFloat())
 21.2066 +        __ cvt_i2f();
 21.2067 +    else
 21.2068 +        assert(needed->primitive() == node->type()->primitive());
 21.2069 +}
 21.2070 +
 21.2071 +static inline Type *
 21.2072 +GetCoercionType(TokenKind tok, Type *left, Type *right)
 21.2073 +{
 21.2074 +    if (left->isFloat())
 21.2075 +        return left;
 21.2076 +    return right;
 21.2077 +}
 21.2078 +
 21.2079 +void
 21.2080 +BytecodeCompiler::visit(UnaryExpression *node)
 21.2081 +{
 21.2082 +    Local<Type> out(zone_, ((Expression *)node)->type());
 21.2083 +
 21.2084 +    switch (node->token()) {
 21.2085 +      case TOK_MINUS:
 21.2086 +      {
 21.2087 +        Local<Type> type(zone_, node->expression()->type());
 21.2088 +        node->expression()->accept(this);
 21.2089 +        
 21.2090 +        if (out->isFloat())
 21.2091 +            __ neg_f();
 21.2092 +        else
 21.2093 +            __ neg();
 21.2094 +        break;
 21.2095 +      }
 21.2096 +
 21.2097 +      case TOK_NOT:
 21.2098 +      {
 21.2099 +        Local<Type> type(zone_, node->expression()->type());
 21.2100 +        node->expression()->accept(this);
 21.2101 +        
 21.2102 +        if (out->isFloat())
 21.2103 +            __ not_f();
 21.2104 +        else
 21.2105 +            __ not_();
 21.2106 +        break;
 21.2107 +      }
 21.2108 +
 21.2109 +      case TOK_LABEL:
 21.2110 +      {
 21.2111 +        Local<Type> from(zone_, node->expression()->type());
 21.2112 +
 21.2113 +        node->expression()->accept(this);
 21.2114 +        if (!from->isFloat() && out->isFloat())
 21.2115 +            __ bits_f2i();
 21.2116 +        else if (from->isFloat() && !out->isFloat())
 21.2117 +            __ bits_i2f();
 21.2118 +        break;
 21.2119 +      }
 21.2120 +
 21.2121 +      case TOK_SIZEOF:
 21.2122 +      {
 21.2123 +        Local<Type> type(zone_, node->expression()->type());
 21.2124 +        if (type->isFixedLength()) {
 21.2125 +            __ int_(type->fixedLength());
 21.2126 +        } else {
 21.2127 +            node->expression()->accept(this);
 21.2128 +            __ sizeof_();
 21.2129 +        }
 21.2130 +        break;
 21.2131 +      }
 21.2132 +
 21.2133 +      default:
 21.2134 +        assert(node->token() == TOK_TILDE);
 21.2135 +        node->expression()->accept(this);
 21.2136 +        __ bitnot();
 21.2137 +        break;
 21.2138 +    }
 21.2139 +}
 21.2140 +
 21.2141 +void
 21.2142 +BytecodeCompiler::visit(BinaryExpression *node)
 21.2143 +{
 21.2144 +    if (node->token() == TOK_AND || node->token() == TOK_OR) {
 21.2145 +        Label success, failure, done;
 21.2146 +        visitForTest(node, &success, &failure, &success);
 21.2147 +        __ bind(&success);
 21.2148 +        __ int_(1);
 21.2149 +        __ drop(1);         // Otherwise, the stack depth will be +1 too much.
 21.2150 +        __ jump(&done);
 21.2151 +        __ bind(&failure);
 21.2152 +        __ int_(0);
 21.2153 +        __ bind(&done);
 21.2154 +        return;
 21.2155 +    }
 21.2156 +
 21.2157 +    Local<Type> leftType(zone_, node->left()->type());
 21.2158 +    Local<Type> rightType(zone_, node->right()->type());
 21.2159 +    Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
 21.2160 +
 21.2161 +    visitForALU(coerce, node->left());
 21.2162 +    visitForALU(coerce, node->right());
 21.2163 +
 21.2164 +    Opcode op = TokenToOpcode(node->token());
 21.2165 +    if (node->type()->isFloat())
 21.2166 +        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
 21.2167 +
 21.2168 +    __ note_position(node->pos());
 21.2169 +    __ binary(op);
 21.2170 +}
 21.2171 +
 21.2172 +void
 21.2173 +BytecodeCompiler::visit(IndexExpression *node)
 21.2174 +{
 21.2175 +    node->left()->accept(this);
 21.2176 +    node->right()->accept(this);
 21.2177 +    __ note_position(node->pos());
 21.2178 +    __ getelem(node->type());
 21.2179 +}
 21.2180 +
 21.2181 +void
 21.2182 +BytecodeCompiler::visit(FieldExpression *node)
 21.2183 +{
 21.2184 +    node->left()->accept(this);
 21.2185 +    __ getfield(node->fieldIndex(), node->type());
 21.2186 +}
 21.2187 +
 21.2188 +void
 21.2189 +BytecodeCompiler::visit(ReturnStatement *node)
 21.2190 +{
 21.2191 +    if (node->expression()) {
 21.2192 +        node->expression()->accept(this);
 21.2193 +        __ return_();
 21.2194 +    } else {
 21.2195 +        __ returnvoid();
 21.2196 +    }
 21.2197 +}
 21.2198 +
 21.2199 +void
 21.2200 +BytecodeCompiler::visitForTest(Expression *expression,
 21.2201 +                               Label *trueBranch,
 21.2202 +                               Label *falseBranch,
 21.2203 +                               Label *fallthrough)
 21.2204 +{
 21.2205 +    TokenKind token = ToCompare(expression);
 21.2206 +    if (token == TOK_EOF || token == TOK_NOT) {
 21.2207 +        if (token == TOK_EOF)
 21.2208 +            expression->accept(this);
 21.2209 +        else
 21.2210 +            expression->toUnaryExpression()->expression()->accept(this);
 21.2211 +        
 21.2212 +        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
 21.2213 +
 21.2214 +        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
 21.2215 +        if (expression->type()->isFloat())
 21.2216 +            op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
 21.2217 +
 21.2218 +        if (fallthrough == falseBranch)
 21.2219 +            __ j(op, trueBranch);
 21.2220 +        else
 21.2221 +            __ j(op, falseBranch); 
 21.2222 +        return;
 21.2223 +    }
 21.2224 +
 21.2225 +    BinaryExpression *binary = expression->toBinaryExpression();
 21.2226 +
 21.2227 +    if (token == TOK_AND || token == TOK_OR) {
 21.2228 +        Label next;
 21.2229 +        if (token == TOK_AND)
 21.2230 +            visitForTest(binary->left(), &next, falseBranch, &next);
 21.2231 +        else
 21.2232 +            visitForTest(binary->left(), trueBranch, &next, &next);
 21.2233 +        __ bind(&next);
 21.2234 +        visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
 21.2235 +        return;
 21.2236 +    }
 21.2237 +
 21.2238 +    Opcode op = CompareTokenToJump(token);
 21.2239 +    if (fallthrough == trueBranch)
 21.2240 +        op = Invert(op);
 21.2241 +
 21.2242 +    Local<Type> leftType(zone_, binary->left()->type());
 21.2243 +    Local<Type> rightType(zone_, binary->right()->type());
 21.2244 +    Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
 21.2245 +
 21.2246 +    visitForALU(coerce, binary->left());
 21.2247 +    visitForALU(coerce, binary->right());
 21.2248 +    if (coerce->isFloat())
 21.2249 +        op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
 21.2250 +
 21.2251 +    if (fallthrough == trueBranch)
 21.2252 +        __ j(op, falseBranch);
 21.2253 +    else
 21.2254 +        __ j(op, trueBranch);
 21.2255 +}
 21.2256 +
 21.2257 +void
 21.2258 +BytecodeCompiler::visit(ForStatement *node)
 21.2259 +{
 21.2260 +    AutoEnterScope forScope(this, node->scope());
 21.2261 +
 21.2262 +    recordLifoSlot(node->scope());
 21.2263 +
 21.2264 +    Label join, update;
 21.2265 +    LoopScope loop(scope_, &join, &update, &loop_);
 21.2266 +
 21.2267 +    if (node->initialization())
 21.2268 +        node->initialization()->accept(this);
 21.2269 +
 21.2270 +    Label header, test;
 21.2271 +    if (node->condition())
 21.2272 +        __ jump(&test);
 21.2273 +
 21.2274 +    __ bind(&header);
 21.2275 +    node->body()->accept(this);
 21.2276 +
 21.2277 +    __ bind(&update);
 21.2278 +    if (node->update())
 21.2279 +        node->update()->accept(this);
 21.2280 +
 21.2281 +    if (node->condition()) {
 21.2282 +        __ bind(&test);
 21.2283 +        visitForTest(node->condition(), &header, &join, &join);
 21.2284 +    } else {
 21.2285 +        __ jump(&header);
 21.2286 +    }
 21.2287 +
 21.2288 +    __ bind(&join);
 21.2289 +
 21.2290 +    if (node->scope())
 21.2291 +        unwindTo(node->scope()->enclosing());
 21.2292 +    assert(__ stackDepth() == 0);
 21.2293 +}
 21.2294 +
 21.2295 +void
 21.2296 +BytecodeCompiler::visit(WhileStatement *node)
 21.2297 +{
 21.2298 +    Label header, join;
 21.2299 +
 21.2300 +    __ bind(&header);
 21.2301 +
 21.2302 +    LoopScope loop(scope_, &join, &header, &loop_);
 21.2303 +
 21.2304 +    if (node->token() == TOK_WHILE) {
 21.2305 +        Label body;
 21.2306 +
 21.2307 +        visitForTest(node->condition(), &body, &join, &body);
 21.2308 +        __ bind(&body);
 21.2309 +        node->body()->accept(this);
 21.2310 +        __ jump(&header);
 21.2311 +    } else {
 21.2312 +        node->body()->accept(this);
 21.2313 +        visitForTest(node->condition(), &header, &join, &join);
 21.2314 +    }
 21.2315 +
 21.2316 +    __ bind(&join);
 21.2317 +}
 21.2318 +
 21.2319 +void
 21.2320 +BytecodeCompiler::visit(BreakStatement *node)
 21.2321 +{
 21.2322 +    unwindTo(loop_->scope());
 21.2323 +    __ jump(loop_->break_());
 21.2324 +}
 21.2325 +
 21.2326 +void
 21.2327 +BytecodeCompiler::visit(ContinueStatement *node)
 21.2328 +{
 21.2329 +    unwindTo(loop_->scope());
 21.2330 +    __ jump(loop_->continue_());
 21.2331 +}
 21.2332 +
 21.2333 +void
 21.2334 +BytecodeCompiler::visit(BlockStatement *node)
 21.2335 +{
 21.2336 +    AutoEnterScope blockScope(this, node->scope());
 21.2337 +
 21.2338 +    recordLifoSlot(node->scope());
 21.2339 +
 21.2340 +    for (size_t i = 0; i < node->statements()->length(); i++) {
 21.2341 +        Statement *statement = node->statements()->at(i);
 21.2342 +        statement->accept(this);
 21.2343 +        assert(__ stackDepth() == 0);
 21.2344 +    }
 21.2345 +
 21.2346 +    // We don't bother emitting an "unwind" instruction for function scopes,
 21.2347 +    // since this is taken care of by the calling convention.
 21.2348 +    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
 21.2349 +        unwindTo(node->scope()->enclosing());
 21.2350 +}
 21.2351 +
 21.2352 +void
 21.2353 +BytecodeCompiler::visit(IntegerLiteral *node)
 21.2354 +{
 21.2355 +    __ int_(node->value());
 21.2356 +}
 21.2357 +
 21.2358 +void
 21.2359 +BytecodeCompiler::visit(BooleanLiteral *node)
 21.2360 +{
 21.2361 +    if (node->token() == TOK_TRUE)
 21.2362 +        __ true_();
 21.2363 +    else
 21.2364 +        __ false_();
 21.2365 +}
 21.2366 +
 21.2367 +void
 21.2368 +BytecodeCompiler::visit(FloatLiteral *node)
 21.2369 +{
 21.2370 +    __ float_((float)node->value());
 21.2371 +}
 21.2372 +
 21.2373 +void
 21.2374 +BytecodeCompiler::visit(StringLiteral *node)
 21.2375 +{
 21.2376 +    Local<Array> array(zone_, StringLiteralToArray(zone_, node));
 21.2377 +    if (!array)
 21.2378 +        return;
 21.2379 +
 21.2380 +    __ note_position(node->pos());
 21.2381 +    __ object(array);
 21.2382 +}
 21.2383 +
 21.2384 +void
 21.2385 +BytecodeCompiler::getEnvSlot(Variable *var)
 21.2386 +{
 21.2387 +    assert(var->scope()->kind() == Scope::GLOBAL);
 21.2388 +    __ getglobal(var);
 21.2389 +}
 21.2390 +
 21.2391 +void
 21.2392 +BytecodeCompiler::setEnvSlot(Variable *var)
 21.2393 +{
 21.2394 +    assert(var->scope()->kind() == Scope::GLOBAL);
 21.2395 +    __ setglobal(var);
 21.2396 +}
 21.2397 +
 21.2398 +static bool
 21.2399 +FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
 21.2400 +{
 21.2401 +    Local<Array> string(zone);
 21.2402 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
 21.2403 +        Expression *expr = literal->expressions()->at(i);
 21.2404 +        StringLiteral *lit = expr->toStringLiteral();
 21.2405 +        if ((string = StringLiteralToArray(zone, lit)) == NULL)
 21.2406 +            return false;
 21.2407 +
 21.2408 +        array->writeObject(zone, i, string);
 21.2409 +
 21.2410 +        if (string->length() > *maxsize)
 21.2411 +            *maxsize = string->length();
 21.2412 +
 21.2413 +        assert(!array->type()->contained()->isFixedLength() ||
 21.2414 +                array->type()->contained()->fixedLength() >= string->length());
 21.2415 +    }
 21.2416 +
 21.2417 +    return true;
 21.2418 +}
 21.2419 +
 21.2420 +static bool
 21.2421 +FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
 21.2422 +{
 21.2423 +    assert(array->type()->fixedLength() == literal->expressions()->length());
 21.2424 +
 21.2425 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
 21.2426 +        Expression *expr = literal->expressions()->at(i);
 21.2427 +        if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
 21.2428 +            array->writeInt32(i, lit->value());
 21.2429 +            continue;
 21.2430 +        }
 21.2431 +        if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
 21.2432 +            if (lit->token() == TOK_TRUE)
 21.2433 +                array->writeInt32(i, 1);
 21.2434 +            else
 21.2435 +                array->writeInt32(i, 0);
 21.2436 +            continue;
 21.2437 +        }
 21.2438 +        if (FloatLiteral *lit = expr->asFloatLiteral()) {
 21.2439 +            array->writeFloat(i, (float)lit->value());
 21.2440 +            continue;
 21.2441 +        }
 21.2442 +
 21.2443 +        // Unrecognized literal type.
 21.2444 +        assert(false);
 21.2445 +    }
 21.2446 +
 21.2447 +    return true;
 21.2448 +}
 21.2449 +
 21.2450 +static bool
 21.2451 +TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
 21.2452 +                     unsigned *maxsize)
 21.2453 +{
 21.2454 +    assert(type->fixedLength() == literal->expressions()->length());
 21.2455 +
 21.2456 +    Local<Type> contained(zone, type->contained());
 21.2457 +    if (contained->isCharArray())
 21.2458 +        return FillArrayLiteral_String(zone, array, literal, maxsize);
 21.2459 +
 21.2460 +    if (!contained->isArray())
 21.2461 +        return FillArrayLiteral_Primitive(zone, array, literal);
 21.2462 +
 21.2463 +    Local<Array> subarray(zone);
 21.2464 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
 21.2465 +        Expression *expr = literal->expressions()->at(i);
 21.2466 +        subarray = Array::cast(array->readObject(i));
 21.2467 +        if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
 21.2468 +            return false;
 21.2469 +    }
 21.2470 +
 21.2471 +    return true;
 21.2472 +}
 21.2473 +
 21.2474 +static Array *
 21.2475 +BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
 21.2476 +{
 21.2477 +    Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
 21.2478 +    if (!root)
 21.2479 +        return NULL;
 21.2480 +
 21.2481 +    // This should have allocated everything in the array, so all we need to
 21.2482 +    // do is traverse down to the lowest levels and copy things.
 21.2483 +    Local<Type> type(zone, map->type());
 21.2484 +    if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
 21.2485 +        return NULL;
 21.2486 +
 21.2487 +    return root;
 21.2488 +}
 21.2489 +
 21.2490 +static inline bool
 21.2491 +ArrayContainsCharBuffers(Type *type)
 21.2492 +{
 21.2493 +    if (type->contained()->isArray())
 21.2494 +        return ArrayContainsCharBuffers(type->contained());
 21.2495 +    return type->isCharArray();
 21.2496 +}
 21.2497 +
 21.2498 +void
 21.2499 +BytecodeCompiler::visit(VariableDeclaration *node)
 21.2500 +{
 21.2501 +    Variable *var = node->variable();
 21.2502 +    
 21.2503 +    Local<Type> type(zone_, var->type());
 21.2504 +    if (type->isArray()) {
 21.2505 +        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
 21.2506 +        __ note_position(node->pos());
 21.2507 +
 21.2508 +        Local<Type> right(zone_);
 21.2509 +        if (node->initialization())
 21.2510 +            right = node->initialization()->type();
 21.2511 +
 21.2512 +        // There are a few methods for allocating, here:
 21.2513 +        // (1) If the array is fixed,
 21.2514 +        //    (a) Initializer not present,
 21.2515 +        //              NEWFIXED
 21.2516 +        //    (b) Left is const non-string:
 21.2517 +        //              <nothing>
 21.2518 +        //    (b) Otherwise:
 21.2519 +        //              NEWFIXED
 21.2520 +        //              COPYARRAY
 21.2521 +        // (2) If the array is not fixed,
 21.2522 +        //    (a) Initializer is not present,
 21.2523 +        //              NEWEMPTY
 21.2524 +        //    (b) Initializer is not a string literal,
 21.2525 +        //        or left is const:
 21.2526 +        //              <nothing>
 21.2527 +        //    (c) Initializer is a string literal,
 21.2528 +        //              NEWSIZED
 21.2529 +        //              COPYARRAY
 21.2530 +        //
 21.2531 +
 21.2532 +        Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
 21.2533 +                              ? Heap::Tenure_Old
 21.2534 +                              : Heap::Tenure_Default;
 21.2535 +
 21.2536 +        if (Expression *init = node->initialization()) {
 21.2537 +            if (init->isArrayLiteral()) {
 21.2538 +                unsigned maxsize = 0;
 21.2539 +                Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
 21.2540 +                if (!array)
 21.2541 +                    return;
 21.2542 +
 21.2543 +                assert(type->isFixedLength());
 21.2544 +
 21.2545 +                if (type->isConst()) {
 21.2546 +                    __ object(array);
 21.2547 +                } else if (ArrayContainsCharBuffers(type)) {
 21.2548 +                    // This array contains mutable char buffers, so
 21.2549 +                    // unfortunately this gets a little more complicated. We
 21.2550 +                    // compute the maximum size needed for the innermost
 21.2551 +                    // string, which is similar to SP1. This means we can use
 21.2552 +                    // CopyArray rather than individually emit opcodes to clone
 21.2553 +                    // every string.
 21.2554 +                    Local<Type> child(zone_, type);
 21.2555 +                    for (size_t i = 0; i < type->levels() - 1; i++) {
 21.2556 +                        __ int_(child->fixedLength());
 21.2557 +                        child = child->contained();
 21.2558 +                    }
 21.2559 +                    __ int_(maxsize);
 21.2560 +                    __ newarray(OP_NEWSIZED, map, tenure);
 21.2561 +                    __ object(array);
 21.2562 +                    __ copyarray();
 21.2563 +                } else {
 21.2564 +                    __ newarray(OP_NEWFIXED, map, tenure);
 21.2565 +                    __ object(array);
 21.2566 +                    __ copyarray();
 21.2567 +                }
 21.2568 +            } else if (type->isFixedLength()) {
 21.2569 +                // Note in the case of:
 21.2570 +                // const String:buffer[50] = "hello";
 21.2571 +                //
 21.2572 +                // We want to preserve sizeof(buffer) == 50.
 21.2573 +                if (type->isConst() && !type->isCharArray()) {
 21.2574 +                    init->accept(this);
 21.2575 +                } else {
 21.2576 +                    __ newarray(OP_NEWFIXED, map, tenure);
 21.2577 +                    init->accept(this);
 21.2578 +                    __ copyarray();
 21.2579 +                }
 21.2580 +            } else if (!type->isConst() && init->isStringLiteral()) {
 21.2581 +                // This is a degenerate case of ArrayLiteral.
 21.2582 +                __ int_(right->fixedLength());
 21.2583 +                __ newarray(OP_NEWSIZED, map, tenure);
 21.2584 +                init->accept(this);
 21.2585 +                __ copyarray();
 21.2586 +            } else if (type->isConst()) {
 21.2587 +                init->accept(this);
 21.2588 +            }
 21.2589 +        } else if (type->isFixedLength()) {
 21.2590 +            __ newarray(OP_NEWFIXED, map, tenure);
 21.2591 +        } else {
 21.2592 +#if 0
 21.2593 +            if (node->postDimensions()) {
 21.2594 +                for (size_t i = 0; i < node->postDimensions()->length(); i++) {
 21.2595 +                    Expression *expr = node->postDimensions()->at(i);
 21.2596 +                    if (expr)
 21.2597 +                        expr->accept(this);
 21.2598 +                    else
 21.2599 +                        __ int_(0);
 21.2600 +                }
 21.2601 +                __ newarray(OP_NEWSIZED, map, tenure);
 21.2602 +            } else {
 21.2603 +                __ newarray(OP_NEWEMPTY, map, tenure);
 21.2604 +            }
 21.2605 +#endif
 21.2606 +        }
 21.2607 +    } else if (type->isStruct()) {
 21.2608 +        Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
 21.2609 +
 21.2610 +        // Because structs can contain arrays, any sort of composition
 21.2611 +        // triggers non-LIFO allocation. This is just for correctness.
 21.2612 +        // We could do better by:
 21.2613 +        //  (1) Limiting to structs that just (recursively) contain arrays,
 21.2614 +        //  (2) Swap Stack for Default tenure in Struct::New
 21.2615 +        //  (3) JIT analysis
 21.2616 +        if (var->scope()->kind() == Scope::GLOBAL)
 21.2617 +            __ newstruct(map, Heap::Tenure_Old);
 21.2618 +        else if (var->needsHeapAllocation() || map->composed())
 21.2619 +            __ newstruct(map, Heap::Tenure_Default);
 21.2620 +        else
 21.2621 +            __ newstruct(map, Heap::Tenure_Stack);
 21.2622 +    } else {
 21.2623 +        if (node->initialization()) {
 21.2624 +            node->initialization()->accept(this);
 21.2625 +        } else {
 21.2626 +            if (type->isInt32OrEnum() || type->isBool()) {
 21.2627 +                __ int_(0);
 21.2628 +            } else {
 21.2629 +                assert(type->isFloat());
 21.2630 +                __ float_(0);
 21.2631 +            }
 21.2632 +        }
 21.2633 +    }
 21.2634 +
 21.2635 +    if (var->location() == Variable::STACK) {
 21.2636 +        __ setlocal(var);
 21.2637 +        locals_->set(zone_, var->slot(), var->type());
 21.2638 +    } else {
 21.2639 +        assert(var->location() == Variable::ENVIRONMENT);
 21.2640 +        setEnvSlot(var);
 21.2641 +    }
 21.2642 +
 21.2643 +    __ pop();
 21.2644 +}
 21.2645 +
 21.2646 +void
 21.2647 +BytecodeCompiler::visit(CallExpression *node)
 21.2648 +{
 21.2649 +#if 0
 21.2650 +    Local<Type> funType(zone_, node->callee()->type());
 21.2651 +
 21.2652 +    // Sniff out natives, which have a specific opcode and are guaranteed to
 21.2653 +    // be called via name proxy.
 21.2654 +    NamedFunction *native = NULL;
 21.2655 +    if (funType->isNative())
 21.2656 +        native = node->callee()->toNameProxy()->binding()->toNamedFunction();
 21.2657 +
 21.2658 +    Local<Type> given(zone_);
 21.2659 +    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
 21.2660 +        Expression *arg = node->arguments()->at(i);
 21.2661 +
 21.2662 +        given = arg->type();
 21.2663 +
 21.2664 +        // We need to compute a reference if the parameter was in the form:
 21.2665 +        //  f(&a)
 21.2666 +        // Note this form does not allow: f({})
 21.2667 +        // 
 21.2668 +        // We also need to compute references for all variadic native
 21.2669 +        // arguments, but arrays and references are already in the
 21.2670 +        // appropriate form.
 21.2671 +        bool mustPushReference = false;
 21.2672 +        if (i >= funType->parameters()->length()) {
 21.2673 +            assert(funType->isNative() && funType->isNativeVariadic());
 21.2674 +            mustPushReference = !given->isArray() && !given->isReference();
 21.2675 +        } else if (funType->parameterAt(i)->isReference()) {
 21.2676 +            mustPushReference = !given->isReference();
 21.2677 +        }
 21.2678 +
 21.2679 +        // If a native is passed to a native, it must only be one level deep.
 21.2680 +        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
 21.2681 +
 21.2682 +        if (mustPushReference) {
 21.2683 +            if (arg->isNameProxy()) {
 21.2684 +                // :TODO: test with functions and globals
 21.2685 +                // Compute a reference to the name.
 21.2686 +                Variable *var = arg->toNameProxy()->binding()->toVariable();
 21.2687 +                __ note_position(node->pos());
 21.2688 +                __ newref(var);
 21.2689 +            } else if (arg->isFieldExpression()) {
 21.2690 +                FieldExpression *expr = arg->toFieldExpression();
 21.2691 +                expr->left()->accept(this);
 21.2692 +                __ note_position(expr->pos());
 21.2693 +                __ fieldref_lifo(expr->fieldIndex());
 21.2694 +            } else {
 21.2695 +                // We don't know how to, or can't, build a direct reference to
 21.2696 +                // this type. Make an indirect one, by taking the top of the
 21.2697 +                // stack and boxing it up.
 21.2698 +                arg->accept(this);
 21.2699 +                __ note_position(node->pos());
 21.2700 +                __ slotref_lifo();
 21.2701 +            }
 21.2702 +        } else {
 21.2703 +            arg->accept(this);
 21.2704 +        }
 21.2705 +    }
 21.2706 +
 21.2707 +    unsigned argc = node->arguments()->length();
 21.2708 +
 21.2709 +    // If there are missing arguments, then we're not done and have to push
 21.2710 +    // default parameters.
 21.2711 +    Local<Box> box(zone_);
 21.2712 +    Local<Array> array(zone_);
 21.2713 +    Local<ArrayMap> map(zone_);
 21.2714 +    for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
 21.2715 +        box = Box::cast(funType->defaults()->at(i));
 21.2716 +
 21.2717 +        if (box->type()->isPod()) {
 21.2718 +            if (box->type()->pod() == PrimitiveType_Int32)
 21.2719 +                __ int_(box->toInt32());
 21.2720 +            else if (box->type()->pod() == PrimitiveType_Float)
 21.2721 +                __ float_(box->toFloat());
 21.2722 +            else
 21.2723 +                assert(false);
 21.2724 +
 21.2725 +            if (funType->parameterAt(i)->isReference()) {
 21.2726 +                __ note_position(node->pos());
 21.2727 +                __ slotref_lifo();
 21.2728 +            }
 21.2729 +        } else {
 21.2730 +            assert(box->type()->isArray());
 21.2731 +
 21.2732 +            array = Array::cast(box->toObject());
 21.2733 +            if (funType->parameterAt(i)->isConst()) {
 21.2734 +                __ object(array);
 21.2735 +            } else {
 21.2736 +                // We need to copy the array since it's mutable. Note that
 21.2737 +                // although COPYARRAY returns its left-hand side, this may
 21.2738 +                // change in the future, we do the same thing and dupe the
 21.2739 +                // newly allocated array.
 21.2740 +                map = ArrayMap::cast(array->map());
 21.2741 +                
 21.2742 +                // Natives cannot escape array references, so we can allocate
 21.2743 +                // them on the LIFO stack.
 21.2744 +                if (funType->isNative())
 21.2745 +                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
 21.2746 +                else
 21.2747 +                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
 21.2748 +                __ dup();
 21.2749 +                __ object(array);
 21.2750 +                __ copyarray();
 21.2751 +                __ pop();
 21.2752 +            }
 21.2753 +        }
 21.2754 +
 21.2755 +        argc++;
 21.2756 +    }
 21.2757 +
 21.2758 +    __ note_position(node->pos());
 21.2759 +    if (native) {
 21.2760 +        __ callnative(native->slot(), argc);
 21.2761 +        __ drop(argc);
 21.2762 +    } else {
 21.2763 +        node->callee()->accept(this);
 21.2764 +        __ call(funType);
 21.2765 +        __ drop(argc + 1);
 21.2766 +    }
 21.2767 +#endif
 21.2768 +}
 21.2769 +
 21.2770 +void
 21.2771 +BytecodeCompiler::visit(TernaryExpression *node)
 21.2772 +{
 21.2773 +    Label success, failure, join;
 21.2774 +
 21.2775 +    visitForTest(node->condition(), &success, &failure, &success);
 21.2776 +    __ bind(&success);
 21.2777 +    node->left()->accept(this);
 21.2778 +    __ drop(1);
 21.2779 +    __ jump(&join);
 21.2780 +    __ bind(&failure);
 21.2781 +    node->right()->accept(this);
 21.2782 +    __ bind(&join);
 21.2783 +}
 21.2784 +
 21.2785 +void
 21.2786 +BytecodeCompiler::visit(IfStatement *node)
 21.2787 +{
 21.2788 +    Label join;
 21.2789 +    if (!node->ifFalse()) {
 21.2790 +        Label success;
 21.2791 +
 21.2792 +        visitForTest(node->condition(), &success, &join, &success);
 21.2793 +        __ bind(&success);
 21.2794 +        node->ifTrue()->accept(this);
 21.2795 +    } else {
 21.2796 +        Label success, next;
 21.2797 +
 21.2798 +        visitForTest(node->condition(), &success, &next, &success);
 21.2799 +        __ bind(&success);
 21.2800 +        node->ifTrue()->accept(this);
 21.2801 +        __ jump(&join);
 21.2802 +        __ bind(&next);
 21.2803 +        node->ifFalse()->accept(this);
 21.2804 +    }
 21.2805 +
 21.2806 +    __ bind(&join);
 21.2807 +}
 21.2808 +
 21.2809 +bool
 21.2810 +BytecodeCompiler::tableswitch(SwitchStatement *node)
 21.2811 +{
 21.2812 +    CaseValueList *values = node->caseValueList();
 21.2813 +
 21.2814 +    if (values->length() < 3)
 21.2815 +        return false;
 21.2816 +
 21.2817 +    // Find the delta between the largest and smallest value.
 21.2818 +    int hi = values->at(values->length() - 1).box.toInt();
 21.2819 +    int lo = values->at(0).box.toInt();
 21.2820 +    assert(hi > lo);
 21.2821 +
 21.2822 +    unsigned tablesize = TableSwitchEntries(lo, hi);
 21.2823 +    if (tablesize > MAX_TABLESWITCH_ENTRIES)
 21.2824 +        return false;
 21.2825 +
 21.2826 +    Label def, join;
 21.2827 +
 21.2828 +    // Create the list of labels that each statement will bind to.
 21.2829 +    Label *labels = new Label[node->cases()->length()];
 21.2830 +
 21.2831 +    // Create the table of labels we'll use for each case.
 21.2832 +    Label **table = new Label *[tablesize];
 21.2833 +
 21.2834 +    // Link all cases, by default, to the default label.
 21.2835 +    for (size_t i = 0; i < tablesize; i++)
 21.2836 +        table[i] = &def;
 21.2837 +
 21.2838 +    // Now patch actual cases to their correct labels.
 21.2839 +    for (size_t i = 0; i < values->length(); i++) {
 21.2840 +        CaseValue &v = values->at(i);
 21.2841 +        assert(v.statement < node->cases()->length());
 21.2842 +
 21.2843 +        unsigned index = unsigned(v.box.toInt() - lo);
 21.2844 +        assert(index < tablesize);
 21.2845 +
 21.2846 +        table[index] = &labels[v.statement];
 21.2847 +    }
 21.2848 +
 21.2849 +    // Emit the tableswitch opcode and the jump table.
 21.2850 +    __ tableswitch(lo, hi, &def, table);
 21.2851 +
 21.2852 +    // We're done with the jump table now.
 21.2853 +    delete [] table;
 21.2854 +
 21.2855 +    // Emit each statement.
 21.2856 +    for (size_t i = 0; i < node->cases()->length(); i++) {
 21.2857 +        Statement *stmt = node->cases()->at(i)->statement();
 21.2858 +
 21.2859 +        __ bind(&labels[i]);
 21.2860 +        stmt->accept(this);
 21.2861 +        __ jump(&join);
 21.2862 +    }
 21.2863 +
 21.2864 +    // We're done with the statement labels.
 21.2865 +    delete [] labels;
 21.2866 +
 21.2867 +    // Emit the default case.
 21.2868 +    __ bind(&def);
 21.2869 +    if (node->defaultCase())
 21.2870 +        node->defaultCase()->accept(this);
 21.2871 +
 21.2872 +    __ bind(&join);
 21.2873 +
 21.2874 +    return true;
 21.2875 +}
 21.2876 +
 21.2877 +void
 21.2878 +BytecodeCompiler::visit(SwitchStatement *node)
 21.2879 +{
 21.2880 +    node->expression()->accept(this);
 21.2881 +
 21.2882 +    if (tableswitch(node))
 21.2883 +        return;
 21.2884 +
 21.2885 +    Label join;
 21.2886 +
 21.2887 +    for (size_t i = 0; i < node->cases()->length(); i++) {
 21.2888 +        Case *c = node->cases()->at(i);
 21.2889 +
 21.2890 +        Label success, fail;
 21.2891 +        if (c->others()) {
 21.2892 +            for (size_t j = 0; j < c->others()->length(); j++) {
 21.2893 +                Expression *expr = c->others()->at(j);
 21.2894 +
 21.2895 +                __ dup();
 21.2896 +                expr->accept(this);
 21.2897 +                __ j(OP_JEQ, &success);
 21.2898 +            }
 21.2899 +        }
 21.2900 +
 21.2901 +        // The final test.
 21.2902 +        __ dup();
 21.2903 +        c->expression()->accept(this);
 21.2904 +        __ j(OP_JNE, &fail);
 21.2905 +        __ bind(&success);
 21.2906 +        c->statement()->accept(this);
 21.2907 +        __ jump(&join);
 21.2908 +        __ bind(&fail);
 21.2909 +    }
 21.2910 +
 21.2911 +    if (node->defaultCase())
 21.2912 +        node->defaultCase()->accept(this);
 21.2913 +
 21.2914 +    __ pop();
 21.2915 +    __ bind(&join);
 21.2916 +}
 21.2917 +
 21.2918 +void
 21.2919 +BytecodeCompiler::visit(FunctionStatement *node)
 21.2920 +{
 21.2921 +    if (!node->fun()->used())
 21.2922 +        return;
 21.2923 +
 21.2924 +    if (node->fun()->isNative()) {
 21.2925 +        assert(!moduleData_->natives->at(node->fun()->slot()));
 21.2926 +
 21.2927 +        Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
 21.2928 +        Local<String> name(zone_, node->fun()->name());
 21.2929 +        Local<Native> native(zone_, Native::New(zone_, type, name));
 21.2930 +        if (!native)
 21.2931 +            return;
 21.2932 +
 21.2933 +        moduleData_->natives->set(zone_, node->fun()->slot(), native);
 21.2934 +        return;
 21.2935 +    }
 21.2936 +
 21.2937 +    // If the function has no body, then it's just a declaration.
 21.2938 +    if (!node->body()) {
 21.2939 +        assert(node->fun()->isForward() || node->fun()->isPublic());
 21.2940 +        return;
 21.2941 +    }
 21.2942 +
 21.2943 +    BytecodeCompiler child(zone_, tree_, moduleData_);
 21.2944 +    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
 21.2945 +    if (!fun)
 21.2946 +        return;
 21.2947 +    
 21.2948 +    assert(!moduleData_->module->getFunction(node->fun()->slot()));
 21.2949 +    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
 21.2950 +}
 21.2951 +
 21.2952 +void
 21.2953 +BytecodeCompiler::visit(FunctionTypeStatement *node)
 21.2954 +{
 21.2955 +}
 21.2956 +
 21.2957 +void
 21.2958 +BytecodeCompiler::visit(EnumStatement *node)
 21.2959 +{
 21.2960 +}
 21.2961 +
 21.2962 +void
 21.2963 +BytecodeCompiler::visit(StructureStatement *node)
 21.2964 +{
 21.2965 +}
 21.2966 +
 21.2967 +void
 21.2968 +BytecodeCompiler::visit(ArrayLiteral *node)
 21.2969 +{
 21.2970 +    // We shouldn't reach these; they're handled manually when initializing
 21.2971 +    // declared arrays.
 21.2972 +    assert(false);
 21.2973 +}
 21.2974 +
 21.2975 +void
 21.2976 +BytecodeCompiler::visit(ImportStatement *node)
 21.2977 +{
 21.2978 +}
 21.2979 +
 21.2980 +Code *
 21.2981 +BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
 21.2982 +{
 21.2983 +    // STOP doubles as RETURNVOID.
 21.2984 +    __ stop();
 21.2985 +
 21.2986 +    if (__ oom() || zone_->hasPendingException())
 21.2987 +        return NULL;
 21.2988 +
 21.2989 +    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
 21.2990 +    if (!bytes)
 21.2991 +        return NULL;
 21.2992 +    memcpy(bytes->raw(), __ buffer(), __ length());
 21.2993 +
 21.2994 +    for (size_t i = 0; i < scope->maxContainedLocals(); i++)
 21.2995 +        assert(locals_->at(i));
 21.2996 +
 21.2997 +    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
 21.2998 +    if (!objects)
 21.2999 +        return NULL;
 21.3000 +
 21.3001 +    for (size_t i = 0; i < __ objects()->length(); i++)
 21.3002 +        objects->set(zone_, i, *(__ objects()->at(i)));
 21.3003 +
 21.3004 +    Local<ByteArray> safepoints(zone_);
 21.3005 +
 21.3006 +    // If any stack slots hold gc pointers at potential failure points in the
 21.3007 +    // bytecode, record them now. We do this by building a list of tuples;
 21.3008 +    // each tuple contains the pc offset, and a bitset containing which stack
 21.3009 +    // slots must be scanned by the gc.
 21.3010 +    if (__ oopRecords()->length()) {
 21.3011 +        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
 21.3012 +        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
 21.3013 +        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
 21.3014 +        if (!safepoints)
 21.3015 +            return NULL;
 21.3016 +
 21.3017 +        Address cursor = safepoints->raw();
 21.3018 +        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
 21.3019 +            OopRecord *record = __ oopRecords()->at(i);
 21.3020 +            assert(record->depth <= __ maxStackDepth());
 21.3021 +
 21.3022 +            *reinterpret_cast<unsigned *>(cursor) = record->offset;
 21.3023 +
 21.3024 +            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
 21.3025 +            for (unsigned i = 0; i < record->depth; i++)
 21.3026 +                bits[i / 8] |= (1 << (i % 8));
 21.3027 +
 21.3028 +            cursor += bytesPerSafepoint;
 21.3029 +        }
 21.3030 +
 21.3031 +        assert(cursor == safepoints->raw() + gcmapSize);
 21.3032 +    }
 21.3033 +
 21.3034 +    Local<ByteArray> sourcemap(zone_);
 21.3035 +    if (__ sourcemapLength()) {
 21.3036 +        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
 21.3037 +        if (!sourcemap)
 21.3038 +            return NULL;
 21.3039 +
 21.3040 +        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
 21.3041 +    }
 21.3042 +
 21.3043 +    Local<Code> code(zone_);
 21.3044 +
 21.3045 +    code = Code::New(zone_,
 21.3046 +                     bytes,
 21.3047 +                     locals_,
 21.3048 +                     objects,
 21.3049 +                     __ maxStackDepth(),
 21.3050 +                     moduleData_->module,
 21.3051 +                     safepoints,
 21.3052 +                     sourcemap,
 21.3053 +                     lineno);
 21.3054 +    return code;
 21.3055 +}
 21.3056 +
 21.3057 +Function *
 21.3058 +BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
 21.3059 +{
 21.3060 +    // Note: No need to record a life slot here, since it's part of the Frame.
 21.3061 +    AutoEnterScope functionScope(this, node->scope());
 21.3062 +
 21.3063 +    // Set the initial line, because line mappings are deltas.
 21.3064 +    __ setFirstLine(node->pos().line);
 21.3065 +    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
 21.3066 +
 21.3067 +    node->body()->accept(this);
 21.3068 +
 21.3069 +    unsigned nargs = node->scope()->numArguments();
 21.3070 +    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
 21.3071 +    if (!args)
 21.3072 +        return NULL;
 21.3073 +
 21.3074 +    for (size_t i = 0; i < node->scope()->numArguments(); i++)
 21.3075 +        args->set(zone_, i, node->scope()->getArgument(i)->type());
 21.3076 +
 21.3077 +
 21.3078 +    Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
 21.3079 +    if (!code)
 21.3080 +        return NULL;
 21.3081 +
 21.3082 +    Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
 21.3083 +    Local<String> name(zone_, node->fun()->name());
 21.3084 +    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
 21.3085 +    if (!fun)
 21.3086 +        return NULL;
 21.3087 +
 21.3088 +    // If this function had a forward, export it as a named public.
 21.3089 +    if (node->fun()->isPublic()) {
 21.3090 +        assert(node->fun()->isPublic());
 21.3091 +        ScopedRoot<Function> root(fun);
 21.3092 +        if (!root)
 21.3093 +            return NULL;
 21.3094 +        if (!moduleData_->publics.append(root))
 21.3095 +            return NULL;
 21.3096 +    }
 21.3097 +
 21.3098 +#ifndef NDEBUG
 21.3099 +    Disassemble(code, stdout);
 21.3100 +#endif
 21.3101 +    
 21.3102 +    return fun;
 21.3103 +}
 21.3104 +
 21.3105 +Module *
 21.3106 +BytecodeCompiler::compile()
 21.3107 +{
 21.3108 +    AutoEnterScope scope(this, tree_->globalScope());
 21.3109 +
 21.3110 +    ModuleData moduleData;
 21.3111 +
 21.3112 +    moduleData_ = &moduleData;
 21.3113 +    moduleData_->module = Module::New(zone_, tree_->globalScope()->numFunctions());
 21.3114 +
 21.3115 +    if (!moduleData_)
 21.3116 +        return NULL;
 21.3117 +    
 21.3118 +    moduleData_->natives = FixedArray::New(zone_, tree_->globalScope()->numNatives(), Heap::Tenure_Old);
 21.3119 +    if (!moduleData_->natives)
 21.3120 +        return NULL;
 21.3121 +
 21.3122 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
 21.3123 +        Statement *statement = tree_->statements()->at(i);
 21.3124 +        statement->accept(this);
 21.3125 +    }
 21.3126 +
 21.3127 +    if (zone_->hasPendingException())
 21.3128 +        return NULL;
 21.3129 +
 21.3130 +#ifndef NDEBUG
 21.3131 +    for (size_t i = 0; i < tree_->globalScope()->numFunctions(); i++)
 21.3132 +        assert(moduleData_->module->getFunction(i));
 21.3133 +    for (size_t i = 0; i < tree_->globalScope()->numNatives(); i++)
 21.3134 +        assert(moduleData_->natives->at(i));
 21.3135 +#endif
 21.3136 +
 21.3137 +    if (moduleData_->publics.length()) {
 21.3138 +        Local<Function> fun(zone_);
 21.3139 +        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
 21.3140 +                               Heap::Tenure_Old));
 21.3141 +        if (!list)
 21.3142 +            return NULL;
 21.3143 +
 21.3144 +        for (size_t i = 0; i < moduleData_->publics.length(); i++)
 21.3145 +            list->set(zone_, i, moduleData_->publics[i]);
 21.3146 +
 21.3147 +        moduleData_->module->setPublics(list);
 21.3148 +    }
 21.3149 +
 21.3150 +    moduleData_->module->setNatives(moduleData_->natives);
 21.3151 +
 21.3152 +    if (scope_->numEnvironmentVars()) {
 21.3153 +        Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
 21.3154 +        if (!globalMap)
 21.3155 +            return NULL;
 21.3156 +
 21.3157 +        Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
 21.3158 +        if (!environment)
 21.3159 +            return NULL;
 21.3160 +
 21.3161 +        moduleData_->module->setEnvironment(environment);
 21.3162 +    }
 21.3163 +
 21.3164 +    Local<Code> code(zone_, compileCode(tree_->globalScope(), 1));
 21.3165 +    if (!code)
 21.3166 +        return NULL;
 21.3167 +
 21.3168 +    Disassemble(code, stdout);
 21.3169 +
 21.3170 +    moduleData_->module->setCode(code);
 21.3171 +
 21.3172 +    return moduleData_->module;
 21.3173 +}
    22.1 --- a/src/OldByCo.h	Mon Jun 10 00:46:29 2013 +0100
    22.2 +++ b/src/OldByCo.h	Mon Jun 10 01:04:43 2013 +0100
    22.3 @@ -1,160 +1,160 @@
    22.4 -/* vim: set ts=4 sw=4 tw=99 et:
    22.5 - *
    22.6 - * Copyright (C) 2012 David Anderson
    22.7 - *
    22.8 - * This file is part of JITCraft.
    22.9 - *
   22.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   22.11 - * the terms of the GNU General Public License as published by the Free
   22.12 - * Software Foundation, either version 3 of the License, or (at your option)
   22.13 - * any later version.
   22.14 - * 
   22.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   22.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   22.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   22.18 - *
   22.19 - * You should have received a copy of the GNU General Public License along with
   22.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   22.21 - */
   22.22 -#ifndef _include_bytecode_compiler_h_
   22.23 -#define _include_bytecode_compiler_h_
   22.24 -
   22.25 -#include "../Functions.h"
   22.26 -#include "AST.h"
   22.27 -#include "BytecodeEmitter.h"
   22.28 -
   22.29 -namespace ke {
   22.30 -
   22.31 -class Module;
   22.32 -class Array;
   22.33 -class ArrayMap;
   22.34 -
   22.35 -struct ModuleData
   22.36 -{
   22.37 -    ScopedRoot<Module> module;
   22.38 -    PoolList<ScopedRoot<Function> > publics;
   22.39 -    ScopedRoot<FixedArray> natives;
   22.40 -};
   22.41 -
   22.42 -class BytecodeCompiler : public AstVisitor
   22.43 -{
   22.44 -    Zone *zone_;
   22.45 -    ParseTree *tree_;
   22.46 -    BytecodeEmitter emitter_;
   22.47 -    ScopedRoot<FixedArray> locals_;
   22.48 -    Scope *scope_;
   22.49 -    ModuleData *moduleData_;
   22.50 -
   22.51 -    class LoopScope
   22.52 -    {
   22.53 -        Scope *scope_;
   22.54 -        BytecodeEmitter::Label *bk_;
   22.55 -        BytecodeEmitter::Label *ct_;
   22.56 -        LoopScope **prevp_;
   22.57 -        LoopScope *prev_;
   22.58 -
   22.59 -      public:
   22.60 -        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
   22.61 -                  LoopScope **prevp)
   22.62 -          : scope_(scope),
   22.63 -            bk_(bk),
   22.64 -            ct_(ct),
   22.65 -            prevp_(prevp),
   22.66 -            prev_(*prevp)
   22.67 -        {
   22.68 -            *prevp_ = this;
   22.69 -        }
   22.70 -
   22.71 -        ~LoopScope()
   22.72 -        {
   22.73 -            *prevp_ = prev_;
   22.74 -        }
   22.75 -
   22.76 -        BytecodeEmitter::Label *break_() {
   22.77 -            return bk_;
   22.78 -        }
   22.79 -        BytecodeEmitter::Label *continue_() {
   22.80 -            return ct_;
   22.81 -        }
   22.82 -        Scope *scope() {
   22.83 -            return scope_;
   22.84 -        }
   22.85 -    };
   22.86 -
   22.87 -    LoopScope *loop_;
   22.88 -
   22.89 -  public:
   22.90 -    class AutoEnterScope
   22.91 -    {
   22.92 -        BytecodeCompiler *bc_;
   22.93 -        Scope *saved_;
   22.94 -
   22.95 -      public:
   22.96 -        AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
   22.97 -          : bc_(bc),
   22.98 -            saved_(bc->scope_)
   22.99 -        {
  22.100 -            if (scope)
  22.101 -                bc->scope_ = scope;
  22.102 -        }
  22.103 -        ~AutoEnterScope() {
  22.104 -            bc_->scope_ = saved_;
  22.105 -        }
  22.106 -    };
  22.107 -
  22.108 -  private:
  22.109 -    void recordLifoSlot(Scope *scope);
  22.110 -    void unwindTo(Scope *scope);
  22.111 -    void visitForTest(Expression *expression,
  22.112 -                      BytecodeEmitter::Label *trueBranch,
  22.113 -                      BytecodeEmitter::Label *falseBranch,
  22.114 -                      BytecodeEmitter::Label *fallthrough);
  22.115 -    Code *compileCode(Scope *scope, unsigned lineno);
  22.116 -    Function *compileFunction(ModuleData *module, FunctionStatement *fun);
  22.117 -    void visitForALU(Type *needed, Expression *node);
  22.118 -
  22.119 -    void getEnvSlot(Variable *var);
  22.120 -    void setEnvSlot(Variable *var);
  22.121 -
  22.122 -    bool tableswitch(SwitchStatement *node);
  22.123 -
  22.124 -  public:
  22.125 -    BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
  22.126 -
  22.127 -    Module *compile();
  22.128 -
  22.129 -  public:
  22.130 -    void visit(NameProxy *name);
  22.131 -    void visit(Assignment *node);
  22.132 -    void visit(BinaryExpression *node);
  22.133 -    void visit(ReturnStatement *node);
  22.134 -    void visit(ForStatement *node);
  22.135 -    void visit(BlockStatement *node);
  22.136 -    void visit(VariableDeclaration *node);
  22.137 -    void visit(IntegerLiteral *node);
  22.138 -    void visit(BooleanLiteral *node);
  22.139 -    void visit(FloatLiteral *node);
  22.140 -    void visit(StringLiteral *node);
  22.141 -    void visit(ExpressionStatement *node);
  22.142 -    void visit(FunctionStatement *node);
  22.143 -    void visit(CallExpression *node);
  22.144 -    void visit(IfStatement *node);
  22.145 -    void visit(IndexExpression *node);
  22.146 -    void visit(EnumStatement *node);
  22.147 -    void visit(WhileStatement *node);
  22.148 -    void visit(BreakStatement *node);
  22.149 -    void visit(ContinueStatement *node);
  22.150 -    void visit(IncDecExpression *node);
  22.151 -    void visit(UnaryExpression *node);
  22.152 -    void visit(TernaryExpression *node);
  22.153 -    void visit(StructureStatement *node);
  22.154 -    void visit(FieldExpression *node);
  22.155 -    void visit(SwitchStatement *node);
  22.156 -    void visit(FunctionTypeStatement *node);
  22.157 -    void visit(ArrayLiteral *node);
  22.158 -    void visit(ImportStatement *node);
  22.159 -};
  22.160 -
  22.161 -}
  22.162 -
  22.163 -#endif // _include_bytecode_generator_h_
  22.164 +/* vim: set ts=4 sw=4 tw=99 et:
  22.165 + *
  22.166 + * Copyright (C) 2012 David Anderson
  22.167 + *
  22.168 + * This file is part of JITCraft.
  22.169 + *
  22.170 + * JITCraft is free software: you can redistribute it and/or modify it under
  22.171 + * the terms of the GNU General Public License as published by the Free
  22.172 + * Software Foundation, either version 3 of the License, or (at your option)
  22.173 + * any later version.
  22.174 + * 
  22.175 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  22.176 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  22.177 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  22.178 + *
  22.179 + * You should have received a copy of the GNU General Public License along with
  22.180 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  22.181 + */
  22.182 +#ifndef _include_bytecode_compiler_h_
  22.183 +#define _include_bytecode_compiler_h_
  22.184 +
  22.185 +#include "../Functions.h"
  22.186 +#include "AST.h"
  22.187 +#include "BytecodeEmitter.h"
  22.188 +
  22.189 +namespace ke {
  22.190 +
  22.191 +class Module;
  22.192 +class Array;
  22.193 +class ArrayMap;
  22.194 +
  22.195 +struct ModuleData
  22.196 +{
  22.197 +    ScopedRoot<Module> module;
  22.198 +    PoolList<ScopedRoot<Function> > publics;
  22.199 +    ScopedRoot<FixedArray> natives;
  22.200 +};
  22.201 +
  22.202 +class BytecodeCompiler : public AstVisitor
  22.203 +{
  22.204 +    Zone *zone_;
  22.205 +    ParseTree *tree_;
  22.206 +    BytecodeEmitter emitter_;
  22.207 +    ScopedRoot<FixedArray> locals_;
  22.208 +    Scope *scope_;
  22.209 +    ModuleData *moduleData_;
  22.210 +
  22.211 +    class LoopScope
  22.212 +    {
  22.213 +        Scope *scope_;
  22.214 +        BytecodeEmitter::Label *bk_;
  22.215 +        BytecodeEmitter::Label *ct_;
  22.216 +        LoopScope **prevp_;
  22.217 +        LoopScope *prev_;
  22.218 +
  22.219 +      public:
  22.220 +        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
  22.221 +                  LoopScope **prevp)
  22.222 +          : scope_(scope),
  22.223 +            bk_(bk),
  22.224 +            ct_(ct),
  22.225 +            prevp_(prevp),
  22.226 +            prev_(*prevp)
  22.227 +        {
  22.228 +            *prevp_ = this;
  22.229 +        }
  22.230 +
  22.231 +        ~LoopScope()
  22.232 +        {
  22.233 +            *prevp_ = prev_;
  22.234 +        }
  22.235 +
  22.236 +        BytecodeEmitter::Label *break_() {
  22.237 +            return bk_;
  22.238 +        }
  22.239 +        BytecodeEmitter::Label *continue_() {
  22.240 +            return ct_;
  22.241 +        }
  22.242 +        Scope *scope() {
  22.243 +            return scope_;
  22.244 +        }
  22.245 +    };
  22.246 +
  22.247 +    LoopScope *loop_;
  22.248 +
  22.249 +  public:
  22.250 +    class AutoEnterScope
  22.251 +    {
  22.252 +        BytecodeCompiler *bc_;
  22.253 +        Scope *saved_;
  22.254 +
  22.255 +      public:
  22.256 +        AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
  22.257 +          : bc_(bc),
  22.258 +            saved_(bc->scope_)
  22.259 +        {
  22.260 +            if (scope)
  22.261 +                bc->scope_ = scope;
  22.262 +        }
  22.263 +        ~AutoEnterScope() {
  22.264 +            bc_->scope_ = saved_;
  22.265 +        }
  22.266 +    };
  22.267 +
  22.268 +  private:
  22.269 +    void recordLifoSlot(Scope *scope);
  22.270 +    void unwindTo(Scope *scope);
  22.271 +    void visitForTest(Expression *expression,
  22.272 +                      BytecodeEmitter::Label *trueBranch,
  22.273 +                      BytecodeEmitter::Label *falseBranch,
  22.274 +                      BytecodeEmitter::Label *fallthrough);
  22.275 +    Code *compileCode(Scope *scope, unsigned lineno);
  22.276 +    Function *compileFunction(ModuleData *module, FunctionStatement *fun);
  22.277 +    void visitForALU(Type *needed, Expression *node);
  22.278 +
  22.279 +    void getEnvSlot(Variable *var);
  22.280 +    void setEnvSlot(Variable *var);
  22.281 +
  22.282 +    bool tableswitch(SwitchStatement *node);
  22.283 +
  22.284 +  public:
  22.285 +    BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
  22.286 +
  22.287 +    Module *compile();
  22.288 +
  22.289 +  public:
  22.290 +    void visit(NameProxy *name);
  22.291 +    void visit(Assignment *node);
  22.292 +    void visit(BinaryExpression *node);
  22.293 +    void visit(ReturnStatement *node);
  22.294 +    void visit(ForStatement *node);
  22.295 +    void visit(BlockStatement *node);
  22.296 +    void visit(VariableDeclaration *node);
  22.297 +    void visit(IntegerLiteral *node);
  22.298 +    void visit(BooleanLiteral *node);
  22.299 +    void visit(FloatLiteral *node);
  22.300 +    void visit(StringLiteral *node);
  22.301 +    void visit(ExpressionStatement *node);
  22.302 +    void visit(FunctionStatement *node);
  22.303 +    void visit(CallExpression *node);
  22.304 +    void visit(IfStatement *node);
  22.305 +    void visit(IndexExpression *node);
  22.306 +    void visit(EnumStatement *node);
  22.307 +    void visit(WhileStatement *node);
  22.308 +    void visit(BreakStatement *node);
  22.309 +    void visit(ContinueStatement *node);
  22.310 +    void visit(IncDecExpression *node);
  22.311 +    void visit(UnaryExpression *node);
  22.312 +    void visit(TernaryExpression *node);
  22.313 +    void visit(StructureStatement *node);
  22.314 +    void visit(FieldExpression *node);
  22.315 +    void visit(SwitchStatement *node);
  22.316 +    void visit(FunctionTypeStatement *node);
  22.317 +    void visit(ArrayLiteral *node);
  22.318 +    void visit(ImportStatement *node);
  22.319 +};
  22.320 +
  22.321 +}
  22.322 +
  22.323 +#endif // _include_bytecode_generator_h_
    23.1 --- a/src/OldSema.cpp	Mon Jun 10 00:46:29 2013 +0100
    23.2 +++ b/src/OldSema.cpp	Mon Jun 10 01:04:43 2013 +0100
    23.3 @@ -1,1899 +1,1899 @@
    23.4 -/* vim: set ts=4 sw=4 tw=99 et:
    23.5 - *
    23.6 - * Copyright (C) 2012 David Anderson
    23.7 - *
    23.8 - * This file is part of JITCraft.
    23.9 - *
   23.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   23.11 - * the terms of the GNU General Public License as published by the Free
   23.12 - * Software Foundation, either version 3 of the License, or (at your option)
   23.13 - * any later version.
   23.14 - * 
   23.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   23.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   23.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   23.18 - *
   23.19 - * You should have received a copy of the GNU General Public License along with
   23.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   23.21 - */
   23.22 -#include <string.h>
   23.23 -#include "SemanticAnalysis.h"
   23.24 -#include "../Types.h"
   23.25 -#include "../Zone.h"
   23.26 -#include "../TypeManager.h"
   23.27 -#include "../Strings.h"
   23.28 -#include "../Box.h"
   23.29 -#include "../Array.h"
   23.30 -#include "../Heap-inl.h"
   23.31 -#include "Scopes.h"
   23.32 -#include "NameBinding.h"
   23.33 -
   23.34 -using namespace ke;
   23.35 -
   23.36 -SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
   23.37 -  : zone_(zone),
   23.38 -    cc_(cc),
   23.39 -    tree_(tree),
   23.40 -    scope_(NULL),
   23.41 -    loop_(NULL)
   23.42 -{
   23.43 -}
   23.44 -
   23.45 -bool
   23.46 -SemanticAnalysis::analyze()
   23.47 -{
   23.48 -    assert(false);
   23.49 -    return false;
   23.50 -}
   23.51 -
   23.52 -
   23.53 -#if 0
   23.54 -
   23.55 -static inline bool
   23.56 -IsPrimitiveType(Type *type, PrimitiveType primitive)
   23.57 -{
   23.58 -    if (!type)
   23.59 -        return false;
   23.60 -
   23.61 -    if (!type->isPrimitive())
   23.62 -        return false;
   23.63 -
   23.64 -    return primitive == type->primitive();
   23.65 -}
   23.66 -
   23.67 -static inline bool
   23.68 -EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
   23.69 -                        BoxedPrimitive *out)
   23.70 -{
   23.71 -    switch (kind) {
   23.72 -      case TOK_PLUS:
   23.73 -        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
   23.74 -        return true;
   23.75 -
   23.76 -      case TOK_SHL:
   23.77 -        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
   23.78 -        return true;
   23.79 -
   23.80 -      default:
   23.81 -        return false;
   23.82 -    }
   23.83 -}
   23.84 -
   23.85 -static inline bool
   23.86 -EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
   23.87 -{
   23.88 -  switch (kind) {
   23.89 -    case TOK_MINUS:
   23.90 -      *out = BoxedPrimitive::Int(-inner.toInt());
   23.91 -      return true;
   23.92 -
   23.93 -    default:
   23.94 -      return false;
   23.95 -  }
   23.96 -}
   23.97 -
   23.98 -static bool
   23.99 -EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
  23.100 -{
  23.101 -    switch (expression->kind()) {
  23.102 -      case AstNode::kBinaryExpression:
  23.103 -      {
  23.104 -        BoxedPrimitive left;
  23.105 -        BoxedPrimitive right;
  23.106 -        BinaryExpression *b = expression->toBinaryExpression();
  23.107 -        if (!EvaluateForConstant(b->left(), &left) ||
  23.108 -            !EvaluateForConstant(b->right(), &right))
  23.109 -        {
  23.110 -            return false;
  23.111 -        }
  23.112 -        return EvaluateBinaryOperation(b->token(), left, right, out);
  23.113 -      }
  23.114 -
  23.115 -      case AstNode::kUnaryExpression:
  23.116 -      {
  23.117 -        BoxedPrimitive inner;
  23.118 -        UnaryExpression *u = expression->toUnaryExpression();
  23.119 -        if (!EvaluateForConstant(u->expression(), &inner))
  23.120 -            return false;
  23.121 -        return EvaluateUnaryOperation(u->token(), inner, out);
  23.122 -      }
  23.123 -
  23.124 -      case AstNode::kNameProxy:
  23.125 -      {
  23.126 -        NameProxy *proxy = expression->toNameProxy();
  23.127 -        if (proxy->binding()->kind() != BoundName::CONSTANT)
  23.128 -            return false;
  23.129 -
  23.130 -        NamedConstant *c = proxy->binding()->toNamedConstant();
  23.131 -        if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
  23.132 -            return false;
  23.133 -
  23.134 -        *out = c->value();
  23.135 -        return true;
  23.136 -      }
  23.137 -
  23.138 -      case AstNode::kBooleanLiteral:
  23.139 -        *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
  23.140 -        return true;
  23.141 -
  23.142 -      case AstNode::kIntegerLiteral:
  23.143 -        *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
  23.144 -        return true;
  23.145 -
  23.146 -      default:
  23.147 -        return false;
  23.148 -    }
  23.149 -}
  23.150 -
  23.151 -SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
  23.152 -  : zone_(zone),
  23.153 -    cc_(cc),
  23.154 -    tree_(tree),
  23.155 -    scope_(NULL),
  23.156 -    loop_(NULL)
  23.157 -{
  23.158 -}
  23.159 -
  23.160 -bool
  23.161 -SemanticAnalysis::analyze()
  23.162 -{
  23.163 -    if (cc_.failures())
  23.164 -        return false;
  23.165 -
  23.166 -    scope_ = tree_->globalScope();
  23.167 -    assert(scope_->kind() == Scope::GLOBAL);
  23.168 -
  23.169 -    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  23.170 -        Statement *statement = tree_->statements()->at(i);
  23.171 -        if (statement->isFunctionStatement()) {
  23.172 -            FunctionStatement *funstmt = statement->toFunctionStatement();
  23.173 -            if (!preanalyze(funstmt))
  23.174 -                return false;
  23.175 -        } else if (statement->isEnumStatement()) {
  23.176 -            EnumStatement *enumstmt = statement->toEnumStatement();
  23.177 -
  23.178 -            // We pre-fill global enum types, since they may occur in function
  23.179 -            // signatures. This should probably be somewhere else...
  23.180 -            enumstmt->accept(this);
  23.181 -        } else if (statement->isStructureStatement()) {
  23.182 -            StructureStatement *node = statement->toStructureStatement();
  23.183 -            node->accept(this);
  23.184 -            if (!node->decl()->type())
  23.185 -                return false;
  23.186 -        } else if (statement->isFunctionTypeStatement()) {
  23.187 -            FunctionTypeStatement *node = statement->toFunctionTypeStatement();
  23.188 -            node->accept(this);
  23.189 -            if (!node->decl()->type())
  23.190 -                return false;
  23.191 -        }
  23.192 -    }
  23.193 -
  23.194 -    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  23.195 -        Statement *statement = tree_->statements()->at(i);
  23.196 -
  23.197 -        // We can't double-process these. Maybe put this check somewhere else.
  23.198 -        if (statement->isEnumStatement())
  23.199 -            continue;
  23.200 -
  23.201 -        statement->accept(this);
  23.202 -    }
  23.203 -
  23.204 -    if (!determineLiveFunctions())
  23.205 -        return false;
  23.206 -
  23.207 -    return !cc_.failures();
  23.208 -}
  23.209 -
  23.210 -bool
  23.211 -SemanticAnalysis::determineLiveFunctions()
  23.212 -{
  23.213 -    Vector<NamedFunction *> worklist;
  23.214 -
  23.215 -    // Add the root set.
  23.216 -    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  23.217 -        Statement *statement = tree_->statements()->at(i);
  23.218 -        if (!statement->isFunctionStatement())
  23.219 -            continue;
  23.220 -
  23.221 -        FunctionStatement *stmt = statement->toFunctionStatement();
  23.222 -        NamedFunction  *fun = stmt->fun();
  23.223 -        if (!fun->used())
  23.224 -            continue;
  23.225 -
  23.226 -        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
  23.227 -            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
  23.228 -
  23.229 -            // Names in these lists are always unused, however, we mark them
  23.230 -            // as used while inserting into the work queue, to avoid double-
  23.231 -            // insertion.
  23.232 -            if (name->used())
  23.233 -                continue;
  23.234 -
  23.235 -            if (!worklist.append(name))
  23.236 -                return false;
  23.237 -
  23.238 -            name->setUsed();
  23.239 -        }
  23.240 -    }
  23.241 -
  23.242 -    while (!worklist.empty()) {
  23.243 -        NamedFunction *fun = worklist.popCopy();
  23.244 -
  23.245 -        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
  23.246 -            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
  23.247 -            if (name->used())
  23.248 -                continue;
  23.249 -            if (!worklist.append(name))
  23.250 -                return false;
  23.251 -            name->setUsed();
  23.252 -        }
  23.253 -    }
  23.254 -
  23.255 -    return true;
  23.256 -}
  23.257 -
  23.258 -Type *
  23.259 -SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
  23.260 -{
  23.261 -    if (!name)
  23.262 -        return zone_->types()->getPrimitive(PrimitiveType_Int32);
  23.263 -
  23.264 -    if (name->kind() == BoundName::UNBOUND) {
  23.265 -        cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
  23.266 -        return NULL;
  23.267 -    }
  23.268 -
  23.269 -    if (name->kind() != BoundName::TYPE) {
  23.270 -        cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
  23.271 -        return NULL;
  23.272 -    }
  23.273 -
  23.274 -    if (!name->type())
  23.275 -        return NULL;
  23.276 -
  23.277 -    return name->type();
  23.278 -}
  23.279 -
  23.280 -Type *
  23.281 -SemanticAnalysis::visitAndApplyType(Expression *expression)
  23.282 -{
  23.283 -    expression->accept(this);
  23.284 -    return expression->type();
  23.285 -}
  23.286 -
  23.287 -Type *
  23.288 -SemanticAnalysis::visitForLoad(Expression *expression)
  23.289 -{
  23.290 -    Local<Type> type(zone_, visitAndApplyType(expression));
  23.291 -    if (!type)
  23.292 -        return NULL;
  23.293 -
  23.294 -    if (type->isReference()) {
  23.295 -        expression->setType(type->contained());
  23.296 -    } else if (expression->isCallExpression()) {
  23.297 -        if (type->isVoid()) {
  23.298 -            CallExpression *call = expression->toCallExpression();
  23.299 -            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
  23.300 -            return NULL;
  23.301 -        }
  23.302 -    }
  23.303 -
  23.304 -    return expression->type();
  23.305 -}
  23.306 -
  23.307 -void
  23.308 -SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
  23.309 -{
  23.310 -    const char *op = TokenNames[token];
  23.311 -    const char *name = GetTypeName(type);
  23.312 -
  23.313 -    cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
  23.314 -}
  23.315 -
  23.316 -void
  23.317 -SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  23.318 -{
  23.319 -    const char *op = TokenNames[token];
  23.320 -    const char *leftName = GetTypeName(left);
  23.321 -    const char *rightName = GetTypeName(right);
  23.322 -
  23.323 -    cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
  23.324 -}
  23.325 -
  23.326 -Type *
  23.327 -SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  23.328 -{
  23.329 -    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
  23.330 -        (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
  23.331 -    {
  23.332 -        // If either side is a float, the other side must be a float or int.
  23.333 -        if (left->isFloat() || right->isFloat()) {
  23.334 -            Type *floatType = left->isFloat() ? left : right;
  23.335 -            Type *other = left->isFloat() ? right : left;
  23.336 -            if (other->isFloat() || other->isInt32())
  23.337 -                return floatType;
  23.338 -        }
  23.339 -    }
  23.340 -
  23.341 -    if (token == TOK_OR || token == TOK_AND) {
  23.342 -        if (!canTest(node, left) || !canTest(node, right))
  23.343 -            return NULL;
  23.344 -        return zone_->types()->getPrimitive(PrimitiveType_Bool);
  23.345 -    }
  23.346 -
  23.347 -    if (token >= TOK_EQUALS && token <= TOK_GE) {
  23.348 -        if ((left->isFloat() || left->isInt32()) &&
  23.349 -            (right->isFloat() || right->isInt32()))
  23.350 -        {
  23.351 -            return zone_->types()->getPrimitive(PrimitiveType_Bool);
  23.352 -        }
  23.353 -        binaryTypeError(node, token, left, right);
  23.354 -        return NULL;
  23.355 -    }
  23.356 -
  23.357 -    if (!left->isInt32() || !right->isInt32()) {
  23.358 -        binaryTypeError(node, token, left, right);
  23.359 -        return NULL;
  23.360 -    }
  23.361 -
  23.362 -    return left;
  23.363 -}
  23.364 -
  23.365 -bool
  23.366 -SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
  23.367 -{
  23.368 -    if (!type->isPrimitive() && !type->isEnum()) {
  23.369 -        cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
  23.370 -        return false;
  23.371 -    }
  23.372 -    return true;
  23.373 -}
  23.374 -
  23.375 -Type *
  23.376 -SemanticAnalysis::visitForLValue(Expression *expression)
  23.377 -{
  23.378 -    if (expression->isIndexExpression()) {
  23.379 -        Type *type = visitAndApplyType(expression);
  23.380 -        if (!type)
  23.381 -            return NULL;
  23.382 -
  23.383 -        // if (type->isConst()) {
  23.384 -        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  23.385 -        //     return NULL;
  23.386 -        // }
  23.387 -
  23.388 -        return type;
  23.389 -    }
  23.390 -
  23.391 -    if (expression->isFieldExpression()) {
  23.392 -        Type *type = visitAndApplyType(expression);
  23.393 -        if (!type)
  23.394 -            return NULL;
  23.395 -
  23.396 -        // if (expression->toFieldExpression()->left()->type()->isConst()) {
  23.397 -        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  23.398 -        //     return NULL;
  23.399 -        // }
  23.400 -
  23.401 -        return type;
  23.402 -    }
  23.403 -
  23.404 -    if (!expression->isNameProxy()) {
  23.405 -        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  23.406 -        return NULL;
  23.407 -    }
  23.408 -
  23.409 -    NameProxy *proxy = expression->toNameProxy();
  23.410 -    if (!proxy->binding()->kind() == BoundName::VARIABLE) {
  23.411 -        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  23.412 -        return NULL;
  23.413 -    }
  23.414 -
  23.415 -    Variable *var = proxy->binding()->toVariable();
  23.416 -    if (!var->type())
  23.417 -        return NULL;
  23.418 -
  23.419 -    if  (var->type()->isReference()) {
  23.420 -        if (var->type()->isConst()) {
  23.421 -            cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  23.422 -            return NULL;
  23.423 -        }
  23.424 -        return var->type()->contained();
  23.425 -    }
  23.426 -    return var->type();
  23.427 -}
  23.428 -
  23.429 -SemanticAnalysis::ControlStatus
  23.430 -SemanticAnalysis::visitForControl(Statement *statement)
  23.431 -{
  23.432 -    ControlScope scope(&control_);
  23.433 -    statement->accept(this);
  23.434 -    return scope.status();
  23.435 -}
  23.436 -
  23.437 -void
  23.438 -SemanticAnalysis::visit(NameProxy *name)
  23.439 -{
  23.440 -    BoundName *binding = name->binding();
  23.441 -
  23.442 -    if (binding->scope()->kind() == Scope::GLOBAL) {
  23.443 -        if (!function_ || function_->isPublic()) {
  23.444 -            // Whatever we're referencing must be kept alive no matter what.
  23.445 -            // As such, we simply mark it used, and don't do anything special.
  23.446 -            binding->setUsed();
  23.447 -        } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
  23.448 -            // Otherwise, we're inside a normal stock or function. Since we
  23.449 -            // don't really know if we've been used yet, we shouldn't
  23.450 -            // prematurely references as alive. Instead, we keep a list of
  23.451 -            // which names have been used, so we can mark them later if needed.
  23.452 -            //
  23.453 -            // Note that we skip this step if the binding is already in the
  23.454 -            // root set.
  23.455 -            if (!function_->addUsedGlobal(binding))
  23.456 -                return;
  23.457 -        }
  23.458 -    }
  23.459 -
  23.460 -    name->setType(binding->type());
  23.461 -}
  23.462 -
  23.463 -void
  23.464 -SemanticAnalysis::visit(Assignment *node)
  23.465 -{
  23.466 -    Local<Type> exprType(zone_, visitForLoad(node->expression()));
  23.467 -    if (!exprType)
  23.468 -        return ;
  23.469 -
  23.470 -    Local<Type> type(zone_, visitForLValue(node->lvalue()));
  23.471 -    if (!type)
  23.472 -        return;
  23.473 -
  23.474 -    if (node->token() != TOK_ASSIGN) {
  23.475 -        if (!typeCheckBinary(node, node->token(), type, exprType))
  23.476 -            return;
  23.477 -    }
  23.478 -
  23.479 -    if (!typeCheckAssignment(node->pos(), exprType, type, true))
  23.480 -        return;
  23.481 -
  23.482 -    node->setType(type);
  23.483 -}
  23.484 -
  23.485 -void
  23.486 -SemanticAnalysis::visit(IncDecExpression *node)
  23.487 -{
  23.488 -    Local<Type> type(zone_, visitForLValue(node->expression()));
  23.489 -    if (!type)
  23.490 -        return;
  23.491 -
  23.492 -    assert(!type->isReference());
  23.493 -
  23.494 -    if (!type->isInt32() && !type->isFloat()) {
  23.495 -        unaryTypeError(node, node->token(), type);
  23.496 -        return;
  23.497 -    }
  23.498 -
  23.499 -    node->setType(type);
  23.500 -}
  23.501 -
  23.502 -void
  23.503 -SemanticAnalysis::visit(UnaryExpression *node)
  23.504 -{
  23.505 -    Local<Type> type(zone_, visitForLoad(node->expression()));
  23.506 -    if (!type)
  23.507 -        return;
  23.508 -
  23.509 -    switch (node->token())
  23.510 -    {
  23.511 -      case TOK_NOT:
  23.512 -        if (!canTest(node->expression(), type))
  23.513 -            return;
  23.514 -        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
  23.515 -        if (!type)
  23.516 -            return;
  23.517 -        node->setType(type);
  23.518 -        break;
  23.519 -
  23.520 -      case TOK_MINUS:
  23.521 -        if (!type->isFloat() && !type->isInt32()) {
  23.522 -            unaryTypeError(node, node->token(), type);
  23.523 -            return;
  23.524 -        }
  23.525 -        node->setType(type);
  23.526 -        break;
  23.527 -
  23.528 -      case TOK_LABEL:
  23.529 -      {
  23.530 -        Local<Type> to(zone_, bindType(node->pos(), node->type()));
  23.531 -        if (!to)
  23.532 -            return;
  23.533 -
  23.534 -        if ((!type->isFloat() && !type->isInt32OrEnum()) ||
  23.535 -            (!to->isFloat() && !to->isInt32OrEnum()))
  23.536 -        {
  23.537 -            unaryTypeError(node, node->token(), type);
  23.538 -            return;
  23.539 -        }
  23.540 -
  23.541 -        node->setType(to);
  23.542 -        break;
  23.543 -      }
  23.544 -
  23.545 -      case TOK_SIZEOF:
  23.546 -      {
  23.547 -        if (!type->isArray()) {
  23.548 -            cc_.reportError(node->pos(), Message_SizeofNeedsArray);
  23.549 -            return;
  23.550 -        }
  23.551 -        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
  23.552 -        break;
  23.553 -      }
  23.554 -
  23.555 -      default:
  23.556 -        assert(node->token() == TOK_TILDE);
  23.557 -        if (!type->isInt32()) {
  23.558 -            unaryTypeError(node, node->token(), type);
  23.559 -            return;
  23.560 -        }
  23.561 -        node->setType(type);
  23.562 -        break;
  23.563 -    }
  23.564 -}
  23.565 -
  23.566 -void
  23.567 -SemanticAnalysis::visit(TernaryExpression *node)
  23.568 -{
  23.569 -    Local<Type> type(zone_, visitForLoad(node->condition()));
  23.570 -    if (!type)
  23.571 -        return;
  23.572 -
  23.573 -    if (!canTest(node->condition(), type))
  23.574 -        return;
  23.575 -
  23.576 -    Local<Type> left(zone_, visitForLoad(node->left()));
  23.577 -    Local<Type> right(zone_, visitForLoad(node->right()));
  23.578 -    if (!left || !right)
  23.579 -        return;
  23.580 -
  23.581 -    if (left != right) {
  23.582 -        binaryTypeError(node, TOK_QMARK, left, right);
  23.583 -        return;
  23.584 -    }
  23.585 -}
  23.586 -
  23.587 -void
  23.588 -SemanticAnalysis::visit(BinaryExpression *node)
  23.589 -{
  23.590 -    Local<Type> left(zone_, visitForLoad(node->left()));
  23.591 -    Local<Type> right(zone_, visitForLoad(node->right()));
  23.592 -    if (!left || !right)
  23.593 -        return;
  23.594 -
  23.595 -    Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
  23.596 -    if (!result)
  23.597 -        return;
  23.598 -
  23.599 -    node->setType(result);
  23.600 -}
  23.601 -
  23.602 -void
  23.603 -SemanticAnalysis::visit(ReturnStatement *node)
  23.604 -{
  23.605 -    // Set this early, so if we error we don't get more errors.
  23.606 -    control_->returns(Returns_Always);
  23.607 -
  23.608 -    if (!node->expression()) {
  23.609 -        if (!function_->type()->returnType()->isVoid())
  23.610 -            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
  23.611 -        return;
  23.612 -    }
  23.613 -
  23.614 -    Local<Type> type(zone_, visitForLoad(node->expression()));
  23.615 -    if (!type)
  23.616 -        return;
  23.617 -
  23.618 -    Local<Type> returnType(zone_, function_->type()->returnType());
  23.619 -    if (!typeCheckAssignment(node->pos(), type, returnType, true))
  23.620 -        return;
  23.621 -}
  23.622 -
  23.623 -void
  23.624 -SemanticAnalysis::visit(ForStatement *node)
  23.625 -{
  23.626 -    LoopScope loop(&loop_);
  23.627 -
  23.628 -    if (node->scope())
  23.629 -        scope_ = node->scope();
  23.630 -
  23.631 -    if (node->initialization())
  23.632 -        node->initialization()->accept(this);
  23.633 -
  23.634 -    if (node->condition()) {
  23.635 -        Local<Type> type(zone_, visitForLoad(node->condition()));
  23.636 -        if (!type || !canTest(node->condition(), type)) {
  23.637 -            return;
  23.638 -        }
  23.639 -    }
  23.640 -
  23.641 -    if (node->update())
  23.642 -        node->update()->accept(this);
  23.643 -
  23.644 -    ControlStatus status = visitForControl(node->body());
  23.645 -
  23.646 -    // If there is a condition, we treat this like a while loop. Otherwise,
  23.647 -    // join point is only reachable if the loop contains a break. The
  23.648 -    // termination status doesn't tell us anything yet.
  23.649 -    if (node->condition() || loop.breaks())
  23.650 -        control_->merge(status, ControlStatus(false, Returns_Never));
  23.651 -    else
  23.652 -        control_->terminate(status.returns());
  23.653 -
  23.654 -    if (node->scope())
  23.655 -        scope_ = scope_->enclosing();
  23.656 -}
  23.657 -
  23.658 -void 
  23.659 -SemanticAnalysis::visit(WhileStatement *node)
  23.660 -{
  23.661 -    LoopScope loop(&loop_);
  23.662 -
  23.663 -    Local<Type> type(zone_, visitForLoad(node->condition()));
  23.664 -    if (!type || !canTest(node->condition(), type)) {
  23.665 -        return;
  23.666 -    }
  23.667 -
  23.668 -    ControlStatus status = visitForControl(node->body());
  23.669 -
  23.670 -    // Detect loops that will always have a fork in the control-flow graph.
  23.671 -    // This will be a |while| loop, or a |do-while| loop whose body does
  23.672 -    // not terminate.
  23.673 -    //
  23.674 -    // For now, we treat these as an |if| regardless of the direction the
  23.675 -    // branch can take. That means the control-flow is always conditional.
  23.676 -    if (node->token() == TOK_WHILE ||
  23.677 -        !status.terminates() ||
  23.678 -        loop.breaks())
  23.679 -    {
  23.680 -        control_->merge(status, ControlStatus(false, Returns_Never));
  23.681 -    } else {
  23.682 -        // At this point, we've got a do-while loop with a |return| or
  23.683 -        // |continue|, meaning that the rest of the block is unreachable.
  23.684 -        control_->terminate(status.returns());
  23.685 -    }
  23.686 -}
  23.687 -
  23.688 -void
  23.689 -SemanticAnalysis::visit(BlockStatement *node)
  23.690 -{
  23.691 -    if (node->scope())
  23.692 -        scope_ = node->scope();
  23.693 -    for (size_t i = 0; i < node->statements()->length(); i++) {
  23.694 -        Statement *statement = node->statements()->at(i);
  23.695 -        statement->accept(this);
  23.696 -    }
  23.697 -    if (node->scope())
  23.698 -        scope_ = scope_->enclosing();
  23.699 -}
  23.700 -
  23.701 -static inline bool
  23.702 -IsScalarString(Type *type)
  23.703 -{
  23.704 -    if (type->isPrimitive() && type->primitive() == PrimitiveType_Char)
  23.705 -        return true;
  23.706 -    if (type->isReference())
  23.707 -        return IsScalarString(type->contained());
  23.708 -    return false;
  23.709 -}
  23.710 -
  23.711 -static const int INFER_ARRAY_SIZE = 0;
  23.712 -static const int EVAL_ARRAY_SIZE = -1;
  23.713 -static const int DYNAMIC_ARRAY_SIZE = -2;
  23.714 -
  23.715 -bool
  23.716 -SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
  23.717 -{
  23.718 -    bool hadEmptySize = false;
  23.719 -
  23.720 -    for (size_t i = 0; i < exprs->length(); i++) {
  23.721 -        Expression *expr = exprs->at(i);
  23.722 -        if (!expr) {
  23.723 -            dims[i] = INFER_ARRAY_SIZE;
  23.724 -            hadEmptySize = true;
  23.725 -            continue;
  23.726 -        }
  23.727 -
  23.728 -        BoxedPrimitive box;
  23.729 -        if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
  23.730 -            int size = box.toInt();
  23.731 -            if (size <= 0) {
  23.732 -                cc_.reportError(expr->pos(), Message_BadArraySize);
  23.733 -                return false;
  23.734 -            }
  23.735 -
  23.736 -            dims[i] = size;
  23.737 -            continue;
  23.738 -        }
  23.739 -
  23.740 -        Local<Type> exprType(zone_, visitForLoad(expr));
  23.741 -        if (!exprType)
  23.742 -            return false;
  23.743 -
  23.744 -        if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
  23.745 -            cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
  23.746 -            return false;
  23.747 -        }
  23.748 -
  23.749 -        if (hadEmptySize) {
  23.750 -            cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
  23.751 -            return false;
  23.752 -        }
  23.753 -
  23.754 -        dims[i] = EVAL_ARRAY_SIZE;
  23.755 -    }
  23.756 -
  23.757 -    return true;
  23.758 -}
  23.759 -
  23.760 -bool
  23.761 -SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
  23.762 -                                         int dims[MAX_ARRAY_DEPTH],
  23.763 -                                         unsigned dimcount, unsigned level)
  23.764 -{
  23.765 -    if (dims[level] == EVAL_ARRAY_SIZE) {
  23.766 -        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
  23.767 -        return false;
  23.768 -    }
  23.769 -
  23.770 -    if (dims[level] == INFER_ARRAY_SIZE) {
  23.771 -        // Strings always become dynamic arrays.
  23.772 -        if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
  23.773 -            dims[level] = literal->expressions()->length();
  23.774 -    } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
  23.775 -        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
  23.776 -        return false;
  23.777 -    } else {
  23.778 -        if (literal->expressions()->length() != unsigned(dims[level])) {
  23.779 -            cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
  23.780 -            return false;
  23.781 -        }
  23.782 -    }
  23.783 -
  23.784 -    if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
  23.785 -        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  23.786 -            Expression *expr = literal->expressions()->at(i);
  23.787 -            if (!expr->isStringLiteral()) {
  23.788 -                cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
  23.789 -                return false;
  23.790 -            }
  23.791 -
  23.792 -            StringLiteral *lit = expr->toStringLiteral();
  23.793 -            if (dims[level + 1] > 0 &&
  23.794 -                unsigned(dims[level]) < lit->string()->length())
  23.795 -            {
  23.796 -                cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
  23.797 -                return false;
  23.798 -            }
  23.799 -            if (!visitAndApplyType(lit))
  23.800 -                return false;
  23.801 -        }
  23.802 -    } else if (level == dimcount - 1) {
  23.803 -        Local<Type> type(zone_);
  23.804 -        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  23.805 -            Expression *expr = literal->expressions()->at(i);
  23.806 -            if (expr->isArrayLiteral()) {
  23.807 -                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
  23.808 -                return false;
  23.809 -            }
  23.810 -
  23.811 -            if ((type = visitAndApplyType(expr)) == NULL)
  23.812 -                return false;
  23.813 -
  23.814 -            if (!typeCheckAssignment(expr->pos(), type, contained, true))
  23.815 -                return false;
  23.816 -        }
  23.817 -    } else {
  23.818 -        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  23.819 -            Expression *expr = literal->expressions()->at(i);
  23.820 -            if (!expr->isArrayLiteral()) {
  23.821 -                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
  23.822 -                return false;
  23.823 -            }
  23.824 -
  23.825 -            assert(expr->toArrayLiteral()->isFixed());
  23.826 -
  23.827 -            if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
  23.828 -                                        contained,
  23.829 -                                        dims,
  23.830 -                                        dimcount,
  23.831 -                                        level + 1))
  23.832 -            {
  23.833 -                return false;
  23.834 -            }
  23.835 -        }
  23.836 -    }
  23.837 -
  23.838 -    return true;
  23.839 -}
  23.840 -
  23.841 -void
  23.842 -SemanticAnalysis::visit(VariableDeclaration *node)
  23.843 -{
  23.844 -    Local<Type> type(zone_, bindType(node->pos(), node->type()));
  23.845 -    if (!type)
  23.846 -        return;
  23.847 -
  23.848 -#if 0
  23.849 -    if (node->postDimensions() || type->isArray()) {
  23.850 -        // The type could be an array type, so sum the type and postDimensions
  23.851 -        // together.
  23.852 -        unsigned dimcount = node->postDimensions()->length();
  23.853 -        if (type->isArray())
  23.854 -            dimcount += type->levels();
  23.855 -        if (dimcount > MAX_ARRAY_DEPTH) {
  23.856 -            cc_.reportError(node->pos(), Message_MaximumArrayDepth);
  23.857 -            return;
  23.858 -        }
  23.859 -
  23.860 -        // Take an initial guess at the array dimension sizes.
  23.861 -        int dims[MAX_ARRAY_DEPTH];
  23.862 -        if (!evaluateDimensions(node->postDimensions(), dims))
  23.863 -            return;
  23.864 -
  23.865 -        // Now add in the type's array dimensions.
  23.866 -        Local<Type> contained(zone_, type);
  23.867 -        for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
  23.868 -            if (type->isFixedLength())
  23.869 -                dims[i] = type->fixedLength();
  23.870 -            else
  23.871 -                dims[i] = DYNAMIC_ARRAY_SIZE;
  23.872 -            contained = contained->contained();
  23.873 -        }
  23.874 -
  23.875 -        Expression *initializer = node->initialization();
  23.876 -        if (initializer &&
  23.877 -            initializer->isArrayLiteral() &&
  23.878 -            initializer->toArrayLiteral()->isFixed())
  23.879 -        {
  23.880 -            // Fixed array initializers are special; we use them to infer any
  23.881 -            // missing information in the original array. We do not evaluate
  23.882 -            // the array initializer as an expression.
  23.883 -            if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
  23.884 -                                        contained,
  23.885 -                                        dims,
  23.886 -                                        dimcount,
  23.887 -                                        0))
  23.888 -            {
  23.889 -                return;
  23.890 -            }
  23.891 -            initializer = NULL;
  23.892 -        }
  23.893 -
  23.894 -        // We now have enough information to build the actual array type.
  23.895 -        // Start from the original dimcount, not the one computed for
  23.896 -        // initializers.
  23.897 -        for (size_t i = node->postDimensions()->length() - 1;
  23.898 -             i < node->postDimensions()->length();
  23.899 -             i--)
  23.900 -        {
  23.901 -            int size = dims[i] > 0
  23.902 -                       ? dims[i]
  23.903 -                       : Type::DYNAMIC_ARRAY_SIZE;
  23.904 -
  23.905 -            type = zone_->types()->newArray(type, size, false);
  23.906 -            if (!type)
  23.907 -                return;
  23.908 -        }
  23.909 -
  23.910 -        // Finally, if we had a non-fixed initializer, make sure it type
  23.911 -        // checks. 
  23.912 -        if (initializer) {
  23.913 -            Local<Type> right(zone_, visitForLoad(initializer));
  23.914 -            if (!right)
  23.915 -                return;
  23.916 -
  23.917 -            if (!typeCheckAssignment(node->pos(), right, type, true))
  23.918 -                return;
  23.919 -        }
  23.920 -    } else {
  23.921 -        if (node->initialization()) {
  23.922 -            Local<Type> right(zone_, visitForLoad(node->initialization()));
  23.923 -            if (!right)
  23.924 -                return;
  23.925 -            if (!typeCheckAssignment(node->pos(), right, type, true))
  23.926 -                return;
  23.927 -        }
  23.928 -
  23.929 -        if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) {
  23.930 -            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
  23.931 -            return;
  23.932 -        }
  23.933 -    }
  23.934 -#endif
  23.935 -
  23.936 -#if 0
  23.937 -    // If this variable is stack allocated, we could use the LIFO heap
  23.938 -    // to allocate it. If that's the case, make sure to reserve a slot
  23.939 -    // so we can unwind the LIFO heap at the end of this scope.
  23.940 -    if (!node->variable()->needsHeapAllocation()) {
  23.941 -        if (type->isArray() || type->isStruct())
  23.942 -            scope_->setUsesLifoHeap();
  23.943 -    }
  23.944 -
  23.945 -    node->variable()->setType(type);
  23.946 -#endif
  23.947 -}
  23.948 -
  23.949 -void
  23.950 -SemanticAnalysis::visit(IntegerLiteral *node)
  23.951 -{
  23.952 -    node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
  23.953 -}
  23.954 -
  23.955 -void
  23.956 -SemanticAnalysis::visit(BooleanLiteral *node)
  23.957 -{
  23.958 -    node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool));
  23.959 -}
  23.960 -
  23.961 -void
  23.962 -SemanticAnalysis::visit(ExpressionStatement *node)
  23.963 -{
  23.964 -    visitAndApplyType(node->expression());
  23.965 -}
  23.966 -
  23.967 -Box *
  23.968 -SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
  23.969 -{
  23.970 -    Local<Type> given(zone_, visitForLoad(parameter->initializer()));
  23.971 -
  23.972 -    BoxedPrimitive prim;
  23.973 -    if (EvaluateForConstant(parameter->initializer(), &prim)) {
  23.974 -        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
  23.975 -            return NULL;
  23.976 -
  23.977 -        if (prim.type() == PrimitiveType_Int32)
  23.978 -            return Box::New(zone_, given, prim.toInt());
  23.979 -        return Box::New(zone_, given, prim.toFloat());
  23.980 -    } else if (parameter->initializer()->isStringLiteral()) {
  23.981 -        StringLiteral *literal = parameter->initializer()->toStringLiteral();
  23.982 -
  23.983 -        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
  23.984 -            return NULL;
  23.985 -
  23.986 -        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, given));
  23.987 -        if (!map)
  23.988 -            return NULL;
  23.989 -
  23.990 -        Local<Array> array(zone_,
  23.991 -            Array::NewString(zone_,
  23.992 -                             map,
  23.993 -                             literal->string()->raw(),
  23.994 -                             literal->string()->length(),
  23.995 -                             Heap::Tenure_Old));
  23.996 -        if (!array)
  23.997 -            return NULL;
  23.998 -
  23.999 -        return Box::NewObj(zone_, given, array, Heap::Tenure_Old);
 23.1000 -    }
 23.1001 -
 23.1002 -    cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant);
 23.1003 -    return NULL;
 23.1004 -}
 23.1005 -
 23.1006 -bool
 23.1007 -SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
 23.1008 -                                    FixedArray **argsp, FixedArray **defaultsp)
 23.1009 -{
 23.1010 -    Local<FixedArray> args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
 23.1011 -    if (!args)
 23.1012 -        return false;
 23.1013 -
 23.1014 -    Local<FixedArray> defaults(zone_);
 23.1015 -
 23.1016 -    // Apply types to arguments.
 23.1017 -    for (size_t i = 0; i < sig.parameters()->length(); i++) {
 23.1018 -        Parameter *parameter = sig.parameters()->at(i);
 23.1019 -        
 23.1020 -#if 0
 23.1021 -        Local<Type> type(zone_, bindType(parameter->variable()->pos(), parameter->type()));
 23.1022 -        if (!type)
 23.1023 -            return false;
 23.1024 -
 23.1025 -        if (parameter->reference()) {
 23.1026 -            if (parameter->dimensions()) {
 23.1027 -                cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
 23.1028 -                return false;
 23.1029 -            }
 23.1030 -
 23.1031 -            if (type->isStruct()) {
 23.1032 -                cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference);
 23.1033 -                return false;
 23.1034 -            }
 23.1035 -
 23.1036 -            type = zone_->types()->getReference(type, parameter->isConst());
 23.1037 -            if (!type)
 23.1038 -                return false;
 23.1039 -        } else if (parameter->dimensions()) {
 23.1040 -            type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
 23.1041 -            if (!type)
 23.1042 -                return false;
 23.1043 -
 23.1044 -            if (kind == TOK_NATIVE && type->levels() > 1) {
 23.1045 -                cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
 23.1046 -                return false;
 23.1047 -            }
 23.1048 -        }
 23.1049 -
 23.1050 -        if (IsScalarString(type)) {
 23.1051 -            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
 23.1052 -            return false;
 23.1053 -        }
 23.1054 -
 23.1055 -        args->set(zone_, i, type);
 23.1056 -        parameter->variable()->setType(type);
 23.1057 -
 23.1058 -        if (parameter->initializer()) {
 23.1059 -            if (!defaults) {
 23.1060 -                defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old);
 23.1061 -                if (!defaults)
 23.1062 -                    return false;
 23.1063 -            }
 23.1064 -
 23.1065 -            Local<Box> box(zone_, evaluateDefaultParameter(type, parameter));
 23.1066 -            if (!box)
 23.1067 -                return false;
 23.1068 -
 23.1069 -            defaults->set(zone_, i, box);
 23.1070 -        }
 23.1071 -#endif
 23.1072 -    }
 23.1073 -
 23.1074 -    *argsp = args;
 23.1075 -    *defaultsp = defaults;
 23.1076 -
 23.1077 -    return true;
 23.1078 -}
 23.1079 -
 23.1080 -void
 23.1081 -SemanticAnalysis::visit(FunctionTypeStatement *node)
 23.1082 -{
 23.1083 -    if (node->decl()->type())
 23.1084 -        return;
 23.1085 -
 23.1086 -    Local<FixedArray> args(zone_);
 23.1087 -    Local<FixedArray> defaults(zone_);
 23.1088 -
 23.1089 -    const FunctionSignature &sig= node->signature();
 23.1090 -    if (!buildFunctionArgs(node,
 23.1091 -                           TOK_STOCK,
 23.1092 -                           sig,
 23.1093 -                           args.address(),
 23.1094 -                           defaults.address()))
 23.1095 -    {
 23.1096 -        return;
 23.1097 -    }
 23.1098 -
 23.1099 -#if 0
 23.1100 -    Local<Type> returnType(zone_);
 23.1101 -    if (sig.returnType())
 23.1102 -        returnType = bindType(node->pos(), sig.returnType());
 23.1103 -    else
 23.1104 -        returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
 23.1105 -
 23.1106 -    if (!returnType)
 23.1107 -        return;
 23.1108 -
 23.1109 -    Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args, defaults));
 23.1110 -    if (!funtype)
 23.1111 -        return;
 23.1112 -
 23.1113 -    node->decl()->setType(funtype);
 23.1114 -#endif
 23.1115 -}
 23.1116 -
 23.1117 -Type *
 23.1118 -SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
 23.1119 -{
 23.1120 -    Local<Type> arrayType(zone_, type);
 23.1121 -
 23.1122 -    unsigned dimcount = dimensions->length();
 23.1123 -    if (type->isArray())
 23.1124 -        dimcount += type->levels();
 23.1125 -
 23.1126 -    if (dimcount > MAX_ARRAY_DEPTH) {
 23.1127 -        cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
 23.1128 -                        Message_MaximumArrayDepth);
 23.1129 -        return false;
 23.1130 -    }
 23.1131 -
 23.1132 -    // Note: constness is sort of bogus. Fix this sometime.
 23.1133 -    for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
 23.1134 -        Expression *expr = dimensions->at(i);
 23.1135 -        if (!expr) {
 23.1136 -            arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
 23.1137 -            if (!arrayType)
 23.1138 -                return NULL;
 23.1139 -
 23.1140 -            continue;
 23.1141 -        }
 23.1142 -
 23.1143 -        BoxedPrimitive box;
 23.1144 -        if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
 23.1145 -            cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
 23.1146 -            return NULL;
 23.1147 -        }
 23.1148 -
 23.1149 -        if (box.toInt() <= 0) {
 23.1150 -            cc_.reportError(expr->pos(), Message_BadArraySize);
 23.1151 -            return NULL;
 23.1152 -        }
 23.1153 -
 23.1154 -        arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
 23.1155 -        if (!arrayType)
 23.1156 -            return NULL;
 23.1157 -    }
 23.1158 -
 23.1159 -    return arrayType;
 23.1160 -}
 23.1161 -
 23.1162 -bool
 23.1163 -SemanticAnalysis::preanalyze(FunctionStatement *node)
 23.1164 -{
 23.1165 -    Local<FixedArray> args(zone_);
 23.1166 -    Local<FixedArray> defaults(zone_);
 23.1167 -
 23.1168 -    const FunctionSignature &sig = node->signature();
 23.1169 -    if (!buildFunctionArgs(node,
 23.1170 -                           node->fun()->token(),
 23.1171 -                           sig,
 23.1172 -                           args.address(),
 23.1173 -                           defaults.address()))
 23.1174 -    {
 23.1175 -        return false;
 23.1176 -    }
 23.1177 -
 23.1178 -#if 0
 23.1179 -    Local<Type> returnType(zone_);
 23.1180 -    if (sig.returnType() ||
 23.1181 -        node->hasExplicitReturn() ||
 23.1182 -        node->fun()->isNative())
 23.1183 -    {
 23.1184 -        returnType = bindType(node->pos(), sig.returnType());
 23.1185 -    } else {
 23.1186 -        returnType = zone_->types()->getVoid();
 23.1187 -    }
 23.1188 -    if (!returnType)
 23.1189 -        return false;
 23.1190 -
 23.1191 -    if (sig.returnDimensions()) {
 23.1192 -        returnType = buildArrayType(returnType, sig.returnDimensions(), false);
 23.1193 -        if (!returnType)
 23.1194 -            return false;
 23.1195 -    }
 23.1196 -
 23.1197 -    if (IsScalarString(returnType)) {
 23.1198 -        cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
 23.1199 -        return false;
 23.1200 -    }
 23.1201 -
 23.1202 -    Local<Type> funtype(zone_);
 23.1203 -    if (node->fun()->isNative())
 23.1204 -        funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
 23.1205 -    else
 23.1206 -        funtype = zone_->types()->newFunction(returnType, args, defaults);
 23.1207 -    if (!funtype)
 23.1208 -        return false;
 23.1209 -    
 23.1210 -    // If the function already has a type, it was forward declared before, and
 23.1211 -    // now this is our chance to type check the second declaration.
 23.1212 -    if (node->fun()->type()) {
 23.1213 -        Local<Type> forward(zone_, node->fun()->type());
 23.1214 -        if (!Type::Compare(funtype, forward)) {
 23.1215 -            cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
 23.1216 -            return false;
 23.1217 -        }
 23.1218 -        node->fun()->setForwardType(forward);
 23.1219 -    }
 23.1220 -
 23.1221 -    node->fun()->setType(funtype);
 23.1222 -#endif
 23.1223 -
 23.1224 -    return true;
 23.1225 -}
 23.1226 -
 23.1227 -void
 23.1228 -SemanticAnalysis::visit(FunctionStatement *node)
 23.1229 -{
 23.1230 -    function_ = node->fun();
 23.1231 -    scope_ = node->scope();
 23.1232 -
 23.1233 -    ControlScope control(&control_);
 23.1234 -    if (node->body()) {
 23.1235 -        node->body()->accept(this);
 23.1236 -
 23.1237 -        ControlStatus status = control.status();
 23.1238 -        if (status.returns() == Returns_Sometimes) {
 23.1239 -            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
 23.1240 -        } else if (status.returns() == Returns_Never) {
 23.1241 -            if (!function_->type()->returnType()->isVoid())
 23.1242 -                cc_.reportError(node->pos(), Message_MissingReturnValue);
 23.1243 -        }
 23.1244 -    }
 23.1245 -
 23.1246 -    scope_ = NULL;
 23.1247 -    function_ = NULL;
 23.1248 -}
 23.1249 -
 23.1250 -void
 23.1251 -SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given)
 23.1252 -{
 23.1253 -    cc_.reportError(pos, Message_TypeMismatch,
 23.1254 -                    GetTypeName(actual),
 23.1255 -                    GetTypeName(given));
 23.1256 -}
 23.1257 -
 23.1258 -bool
 23.1259 -SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> argGiven,
 23.1260 -                                           Handle<Type> argActual, bool forAssign)
 23.1261 -{
 23.1262 -    Local<Type> actual(zone_, argActual);
 23.1263 -    Local<Type> given(zone_, argGiven);
 23.1264 -
 23.1265 -    if (!given->isArray()) {
 23.1266 -        cc_.reportError(pos, Message_ExpectedArray);
 23.1267 -        return false;
 23.1268 -    }
 23.1269 -    if (given->levels() != actual->levels()) {
 23.1270 -        cc_.reportError(pos, Message_ArrayDimensionsMismatch);
 23.1271 -        return false;
 23.1272 -    }
 23.1273 -
 23.1274 -    unsigned level = 1;
 23.1275 -    while (given->isArray()) {
 23.1276 -        if (actual->isFixedLength()) {
 23.1277 -            if (forAssign) {
 23.1278 -                if (!given->isFixedLength()) {
 23.1279 -                    cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 23.1280 -                    return false;
 23.1281 -                }
 23.1282 -
 23.1283 -                if (actual->isCharArray()) {
 23.1284 -                    // String assignment can have a truncated |given|.
 23.1285 -                    if (given->fixedLength() > actual->fixedLength()) {
 23.1286 -                        cc_.reportError(pos, Message_ArrayAssignmentTooBig);
 23.1287 -                        return false;
 23.1288 -                    }
 23.1289 -                } else {
 23.1290 -                    if (given->fixedLength() != actual->fixedLength()) {
 23.1291 -                        cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 23.1292 -                        return false;
 23.1293 -                    }
 23.1294 -                }
 23.1295 -            }
 23.1296 -        } else if (given->isFixedLength()) {
 23.1297 -            // We do not allow assignments in the form:
 23.1298 -            //    [][] = [][Y]
 23.1299 -            //
 23.1300 -            // Otherwise, the following code could break the size guarantees
 23.1301 -            // of the right-hand side:
 23.1302 -            //
 23.1303 -            //   new x[][5];
 23.1304 -            //   new y[][];
 23.1305 -            //   new z[3];
 23.1306 -            //
 23.1307 -            //   y = x;
 23.1308 -            //   y[0] = z;
 23.1309 -            //   
 23.1310 -            // Now |x[0]| contains a 4-length array.
 23.1311 -            if (level > 1) {
 23.1312 -                cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 23.1313 -                return false;
 23.1314 -            }
 23.1315 -        }
 23.1316 -        given = given->contained();
 23.1317 -        actual = actual->contained();
 23.1318 -        level++;
 23.1319 -    }
 23.1320 -
 23.1321 -    return typeCheckAssignment(pos, given, actual, forAssign);
 23.1322 -}
 23.1323 -
 23.1324 -bool
 23.1325 -SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle<Type> argGiven,
 23.1326 -                                      Handle<Type> argActual, bool forAssign)
 23.1327 -{
 23.1328 -    Local<Type> actual(zone_, argActual);
 23.1329 -    Local<Type> given(zone_, argGiven);
 23.1330 -
 23.1331 -    if (actual->isArray())
 23.1332 -        return typeCheckArrayAssignment(pos, given, actual, forAssign);
 23.1333 -
 23.1334 -    if (given->isArray()) {
 23.1335 -        cc_.reportError(pos, Message_CannotAssignArrayToScalar);
 23.1336 -        return false;
 23.1337 -    }
 23.1338 -
 23.1339 -    // The given type may not have been dereferenced.
 23.1340 -    if (given->isReference())
 23.1341 -        given = given->contained();
 23.1342 -    if (actual->isReference())
 23.1343 -        actual = actual->contained();
 23.1344 -
 23.1345 -    // We coerce unchecked to a few things.
 23.1346 -    if (actual->isUnchecked() || given->isUnchecked()) {
 23.1347 -        Type *check = actual->isUnchecked() ? given : actual;
 23.1348 -        if (check->isUnchecked() ||
 23.1349 -            check->isEnum() ||
 23.1350 -            check->isInt32() ||
 23.1351 -            check->isBool() ||
 23.1352 -            check->isFloat())
 23.1353 -        {
 23.1354 -            return true;
 23.1355 -        }
 23.1356 -        typeMismatch(pos, actual, given);
 23.1357 -        return false;
 23.1358 -    }
 23.1359 -
 23.1360 -    if (given->isFunction() && actual->isFunction()) {
 23.1361 -        if (!Type::Compare(given, actual)) {
 23.1362 -            typeMismatch(pos, actual, given);
 23.1363 -            return false;
 23.1364 -        }
 23.1365 -        return true;
 23.1366 -    }
 23.1367 -
 23.1368 -    if (actual->isEnum()) {
 23.1369 -        if (!given->isEnum() || actual != given) {
 23.1370 -            typeMismatch(pos, actual, given);
 23.1371 -            return false;
 23.1372 -        }
 23.1373 -        return true;
 23.1374 -    }
 23.1375 -
 23.1376 -    if (actual->isStruct()) {
 23.1377 -        if (!given->isStruct() || actual != given) {
 23.1378 -            typeMismatch(pos, actual, given);
 23.1379 -            return false;
 23.1380 -        }
 23.1381 -        return true;
 23.1382 -    }
 23.1383 -
 23.1384 -    if (given->isEnum() || given->isFunction() || given->isStruct()) {
 23.1385 -        typeMismatch(pos, actual, given);
 23.1386 -        return false;
 23.1387 -    }
 23.1388 -
 23.1389 -    // This coercion is trivial.
 23.1390 -    if (given->isBool() && actual->isInt32())
 23.1391 -        return true;
 23.1392 -
 23.1393 -    if (given->primitive() != actual->primitive()) {
 23.1394 -        typeMismatch(pos, actual, given);
 23.1395 -        return false;
 23.1396 -    }
 23.1397 -
 23.1398 -    return true;
 23.1399 -}
 23.1400 -
 23.1401 -bool
 23.1402 -SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
 23.1403 -{
 23.1404 -    return typeCheckAssignment(node->pos(), given, actual, false);
 23.1405 -}
 23.1406 -
 23.1407 -bool
 23.1408 -SemanticAnalysis::checkArgumentCount(Handle<Type> type, unsigned actual)
 23.1409 -{
 23.1410 -    if (type->parameters()->length() == actual)
 23.1411 -        return true;
 23.1412 -
 23.1413 -    if (actual > type->parameters()->length()) {
 23.1414 -        if (!type->isNative() || !type->isNativeVariadic())
 23.1415 -            return false;
 23.1416 -        return true;
 23.1417 -    }
 23.1418 -
 23.1419 -    if (!type->defaults())
 23.1420 -        return false;
 23.1421 -
 23.1422 -    // Missing arguments. See if there's a default argument for each missing
 23.1423 -    // actual.
 23.1424 -    for (unsigned i = actual; i < type->parameters()->length(); i++) {
 23.1425 -        if (!type->defaults()->at(i))
 23.1426 -            return false;
 23.1427 -    }
 23.1428 -
 23.1429 -    return true;
 23.1430 -}
 23.1431 -
 23.1432 -void
 23.1433 -SemanticAnalysis::visit(CallExpression *node)
 23.1434 -{
 23.1435 -    Local<Type> type(zone_, visitForLoad(node->callee()));
 23.1436 -    if (!type)
 23.1437 -        return;
 23.1438 -
 23.1439 -    if (!type->isFunction()) {
 23.1440 -        cc_.reportError(node->pos(), Message_CalleeNotFunction);
 23.1441 -        return;
 23.1442 -    }
 23.1443 -
 23.1444 -    if (!checkArgumentCount(type, node->arguments()->length())) {
 23.1445 -        cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
 23.1446 -        return;
 23.1447 -    }
 23.1448 -
 23.1449 -    // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
 23.1450 -    // if (fun->isForward()) {
 23.1451 -    //     cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
 23.1452 -    //     return;
 23.1453 -    // }
 23.1454 -
 23.1455 -    for (unsigned i = 0; i < node->arguments()->length(); i++) {
 23.1456 -        // Note: we don't compute references unless the callee needs a
 23.1457 -        // reference type.
 23.1458 -        Expression *expression = node->arguments()->at(i);
 23.1459 -        Local<Type> given(zone_, visitAndApplyType(expression));
 23.1460 -        if (!given)
 23.1461 -            return;
 23.1462 -
 23.1463 -        // Since we skip a load, check for a call expression that returns void.
 23.1464 -        if (given->isVoid()) {
 23.1465 -            assert(expression->isCallExpression());
 23.1466 -            CallExpression *call = expression->toCallExpression();
 23.1467 -            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
 23.1468 -            return;
 23.1469 -        }
 23.1470 -        
 23.1471 -        bool mustComputeReference;
 23.1472 -        if (i >= type->parameters()->length()) {
 23.1473 -            // Special handling for natives. Arguments past the formal must
 23.1474 -            // always have references computed. However, arrays are already
 23.1475 -            // references for natives.  
 23.1476 -            assert(type->isNative() && type->isNativeVariadic());
 23.1477 -            mustComputeReference = !given->isReference() && !given->isArray();
 23.1478 -        } else {
 23.1479 -            Local<Type> actual(zone_, type->parameterAt(i));
 23.1480 -
 23.1481 -            if (expression->isIndexExpression()) {
 23.1482 -                // Disabled until we can make it work.
 23.1483 -#if 0
 23.1484 -                if (actual->isArray()) {
 23.1485 -                    // We special case the ability to pass x[y] into x[], which
 23.1486 -                    // creates an array slice. We only do this if we know the
 23.1487 -                    // assignment would otherwise not type-check.
 23.1488 -                    IndexExpression *index = expression->toIndexExpression();
 23.1489 -                    if (index->left()->type()->levels() == actual->levels())
 23.1490 -                        given = index->left()->type();
 23.1491 -                } else
 23.1492 -#endif
 23.1493 -                if (actual->isReference()) {
 23.1494 -                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
 23.1495 -                    return;
 23.1496 -                }
 23.1497 -            }
 23.1498 -
 23.1499 -            if (!typeCheckParameter(expression, given, actual))
 23.1500 -                return;
 23.1501 -            mustComputeReference = actual->isReference() && !given->isReference();
 23.1502 -        }
 23.1503 -
 23.1504 -        // If the actual is a reference, and the given is not, we'll need to
 23.1505 -        // compute a reference, which may be allocated on the stack.
 23.1506 -        if (mustComputeReference)
 23.1507 -            scope_->setUsesLifoHeap();
 23.1508 -    }
 23.1509 -
 23.1510 -    node->setType(type->returnType());
 23.1511 -}
 23.1512 -
 23.1513 -void
 23.1514 -SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
 23.1515 -{
 23.1516 -    if (other.returns() < status().returns())
 23.1517 -        return;
 23.1518 -
 23.1519 -    if (other.terminates())
 23.1520 -        terminate(other.returns());
 23.1521 -    else
 23.1522 -        returns(other.returns());
 23.1523 -}
 23.1524 -
 23.1525 -void
 23.1526 -SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
 23.1527 -{
 23.1528 -    // If both sides terminate in a return, we consider this a return as well.
 23.1529 -    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
 23.1530 -        terminate(Returns_Always);
 23.1531 -        return;
 23.1532 -    }
 23.1533 -
 23.1534 -    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
 23.1535 -                          ? Returns_Never
 23.1536 -                          : Returns_Sometimes;
 23.1537 -
 23.1538 -    if (left.terminates() && right.terminates())
 23.1539 -        terminate(status);
 23.1540 -    else
 23.1541 -        returns(status);
 23.1542 -}
 23.1543 -
 23.1544 -void
 23.1545 -SemanticAnalysis::visit(IfStatement *node)
 23.1546 -{
 23.1547 -    Local<Type> type(zone_, visitForLoad(node->condition()));
 23.1548 -    if (!type)
 23.1549 -        return;
 23.1550 -
 23.1551 -    if (!canTest(node, type))
 23.1552 -        return;
 23.1553 -
 23.1554 -    ControlStatus trueBranch = visitForControl(node->ifTrue());
 23.1555 -    ControlStatus falseBranch = ControlStatus(false, Returns_Never);
 23.1556 -
 23.1557 -    if (node->ifFalse())
 23.1558 -        falseBranch = visitForControl(node->ifFalse());
 23.1559 -
 23.1560 -    control_->merge(trueBranch, falseBranch);
 23.1561 -}
 23.1562 -
 23.1563 -void
 23.1564 -SemanticAnalysis::visit(IndexExpression *node)
 23.1565 -{
 23.1566 -    Local<Type> left(zone_, visitForLoad(node->left()));
 23.1567 -    Local<Type> right(zone_, visitForLoad(node->right()));
 23.1568 -
 23.1569 -    if (!left || !right)
 23.1570 -        return;
 23.1571 -
 23.1572 -    if (!right->isInt32() && !right->isEnum()) {
 23.1573 -        cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
 23.1574 -        return;
 23.1575 -    }
 23.1576 -    if (!left->isArray()) {
 23.1577 -        cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
 23.1578 -        return;
 23.1579 -    }
 23.1580 -
 23.1581 -    // Note: char arrays are automatically up-casted to return an int32.
 23.1582 -    if (left->isCharArray())
 23.1583 -        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
 23.1584 -    else
 23.1585 -        node->setType(left->contained());
 23.1586 -}
 23.1587 -
 23.1588 -void
 23.1589 -SemanticAnalysis::visit(FieldExpression *node)
 23.1590 -{
 23.1591 -    Local<Type> left(zone_, visitForLoad(node->left()));
 23.1592 -    if (!left)
 23.1593 -        return;
 23.1594 -
 23.1595 -    if (!left->isStruct()) {
 23.1596 -        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
 23.1597 -                        GetTypeName(left));
 23.1598 -        return;
 23.1599 -    }
 23.1600 -
 23.1601 -    Local<String> field(zone_, node->field());
 23.1602 -
 23.1603 -    unsigned offset;
 23.1604 -    Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
 23.1605 -    if (!desc) {
 23.1606 -        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
 23.1607 -                        GetTypeName(left));
 23.1608 -        return;
 23.1609 -    }
 23.1610 -
 23.1611 -    node->setFieldIndex(offset);
 23.1612 -    node->setType(desc->type());
 23.1613 -}
 23.1614 -
 23.1615 -void
 23.1616 -SemanticAnalysis::visit(EnumStatement *node)
 23.1617 -{
 23.1618 -    Local<String> name(zone_, node->name());
 23.1619 -    Local<Type> type(zone_);
 23.1620 -    if (name)
 23.1621 -        type = zone_->types()->newEnum(name);
 23.1622 -    else
 23.1623 -        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
 23.1624 -
 23.1625 -    if (!type)
 23.1626 -        return;
 23.1627 -
 23.1628 -    if (node->decl())
 23.1629 -        node->decl()->setType(type);
 23.1630 -
 23.1631 -    int value = 0;
 23.1632 -    for (size_t i = 0; i < node->entries()->length(); i++) {
 23.1633 -        EnumStatement::Entry &entry = node->entries()->at(i);
 23.1634 -
 23.1635 -        BoxedPrimitive box = BoxedPrimitive::Int(value);
 23.1636 -        if (entry.expr) {
 23.1637 -            entry.expr->accept(this);
 23.1638 -            if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
 23.1639 -                cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
 23.1640 -                return;
 23.1641 -            }
 23.1642 -
 23.1643 -            assert(box.type() == PrimitiveType_Int32);
 23.1644 -            value = box.toInt();
 23.1645 -        }
 23.1646 -
 23.1647 -#if 0
 23.1648 -        entry.name->set(type, box);
 23.1649 -#endif
 23.1650 -        value++;
 23.1651 -    }
 23.1652 -}
 23.1653 -
 23.1654 -static int
 23.1655 -SortCaseIntValues(const void *p1, const void *p2)
 23.1656 -{
 23.1657 -    CaseValue *v1 = (CaseValue *)p1;
 23.1658 -    CaseValue *v2 = (CaseValue *)p2;
 23.1659 -
 23.1660 -    return v1->box.toInt() - v2->box.toInt();
 23.1661 -}
 23.1662 -
 23.1663 -void
 23.1664 -SemanticAnalysis::visit(SwitchStatement *node)
 23.1665 -{
 23.1666 -    Local<Type> caseType(zone_, visitForLoad(node->expression()));
 23.1667 -    if (!caseType)
 23.1668 -        return;
 23.1669 -
 23.1670 -    if (!caseType->isEnum() && !caseType->isInt32()) {
 23.1671 -        cc_.reportError(node->pos(), Message_CaseMustBeInteger);
 23.1672 -        return;
 23.1673 -    }
 23.1674 -
 23.1675 -    PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
 23.1676 -    ControlStatus status = ControlStatus(false, Returns_Never);
 23.1677 -
 23.1678 -    Local<Type> check(zone_);
 23.1679 -    for (size_t i = 0; i < node->cases()->length(); i++) {
 23.1680 -        Case *c = node->cases()->at(i);
 23.1681 -
 23.1682 -        check = visitForLoad(c->expression());
 23.1683 -        if (!check)
 23.1684 -            return;
 23.1685 -
 23.1686 -        if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
 23.1687 -            return;
 23.1688 -
 23.1689 -        CaseValue v(i);
 23.1690 -        if (!EvaluateForConstant(c->expression(), &v.box)) {
 23.1691 -            cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
 23.1692 -            return;
 23.1693 -        }
 23.1694 -        if (!values->append(v))
 23.1695 -            return;
 23.1696 -
 23.1697 -        if (c->others()) {
 23.1698 -            for (size_t j = 0; j < c->others()->length(); j++) {
 23.1699 -                Expression *expr = c->others()->at(j);
 23.1700 -                check = visitForLoad(expr);
 23.1701 -                if (!check)
 23.1702 -                    return;
 23.1703 -
 23.1704 -                if (!typeCheckAssignment(expr->pos(), check, caseType, false))
 23.1705 -                    return;
 23.1706 -
 23.1707 -                CaseValue v(i);
 23.1708 -                if (!EvaluateForConstant(expr, &v.box)) {
 23.1709 -                    cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
 23.1710 -                    return;
 23.1711 -                }
 23.1712 -                if (!values->append(v))
 23.1713 -                    return;
 23.1714 -            }
 23.1715 -        }
 23.1716 -
 23.1717 -        ControlStatus latest = visitForControl(c->statement());
 23.1718 -
 23.1719 -        if (i != 0)
 23.1720 -            control_->merge(status, latest);
 23.1721 -
 23.1722 -        status = latest;
 23.1723 -    }
 23.1724 -
 23.1725 -    if (node->defaultCase()) {
 23.1726 -        ControlStatus latest = visitForControl(node->defaultCase());
 23.1727 -
 23.1728 -        if (node->cases()->length()) {
 23.1729 -            // If we had any other cases, we must merge.
 23.1730 -            control_->merge(status, latest);
 23.1731 -        } else {
 23.1732 -            // Otherwise, control-flow always flows through here.
 23.1733 -            control_->inherit(latest);
 23.1734 -        }
 23.1735 -    } else if (node->cases()->length()) {
 23.1736 -        control_->merge(status, ControlStatus(false, Returns_Never));
 23.1737 -    }
 23.1738 -
 23.1739 -    if (values->length() > 1) {
 23.1740 -        qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
 23.1741 -
 23.1742 -        for (size_t i = 1; i < values->length(); i++) {
 23.1743 -            CaseValue &prev = values->at(i - 1);
 23.1744 -            CaseValue &cur = values->at(i);
 23.1745 -            if (prev.box.toInt() == cur.box.toInt()) {
 23.1746 -                cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
 23.1747 -                return;
 23.1748 -            }
 23.1749 -        }
 23.1750 -    }
 23.1751 -
 23.1752 -    node->setCaseValueList(values);
 23.1753 -}
 23.1754 -
 23.1755 -void
 23.1756 -SemanticAnalysis::visit(StructureStatement *node)
 23.1757 -{
 23.1758 -#if 0
 23.1759 -    // If this node already has a type, it was pre-analyzed, so skip it.
 23.1760 -    if (node->decl()->type())
 23.1761 -        return;
 23.1762 -
 23.1763 -    FieldList *fields = node->fields();
 23.1764 -    Local<FixedArray> desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old));
 23.1765 -    if (!desctable)
 23.1766 -        return;
 23.1767 -
 23.1768 -    Vector<unsigned> composedList;
 23.1769 -    StructureBufferBuilder builder;
 23.1770 -
 23.1771 -    Local<Type> type(zone_);
 23.1772 -    Local<String> name(zone_);
 23.1773 -    Local<Descriptor> desc(zone_);
 23.1774 -    for (size_t i = 0; i < fields->length(); i++) {
 23.1775 -        StructureStatement::Field *field = fields->at(i);
 23.1776 -
 23.1777 -        type = bindType(field->pos(), field->type());
 23.1778 -        if (!type)
 23.1779 -            return;
 23.1780 -
 23.1781 -        if (field->dimensions()) {
 23.1782 -            type = buildArrayType(type, field->dimensions(), false);
 23.1783 -            if (!type)
 23.1784 -                return;
 23.1785 -
 23.1786 -            if (!ArrayMap::Attach(zone_, type))
 23.1787 -                return;
 23.1788 -        }
 23.1789 -
 23.1790 -        if (IsScalarString(type)) {
 23.1791 -            cc_.reportError(field->pos(), Message_CannotDeclareStringCell);
 23.1792 -            return;
 23.1793 -        }
 23.1794 -
 23.1795 -        unsigned offset;
 23.1796 -        if (!builder.add(type, &offset))
 23.1797 -            return;
 23.1798 -
 23.1799 -        name = field->name();
 23.1800 -        desc = Descriptor::New(zone_, name, type, offset);
 23.1801 -        if (!desc)
 23.1802 -            return;
 23.1803 -
 23.1804 -        desctable->set(zone_, i, desc);
 23.1805 -
 23.1806 -        if (type->isStruct() || type->isArray()) {
 23.1807 -            if (!composedList.append(i))
 23.1808 -                return;
 23.1809 -        }
 23.1810 -    }
 23.1811 -
 23.1812 -    Local<FixedArray> composed(zone_);
 23.1813 -    if (composedList.length()) {
 23.1814 -        composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old);
 23.1815 -        if (!composed)
 23.1816 -            return;
 23.1817 -
 23.1818 -        for (unsigned i = 0; i < composedList.length(); i++)
 23.1819 -            composed->set(zone_, i, desctable->at(i));
 23.1820 -    }
 23.1821 -
 23.1822 -    Local<StructMap> map(zone_, StructMap::New(zone_, builder, composed));
 23.1823 -    if (!map)
 23.1824 -        return;
 23.1825 -
 23.1826 -    name = node->decl()->name();
 23.1827 -    type = zone_->types()->newStruct(name, desctable, map);
 23.1828 -    if (!type)
 23.1829 -        return;
 23.1830 -
 23.1831 -    map->setType(type);
 23.1832 -    node->decl()->setType(type);
 23.1833 -#endif
 23.1834 -}
 23.1835 -
 23.1836 -void
 23.1837 -SemanticAnalysis::visit(StringLiteral *node)
 23.1838 -{
 23.1839 -    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
 23.1840 -    if (!type)
 23.1841 -        return;
 23.1842 -
 23.1843 -    type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
 23.1844 -    if (!type)
 23.1845 -        return;
 23.1846 -
 23.1847 -    node->setType(type);
 23.1848 -}
 23.1849 -
 23.1850 -void
 23.1851 -SemanticAnalysis::visit(FloatLiteral *node)
 23.1852 -{
 23.1853 -    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
 23.1854 -    if (!type)
 23.1855 -        return;
 23.1856 -
 23.1857 -    node->setType(type);
 23.1858 -}
 23.1859 -
 23.1860 -void
 23.1861 -SemanticAnalysis::visit(BreakStatement *node)
 23.1862 -{
 23.1863 -    if (!loop_) {
 23.1864 -        cc_.reportError(node->pos(), Message_BreakOutsideLoop);
 23.1865 -        return;
 23.1866 -    }
 23.1867 -
 23.1868 -    // Note: ignore breaks that occur in unreachable control-flow.
 23.1869 -    if (!control_->status().terminates())
 23.1870 -        loop_->addBreak();
 23.1871 -
 23.1872 -    control_->terminate(Returns_Never);
 23.1873 -}
 23.1874 -
 23.1875 -void
 23.1876 -SemanticAnalysis::visit(ContinueStatement *node)
 23.1877 -{
 23.1878 -    if (!loop_) {
 23.1879 -        cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
 23.1880 -        return;
 23.1881 -    }
 23.1882 -
 23.1883 -    // Note: ignore continues that occur in unreachable control-flow.
 23.1884 -    if (!control_->status().terminates())
 23.1885 -        loop_->addContinue();
 23.1886 -
 23.1887 -    control_->terminate(Returns_Never);
 23.1888 -}
 23.1889 -
 23.1890 -void
 23.1891 -SemanticAnalysis::visit(ArrayLiteral *node)
 23.1892 -{
 23.1893 -    // We should never visit this.
 23.1894 -    cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
 23.1895 -}
 23.1896 -
 23.1897 -void
 23.1898 -SemanticAnalysis::visit(ImportStatement *node)
 23.1899 -{
 23.1900 -}
 23.1901 -
 23.1902 +/* vim: set ts=4 sw=4 tw=99 et:
 23.1903 + *
 23.1904 + * Copyright (C) 2012 David Anderson
 23.1905 + *
 23.1906 + * This file is part of JITCraft.
 23.1907 + *
 23.1908 + * JITCraft is free software: you can redistribute it and/or modify it under
 23.1909 + * the terms of the GNU General Public License as published by the Free
 23.1910 + * Software Foundation, either version 3 of the License, or (at your option)
 23.1911 + * any later version.
 23.1912 + * 
 23.1913 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
 23.1914 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 23.1915 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 23.1916 + *
 23.1917 + * You should have received a copy of the GNU General Public License along with
 23.1918 + * JITCraft. If not, see http://www.gnu.org/licenses/.
 23.1919 + */
 23.1920 +#include <string.h>
 23.1921 +#include "SemanticAnalysis.h"
 23.1922 +#include "../Types.h"
 23.1923 +#include "../Zone.h"
 23.1924 +#include "../TypeManager.h"
 23.1925 +#include "../Strings.h"
 23.1926 +#include "../Box.h"
 23.1927 +#include "../Array.h"
 23.1928 +#include "../Heap-inl.h"
 23.1929 +#include "Scopes.h"
 23.1930 +#include "NameBinding.h"
 23.1931 +
 23.1932 +using namespace ke;
 23.1933 +
 23.1934 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
 23.1935 +  : zone_(zone),
 23.1936 +    cc_(cc),
 23.1937 +    tree_(tree),
 23.1938 +    scope_(NULL),
 23.1939 +    loop_(NULL)
 23.1940 +{
 23.1941 +}
 23.1942 +
 23.1943 +bool
 23.1944 +SemanticAnalysis::analyze()
 23.1945 +{
 23.1946 +    assert(false);
 23.1947 +    return false;
 23.1948 +}
 23.1949 +
 23.1950 +
 23.1951 +#if 0
 23.1952 +
 23.1953 +static inline bool
 23.1954 +IsPrimitiveType(Type *type, PrimitiveType primitive)
 23.1955 +{
 23.1956 +    if (!type)
 23.1957 +        return false;
 23.1958 +
 23.1959 +    if (!type->isPrimitive())
 23.1960 +        return false;
 23.1961 +
 23.1962 +    return primitive == type->primitive();
 23.1963 +}
 23.1964 +
 23.1965 +static inline bool
 23.1966 +EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
 23.1967 +                        BoxedPrimitive *out)
 23.1968 +{
 23.1969 +    switch (kind) {
 23.1970 +      case TOK_PLUS:
 23.1971 +        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
 23.1972 +        return true;
 23.1973 +
 23.1974 +      case TOK_SHL:
 23.1975 +        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
 23.1976 +        return true;
 23.1977 +
 23.1978 +      default:
 23.1979 +        return false;
 23.1980 +    }
 23.1981 +}
 23.1982 +
 23.1983 +static inline bool
 23.1984 +EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
 23.1985 +{
 23.1986 +  switch (kind) {
 23.1987 +    case TOK_MINUS:
 23.1988 +      *out = BoxedPrimitive::Int(-inner.toInt());
 23.1989 +      return true;
 23.1990 +
 23.1991 +    default:
 23.1992 +      return false;
 23.1993 +  }
 23.1994 +}
 23.1995 +
 23.1996 +static bool
 23.1997 +EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
 23.1998 +{
 23.1999 +    switch (expression->kind()) {
 23.2000 +      case AstNode::kBinaryExpression:
 23.2001 +      {
 23.2002 +        BoxedPrimitive left;
 23.2003 +        BoxedPrimitive right;
 23.2004 +        BinaryExpression *b = expression->toBinaryExpression();
 23.2005 +        if (!EvaluateForConstant(b->left(), &left) ||
 23.2006 +            !EvaluateForConstant(b->right(), &right))
 23.2007 +        {
 23.2008 +            return false;
 23.2009 +        }
 23.2010 +        return EvaluateBinaryOperation(b->token(), left, right, out);
 23.2011 +      }
 23.2012 +
 23.2013 +      case AstNode::kUnaryExpression:
 23.2014 +      {
 23.2015 +        BoxedPrimitive inner;
 23.2016 +        UnaryExpression *u = expression->toUnaryExpression();
 23.2017 +        if (!EvaluateForConstant(u->expression(), &inner))
 23.2018 +            return false;
 23.2019 +        return EvaluateUnaryOperation(u->token(), inner, out);
 23.2020 +      }
 23.2021 +
 23.2022 +      case AstNode::kNameProxy:
 23.2023 +      {
 23.2024 +        NameProxy *proxy = expression->toNameProxy();
 23.2025 +        if (proxy->binding()->kind() != BoundName::CONSTANT)
 23.2026 +            return false;
 23.2027 +
 23.2028 +        NamedConstant *c = proxy->binding()->toNamedConstant();
 23.2029 +        if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
 23.2030 +            return false;
 23.2031 +
 23.2032 +        *out = c->value();
 23.2033 +        return true;
 23.2034 +      }
 23.2035 +
 23.2036 +      case AstNode::kBooleanLiteral:
 23.2037 +        *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
 23.2038 +        return true;
 23.2039 +
 23.2040 +      case AstNode::kIntegerLiteral:
 23.2041 +        *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
 23.2042 +        return true;
 23.2043 +
 23.2044 +      default:
 23.2045 +        return false;
 23.2046 +    }
 23.2047 +}
 23.2048 +
 23.2049 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
 23.2050 +  : zone_(zone),
 23.2051 +    cc_(cc),
 23.2052 +    tree_(tree),
 23.2053 +    scope_(NULL),
 23.2054 +    loop_(NULL)
 23.2055 +{
 23.2056 +}
 23.2057 +
 23.2058 +bool
 23.2059 +SemanticAnalysis::analyze()
 23.2060 +{
 23.2061 +    if (cc_.failures())
 23.2062 +        return false;
 23.2063 +
 23.2064 +    scope_ = tree_->globalScope();
 23.2065 +    assert(scope_->kind() == Scope::GLOBAL);
 23.2066 +
 23.2067 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
 23.2068 +        Statement *statement = tree_->statements()->at(i);
 23.2069 +        if (statement->isFunctionStatement()) {
 23.2070 +            FunctionStatement *funstmt = statement->toFunctionStatement();
 23.2071 +            if (!preanalyze(funstmt))
 23.2072 +                return false;
 23.2073 +        } else if (statement->isEnumStatement()) {
 23.2074 +            EnumStatement *enumstmt = statement->toEnumStatement();
 23.2075 +
 23.2076 +            // We pre-fill global enum types, since they may occur in function
 23.2077 +            // signatures. This should probably be somewhere else...
 23.2078 +            enumstmt->accept(this);
 23.2079 +        } else if (statement->isStructureStatement()) {
 23.2080 +            StructureStatement *node = statement->toStructureStatement();
 23.2081 +            node->accept(this);
 23.2082 +            if (!node->decl()->type())
 23.2083 +                return false;
 23.2084 +        } else if (statement->isFunctionTypeStatement()) {
 23.2085 +            FunctionTypeStatement *node = statement->toFunctionTypeStatement();
 23.2086 +            node->accept(this);
 23.2087 +            if (!node->decl()->type())
 23.2088 +                return false;
 23.2089 +        }
 23.2090 +    }
 23.2091 +
 23.2092 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
 23.2093 +        Statement *statement = tree_->statements()->at(i);
 23.2094 +
 23.2095 +        // We can't double-process these. Maybe put this check somewhere else.
 23.2096 +        if (statement->isEnumStatement())
 23.2097 +            continue;
 23.2098 +
 23.2099 +        statement->accept(this);
 23.2100 +    }
 23.2101 +
 23.2102 +    if (!determineLiveFunctions())
 23.2103 +        return false;
 23.2104 +
 23.2105 +    return !cc_.failures();
 23.2106 +}
 23.2107 +
 23.2108 +bool
 23.2109 +SemanticAnalysis::determineLiveFunctions()
 23.2110 +{
 23.2111 +    Vector<NamedFunction *> worklist;
 23.2112 +
 23.2113 +    // Add the root set.
 23.2114 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
 23.2115 +        Statement *statement = tree_->statements()->at(i);
 23.2116 +        if (!statement->isFunctionStatement())
 23.2117 +            continue;
 23.2118 +
 23.2119 +        FunctionStatement *stmt = statement->toFunctionStatement();
 23.2120 +        NamedFunction  *fun = stmt->fun();
 23.2121 +        if (!fun->used())
 23.2122 +            continue;
 23.2123 +
 23.2124 +        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
 23.2125 +            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
 23.2126 +
 23.2127 +            // Names in these lists are always unused, however, we mark them
 23.2128 +            // as used while inserting into the work queue, to avoid double-
 23.2129 +            // insertion.
 23.2130 +            if (name->used())
 23.2131 +                continue;
 23.2132 +
 23.2133 +            if (!worklist.append(name))
 23.2134 +                return false;
 23.2135 +
 23.2136 +            name->setUsed();
 23.2137 +        }
 23.2138 +    }
 23.2139 +
 23.2140 +    while (!worklist.empty()) {
 23.2141 +        NamedFunction *fun = worklist.popCopy();
 23.2142 +
 23.2143 +        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
 23.2144 +            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
 23.2145 +            if (name->used())
 23.2146 +                continue;
 23.2147 +            if (!worklist.append(name))
 23.2148 +                return false;
 23.2149 +            name->setUsed();
 23.2150 +        }
 23.2151 +    }
 23.2152 +
 23.2153 +    return true;
 23.2154 +}
 23.2155 +
 23.2156 +Type *
 23.2157 +SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
 23.2158 +{
 23.2159 +    if (!name)
 23.2160 +        return zone_->types()->getPrimitive(PrimitiveType_Int32);
 23.2161 +
 23.2162 +    if (name->kind() == BoundName::UNBOUND) {
 23.2163 +        cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
 23.2164 +        return NULL;
 23.2165 +    }
 23.2166 +
 23.2167 +    if (name->kind() != BoundName::TYPE) {
 23.2168 +        cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
 23.2169 +        return NULL;
 23.2170 +    }
 23.2171 +
 23.2172 +    if (!name->type())
 23.2173 +        return NULL;
 23.2174 +
 23.2175 +    return name->type();
 23.2176 +}
 23.2177 +
 23.2178 +Type *
 23.2179 +SemanticAnalysis::visitAndApplyType(Expression *expression)
 23.2180 +{
 23.2181 +    expression->accept(this);
 23.2182 +    return expression->type();
 23.2183 +}
 23.2184 +
 23.2185 +Type *
 23.2186 +SemanticAnalysis::visitForLoad(Expression *expression)
 23.2187 +{
 23.2188 +    Local<Type> type(zone_, visitAndApplyType(expression));
 23.2189 +    if (!type)
 23.2190 +        return NULL;
 23.2191 +
 23.2192 +    if (type->isReference()) {
 23.2193 +        expression->setType(type->contained());
 23.2194 +    } else if (expression->isCallExpression()) {
 23.2195 +        if (type->isVoid()) {
 23.2196 +            CallExpression *call = expression->toCallExpression();
 23.2197 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
 23.2198 +            return NULL;
 23.2199 +        }
 23.2200 +    }
 23.2201 +
 23.2202 +    return expression->type();
 23.2203 +}
 23.2204 +
 23.2205 +void
 23.2206 +SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
 23.2207 +{
 23.2208 +    const char *op = TokenNames[token];
 23.2209 +    const char *name = GetTypeName(type);
 23.2210 +
 23.2211 +    cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
 23.2212 +}
 23.2213 +
 23.2214 +void
 23.2215 +SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
 23.2216 +{
 23.2217 +    const char *op = TokenNames[token];
 23.2218 +    const char *leftName = GetTypeName(left);
 23.2219 +    const char *rightName = GetTypeName(right);
 23.2220 +
 23.2221 +    cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
 23.2222 +}
 23.2223 +
 23.2224 +Type *
 23.2225 +SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
 23.2226 +{
 23.2227 +    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
 23.2228 +        (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
 23.2229 +    {
 23.2230 +        // If either side is a float, the other side must be a float or int.
 23.2231 +        if (left->isFloat() || right->isFloat()) {
 23.2232 +            Type *floatType = left->isFloat() ? left : right;
 23.2233 +            Type *other = left->isFloat() ? right : left;
 23.2234 +            if (other->isFloat() || other->isInt32())
 23.2235 +                return floatType;
 23.2236 +        }
 23.2237 +    }
 23.2238 +
 23.2239 +    if (token == TOK_OR || token == TOK_AND) {
 23.2240 +        if (!canTest(node, left) || !canTest(node, right))
 23.2241 +            return NULL;
 23.2242 +        return zone_->types()->getPrimitive(PrimitiveType_Bool);
 23.2243 +    }
 23.2244 +
 23.2245 +    if (token >= TOK_EQUALS && token <= TOK_GE) {
 23.2246 +        if ((left->isFloat() || left->isInt32()) &&
 23.2247 +            (right->isFloat() || right->isInt32()))
 23.2248 +        {
 23.2249 +            return zone_->types()->getPrimitive(PrimitiveType_Bool);
 23.2250 +        }
 23.2251 +        binaryTypeError(node, token, left, right);
 23.2252 +        return NULL;
 23.2253 +    }
 23.2254 +
 23.2255 +    if (!left->isInt32() || !right->isInt32()) {
 23.2256 +        binaryTypeError(node, token, left, right);
 23.2257 +        return NULL;
 23.2258 +    }
 23.2259 +
 23.2260 +    return left;
 23.2261 +}
 23.2262 +
 23.2263 +bool
 23.2264 +SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
 23.2265 +{
 23.2266 +    if (!type->isPrimitive() && !type->isEnum()) {
 23.2267 +        cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
 23.2268 +        return false;
 23.2269 +    }
 23.2270 +    return true;
 23.2271 +}
 23.2272 +
 23.2273 +Type *
 23.2274 +SemanticAnalysis::visitForLValue(Expression *expression)
 23.2275 +{
 23.2276 +    if (expression->isIndexExpression()) {
 23.2277 +        Type *type = visitAndApplyType(expression);
 23.2278 +        if (!type)
 23.2279 +            return NULL;
 23.2280 +
 23.2281 +        // if (type->isConst()) {
 23.2282 +        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
 23.2283 +        //     return NULL;
 23.2284 +        // }
 23.2285 +
 23.2286 +        return type;
 23.2287 +    }
 23.2288 +
 23.2289 +    if (expression->isFieldExpression()) {
 23.2290 +        Type *type = visitAndApplyType(expression);
 23.2291 +        if (!type)
 23.2292 +            return NULL;
 23.2293 +
 23.2294 +        // if (expression->toFieldExpression()->left()->type()->isConst()) {
 23.2295 +        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
 23.2296 +        //     return NULL;
 23.2297 +        // }
 23.2298 +
 23.2299 +        return type;
 23.2300 +    }
 23.2301 +
 23.2302 +    if (!expression->isNameProxy()) {
 23.2303 +        cc_.reportError(expression->pos(), Message_ExpectedLValue);
 23.2304 +        return NULL;
 23.2305 +    }
 23.2306 +
 23.2307 +    NameProxy *proxy = expression->toNameProxy();
 23.2308 +    if (!proxy->binding()->kind() == BoundName::VARIABLE) {
 23.2309 +        cc_.reportError(expression->pos(), Message_ExpectedLValue);
 23.2310 +        return NULL;
 23.2311 +    }
 23.2312 +
 23.2313 +    Variable *var = proxy->binding()->toVariable();
 23.2314 +    if (!var->type())
 23.2315 +        return NULL;
 23.2316 +
 23.2317 +    if  (var->type()->isReference()) {
 23.2318 +        if (var->type()->isConst()) {
 23.2319 +            cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
 23.2320 +            return NULL;
 23.2321 +        }
 23.2322 +        return var->type()->contained();
 23.2323 +    }
 23.2324 +    return var->type();
 23.2325 +}
 23.2326 +
 23.2327 +SemanticAnalysis::ControlStatus
 23.2328 +SemanticAnalysis::visitForControl(Statement *statement)
 23.2329 +{
 23.2330 +    ControlScope scope(&control_);
 23.2331 +    statement->accept(this);
 23.2332 +    return scope.status();
 23.2333 +}
 23.2334 +
 23.2335 +void
 23.2336 +SemanticAnalysis::visit(NameProxy *name)
 23.2337 +{
 23.2338 +    BoundName *binding = name->binding();
 23.2339 +
 23.2340 +    if (binding->scope()->kind() == Scope::GLOBAL) {
 23.2341 +        if (!function_ || function_->isPublic()) {
 23.2342 +            // Whatever we're referencing must be kept alive no matter what.
 23.2343 +            // As such, we simply mark it used, and don't do anything special.
 23.2344 +            binding->setUsed();
 23.2345 +        } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
 23.2346 +            // Otherwise, we're inside a normal stock or function. Since we
 23.2347 +            // don't really know if we've been used yet, we shouldn't
 23.2348 +            // prematurely references as alive. Instead, we keep a list of
 23.2349 +            // which names have been used, so we can mark them later if needed.
 23.2350 +            //
 23.2351 +            // Note that we skip this step if the binding is already in the
 23.2352 +            // root set.
 23.2353 +            if (!function_->addUsedGlobal(binding))
 23.2354 +                return;
 23.2355 +        }
 23.2356 +    }
 23.2357 +
 23.2358 +    name->setType(binding->type());
 23.2359 +}
 23.2360 +
 23.2361 +void
 23.2362 +SemanticAnalysis::visit(Assignment *node)
 23.2363 +{
 23.2364 +    Local<Type> exprType(zone_, visitForLoad(node->expression()));
 23.2365 +    if (!exprType)
 23.2366 +        return ;
 23.2367 +
 23.2368 +    Local<Type> type(zone_, visitForLValue(node->lvalue()));
 23.2369 +    if (!type)
 23.2370 +        return;
 23.2371 +
 23.2372 +    if (node->token() != TOK_ASSIGN) {
 23.2373 +        if (!typeCheckBinary(node, node->token(), type, exprType))
 23.2374 +            return;
 23.2375 +    }
 23.2376 +
 23.2377 +    if (!typeCheckAssignment(node->pos(), exprType, type, true))
 23.2378 +        return;
 23.2379 +
 23.2380 +    node->setType(type);
 23.2381 +}
 23.2382 +
 23.2383 +void
 23.2384 +SemanticAnalysis::visit(IncDecExpression *node)
 23.2385 +{
 23.2386 +    Local<Type> type(zone_, visitForLValue(node->expression()));
 23.2387 +    if (!type)
 23.2388 +        return;
 23.2389 +
 23.2390 +    assert(!type->isReference());
 23.2391 +
 23.2392 +    if (!type->isInt32() && !type->isFloat()) {
 23.2393 +        unaryTypeError(node, node->token(), type);
 23.2394 +        return;
 23.2395 +    }
 23.2396 +
 23.2397 +    node->setType(type);
 23.2398 +}
 23.2399 +
 23.2400 +void
 23.2401 +SemanticAnalysis::visit(UnaryExpression *node)
 23.2402 +{
 23.2403 +    Local<Type> type(zone_, visitForLoad(node->expression()));
 23.2404 +    if (!type)
 23.2405 +        return;
 23.2406 +
 23.2407 +    switch (node->token())
 23.2408 +    {
 23.2409 +      case TOK_NOT:
 23.2410 +        if (!canTest(node->expression(), type))
 23.2411 +            return;
 23.2412 +        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
 23.2413 +        if (!type)
 23.2414 +            return;
 23.2415 +        node->setType(type);
 23.2416 +        break;
 23.2417 +
 23.2418 +      case TOK_MINUS:
 23.2419 +        if (!type->isFloat() && !type->isInt32()) {
 23.2420 +            unaryTypeError(node, node->token(), type);
 23.2421 +            return;
 23.2422 +        }
 23.2423 +        node->setType(type);
 23.2424 +        break;
 23.2425 +
 23.2426 +      case TOK_LABEL:
 23.2427 +      {
 23.2428 +        Local<Type> to(zone_, bindType(node->pos(), node->type()));
 23.2429 +        if (!to)
 23.2430 +            return;
 23.2431 +
 23.2432 +        if ((!type->isFloat() && !type->isInt32OrEnum()) ||
 23.2433 +            (!to->isFloat() && !to->isInt32OrEnum()))
 23.2434 +        {
 23.2435 +            unaryTypeError(node, node->token(), type);
 23.2436 +            return;
 23.2437 +        }
 23.2438 +
 23.2439 +        node->setType(to);
 23.2440 +        break;
 23.2441 +      }
 23.2442 +
 23.2443 +      case TOK_SIZEOF:
 23.2444 +      {
 23.2445 +        if (!type->isArray()) {
 23.2446 +            cc_.reportError(node->pos(), Message_SizeofNeedsArray);
 23.2447 +            return;
 23.2448 +        }
 23.2449 +        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
 23.2450 +        break;
 23.2451 +      }
 23.2452 +
 23.2453 +      default:
 23.2454 +        assert(node->token() == TOK_TILDE);
 23.2455 +        if (!type->isInt32()) {
 23.2456 +            unaryTypeError(node, node->token(), type);
 23.2457 +            return;
 23.2458 +        }
 23.2459 +        node->setType(type);
 23.2460 +        break;
 23.2461 +    }
 23.2462 +}
 23.2463 +
 23.2464 +void
 23.2465 +SemanticAnalysis::visit(TernaryExpression *node)
 23.2466 +{
 23.2467 +    Local<Type> type(zone_, visitForLoad(node->condition()));
 23.2468 +    if (!type)
 23.2469 +        return;
 23.2470 +
 23.2471 +    if (!canTest(node->condition(), type))
 23.2472 +        return;
 23.2473 +
 23.2474 +    Local<Type> left(zone_, visitForLoad(node->left()));
 23.2475 +    Local<Type> right(zone_, visitForLoad(node->right()));
 23.2476 +    if (!left || !right)
 23.2477 +        return;
 23.2478 +
 23.2479 +    if (left != right) {
 23.2480 +        binaryTypeError(node, TOK_QMARK, left, right);
 23.2481 +        return;
 23.2482 +    }
 23.2483 +}
 23.2484 +
 23.2485 +void
 23.2486 +SemanticAnalysis::visit(BinaryExpression *node)
 23.2487 +{
 23.2488 +    Local<Type> left(zone_, visitForLoad(node->left()));
 23.2489 +    Local<Type> right(zone_, visitForLoad(node->right()));
 23.2490 +    if (!left || !right)
 23.2491 +        return;
 23.2492 +
 23.2493 +    Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
 23.2494 +    if (!result)
 23.2495 +        return;
 23.2496 +
 23.2497 +    node->setType(result);
 23.2498 +}
 23.2499 +
 23.2500 +void
 23.2501 +SemanticAnalysis::visit(ReturnStatement *node)
 23.2502 +{
 23.2503 +    // Set this early, so if we error we don't get more errors.
 23.2504 +    control_->returns(Returns_Always);
 23.2505 +
 23.2506 +    if (!node->expression()) {
 23.2507 +        if (!function_->type()->returnType()->isVoid())
 23.2508 +            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
 23.2509 +        return;
 23.2510 +    }
 23.2511 +
 23.2512 +    Local<Type> type(zone_, visitForLoad(node->expression()));
 23.2513 +    if (!type)
 23.2514 +        return;
 23.2515 +
 23.2516 +    Local<Type> returnType(zone_, function_->type()->returnType());
 23.2517 +    if (!typeCheckAssignment(node->pos(), type, returnType, true))
 23.2518 +        return;
 23.2519 +}
 23.2520 +
 23.2521 +void
 23.2522 +SemanticAnalysis::visit(ForStatement *node)
 23.2523 +{
 23.2524 +    LoopScope loop(&loop_);
 23.2525 +
 23.2526 +    if (node->scope())
 23.2527 +        scope_ = node->scope();
 23.2528 +
 23.2529 +    if (node->initialization())
 23.2530 +        node->initialization()->accept(this);
 23.2531 +
 23.2532 +    if (node->condition()) {
 23.2533 +        Local<Type> type(zone_, visitForLoad(node->condition()));
 23.2534 +        if (!type || !canTest(node->condition(), type)) {
 23.2535 +            return;
 23.2536 +        }
 23.2537 +    }
 23.2538 +
 23.2539 +    if (node->update())
 23.2540 +        node->update()->accept(this);
 23.2541 +
 23.2542 +    ControlStatus status = visitForControl(node->body());
 23.2543 +
 23.2544 +    // If there is a condition, we treat this like a while loop. Otherwise,
 23.2545 +    // join point is only reachable if the loop contains a break. The
 23.2546 +    // termination status doesn't tell us anything yet.
 23.2547 +    if (node->condition() || loop.breaks())
 23.2548 +        control_->merge(status, ControlStatus(false, Returns_Never));
 23.2549 +    else
 23.2550 +        control_->terminate(status.returns());
 23.2551 +
 23.2552 +    if (node->scope())
 23.2553 +        scope_ = scope_->enclosing();
 23.2554 +}
 23.2555 +
 23.2556 +void 
 23.2557 +SemanticAnalysis::visit(WhileStatement *node)
 23.2558 +{
 23.2559 +    LoopScope loop(&loop_);
 23.2560 +
 23.2561 +    Local<Type> type(zone_, visitForLoad(node->condition()));
 23.2562 +    if (!type || !canTest(node->condition(), type)) {
 23.2563 +        return;
 23.2564 +    }
 23.2565 +
 23.2566 +    ControlStatus status = visitForControl(node->body());
 23.2567 +
 23.2568 +    // Detect loops that will always have a fork in the control-flow graph.
 23.2569 +    // This will be a |while| loop, or a |do-while| loop whose body does
 23.2570 +    // not terminate.
 23.2571 +    //
 23.2572 +    // For now, we treat these as an |if| regardless of the direction the
 23.2573 +    // branch can take. That means the control-flow is always conditional.
 23.2574 +    if (node->token() == TOK_WHILE ||
 23.2575 +        !status.terminates() ||
 23.2576 +        loop.breaks())
 23.2577 +    {
 23.2578 +        control_->merge(status, ControlStatus(false, Returns_Never));
 23.2579 +    } else {
 23.2580 +        // At this point, we've got a do-while loop with a |return| or
 23.2581 +        // |continue|, meaning that the rest of the block is unreachable.
 23.2582 +        control_->terminate(status.returns());
 23.2583 +    }
 23.2584 +}
 23.2585 +
 23.2586 +void
 23.2587 +SemanticAnalysis::visit(BlockStatement *node)
 23.2588 +{
 23.2589 +    if (node->scope())
 23.2590 +        scope_ = node->scope();
 23.2591 +    for (size_t i = 0; i < node->statements()->length(); i++) {
 23.2592 +        Statement *statement = node->statements()->at(i);
 23.2593 +        statement->accept(this);
 23.2594 +    }
 23.2595 +    if (node->scope())
 23.2596 +        scope_ = scope_->enclosing();
 23.2597 +}
 23.2598 +
 23.2599 +static inline bool
 23.2600 +IsScalarString(Type *type)
 23.2601 +{
 23.2602 +    if (type->isPrimitive() && type->primitive() == PrimitiveType_Char)
 23.2603 +        return true;
 23.2604 +    if (type->isReference())
 23.2605 +        return IsScalarString(type->contained());
 23.2606 +    return false;
 23.2607 +}
 23.2608 +
 23.2609 +static const int INFER_ARRAY_SIZE = 0;
 23.2610 +static const int EVAL_ARRAY_SIZE = -1;
 23.2611 +static const int DYNAMIC_ARRAY_SIZE = -2;
 23.2612 +
 23.2613 +bool
 23.2614 +SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
 23.2615 +{
 23.2616 +    bool hadEmptySize = false;
 23.2617 +
 23.2618 +    for (size_t i = 0; i < exprs->length(); i++) {
 23.2619 +        Expression *expr = exprs->at(i);
 23.2620 +        if (!expr) {
 23.2621 +            dims[i] = INFER_ARRAY_SIZE;
 23.2622 +            hadEmptySize = true;
 23.2623 +            continue;
 23.2624 +        }
 23.2625 +
 23.2626 +        BoxedPrimitive box;
 23.2627 +        if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
 23.2628 +            int size = box.toInt();
 23.2629 +            if (size <= 0) {
 23.2630 +                cc_.reportError(expr->pos(), Message_BadArraySize);
 23.2631 +                return false;
 23.2632 +            }
 23.2633 +
 23.2634 +            dims[i] = size;
 23.2635 +            continue;
 23.2636 +        }
 23.2637 +
 23.2638 +        Local<Type> exprType(zone_, visitForLoad(expr));
 23.2639 +        if (!exprType)
 23.2640 +            return false;
 23.2641 +
 23.2642 +        if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
 23.2643 +            cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
 23.2644 +            return false;
 23.2645 +        }
 23.2646 +
 23.2647 +        if (hadEmptySize) {
 23.2648 +            cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
 23.2649 +            return false;
 23.2650 +        }
 23.2651 +
 23.2652 +        dims[i] = EVAL_ARRAY_SIZE;
 23.2653 +    }
 23.2654 +
 23.2655 +    return true;
 23.2656 +}
 23.2657 +
 23.2658 +bool
 23.2659 +SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
 23.2660 +                                         int dims[MAX_ARRAY_DEPTH],
 23.2661 +                                         unsigned dimcount, unsigned level)
 23.2662 +{
 23.2663 +    if (dims[level] == EVAL_ARRAY_SIZE) {
 23.2664 +        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
 23.2665 +        return false;
 23.2666 +    }
 23.2667 +
 23.2668 +    if (dims[level] == INFER_ARRAY_SIZE) {
 23.2669 +        // Strings always become dynamic arrays.
 23.2670 +        if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
 23.2671 +            dims[level] = literal->expressions()->length();
 23.2672 +    } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
 23.2673 +        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
 23.2674 +        return false;
 23.2675 +    } else {
 23.2676 +        if (literal->expressions()->length() != unsigned(dims[level])) {
 23.2677 +            cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
 23.2678 +            return false;
 23.2679 +        }
 23.2680 +    }
 23.2681 +
 23.2682 +    if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
 23.2683 +        for (size_t i = 0; i < literal->expressions()->length(); i++) {
 23.2684 +            Expression *expr = literal->expressions()->at(i);
 23.2685 +            if (!expr->isStringLiteral()) {
 23.2686 +                cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
 23.2687 +                return false;
 23.2688 +            }
 23.2689 +
 23.2690 +            StringLiteral *lit = expr->toStringLiteral();
 23.2691 +            if (dims[level + 1] > 0 &&
 23.2692 +                unsigned(dims[level]) < lit->string()->length())
 23.2693 +            {
 23.2694 +                cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
 23.2695 +                return false;
 23.2696 +            }
 23.2697 +            if (!visitAndApplyType(lit))
 23.2698 +                return false;
 23.2699 +        }
 23.2700 +    } else if (level == dimcount - 1) {
 23.2701 +        Local<Type> type(zone_);
 23.2702 +        for (size_t i = 0; i < literal->expressions()->length(); i++) {
 23.2703 +            Expression *expr = literal->expressions()->at(i);
 23.2704 +            if (expr->isArrayLiteral()) {
 23.2705 +                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
 23.2706 +                return false;
 23.2707 +            }
 23.2708 +
 23.2709 +            if ((type = visitAndApplyType(expr)) == NULL)
 23.2710 +                return false;
 23.2711 +
 23.2712 +            if (!typeCheckAssignment(expr->pos(), type, contained, true))
 23.2713 +                return false;
 23.2714 +        }
 23.2715 +    } else {
 23.2716 +        for (size_t i = 0; i < literal->expressions()->length(); i++) {
 23.2717 +            Expression *expr = literal->expressions()->at(i);
 23.2718 +            if (!expr->isArrayLiteral()) {
 23.2719 +                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
 23.2720 +                return false;
 23.2721 +            }
 23.2722 +
 23.2723 +            assert(expr->toArrayLiteral()->isFixed());
 23.2724 +
 23.2725 +            if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
 23.2726 +                                        contained,
 23.2727 +                                        dims,
 23.2728 +                                        dimcount,
 23.2729 +                                        level + 1))
 23.2730 +            {
 23.2731 +                return false;
 23.2732 +            }
 23.2733 +        }
 23.2734 +    }
 23.2735 +
 23.2736 +    return true;
 23.2737 +}
 23.2738 +
 23.2739 +void
 23.2740 +SemanticAnalysis::visit(VariableDeclaration *node)
 23.2741 +{
 23.2742 +    Local<Type> type(zone_, bindType(node->pos(), node->type()));
 23.2743 +    if (!type)
 23.2744 +        return;
 23.2745 +
 23.2746 +#if 0
 23.2747 +    if (node->postDimensions() || type->isArray()) {
 23.2748 +        // The type could be an array type, so sum the type and postDimensions
 23.2749 +        // together.
 23.2750 +        unsigned dimcount = node->postDimensions()->length();
 23.2751 +        if (type->isArray())
 23.2752 +            dimcount += type->levels();
 23.2753 +        if (dimcount > MAX_ARRAY_DEPTH) {
 23.2754 +            cc_.reportError(node->pos(), Message_MaximumArrayDepth);
 23.2755 +            return;
 23.2756 +        }
 23.2757 +
 23.2758 +        // Take an initial guess at the array dimension sizes.
 23.2759 +        int dims[MAX_ARRAY_DEPTH];
 23.2760 +        if (!evaluateDimensions(node->postDimensions(), dims))
 23.2761 +            return;
 23.2762 +
 23.2763 +        // Now add in the type's array dimensions.
 23.2764 +        Local<Type> contained(zone_, type);
 23.2765 +        for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
 23.2766 +            if (type->isFixedLength())
 23.2767 +                dims[i] = type->fixedLength();
 23.2768 +            else
 23.2769 +                dims[i] = DYNAMIC_ARRAY_SIZE;
 23.2770 +            contained = contained->contained();
 23.2771 +        }
 23.2772 +
 23.2773 +        Expression *initializer = node->initialization();
 23.2774 +        if (initializer &&
 23.2775 +            initializer->isArrayLiteral() &&
 23.2776 +            initializer->toArrayLiteral()->isFixed())
 23.2777 +        {
 23.2778 +            // Fixed array initializers are special; we use them to infer any
 23.2779 +            // missing information in the original array. We do not evaluate
 23.2780 +            // the array initializer as an expression.
 23.2781 +            if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
 23.2782 +                                        contained,
 23.2783 +                                        dims,
 23.2784 +                                        dimcount,
 23.2785 +                                        0))
 23.2786 +            {
 23.2787 +                return;
 23.2788 +            }
 23.2789 +            initializer = NULL;
 23.2790 +        }
 23.2791 +
 23.2792 +        // We now have enough information to build the actual array type.
 23.2793 +        // Start from the original dimcount, not the one computed for
 23.2794 +        // initializers.
 23.2795 +        for (size_t i = node->postDimensions()->length() - 1;
 23.2796 +             i < node->postDimensions()->length();
 23.2797 +             i--)
 23.2798 +        {
 23.2799 +            int size = dims[i] > 0
 23.2800 +                       ? dims[i]
 23.2801 +                       : Type::DYNAMIC_ARRAY_SIZE;
 23.2802 +
 23.2803 +            type = zone_->types()->newArray(type, size, false);
 23.2804 +            if (!type)
 23.2805 +                return;
 23.2806 +        }
 23.2807 +
 23.2808 +        // Finally, if we had a non-fixed initializer, make sure it type
 23.2809 +        // checks. 
 23.2810 +        if (initializer) {
 23.2811 +            Local<Type> right(zone_, visitForLoad(initializer));
 23.2812 +            if (!right)
 23.2813 +                return;
 23.2814 +
 23.2815 +            if (!typeCheckAssignment(node->pos(), right, type, true))
 23.2816 +                return;
 23.2817 +        }
 23.2818 +    } else {
 23.2819 +        if (node->initialization()) {
 23.2820 +            Local<Type> right(zone_, visitForLoad(node->initialization()));
 23.2821 +            if (!right)
 23.2822 +                return;
 23.2823 +            if (!typeCheckAssignment(node->pos(), right, type, true))
 23.2824 +                return;
 23.2825 +        }
 23.2826 +
 23.2827 +        if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) {
 23.2828 +            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
 23.2829 +            return;
 23.2830 +        }
 23.2831 +    }
 23.2832 +#endif
 23.2833 +
 23.2834 +#if 0
 23.2835 +    // If this variable is stack allocated, we could use the LIFO heap
 23.2836 +    // to allocate it. If that's the case, make sure to reserve a slot
 23.2837 +    // so we can unwind the LIFO heap at the end of this scope.
 23.2838 +    if (!node->variable()->needsHeapAllocation()) {
 23.2839 +        if (type->isArray() || type->isStruct())
 23.2840 +            scope_->setUsesLifoHeap();
 23.2841 +    }
 23.2842 +
 23.2843 +    node->variable()->setType(type);
 23.2844 +#endif
 23.2845 +}
 23.2846 +
 23.2847 +void
 23.2848 +SemanticAnalysis::visit(IntegerLiteral *node)
 23.2849 +{
 23.2850 +    node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
 23.2851 +}
 23.2852 +
 23.2853 +void
 23.2854 +SemanticAnalysis::visit(BooleanLiteral *node)
 23.2855 +{
 23.2856 +    node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool));
 23.2857 +}
 23.2858 +
 23.2859 +void
 23.2860 +SemanticAnalysis::visit(ExpressionStatement *node)
 23.2861 +{
 23.2862 +    visitAndApplyType(node->expression());
 23.2863 +}
 23.2864 +
 23.2865 +Box *
 23.2866 +SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
 23.2867 +{
 23.2868 +    Local<Type> given(zone_, visitForLoad(parameter->initializer()));
 23.2869 +
 23.2870 +    BoxedPrimitive prim;
 23.2871 +    if (EvaluateForConstant(parameter->initializer(), &prim)) {
 23.2872 +        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
 23.2873 +            return NULL;
 23.2874 +
 23.2875 +        if (prim.type() == PrimitiveType_Int32)
 23.2876 +            return Box::New(zone_, given, prim.toInt());
 23.2877 +        return Box::New(zone_, given, prim.toFloat());
 23.2878 +    } else if (parameter->initializer()->isStringLiteral()) {
 23.2879 +        StringLiteral *literal = parameter->initializer()->toStringLiteral();
 23.2880 +
 23.2881 +        if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
 23.2882 +            return NULL;
 23.2883 +
 23.2884 +        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, given));
 23.2885 +        if (!map)
 23.2886 +            return NULL;
 23.2887 +
 23.2888 +        Local<Array> array(zone_,
 23.2889 +            Array::NewString(zone_,
 23.2890 +                             map,
 23.2891 +                             literal->string()->raw(),
 23.2892 +                             literal->string()->length(),
 23.2893 +                             Heap::Tenure_Old));
 23.2894 +        if (!array)
 23.2895 +            return NULL;
 23.2896 +
 23.2897 +        return Box::NewObj(zone_, given, array, Heap::Tenure_Old);
 23.2898 +    }
 23.2899 +
 23.2900 +    cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant);
 23.2901 +    return NULL;
 23.2902 +}
 23.2903 +
 23.2904 +bool
 23.2905 +SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
 23.2906 +                                    FixedArray **argsp, FixedArray **defaultsp)
 23.2907 +{
 23.2908 +    Local<FixedArray> args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
 23.2909 +    if (!args)
 23.2910 +        return false;
 23.2911 +
 23.2912 +    Local<FixedArray> defaults(zone_);
 23.2913 +
 23.2914 +    // Apply types to arguments.
 23.2915 +    for (size_t i = 0; i < sig.parameters()->length(); i++) {
 23.2916 +        Parameter *parameter = sig.parameters()->at(i);
 23.2917 +        
 23.2918 +#if 0
 23.2919 +        Local<Type> type(zone_, bindType(parameter->variable()->pos(), parameter->type()));
 23.2920 +        if (!type)
 23.2921 +            return false;
 23.2922 +
 23.2923 +        if (parameter->reference()) {
 23.2924 +            if (parameter->dimensions()) {
 23.2925 +                cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
 23.2926 +                return false;
 23.2927 +            }
 23.2928 +
 23.2929 +            if (type->isStruct()) {
 23.2930 +                cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference);
 23.2931 +                return false;
 23.2932 +            }
 23.2933 +
 23.2934 +            type = zone_->types()->getReference(type, parameter->isConst());
 23.2935 +            if (!type)
 23.2936 +                return false;
 23.2937 +        } else if (parameter->dimensions()) {
 23.2938 +            type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
 23.2939 +            if (!type)
 23.2940 +                return false;
 23.2941 +
 23.2942 +            if (kind == TOK_NATIVE && type->levels() > 1) {
 23.2943 +                cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
 23.2944 +                return false;
 23.2945 +            }
 23.2946 +        }
 23.2947 +
 23.2948 +        if (IsScalarString(type)) {
 23.2949 +            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
 23.2950 +            return false;
 23.2951 +        }
 23.2952 +
 23.2953 +        args->set(zone_, i, type);
 23.2954 +        parameter->variable()->setType(type);
 23.2955 +
 23.2956 +        if (parameter->initializer()) {
 23.2957 +            if (!defaults) {
 23.2958 +                defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old);
 23.2959 +                if (!defaults)
 23.2960 +                    return false;
 23.2961 +            }
 23.2962 +
 23.2963 +            Local<Box> box(zone_, evaluateDefaultParameter(type, parameter));
 23.2964 +            if (!box)
 23.2965 +                return false;
 23.2966 +
 23.2967 +            defaults->set(zone_, i, box);
 23.2968 +        }
 23.2969 +#endif
 23.2970 +    }
 23.2971 +
 23.2972 +    *argsp = args;
 23.2973 +    *defaultsp = defaults;
 23.2974 +
 23.2975 +    return true;
 23.2976 +}
 23.2977 +
 23.2978 +void
 23.2979 +SemanticAnalysis::visit(FunctionTypeStatement *node)
 23.2980 +{
 23.2981 +    if (node->decl()->type())
 23.2982 +        return;
 23.2983 +
 23.2984 +    Local<FixedArray> args(zone_);
 23.2985 +    Local<FixedArray> defaults(zone_);
 23.2986 +
 23.2987 +    const FunctionSignature &sig= node->signature();
 23.2988 +    if (!buildFunctionArgs(node,
 23.2989 +                           TOK_STOCK,
 23.2990 +                           sig,
 23.2991 +                           args.address(),
 23.2992 +                           defaults.address()))
 23.2993 +    {
 23.2994 +        return;
 23.2995 +    }
 23.2996 +
 23.2997 +#if 0
 23.2998 +    Local<Type> returnType(zone_);
 23.2999 +    if (sig.returnType())
 23.3000 +        returnType = bindType(node->pos(), sig.returnType());
 23.3001 +    else
 23.3002 +        returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
 23.3003 +
 23.3004 +    if (!returnType)
 23.3005 +        return;
 23.3006 +
 23.3007 +    Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args, defaults));
 23.3008 +    if (!funtype)
 23.3009 +        return;
 23.3010 +
 23.3011 +    node->decl()->setType(funtype);
 23.3012 +#endif
 23.3013 +}
 23.3014 +
 23.3015 +Type *
 23.3016 +SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
 23.3017 +{
 23.3018 +    Local<Type> arrayType(zone_, type);
 23.3019 +
 23.3020 +    unsigned dimcount = dimensions->length();
 23.3021 +    if (type->isArray())
 23.3022 +        dimcount += type->levels();
 23.3023 +
 23.3024 +    if (dimcount > MAX_ARRAY_DEPTH) {
 23.3025 +        cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
 23.3026 +                        Message_MaximumArrayDepth);
 23.3027 +        return false;
 23.3028 +    }
 23.3029 +
 23.3030 +    // Note: constness is sort of bogus. Fix this sometime.
 23.3031 +    for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
 23.3032 +        Expression *expr = dimensions->at(i);
 23.3033 +        if (!expr) {
 23.3034 +            arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
 23.3035 +            if (!arrayType)
 23.3036 +                return NULL;
 23.3037 +
 23.3038 +            continue;
 23.3039 +        }
 23.3040 +
 23.3041 +        BoxedPrimitive box;
 23.3042 +        if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
 23.3043 +            cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
 23.3044 +            return NULL;
 23.3045 +        }
 23.3046 +
 23.3047 +        if (box.toInt() <= 0) {
 23.3048 +            cc_.reportError(expr->pos(), Message_BadArraySize);
 23.3049 +            return NULL;
 23.3050 +        }
 23.3051 +
 23.3052 +        arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
 23.3053 +        if (!arrayType)
 23.3054 +            return NULL;
 23.3055 +    }
 23.3056 +
 23.3057 +    return arrayType;
 23.3058 +}
 23.3059 +
 23.3060 +bool
 23.3061 +SemanticAnalysis::preanalyze(FunctionStatement *node)
 23.3062 +{
 23.3063 +    Local<FixedArray> args(zone_);
 23.3064 +    Local<FixedArray> defaults(zone_);
 23.3065 +
 23.3066 +    const FunctionSignature &sig = node->signature();
 23.3067 +    if (!buildFunctionArgs(node,
 23.3068 +                           node->fun()->token(),
 23.3069 +                           sig,
 23.3070 +                           args.address(),
 23.3071 +                           defaults.address()))
 23.3072 +    {
 23.3073 +        return false;
 23.3074 +    }
 23.3075 +
 23.3076 +#if 0
 23.3077 +    Local<Type> returnType(zone_);
 23.3078 +    if (sig.returnType() ||
 23.3079 +        node->hasExplicitReturn() ||
 23.3080 +        node->fun()->isNative())
 23.3081 +    {
 23.3082 +        returnType = bindType(node->pos(), sig.returnType());
 23.3083 +    } else {
 23.3084 +        returnType = zone_->types()->getVoid();
 23.3085 +    }
 23.3086 +    if (!returnType)
 23.3087 +        return false;
 23.3088 +
 23.3089 +    if (sig.returnDimensions()) {
 23.3090 +        returnType = buildArrayType(returnType, sig.returnDimensions(), false);
 23.3091 +        if (!returnType)
 23.3092 +            return false;
 23.3093 +    }
 23.3094 +
 23.3095 +    if (IsScalarString(returnType)) {
 23.3096 +        cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
 23.3097 +        return false;
 23.3098 +    }
 23.3099 +
 23.3100 +    Local<Type> funtype(zone_);
 23.3101 +    if (node->fun()->isNative())
 23.3102 +        funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
 23.3103 +    else
 23.3104 +        funtype = zone_->types()->newFunction(returnType, args, defaults);
 23.3105 +    if (!funtype)
 23.3106 +        return false;
 23.3107 +    
 23.3108 +    // If the function already has a type, it was forward declared before, and
 23.3109 +    // now this is our chance to type check the second declaration.
 23.3110 +    if (node->fun()->type()) {
 23.3111 +        Local<Type> forward(zone_, node->fun()->type());
 23.3112 +        if (!Type::Compare(funtype, forward)) {
 23.3113 +            cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
 23.3114 +            return false;
 23.3115 +        }
 23.3116 +        node->fun()->setForwardType(forward);
 23.3117 +    }
 23.3118 +
 23.3119 +    node->fun()->setType(funtype);
 23.3120 +#endif
 23.3121 +
 23.3122 +    return true;
 23.3123 +}
 23.3124 +
 23.3125 +void
 23.3126 +SemanticAnalysis::visit(FunctionStatement *node)
 23.3127 +{
 23.3128 +    function_ = node->fun();
 23.3129 +    scope_ = node->scope();
 23.3130 +
 23.3131 +    ControlScope control(&control_);
 23.3132 +    if (node->body()) {
 23.3133 +        node->body()->accept(this);
 23.3134 +
 23.3135 +        ControlStatus status = control.status();
 23.3136 +        if (status.returns() == Returns_Sometimes) {
 23.3137 +            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
 23.3138 +        } else if (status.returns() == Returns_Never) {
 23.3139 +            if (!function_->type()->returnType()->isVoid())
 23.3140 +                cc_.reportError(node->pos(), Message_MissingReturnValue);
 23.3141 +        }
 23.3142 +    }
 23.3143 +
 23.3144 +    scope_ = NULL;
 23.3145 +    function_ = NULL;
 23.3146 +}
 23.3147 +
 23.3148 +void
 23.3149 +SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given)
 23.3150 +{
 23.3151 +    cc_.reportError(pos, Message_TypeMismatch,
 23.3152 +                    GetTypeName(actual),
 23.3153 +                    GetTypeName(given));
 23.3154 +}
 23.3155 +
 23.3156 +bool
 23.3157 +SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> argGiven,
 23.3158 +                                           Handle<Type> argActual, bool forAssign)
 23.3159 +{
 23.3160 +    Local<Type> actual(zone_, argActual);
 23.3161 +    Local<Type> given(zone_, argGiven);
 23.3162 +
 23.3163 +    if (!given->isArray()) {
 23.3164 +        cc_.reportError(pos, Message_ExpectedArray);
 23.3165 +        return false;
 23.3166 +    }
 23.3167 +    if (given->levels() != actual->levels()) {
 23.3168 +        cc_.reportError(pos, Message_ArrayDimensionsMismatch);
 23.3169 +        return false;
 23.3170 +    }
 23.3171 +
 23.3172 +    unsigned level = 1;
 23.3173 +    while (given->isArray()) {
 23.3174 +        if (actual->isFixedLength()) {
 23.3175 +            if (forAssign) {
 23.3176 +                if (!given->isFixedLength()) {
 23.3177 +                    cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 23.3178 +                    return false;
 23.3179 +                }
 23.3180 +
 23.3181 +                if (actual->isCharArray()) {
 23.3182 +                    // String assignment can have a truncated |given|.
 23.3183 +                    if (given->fixedLength() > actual->fixedLength()) {
 23.3184 +                        cc_.reportError(pos, Message_ArrayAssignmentTooBig);
 23.3185 +                        return false;
 23.3186 +                    }
 23.3187 +                } else {
 23.3188 +                    if (given->fixedLength() != actual->fixedLength()) {
 23.3189 +                        cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 23.3190 +                        return false;
 23.3191 +                    }
 23.3192 +                }
 23.3193 +            }
 23.3194 +        } else if (given->isFixedLength()) {
 23.3195 +            // We do not allow assignments in the form:
 23.3196 +            //    [][] = [][Y]
 23.3197 +            //
 23.3198 +            // Otherwise, the following code could break the size guarantees
 23.3199 +            // of the right-hand side:
 23.3200 +            //
 23.3201 +            //   new x[][5];
 23.3202 +            //   new y[][];
 23.3203 +            //   new z[3];
 23.3204 +            //
 23.3205 +            //   y = x;
 23.3206 +            //   y[0] = z;
 23.3207 +            //   
 23.3208 +            // Now |x[0]| contains a 4-length array.
 23.3209 +            if (level > 1) {
 23.3210 +                cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 23.3211 +                return false;
 23.3212 +            }
 23.3213 +        }
 23.3214 +        given = given->contained();
 23.3215 +        actual = actual->contained();
 23.3216 +        level++;
 23.3217 +    }
 23.3218 +
 23.3219 +    return typeCheckAssignment(pos, given, actual, forAssign);
 23.3220 +}
 23.3221 +
 23.3222 +bool
 23.3223 +SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle<Type> argGiven,
 23.3224 +                                      Handle<Type> argActual, bool forAssign)
 23.3225 +{
 23.3226 +    Local<Type> actual(zone_, argActual);
 23.3227 +    Local<Type> given(zone_, argGiven);
 23.3228 +
 23.3229 +    if (actual->isArray())
 23.3230 +        return typeCheckArrayAssignment(pos, given, actual, forAssign);
 23.3231 +
 23.3232 +    if (given->isArray()) {
 23.3233 +        cc_.reportError(pos, Message_CannotAssignArrayToScalar);
 23.3234 +        return false;
 23.3235 +    }
 23.3236 +
 23.3237 +    // The given type may not have been dereferenced.
 23.3238 +    if (given->isReference())
 23.3239 +        given = given->contained();
 23.3240 +    if (actual->isReference())
 23.3241 +        actual = actual->contained();
 23.3242 +
 23.3243 +    // We coerce unchecked to a few things.
 23.3244 +    if (actual->isUnchecked() || given->isUnchecked()) {
 23.3245 +        Type *check = actual->isUnchecked() ? given : actual;
 23.3246 +        if (check->isUnchecked() ||
 23.3247 +            check->isEnum() ||
 23.3248 +            check->isInt32() ||
 23.3249 +            check->isBool() ||
 23.3250 +            check->isFloat())
 23.3251 +        {
 23.3252 +            return true;
 23.3253 +        }
 23.3254 +        typeMismatch(pos, actual, given);
 23.3255 +        return false;
 23.3256 +    }
 23.3257 +
 23.3258 +    if (given->isFunction() && actual->isFunction()) {
 23.3259 +        if (!Type::Compare(given, actual)) {
 23.3260 +            typeMismatch(pos, actual, given);
 23.3261 +            return false;
 23.3262 +        }
 23.3263 +        return true;
 23.3264 +    }
 23.3265 +
 23.3266 +    if (actual->isEnum()) {
 23.3267 +        if (!given->isEnum() || actual != given) {
 23.3268 +            typeMismatch(pos, actual, given);
 23.3269 +            return false;
 23.3270 +        }
 23.3271 +        return true;
 23.3272 +    }
 23.3273 +
 23.3274 +    if (actual->isStruct()) {
 23.3275 +        if (!given->isStruct() || actual != given) {
 23.3276 +            typeMismatch(pos, actual, given);
 23.3277 +            return false;
 23.3278 +        }
 23.3279 +        return true;
 23.3280 +    }
 23.3281 +
 23.3282 +    if (given->isEnum() || given->isFunction() || given->isStruct()) {
 23.3283 +        typeMismatch(pos, actual, given);
 23.3284 +        return false;
 23.3285 +    }
 23.3286 +
 23.3287 +    // This coercion is trivial.
 23.3288 +    if (given->isBool() && actual->isInt32())
 23.3289 +        return true;
 23.3290 +
 23.3291 +    if (given->primitive() != actual->primitive()) {
 23.3292 +        typeMismatch(pos, actual, given);
 23.3293 +        return false;
 23.3294 +    }
 23.3295 +
 23.3296 +    return true;
 23.3297 +}
 23.3298 +
 23.3299 +bool
 23.3300 +SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
 23.3301 +{
 23.3302 +    return typeCheckAssignment(node->pos(), given, actual, false);
 23.3303 +}
 23.3304 +
 23.3305 +bool
 23.3306 +SemanticAnalysis::checkArgumentCount(Handle<Type> type, unsigned actual)
 23.3307 +{
 23.3308 +    if (type->parameters()->length() == actual)
 23.3309 +        return true;
 23.3310 +
 23.3311 +    if (actual > type->parameters()->length()) {
 23.3312 +        if (!type->isNative() || !type->isNativeVariadic())
 23.3313 +            return false;
 23.3314 +        return true;
 23.3315 +    }
 23.3316 +
 23.3317 +    if (!type->defaults())
 23.3318 +        return false;
 23.3319 +
 23.3320 +    // Missing arguments. See if there's a default argument for each missing
 23.3321 +    // actual.
 23.3322 +    for (unsigned i = actual; i < type->parameters()->length(); i++) {
 23.3323 +        if (!type->defaults()->at(i))
 23.3324 +            return false;
 23.3325 +    }
 23.3326 +
 23.3327 +    return true;
 23.3328 +}
 23.3329 +
 23.3330 +void
 23.3331 +SemanticAnalysis::visit(CallExpression *node)
 23.3332 +{
 23.3333 +    Local<Type> type(zone_, visitForLoad(node->callee()));
 23.3334 +    if (!type)
 23.3335 +        return;
 23.3336 +
 23.3337 +    if (!type->isFunction()) {
 23.3338 +        cc_.reportError(node->pos(), Message_CalleeNotFunction);
 23.3339 +        return;
 23.3340 +    }
 23.3341 +
 23.3342 +    if (!checkArgumentCount(type, node->arguments()->length())) {
 23.3343 +        cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
 23.3344 +        return;
 23.3345 +    }
 23.3346 +
 23.3347 +    // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
 23.3348 +    // if (fun->isForward()) {
 23.3349 +    //     cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
 23.3350 +    //     return;
 23.3351 +    // }
 23.3352 +
 23.3353 +    for (unsigned i = 0; i < node->arguments()->length(); i++) {
 23.3354 +        // Note: we don't compute references unless the callee needs a
 23.3355 +        // reference type.
 23.3356 +        Expression *expression = node->arguments()->at(i);
 23.3357 +        Local<Type> given(zone_, visitAndApplyType(expression));
 23.3358 +        if (!given)
 23.3359 +            return;
 23.3360 +
 23.3361 +        // Since we skip a load, check for a call expression that returns void.
 23.3362 +        if (given->isVoid()) {
 23.3363 +            assert(expression->isCallExpression());
 23.3364 +            CallExpression *call = expression->toCallExpression();
 23.3365 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
 23.3366 +            return;
 23.3367 +        }
 23.3368 +        
 23.3369 +        bool mustComputeReference;
 23.3370 +        if (i >= type->parameters()->length()) {
 23.3371 +            // Special handling for natives. Arguments past the formal must
 23.3372 +            // always have references computed. However, arrays are already
 23.3373 +            // references for natives.  
 23.3374 +            assert(type->isNative() && type->isNativeVariadic());
 23.3375 +            mustComputeReference = !given->isReference() && !given->isArray();
 23.3376 +        } else {
 23.3377 +            Local<Type> actual(zone_, type->parameterAt(i));
 23.3378 +
 23.3379 +            if (expression->isIndexExpression()) {
 23.3380 +                // Disabled until we can make it work.
 23.3381 +#if 0
 23.3382 +                if (actual->isArray()) {
 23.3383 +                    // We special case the ability to pass x[y] into x[], which
 23.3384 +                    // creates an array slice. We only do this if we know the
 23.3385 +                    // assignment would otherwise not type-check.
 23.3386 +                    IndexExpression *index = expression->toIndexExpression();
 23.3387 +                    if (index->left()->type()->levels() == actual->levels())
 23.3388 +                        given = index->left()->type();
 23.3389 +                } else
 23.3390 +#endif
 23.3391 +                if (actual->isReference()) {
 23.3392 +                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
 23.3393 +                    return;
 23.3394 +                }
 23.3395 +            }
 23.3396 +
 23.3397 +            if (!typeCheckParameter(expression, given, actual))
 23.3398 +                return;
 23.3399 +            mustComputeReference = actual->isReference() && !given->isReference();
 23.3400 +        }
 23.3401 +
 23.3402 +        // If the actual is a reference, and the given is not, we'll need to
 23.3403 +        // compute a reference, which may be allocated on the stack.
 23.3404 +        if (mustComputeReference)
 23.3405 +            scope_->setUsesLifoHeap();
 23.3406 +    }
 23.3407 +
 23.3408 +    node->setType(type->returnType());
 23.3409 +}
 23.3410 +
 23.3411 +void
 23.3412 +SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
 23.3413 +{
 23.3414 +    if (other.returns() < status().returns())
 23.3415 +        return;
 23.3416 +
 23.3417 +    if (other.terminates())
 23.3418 +        terminate(other.returns());
 23.3419 +    else
 23.3420 +        returns(other.returns());
 23.3421 +}
 23.3422 +
 23.3423 +void
 23.3424 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
 23.3425 +{
 23.3426 +    // If both sides terminate in a return, we consider this a return as well.
 23.3427 +    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
 23.3428 +        terminate(Returns_Always);
 23.3429 +        return;
 23.3430 +    }
 23.3431 +
 23.3432 +    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
 23.3433 +                          ? Returns_Never
 23.3434 +                          : Returns_Sometimes;
 23.3435 +
 23.3436 +    if (left.terminates() && right.terminates())
 23.3437 +        terminate(status);
 23.3438 +    else
 23.3439 +        returns(status);
 23.3440 +}
 23.3441 +
 23.3442 +void
 23.3443 +SemanticAnalysis::visit(IfStatement *node)
 23.3444 +{
 23.3445 +    Local<Type> type(zone_, visitForLoad(node->condition()));
 23.3446 +    if (!type)
 23.3447 +        return;
 23.3448 +
 23.3449 +    if (!canTest(node, type))
 23.3450 +        return;
 23.3451 +
 23.3452 +    ControlStatus trueBranch = visitForControl(node->ifTrue());
 23.3453 +    ControlStatus falseBranch = ControlStatus(false, Returns_Never);
 23.3454 +
 23.3455 +    if (node->ifFalse())
 23.3456 +        falseBranch = visitForControl(node->ifFalse());
 23.3457 +
 23.3458 +    control_->merge(trueBranch, falseBranch);
 23.3459 +}
 23.3460 +
 23.3461 +void
 23.3462 +SemanticAnalysis::visit(IndexExpression *node)
 23.3463 +{
 23.3464 +    Local<Type> left(zone_, visitForLoad(node->left()));
 23.3465 +    Local<Type> right(zone_, visitForLoad(node->right()));
 23.3466 +
 23.3467 +    if (!left || !right)
 23.3468 +        return;
 23.3469 +
 23.3470 +    if (!right->isInt32() && !right->isEnum()) {
 23.3471 +        cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
 23.3472 +        return;
 23.3473 +    }
 23.3474 +    if (!left->isArray()) {
 23.3475 +        cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
 23.3476 +        return;
 23.3477 +    }
 23.3478 +
 23.3479 +    // Note: char arrays are automatically up-casted to return an int32.
 23.3480 +    if (left->isCharArray())
 23.3481 +        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
 23.3482 +    else
 23.3483 +        node->setType(left->contained());
 23.3484 +}
 23.3485 +
 23.3486 +void
 23.3487 +SemanticAnalysis::visit(FieldExpression *node)
 23.3488 +{
 23.3489 +    Local<Type> left(zone_, visitForLoad(node->left()));
 23.3490 +    if (!left)
 23.3491 +        return;
 23.3492 +
 23.3493 +    if (!left->isStruct()) {
 23.3494 +        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
 23.3495 +                        GetTypeName(left));
 23.3496 +        return;
 23.3497 +    }
 23.3498 +
 23.3499 +    Local<String> field(zone_, node->field());
 23.3500 +
 23.3501 +    unsigned offset;
 23.3502 +    Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
 23.3503 +    if (!desc) {
 23.3504 +        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
 23.3505 +                        GetTypeName(left));
 23.3506 +        return;
 23.3507 +    }
 23.3508 +
 23.3509 +    node->setFieldIndex(offset);
 23.3510 +    node->setType(desc->type());
 23.3511 +}
 23.3512 +
 23.3513 +void
 23.3514 +SemanticAnalysis::visit(EnumStatement *node)
 23.3515 +{
 23.3516 +    Local<String> name(zone_, node->name());
 23.3517 +    Local<Type> type(zone_);
 23.3518 +    if (name)
 23.3519 +        type = zone_->types()->newEnum(name);
 23.3520 +    else
 23.3521 +        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
 23.3522 +
 23.3523 +    if (!type)
 23.3524 +        return;
 23.3525 +
 23.3526 +    if (node->decl())
 23.3527 +        node->decl()->setType(type);
 23.3528 +
 23.3529 +    int value = 0;
 23.3530 +    for (size_t i = 0; i < node->entries()->length(); i++) {
 23.3531 +        EnumStatement::Entry &entry = node->entries()->at(i);
 23.3532 +
 23.3533 +        BoxedPrimitive box = BoxedPrimitive::Int(value);
 23.3534 +        if (entry.expr) {
 23.3535 +            entry.expr->accept(this);
 23.3536 +            if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
 23.3537 +                cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
 23.3538 +                return;
 23.3539 +            }
 23.3540 +
 23.3541 +            assert(box.type() == PrimitiveType_Int32);
 23.3542 +            value = box.toInt();
 23.3543 +        }
 23.3544 +
 23.3545 +#if 0
 23.3546 +        entry.name->set(type, box);
 23.3547 +#endif
 23.3548 +        value++;
 23.3549 +    }
 23.3550 +}
 23.3551 +
 23.3552 +static int
 23.3553 +SortCaseIntValues(const void *p1, const void *p2)
 23.3554 +{
 23.3555 +    CaseValue *v1 = (CaseValue *)p1;
 23.3556 +    CaseValue *v2 = (CaseValue *)p2;
 23.3557 +
 23.3558 +    return v1->box.toInt() - v2->box.toInt();
 23.3559 +}
 23.3560 +
 23.3561 +void
 23.3562 +SemanticAnalysis::visit(SwitchStatement *node)
 23.3563 +{
 23.3564 +    Local<Type> caseType(zone_, visitForLoad(node->expression()));
 23.3565 +    if (!caseType)
 23.3566 +        return;
 23.3567 +
 23.3568 +    if (!caseType->isEnum() && !caseType->isInt32()) {
 23.3569 +        cc_.reportError(node->pos(), Message_CaseMustBeInteger);
 23.3570 +        return;
 23.3571 +    }
 23.3572 +
 23.3573 +    PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
 23.3574 +    ControlStatus status = ControlStatus(false, Returns_Never);
 23.3575 +
 23.3576 +    Local<Type> check(zone_);
 23.3577 +    for (size_t i = 0; i < node->cases()->length(); i++) {
 23.3578 +        Case *c = node->cases()->at(i);
 23.3579 +
 23.3580 +        check = visitForLoad(c->expression());
 23.3581 +        if (!check)
 23.3582 +            return;
 23.3583 +
 23.3584 +        if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
 23.3585 +            return;
 23.3586 +
 23.3587 +        CaseValue v(i);
 23.3588 +        if (!EvaluateForConstant(c->expression(), &v.box)) {
 23.3589 +            cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
 23.3590 +            return;
 23.3591 +        }
 23.3592 +        if (!values->append(v))
 23.3593 +            return;
 23.3594 +
 23.3595 +        if (c->others()) {
 23.3596 +            for (size_t j = 0; j < c->others()->length(); j++) {
 23.3597 +                Expression *expr = c->others()->at(j);
 23.3598 +                check = visitForLoad(expr);
 23.3599 +                if (!check)
 23.3600 +                    return;
 23.3601 +
 23.3602 +                if (!typeCheckAssignment(expr->pos(), check, caseType, false))
 23.3603 +                    return;
 23.3604 +
 23.3605 +                CaseValue v(i);
 23.3606 +                if (!EvaluateForConstant(expr, &v.box)) {
 23.3607 +                    cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
 23.3608 +                    return;
 23.3609 +                }
 23.3610 +                if (!values->append(v))
 23.3611 +                    return;
 23.3612 +            }
 23.3613 +        }
 23.3614 +
 23.3615 +        ControlStatus latest = visitForControl(c->statement());
 23.3616 +
 23.3617 +        if (i != 0)
 23.3618 +            control_->merge(status, latest);
 23.3619 +
 23.3620 +        status = latest;
 23.3621 +    }
 23.3622 +
 23.3623 +    if (node->defaultCase()) {
 23.3624 +        ControlStatus latest = visitForControl(node->defaultCase());
 23.3625 +
 23.3626 +        if (node->cases()->length()) {
 23.3627 +            // If we had any other cases, we must merge.
 23.3628 +            control_->merge(status, latest);
 23.3629 +        } else {
 23.3630 +            // Otherwise, control-flow always flows through here.
 23.3631 +            control_->inherit(latest);
 23.3632 +        }
 23.3633 +    } else if (node->cases()->length()) {
 23.3634 +        control_->merge(status, ControlStatus(false, Returns_Never));
 23.3635 +    }
 23.3636 +
 23.3637 +    if (values->length() > 1) {
 23.3638 +        qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
 23.3639 +
 23.3640 +        for (size_t i = 1; i < values->length(); i++) {
 23.3641 +            CaseValue &prev = values->at(i - 1);
 23.3642 +            CaseValue &cur = values->at(i);
 23.3643 +            if (prev.box.toInt() == cur.box.toInt()) {
 23.3644 +                cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
 23.3645 +                return;
 23.3646 +            }
 23.3647 +        }
 23.3648 +    }
 23.3649 +
 23.3650 +    node->setCaseValueList(values);
 23.3651 +}
 23.3652 +
 23.3653 +void
 23.3654 +SemanticAnalysis::visit(StructureStatement *node)
 23.3655 +{
 23.3656 +#if 0
 23.3657 +    // If this node already has a type, it was pre-analyzed, so skip it.
 23.3658 +    if (node->decl()->type())
 23.3659 +        return;
 23.3660 +
 23.3661 +    FieldList *fields = node->fields();
 23.3662 +    Local<FixedArray> desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old));
 23.3663 +    if (!desctable)
 23.3664 +        return;
 23.3665 +
 23.3666 +    Vector<unsigned> composedList;
 23.3667 +    StructureBufferBuilder builder;
 23.3668 +
 23.3669 +    Local<Type> type(zone_);
 23.3670 +    Local<String> name(zone_);
 23.3671 +    Local<Descriptor> desc(zone_);
 23.3672 +    for (size_t i = 0; i < fields->length(); i++) {
 23.3673 +        StructureStatement::Field *field = fields->at(i);
 23.3674 +
 23.3675 +        type = bindType(field->pos(), field->type());
 23.3676 +        if (!type)
 23.3677 +            return;
 23.3678 +
 23.3679 +        if (field->dimensions()) {
 23.3680 +            type = buildArrayType(type, field->dimensions(), false);
 23.3681 +            if (!type)
 23.3682 +                return;
 23.3683 +
 23.3684 +            if (!ArrayMap::Attach(zone_, type))
 23.3685 +                return;
 23.3686 +        }
 23.3687 +
 23.3688 +        if (IsScalarString(type)) {
 23.3689 +            cc_.reportError(field->pos(), Message_CannotDeclareStringCell);
 23.3690 +            return;
 23.3691 +        }
 23.3692 +
 23.3693 +        unsigned offset;
 23.3694 +        if (!builder.add(type, &offset))
 23.3695 +            return;
 23.3696 +
 23.3697 +        name = field->name();
 23.3698 +        desc = Descriptor::New(zone_, name, type, offset);
 23.3699 +        if (!desc)
 23.3700 +            return;
 23.3701 +
 23.3702 +        desctable->set(zone_, i, desc);
 23.3703 +
 23.3704 +        if (type->isStruct() || type->isArray()) {
 23.3705 +            if (!composedList.append(i))
 23.3706 +                return;
 23.3707 +        }
 23.3708 +    }
 23.3709 +
 23.3710 +    Local<FixedArray> composed(zone_);
 23.3711 +    if (composedList.length()) {
 23.3712 +        composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old);
 23.3713 +        if (!composed)
 23.3714 +            return;
 23.3715 +
 23.3716 +        for (unsigned i = 0; i < composedList.length(); i++)
 23.3717 +            composed->set(zone_, i, desctable->at(i));
 23.3718 +    }
 23.3719 +
 23.3720 +    Local<StructMap> map(zone_, StructMap::New(zone_, builder, composed));
 23.3721 +    if (!map)
 23.3722 +        return;
 23.3723 +
 23.3724 +    name = node->decl()->name();
 23.3725 +    type = zone_->types()->newStruct(name, desctable, map);
 23.3726 +    if (!type)
 23.3727 +        return;
 23.3728 +
 23.3729 +    map->setType(type);
 23.3730 +    node->decl()->setType(type);
 23.3731 +#endif
 23.3732 +}
 23.3733 +
 23.3734 +void
 23.3735 +SemanticAnalysis::visit(StringLiteral *node)
 23.3736 +{
 23.3737 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
 23.3738 +    if (!type)
 23.3739 +        return;
 23.3740 +
 23.3741 +    type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
 23.3742 +    if (!type)
 23.3743 +        return;
 23.3744 +
 23.3745 +    node->setType(type);
 23.3746 +}
 23.3747 +
 23.3748 +void
 23.3749 +SemanticAnalysis::visit(FloatLiteral *node)
 23.3750 +{
 23.3751 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
 23.3752 +    if (!type)
 23.3753 +        return;
 23.3754 +
 23.3755 +    node->setType(type);
 23.3756 +}
 23.3757 +
 23.3758 +void
 23.3759 +SemanticAnalysis::visit(BreakStatement *node)
 23.3760 +{
 23.3761 +    if (!loop_) {
 23.3762 +        cc_.reportError(node->pos(), Message_BreakOutsideLoop);
 23.3763 +        return;
 23.3764 +    }
 23.3765 +
 23.3766 +    // Note: ignore breaks that occur in unreachable control-flow.
 23.3767 +    if (!control_->status().terminates())
 23.3768 +        loop_->addBreak();
 23.3769 +
 23.3770 +    control_->terminate(Returns_Never);
 23.3771 +}
 23.3772 +
 23.3773 +void
 23.3774 +SemanticAnalysis::visit(ContinueStatement *node)
 23.3775 +{
 23.3776 +    if (!loop_) {
 23.3777 +        cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
 23.3778 +        return;
 23.3779 +    }
 23.3780 +
 23.3781 +    // Note: ignore continues that occur in unreachable control-flow.
 23.3782 +    if (!control_->status().terminates())
 23.3783 +        loop_->addContinue();
 23.3784 +
 23.3785 +    control_->terminate(Returns_Never);
 23.3786 +}
 23.3787 +
 23.3788 +void
 23.3789 +SemanticAnalysis::visit(ArrayLiteral *node)
 23.3790 +{
 23.3791 +    // We should never visit this.
 23.3792 +    cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
 23.3793 +}
 23.3794 +
 23.3795 +void
 23.3796 +SemanticAnalysis::visit(ImportStatement *node)
 23.3797 +{
 23.3798 +}
 23.3799 +
 23.3800  #endif
 23.3801 \ No newline at end of file
    24.1 --- a/src/OldSema.h	Mon Jun 10 00:46:29 2013 +0100
    24.2 +++ b/src/OldSema.h	Mon Jun 10 01:04:43 2013 +0100
    24.3 @@ -1,237 +1,237 @@
    24.4 -/* vim: set ts=4 sw=4 tw=99 et:
    24.5 - *
    24.6 - * Copyright (C) 2012 David Anderson
    24.7 - *
    24.8 - * This file is part of JITCraft.
    24.9 - *
   24.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   24.11 - * the terms of the GNU General Public License as published by the Free
   24.12 - * Software Foundation, either version 3 of the License, or (at your option)
   24.13 - * any later version.
   24.14 - * 
   24.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   24.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   24.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   24.18 - *
   24.19 - * You should have received a copy of the GNU General Public License along with
   24.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   24.21 - */
   24.22 -#ifndef _include_semantic_analysis_h_
   24.23 -#define _include_semantic_analysis_h_
   24.24 -
   24.25 -#include <assert.h>
   24.26 -#include "AST.h"
   24.27 -#include "../Types.h"
   24.28 -
   24.29 -namespace ke {
   24.30 -
   24.31 -class Box;
   24.32 -
   24.33 -class SemanticAnalysis : public AstVisitor
   24.34 -{
   24.35 -    Zone *zone_;
   24.36 -    CompileContext &cc_;
   24.37 -    ParseTree *tree_;
   24.38 -    Scope *scope_;
   24.39 -    NamedFunction *function_;
   24.40 -
   24.41 -    enum ReturnStatus
   24.42 -    {
   24.43 -        Returns_Never,
   24.44 -        Returns_Sometimes,
   24.45 -        Returns_Always
   24.46 -    };
   24.47 -
   24.48 -    // Tuple that describes whether a path terminates control flow, and
   24.49 -    // if it is guaranteed to end in a return.
   24.50 -    class ControlStatus
   24.51 -    {
   24.52 -        bool terminates_;
   24.53 -        ReturnStatus returns_;
   24.54 -
   24.55 -      public:
   24.56 -        ControlStatus(bool terminates, ReturnStatus returns)
   24.57 -          : terminates_(terminates),
   24.58 -            returns_(returns)
   24.59 -        {
   24.60 -        }
   24.61 -
   24.62 -        bool terminates() const {
   24.63 -            return terminates_;
   24.64 -        }
   24.65 -        ReturnStatus returns() const {
   24.66 -            return returns_;
   24.67 -        }
   24.68 -    };
   24.69 -
   24.70 -    // Used to keep track of terminating control flow and return statements
   24.71 -    // inside control structures.
   24.72 -    class ControlScope
   24.73 -    {
   24.74 -        ReturnStatus returns_;
   24.75 -        ControlScope **prevp_;
   24.76 -        ControlScope *prev_;
   24.77 -        bool terminates_;
   24.78 -
   24.79 -      public:
   24.80 -        ControlScope(ControlScope **prev)
   24.81 -          : returns_(Returns_Never),
   24.82 -            prevp_(prev),
   24.83 -            prev_(*prev),
   24.84 -            terminates_(false)
   24.85 -        {
   24.86 -            *prevp_ = this;
   24.87 -        }
   24.88 -
   24.89 -        ControlStatus status() const {
   24.90 -            return ControlStatus(terminates_, returns_);
   24.91 -        }
   24.92 -
   24.93 -        // We allow multiple terminators, but only the first one takes effect.
   24.94 -        // For example, |break; continue;| is legal but the continue is
   24.95 -        // unreachable.
   24.96 -        void returns(ReturnStatus status) {
   24.97 -            if (terminates_)
   24.98 -                return;
   24.99 -            if (status > returns_)
  24.100 -                returns_ = status;
  24.101 -        }
  24.102 -        void terminate(ReturnStatus status) {
  24.103 -            if (terminates_)
  24.104 -                return;
  24.105 -            terminates_ = true;
  24.106 -            returns_ = status;
  24.107 -        }
  24.108 -        void merge(const ControlStatus &left, const ControlStatus &right);
  24.109 -        void inherit(const ControlStatus &other);
  24.110 -
  24.111 -        ~ControlScope()
  24.112 -        {
  24.113 -            *prevp_ = prev_;
  24.114 -        }
  24.115 -    };
  24.116 -
  24.117 -    class LoopScope
  24.118 -    {
  24.119 -        LoopScope **prevp_;
  24.120 -        LoopScope *prev_;
  24.121 -        unsigned breaks_;
  24.122 -        unsigned continues_;
  24.123 -
  24.124 -      public:
  24.125 -        LoopScope(LoopScope **prev)
  24.126 -          : prevp_(prev),
  24.127 -            prev_(*prev),
  24.128 -            breaks_(0),
  24.129 -            continues_(0)
  24.130 -        {
  24.131 -            *prevp_ = this;
  24.132 -        }
  24.133 -
  24.134 -        ~LoopScope()
  24.135 -        {
  24.136 -            *prevp_ = prev_;
  24.137 -        }
  24.138 -
  24.139 -        void addBreak() {
  24.140 -            breaks_++;
  24.141 -        }
  24.142 -        void addContinue() {
  24.143 -            continues_++;
  24.144 -        }
  24.145 -        unsigned breaks() const {
  24.146 -            return breaks_;
  24.147 -        }
  24.148 -        unsigned continues() const {
  24.149 -            return continues_;
  24.150 -        }
  24.151 -    };
  24.152 -
  24.153 -    ControlScope *control_;
  24.154 -    LoopScope *loop_;
  24.155 -
  24.156 -  private:
  24.157 -    bool canTest(AstNode *node, Handle<Type> type);
  24.158 -    void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
  24.159 -    void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
  24.160 -    void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  24.161 -    Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  24.162 -
  24.163 -    Type *bindType(const SourcePosition &pos, BoundName *name);
  24.164 -
  24.165 -    // These check if one type is compatible with another type, for various
  24.166 -    // purposes, like:
  24.167 -    //      return (expr) matches function return type
  24.168 -    //      call(a, b)    matches expected arg type
  24.169 -    //      a = b         matches declared type
  24.170 -    //
  24.171 -    bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
  24.172 -    bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
  24.173 -    bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
  24.174 -
  24.175 -    Type *visitForLoad(Expression *expression);
  24.176 -    bool preanalyze(FunctionStatement *node);
  24.177 -    Type *visitForLValue(Expression *expression);
  24.178 -    Type *visitAndApplyType(Expression *expression);
  24.179 -    ControlStatus visitForControl(Statement *statement);
  24.180 -
  24.181 -    bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
  24.182 -    bool inferFixedArrayLiteral(ArrayLiteral *literal,
  24.183 -                                Handle<Type> type,
  24.184 -                                int dims[MAX_ARRAY_DEPTH],
  24.185 -                                unsigned dimcount,
  24.186 -                                unsigned level);
  24.187 -
  24.188 -    // Builds an array type used for parameters, returns, or field entries.
  24.189 -    Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
  24.190 -
  24.191 -    Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
  24.192 -    bool checkArgumentCount(Handle<Type> type, unsigned actual);
  24.193 -    bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
  24.194 -                           FixedArray **args, FixedArray **defaults);
  24.195 -
  24.196 -    void markCallResultUsed(CallExpression *call);
  24.197 -
  24.198 -    bool determineLiveFunctions();
  24.199 -
  24.200 -  public:
  24.201 -    SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
  24.202 -    bool analyze();
  24.203 -
  24.204 -  public:
  24.205 -    void visit(NameProxy *name);
  24.206 -    void visit(Assignment *node);
  24.207 -    void visit(BinaryExpression *node);
  24.208 -    void visit(ReturnStatement *node);
  24.209 -    void visit(ForStatement *node);
  24.210 -    void visit(BlockStatement *node);
  24.211 -    void visit(VariableDeclaration *node);
  24.212 -    void visit(IntegerLiteral *node);
  24.213 -    void visit(ExpressionStatement *node);
  24.214 -    void visit(FunctionStatement *node);
  24.215 -    void visit(CallExpression *node);
  24.216 -    void visit(IfStatement *node);
  24.217 -    void visit(IndexExpression *node);
  24.218 -    void visit(EnumStatement *node);
  24.219 -    void visit(FloatLiteral *node);
  24.220 -    void visit(WhileStatement *node);
  24.221 -    void visit(BreakStatement *node);
  24.222 -    void visit(ContinueStatement *node);
  24.223 -    void visit(StringLiteral *node);
  24.224 -    void visit(IncDecExpression *node);
  24.225 -    void visit(UnaryExpression *node);
  24.226 -    void visit(TernaryExpression *node);
  24.227 -    void visit(BooleanLiteral *node);
  24.228 -    void visit(StructureStatement *node);
  24.229 -    void visit(FieldExpression *node);
  24.230 -    void visit(SwitchStatement *node);
  24.231 -    void visit(FunctionTypeStatement *node);
  24.232 -    void visit(ArrayLiteral *node);
  24.233 -    void visit(ImportStatement *node);
  24.234 -};
  24.235 -
  24.236 -const char *GetTypeName(Type *type);
  24.237 -
  24.238 -} // namespace ke
  24.239 -
  24.240 -#endif // _include_semantic_analysis_h_
  24.241 +/* vim: set ts=4 sw=4 tw=99 et:
  24.242 + *
  24.243 + * Copyright (C) 2012 David Anderson
  24.244 + *
  24.245 + * This file is part of JITCraft.
  24.246 + *
  24.247 + * JITCraft is free software: you can redistribute it and/or modify it under
  24.248 + * the terms of the GNU General Public License as published by the Free
  24.249 + * Software Foundation, either version 3 of the License, or (at your option)
  24.250 + * any later version.
  24.251 + * 
  24.252 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  24.253 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  24.254 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  24.255 + *
  24.256 + * You should have received a copy of the GNU General Public License along with
  24.257 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  24.258 + */
  24.259 +#ifndef _include_semantic_analysis_h_
  24.260 +#define _include_semantic_analysis_h_
  24.261 +
  24.262 +#include <assert.h>
  24.263 +#include "AST.h"
  24.264 +#include "../Types.h"
  24.265 +
  24.266 +namespace ke {
  24.267 +
  24.268 +class Box;
  24.269 +
  24.270 +class SemanticAnalysis : public AstVisitor
  24.271 +{
  24.272 +    Zone *zone_;
  24.273 +    CompileContext &cc_;
  24.274 +    ParseTree *tree_;
  24.275 +    Scope *scope_;
  24.276 +    NamedFunction *function_;
  24.277 +
  24.278 +    enum ReturnStatus
  24.279 +    {
  24.280 +        Returns_Never,
  24.281 +        Returns_Sometimes,
  24.282 +        Returns_Always
  24.283 +    };
  24.284 +
  24.285 +    // Tuple that describes whether a path terminates control flow, and
  24.286 +    // if it is guaranteed to end in a return.
  24.287 +    class ControlStatus
  24.288 +    {
  24.289 +        bool terminates_;
  24.290 +        ReturnStatus returns_;
  24.291 +
  24.292 +      public:
  24.293 +        ControlStatus(bool terminates, ReturnStatus returns)
  24.294 +          : terminates_(terminates),
  24.295 +            returns_(returns)
  24.296 +        {
  24.297 +        }
  24.298 +
  24.299 +        bool terminates() const {
  24.300 +            return terminates_;
  24.301 +        }
  24.302 +        ReturnStatus returns() const {
  24.303 +            return returns_;
  24.304 +        }
  24.305 +    };
  24.306 +
  24.307 +    // Used to keep track of terminating control flow and return statements
  24.308 +    // inside control structures.
  24.309 +    class ControlScope
  24.310 +    {
  24.311 +        ReturnStatus returns_;
  24.312 +        ControlScope **prevp_;
  24.313 +        ControlScope *prev_;
  24.314 +        bool terminates_;
  24.315 +
  24.316 +      public:
  24.317 +        ControlScope(ControlScope **prev)
  24.318 +          : returns_(Returns_Never),
  24.319 +            prevp_(prev),
  24.320 +            prev_(*prev),
  24.321 +            terminates_(false)
  24.322 +        {
  24.323 +            *prevp_ = this;
  24.324 +        }
  24.325 +
  24.326 +        ControlStatus status() const {
  24.327 +            return ControlStatus(terminates_, returns_);
  24.328 +        }
  24.329 +
  24.330 +        // We allow multiple terminators, but only the first one takes effect.
  24.331 +        // For example, |break; continue;| is legal but the continue is
  24.332 +        // unreachable.
  24.333 +        void returns(ReturnStatus status) {
  24.334 +            if (terminates_)
  24.335 +                return;
  24.336 +            if (status > returns_)
  24.337 +                returns_ = status;
  24.338 +        }
  24.339 +        void terminate(ReturnStatus status) {
  24.340 +            if (terminates_)
  24.341 +                return;
  24.342 +            terminates_ = true;
  24.343 +            returns_ = status;
  24.344 +        }
  24.345 +        void merge(const ControlStatus &left, const ControlStatus &right);
  24.346 +        void inherit(const ControlStatus &other);
  24.347 +
  24.348 +        ~ControlScope()
  24.349 +        {
  24.350 +            *prevp_ = prev_;
  24.351 +        }
  24.352 +    };
  24.353 +
  24.354 +    class LoopScope
  24.355 +    {
  24.356 +        LoopScope **prevp_;
  24.357 +        LoopScope *prev_;
  24.358 +        unsigned breaks_;
  24.359 +        unsigned continues_;
  24.360 +
  24.361 +      public:
  24.362 +        LoopScope(LoopScope **prev)
  24.363 +          : prevp_(prev),
  24.364 +            prev_(*prev),
  24.365 +            breaks_(0),
  24.366 +            continues_(0)
  24.367 +        {
  24.368 +            *prevp_ = this;
  24.369 +        }
  24.370 +
  24.371 +        ~LoopScope()
  24.372 +        {
  24.373 +            *prevp_ = prev_;
  24.374 +        }
  24.375 +
  24.376 +        void addBreak() {
  24.377 +            breaks_++;
  24.378 +        }
  24.379 +        void addContinue() {
  24.380 +            continues_++;
  24.381 +        }
  24.382 +        unsigned breaks() const {
  24.383 +            return breaks_;
  24.384 +        }
  24.385 +        unsigned continues() const {
  24.386 +            return continues_;
  24.387 +        }
  24.388 +    };
  24.389 +
  24.390 +    ControlScope *control_;
  24.391 +    LoopScope *loop_;
  24.392 +
  24.393 +  private:
  24.394 +    bool canTest(AstNode *node, Handle<Type> type);
  24.395 +    void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
  24.396 +    void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
  24.397 +    void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  24.398 +    Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  24.399 +
  24.400 +    Type *bindType(const SourcePosition &pos, BoundName *name);
  24.401 +
  24.402 +    // These check if one type is compatible with another type, for various
  24.403 +    // purposes, like:
  24.404 +    //      return (expr) matches function return type
  24.405 +    //      call(a, b)    matches expected arg type
  24.406 +    //      a = b         matches declared type
  24.407 +    //
  24.408 +    bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
  24.409 +    bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
  24.410 +    bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
  24.411 +
  24.412 +    Type *visitForLoad(Expression *expression);
  24.413 +    bool preanalyze(FunctionStatement *node);
  24.414 +    Type *visitForLValue(Expression *expression);
  24.415 +    Type *visitAndApplyType(Expression *expression);
  24.416 +    ControlStatus visitForControl(Statement *statement);
  24.417 +
  24.418 +    bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
  24.419 +    bool inferFixedArrayLiteral(ArrayLiteral *literal,
  24.420 +                                Handle<Type> type,
  24.421 +                                int dims[MAX_ARRAY_DEPTH],
  24.422 +                                unsigned dimcount,
  24.423 +                                unsigned level);
  24.424 +
  24.425 +    // Builds an array type used for parameters, returns, or field entries.
  24.426 +    Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
  24.427 +
  24.428 +    Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
  24.429 +    bool checkArgumentCount(Handle<Type> type, unsigned actual);
  24.430 +    bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
  24.431 +                           FixedArray **args, FixedArray **defaults);
  24.432 +
  24.433 +    void markCallResultUsed(CallExpression *call);
  24.434 +
  24.435 +    bool determineLiveFunctions();
  24.436 +
  24.437 +  public:
  24.438 +    SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
  24.439 +    bool analyze();
  24.440 +
  24.441 +  public:
  24.442 +    void visit(NameProxy *name);
  24.443 +    void visit(Assignment *node);
  24.444 +    void visit(BinaryExpression *node);
  24.445 +    void visit(ReturnStatement *node);
  24.446 +    void visit(ForStatement *node);
  24.447 +    void visit(BlockStatement *node);
  24.448 +    void visit(VariableDeclaration *node);
  24.449 +    void visit(IntegerLiteral *node);
  24.450 +    void visit(ExpressionStatement *node);
  24.451 +    void visit(FunctionStatement *node);
  24.452 +    void visit(CallExpression *node);
  24.453 +    void visit(IfStatement *node);
  24.454 +    void visit(IndexExpression *node);
  24.455 +    void visit(EnumStatement *node);
  24.456 +    void visit(FloatLiteral *node);
  24.457 +    void visit(WhileStatement *node);
  24.458 +    void visit(BreakStatement *node);
  24.459 +    void visit(ContinueStatement *node);
  24.460 +    void visit(StringLiteral *node);
  24.461 +    void visit(IncDecExpression *node);
  24.462 +    void visit(UnaryExpression *node);
  24.463 +    void visit(TernaryExpression *node);
  24.464 +    void visit(BooleanLiteral *node);
  24.465 +    void visit(StructureStatement *node);
  24.466 +    void visit(FieldExpression *node);
  24.467 +    void visit(SwitchStatement *node);
  24.468 +    void visit(FunctionTypeStatement *node);
  24.469 +    void visit(ArrayLiteral *node);
  24.470 +    void visit(ImportStatement *node);
  24.471 +};
  24.472 +
  24.473 +const char *GetTypeName(Type *type);
  24.474 +
  24.475 +} // namespace ke
  24.476 +
  24.477 +#endif // _include_semantic_analysis_h_
    25.1 --- a/src/Opcodes.cpp	Mon Jun 10 00:46:29 2013 +0100
    25.2 +++ b/src/Opcodes.cpp	Mon Jun 10 01:04:43 2013 +0100
    25.3 @@ -1,350 +1,350 @@
    25.4 -/* vim: set ts=4 sw=4 tw=99 et:
    25.5 - *
    25.6 - * Copyright (C) 2012 David Anderson
    25.7 - *
    25.8 - * This file is part of JITCraft.
    25.9 - *
   25.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   25.11 - * the terms of the GNU General Public License as published by the Free
   25.12 - * Software Foundation, either version 3 of the License, or (at your option)
   25.13 - * any later version.
   25.14 - * 
   25.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   25.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   25.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   25.18 - *
   25.19 - * You should have received a copy of the GNU General Public License along with
   25.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   25.21 - */
   25.22 -#include <stdlib.h>
   25.23 -#include "Opcodes.h"
   25.24 -#include "Utility.h"
   25.25 -#include "Code.h"
   25.26 -#include "Zone.h"
   25.27 -#include "Array.h"
   25.28 -#include "Strings.h"
   25.29 -#include "CompactBuffer.h"
   25.30 -#include "Structures.h"
   25.31 -#include "Modules.h"
   25.32 -#include "Heap-inl.h"
   25.33 -
   25.34 -using namespace ke;
   25.35 -
   25.36 -OpInfo ke::OpcodeInfo[] =
   25.37 -{
   25.38 -#define OPDEF(name, text, length, uses, defs) \
   25.39 -    {text, length, uses, defs},
   25.40 -#include "Opcodes.tbl"
   25.41 -#undef OPDEF
   25.42 -};
   25.43 -
   25.44 -Code *
   25.45 -Code::New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
   25.46 -          Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
   25.47 -          unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap)
   25.48 -{
   25.49 -    Local<Code> code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old)));
   25.50 -    if (!code)
   25.51 -        return NULL;
   25.52 -
   25.53 -    code->bytecode_ = bytecode;
   25.54 -    code->locals_ = locals;
   25.55 -    code->objects_ = objects;
   25.56 -    code->maxStackDepth_ = maxStackDepth;
   25.57 -    code->module_ = NULL;
   25.58 -    code->safepoints_ = safepoints;
   25.59 -    code->sourcemap_ = sourcemap;
   25.60 -    code->lineNumber_ = 0;
   25.61 -    code->strings_ = strings;
   25.62 -    code->maxLoopDepth_ = maxLoopDepth;
   25.63 -    return code;
   25.64 -}
   25.65 -
   25.66 -static int
   25.67 -CompareSafepoints(const void *a, const void *b)
   25.68 -{
   25.69 -    const unsigned *sa = reinterpret_cast<const unsigned *>(a);
   25.70 -    const unsigned *sb = reinterpret_cast<const unsigned *>(b);
   25.71 -    if (*sa > *sb)
   25.72 -        return 1;
   25.73 -    if (*sa == *sb)
   25.74 -        return 0;
   25.75 -    return -1;
   25.76 -}
   25.77 -
   25.78 -uint8 *
   25.79 -Code::safepointAt(unsigned pcOffset)
   25.80 -{
   25.81 -    // Only specific opcodes may have safepoints. Asking for a safepoint at
   25.82 -    // any other position indicates a failure to mark that position as a
   25.83 -    // safepoint, which is a bug.
   25.84 -#ifndef NDEBUG
   25.85 -    Opcode op = Opcode(*(start() + pcOffset));
   25.86 -    assert(op == OP_CALL ||
   25.87 -           op == OP_NEWFIXED ||
   25.88 -           op == OP_NEWEMPTY ||
   25.89 -           op == OP_NEWSIZED ||
   25.90 -           op == OP_VARREF_LIFO ||
   25.91 -           op == OP_ARGREF_LIFO ||
   25.92 -           op == OP_SLOTREF_LIFO ||
   25.93 -           op == OP_COPYARRAY ||
   25.94 -           op == OP_CALLNATIVE ||
   25.95 -           op == OP_PUBLIC);
   25.96 -#endif
   25.97 -
   25.98 -    if (!safepoints_)
   25.99 -        return NULL;
  25.100 -
  25.101 -    size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth());
  25.102 -    assert(!(safepoints_->length() % bytesPerSafepoint));
  25.103 -
  25.104 -    size_t count = safepoints_->length() / bytesPerSafepoint;
  25.105 -
  25.106 -    void *result = bsearch(&pcOffset,
  25.107 -                           safepoints_->raw(),
  25.108 -                           count,
  25.109 -                           bytesPerSafepoint,
  25.110 -                           CompareSafepoints);
  25.111 -
  25.112 -    if (!result)
  25.113 -        return NULL;
  25.114 -
  25.115 -    assert(*reinterpret_cast<unsigned *>(result) == pcOffset);
  25.116 -
  25.117 -    return Address(result) + sizeof(unsigned);
  25.118 -}
  25.119 -
  25.120 -SourcePosition
  25.121 -Code::pcToSource(unsigned pc)
  25.122 -{
  25.123 -    assert(pc < bytecode_->length());
  25.124 -
  25.125 -    CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length());
  25.126 -
  25.127 -    unsigned line = 1;
  25.128 -    unsigned col = 0;
  25.129 -    unsigned curPc = 0;
  25.130 -    while (!reader.done()) {
  25.131 -        curPc += reader.readUint32();
  25.132 -        if (curPc > pc)
  25.133 -            break;
  25.134 -
  25.135 -        line = reader.readUint32();
  25.136 -        col = reader.readUint32();
  25.137 -    }
  25.138 -
  25.139 -    return SourcePosition(lineNumber_ + line, col);
  25.140 -}
  25.141 -
  25.142 -// All jumps must be the same length.
  25.143 -STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH);
  25.144 -STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH);
  25.145 -
  25.146 -void
  25.147 -ke::Disassemble(Code *code, FILE *fp)
  25.148 -{
  25.149 -    bytecode *pc = code->start();
  25.150 -    for (;;) {
  25.151 -        Opcode op = Opcode(*pc);
  25.152 -
  25.153 -        fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name);
  25.154 -
  25.155 -        switch (op) {
  25.156 -          case OP_NOP:
  25.157 -          case OP_RETURN:
  25.158 -          case OP_RETURNVOID:
  25.159 -          case OP_ADD:
  25.160 -          case OP_SUB:
  25.161 -          case OP_MUL:
  25.162 -          case OP_DIV:
  25.163 -          case OP_ADD_F:
  25.164 -          case OP_SUB_F:
  25.165 -          case OP_MUL_F:
  25.166 -          case OP_DIV_F:
  25.167 -          case OP_CVT_I2F:
  25.168 -          case OP_CVT_I2B:
  25.169 -          case OP_POP:
  25.170 -          case OP_GETELEM:
  25.171 -          case OP_SETELEM:
  25.172 -          case OP_SHL:
  25.173 -          case OP_SHR:
  25.174 -          case OP_USHR:
  25.175 -          case OP_BITAND:
  25.176 -          case OP_BITOR:
  25.177 -          case OP_BITXOR:
  25.178 -          case OP_GETREF_I:
  25.179 -          case OP_SETREF_I:
  25.180 -          case OP_GETREF_F:
  25.181 -          case OP_SETREF_F:
  25.182 -          case OP_SLOTREF_LIFO:
  25.183 -          case OP_COPYARRAY:
  25.184 -          case OP_COPYSTRUCT:
  25.185 -          case OP_DUP:
  25.186 -          case OP_DUP2:
  25.187 -          case OP_SWAP:
  25.188 -          case OP_ROLL3:
  25.189 -          case OP_PICK2:
  25.190 -          case OP_PICK3:
  25.191 -          case OP_CALL:
  25.192 -          case OP_LT:
  25.193 -          case OP_LE:
  25.194 -          case OP_GE:
  25.195 -          case OP_GT:
  25.196 -          case OP_EQ:
  25.197 -          case OP_NE:
  25.198 -          case OP_LT_F:
  25.199 -          case OP_LE_F:
  25.200 -          case OP_GE_F:
  25.201 -          case OP_GT_F:
  25.202 -          case OP_EQ_F:
  25.203 -          case OP_NE_F:
  25.204 -          case OP_BITNOT:
  25.205 -          case OP_NOT:
  25.206 -          case OP_NOT_F:
  25.207 -          case OP_NEG:
  25.208 -          case OP_NEG_F:
  25.209 -          case OP_MOD:
  25.210 -          case OP_BITCAST:
  25.211 -          case OP_TRUE:
  25.212 -          case OP_FALSE:
  25.213 -          case OP_SIZEOF:
  25.214 -          case OP_PUBLIC:
  25.215 -          case OP_LEAVELOOP:
  25.216 -          case OP_DUPARRAY:
  25.217 -          case OP_DEPARRAY:
  25.218 -            break;
  25.219 -
  25.220 -          case OP_ENTERLOOP:
  25.221 -            if (pc[1])
  25.222 -              fprintf(fp, "; lifo region");
  25.223 -            break;
  25.224 -
  25.225 -          case OP_STOP:
  25.226 -            fprintf(fp, "\n");
  25.227 -            break;
  25.228 -
  25.229 -          case OP_INT:
  25.230 -            fprintf(fp, "%d", READ_INT32(pc));
  25.231 -            break;
  25.232 -
  25.233 -          case OP_FLOAT:
  25.234 -            fprintf(fp, "%f", READ_FLOAT(pc));
  25.235 -            break;
  25.236 -
  25.237 -          case OP_JT:
  25.238 -          case OP_JF:
  25.239 -          case OP_JUMP:
  25.240 -          case OP_CONTINUE:
  25.241 -          case OP_BREAK:
  25.242 -            fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc));
  25.243 -            break;
  25.244 -
  25.245 -          case OP_NEWFIXED:
  25.246 -          case OP_NEWEMPTY:
  25.247 -          case OP_NEWSIZED:
  25.248 -          {
  25.249 -            Heap::Tenure tenure = (Heap::Tenure)pc[1];
  25.250 -            //ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1)));
  25.251 -            if (tenure == Heap::Tenure_Stack)
  25.252 -                fprintf(fp, " ; lifo");
  25.253 -            else if (tenure == Heap::Tenure_Old)
  25.254 -                fprintf(fp, " ; pretenured");
  25.255 -            else if (tenure == Heap::Tenure_Default)
  25.256 -                fprintf(fp, " ; newborn");
  25.257 -            break;
  25.258 -          }
  25.259 -
  25.260 -          case OP_NEWSTRUCT:
  25.261 -          {
  25.262 -            Heap::Tenure tenure = (Heap::Tenure)pc[1];
  25.263 -            StructMap *map = StructMap::cast(code->map(READ_UINT32(pc + 1)));
  25.264 -            fprintf(fp, "%s", StructType::cast(map->type())->name()->chars());
  25.265 -            if (tenure == Heap::Tenure_Stack)
  25.266 -                fprintf(fp, " ; lifo");
  25.267 -            else if (tenure == Heap::Tenure_Old)
  25.268 -                fprintf(fp, " ; pretenured");
  25.269 -            else if (tenure == Heap::Tenure_Default)
  25.270 -                fprintf(fp, " ; newborn");
  25.271 -            break;
  25.272 -          }
  25.273 -
  25.274 -          case OP_GETLOCAL:
  25.275 -          case OP_SETLOCAL:
  25.276 -          case OP_GETARG:
  25.277 -          case OP_SETARG:
  25.278 -          case OP_SAVELIFO:
  25.279 -          case OP_UNWINDLIFO:
  25.280 -          case OP_VARREF_LIFO:
  25.281 -          case OP_ARGREF_LIFO:
  25.282 -          case OP_OBJECT:
  25.283 -          case OP_GETFIELD:
  25.284 -          case OP_SETFIELD:
  25.285 -            fprintf(fp, "%u", READ_UINT32(pc));
  25.286 -            break;
  25.287 -
  25.288 -          case OP_CALLNATIVE:
  25.289 -          {
  25.290 -            unsigned argc = READ_UINT32(pc);
  25.291 -            fprintf(fp, " ; %u args", argc);
  25.292 -            break;
  25.293 -          }
  25.294 -
  25.295 -          case OP_TABLESWITCH:
  25.296 -          {
  25.297 -            int low = READ_TABLESWITCH_LOW(pc);
  25.298 -            int high = READ_TABLESWITCH_HIGH(pc);
  25.299 -            fprintf(fp, "%d, %d\n", low, high);
  25.300 -            break;
  25.301 -          }
  25.302 -
  25.303 -          case OP_GETGLOBAL:
  25.304 -          case OP_SETGLOBAL:
  25.305 -          {
  25.306 -            unsigned index = READ_UINT32(pc);
  25.307 -            fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars());
  25.308 -            break;
  25.309 -          }
  25.310 -
  25.311 -          case OP_IMPORT:
  25.312 -          {
  25.313 -            unsigned index = READ_UINT32(pc);
  25.314 -            FixedArray *path = code->module()->importPathAt(index);
  25.315 -            fprintf(fp, " ; ");
  25.316 -            for (unsigned i = 0; i < path->length(); i++) {
  25.317 -                fprintf(fp, "%s", String::cast(path->at(i))->chars());
  25.318 -                if (i != path->length() - 1)
  25.319 -                    fprintf(fp, ".");
  25.320 -            }
  25.321 -            break;
  25.322 -          }
  25.323 -
  25.324 -          default:
  25.325 -            // Unknown opcode!
  25.326 -            assert(false);
  25.327 -            return;
  25.328 -        }
  25.329 -
  25.330 -        if (op == OP_STOP)
  25.331 -            break;
  25.332 -
  25.333 -        fprintf(fp, "\n");
  25.334 -        pc += OpcodeInfo[op].length;
  25.335 -        assert(pc < code->start() + code->length());
  25.336 -    }
  25.337 -
  25.338 -    fprintf(fp, "\nSafepoints:\n");
  25.339 -    ByteArray *safepoints = code->safepoints();
  25.340 -    if (safepoints) {
  25.341 -        size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth());
  25.342 -        for (size_t i = 0; i < nsafepoints; i++) {
  25.343 -            Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i;
  25.344 -            fprintf(fp, "%4d: ", *reinterpret_cast<unsigned *>(address));
  25.345 -            unsigned char *bits = (unsigned char *)(address + sizeof(unsigned));
  25.346 -            for (unsigned j = 0; j < code->maxStackDepth(); j++) {
  25.347 -                if (bits[j / 8] & (1 << (j % 8)))
  25.348 -                    fprintf(fp, "%d ", j);
  25.349 -            }
  25.350 -            fprintf(fp, "\n");
  25.351 -        }
  25.352 -    }
  25.353 -}
  25.354 +/* vim: set ts=4 sw=4 tw=99 et:
  25.355 + *
  25.356 + * Copyright (C) 2012 David Anderson
  25.357 + *
  25.358 + * This file is part of JITCraft.
  25.359 + *
  25.360 + * JITCraft is free software: you can redistribute it and/or modify it under
  25.361 + * the terms of the GNU General Public License as published by the Free
  25.362 + * Software Foundation, either version 3 of the License, or (at your option)
  25.363 + * any later version.
  25.364 + * 
  25.365 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  25.366 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  25.367 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  25.368 + *
  25.369 + * You should have received a copy of the GNU General Public License along with
  25.370 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  25.371 + */
  25.372 +#include <stdlib.h>
  25.373 +#include "Opcodes.h"
  25.374 +#include "Utility.h"
  25.375 +#include "Code.h"
  25.376 +#include "Zone.h"
  25.377 +#include "Array.h"
  25.378 +#include "Strings.h"
  25.379 +#include "CompactBuffer.h"
  25.380 +#include "Structures.h"
  25.381 +#include "Modules.h"
  25.382 +#include "Heap-inl.h"
  25.383 +
  25.384 +using namespace ke;
  25.385 +
  25.386 +OpInfo ke::OpcodeInfo[] =
  25.387 +{
  25.388 +#define OPDEF(name, text, length, uses, defs) \
  25.389 +    {text, length, uses, defs},
  25.390 +#include "Opcodes.tbl"
  25.391 +#undef OPDEF
  25.392 +};
  25.393 +
  25.394 +Code *
  25.395 +Code::New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
  25.396 +          Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
  25.397 +          unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap)
  25.398 +{
  25.399 +    Local<Code> code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old)));
  25.400 +    if (!code)
  25.401 +        return NULL;
  25.402 +
  25.403 +    code->bytecode_ = bytecode;
  25.404 +    code->locals_ = locals;
  25.405 +    code->objects_ = objects;
  25.406 +    code->maxStackDepth_ = maxStackDepth;
  25.407 +    code->module_ = NULL;
  25.408 +    code->safepoints_ = safepoints;
  25.409 +    code->sourcemap_ = sourcemap;
  25.410 +    code->lineNumber_ = 0;
  25.411 +    code->strings_ = strings;
  25.412 +    code->maxLoopDepth_ = maxLoopDepth;
  25.413 +    return code;
  25.414 +}
  25.415 +
  25.416 +static int
  25.417 +CompareSafepoints(const void *a, const void *b)
  25.418 +{
  25.419 +    const unsigned *sa = reinterpret_cast<const unsigned *>(a);
  25.420 +    const unsigned *sb = reinterpret_cast<const unsigned *>(b);
  25.421 +    if (*sa > *sb)
  25.422 +        return 1;
  25.423 +    if (*sa == *sb)
  25.424 +        return 0;
  25.425 +    return -1;
  25.426 +}
  25.427 +
  25.428 +uint8 *
  25.429 +Code::safepointAt(unsigned pcOffset)
  25.430 +{
  25.431 +    // Only specific opcodes may have safepoints. Asking for a safepoint at
  25.432 +    // any other position indicates a failure to mark that position as a
  25.433 +    // safepoint, which is a bug.
  25.434 +#ifndef NDEBUG
  25.435 +    Opcode op = Opcode(*(start() + pcOffset));
  25.436 +    assert(op == OP_CALL ||
  25.437 +           op == OP_NEWFIXED ||
  25.438 +           op == OP_NEWEMPTY ||
  25.439 +           op == OP_NEWSIZED ||
  25.440 +           op == OP_VARREF_LIFO ||
  25.441 +           op == OP_ARGREF_LIFO ||
  25.442 +           op == OP_SLOTREF_LIFO ||
  25.443 +           op == OP_COPYARRAY ||
  25.444 +           op == OP_CALLNATIVE ||
  25.445 +           op == OP_PUBLIC);
  25.446 +#endif
  25.447 +
  25.448 +    if (!safepoints_)
  25.449 +        return NULL;
  25.450 +
  25.451 +    size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth());
  25.452 +    assert(!(safepoints_->length() % bytesPerSafepoint));
  25.453 +
  25.454 +    size_t count = safepoints_->length() / bytesPerSafepoint;
  25.455 +
  25.456 +    void *result = bsearch(&pcOffset,
  25.457 +                           safepoints_->raw(),
  25.458 +                           count,
  25.459 +                           bytesPerSafepoint,
  25.460 +                           CompareSafepoints);
  25.461 +
  25.462 +    if (!result)
  25.463 +        return NULL;
  25.464 +
  25.465 +    assert(*reinterpret_cast<unsigned *>(result) == pcOffset);
  25.466 +
  25.467 +    return Address(result) + sizeof(unsigned);
  25.468 +}
  25.469 +
  25.470 +SourcePosition
  25.471 +Code::pcToSource(unsigned pc)
  25.472 +{
  25.473 +    assert(pc < bytecode_->length());
  25.474 +
  25.475 +    CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length());
  25.476 +
  25.477 +    unsigned line = 1;
  25.478 +    unsigned col = 0;
  25.479 +    unsigned curPc = 0;
  25.480 +    while (!reader.done()) {
  25.481 +        curPc += reader.readUint32();
  25.482 +        if (curPc > pc)
  25.483 +            break;
  25.484 +
  25.485 +        line = reader.readUint32();
  25.486 +        col = reader.readUint32();
  25.487 +    }
  25.488 +
  25.489 +    return SourcePosition(lineNumber_ + line, col);
  25.490 +}
  25.491 +
  25.492 +// All jumps must be the same length.
  25.493 +STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH);
  25.494 +STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH);
  25.495 +
  25.496 +void
  25.497 +ke::Disassemble(Code *code, FILE *fp)
  25.498 +{
  25.499 +    bytecode *pc = code->start();
  25.500 +    for (;;) {
  25.501 +        Opcode op = Opcode(*pc);
  25.502 +
  25.503 +        fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name);
  25.504 +
  25.505 +        switch (op) {
  25.506 +          case OP_NOP:
  25.507 +          case OP_RETURN:
  25.508 +          case OP_RETURNVOID:
  25.509 +          case OP_ADD:
  25.510 +          case OP_SUB:
  25.511 +          case OP_MUL:
  25.512 +          case OP_DIV:
  25.513 +          case OP_ADD_F:
  25.514 +          case OP_SUB_F:
  25.515 +          case OP_MUL_F:
  25.516 +          case OP_DIV_F:
  25.517 +          case OP_CVT_I2F:
  25.518 +          case OP_CVT_I2B:
  25.519 +          case OP_POP:
  25.520 +          case OP_GETELEM:
  25.521 +          case OP_SETELEM:
  25.522 +          case OP_SHL:
  25.523 +          case OP_SHR:
  25.524 +          case OP_USHR:
  25.525 +          case OP_BITAND:
  25.526 +          case OP_BITOR:
  25.527 +          case OP_BITXOR:
  25.528 +          case OP_GETREF_I:
  25.529 +          case OP_SETREF_I:
  25.530 +          case OP_GETREF_F:
  25.531 +          case OP_SETREF_F:
  25.532 +          case OP_SLOTREF_LIFO:
  25.533 +          case OP_COPYARRAY:
  25.534 +          case OP_COPYSTRUCT:
  25.535 +          case OP_DUP:
  25.536 +          case OP_DUP2:
  25.537 +          case OP_SWAP:
  25.538 +          case OP_ROLL3:
  25.539 +          case OP_PICK2:
  25.540 +          case OP_PICK3:
  25.541 +          case OP_CALL:
  25.542 +          case OP_LT:
  25.543 +          case OP_LE:
  25.544 +          case OP_GE:
  25.545 +          case OP_GT:
  25.546 +          case OP_EQ:
  25.547 +          case OP_NE:
  25.548 +          case OP_LT_F:
  25.549 +          case OP_LE_F:
  25.550 +          case OP_GE_F:
  25.551 +          case OP_GT_F:
  25.552 +          case OP_EQ_F:
  25.553 +          case OP_NE_F:
  25.554 +          case OP_BITNOT:
  25.555 +          case OP_NOT:
  25.556 +          case OP_NOT_F:
  25.557 +          case OP_NEG:
  25.558 +          case OP_NEG_F:
  25.559 +          case OP_MOD:
  25.560 +          case OP_BITCAST:
  25.561 +          case OP_TRUE:
  25.562 +          case OP_FALSE:
  25.563 +          case OP_SIZEOF:
  25.564 +          case OP_PUBLIC:
  25.565 +          case OP_LEAVELOOP:
  25.566 +          case OP_DUPARRAY:
  25.567 +          case OP_DEPARRAY:
  25.568 +            break;
  25.569 +
  25.570 +          case OP_ENTERLOOP:
  25.571 +            if (pc[1])
  25.572 +              fprintf(fp, "; lifo region");
  25.573 +            break;
  25.574 +
  25.575 +          case OP_STOP:
  25.576 +            fprintf(fp, "\n");
  25.577 +            break;
  25.578 +
  25.579 +          case OP_INT:
  25.580 +            fprintf(fp, "%d", READ_INT32(pc));
  25.581 +            break;
  25.582 +
  25.583 +          case OP_FLOAT:
  25.584 +            fprintf(fp, "%f", READ_FLOAT(pc));
  25.585 +            break;
  25.586 +
  25.587 +          case OP_JT:
  25.588 +          case OP_JF:
  25.589 +          case OP_JUMP:
  25.590 +          case OP_CONTINUE:
  25.591 +          case OP_BREAK:
  25.592 +            fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc));
  25.593 +            break;
  25.594 +
  25.595 +          case OP_NEWFIXED:
  25.596 +          case OP_NEWEMPTY:
  25.597 +          case OP_NEWSIZED:
  25.598 +          {
  25.599 +            Heap::Tenure tenure = (Heap::Tenure)pc[1];
  25.600 +            //ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1)));
  25.601 +            if (tenure == Heap::Tenure_Stack)
  25.602 +                fprintf(fp, " ; lifo");
  25.603 +            else if (tenure == Heap::Tenure_Old)
  25.604 +                fprintf(fp, " ; pretenured");
  25.605 +            else if (tenure == Heap::Tenure_Default)
  25.606 +                fprintf(fp, " ; newborn");
  25.607 +            break;
  25.608 +          }
  25.609 +
  25.610 +          case OP_NEWSTRUCT:
  25.611 +          {
  25.612 +            Heap::Tenure tenure = (Heap::Tenure)pc[1];
  25.613 +            StructMap *map = StructMap::cast(code->map(READ_UINT32(pc + 1)));
  25.614 +            fprintf(fp, "%s", StructType::cast(map->type())->name()->chars());
  25.615 +            if (tenure == Heap::Tenure_Stack)
  25.616 +                fprintf(fp, " ; lifo");
  25.617 +            else if (tenure == Heap::Tenure_Old)
  25.618 +                fprintf(fp, " ; pretenured");
  25.619 +            else if (tenure == Heap::Tenure_Default)
  25.620 +                fprintf(fp, " ; newborn");
  25.621 +            break;
  25.622 +          }
  25.623 +
  25.624 +          case OP_GETLOCAL:
  25.625 +          case OP_SETLOCAL:
  25.626 +          case OP_GETARG:
  25.627 +          case OP_SETARG:
  25.628 +          case OP_SAVELIFO:
  25.629 +          case OP_UNWINDLIFO:
  25.630 +          case OP_VARREF_LIFO:
  25.631 +          case OP_ARGREF_LIFO:
  25.632 +          case OP_OBJECT:
  25.633 +          case OP_GETFIELD:
  25.634 +          case OP_SETFIELD:
  25.635 +            fprintf(fp, "%u", READ_UINT32(pc));
  25.636 +            break;
  25.637 +
  25.638 +          case OP_CALLNATIVE:
  25.639 +          {
  25.640 +            unsigned argc = READ_UINT32(pc);
  25.641 +            fprintf(fp, " ; %u args", argc);
  25.642 +            break;
  25.643 +          }
  25.644 +
  25.645 +          case OP_TABLESWITCH:
  25.646 +          {
  25.647 +            int low = READ_TABLESWITCH_LOW(pc);
  25.648 +            int high = READ_TABLESWITCH_HIGH(pc);
  25.649 +            fprintf(fp, "%d, %d\n", low, high);
  25.650 +            break;
  25.651 +          }
  25.652 +
  25.653 +          case OP_GETGLOBAL:
  25.654 +          case OP_SETGLOBAL:
  25.655 +          {
  25.656 +            unsigned index = READ_UINT32(pc);
  25.657 +            fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars());
  25.658 +            break;
  25.659 +          }
  25.660 +
  25.661 +          case OP_IMPORT:
  25.662 +          {
  25.663 +            unsigned index = READ_UINT32(pc);
  25.664 +            FixedArray *path = code->module()->importPathAt(index);
  25.665 +            fprintf(fp, " ; ");
  25.666 +            for (unsigned i = 0; i < path->length(); i++) {
  25.667 +                fprintf(fp, "%s", String::cast(path->at(i))->chars());
  25.668 +                if (i != path->length() - 1)
  25.669 +                    fprintf(fp, ".");
  25.670 +            }
  25.671 +            break;
  25.672 +          }
  25.673 +
  25.674 +          default:
  25.675 +            // Unknown opcode!
  25.676 +            assert(false);
  25.677 +            return;
  25.678 +        }
  25.679 +
  25.680 +        if (op == OP_STOP)
  25.681 +            break;
  25.682 +
  25.683 +        fprintf(fp, "\n");
  25.684 +        pc += OpcodeInfo[op].length;
  25.685 +        assert(pc < code->start() + code->length());
  25.686 +    }
  25.687 +
  25.688 +    fprintf(fp, "\nSafepoints:\n");
  25.689 +    ByteArray *safepoints = code->safepoints();
  25.690 +    if (safepoints) {
  25.691 +        size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth());
  25.692 +        for (size_t i = 0; i < nsafepoints; i++) {
  25.693 +            Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i;
  25.694 +            fprintf(fp, "%4d: ", *reinterpret_cast<unsigned *>(address));
  25.695 +            unsigned char *bits = (unsigned char *)(address + sizeof(unsigned));
  25.696 +            for (unsigned j = 0; j < code->maxStackDepth(); j++) {
  25.697 +                if (bits[j / 8] & (1 << (j % 8)))
  25.698 +                    fprintf(fp, "%d ", j);
  25.699 +            }
  25.700 +            fprintf(fp, "\n");
  25.701 +        }
  25.702 +    }
  25.703 +}
    26.1 --- a/src/Opcodes.h	Mon Jun 10 00:46:29 2013 +0100
    26.2 +++ b/src/Opcodes.h	Mon Jun 10 01:04:43 2013 +0100
    26.3 @@ -1,113 +1,113 @@
    26.4 -/* vim: set ts=4 sw=4 tw=99 et:
    26.5 - *
    26.6 - * Copyright (C) 2012 David Anderson
    26.7 - *
    26.8 - * This file is part of SourcePawn.
    26.9 - *
   26.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   26.11 - * the terms of the GNU General Public License as published by the Free
   26.12 - * Software Foundation, either version 3 of the License, or (at your option)
   26.13 - * any later version.
   26.14 - * 
   26.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   26.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   26.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   26.18 - *
   26.19 - * You should have received a copy of the GNU General Public License along with
   26.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   26.21 - */
   26.22 -#ifndef _include_opcodes_h_
   26.23 -#define _include_opcodes_h_
   26.24 -
   26.25 -#include <assert.h>
   26.26 -#include <stdio.h>
   26.27 -
   26.28 -namespace ke {
   26.29 -    
   26.30 -struct SourcePosition
   26.31 -{
   26.32 -    int line;
   26.33 -    int col;
   26.34 -
   26.35 -    SourcePosition()
   26.36 -      : line(-1),
   26.37 -        col(-1)
   26.38 -    {
   26.39 -    }
   26.40 -
   26.41 -    SourcePosition(unsigned line, unsigned col)
   26.42 -      : line(line),
   26.43 -        col(col)
   26.44 -    {
   26.45 -    }
   26.46 -};
   26.47 -
   26.48 -enum Opcode
   26.49 -{
   26.50 -#define OPDEF(name, text, length, uses, defs)   \
   26.51 -    name,
   26.52 -#include "Opcodes.tbl"
   26.53 -#undef OPDEF
   26.54 -    OPCODES_TOTAL
   26.55 -};
   26.56 -
   26.57 -#define OPDEF(name, text, length, uses, defs)   \
   26.58 -static const unsigned name##_LENGTH = length;
   26.59 -#include "Opcodes.tbl"
   26.60 -#undef OPDEF
   26.61 -
   26.62 -struct OpInfo
   26.63 -{
   26.64 -    const char *name;
   26.65 -    int length;
   26.66 -    int nuses;
   26.67 -    int ndefs;
   26.68 -};
   26.69 -
   26.70 -typedef unsigned char bytecode;
   26.71 -
   26.72 -extern OpInfo OpcodeInfo[];
   26.73 -
   26.74 -static const unsigned MAX_TABLESWITCH_ENTRIES = 256;
   26.75 -
   26.76 -static inline unsigned
   26.77 -TableSwitchEntries(int low, int high)
   26.78 -{
   26.79 -    return unsigned(high - low) + 1;
   26.80 -}
   26.81 -
   26.82 -static inline int
   26.83 -READ_INT32(bytecode *pc)
   26.84 -{
   26.85 -    return *reinterpret_cast<int *>(pc + 1);
   26.86 -}
   26.87 -static inline unsigned
   26.88 -READ_UINT32(bytecode *pc)
   26.89 -{
   26.90 -    return *reinterpret_cast<unsigned *>(pc + 1);
   26.91 -}
   26.92 -static inline float
   26.93 -READ_FLOAT(bytecode *pc)
   26.94 -{
   26.95 -    return *reinterpret_cast<float *>(pc + 1);
   26.96 -}
   26.97 -
   26.98 -static inline int
   26.99 -READ_TABLESWITCH_LOW(bytecode *pc)
  26.100 -{
  26.101 -    return READ_INT32(pc);
  26.102 -}
  26.103 -
  26.104 -static inline int
  26.105 -READ_TABLESWITCH_HIGH(bytecode *pc)
  26.106 -{
  26.107 -    return READ_INT32(pc + sizeof(int));
  26.108 -}
  26.109 -
  26.110 -class Code;
  26.111 -
  26.112 -void Disassemble(Code *code, FILE *fp);
  26.113 -
  26.114 -}
  26.115 -
  26.116 -#endif // _include_opcodes_h_
  26.117 +/* vim: set ts=4 sw=4 tw=99 et:
  26.118 + *
  26.119 + * Copyright (C) 2012 David Anderson
  26.120 + *
  26.121 + * This file is part of SourcePawn.
  26.122 + *
  26.123 + * SourcePawn is free software: you can redistribute it and/or modify it under
  26.124 + * the terms of the GNU General Public License as published by the Free
  26.125 + * Software Foundation, either version 3 of the License, or (at your option)
  26.126 + * any later version.
  26.127 + * 
  26.128 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  26.129 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  26.130 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  26.131 + *
  26.132 + * You should have received a copy of the GNU General Public License along with
  26.133 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  26.134 + */
  26.135 +#ifndef _include_opcodes_h_
  26.136 +#define _include_opcodes_h_
  26.137 +
  26.138 +#include <assert.h>
  26.139 +#include <stdio.h>
  26.140 +
  26.141 +namespace ke {
  26.142 +    
  26.143 +struct SourcePosition
  26.144 +{
  26.145 +    int line;
  26.146 +    int col;
  26.147 +
  26.148 +    SourcePosition()
  26.149 +      : line(-1),
  26.150 +        col(-1)
  26.151 +    {
  26.152 +    }
  26.153 +
  26.154 +    SourcePosition(unsigned line, unsigned col)
  26.155 +      : line(line),
  26.156 +        col(col)
  26.157 +    {
  26.158 +    }
  26.159 +};
  26.160 +
  26.161 +enum Opcode
  26.162 +{
  26.163 +#define OPDEF(name, text, length, uses, defs)   \
  26.164 +    name,
  26.165 +#include "Opcodes.tbl"
  26.166 +#undef OPDEF
  26.167 +    OPCODES_TOTAL
  26.168 +};
  26.169 +
  26.170 +#define OPDEF(name, text, length, uses, defs)   \
  26.171 +static const unsigned name##_LENGTH = length;
  26.172 +#include "Opcodes.tbl"
  26.173 +#undef OPDEF
  26.174 +
  26.175 +struct OpInfo
  26.176 +{
  26.177 +    const char *name;
  26.178 +    int length;
  26.179 +    int nuses;
  26.180 +    int ndefs;
  26.181 +};
  26.182 +
  26.183 +typedef unsigned char bytecode;
  26.184 +
  26.185 +extern OpInfo OpcodeInfo[];
  26.186 +
  26.187 +static const unsigned MAX_TABLESWITCH_ENTRIES = 256;
  26.188 +
  26.189 +static inline unsigned
  26.190 +TableSwitchEntries(int low, int high)
  26.191 +{
  26.192 +    return unsigned(high - low) + 1;
  26.193 +}
  26.194 +
  26.195 +static inline int
  26.196 +READ_INT32(bytecode *pc)
  26.197 +{
  26.198 +    return *reinterpret_cast<int *>(pc + 1);
  26.199 +}
  26.200 +static inline unsigned
  26.201 +READ_UINT32(bytecode *pc)
  26.202 +{
  26.203 +    return *reinterpret_cast<unsigned *>(pc + 1);
  26.204 +}
  26.205 +static inline float
  26.206 +READ_FLOAT(bytecode *pc)
  26.207 +{
  26.208 +    return *reinterpret_cast<float *>(pc + 1);
  26.209 +}
  26.210 +
  26.211 +static inline int
  26.212 +READ_TABLESWITCH_LOW(bytecode *pc)
  26.213 +{
  26.214 +    return READ_INT32(pc);
  26.215 +}
  26.216 +
  26.217 +static inline int
  26.218 +READ_TABLESWITCH_HIGH(bytecode *pc)
  26.219 +{
  26.220 +    return READ_INT32(pc + sizeof(int));
  26.221 +}
  26.222 +
  26.223 +class Code;
  26.224 +
  26.225 +void Disassemble(Code *code, FILE *fp);
  26.226 +
  26.227 +}
  26.228 +
  26.229 +#endif // _include_opcodes_h_
    27.1 --- a/src/Packages.cpp	Mon Jun 10 00:46:29 2013 +0100
    27.2 +++ b/src/Packages.cpp	Mon Jun 10 01:04:43 2013 +0100
    27.3 @@ -1,226 +1,226 @@
    27.4 -/*
    27.5 - * Copyright (C) 2012 David Anderson
    27.6 - *
    27.7 - * This file is part of SourcePawn.
    27.8 - *
    27.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   27.10 - * the terms of the GNU General Public License as published by the Free
   27.11 - * Software Foundation, either version 3 of the License, or (at your option)
   27.12 - * any later version.
   27.13 - * 
   27.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   27.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   27.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   27.17 - *
   27.18 - * You should have received a copy of the GNU General Public License along with
   27.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   27.20 - */
   27.21 -#include <string.h>
   27.22 -#include "Zone.h"
   27.23 -#include "Heap.h"
   27.24 -#include "Strings.h"
   27.25 -#include "Modules.h"
   27.26 -#include "Packages.h"
   27.27 -#include "FileSystem.h"
   27.28 -#include "List.h"
   27.29 -#include "Heap-inl.h"
   27.30 -#include "Handles-inl.h"
   27.31 -
   27.32 -using namespace ke;
   27.33 -
   27.34 -Package *
   27.35 -Package::NewNormalized(Zone *zone, Handle<Package> parent, Handle<String> path, Handle<String> name, unsigned flags)
   27.36 -{
   27.37 -    Local<Package> package(zone, Package::cast(zone->allocate(MapKind_Package, sizeof(Package), Heap::Tenure_Old)));
   27.38 -    if (!package)
   27.39 -        return NULL;
   27.40 -
   27.41 -    // :TODO: assert path, name are atoms.
   27.42 -
   27.43 -    package->flags_ = flags;
   27.44 -    package->name_ = name;
   27.45 -    package->parent_ = parent;
   27.46 -    package->path_ = path;
   27.47 -    package->nativeIdentity_ = parent ? parent->getNativeIdentity() : NULL;
   27.48 -
   27.49 -    return package;
   27.50 -}
   27.51 -
   27.52 -Package *
   27.53 -Package::New(Zone *zone, Handle<Package> parent, const char *path, Handle<String> name, unsigned flags)
   27.54 -{
   27.55 -    Local<String> strpath(zone, zone->makeSymbol(path));
   27.56 -    if (!strpath)
   27.57 -        return NULL;
   27.58 -
   27.59 -    return Package::NewNormalized(zone, parent, strpath, name, flags);
   27.60 -}
   27.61 -
   27.62 -bool
   27.63 -Package::add(Zone *zone, Handle<Importable> obj)
   27.64 -{
   27.65 -    Local<Package> pkg(zone, this);
   27.66 -
   27.67 -    assert(obj->parent() == pkg);
   27.68 -
   27.69 -    if (!pkg->contents_) {
   27.70 -        pkg->contents_ = List<Importable>::New(zone);
   27.71 -        if (!pkg->contents_)
   27.72 -            return false;
   27.73 -    }
   27.74 -
   27.75 -#ifndef NDEBUG
   27.76 -    // Assert no duplicate names.
   27.77 -    for (unsigned i = 0; i < pkg->contents_->length(); i++)
   27.78 -        assert(pkg->contents_->at(i)->name() != obj->name());
   27.79 -#endif
   27.80 -
   27.81 -    if (!pkg->contents_->append(zone, obj))
   27.82 -        return false;
   27.83 -
   27.84 -    return true;
   27.85 -}
   27.86 -
   27.87 -Importable *
   27.88 -Package::import(Handle<String> name)
   27.89 -{
   27.90 -    if (!contents_)
   27.91 -        return NULL;
   27.92 -    
   27.93 -    for (unsigned i = 0; i < contents_->length(); i++) {
   27.94 -        Importable *obj = contents_->at(i);
   27.95 -        if (obj->isPackage() && Package::cast(obj)->name() == name)
   27.96 -            return obj;
   27.97 -        if (obj->isModule() && Module::cast(obj)->name() == name)
   27.98 -            return obj;
   27.99 -    }
  27.100 -
  27.101 -    return NULL;
  27.102 -}
  27.103 -
  27.104 -PackageCache::PackageCache(Zone *zone)
  27.105 -  : zone_(zone)
  27.106 -{
  27.107 -}
  27.108 -
  27.109 -bool
  27.110 -PackageCache::initialize()
  27.111 -{
  27.112 -    return true;
  27.113 -}
  27.114 -
  27.115 -void
  27.116 -PackageCache::accept(VirtualObjectVisitor *visitor)
  27.117 -{
  27.118 -    for (size_t i = 0; i < roots_.length(); i++)
  27.119 -        visitor->visit(roots_[i].address());
  27.120 -}
  27.121 -
  27.122 -bool
  27.123 -PackageCache::checkfs(Handle<Package> package, PathComponent *path, Importable **out)
  27.124 -{
  27.125 -    AutoFree<char> left(strdup(package->path()->chars()));
  27.126 -    AutoFree<char> right(strdup(path->name->chars()));
  27.127 -    AutoFree<char> result;
  27.128 -
  27.129 -    if (!JoinPaths(zone_, result, *left, *right))
  27.130 -        return false;
  27.131 -
  27.132 -    OS::PathType type = OS::InspectPath(*result);
  27.133 -    if (type == OS::Path_Folder) {
  27.134 -        // If there is a folder matching this path, create a new subpackage,
  27.135 -        // and then either return it (if this is the last link), or keep
  27.136 -        // trying to import the rest of the path.
  27.137 -        Local<String> strpath(zone_, zone_->makeSymbol(*result));
  27.138 -        Local<Package> subpackage(zone_, Package::NewNormalized(zone_, package, strpath, path->name, Package::Normal));
  27.139 -        if (!subpackage)
  27.140 -            return false;
  27.141 -        if (!path->next) {
  27.142 -            *out = subpackage;
  27.143 -            return true;
  27.144 -        }
  27.145 -        return import(subpackage, path->next, out);
  27.146 -    }
  27.147 -
  27.148 -    // Otherwise, look for a file ending in ".sp".
  27.149 -    AutoFree<char> filepath((char *)zone_->malloc(strlen(*result) + strlen(".sp") + 1));
  27.150 -    if (!*filepath)
  27.151 -        return false;
  27.152 -
  27.153 -    strcpy(*filepath, *result);
  27.154 -    strcat(*filepath, ".sp");
  27.155 -
  27.156 -    type = OS::InspectPath(*filepath);
  27.157 -    if (type != OS::Path_File)
  27.158 -        return true;
  27.159 -
  27.160 -    // Create a new, empty module.
  27.161 -    Local<String> strpath(zone_, zone_->makeSymbol(*filepath));
  27.162 -    if (!strpath)
  27.163 -        return false;
  27.164 -
  27.165 -    Local<Module> module(zone_, Module::New(zone_, package, strpath, path->name));
  27.166 -    if (!module || !package->add(zone_, module))
  27.167 -        return false;
  27.168 -
  27.169 -    *out = module;
  27.170 -    return true;
  27.171 -}
  27.172 -
  27.173 -bool
  27.174 -PackageCache::import(Handle<Package> package, PathComponent *path, Importable **out)
  27.175 -{
  27.176 -    // If the package is jailed, none of its imports are visible.
  27.177 -    if (package->jailed())
  27.178 -        return true;
  27.179 -
  27.180 -    Local<Importable> obj(zone_, package->import(path->name));
  27.181 -    if (!obj) {
  27.182 -        // We couldn't find anything. Try the file system.
  27.183 -        if (!checkfs(package, path, out))
  27.184 -            return false;
  27.185 -
  27.186 -        // checkfs will keep trying to import, so if it fails, we just
  27.187 -        // propagate up.
  27.188 -        return true;
  27.189 -    }
  27.190 -
  27.191 -    // If we found an existing module, or the path has no next link, then
  27.192 -    // we can't go any further.
  27.193 -    if (obj->is(MapKind_Module) || !path->next) {
  27.194 -        *out = obj;
  27.195 -        return true;
  27.196 -    }
  27.197 -
  27.198 -    Local<Package> subpackage(zone_, Package::cast(obj));
  27.199 -    return import(subpackage, path->next, out);
  27.200 -}
  27.201 -
  27.202 -bool
  27.203 -PackageCache::findOrAdd(Handle<Package> package, PathComponent *path, Importable **out)
  27.204 -{
  27.205 -    // Local rooters should have initialized this, but whatever.
  27.206 -    assert(*out == NULL);
  27.207 -
  27.208 -    // Try to import locally first.
  27.209 -    if (!import(package, path, out))
  27.210 -        return false;
  27.211 -    if (*out)
  27.212 -        return true;
  27.213 -
  27.214 -    // Otherwise, search system roots.
  27.215 -    Local<Package> root(zone_);
  27.216 -    for (size_t i = 0; i < roots_.length(); i++) {
  27.217 -        root = roots_[i];
  27.218 -        if (!import(root, path, out))
  27.219 -            return false;
  27.220 -        if (*out)
  27.221 -            return true;
  27.222 -    }
  27.223 -
  27.224 -    return true;
  27.225 -}
  27.226 -
  27.227 -PackageCache::~PackageCache()
  27.228 -{
  27.229 -}
  27.230 +/*
  27.231 + * Copyright (C) 2012 David Anderson
  27.232 + *
  27.233 + * This file is part of SourcePawn.
  27.234 + *
  27.235 + * SourcePawn is free software: you can redistribute it and/or modify it under
  27.236 + * the terms of the GNU General Public License as published by the Free
  27.237 + * Software Foundation, either version 3 of the License, or (at your option)
  27.238 + * any later version.
  27.239 + * 
  27.240 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  27.241 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  27.242 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  27.243 + *
  27.244 + * You should have received a copy of the GNU General Public License along with
  27.245 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  27.246 + */
  27.247 +#include <string.h>
  27.248 +#include "Zone.h"
  27.249 +#include "Heap.h"
  27.250 +#include "Strings.h"
  27.251 +#include "Modules.h"
  27.252 +#include "Packages.h"
  27.253 +#include "FileSystem.h"
  27.254 +#include "List.h"
  27.255 +#include "Heap-inl.h"
  27.256 +#include "Handles-inl.h"
  27.257 +
  27.258 +using namespace ke;
  27.259 +
  27.260 +Package *
  27.261 +Package::NewNormalized(Zone *zone, Handle<Package> parent, Handle<String> path, Handle<String> name, unsigned flags)
  27.262 +{
  27.263 +    Local<Package> package(zone, Package::cast(zone->allocate(MapKind_Package, sizeof(Package), Heap::Tenure_Old)));
  27.264 +    if (!package)
  27.265 +        return NULL;
  27.266 +
  27.267 +    // :TODO: assert path, name are atoms.
  27.268 +
  27.269 +    package->flags_ = flags;
  27.270 +    package->name_ = name;
  27.271 +    package->parent_ = parent;
  27.272 +    package->path_ = path;
  27.273 +    package->nativeIdentity_ = parent ? parent->getNativeIdentity() : NULL;
  27.274 +
  27.275 +    return package;
  27.276 +}
  27.277 +
  27.278 +Package *
  27.279 +Package::New(Zone *zone, Handle<Package> parent, const char *path, Handle<String> name, unsigned flags)
  27.280 +{
  27.281 +    Local<String> strpath(zone, zone->makeSymbol(path));
  27.282 +    if (!strpath)
  27.283 +        return NULL;
  27.284 +
  27.285 +    return Package::NewNormalized(zone, parent, strpath, name, flags);
  27.286 +}
  27.287 +
  27.288 +bool
  27.289 +Package::add(Zone *zone, Handle<Importable> obj)
  27.290 +{
  27.291 +    Local<Package> pkg(zone, this);
  27.292 +
  27.293 +    assert(obj->parent() == pkg);
  27.294 +
  27.295 +    if (!pkg->contents_) {
  27.296 +        pkg->contents_ = List<Importable>::New(zone);
  27.297 +        if (!pkg->contents_)
  27.298 +            return false;
  27.299 +    }
  27.300 +
  27.301 +#ifndef NDEBUG
  27.302 +    // Assert no duplicate names.
  27.303 +    for (unsigned i = 0; i < pkg->contents_->length(); i++)
  27.304 +        assert(pkg->contents_->at(i)->name() != obj->name());
  27.305 +#endif
  27.306 +
  27.307 +    if (!pkg->contents_->append(zone, obj))
  27.308 +        return false;
  27.309 +
  27.310 +    return true;
  27.311 +}
  27.312 +
  27.313 +Importable *
  27.314 +Package::import(Handle<String> name)
  27.315 +{
  27.316 +    if (!contents_)
  27.317 +        return NULL;
  27.318 +    
  27.319 +    for (unsigned i = 0; i < contents_->length(); i++) {
  27.320 +        Importable *obj = contents_->at(i);
  27.321 +        if (obj->isPackage() && Package::cast(obj)->name() == name)
  27.322 +            return obj;
  27.323 +        if (obj->isModule() && Module::cast(obj)->name() == name)
  27.324 +            return obj;
  27.325 +    }
  27.326 +
  27.327 +    return NULL;
  27.328 +}
  27.329 +
  27.330 +PackageCache::PackageCache(Zone *zone)
  27.331 +  : zone_(zone)
  27.332 +{
  27.333 +}
  27.334 +
  27.335 +bool
  27.336 +PackageCache::initialize()
  27.337 +{
  27.338 +    return true;
  27.339 +}
  27.340 +
  27.341 +void
  27.342 +PackageCache::accept(VirtualObjectVisitor *visitor)
  27.343 +{
  27.344 +    for (size_t i = 0; i < roots_.length(); i++)
  27.345 +        visitor->visit(roots_[i].address());
  27.346 +}
  27.347 +
  27.348 +bool
  27.349 +PackageCache::checkfs(Handle<Package> package, PathComponent *path, Importable **out)
  27.350 +{
  27.351 +    AutoFree<char> left(strdup(package->path()->chars()));
  27.352 +    AutoFree<char> right(strdup(path->name->chars()));
  27.353 +    AutoFree<char> result;
  27.354 +
  27.355 +    if (!JoinPaths(zone_, result, *left, *right))
  27.356 +        return false;
  27.357 +
  27.358 +    OS::PathType type = OS::InspectPath(*result);
  27.359 +    if (type == OS::Path_Folder) {
  27.360 +        // If there is a folder matching this path, create a new subpackage,
  27.361 +        // and then either return it (if this is the last link), or keep
  27.362 +        // trying to import the rest of the path.
  27.363 +        Local<String> strpath(zone_, zone_->makeSymbol(*result));
  27.364 +        Local<Package> subpackage(zone_, Package::NewNormalized(zone_, package, strpath, path->name, Package::Normal));
  27.365 +        if (!subpackage)
  27.366 +            return false;
  27.367 +        if (!path->next) {
  27.368 +            *out = subpackage;
  27.369 +            return true;
  27.370 +        }
  27.371 +        return import(subpackage, path->next, out);
  27.372 +    }
  27.373 +
  27.374 +    // Otherwise, look for a file ending in ".sp".
  27.375 +    AutoFree<char> filepath((char *)zone_->malloc(strlen(*result) + strlen(".sp") + 1));
  27.376 +    if (!*filepath)
  27.377 +        return false;
  27.378 +
  27.379 +    strcpy(*filepath, *result);
  27.380 +    strcat(*filepath, ".sp");
  27.381 +
  27.382 +    type = OS::InspectPath(*filepath);
  27.383 +    if (type != OS::Path_File)
  27.384 +        return true;
  27.385 +
  27.386 +    // Create a new, empty module.
  27.387 +    Local<String> strpath(zone_, zone_->makeSymbol(*filepath));
  27.388 +    if (!strpath)
  27.389 +        return false;
  27.390 +
  27.391 +    Local<Module> module(zone_, Module::New(zone_, package, strpath, path->name));
  27.392 +    if (!module || !package->add(zone_, module))
  27.393 +        return false;
  27.394 +
  27.395 +    *out = module;
  27.396 +    return true;
  27.397 +}
  27.398 +
  27.399 +bool
  27.400 +PackageCache::import(Handle<Package> package, PathComponent *path, Importable **out)
  27.401 +{
  27.402 +    // If the package is jailed, none of its imports are visible.
  27.403 +    if (package->jailed())
  27.404 +        return true;
  27.405 +
  27.406 +    Local<Importable> obj(zone_, package->import(path->name));
  27.407 +    if (!obj) {
  27.408 +        // We couldn't find anything. Try the file system.
  27.409 +        if (!checkfs(package, path, out))
  27.410 +            return false;
  27.411 +
  27.412 +        // checkfs will keep trying to import, so if it fails, we just
  27.413 +        // propagate up.
  27.414 +        return true;
  27.415 +    }
  27.416 +
  27.417 +    // If we found an existing module, or the path has no next link, then
  27.418 +    // we can't go any further.
  27.419 +    if (obj->is(MapKind_Module) || !path->next) {
  27.420 +        *out = obj;
  27.421 +        return true;
  27.422 +    }
  27.423 +
  27.424 +    Local<Package> subpackage(zone_, Package::cast(obj));
  27.425 +    return import(subpackage, path->next, out);
  27.426 +}
  27.427 +
  27.428 +bool
  27.429 +PackageCache::findOrAdd(Handle<Package> package, PathComponent *path, Importable **out)
  27.430 +{
  27.431 +    // Local rooters should have initialized this, but whatever.
  27.432 +    assert(*out == NULL);
  27.433 +
  27.434 +    // Try to import locally first.
  27.435 +    if (!import(package, path, out))
  27.436 +        return false;
  27.437 +    if (*out)
  27.438 +        return true;
  27.439 +
  27.440 +    // Otherwise, search system roots.
  27.441 +    Local<Package> root(zone_);
  27.442 +    for (size_t i = 0; i < roots_.length(); i++) {
  27.443 +        root = roots_[i];
  27.444 +        if (!import(root, path, out))
  27.445 +            return false;
  27.446 +        if (*out)
  27.447 +            return true;
  27.448 +    }
  27.449 +
  27.450 +    return true;
  27.451 +}
  27.452 +
  27.453 +PackageCache::~PackageCache()
  27.454 +{
  27.455 +}
    28.1 --- a/src/Packages.h	Mon Jun 10 00:46:29 2013 +0100
    28.2 +++ b/src/Packages.h	Mon Jun 10 01:04:43 2013 +0100
    28.3 @@ -1,193 +1,193 @@
    28.4 -/*
    28.5 - * Copyright (C) 2012 David Anderson
    28.6 - *
    28.7 - * This file is part of SourcePawn.
    28.8 - *
    28.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   28.10 - * the terms of the GNU General Public License as published by the Free
   28.11 - * Software Foundation, either version 3 of the License, or (at your option)
   28.12 - * any later version.
   28.13 - * 
   28.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   28.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   28.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   28.17 - *
   28.18 - * You should have received a copy of the GNU General Public License along with
   28.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   28.20 - */
   28.21 -#ifndef _include_sp2_packages_h_
   28.22 -#define _include_sp2_packages_h_
   28.23 -
   28.24 -#include "PoolAllocator.h"
   28.25 -#include "Objects.h"
   28.26 -#include "HashTable.h"
   28.27 -
   28.28 -namespace ke {
   28.29 -
   28.30 -class String;
   28.31 -class Module;
   28.32 -class Package;
   28.33 -class ImportStatement;
   28.34 -class VirtualObjectVisitor;
   28.35 -
   28.36 -template <typename T> class List;
   28.37 -
   28.38 -struct PathComponent : PoolObject
   28.39 -{
   28.40 -    PathComponent(ScopedRoot<String> *name, PathComponent *next)
   28.41 -      : name(*name),
   28.42 -        next(next)
   28.43 -    {
   28.44 -    }
   28.45 -    ScopedRoot<String> &name;
   28.46 -    PathComponent *next;
   28.47 -};
   28.48 -
   28.49 -class Importable : public Object
   28.50 -{
   28.51 -  public:
   28.52 -    Package *parent() {
   28.53 -        return parent_;
   28.54 -    }
   28.55 -    String *path() {
   28.56 -        return path_;
   28.57 -    }
   28.58 -    String *name() {
   28.59 -        return name_;
   28.60 -    }
   28.61 -
   28.62 -    bool isModule() {
   28.63 -        return is(MapKind_Module);
   28.64 -    }
   28.65 -    bool isPackage() {
   28.66 -        return is(MapKind_Package);
   28.67 -    }
   28.68 -
   28.69 -    static inline size_t offsetOfName() {
   28.70 -        return OFFSETOF(Importable, name_);
   28.71 -    }
   28.72 -    static inline size_t offsetOfParent() {
   28.73 -        return OFFSETOF(Importable, parent_);
   28.74 -    }
   28.75 -    static inline size_t offsetOfPath() {
   28.76 -        return OFFSETOF(Importable, path_);
   28.77 -    }
   28.78 -
   28.79 -    static inline Importable *cast(Object *obj) {
   28.80 -        assert(!obj || obj->is(MapKind_Module) || obj->is(MapKind_Package));
   28.81 -        return reinterpret_cast<Importable *>(obj);
   28.82 -    }
   28.83 -
   28.84 -  protected:
   28.85 -    Barriered<String> name_;
   28.86 -    Barriered<Package> parent_;
   28.87 -    Barriered<String> path_;
   28.88 -};
   28.89 -
   28.90 -// A package is a single folder in the file system, and contains any number of
   28.91 -// modules and sub-packages. The package hierarchy forms a tree. For simplicity
   28.92 -// the root of the tree is an anonymous package that contains no modules.
   28.93 -//
   28.94 -// Each package in the package hierarchy has two components of path information:
   28.95 -//   (1) Canonical path. This is a normalized path used to compute the paths of
   28.96 -//       modules.
   28.97 -//   (2) Name. This is the package's name as it would appear in a path
   28.98 -//       component. It is optional.
   28.99 -//
  28.100 -// Packages may be "hidden", meaning that even if they have names, their name
  28.101 -// is not accessible from any import statements. Packages may also be "jailed",
  28.102 -// meaning that other names in the package are not visible to each other.
  28.103 -//
  28.104 -// Packages are created in a few ways:
  28.105 -//
  28.106 -//   (1) System Roots. A system root is a default search location for imports,
  28.107 -//       and they are installed at the top-level of the hierarchy by the host
  28.108 -//       application. A system root has a unique top-level name and path.
  28.109 -//       System roots are always hidden.
  28.110 -//
  28.111 -//   (2) Imports. When importing, the package hierarchy may be extended as
  28.112 -//       new paths are discovered. Packages discovered this way are never
  28.113 -//       hidden or jailed.
  28.114 -//
  28.115 -//   (3) Via Package::New(), which creates an empty package. This can be used
  28.116 -//       to create custom packages.
  28.117 -class Package : public Importable
  28.118 -{
  28.119 -  public:
  28.120 -    enum {
  28.121 -        Normal = 0,
  28.122 -
  28.123 -        // These must match the flags in the public API for Package.
  28.124 -        Hidden = (1 << 0),
  28.125 -        Jailed = (1 << 1)
  28.126 -    };
  28.127 -
  28.128 -  public:
  28.129 -    static Package *NewNormalized(Zone *zone,
  28.130 -                                  Handle<Package> parent,
  28.131 -                                  Handle<String> path,
  28.132 -                                  Handle<String> name,
  28.133 -                                  unsigned flags);
  28.134 -    static Package *New(Zone *zone,
  28.135 -                        Handle<Package> parent,
  28.136 -                        const char *path,
  28.137 -                        Handle<String> name,
  28.138 -                        unsigned flags);
  28.139 -
  28.140 -    bool add(Zone *zone, Handle<Importable> component);
  28.141 -
  28.142 -    bool hidden() {
  28.143 -        return !!(flags_ & Package::Hidden);
  28.144 -    }
  28.145 -    bool jailed() {
  28.146 -        return !!(flags_ & Package::Jailed);
  28.147 -    }
  28.148 -
  28.149 -    void setNativeIdentity(void *identity) {
  28.150 -        nativeIdentity_ = identity;
  28.151 -    }
  28.152 -    void *getNativeIdentity() {
  28.153 -        return nativeIdentity_;
  28.154 -    }
  28.155 -    Importable *import(Handle<String> name);
  28.156 -
  28.157 -    // Begin GC descriptor.
  28.158 -    static inline size_t offsetOfContents() {
  28.159 -        return OFFSETOF(Package, contents_);
  28.160 -    }
  28.161 -    // End GC descriptor.
  28.162 -
  28.163 -    static inline Package *cast(Object *obj) {
  28.164 -        assert(!obj || obj->is(MapKind_Package));
  28.165 -        return reinterpret_cast<Package *>(obj);
  28.166 -    }
  28.167 -
  28.168 -  private:
  28.169 -    unsigned flags_;
  28.170 -    Barriered<List<Importable> > contents_;
  28.171 -    void *nativeIdentity_;
  28.172 -};
  28.173 -
  28.174 -class PackageCache
  28.175 -{
  28.176 -  public:
  28.177 -    PackageCache(Zone *zone);
  28.178 -    ~PackageCache();
  28.179 -    bool initialize();
  28.180 -
  28.181 -    bool findOrAdd(Handle<Package> package, PathComponent *path, Importable **out);
  28.182 -
  28.183 -    void accept(VirtualObjectVisitor *visitor);
  28.184 -
  28.185 -  private:
  28.186 -    bool import(Handle<Package> package, PathComponent *path, Importable **out);
  28.187 -    bool checkfs(Handle<Package> package, PathComponent *path, Importable **out);
  28.188 -
  28.189 -  private:
  28.190 -    Zone *zone_;
  28.191 -    Vector<Unbarriered<Package> > roots_;
  28.192 -};
  28.193 -
  28.194 -} // namespace ke
  28.195 -
  28.196 -#endif // _include_sp2_packages_h_
  28.197 +/*
  28.198 + * Copyright (C) 2012 David Anderson
  28.199 + *
  28.200 + * This file is part of SourcePawn.
  28.201 + *
  28.202 + * SourcePawn is free software: you can redistribute it and/or modify it under
  28.203 + * the terms of the GNU General Public License as published by the Free
  28.204 + * Software Foundation, either version 3 of the License, or (at your option)
  28.205 + * any later version.
  28.206 + * 
  28.207 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  28.208 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  28.209 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  28.210 + *
  28.211 + * You should have received a copy of the GNU General Public License along with
  28.212 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  28.213 + */
  28.214 +#ifndef _include_sp2_packages_h_
  28.215 +#define _include_sp2_packages_h_
  28.216 +
  28.217 +#include "PoolAllocator.h"
  28.218 +#include "Objects.h"
  28.219 +#include "HashTable.h"
  28.220 +
  28.221 +namespace ke {
  28.222 +
  28.223 +class String;
  28.224 +class Module;
  28.225 +class Package;
  28.226 +class ImportStatement;
  28.227 +class VirtualObjectVisitor;
  28.228 +
  28.229 +template <typename T> class List;
  28.230 +
  28.231 +struct PathComponent : PoolObject
  28.232 +{
  28.233 +    PathComponent(ScopedRoot<String> *name, PathComponent *next)
  28.234 +      : name(*name),
  28.235 +        next(next)
  28.236 +    {
  28.237 +    }
  28.238 +    ScopedRoot<String> &name;
  28.239 +    PathComponent *next;
  28.240 +};
  28.241 +
  28.242 +class Importable : public Object
  28.243 +{
  28.244 +  public:
  28.245 +    Package *parent() {
  28.246 +        return parent_;
  28.247 +    }
  28.248 +    String *path() {
  28.249 +        return path_;
  28.250 +    }
  28.251 +    String *name() {
  28.252 +        return name_;
  28.253 +    }
  28.254 +
  28.255 +    bool isModule() {
  28.256 +        return is(MapKind_Module);
  28.257 +    }
  28.258 +    bool isPackage() {
  28.259 +        return is(MapKind_Package);
  28.260 +    }
  28.261 +
  28.262 +    static inline size_t offsetOfName() {
  28.263 +        return OFFSETOF(Importable, name_);
  28.264 +    }
  28.265 +    static inline size_t offsetOfParent() {
  28.266 +        return OFFSETOF(Importable, parent_);
  28.267 +    }
  28.268 +    static inline size_t offsetOfPath() {
  28.269 +        return OFFSETOF(Importable, path_);
  28.270 +    }
  28.271 +
  28.272 +    static inline Importable *cast(Object *obj) {
  28.273 +        assert(!obj || obj->is(MapKind_Module) || obj->is(MapKind_Package));
  28.274 +        return reinterpret_cast<Importable *>(obj);
  28.275 +    }
  28.276 +
  28.277 +  protected:
  28.278 +    Barriered<String> name_;
  28.279 +    Barriered<Package> parent_;
  28.280 +    Barriered<String> path_;
  28.281 +};
  28.282 +
  28.283 +// A package is a single folder in the file system, and contains any number of
  28.284 +// modules and sub-packages. The package hierarchy forms a tree. For simplicity
  28.285 +// the root of the tree is an anonymous package that contains no modules.
  28.286 +//
  28.287 +// Each package in the package hierarchy has two components of path information:
  28.288 +//   (1) Canonical path. This is a normalized path used to compute the paths of
  28.289 +//       modules.
  28.290 +//   (2) Name. This is the package's name as it would appear in a path
  28.291 +//       component. It is optional.
  28.292 +//
  28.293 +// Packages may be "hidden", meaning that even if they have names, their name
  28.294 +// is not accessible from any import statements. Packages may also be "jailed",
  28.295 +// meaning that other names in the package are not visible to each other.
  28.296 +//
  28.297 +// Packages are created in a few ways:
  28.298 +//
  28.299 +//   (1) System Roots. A system root is a default search location for imports,
  28.300 +//       and they are installed at the top-level of the hierarchy by the host
  28.301 +//       application. A system root has a unique top-level name and path.
  28.302 +//       System roots are always hidden.
  28.303 +//
  28.304 +//   (2) Imports. When importing, the package hierarchy may be extended as
  28.305 +//       new paths are discovered. Packages discovered this way are never
  28.306 +//       hidden or jailed.
  28.307 +//
  28.308 +//   (3) Via Package::New(), which creates an empty package. This can be used
  28.309 +//       to create custom packages.
  28.310 +class Package : public Importable
  28.311 +{
  28.312 +  public:
  28.313 +    enum {
  28.314 +        Normal = 0,
  28.315 +
  28.316 +        // These must match the flags in the public API for Package.
  28.317 +        Hidden = (1 << 0),
  28.318 +        Jailed = (1 << 1)
  28.319 +    };
  28.320 +
  28.321 +  public:
  28.322 +    static Package *NewNormalized(Zone *zone,
  28.323 +                                  Handle<Package> parent,
  28.324 +                                  Handle<String> path,
  28.325 +                                  Handle<String> name,
  28.326 +                                  unsigned flags);
  28.327 +    static Package *New(Zone *zone,
  28.328 +                        Handle<Package> parent,
  28.329 +                        const char *path,
  28.330 +                        Handle<String> name,
  28.331 +                        unsigned flags);
  28.332 +
  28.333 +    bool add(Zone *zone, Handle<Importable> component);
  28.334 +
  28.335 +    bool hidden() {
  28.336 +        return !!(flags_ & Package::Hidden);
  28.337 +    }
  28.338 +    bool jailed() {
  28.339 +        return !!(flags_ & Package::Jailed);
  28.340 +    }
  28.341 +
  28.342 +    void setNativeIdentity(void *identity) {
  28.343 +        nativeIdentity_ = identity;
  28.344 +    }
  28.345 +    void *getNativeIdentity() {
  28.346 +        return nativeIdentity_;
  28.347 +    }
  28.348 +    Importable *import(Handle<String> name);
  28.349 +
  28.350 +    // Begin GC descriptor.
  28.351 +    static inline size_t offsetOfContents() {
  28.352 +        return OFFSETOF(Package, contents_);
  28.353 +    }
  28.354 +    // End GC descriptor.
  28.355 +
  28.356 +    static inline Package *cast(Object *obj) {
  28.357 +        assert(!obj || obj->is(MapKind_Package));
  28.358 +        return reinterpret_cast<Package *>(obj);
  28.359 +    }
  28.360 +
  28.361 +  private:
  28.362 +    unsigned flags_;
  28.363 +    Barriered<List<Importable> > contents_;
  28.364 +    void *nativeIdentity_;
  28.365 +};
  28.366 +
  28.367 +class PackageCache
  28.368 +{
  28.369 +  public:
  28.370 +    PackageCache(Zone *zone);
  28.371 +    ~PackageCache();
  28.372 +    bool initialize();
  28.373 +
  28.374 +    bool findOrAdd(Handle<Package> package, PathComponent *path, Importable **out);
  28.375 +
  28.376 +    void accept(VirtualObjectVisitor *visitor);
  28.377 +
  28.378 +  private:
  28.379 +    bool import(Handle<Package> package, PathComponent *path, Importable **out);
  28.380 +    bool checkfs(Handle<Package> package, PathComponent *path, Importable **out);
  28.381 +
  28.382 +  private:
  28.383 +    Zone *zone_;
  28.384 +    Vector<Unbarriered<Package> > roots_;
  28.385 +};
  28.386 +
  28.387 +} // namespace ke
  28.388 +
  28.389 +#endif // _include_sp2_packages_h_
    29.1 --- a/src/PoolAllocator.cpp	Mon Jun 10 00:46:29 2013 +0100
    29.2 +++ b/src/PoolAllocator.cpp	Mon Jun 10 01:04:43 2013 +0100
    29.3 @@ -1,131 +1,131 @@
    29.4 -/*
    29.5 - * Copyright (C) 2012 David Anderson
    29.6 - *
    29.7 - * This file is part of JITCraft.
    29.8 - *
    29.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   29.10 - * the terms of the GNU General Public License as published by the Free
   29.11 - * Software Foundation, either version 3 of the License, or (at your option)
   29.12 - * any later version.
   29.13 - * 
   29.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   29.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   29.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   29.17 - *
   29.18 - * You should have received a copy of the GNU General Public License along with
   29.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   29.20 - */
   29.21 -#include <assert.h>
   29.22 -#include <stdlib.h>
   29.23 -#include <new>
   29.24 -#include "PoolAllocator.h"
   29.25 -#include "Zone.h"
   29.26 -#include "Spaces-inl.h"
   29.27 -#include "Heap-inl.h"
   29.28 -
   29.29 -using namespace ke;
   29.30 -
   29.31 -PoolAllocator::PoolAllocator()
   29.32 -  : reserved_(NULL),
   29.33 -    last_(NULL)
   29.34 -{
   29.35 -}
   29.36 -
   29.37 -PoolAllocator::~PoolAllocator()
   29.38 -{
   29.39 -    unwind(NULL);
   29.40 -    if (reserved_)
   29.41 -        free(reserved_);
   29.42 -}
   29.43 -
   29.44 -char *
   29.45 -PoolAllocator::enter()
   29.46 -{
   29.47 -    if (!last_)
   29.48 -        return NULL;
   29.49 -    return last_->ptr;
   29.50 -}
   29.51 -
   29.52 -void
   29.53 -PoolAllocator::leave(char *pos)
   29.54 -{
   29.55 -    unwind(pos);
   29.56 -}
   29.57 -
   29.58 -void
   29.59 -PoolAllocator::unwind(char *pos)
   29.60 -{
   29.61 -    while (last_) {
   29.62 -        if (pos && pos >= last_->base && pos < last_->end)
   29.63 -            break;
   29.64 -        Pool *prev = last_->prev;
   29.65 -        {
   29.66 -            if (last_->size() <= kMaxReserveSize &&
   29.67 -                (!reserved_ || reserved_->size() < last_->size()))
   29.68 -            {
   29.69 -                if (reserved_)
   29.70 -                    free(reserved_);
   29.71 -                reserved_ = last_;
   29.72 -            } else {
   29.73 -                free(last_);
   29.74 -            }
   29.75 -        }
   29.76 -        last_ = prev;
   29.77 -    }
   29.78 -
   29.79 -    if (!last_) {
   29.80 -        assert(!pos);
   29.81 -        return;
   29.82 -    }
   29.83 -
   29.84 -    last_->ptr = pos;
   29.85 -}
   29.86 -
   29.87 -void *
   29.88 -PoolAllocator::slowAllocate(size_t actualBytes)
   29.89 -{
   29.90 -    size_t bytesNeeded = actualBytes + sizeof(Pool);
   29.91 -    if (bytesNeeded < kDefaultPoolSize)
   29.92 -        bytesNeeded = kDefaultPoolSize;
   29.93 -
   29.94 -    Pool *pool;
   29.95 -    if (reserved_ && reserved_->size() >= bytesNeeded) {
   29.96 -        pool = reserved_;
   29.97 -        reserved_ = NULL;
   29.98 -    } else {
   29.99 -        pool = (Pool *)malloc(bytesNeeded);
  29.100 -        if (!pool) {
  29.101 -            ZONE()->reportOutOfMemory();
  29.102 -            return NULL;
  29.103 -        }
  29.104 -        pool->base = (char *)(pool + 1);
  29.105 -        pool->end = (char *)pool + bytesNeeded;
  29.106 -    }
  29.107 -    pool->ptr = pool->base + actualBytes;
  29.108 -    pool->prev = last_;
  29.109 -    last_ = pool;
  29.110 -    return pool->base;
  29.111 -}
  29.112 -
  29.113 -void
  29.114 -PoolAllocationPolicy::reportOutOfMemory()
  29.115 -{
  29.116 -    ZONE()->reportOutOfMemory();
  29.117 -}
  29.118 -
  29.119 -void
  29.120 -PoolAllocationPolicy::reportAllocationOverflow()
  29.121 -{
  29.122 -    ZONE()->reportError(Message_AllocationOverflow);
  29.123 -}
  29.124 -
  29.125 -void *
  29.126 -PoolAllocationPolicy::malloc(size_t bytes)
  29.127 -{
  29.128 -    return ZONE()->pool().rawAllocate(bytes);
  29.129 -}
  29.130 -
  29.131 -void
  29.132 -PoolAllocationPolicy::free(void *ptr)
  29.133 -{
  29.134 -}
  29.135 +/*
  29.136 + * Copyright (C) 2012 David Anderson
  29.137 + *
  29.138 + * This file is part of JITCraft.
  29.139 + *
  29.140 + * JITCraft is free software: you can redistribute it and/or modify it under
  29.141 + * the terms of the GNU General Public License as published by the Free
  29.142 + * Software Foundation, either version 3 of the License, or (at your option)
  29.143 + * any later version.
  29.144 + * 
  29.145 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  29.146 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  29.147 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  29.148 + *
  29.149 + * You should have received a copy of the GNU General Public License along with
  29.150 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  29.151 + */
  29.152 +#include <assert.h>
  29.153 +#include <stdlib.h>
  29.154 +#include <new>
  29.155 +#include "PoolAllocator.h"
  29.156 +#include "Zone.h"
  29.157 +#include "Spaces-inl.h"
  29.158 +#include "Heap-inl.h"
  29.159 +
  29.160 +using namespace ke;
  29.161 +
  29.162 +PoolAllocator::PoolAllocator()
  29.163 +  : reserved_(NULL),
  29.164 +    last_(NULL)
  29.165 +{
  29.166 +}
  29.167 +
  29.168 +PoolAllocator::~PoolAllocator()
  29.169 +{
  29.170 +    unwind(NULL);
  29.171 +    if (reserved_)
  29.172 +        free(reserved_);
  29.173 +}
  29.174 +
  29.175 +char *
  29.176 +PoolAllocator::enter()
  29.177 +{
  29.178 +    if (!last_)
  29.179 +        return NULL;
  29.180 +    return last_->ptr;
  29.181 +}
  29.182 +
  29.183 +void
  29.184 +PoolAllocator::leave(char *pos)
  29.185 +{
  29.186 +    unwind(pos);
  29.187 +}
  29.188 +
  29.189 +void
  29.190 +PoolAllocator::unwind(char *pos)
  29.191 +{
  29.192 +    while (last_) {
  29.193 +        if (pos && pos >= last_->base && pos < last_->end)
  29.194 +            break;
  29.195 +        Pool *prev = last_->prev;
  29.196 +        {
  29.197 +            if (last_->size() <= kMaxReserveSize &&
  29.198 +                (!reserved_ || reserved_->size() < last_->size()))
  29.199 +            {
  29.200 +                if (reserved_)
  29.201 +                    free(reserved_);
  29.202 +                reserved_ = last_;
  29.203 +            } else {
  29.204 +                free(last_);
  29.205 +            }
  29.206 +        }
  29.207 +        last_ = prev;
  29.208 +    }
  29.209 +
  29.210 +    if (!last_) {
  29.211 +        assert(!pos);
  29.212 +        return;
  29.213 +    }
  29.214 +
  29.215 +    last_->ptr = pos;
  29.216 +}
  29.217 +
  29.218 +void *
  29.219 +PoolAllocator::slowAllocate(size_t actualBytes)
  29.220 +{
  29.221 +    size_t bytesNeeded = actualBytes + sizeof(Pool);
  29.222 +    if (bytesNeeded < kDefaultPoolSize)
  29.223 +        bytesNeeded = kDefaultPoolSize;
  29.224 +
  29.225 +    Pool *pool;
  29.226 +    if (reserved_ && reserved_->size() >= bytesNeeded) {
  29.227 +        pool = reserved_;
  29.228 +        reserved_ = NULL;
  29.229 +    } else {
  29.230 +        pool = (Pool *)malloc(bytesNeeded);
  29.231 +        if (!pool) {
  29.232 +            ZONE()->reportOutOfMemory();
  29.233 +            return NULL;
  29.234 +        }
  29.235 +        pool->base = (char *)(pool + 1);
  29.236 +        pool->end = (char *)pool + bytesNeeded;
  29.237 +    }
  29.238 +    pool->ptr = pool->base + actualBytes;
  29.239 +    pool->prev = last_;
  29.240 +    last_ = pool;
  29.241 +    return pool->base;
  29.242 +}
  29.243 +
  29.244 +void
  29.245 +PoolAllocationPolicy::reportOutOfMemory()
  29.246 +{
  29.247 +    ZONE()->reportOutOfMemory();
  29.248 +}
  29.249 +
  29.250 +void
  29.251 +PoolAllocationPolicy::reportAllocationOverflow()
  29.252 +{
  29.253 +    ZONE()->reportError(Message_AllocationOverflow);
  29.254 +}
  29.255 +
  29.256 +void *
  29.257 +PoolAllocationPolicy::malloc(size_t bytes)
  29.258 +{
  29.259 +    return ZONE()->pool().rawAllocate(bytes);
  29.260 +}
  29.261 +
  29.262 +void
  29.263 +PoolAllocationPolicy::free(void *ptr)
  29.264 +{
  29.265 +}
    30.1 --- a/src/PoolAllocator.h	Mon Jun 10 00:46:29 2013 +0100
    30.2 +++ b/src/PoolAllocator.h	Mon Jun 10 01:04:43 2013 +0100
    30.3 @@ -1,145 +1,145 @@
    30.4 -/*
    30.5 - * Copyright (C) 2012 David Anderson
    30.6 - *
    30.7 - * This file is part of JITCraft.
    30.8 - *
    30.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   30.10 - * the terms of the GNU General Public License as published by the Free
   30.11 - * Software Foundation, either version 3 of the License, or (at your option)
   30.12 - * any later version.
   30.13 - * 
   30.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   30.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   30.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   30.17 - *
   30.18 - * You should have received a copy of the GNU General Public License along with
   30.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   30.20 - */
   30.21 -#ifndef _include_jitcraft_pool_allocator_h_
   30.22 -#define _include_jitcraft_pool_allocator_h_
   30.23 -
   30.24 -#include <new>
   30.25 -#include <stddef.h>
   30.26 -#include <limits.h>
   30.27 -#include "Utility.h"
   30.28 -#include "Vector.h"
   30.29 -
   30.30 -namespace ke {
   30.31 -
   30.32 -// Allocates memory in chunks that are not freed until the entire allocator
   30.33 -// is freed. This is intended for use with large, temporary data structures.
   30.34 -class PoolAllocator
   30.35 -{
   30.36 -    friend class PoolAllocationScope;
   30.37 -
   30.38 -    struct Pool {
   30.39 -        char *base;
   30.40 -        char *ptr;
   30.41 -        char *end;
   30.42 -        Pool *prev;
   30.43 -
   30.44 -        size_t size() const {
   30.45 -            return size_t(end - base);
   30.46 -        }
   30.47 -    };
   30.48 -
   30.49 -    static const size_t kDefaultPoolSize = 8 * 1024;
   30.50 -    static const size_t kMaxReserveSize = 64 * 1024;
   30.51 -
   30.52 -  private:
   30.53 -    Pool *reserved_;
   30.54 -    Pool *last_;
   30.55 -
   30.56 -  private:
   30.57 -    void unwind(char *pos);
   30.58 -    void *slowAllocate(size_t actualBytes);
   30.59 -
   30.60 -  public:
   30.61 -    PoolAllocator();
   30.62 -    ~PoolAllocator();
   30.63 -
   30.64 -    void *rawAllocate(size_t bytes) {
   30.65 -        // Guarantee malloc alignment.
   30.66 -        size_t actualBytes = Align(bytes, kMallocAlignment);
   30.67 -        if (!last_ || (size_t(last_->end - last_->ptr) < actualBytes))
   30.68 -            return slowAllocate(actualBytes);
   30.69 -        char *ptr = last_->ptr;
   30.70 -        last_->ptr += actualBytes;
   30.71 -        return ptr;
   30.72 -    }
   30.73 -
   30.74 -    template <typename T>
   30.75 -    T *alloc(size_t count = 1) {
   30.76 -        void *ptr = rawAllocate(count * sizeof(T));
   30.77 -        if (!ptr)
   30.78 -            return NULL;
   30.79 -
   30.80 -        return reinterpret_cast<T *>(ptr);
   30.81 -    }
   30.82 -
   30.83 -    char *enter();
   30.84 -    void leave(char *position);
   30.85 -};
   30.86 -
   30.87 -class PoolScope
   30.88 -{
   30.89 -    PoolAllocator &pool_;
   30.90 -    char *position_;
   30.91 -
   30.92 -  public:
   30.93 -    PoolScope(PoolAllocator &allocator)
   30.94 -      : pool_(allocator),
   30.95 -        position_(allocator.enter())
   30.96 -    {
   30.97 -    }
   30.98 -    ~PoolScope()
   30.99 -    {
  30.100 -        pool_.leave(position_);
  30.101 -    }
  30.102 -};
  30.103 -
  30.104 -class PoolObject
  30.105 -{
  30.106 -  public:
  30.107 -    void *operator new(size_t size, PoolAllocator &pool) {
  30.108 -        return pool.rawAllocate(size);
  30.109 -    }
  30.110 -    void *operator new [](size_t size, PoolAllocator &pool) {
  30.111 -        return pool.rawAllocate(size);
  30.112 -    }
  30.113 -    
  30.114 -    // Using delete on pool-allocated objects is illegal.
  30.115 -    void operator delete(void *ptr, PoolAllocator &pool) {
  30.116 -        assert(false);
  30.117 -    }
  30.118 -    void operator delete [](void *ptr, PoolAllocator &pool) {
  30.119 -        assert(false);
  30.120 -    }
  30.121 -};
  30.122 -
  30.123 -class PoolAllocationPolicy
  30.124 -{
  30.125 -  protected:
  30.126 -    void reportAllocationOverflow();
  30.127 -    void reportOutOfMemory();
  30.128 -
  30.129 -  public:
  30.130 -    void *malloc(size_t bytes);
  30.131 -    void free(void *ptr);
  30.132 -};
  30.133 -
  30.134 -template <typename T>
  30.135 -class PoolList
  30.136 -  : public Vector<T, PoolAllocationPolicy>,
  30.137 -    public PoolObject
  30.138 -{
  30.139 -  public:
  30.140 -    PoolList()
  30.141 -      : Vector<T, PoolAllocationPolicy>(PoolAllocationPolicy())
  30.142 -    {
  30.143 -    }
  30.144 -};
  30.145 -
  30.146 -}
  30.147 -
  30.148 -#endif // _include_jitcraft_pool_allocator_h_
  30.149 +/*
  30.150 + * Copyright (C) 2012 David Anderson
  30.151 + *
  30.152 + * This file is part of JITCraft.
  30.153 + *
  30.154 + * JITCraft is free software: you can redistribute it and/or modify it under
  30.155 + * the terms of the GNU General Public License as published by the Free
  30.156 + * Software Foundation, either version 3 of the License, or (at your option)
  30.157 + * any later version.
  30.158 + * 
  30.159 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  30.160 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  30.161 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  30.162 + *
  30.163 + * You should have received a copy of the GNU General Public License along with
  30.164 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  30.165 + */
  30.166 +#ifndef _include_jitcraft_pool_allocator_h_
  30.167 +#define _include_jitcraft_pool_allocator_h_
  30.168 +
  30.169 +#include <new>
  30.170 +#include <stddef.h>
  30.171 +#include <limits.h>
  30.172 +#include "Utility.h"
  30.173 +#include "Vector.h"
  30.174 +
  30.175 +namespace ke {
  30.176 +
  30.177 +// Allocates memory in chunks that are not freed until the entire allocator
  30.178 +// is freed. This is intended for use with large, temporary data structures.
  30.179 +class PoolAllocator
  30.180 +{
  30.181 +    friend class PoolAllocationScope;
  30.182 +
  30.183 +    struct Pool {
  30.184 +        char *base;
  30.185 +        char *ptr;
  30.186 +        char *end;
  30.187 +        Pool *prev;
  30.188 +
  30.189 +        size_t size() const {
  30.190 +            return size_t(end - base);
  30.191 +        }
  30.192 +    };
  30.193 +
  30.194 +    static const size_t kDefaultPoolSize = 8 * 1024;
  30.195 +    static const size_t kMaxReserveSize = 64 * 1024;
  30.196 +
  30.197 +  private:
  30.198 +    Pool *reserved_;
  30.199 +    Pool *last_;
  30.200 +
  30.201 +  private:
  30.202 +    void unwind(char *pos);
  30.203 +    void *slowAllocate(size_t actualBytes);
  30.204 +
  30.205 +  public:
  30.206 +    PoolAllocator();
  30.207 +    ~PoolAllocator();
  30.208 +
  30.209 +    void *rawAllocate(size_t bytes) {
  30.210 +        // Guarantee malloc alignment.
  30.211 +        size_t actualBytes = Align(bytes, kMallocAlignment);
  30.212 +        if (!last_ || (size_t(last_->end - last_->ptr) < actualBytes))
  30.213 +            return slowAllocate(actualBytes);
  30.214 +        char *ptr = last_->ptr;
  30.215 +        last_->ptr += actualBytes;
  30.216 +        return ptr;
  30.217 +    }
  30.218 +
  30.219 +    template <typename T>
  30.220 +    T *alloc(size_t count = 1) {
  30.221 +        void *ptr = rawAllocate(count * sizeof(T));
  30.222 +        if (!ptr)
  30.223 +            return NULL;
  30.224 +
  30.225 +        return reinterpret_cast<T *>(ptr);
  30.226 +    }
  30.227 +
  30.228 +    char *enter();
  30.229 +    void leave(char *position);
  30.230 +};
  30.231 +
  30.232 +class PoolScope
  30.233 +{
  30.234 +    PoolAllocator &pool_;
  30.235 +    char *position_;
  30.236 +
  30.237 +  public:
  30.238 +    PoolScope(PoolAllocator &allocator)
  30.239 +      : pool_(allocator),
  30.240 +        position_(allocator.enter())
  30.241 +    {
  30.242 +    }
  30.243 +    ~PoolScope()
  30.244 +    {
  30.245 +        pool_.leave(position_);
  30.246 +    }
  30.247 +};
  30.248 +
  30.249 +class PoolObject
  30.250 +{
  30.251 +  public:
  30.252 +    void *operator new(size_t size, PoolAllocator &pool) {
  30.253 +        return pool.rawAllocate(size);
  30.254 +    }
  30.255 +    void *operator new [](size_t size, PoolAllocator &pool) {
  30.256 +        return pool.rawAllocate(size);
  30.257 +    }
  30.258 +    
  30.259 +    // Using delete on pool-allocated objects is illegal.
  30.260 +    void operator delete(void *ptr, PoolAllocator &pool) {
  30.261 +        assert(false);
  30.262 +    }
  30.263 +    void operator delete [](void *ptr, PoolAllocator &pool) {
  30.264 +        assert(false);
  30.265 +    }
  30.266 +};
  30.267 +
  30.268 +class PoolAllocationPolicy
  30.269 +{
  30.270 +  protected:
  30.271 +    void reportAllocationOverflow();
  30.272 +    void reportOutOfMemory();
  30.273 +
  30.274 +  public:
  30.275 +    void *malloc(size_t bytes);
  30.276 +    void free(void *ptr);
  30.277 +};
  30.278 +
  30.279 +template <typename T>
  30.280 +class PoolList
  30.281 +  : public Vector<T, PoolAllocationPolicy>,
  30.282 +    public PoolObject
  30.283 +{
  30.284 +  public:
  30.285 +    PoolList()
  30.286 +      : Vector<T, PoolAllocationPolicy>(PoolAllocationPolicy())
  30.287 +    {
  30.288 +    }
  30.289 +};
  30.290 +
  30.291 +}
  30.292 +
  30.293 +#endif // _include_jitcraft_pool_allocator_h_
    31.1 --- a/src/Reference.cpp	Mon Jun 10 00:46:29 2013 +0100
    31.2 +++ b/src/Reference.cpp	Mon Jun 10 01:04:43 2013 +0100
    31.3 @@ -1,51 +1,51 @@
    31.4 -/* vim: set ts=4 sw=4 tw=99 et:
    31.5 - *
    31.6 - * Copyright (C) 2012 David Anderson
    31.7 - *
    31.8 - * This file is part of SourcePawn.
    31.9 - *
   31.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   31.11 - * the terms of the GNU General Public License as published by the Free
   31.12 - * Software Foundation, either version 3 of the License, or (at your option)
   31.13 - * any later version.
   31.14 - * 
   31.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   31.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   31.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   31.18 - *
   31.19 - * You should have received a copy of the GNU General Public License along with
   31.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   31.21 - */
   31.22 -#include "Reference.h"
   31.23 -#include "Zone.h"
   31.24 -#include "Array.h"
   31.25 -#include "Structures.h"
   31.26 -#include "Heap-inl.h"
   31.27 -
   31.28 -using namespace ke;
   31.29 -
   31.30 -Reference *
   31.31 -Reference::NewStack(Zone *zone, void *location, Heap::Tenure tenure)
   31.32 -{
   31.33 -    Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
   31.34 -    if (!ref)
   31.35 -        return NULL;
   31.36 -
   31.37 -    ref->location_ = location;
   31.38 -    ref->base_ = NULL;
   31.39 -    return ref;
   31.40 -}
   31.41 -
   31.42 -Reference *
   31.43 -Reference::NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure)
   31.44 -{
   31.45 -    Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
   31.46 -    if (!ref)
   31.47 -        return NULL;
   31.48 -
   31.49 -    ref->location_ = &ref->slot_;
   31.50 -    ref->slot_ = slot;
   31.51 -    ref->base_ = NULL;
   31.52 -    return ref;
   31.53 -}
   31.54 -
   31.55 +/* vim: set ts=4 sw=4 tw=99 et:
   31.56 + *
   31.57 + * Copyright (C) 2012 David Anderson
   31.58 + *
   31.59 + * This file is part of SourcePawn.
   31.60 + *
   31.61 + * SourcePawn is free software: you can redistribute it and/or modify it under
   31.62 + * the terms of the GNU General Public License as published by the Free
   31.63 + * Software Foundation, either version 3 of the License, or (at your option)
   31.64 + * any later version.
   31.65 + * 
   31.66 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   31.67 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   31.68 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   31.69 + *
   31.70 + * You should have received a copy of the GNU General Public License along with
   31.71 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   31.72 + */
   31.73 +#include "Reference.h"
   31.74 +#include "Zone.h"
   31.75 +#include "Array.h"
   31.76 +#include "Structures.h"
   31.77 +#include "Heap-inl.h"
   31.78 +
   31.79 +using namespace ke;
   31.80 +
   31.81 +Reference *
   31.82 +Reference::NewStack(Zone *zone, void *location, Heap::Tenure tenure)
   31.83 +{
   31.84 +    Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
   31.85 +    if (!ref)
   31.86 +        return NULL;
   31.87 +
   31.88 +    ref->location_ = location;
   31.89 +    ref->base_ = NULL;
   31.90 +    return ref;
   31.91 +}
   31.92 +
   31.93 +Reference *
   31.94 +Reference::NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure)
   31.95 +{
   31.96 +    Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
   31.97 +    if (!ref)
   31.98 +        return NULL;
   31.99 +
  31.100 +    ref->location_ = &ref->slot_;
  31.101 +    ref->slot_ = slot;
  31.102 +    ref->base_ = NULL;
  31.103 +    return ref;
  31.104 +}
  31.105 +
    32.1 --- a/src/Reference.h	Mon Jun 10 00:46:29 2013 +0100
    32.2 +++ b/src/Reference.h	Mon Jun 10 01:04:43 2013 +0100
    32.3 @@ -1,76 +1,76 @@
    32.4 -/*
    32.5 - * Copyright (C) 2012 David Anderson
    32.6 - *
    32.7 - * This file is part of SourcePawn.
    32.8 - *
    32.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   32.10 - * the terms of the GNU General Public License as published by the Free
   32.11 - * Software Foundation, either version 3 of the License, or (at your option)
   32.12 - * any later version.
   32.13 - * 
   32.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   32.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   32.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   32.17 - *
   32.18 - * You should have received a copy of the GNU General Public License along with
   32.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   32.20 - */
   32.21 -#ifndef _include_jitcraft_reference_h_
   32.22 -#define _include_jitcraft_reference_h_
   32.23 -
   32.24 -#include "Heap.h"
   32.25 -#include "Barriers.h"
   32.26 -#include "Stack.h"
   32.27 -
   32.28 -namespace ke {
   32.29 -
   32.30 -class Array;
   32.31 -class Struct;
   32.32 -
   32.33 -// A Reference is a typed pointer to another location in memory.
   32.34 -class Reference : public Object
   32.35 -{
   32.36 -    void *location_;
   32.37 -    Barriered<Object> base_;
   32.38 -
   32.39 -    // We do not compute references to objects, so this does not need to be
   32.40 -    // traced.
   32.41 -    LocalSlot slot_;
   32.42 -
   32.43 -  public:
   32.44 -    static Reference *NewStack(Zone *zone, void *location, Heap::Tenure tenure = Heap::Tenure_Default);
   32.45 -    static Reference *NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure = Heap::Tenure_Default);
   32.46 -
   32.47 -    int getInt() {
   32.48 -        return *reinterpret_cast<int *>(location_);
   32.49 -    }
   32.50 -    void setInt(int i) {
   32.51 -        *reinterpret_cast<int *>(location_) = i;
   32.52 -    }
   32.53 -    float getFloat() {
   32.54 -        return *reinterpret_cast<float *>(location_);
   32.55 -    }
   32.56 -    void setFloat(float f) {
   32.57 -        *reinterpret_cast<float *>(location_) = f;
   32.58 -    }
   32.59 -
   32.60 -    // WARNING! This should only be for Native calls.
   32.61 -    void *location() {
   32.62 -        return location_;
   32.63 -    }
   32.64 -
   32.65 -    // Begin GC Descriptor.
   32.66 -    static inline size_t offsetOfBase() {
   32.67 -        return offsetof(Reference, base_);
   32.68 -    }
   32.69 -    // End GC Descriptor.
   32.70 -
   32.71 -    static inline Reference *cast(Object *obj) {
   32.72 -        assert(!obj || obj->is(MapKind_Reference));
   32.73 -        return reinterpret_cast<Reference *>(obj);
   32.74 -    }
   32.75 -};
   32.76 -
   32.77 -}
   32.78 -
   32.79 -#endif // _include_jitcraft_reference_h_
   32.80 +/*
   32.81 + * Copyright (C) 2012 David Anderson
   32.82 + *
   32.83 + * This file is part of SourcePawn.
   32.84 + *
   32.85 + * SourcePawn is free software: you can redistribute it and/or modify it under
   32.86 + * the terms of the GNU General Public License as published by the Free
   32.87 + * Software Foundation, either version 3 of the License, or (at your option)
   32.88 + * any later version.
   32.89 + * 
   32.90 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   32.91 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   32.92 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   32.93 + *
   32.94 + * You should have received a copy of the GNU General Public License along with
   32.95 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   32.96 + */
   32.97 +#ifndef _include_jitcraft_reference_h_
   32.98 +#define _include_jitcraft_reference_h_
   32.99 +
  32.100 +#include "Heap.h"
  32.101 +#include "Barriers.h"
  32.102 +#include "Stack.h"
  32.103 +
  32.104 +namespace ke {
  32.105 +
  32.106 +class Array;
  32.107 +class Struct;
  32.108 +
  32.109 +// A Reference is a typed pointer to another location in memory.
  32.110 +class Reference : public Object
  32.111 +{
  32.112 +    void *location_;
  32.113 +    Barriered<Object> base_;
  32.114 +
  32.115 +    // We do not compute references to objects, so this does not need to be
  32.116 +    // traced.
  32.117 +    LocalSlot slot_;
  32.118 +
  32.119 +  public:
  32.120 +    static Reference *NewStack(Zone *zone, void *location, Heap::Tenure tenure = Heap::Tenure_Default);
  32.121 +    static Reference *NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure = Heap::Tenure_Default);
  32.122 +
  32.123 +    int getInt() {
  32.124 +        return *reinterpret_cast<int *>(location_);
  32.125 +    }
  32.126 +    void setInt(int i) {
  32.127 +        *reinterpret_cast<int *>(location_) = i;
  32.128 +    }
  32.129 +    float getFloat() {
  32.130 +        return *reinterpret_cast<float *>(location_);
  32.131 +    }
  32.132 +    void setFloat(float f) {
  32.133 +        *reinterpret_cast<float *>(location_) = f;
  32.134 +    }
  32.135 +
  32.136 +    // WARNING! This should only be for Native calls.
  32.137 +    void *location() {
  32.138 +        return location_;
  32.139 +    }
  32.140 +
  32.141 +    // Begin GC Descriptor.
  32.142 +    static inline size_t offsetOfBase() {
  32.143 +        return offsetof(Reference, base_);
  32.144 +    }
  32.145 +    // End GC Descriptor.
  32.146 +
  32.147 +    static inline Reference *cast(Object *obj) {
  32.148 +        assert(!obj || obj->is(MapKind_Reference));
  32.149 +        return reinterpret_cast<Reference *>(obj);
  32.150 +    }
  32.151 +};
  32.152 +
  32.153 +}
  32.154 +
  32.155 +#endif // _include_jitcraft_reference_h_
    33.1 --- a/src/RootScopes.h	Mon Jun 10 00:46:29 2013 +0100
    33.2 +++ b/src/RootScopes.h	Mon Jun 10 01:04:43 2013 +0100
    33.3 @@ -1,106 +1,106 @@
    33.4 -/* vim: set ts=4 sw=4 tw=99 et:
    33.5 - *
    33.6 - * Copyright (C) 2012 David Anderson
    33.7 - *
    33.8 - * This file is part of SourcePawn.
    33.9 - *
   33.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   33.11 - * the terms of the GNU General Public License as published by the Free
   33.12 - * Software Foundation, either version 3 of the License, or (at your option)
   33.13 - * any later version.
   33.14 - * 
   33.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   33.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   33.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   33.18 - *
   33.19 - * You should have received a copy of the GNU General Public License along with
   33.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   33.21 - */
   33.22 -#ifndef _include_jc_root_scopes_h_
   33.23 -#define _include_jc_root_scopes_h_
   33.24 -
   33.25 -#include "../include/keima.h"
   33.26 -#include "Objects.h"
   33.27 -#include "VirtualObjectVisitor.h"
   33.28 -
   33.29 -namespace ke {
   33.30 -
   33.31 -class RootScope;
   33.32 -
   33.33 -// A RootScopeManager is essentially a specialized PoolAllocator that can
   33.34 -// only allocate Object ** entries. It is used to allow huge, temporary
   33.35 -// heap data structures like ASTs to hold safe references to objects. When
   33.36 -// the data structures is no longer needed, all of the roots are removed
   33.37 -// at once.
   33.38 -class RootScopeManager
   33.39 -{
   33.40 -    static const size_t kObjectsPerBlock = 4096;
   33.41 -
   33.42 -    struct Block {
   33.43 -        Object *objects[kObjectsPerBlock];
   33.44 -        Object **cur;
   33.45 -        Object **end;
   33.46 -        Block *prev;
   33.47 -
   33.48 -        Block(Block *prev)
   33.49 -          : cur(objects),
   33.50 -            end(objects + kObjectsPerBlock),
   33.51 -            prev(prev)
   33.52 -        {
   33.53 -        }
   33.54 -    };
   33.55 -
   33.56 -  private:
   33.57 -    bool grow();
   33.58 -    void unwindSlow(Object **position);
   33.59 -
   33.60 -  public:
   33.61 -    RootScopeManager();
   33.62 -    ~RootScopeManager();
   33.63 -
   33.64 -    Object **position() const {
   33.65 -        return blocks_->cur;
   33.66 -    }
   33.67 -
   33.68 -    void unwind(Object **position) {
   33.69 -        if (position >= blocks_->cur && position <= blocks_->end) {
   33.70 -            blocks_->cur = position;
   33.71 -            return;
   33.72 -        }
   33.73 -        unwindSlow(position);
   33.74 -    }
   33.75 -
   33.76 -    Object **make(Object *obj) {
   33.77 -        assert(scope_);
   33.78 -        if (blocks_->cur + 1 > blocks_->end) {
   33.79 -            if (!grow())
   33.80 -                return NULL;
   33.81 -        }
   33.82 -        Object **ptr = blocks_->cur;
   33.83 -        blocks_->cur++;
   33.84 -        *ptr = obj;
   33.85 -        return ptr;
   33.86 -    }
   33.87 -
   33.88 -    Ke::HandleScope **scope() {
   33.89 -        return &scope_;
   33.90 -    }
   33.91 -
   33.92 -    void accept(VirtualObjectVisitor *visitor);
   33.93 -
   33.94 -  private:
   33.95 -    Block *blocks_;
   33.96 -    Block first_;
   33.97 -    Ke::HandleScope *scope_;
   33.98 -};
   33.99 -
  33.100 -class RootScope : public Ke::HandleScope
  33.101 -{
  33.102 -  public:
  33.103 -    // These are implemented in Zone.h.
  33.104 -    inline RootScope(Zone *zone);
  33.105 -};
  33.106 -
  33.107 -}
  33.108 -
  33.109 -#endif // _include_jc_root_scope_h_
  33.110 +/* vim: set ts=4 sw=4 tw=99 et:
  33.111 + *
  33.112 + * Copyright (C) 2012 David Anderson
  33.113 + *
  33.114 + * This file is part of SourcePawn.
  33.115 + *
  33.116 + * SourcePawn is free software: you can redistribute it and/or modify it under
  33.117 + * the terms of the GNU General Public License as published by the Free
  33.118 + * Software Foundation, either version 3 of the License, or (at your option)
  33.119 + * any later version.
  33.120 + * 
  33.121 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  33.122 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  33.123 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  33.124 + *
  33.125 + * You should have received a copy of the GNU General Public License along with
  33.126 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  33.127 + */
  33.128 +#ifndef _include_jc_root_scopes_h_
  33.129 +#define _include_jc_root_scopes_h_
  33.130 +
  33.131 +#include "../include/keima.h"
  33.132 +#include "Objects.h"
  33.133 +#include "VirtualObjectVisitor.h"
  33.134 +
  33.135 +namespace ke {
  33.136 +
  33.137 +class RootScope;
  33.138 +
  33.139 +// A RootScopeManager is essentially a specialized PoolAllocator that can
  33.140 +// only allocate Object ** entries. It is used to allow huge, temporary
  33.141 +// heap data structures like ASTs to hold safe references to objects. When
  33.142 +// the data structures is no longer needed, all of the roots are removed
  33.143 +// at once.
  33.144 +class RootScopeManager
  33.145 +{
  33.146 +    static const size_t kObjectsPerBlock = 4096;
  33.147 +
  33.148 +    struct Block {
  33.149 +        Object *objects[kObjectsPerBlock];
  33.150 +        Object **cur;
  33.151 +        Object **end;
  33.152 +        Block *prev;
  33.153 +
  33.154 +        Block(Block *prev)
  33.155 +          : cur(objects),
  33.156 +            end(objects + kObjectsPerBlock),
  33.157 +            prev(prev)
  33.158 +        {
  33.159 +        }
  33.160 +    };
  33.161 +
  33.162 +  private:
  33.163 +    bool grow();
  33.164 +    void unwindSlow(Object **position);
  33.165 +
  33.166 +  public:
  33.167 +    RootScopeManager();
  33.168 +    ~RootScopeManager();
  33.169 +
  33.170 +    Object **position() const {
  33.171 +        return blocks_->cur;
  33.172 +    }
  33.173 +
  33.174 +    void unwind(Object **position) {
  33.175 +        if (position >= blocks_->cur && position <= blocks_->end) {
  33.176 +            blocks_->cur = position;
  33.177 +            return;
  33.178 +        }
  33.179 +        unwindSlow(position);
  33.180 +    }
  33.181 +
  33.182 +    Object **make(Object *obj) {
  33.183 +        assert(scope_);
  33.184 +        if (blocks_->cur + 1 > blocks_->end) {
  33.185 +            if (!grow())
  33.186 +                return NULL;
  33.187 +        }
  33.188 +        Object **ptr = blocks_->cur;
  33.189 +        blocks_->cur++;
  33.190 +        *ptr = obj;
  33.191 +        return ptr;
  33.192 +    }
  33.193 +
  33.194 +    Ke::HandleScope **scope() {
  33.195 +        return &scope_;
  33.196 +    }
  33.197 +
  33.198 +    void accept(VirtualObjectVisitor *visitor);
  33.199 +
  33.200 +  private:
  33.201 +    Block *blocks_;
  33.202 +    Block first_;
  33.203 +    Ke::HandleScope *scope_;
  33.204 +};
  33.205 +
  33.206 +class RootScope : public Ke::HandleScope
  33.207 +{
  33.208 +  public:
  33.209 +    // These are implemented in Zone.h.
  33.210 +    inline RootScope(Zone *zone);
  33.211 +};
  33.212 +
  33.213 +}
  33.214 +
  33.215 +#endif // _include_jc_root_scope_h_
    34.1 --- a/src/Stack.h	Mon Jun 10 00:46:29 2013 +0100
    34.2 +++ b/src/Stack.h	Mon Jun 10 01:04:43 2013 +0100
    34.3 @@ -1,246 +1,246 @@
    34.4 -/* vim: set ts=4 sw=4 tw=99 et:
    34.5 - *
    34.6 - * Copyright (C) 2012 David Anderson
    34.7 - *
    34.8 - * This file is part of JITCraft.
    34.9 - *
   34.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   34.11 - * the terms of the GNU General Public License as published by the Free
   34.12 - * Software Foundation, either version 3 of the License, or (at your option)
   34.13 - * any later version.
   34.14 - * 
   34.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   34.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   34.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   34.18 - *
   34.19 - * You should have received a copy of the GNU General Public License along with
   34.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   34.21 - */
   34.22 -#ifndef _include_jc_stack_h_
   34.23 -#define _include_jc_stack_h_
   34.24 -
   34.25 -#include <stddef.h>
   34.26 -#include "Utility.h"
   34.27 -#include "Code.h"
   34.28 -#include "Functions.h"
   34.29 -#include "VirtualObjectVisitor.h"
   34.30 -
   34.31 -namespace ke {
   34.32 -
   34.33 -class Object;
   34.34 -class Array;
   34.35 -class Reference;
   34.36 -class Frame;
   34.37 -class Stack;
   34.38 -class Zone;
   34.39 -class Module;
   34.40 -    
   34.41 -union LocalSlot
   34.42 -{
   34.43 -    int i32;
   34.44 -    float f;
   34.45 -    Address address;
   34.46 -    Object *obj;
   34.47 -    Array *array;
   34.48 -    Reference *ref;
   34.49 -    Function *fun;
   34.50 -    Module *module;
   34.51 -};
   34.52 -
   34.53 -struct Top
   34.54 -{
   34.55 -    LocalSlot *sp;
   34.56 -    bytecode *pc;
   34.57 -    Frame *fp;
   34.58 -};
   34.59 -
   34.60 -class Frame
   34.61 -{
   34.62 -    friend class Stack;
   34.63 -
   34.64 -    Frame *prev_;
   34.65 -    bytecode *prevpc_;
   34.66 -    union {
   34.67 -        Function *fun_;
   34.68 -        Native *native_;
   34.69 -        Object *callee_;
   34.70 -    };
   34.71 -    Code *code_;
   34.72 -
   34.73 -    // Position of the LIFO stack at function entry.
   34.74 -    Address lifoPosition_;
   34.75 -    
   34.76 -    // Loop nesting level, for LIFO stack balancing. LIFO stack balancing
   34.77 -    // is not strictly required, but it helps to avoid unnecessary waste,
   34.78 -    // since once the LIFO stack is depleted, we must use the heap instead.
   34.79 -    unsigned loopDepth_;
   34.80 -
   34.81 -  public:
   34.82 -    Frame(Frame *prev, bytecode *prevpc, Function *fun, Code *code, Address lifoPosition)
   34.83 -      : prev_(prev),
   34.84 -        prevpc_(prevpc),
   34.85 -        fun_(fun),
   34.86 -        code_(code),
   34.87 -        lifoPosition_(lifoPosition),
   34.88 -        loopDepth_(0)
   34.89 -    {
   34.90 -    }
   34.91 -
   34.92 -    Frame(Frame *prev, bytecode *prevpc, Native *native, Address lifoPosition)
   34.93 -      : prev_(prev),
   34.94 -        prevpc_(prevpc),
   34.95 -        native_(native),
   34.96 -        code_(NULL),
   34.97 -        lifoPosition_(lifoPosition)
   34.98 -    {
   34.99 -    }
  34.100 -
  34.101 -    Address *loopStack() {
  34.102 -        return reinterpret_cast<Address *>(this + 1);
  34.103 -    }
  34.104 -    LocalSlot *locals() {
  34.105 -        return reinterpret_cast<LocalSlot *>(loopStack() + code_->maxLoopDepth());
  34.106 -    }
  34.107 -    LocalSlot *stackBase() {
  34.108 -        return locals() + code_->nlocals();
  34.109 -    }
  34.110 -    Function *fun() const {
  34.111 -        assert(fun_ && callee_->is(MapKind_Function));
  34.112 -        return fun_;
  34.113 -    }
  34.114 -    Function *maybeFun() const {
  34.115 -        return (fun_ && callee_->is(MapKind_Function)) ? fun_ : NULL;
  34.116 -    }
  34.117 -    bool isNative() const {
  34.118 -        return callee_ && callee_->is(MapKind_Native);
  34.119 -    }
  34.120 -    Native *native() const {
  34.121 -        assert(isNative());
  34.122 -        return native_;
  34.123 -    }
  34.124 -    Code *code() const {
  34.125 -        assert(code_);
  34.126 -        return code_;
  34.127 -    }
  34.128 -    Frame *prev() const {
  34.129 -        return prev_;
  34.130 -    }
  34.131 -    bytecode *prevpc() const {
  34.132 -        return prevpc_;
  34.133 -    }
  34.134 -    Address lifoPosition() const {
  34.135 -        return lifoPosition_;
  34.136 -    }
  34.137 -    LocalSlot &arg(unsigned slot) {
  34.138 -        assert(slot < fun()->nargs());
  34.139 -        return *(reinterpret_cast<LocalSlot *>(this) - slot - 1);
  34.140 -    }
  34.141 -    void enterLoop(Zone *zone);
  34.142 -    void leaveLoop(Zone *zone);
  34.143 -    void accept(VirtualObjectVisitor *visitor);
  34.144 -};
  34.145 -
  34.146 -// RAII object for calling a function from C++.
  34.147 -class InvokeArgs
  34.148 -{
  34.149 -    friend class Stack;
  34.150 -
  34.151 -    Stack *stack_;
  34.152 -    LocalSlot *args_;
  34.153 -    unsigned nargs_;
  34.154 -
  34.155 -  public:
  34.156 -    InvokeArgs()
  34.157 -      : stack_(NULL),
  34.158 -        args_(NULL),
  34.159 -        nargs_(0)
  34.160 -    {
  34.161 -    }
  34.162 -
  34.163 -    ~InvokeArgs();
  34.164 -
  34.165 -    LocalSlot &arg(unsigned index) {
  34.166 -        assert(index < nargs_);
  34.167 -        return args_[nargs_ - index - 1];
  34.168 -    }
  34.169 -};
  34.170 -
  34.171 -// RAII object for calling a native from C++.
  34.172 -class NativeArgs
  34.173 -{
  34.174 -    friend class Stack;
  34.175 -
  34.176 -    Stack *stack_;
  34.177 -    LocalSlot *argsBase_;
  34.178 -
  34.179 -  public:
  34.180 -    NativeArgs()
  34.181 -      : stack_(NULL),
  34.182 -        argsBase_(NULL)
  34.183 -    {
  34.184 -    }
  34.185 -
  34.186 -    ~NativeArgs();
  34.187 -
  34.188 -    intptr_t *args() {
  34.189 -        return reinterpret_cast<intptr_t *>(argsBase_);
  34.190 -    }
  34.191 -};
  34.192 -
  34.193 -class Stack
  34.194 -{
  34.195 -    friend class InvokeArgs;
  34.196 -    friend class NativeArgs;
  34.197 -
  34.198 -  private:
  34.199 -    static const size_t STACK_SIZE = 1024 * 1024;
  34.200 -
  34.201 -  public:
  34.202 -    Stack(Zone *zone);
  34.203 -    ~Stack();
  34.204 -
  34.205 -    bool initialize();
  34.206 -
  34.207 -  public:
  34.208 -    Frame *pushInlineFrame(Handle<Function> fun);
  34.209 -    Frame *popInlineFrame();
  34.210 -
  34.211 -    bool pushInvokeFrame(Handle<Function> fun, InvokeArgs &args);
  34.212 -    bool pushModuleFrame(Handle<Module> module, InvokeArgs &args);
  34.213 -    bool pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc);
  34.214 -
  34.215 -    Top *top() {
  34.216 -        return &top_;
  34.217 -    }
  34.218 -    bool isInCallStack(Handle<Module> module);
  34.219 -    void accept(VirtualObjectVisitor *visitor);
  34.220 -
  34.221 -  private:
  34.222 -    void popInvokeFrame(InvokeArgs &args);
  34.223 -    void popNativeFrame(NativeArgs &args);
  34.224 -
  34.225 -  private:
  34.226 -    Zone *zone_;
  34.227 -    char *buffer_;
  34.228 -    char *end_;
  34.229 -    Top top_;
  34.230 -};
  34.231 -
  34.232 -class StackIter
  34.233 -{
  34.234 -    bytecode *pc_;
  34.235 -    Frame *fp_;
  34.236 -
  34.237 -  public:
  34.238 -    StackIter(Zone *zone);
  34.239 -
  34.240 -    bool done() const;
  34.241 -    const char *function() const;
  34.242 -    unsigned lineNumber() const;
  34.243 -    const char *source() const;
  34.244 -    void prev();
  34.245 -};
  34.246 -
  34.247 -}
  34.248 -
  34.249 -#endif // _include_jc_stack_h_
  34.250 +/* vim: set ts=4 sw=4 tw=99 et:
  34.251 + *
  34.252 + * Copyright (C) 2012 David Anderson
  34.253 + *
  34.254 + * This file is part of JITCraft.
  34.255 + *
  34.256 + * JITCraft is free software: you can redistribute it and/or modify it under
  34.257 + * the terms of the GNU General Public License as published by the Free
  34.258 + * Software Foundation, either version 3 of the License, or (at your option)
  34.259 + * any later version.
  34.260 + * 
  34.261 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  34.262 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  34.263 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  34.264 + *
  34.265 + * You should have received a copy of the GNU General Public License along with
  34.266 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  34.267 + */
  34.268 +#ifndef _include_jc_stack_h_
  34.269 +#define _include_jc_stack_h_
  34.270 +
  34.271 +#include <stddef.h>
  34.272 +#include "Utility.h"
  34.273 +#include "Code.h"
  34.274 +#include "Functions.h"
  34.275 +#include "VirtualObjectVisitor.h"
  34.276 +
  34.277 +namespace ke {
  34.278 +
  34.279 +class Object;
  34.280 +class Array;
  34.281 +class Reference;
  34.282 +class Frame;
  34.283 +class Stack;
  34.284 +class Zone;
  34.285 +class Module;
  34.286 +    
  34.287 +union LocalSlot
  34.288 +{
  34.289 +    int i32;
  34.290 +    float f;
  34.291 +    Address address;
  34.292 +    Object *obj;
  34.293 +    Array *array;
  34.294 +    Reference *ref;
  34.295 +    Function *fun;
  34.296 +    Module *module;
  34.297 +};
  34.298 +
  34.299 +struct Top
  34.300 +{
  34.301 +    LocalSlot *sp;
  34.302 +    bytecode *pc;
  34.303 +    Frame *fp;
  34.304 +};
  34.305 +
  34.306 +class Frame
  34.307 +{
  34.308 +    friend class Stack;
  34.309 +
  34.310 +    Frame *prev_;
  34.311 +    bytecode *prevpc_;
  34.312 +    union {
  34.313 +        Function *fun_;
  34.314 +        Native *native_;
  34.315 +        Object *callee_;
  34.316 +    };
  34.317 +    Code *code_;
  34.318 +
  34.319 +    // Position of the LIFO stack at function entry.
  34.320 +    Address lifoPosition_;
  34.321 +    
  34.322 +    // Loop nesting level, for LIFO stack balancing. LIFO stack balancing
  34.323 +    // is not strictly required, but it helps to avoid unnecessary waste,
  34.324 +    // since once the LIFO stack is depleted, we must use the heap instead.
  34.325 +    unsigned loopDepth_;
  34.326 +
  34.327 +  public:
  34.328 +    Frame(Frame *prev, bytecode *prevpc, Function *fun, Code *code, Address lifoPosition)
  34.329 +      : prev_(prev),
  34.330 +        prevpc_(prevpc),
  34.331 +        fun_(fun),
  34.332 +        code_(code),
  34.333 +        lifoPosition_(lifoPosition),
  34.334 +        loopDepth_(0)
  34.335 +    {
  34.336 +    }
  34.337 +
  34.338 +    Frame(Frame *prev, bytecode *prevpc, Native *native, Address lifoPosition)
  34.339 +      : prev_(prev),
  34.340 +        prevpc_(prevpc),
  34.341 +        native_(native),
  34.342 +        code_(NULL),
  34.343 +        lifoPosition_(lifoPosition)
  34.344 +    {
  34.345 +    }
  34.346 +
  34.347 +    Address *loopStack() {
  34.348 +        return reinterpret_cast<Address *>(this + 1);
  34.349 +    }
  34.350 +    LocalSlot *locals() {
  34.351 +        return reinterpret_cast<LocalSlot *>(loopStack() + code_->maxLoopDepth());
  34.352 +    }
  34.353 +    LocalSlot *stackBase() {
  34.354 +        return locals() + code_->nlocals();
  34.355 +    }
  34.356 +    Function *fun() const {
  34.357 +        assert(fun_ && callee_->is(MapKind_Function));
  34.358 +        return fun_;
  34.359 +    }
  34.360 +    Function *maybeFun() const {
  34.361 +        return (fun_ && callee_->is(MapKind_Function)) ? fun_ : NULL;
  34.362 +    }
  34.363 +    bool isNative() const {
  34.364 +        return callee_ && callee_->is(MapKind_Native);
  34.365 +    }
  34.366 +    Native *native() const {
  34.367 +        assert(isNative());
  34.368 +        return native_;
  34.369 +    }
  34.370 +    Code *code() const {
  34.371 +        assert(code_);
  34.372 +        return code_;
  34.373 +    }
  34.374 +    Frame *prev() const {
  34.375 +        return prev_;
  34.376 +    }
  34.377 +    bytecode *prevpc() const {
  34.378 +        return prevpc_;
  34.379 +    }
  34.380 +    Address lifoPosition() const {
  34.381 +        return lifoPosition_;
  34.382 +    }
  34.383 +    LocalSlot &arg(unsigned slot) {
  34.384 +        assert(slot < fun()->nargs());
  34.385 +        return *(reinterpret_cast<LocalSlot *>(this) - slot - 1);
  34.386 +    }
  34.387 +    void enterLoop(Zone *zone);
  34.388 +    void leaveLoop(Zone *zone);
  34.389 +    void accept(VirtualObjectVisitor *visitor);
  34.390 +};
  34.391 +
  34.392 +// RAII object for calling a function from C++.
  34.393 +class InvokeArgs
  34.394 +{
  34.395 +    friend class Stack;
  34.396 +
  34.397 +    Stack *stack_;
  34.398 +    LocalSlot *args_;
  34.399 +    unsigned nargs_;
  34.400 +
  34.401 +  public:
  34.402 +    InvokeArgs()
  34.403 +      : stack_(NULL),
  34.404 +        args_(NULL),
  34.405 +        nargs_(0)
  34.406 +    {
  34.407 +    }
  34.408 +
  34.409 +    ~InvokeArgs();
  34.410 +
  34.411 +    LocalSlot &arg(unsigned index) {
  34.412 +        assert(index < nargs_);
  34.413 +        return args_[nargs_ - index - 1];
  34.414 +    }
  34.415 +};
  34.416 +
  34.417 +// RAII object for calling a native from C++.
  34.418 +class NativeArgs
  34.419 +{
  34.420 +    friend class Stack;
  34.421 +
  34.422 +    Stack *stack_;
  34.423 +    LocalSlot *argsBase_;
  34.424 +
  34.425 +  public:
  34.426 +    NativeArgs()
  34.427 +      : stack_(NULL),
  34.428 +        argsBase_(NULL)
  34.429 +    {
  34.430 +    }
  34.431 +
  34.432 +    ~NativeArgs();
  34.433 +
  34.434 +    intptr_t *args() {
  34.435 +        return reinterpret_cast<intptr_t *>(argsBase_);
  34.436 +    }
  34.437 +};
  34.438 +
  34.439 +class Stack
  34.440 +{
  34.441 +    friend class InvokeArgs;
  34.442 +    friend class NativeArgs;
  34.443 +
  34.444 +  private:
  34.445 +    static const size_t STACK_SIZE = 1024 * 1024;
  34.446 +
  34.447 +  public:
  34.448 +    Stack(Zone *zone);
  34.449 +    ~Stack();
  34.450 +
  34.451 +    bool initialize();
  34.452 +
  34.453 +  public:
  34.454 +    Frame *pushInlineFrame(Handle<Function> fun);
  34.455 +    Frame *popInlineFrame();
  34.456 +
  34.457 +    bool pushInvokeFrame(Handle<Function> fun, InvokeArgs &args);
  34.458 +    bool pushModuleFrame(Handle<Module> module, InvokeArgs &args);
  34.459 +    bool pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc);
  34.460 +
  34.461 +    Top *top() {
  34.462 +        return &top_;
  34.463 +    }
  34.464 +    bool isInCallStack(Handle<Module> module);
  34.465 +    void accept(VirtualObjectVisitor *visitor);
  34.466 +
  34.467 +  private:
  34.468 +    void popInvokeFrame(InvokeArgs &args);
  34.469 +    void popNativeFrame(NativeArgs &args);
  34.470 +
  34.471 +  private:
  34.472 +    Zone *zone_;
  34.473 +    char *buffer_;
  34.474 +    char *end_;
  34.475 +    Top top_;
  34.476 +};
  34.477 +
  34.478 +class StackIter
  34.479 +{
  34.480 +    bytecode *pc_;
  34.481 +    Frame *fp_;
  34.482 +
  34.483 +  public:
  34.484 +    StackIter(Zone *zone);
  34.485 +
  34.486 +    bool done() const;
  34.487 +    const char *function() const;
  34.488 +    unsigned lineNumber() const;
  34.489 +    const char *source() const;
  34.490 +    void prev();
  34.491 +};
  34.492 +
  34.493 +}
  34.494 +
  34.495 +#endif // _include_jc_stack_h_
    35.1 --- a/src/StringPool.cpp	Mon Jun 10 00:46:29 2013 +0100
    35.2 +++ b/src/StringPool.cpp	Mon Jun 10 01:04:43 2013 +0100
    35.3 @@ -1,72 +1,72 @@
    35.4 -/*
    35.5 - * Copyright (C) 2012 David Anderson
    35.6 - *
    35.7 - * This file is part of JITCraft.
    35.8 - *
    35.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   35.10 - * the terms of the GNU General Public License as published by the Free
   35.11 - * Software Foundation, either version 3 of the License, or (at your option)
   35.12 - * any later version.
   35.13 - * 
   35.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   35.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   35.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   35.17 - *
   35.18 - * You should have received a copy of the GNU General Public License along with
   35.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   35.20 - */
   35.21 -#include "Zone.h"
   35.22 -#include "StringPool.h"
   35.23 -#include "Strings.h"
   35.24 -#include "Spaces.h"
   35.25 -#include "Spaces-inl.h"
   35.26 -#include "Heap-inl.h"
   35.27 -
   35.28 -using namespace ke;
   35.29 -
   35.30 -StringPool::StringPool(Zone *zone)
   35.31 -  : zone_(zone),
   35.32 -    set_(ZoneAllocatorPolicy())
   35.33 -{
   35.34 -}
   35.35 -
   35.36 -StringPool::~StringPool()
   35.37 -{
   35.38 -}
   35.39 -
   35.40 -bool
   35.41 -StringPool::initialize()
   35.42 -{
   35.43 -    if (!set_.init(32))
   35.44 -        return false;
   35.45 -    return true;
   35.46 -}
   35.47 -
   35.48 -String *
   35.49 -StringPool::add(const char *str, size_t length)
   35.50 -{
   35.51 -    StringSet::Insert i = set_.findForAdd(CharsAndLength(str, length));
   35.52 -    if (i.found())
   35.53 -        return *i;
   35.54 -
   35.55 -    Local<String> obj(zone_, String::New(zone_, str, length, Heap::Tenure_Old));
   35.56 -    if (!obj)
   35.57 -        return NULL;
   35.58 -
   35.59 -    set_.add(i, obj);
   35.60 -    return obj;
   35.61 -}
   35.62 -
   35.63 -void
   35.64 -StringPool::sweep()
   35.65 -{
   35.66 -    for (StringSet::iterator i(&set_); !i.empty(); i.next()) {
   35.67 -        String *obj = *i;
   35.68 -        MarkBit bits = HeapChunk::GetMarkBit(obj);
   35.69 -        if (HeapChunk::IsWhite(bits))
   35.70 -            i.erase();
   35.71 -        else
   35.72 -            assert(HeapChunk::IsBlack(bits));
   35.73 -    }
   35.74 -    set_.checkDensity();
   35.75 -}
   35.76 +/*
   35.77 + * Copyright (C) 2012 David Anderson
   35.78 + *
   35.79 + * This file is part of JITCraft.
   35.80 + *
   35.81 + * JITCraft is free software: you can redistribute it and/or modify it under
   35.82 + * the terms of the GNU General Public License as published by the Free
   35.83 + * Software Foundation, either version 3 of the License, or (at your option)
   35.84 + * any later version.
   35.85 + * 
   35.86 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   35.87 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   35.88 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   35.89 + *
   35.90 + * You should have received a copy of the GNU General Public License along with
   35.91 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   35.92 + */
   35.93 +#include "Zone.h"
   35.94 +#include "StringPool.h"
   35.95 +#include "Strings.h"
   35.96 +#include "Spaces.h"
   35.97 +#include "Spaces-inl.h"
   35.98 +#include "Heap-inl.h"
   35.99 +
  35.100 +using namespace ke;
  35.101 +
  35.102 +StringPool::StringPool(Zone *zone)
  35.103 +  : zone_(zone),
  35.104 +    set_(ZoneAllocatorPolicy())
  35.105 +{
  35.106 +}
  35.107 +
  35.108 +StringPool::~StringPool()
  35.109 +{
  35.110 +}
  35.111 +
  35.112 +bool
  35.113 +StringPool::initialize()
  35.114 +{
  35.115 +    if (!set_.init(32))
  35.116 +        return false;
  35.117 +    return true;
  35.118 +}
  35.119 +
  35.120 +String *
  35.121 +StringPool::add(const char *str, size_t length)
  35.122 +{
  35.123 +    StringSet::Insert i = set_.findForAdd(CharsAndLength(str, length));
  35.124 +    if (i.found())
  35.125 +        return *i;
  35.126 +
  35.127 +    Local<String> obj(zone_, String::New(zone_, str, length, Heap::Tenure_Old));
  35.128 +    if (!obj)
  35.129 +        return NULL;
  35.130 +
  35.131 +    set_.add(i, obj);
  35.132 +    return obj;
  35.133 +}
  35.134 +
  35.135 +void
  35.136 +StringPool::sweep()
  35.137 +{
  35.138 +    for (StringSet::iterator i(&set_); !i.empty(); i.next()) {
  35.139 +        String *obj = *i;
  35.140 +        MarkBit bits = HeapChunk::GetMarkBit(obj);
  35.141 +        if (HeapChunk::IsWhite(bits))
  35.142 +            i.erase();
  35.143 +        else
  35.144 +            assert(HeapChunk::IsBlack(bits));
  35.145 +    }
  35.146 +    set_.checkDensity();
  35.147 +}
    36.1 --- a/src/StringPool.h	Mon Jun 10 00:46:29 2013 +0100
    36.2 +++ b/src/StringPool.h	Mon Jun 10 01:04:43 2013 +0100
    36.3 @@ -1,68 +1,68 @@
    36.4 -/* vim: set ts=4 sw=4 tw=99 et:
    36.5 - *
    36.6 - * Copyright (C) 2012 David Anderson
    36.7 - *
    36.8 - * This file is part of SourcePawn.
    36.9 - *
   36.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   36.11 - * the terms of the GNU General Public License as published by the Free
   36.12 - * Software Foundation, either version 3 of the License, or (at your option)
   36.13 - * any later version.
   36.14 - * 
   36.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   36.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   36.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   36.18 - *
   36.19 - * You should have received a copy of the GNU General Public License along with
   36.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   36.21 - */
   36.22 -#ifndef _include_jitcraft_string_pool_h_
   36.23 -#define _include_jitcraft_string_pool_h_
   36.24 -
   36.25 -#include <string.h>
   36.26 -#include "AllocatorPolicies.h"
   36.27 -#include "HashTable.h"
   36.28 -#include "Strings.h"
   36.29 -
   36.30 -namespace ke {
   36.31 -
   36.32 -class Zone;
   36.33 -class String;
   36.34 -
   36.35 -// Guarantee that strings with the same contents will map to one pointer. 
   36.36 -class StringPool
   36.37 -{
   36.38 -    struct Policy
   36.39 -    {
   36.40 -        typedef String * Payload;
   36.41 -
   36.42 -        static uint32 hash(const CharsAndLength &key) {
   36.43 -            return HashCharSequence(key.str(), key.length());
   36.44 -        }
   36.45 -        
   36.46 -        static bool matches(const CharsAndLength &key, String *string) {
   36.47 -            if (string->length() != key.length())
   36.48 -                return false;
   36.49 -            return memcmp(string->chars(), key.str(), key.length() * sizeof(char)) == 0;
   36.50 -        }
   36.51 -    };
   36.52 -
   36.53 -    typedef HashTable<Policy, ZoneAllocatorPolicy> StringSet;
   36.54 -
   36.55 -  public:
   36.56 -    StringPool(Zone *zone);
   36.57 -    ~StringPool();
   36.58 -    bool initialize();
   36.59 -
   36.60 -  public:
   36.61 -    String *add(const char *str, size_t len);
   36.62 -    void sweep();
   36.63 -
   36.64 -  private:
   36.65 -    Zone *zone_;
   36.66 -    StringSet set_;
   36.67 -};
   36.68 -
   36.69 -}
   36.70 -
   36.71 -#endif // _include_jitcraft_string_pool_h_
   36.72 +/* vim: set ts=4 sw=4 tw=99 et:
   36.73 + *
   36.74 + * Copyright (C) 2012 David Anderson
   36.75 + *
   36.76 + * This file is part of SourcePawn.
   36.77 + *
   36.78 + * SourcePawn is free software: you can redistribute it and/or modify it under
   36.79 + * the terms of the GNU General Public License as published by the Free
   36.80 + * Software Foundation, either version 3 of the License, or (at your option)
   36.81 + * any later version.
   36.82 + * 
   36.83 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   36.84 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   36.85 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   36.86 + *
   36.87 + * You should have received a copy of the GNU General Public License along with
   36.88 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   36.89 + */
   36.90 +#ifndef _include_jitcraft_string_pool_h_
   36.91 +#define _include_jitcraft_string_pool_h_
   36.92 +
   36.93 +#include <string.h>
   36.94 +#include "AllocatorPolicies.h"
   36.95 +#include "HashTable.h"
   36.96 +#include "Strings.h"
   36.97 +
   36.98 +namespace ke {
   36.99 +
  36.100 +class Zone;
  36.101 +class String;
  36.102 +
  36.103 +// Guarantee that strings with the same contents will map to one pointer. 
  36.104 +class StringPool
  36.105 +{
  36.106 +    struct Policy
  36.107 +    {
  36.108 +        typedef String * Payload;
  36.109 +
  36.110 +        static uint32 hash(const CharsAndLength &key) {
  36.111 +            return HashCharSequence(key.str(), key.length());
  36.112 +        }
  36.113 +        
  36.114 +        static bool matches(const CharsAndLength &key, String *string) {
  36.115 +            if (string->length() != key.length())
  36.116 +                return false;
  36.117 +            return memcmp(string->chars(), key.str(), key.length() * sizeof(char)) == 0;
  36.118 +        }
  36.119 +    };
  36.120 +
  36.121 +    typedef HashTable<Policy, ZoneAllocatorPolicy> StringSet;
  36.122 +
  36.123 +  public:
  36.124 +    StringPool(Zone *zone);
  36.125 +    ~StringPool();
  36.126 +    bool initialize();
  36.127 +
  36.128 +  public:
  36.129 +    String *add(const char *str, size_t len);
  36.130 +    void sweep();
  36.131 +
  36.132 +  private:
  36.133 +    Zone *zone_;
  36.134 +    StringSet set_;
  36.135 +};
  36.136 +
  36.137 +}
  36.138 +
  36.139 +#endif // _include_jitcraft_string_pool_h_
    37.1 --- a/src/Strings.cpp	Mon Jun 10 00:46:29 2013 +0100
    37.2 +++ b/src/Strings.cpp	Mon Jun 10 01:04:43 2013 +0100
    37.3 @@ -1,44 +1,44 @@
    37.4 -/* vim: set ts=4 sw=4 tw=99 et:
    37.5 - *
    37.6 - * Copyright (C) 2012 David Anderson
    37.7 - *
    37.8 - * This file is part of JITCraft.
    37.9 - *
   37.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   37.11 - * the terms of the GNU General Public License as published by the Free
   37.12 - * Software Foundation, either version 3 of the License, or (at your option)
   37.13 - * any later version.
   37.14 - * 
   37.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   37.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   37.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   37.18 - *
   37.19 - * You should have received a copy of the GNU General Public License along with
   37.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   37.21 - */
   37.22 -#include <string.h>
   37.23 -#include "Strings.h"
   37.24 -#include "Zone.h"
   37.25 -#include "Heap-inl.h"
   37.26 -
   37.27 -using namespace ke;
   37.28 -
   37.29 -String *
   37.30 -String::New(Zone *zone, const char *from, Heap::Tenure tenure)
   37.31 -{
   37.32 -    return New(zone, from, strlen(from), tenure);
   37.33 -}
   37.34 -
   37.35 -String *
   37.36 -String::New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure)
   37.37 -{
   37.38 -    size_t bytes = SizeFor(length);
   37.39 -    Local<String> string(zone, String::cast(zone->allocate(MapKind_String, bytes, tenure)));
   37.40 -    if (!string)
   37.41 -        return NULL;
   37.42 -
   37.43 -    string->length_ = length;
   37.44 -    memcpy(string->chars(), from, length + 1);
   37.45 -
   37.46 -    return string;
   37.47 -}
   37.48 +/* vim: set ts=4 sw=4 tw=99 et:
   37.49 + *
   37.50 + * Copyright (C) 2012 David Anderson
   37.51 + *
   37.52 + * This file is part of JITCraft.
   37.53 + *
   37.54 + * JITCraft is free software: you can redistribute it and/or modify it under
   37.55 + * the terms of the GNU General Public License as published by the Free
   37.56 + * Software Foundation, either version 3 of the License, or (at your option)
   37.57 + * any later version.
   37.58 + * 
   37.59 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   37.60 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   37.61 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   37.62 + *
   37.63 + * You should have received a copy of the GNU General Public License along with
   37.64 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   37.65 + */
   37.66 +#include <string.h>
   37.67 +#include "Strings.h"
   37.68 +#include "Zone.h"
   37.69 +#include "Heap-inl.h"
   37.70 +
   37.71 +using namespace ke;
   37.72 +
   37.73 +String *
   37.74 +String::New(Zone *zone, const char *from, Heap::Tenure tenure)
   37.75 +{
   37.76 +    return New(zone, from, strlen(from), tenure);
   37.77 +}
   37.78 +
   37.79 +String *
   37.80 +String::New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure)
   37.81 +{
   37.82 +    size_t bytes = SizeFor(length);
   37.83 +    Local<String> string(zone, String::cast(zone->allocate(MapKind_String, bytes, tenure)));
   37.84 +    if (!string)
   37.85 +        return NULL;
   37.86 +
   37.87 +    string->length_ = length;
   37.88 +    memcpy(string->chars(), from, length + 1);
   37.89 +
   37.90 +    return string;
   37.91 +}
    38.1 --- a/src/Strings.h	Mon Jun 10 00:46:29 2013 +0100
    38.2 +++ b/src/Strings.h	Mon Jun 10 01:04:43 2013 +0100
    38.3 @@ -1,80 +1,80 @@
    38.4 -/* vim: set ts=4 sw=4 tw=99 et:
    38.5 - *
    38.6 - * Copyright (C) 2012 David Anderson
    38.7 - *
    38.8 - * This file is part of JITCraft.
    38.9 - *
   38.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   38.11 - * the terms of the GNU General Public License as published by the Free
   38.12 - * Software Foundation, either version 3 of the License, or (at your option)
   38.13 - * any later version.
   38.14 - * 
   38.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   38.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   38.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   38.18 - *
   38.19 - * You should have received a copy of the GNU General Public License along with
   38.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   38.21 - */
   38.22 -#ifndef _include_jitcraft_string_h_
   38.23 -#define _include_jitcraft_string_h_
   38.24 -
   38.25 -#include "Heap.h"
   38.26 -
   38.27 -namespace ke {
   38.28 -
   38.29 -// A fixed-length string containing UTF-8 characters.
   38.30 -class String : public Object
   38.31 -{
   38.32 -    uint32 length_;
   38.33 -    
   38.34 -  public:
   38.35 -    static String *New(Zone *zone, const char *from, Heap::Tenure tenure = Heap::Tenure_Default);
   38.36 -    static String *New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure = Heap::Tenure_Default);
   38.37 -
   38.38 -    unsigned length() {
   38.39 -        return length_;
   38.40 -    }
   38.41 -    char *chars() {
   38.42 -        return reinterpret_cast<char *>(this + 1);
   38.43 -    }
   38.44 -    char *chars(Zone *zone) {
   38.45 -        return chars();
   38.46 -    }
   38.47 -    size_t objSize() {
   38.48 -        return SizeFor(length());
   38.49 -    }
   38.50 -
   38.51 -    static size_t SizeFor(unsigned length) {
   38.52 -        return sizeof(String) + sizeof(char) * (length + 1);
   38.53 -    }
   38.54 -
   38.55 -    static inline String *cast(Object *obj) {
   38.56 -        assert(!obj || obj->is(MapKind_String));
   38.57 -        return reinterpret_cast<String *>(obj);
   38.58 -    }
   38.59 -};
   38.60 -
   38.61 -class CharsAndLength
   38.62 -{
   38.63 -    const char *str_;
   38.64 -    size_t length_;
   38.65 -
   38.66 -  public:
   38.67 -    CharsAndLength(const char *str, size_t length)
   38.68 -        : str_(str),
   38.69 -        length_(length)
   38.70 -    {
   38.71 -    }
   38.72 -
   38.73 -    const char *str() const {
   38.74 -        return str_;
   38.75 -    }
   38.76 -    size_t length() const {
   38.77 -        return length_;
   38.78 -    }
   38.79 -};
   38.80 -
   38.81 -}
   38.82 -
   38.83 -#endif // _include_jitcraft_string_h_
   38.84 +/* vim: set ts=4 sw=4 tw=99 et:
   38.85 + *
   38.86 + * Copyright (C) 2012 David Anderson
   38.87 + *
   38.88 + * This file is part of JITCraft.
   38.89 + *
   38.90 + * JITCraft is free software: you can redistribute it and/or modify it under
   38.91 + * the terms of the GNU General Public License as published by the Free
   38.92 + * Software Foundation, either version 3 of the License, or (at your option)
   38.93 + * any later version.
   38.94 + * 
   38.95 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   38.96 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   38.97 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   38.98 + *
   38.99 + * You should have received a copy of the GNU General Public License along with
  38.100 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  38.101 + */
  38.102 +#ifndef _include_jitcraft_string_h_
  38.103 +#define _include_jitcraft_string_h_
  38.104 +
  38.105 +#include "Heap.h"
  38.106 +
  38.107 +namespace ke {
  38.108 +
  38.109 +// A fixed-length string containing UTF-8 characters.
  38.110 +class String : public Object
  38.111 +{
  38.112 +    uint32 length_;
  38.113 +    
  38.114 +  public:
  38.115 +    static String *New(Zone *zone, const char *from, Heap::Tenure tenure = Heap::Tenure_Default);
  38.116 +    static String *New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure = Heap::Tenure_Default);
  38.117 +
  38.118 +    unsigned length() {
  38.119 +        return length_;
  38.120 +    }
  38.121 +    char *chars() {
  38.122 +        return reinterpret_cast<char *>(this + 1);
  38.123 +    }
  38.124 +    char *chars(Zone *zone) {
  38.125 +        return chars();
  38.126 +    }
  38.127 +    size_t objSize() {
  38.128 +        return SizeFor(length());
  38.129 +    }
  38.130 +
  38.131 +    static size_t SizeFor(unsigned length) {
  38.132 +        return sizeof(String) + sizeof(char) * (length + 1);
  38.133 +    }
  38.134 +
  38.135 +    static inline String *cast(Object *obj) {
  38.136 +        assert(!obj || obj->is(MapKind_String));
  38.137 +        return reinterpret_cast<String *>(obj);
  38.138 +    }
  38.139 +};
  38.140 +
  38.141 +class CharsAndLength
  38.142 +{
  38.143 +    const char *str_;
  38.144 +    size_t length_;
  38.145 +
  38.146 +  public:
  38.147 +    CharsAndLength(const char *str, size_t length)
  38.148 +        : str_(str),
  38.149 +        length_(length)
  38.150 +    {
  38.151 +    }
  38.152 +
  38.153 +    const char *str() const {
  38.154 +        return str_;
  38.155 +    }
  38.156 +    size_t length() const {
  38.157 +        return length_;
  38.158 +    }
  38.159 +};
  38.160 +
  38.161 +}
  38.162 +
  38.163 +#endif // _include_jitcraft_string_h_
    39.1 --- a/src/Structures.cpp	Mon Jun 10 00:46:29 2013 +0100
    39.2 +++ b/src/Structures.cpp	Mon Jun 10 01:04:43 2013 +0100
    39.3 @@ -1,205 +1,205 @@
    39.4 -/* vim: set ts=4 sw=4 tw=99 et:
    39.5 - *
    39.6 - * Copyright (C) 2012 David Anderson
    39.7 - *
    39.8 - * This file is part of SourcePawn.
    39.9 - *
   39.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   39.11 - * the terms of the GNU General Public License as published by the Free
   39.12 - * Software Foundation, either version 3 of the License, or (at your option)
   39.13 - * any later version.
   39.14 - * 
   39.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   39.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   39.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   39.18 - *
   39.19 - * You should have received a copy of the GNU General Public License along with
   39.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   39.21 - */
   39.22 -#include <string.h>
   39.23 -#include "Structures.h"
   39.24 -#include "Zone.h"
   39.25 -#include "Types.h"
   39.26 -#include "Array.h"
   39.27 -#include "Spaces-inl.h"
   39.28 -#include "Heap-inl.h"
   39.29 -
   39.30 -using namespace ke;
   39.31 -
   39.32 -StructureBufferBuilder::StructureBufferBuilder()
   39.33 -  : size_(0)
   39.34 -{
   39.35 -}
   39.36 -
   39.37 -bool
   39.38 -StructureBufferBuilder::add(Handle<Type> type, unsigned *offset)
   39.39 -{
   39.40 -    *offset = size_;
   39.41 -
   39.42 -    if (!type->isTraceable()) {
   39.43 -        // For now, assume the alignment of all primitive storage is 4 bytes,
   39.44 -        // and that all need <= 4 bytes of storage.
   39.45 -        assert(type->isInt32() ||
   39.46 -               type->isFloat() ||
   39.47 -               type->isBool() ||
   39.48 -               type->isChar() ||
   39.49 -               type->isEnum());
   39.50 -        size_ += 4;
   39.51 -        return true;
   39.52 -    }
   39.53 -
   39.54 -    if (!offsets_.append(size_))
   39.55 -        return false;
   39.56 -
   39.57 -    size_ += sizeof(Object *);
   39.58 -    return true;
   39.59 -}
   39.60 -
   39.61 -Descriptor *
   39.62 -Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility)
   39.63 -{
   39.64 -    Local<Descriptor> desc(zone,
   39.65 -        Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old)));
   39.66 -    if (!desc)
   39.67 -        return NULL;
   39.68 -
   39.69 -    desc->name_ = name;
   39.70 -    desc->type_ = type;
   39.71 -    desc->offset_ = unsigned(-1);
   39.72 -    desc->visibility_ = visibility;
   39.73 -    return desc;
   39.74 -}
   39.75 -
   39.76 -StructMap *
   39.77 -StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
   39.78 -{
   39.79 -    Vector<unsigned> composedIndexes;
   39.80 -    for (size_t i = 0; i < type->fields()->length(); i++) {
   39.81 -        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
   39.82 -        if (desc->type()->isArray() || desc->type()->isStruct()) {
   39.83 -            if (!composedIndexes.append(i))
   39.84 -                return NULL;
   39.85 -        }
   39.86 -    }
   39.87 -
   39.88 -    Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
   39.89 -    if (!composed)
   39.90 -        return NULL;
   39.91 -
   39.92 -    for (size_t i = 0; i < composedIndexes.length(); i++) {
   39.93 -        Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
   39.94 -        composed->set(zone, i, desc);
   39.95 -    }
   39.96 -
   39.97 -    size_t bytesNeeded = sizeof(StructMap) +
   39.98 -                         (builder.traceableOffsetCount() * sizeof(unsigned));
   39.99 -
  39.100 -    Local<StructMap> map(zone);
  39.101 -    map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct));
  39.102 -    if (!map)
  39.103 -        return NULL;
  39.104 -
  39.105 -    map->structureSize_ = builder.structureSize();
  39.106 -    map->traceOffsetCount_ = builder.traceableOffsetCount();
  39.107 -    map->type_ = type;
  39.108 -    map->composed_ = composed;
  39.109 -    memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
  39.110 -           sizeof(unsigned) * builder.traceableOffsetCount());
  39.111 -
  39.112 -    return map;
  39.113 -}
  39.114 -
  39.115 -Struct *
  39.116 -Struct::New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure)
  39.117 -{
  39.118 -    size_t bytesNeeded = SizeFor(map);
  39.119 -
  39.120 -    Local<Struct> obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure)));
  39.121 -    if (!obj)
  39.122 -        return NULL;
  39.123 -
  39.124 -    memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct)));
  39.125 -
  39.126 -    // Initialize any sub-structures. Right now, this is performed as part of
  39.127 -    // struct allocation, rather than inlined in bytecode, for simplicity.
  39.128 -    if (map->composed()) {
  39.129 -        Local<Descriptor> desc(zone);
  39.130 -        Local<Object> child(zone);
  39.131 -        Local<StructMap> childStructMap(zone);
  39.132 -        Local<ArrayMap> childArrayMap(zone);
  39.133 -
  39.134 -        for (unsigned i = 0; i < map->composed()->length(); i++) {
  39.135 -            desc = Descriptor::cast(map->composed()->at(i));
  39.136 -
  39.137 -            if (desc->type()->isStruct()) {
  39.138 -                childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
  39.139 -                child = Struct::New(zone, childStructMap, tenure);
  39.140 -            } else if (desc->type()->isArray()) {
  39.141 -                // :TODO: don't create empty arrays for ref slots here.
  39.142 -                // Instead, make a separate Initialize function, so we
  39.143 -                // can avoid double-creating arrays for module globals.
  39.144 -                //  (const char:x[] = "x")
  39.145 -                ArrayType *type = ArrayType::cast(desc->type());
  39.146 -                childArrayMap = ArrayMap::cast(type->newMap());
  39.147 -                if (type->isFixedLength())
  39.148 -                    child = Array::NewFixed(zone, childArrayMap, tenure);
  39.149 -                else
  39.150 -                    child = Array::NewEmpty(zone, childArrayMap, tenure);
  39.151 -            }
  39.152 -            if (!child)
  39.153 -                return NULL;
  39.154 -
  39.155 -            obj->set(zone, desc, child);
  39.156 -        }
  39.157 -    }
  39.158 -
  39.159 -    return obj;
  39.160 -}
  39.161 -
  39.162 -bool
  39.163 -Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
  39.164 -{
  39.165 -    assert(left->map()->type() == right->map()->type());
  39.166 -
  39.167 -    Local<StructType> type(zone, StructType::cast(left->map()->type()));
  39.168 -    Local<Struct> leftStruct(zone);
  39.169 -    Local<Struct> rightStruct(zone);
  39.170 -    Local<Array> leftArray(zone);
  39.171 -    Local<Array> rightArray(zone);
  39.172 -    for (unsigned i = 0; i < type->fields()->length(); i++) {
  39.173 -        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
  39.174 -
  39.175 -        // If the field is a struct, we need to deep-copy.
  39.176 -        if (desc->type()->isStruct()) {
  39.177 -            leftStruct = Struct::cast(left->get<Object *>(desc));
  39.178 -            rightStruct = Struct::cast(right->get<Object *>(desc));
  39.179 -            if (!Struct::Copy(zone, leftStruct, rightStruct))
  39.180 -                return false;
  39.181 -        } else if (desc->type()->isArray()) {
  39.182 -            leftArray = Array::cast(left->get<Object *>(desc));
  39.183 -            rightArray = Array::cast(right->get<Object *>(desc));
  39.184 -            if (!Array::ShallowCopy(zone, leftArray, rightArray))
  39.185 -                return false;
  39.186 -        } else if (desc->type()->isTraceable()) {
  39.187 -            Object *obj = right->get<Object *>(desc);
  39.188 -            left->set(zone, desc, obj);
  39.189 -        } else {
  39.190 -            switch (desc->type()->pod()) {
  39.191 -              case PrimitiveType_Int32:
  39.192 -              case PrimitiveType_Char:
  39.193 -              case PrimitiveType_Bool:
  39.194 -                left->set(desc, right->get<int>(desc));
  39.195 -                break;
  39.196 -
  39.197 -              case PrimitiveType_Float:
  39.198 -                left->set(desc, right->get<float>(desc));
  39.199 -                break;
  39.200 -                
  39.201 -              default:
  39.202 -                assert(false);
  39.203 -            }
  39.204 -        }
  39.205 -    }
  39.206 -
  39.207 -    return true;
  39.208 +/* vim: set ts=4 sw=4 tw=99 et:
  39.209 + *
  39.210 + * Copyright (C) 2012 David Anderson
  39.211 + *
  39.212 + * This file is part of SourcePawn.
  39.213 + *
  39.214 + * SourcePawn is free software: you can redistribute it and/or modify it under
  39.215 + * the terms of the GNU General Public License as published by the Free
  39.216 + * Software Foundation, either version 3 of the License, or (at your option)
  39.217 + * any later version.
  39.218 + * 
  39.219 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  39.220 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  39.221 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  39.222 + *
  39.223 + * You should have received a copy of the GNU General Public License along with
  39.224 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  39.225 + */
  39.226 +#include <string.h>
  39.227 +#include "Structures.h"
  39.228 +#include "Zone.h"
  39.229 +#include "Types.h"
  39.230 +#include "Array.h"
  39.231 +#include "Spaces-inl.h"
  39.232 +#include "Heap-inl.h"
  39.233 +
  39.234 +using namespace ke;
  39.235 +
  39.236 +StructureBufferBuilder::StructureBufferBuilder()
  39.237 +  : size_(0)
  39.238 +{
  39.239 +}
  39.240 +
  39.241 +bool
  39.242 +StructureBufferBuilder::add(Handle<Type> type, unsigned *offset)
  39.243 +{
  39.244 +    *offset = size_;
  39.245 +
  39.246 +    if (!type->isTraceable()) {
  39.247 +        // For now, assume the alignment of all primitive storage is 4 bytes,
  39.248 +        // and that all need <= 4 bytes of storage.
  39.249 +        assert(type->isInt32() ||
  39.250 +               type->isFloat() ||
  39.251 +               type->isBool() ||
  39.252 +               type->isChar() ||
  39.253 +               type->isEnum());
  39.254 +        size_ += 4;
  39.255 +        return true;
  39.256 +    }
  39.257 +
  39.258 +    if (!offsets_.append(size_))
  39.259 +        return false;
  39.260 +
  39.261 +    size_ += sizeof(Object *);
  39.262 +    return true;
  39.263 +}
  39.264 +
  39.265 +Descriptor *
  39.266 +Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility)
  39.267 +{
  39.268 +    Local<Descriptor> desc(zone,
  39.269 +        Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old)));
  39.270 +    if (!desc)
  39.271 +        return NULL;
  39.272 +
  39.273 +    desc->name_ = name;
  39.274 +    desc->type_ = type;
  39.275 +    desc->offset_ = unsigned(-1);
  39.276 +    desc->visibility_ = visibility;
  39.277 +    return desc;
  39.278 +}
  39.279 +
  39.280 +StructMap *
  39.281 +StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
  39.282 +{
  39.283 +    Vector<unsigned> composedIndexes;
  39.284 +    for (size_t i = 0; i < type->fields()->length(); i++) {
  39.285 +        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
  39.286 +        if (desc->type()->isArray() || desc->type()->isStruct()) {
  39.287 +            if (!composedIndexes.append(i))
  39.288 +                return NULL;
  39.289 +        }
  39.290 +    }
  39.291 +
  39.292 +    Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
  39.293 +    if (!composed)
  39.294 +        return NULL;
  39.295 +
  39.296 +    for (size_t i = 0; i < composedIndexes.length(); i++) {
  39.297 +        Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
  39.298 +        composed->set(zone, i, desc);
  39.299 +    }
  39.300 +
  39.301 +    size_t bytesNeeded = sizeof(StructMap) +
  39.302 +                         (builder.traceableOffsetCount() * sizeof(unsigned));
  39.303 +
  39.304 +    Local<StructMap> map(zone);
  39.305 +    map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct));
  39.306 +    if (!map)
  39.307 +        return NULL;
  39.308 +
  39.309 +    map->structureSize_ = builder.structureSize();
  39.310 +    map->traceOffsetCount_ = builder.traceableOffsetCount();
  39.311 +    map->type_ = type;
  39.312 +    map->composed_ = composed;
  39.313 +    memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
  39.314 +           sizeof(unsigned) * builder.traceableOffsetCount());
  39.315 +
  39.316 +    return map;
  39.317 +}
  39.318 +
  39.319 +Struct *
  39.320 +Struct::New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure)
  39.321 +{
  39.322 +    size_t bytesNeeded = SizeFor(map);
  39.323 +
  39.324 +    Local<Struct> obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure)));
  39.325 +    if (!obj)
  39.326 +        return NULL;
  39.327 +
  39.328 +    memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct)));
  39.329 +
  39.330 +    // Initialize any sub-structures. Right now, this is performed as part of
  39.331 +    // struct allocation, rather than inlined in bytecode, for simplicity.
  39.332 +    if (map->composed()) {
  39.333 +        Local<Descriptor> desc(zone);
  39.334 +        Local<Object> child(zone);
  39.335 +        Local<StructMap> childStructMap(zone);
  39.336 +        Local<ArrayMap> childArrayMap(zone);
  39.337 +
  39.338 +        for (unsigned i = 0; i < map->composed()->length(); i++) {
  39.339 +            desc = Descriptor::cast(map->composed()->at(i));
  39.340 +
  39.341 +            if (desc->type()->isStruct()) {
  39.342 +                childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
  39.343 +                child = Struct::New(zone, childStructMap, tenure);
  39.344 +            } else if (desc->type()->isArray()) {
  39.345 +                // :TODO: don't create empty arrays for ref slots here.
  39.346 +                // Instead, make a separate Initialize function, so we
  39.347 +                // can avoid double-creating arrays for module globals.
  39.348 +                //  (const char:x[] = "x")
  39.349 +                ArrayType *type = ArrayType::cast(desc->type());
  39.350 +                childArrayMap = ArrayMap::cast(type->newMap());
  39.351 +                if (type->isFixedLength())
  39.352 +                    child = Array::NewFixed(zone, childArrayMap, tenure);
  39.353 +                else
  39.354 +                    child = Array::NewEmpty(zone, childArrayMap, tenure);
  39.355 +            }
  39.356 +            if (!child)
  39.357 +                return NULL;
  39.358 +
  39.359 +            obj->set(zone, desc, child);
  39.360 +        }
  39.361 +    }
  39.362 +
  39.363 +    return obj;
  39.364 +}
  39.365 +
  39.366 +bool
  39.367 +Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
  39.368 +{
  39.369 +    assert(left->map()->type() == right->map()->type());
  39.370 +
  39.371 +    Local<StructType> type(zone, StructType::cast(left->map()->type()));
  39.372 +    Local<Struct> leftStruct(zone);
  39.373 +    Local<Struct> rightStruct(zone);
  39.374 +    Local<Array> leftArray(zone);
  39.375 +    Local<Array> rightArray(zone);
  39.376 +    for (unsigned i = 0; i < type->fields()->length(); i++) {
  39.377 +        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
  39.378 +
  39.379 +        // If the field is a struct, we need to deep-copy.
  39.380 +        if (desc->type()->isStruct()) {
  39.381 +            leftStruct = Struct::cast(left->get<Object *>(desc));
  39.382 +            rightStruct = Struct::cast(right->get<Object *>(desc));
  39.383 +            if (!Struct::Copy(zone, leftStruct, rightStruct))
  39.384 +                return false;
  39.385 +        } else if (desc->type()->isArray()) {
  39.386 +            leftArray = Array::cast(left->get<Object *>(desc));
  39.387 +            rightArray = Array::cast(right->get<Object *>(desc));
  39.388 +            if (!Array::ShallowCopy(zone, leftArray, rightArray))
  39.389 +                return false;
  39.390 +        } else if (desc->type()->isTraceable()) {
  39.391 +            Object *obj = right->get<Object *>(desc);
  39.392 +            left->set(zone, desc, obj);
  39.393 +        } else {
  39.394 +            switch (desc->type()->pod()) {
  39.395 +              case PrimitiveType_Int32:
  39.396 +              case PrimitiveType_Char:
  39.397 +              case PrimitiveType_Bool:
  39.398 +                left->set(desc, right->get<int>(desc));
  39.399 +                break;
  39.400 +
  39.401 +              case PrimitiveType_Float:
  39.402 +                left->set(desc, right->get<float>(desc));
  39.403 +                break;
  39.404 +                
  39.405 +              default:
  39.406 +                assert(false);
  39.407 +            }
  39.408 +        }
  39.409 +    }
  39.410 +
  39.411 +    return true;
  39.412  }
  39.413 \ No newline at end of file
    40.1 --- a/src/Structures.h	Mon Jun 10 00:46:29 2013 +0100
    40.2 +++ b/src/Structures.h	Mon Jun 10 01:04:43 2013 +0100
    40.3 @@ -1,215 +1,215 @@
    40.4 -/* vim: set ts=4 sw=4 tw=99 et:
    40.5 - *
    40.6 - * Copyright (C) 2012 David Anderson
    40.7 - *
    40.8 - * This file is part of SourcePawn.
    40.9 - *
   40.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   40.11 - * the terms of the GNU General Public License as published by the Free
   40.12 - * Software Foundation, either version 3 of the License, or (at your option)
   40.13 - * any later version.
   40.14 - * 
   40.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   40.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   40.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   40.18 - *
   40.19 - * You should have received a copy of the GNU General Public License along with
   40.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   40.21 - */
   40.22 -#ifndef _include_jc_structure_h_
   40.23 -#define _include_jc_structure_h_
   40.24 -
   40.25 -#include "Objects.h"
   40.26 -#include "Handles.h"
   40.27 -#include "Vector.h"
   40.28 -#include "Heap.h"
   40.29 -
   40.30 -namespace ke {
   40.31 -
   40.32 -class Type;
   40.33 -class String;
   40.34 -class FixedArray;
   40.35 -class StructType;
   40.36 -
   40.37 -// When describing composite structures, the GC must be able to trace interior
   40.38 -// references to Objects. To make this possible, maps that describe composite
   40.39 -// structures must provide a list of offsets into their objects that are
   40.40 -// traceable. StructureBufferBuilder assists with this.
   40.41 -class StructureBufferBuilder
   40.42 -{
   40.43 -  public:
   40.44 -    StructureBufferBuilder();
   40.45 -
   40.46 -    bool add(Handle<Type> type, unsigned *offset);
   40.47 -
   40.48 -    unsigned structureSize() const {
   40.49 -        return size_;
   40.50 -    }
   40.51 -    unsigned traceableOffsetCount() const {
   40.52 -        return offsets_.length();
   40.53 -    }
   40.54 -    const unsigned *offsets() const {
   40.55 -        return offsets_.buffer();
   40.56 -    }
   40.57 -
   40.58 -  private:
   40.59 -    Vector<unsigned> offsets_;
   40.60 -    unsigned size_;
   40.61 -};
   40.62 -
   40.63 -// Represents a property descriptor for a structure field.
   40.64 -class Descriptor : public Object
   40.65 -{
   40.66 -  public:
   40.67 -    enum Visibility {
   40.68 -        Private,
   40.69 -        Protected,
   40.70 -        Public
   40.71 -    };
   40.72 -
   40.73 -  private:
   40.74 -    // The name of the field.
   40.75 -    Barriered<String> name_;
   40.76 -
   40.77 -    // The type of the field.
   40.78 -    Barriered<Type> type_;
   40.79 -
   40.80 -    // The offset into an object at which this field can be accessed.
   40.81 -    unsigned offset_;
   40.82 -
   40.83 -    Visibility visibility_;
   40.84 -
   40.85 -  public:
   40.86 -    static Descriptor *New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility);
   40.87 -
   40.88 -    String *name() {
   40.89 -        return name_;
   40.90 -    }
   40.91 -    Type *type() {
   40.92 -        return type_;
   40.93 -    }
   40.94 -    unsigned offset() {
   40.95 -        assert(offset_ != unsigned(-1));
   40.96 -        return offset_;
   40.97 -    }
   40.98 -    void setOffset(unsigned offset) {
   40.99 -        assert(offset_ == unsigned(-1));
  40.100 -        offset_ = offset;
  40.101 -    }
  40.102 -
  40.103 -    // Begin GC descriptor.
  40.104 -    static inline size_t offsetOfName() {
  40.105 -        return OFFSETOF(Descriptor, name_);
  40.106 -    }
  40.107 -    static inline size_t offsetOfType() {
  40.108 -        return OFFSETOF(Descriptor, type_);
  40.109 -    }
  40.110 -    // End GC descriptor.
  40.111 -    
  40.112 -    static inline Descriptor *cast(Object *obj) {
  40.113 -        assert(!obj || obj->is(MapKind_Descriptor));
  40.114 -        return reinterpret_cast<Descriptor *>(obj);
  40.115 -    }
  40.116 -};
  40.117 -
  40.118 -class StructMap : public Map
  40.119 -{
  40.120 -    unsigned structureSize_;
  40.121 -    unsigned traceOffsetCount_;
  40.122 -    Barriered<StructType> type_;
  40.123 -
  40.124 -    // List of descriptors which must be allocated upon initialization.
  40.125 -    Barriered<FixedArray> composed_;
  40.126 -
  40.127 -  public:
  40.128 -    static StructMap *New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type);
  40.129 -
  40.130 -    unsigned structureSize() {
  40.131 -        return structureSize_;
  40.132 -    }
  40.133 -    unsigned traceOffsetCount() {
  40.134 -        return traceOffsetCount_;
  40.135 -    }
  40.136 -    const unsigned *traceOffsets() {
  40.137 -        return reinterpret_cast<unsigned *>(this + 1);
  40.138 -    }
  40.139 -    size_t objSize() {
  40.140 -        return sizeof(StructMap) + sizeof(unsigned) * traceOffsetCount();
  40.141 -    }
  40.142 -    StructType *type() {
  40.143 -        return type_;
  40.144 -    }
  40.145 -    FixedArray *composed() {
  40.146 -        return composed_;
  40.147 -    }
  40.148 -
  40.149 -    void setType(StructType *type) {
  40.150 -        assert(!type_);
  40.151 -        type_ = type;
  40.152 -    }
  40.153 -
  40.154 -    // Begin GC descriptors.
  40.155 -    static inline size_t offsetOfType() {
  40.156 -        return OFFSETOF(StructMap, type_);
  40.157 -    }
  40.158 -    static inline size_t offsetOfComposed() {
  40.159 -        return OFFSETOF(StructMap, composed_);
  40.160 -    }
  40.161 -    // End GC descriptors.
  40.162 -
  40.163 -    static inline StructMap *cast(Object *obj) {
  40.164 -        assert(!obj || obj->is(MapKind_MetaStruct));
  40.165 -        return reinterpret_cast<StructMap *>(obj);
  40.166 -    }
  40.167 -};
  40.168 -
  40.169 -class Struct : public Object
  40.170 -{
  40.171 -  public:
  40.172 -    static Struct *New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
  40.173 -
  40.174 -    static bool Copy(Zone *zone, Handle<Struct> dest, Handle<Struct> src);
  40.175 -
  40.176 -    StructMap *map() {
  40.177 -        return StructMap::cast(Object::map());
  40.178 -    }
  40.179 -
  40.180 -    void *ref(Descriptor *desc) {
  40.181 -        return reinterpret_cast<Address>(this) + offsetOfSlotOffset(desc->offset());
  40.182 -    }
  40.183 -
  40.184 -    static inline size_t SizeFor(StructMap *map) {
  40.185 -        return Max(sizeof(Struct) + map->structureSize(), kMinObjectSize);
  40.186 -    }
  40.187 -
  40.188 -    template <typename T> T get(Descriptor *desc) {
  40.189 -        return *reinterpret_cast<T *>(ref(desc));
  40.190 -    }
  40.191 -
  40.192 -    // This must NOT be used with any Object * type!
  40.193 -    // :TODO: prevent with type system
  40.194 -    template <typename T> void set(Descriptor *desc, const T &t) {
  40.195 -        *reinterpret_cast<T *>(ref(desc)) = t;
  40.196 -    }
  40.197 -
  40.198 -    void set(Zone *zone, Descriptor *desc, Object *obj) {
  40.199 -        // :TODO: write barrier
  40.200 -        *reinterpret_cast<Object **>(
  40.201 -            reinterpret_cast<Address>(this) +
  40.202 -            offsetOfSlotOffset(desc->offset())) = obj;
  40.203 -    }
  40.204 -
  40.205 -    static inline size_t offsetOfSlotOffset(unsigned offset) {
  40.206 -        return sizeof(Struct) + offset;
  40.207 -    }
  40.208 -
  40.209 -    static inline Struct *cast(Object *obj) {
  40.210 -        assert(!obj || obj->is(MapKind_Struct));
  40.211 -        return reinterpret_cast<Struct *>(obj);
  40.212 -    }
  40.213 -};
  40.214 -
  40.215 -}
  40.216 -
  40.217 -#endif // _include_jc_structure_h_
  40.218 -
  40.219 +/* vim: set ts=4 sw=4 tw=99 et:
  40.220 + *
  40.221 + * Copyright (C) 2012 David Anderson
  40.222 + *
  40.223 + * This file is part of SourcePawn.
  40.224 + *
  40.225 + * SourcePawn is free software: you can redistribute it and/or modify it under
  40.226 + * the terms of the GNU General Public License as published by the Free
  40.227 + * Software Foundation, either version 3 of the License, or (at your option)
  40.228 + * any later version.
  40.229 + * 
  40.230 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  40.231 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  40.232 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  40.233 + *
  40.234 + * You should have received a copy of the GNU General Public License along with
  40.235 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  40.236 + */
  40.237 +#ifndef _include_jc_structure_h_
  40.238 +#define _include_jc_structure_h_
  40.239 +
  40.240 +#include "Objects.h"
  40.241 +#include "Handles.h"
  40.242 +#include "Vector.h"
  40.243 +#include "Heap.h"
  40.244 +
  40.245 +namespace ke {
  40.246 +
  40.247 +class Type;
  40.248 +class String;
  40.249 +class FixedArray;
  40.250 +class StructType;
  40.251 +
  40.252 +// When describing composite structures, the GC must be able to trace interior
  40.253 +// references to Objects. To make this possible, maps that describe composite
  40.254 +// structures must provide a list of offsets into their objects that are
  40.255 +// traceable. StructureBufferBuilder assists with this.
  40.256 +class StructureBufferBuilder
  40.257 +{
  40.258 +  public:
  40.259 +    StructureBufferBuilder();
  40.260 +
  40.261 +    bool add(Handle<Type> type, unsigned *offset);
  40.262 +
  40.263 +    unsigned structureSize() const {
  40.264 +        return size_;
  40.265 +    }
  40.266 +    unsigned traceableOffsetCount() const {
  40.267 +        return offsets_.length();
  40.268 +    }
  40.269 +    const unsigned *offsets() const {
  40.270 +        return offsets_.buffer();
  40.271 +    }
  40.272 +
  40.273 +  private:
  40.274 +    Vector<unsigned> offsets_;
  40.275 +    unsigned size_;
  40.276 +};
  40.277 +
  40.278 +// Represents a property descriptor for a structure field.
  40.279 +class Descriptor : public Object
  40.280 +{
  40.281 +  public:
  40.282 +    enum Visibility {
  40.283 +        Private,
  40.284 +        Protected,
  40.285 +        Public
  40.286 +    };
  40.287 +
  40.288 +  private:
  40.289 +    // The name of the field.
  40.290 +    Barriered<String> name_;
  40.291 +
  40.292 +    // The type of the field.
  40.293 +    Barriered<Type> type_;
  40.294 +
  40.295 +    // The offset into an object at which this field can be accessed.
  40.296 +    unsigned offset_;
  40.297 +
  40.298 +    Visibility visibility_;
  40.299 +
  40.300 +  public:
  40.301 +    static Descriptor *New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility);
  40.302 +
  40.303 +    String *name() {
  40.304 +        return name_;
  40.305 +    }
  40.306 +    Type *type() {
  40.307 +        return type_;
  40.308 +    }
  40.309 +    unsigned offset() {
  40.310 +        assert(offset_ != unsigned(-1));
  40.311 +        return offset_;
  40.312 +    }
  40.313 +    void setOffset(unsigned offset) {
  40.314 +        assert(offset_ == unsigned(-1));
  40.315 +        offset_ = offset;
  40.316 +    }
  40.317 +
  40.318 +    // Begin GC descriptor.
  40.319 +    static inline size_t offsetOfName() {
  40.320 +        return OFFSETOF(Descriptor, name_);
  40.321 +    }
  40.322 +    static inline size_t offsetOfType() {
  40.323 +        return OFFSETOF(Descriptor, type_);
  40.324 +    }
  40.325 +    // End GC descriptor.
  40.326 +    
  40.327 +    static inline Descriptor *cast(Object *obj) {
  40.328 +        assert(!obj || obj->is(MapKind_Descriptor));
  40.329 +        return reinterpret_cast<Descriptor *>(obj);
  40.330 +    }
  40.331 +};
  40.332 +
  40.333 +class StructMap : public Map
  40.334 +{
  40.335 +    unsigned structureSize_;
  40.336 +    unsigned traceOffsetCount_;
  40.337 +    Barriered<StructType> type_;
  40.338 +
  40.339 +    // List of descriptors which must be allocated upon initialization.
  40.340 +    Barriered<FixedArray> composed_;
  40.341 +
  40.342 +  public:
  40.343 +    static StructMap *New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type);
  40.344 +
  40.345 +    unsigned structureSize() {
  40.346 +        return structureSize_;
  40.347 +    }
  40.348 +    unsigned traceOffsetCount() {
  40.349 +        return traceOffsetCount_;
  40.350 +    }
  40.351 +    const unsigned *traceOffsets() {
  40.352 +        return reinterpret_cast<unsigned *>(this + 1);
  40.353 +    }
  40.354 +    size_t objSize() {
  40.355 +        return sizeof(StructMap) + sizeof(unsigned) * traceOffsetCount();
  40.356 +    }
  40.357 +    StructType *type() {
  40.358 +        return type_;
  40.359 +    }
  40.360 +    FixedArray *composed() {
  40.361 +        return composed_;
  40.362 +    }
  40.363 +
  40.364 +    void setType(StructType *type) {
  40.365 +        assert(!type_);
  40.366 +        type_ = type;
  40.367 +    }
  40.368 +
  40.369 +    // Begin GC descriptors.
  40.370 +    static inline size_t offsetOfType() {
  40.371 +        return OFFSETOF(StructMap, type_);
  40.372 +    }
  40.373 +    static inline size_t offsetOfComposed() {
  40.374 +        return OFFSETOF(StructMap, composed_);
  40.375 +    }
  40.376 +    // End GC descriptors.
  40.377 +
  40.378 +    static inline StructMap *cast(Object *obj) {
  40.379 +        assert(!obj || obj->is(MapKind_MetaStruct));
  40.380 +        return reinterpret_cast<StructMap *>(obj);
  40.381 +    }
  40.382 +};
  40.383 +
  40.384 +class Struct : public Object
  40.385 +{
  40.386 +  public:
  40.387 +    static Struct *New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
  40.388 +
  40.389 +    static bool Copy(Zone *zone, Handle<Struct> dest, Handle<Struct> src);
  40.390 +
  40.391 +    StructMap *map() {
  40.392 +        return StructMap::cast(Object::map());
  40.393 +    }
  40.394 +
  40.395 +    void *ref(Descriptor *desc) {
  40.396 +        return reinterpret_cast<Address>(this) + offsetOfSlotOffset(desc->offset());
  40.397 +    }
  40.398 +
  40.399 +    static inline size_t SizeFor(StructMap *map) {
  40.400 +        return Max(sizeof(Struct) + map->structureSize(), kMinObjectSize);
  40.401 +    }
  40.402 +
  40.403 +    template <typename T> T get(Descriptor *desc) {
  40.404 +        return *reinterpret_cast<T *>(ref(desc));
  40.405 +    }
  40.406 +
  40.407 +    // This must NOT be used with any Object * type!
  40.408 +    // :TODO: prevent with type system
  40.409 +    template <typename T> void set(Descriptor *desc, const T &t) {
  40.410 +        *reinterpret_cast<T *>(ref(desc)) = t;
  40.411 +    }
  40.412 +
  40.413 +    void set(Zone *zone, Descriptor *desc, Object *obj) {
  40.414 +        // :TODO: write barrier
  40.415 +        *reinterpret_cast<Object **>(
  40.416 +            reinterpret_cast<Address>(this) +
  40.417 +            offsetOfSlotOffset(desc->offset())) = obj;
  40.418 +    }
  40.419 +
  40.420 +    static inline size_t offsetOfSlotOffset(unsigned offset) {
  40.421 +        return sizeof(Struct) + offset;
  40.422 +    }
  40.423 +
  40.424 +    static inline Struct *cast(Object *obj) {
  40.425 +        assert(!obj || obj->is(MapKind_Struct));
  40.426 +        return reinterpret_cast<Struct *>(obj);
  40.427 +    }
  40.428 +};
  40.429 +
  40.430 +}
  40.431 +
  40.432 +#endif // _include_jc_structure_h_
  40.433 +
    41.1 --- a/src/TypeManager.cpp	Mon Jun 10 00:46:29 2013 +0100
    41.2 +++ b/src/TypeManager.cpp	Mon Jun 10 01:04:43 2013 +0100
    41.3 @@ -1,167 +1,167 @@
    41.4 -/* vim: set ts=4 sw=4 tw=99 et:
    41.5 - *
    41.6 - * Copyright (C) 2012 David Anderson
    41.7 - *
    41.8 - * This file is part of SourcePawn.
    41.9 - *
   41.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   41.11 - * the terms of the GNU General Public License as published by the Free
   41.12 - * Software Foundation, either version 3 of the License, or (at your option)
   41.13 - * any later version.
   41.14 - * 
   41.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   41.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   41.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   41.18 - *
   41.19 - * You should have received a copy of the GNU General Public License along with
   41.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   41.21 - */
   41.22 -#include <string.h>
   41.23 -#include "Types.h"
   41.24 -#include "TypeManager.h"
   41.25 -#include "Zone.h"
   41.26 -#include "Strings.h"
   41.27 -#include "Spaces-inl.h"
   41.28 -#include "Heap-inl.h"
   41.29 -
   41.30 -using namespace ke;
   41.31 -
   41.32 -
   41.33 -TypeManager::TypeManager(Zone *zone)
   41.34 -  : zone_(zone),
   41.35 -    qualTable_(ZoneAllocatorPolicy())
   41.36 -{
   41.37 -}
   41.38 -
   41.39 -bool
   41.40 -TypeManager::initialize()
   41.41 -{
   41.42 -    voidType_ = Type::NewVoid(zone_);
   41.43 -    if (!voidType_)
   41.44 -        return false;
   41.45 -
   41.46 -    uncheckedType_ = Type::NewUnchecked(zone_);
   41.47 -    if (!uncheckedType_)
   41.48 -        return false;
   41.49 -
   41.50 -    stringType_ = Type::NewString(zone_);
   41.51 -    if (!stringType_)
   41.52 -        return false;
   41.53 -
   41.54 -    importableType_ = Type::NewImportable(zone_);
   41.55 -    if (!importableType_)
   41.56 -        return false;
   41.57 -
   41.58 -    typeType_ = Type::NewType(zone_);
   41.59 -    if (!typeType_)
   41.60 -        return false;
   41.61 -
   41.62 -    if ((primitiveTypes_[PrimitiveType_Int32] = Type::NewPrimitive(zone_, PrimitiveType_Int32)) == NULL)
   41.63 -        return false;
   41.64 -    if ((primitiveTypes_[PrimitiveType_Float] = Type::NewPrimitive(zone_, PrimitiveType_Float)) == NULL)
   41.65 -        return false;
   41.66 -    if ((primitiveTypes_[PrimitiveType_Native] = Type::NewPrimitive(zone_, PrimitiveType_Native)) == NULL)
   41.67 -        return false;
   41.68 -    if ((primitiveTypes_[PrimitiveType_Char] = Type::NewPrimitive(zone_, PrimitiveType_Char)) == NULL)
   41.69 -        return false;
   41.70 -    if ((primitiveTypes_[PrimitiveType_Bool] = Type::NewPrimitive(zone_, PrimitiveType_Bool)) == NULL)
   41.71 -        return false;
   41.72 -
   41.73 -    Local<Type> type(zone_);
   41.74 -    for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
   41.75 -        type = primitiveTypes_[i];
   41.76 -        if ((referenceTypes_[i] = ReferenceType::New(zone_, type)) == NULL)
   41.77 -            return false;
   41.78 -    }
   41.79 -
   41.80 -    if (!qualTable_.init(32))
   41.81 -        return false;
   41.82 -
   41.83 -    return true;
   41.84 -}
   41.85 -
   41.86 -ArrayType *
   41.87 -TypeManager::newArray(Handle<Type> contained, int elements)
   41.88 -{
   41.89 -    // :TODO: cache this.
   41.90 -    return ArrayType::New(zone_, contained, elements);
   41.91 -}
   41.92 -
   41.93 -ArrayType *
   41.94 -TypeManager::newExternalArray(Handle<Type> contained)
   41.95 -{
   41.96 -    return ArrayType::NewExternal(zone_, contained);
   41.97 -}
   41.98 -
   41.99 -ReferenceType *
  41.100 -TypeManager::getReference(Handle<Type> type, bool isConst)
  41.101 -{
  41.102 -    if (!isConst && type->isPrimitive())
  41.103 -        return referenceTypes_[type->primitive()];
  41.104 -
  41.105 -    // :TODO: cache this.
  41.106 -    return ReferenceType::New(zone_, type);
  41.107 -}
  41.108 -
  41.109 -EnumType *
  41.110 -TypeManager::newEnum(Handle<String> name)
  41.111 -{
  41.112 -    return EnumType::New(zone_, name);
  41.113 -}
  41.114 -
  41.115 -Type *
  41.116 -TypeManager::qualify(Handle<Type> argType, TypeQualifiers quals)
  41.117 -{
  41.118 -    Local<Type> type(zone_, argType->unqualified());
  41.119 -
  41.120 -    if (!quals)
  41.121 -        return type;
  41.122 -
  41.123 -    LookupKey key(type, quals);
  41.124 -
  41.125 -    // We can't use findForAdd because a GC could rehash the table.
  41.126 -    TypeHashTable::Result r = qualTable_.find(key);
  41.127 -    if (r.found())
  41.128 -        return *r;
  41.129 -
  41.130 -    Type *quald = Type::NewQualified(zone_, quals, type);
  41.131 -    if (!quald)
  41.132 -        return NULL;
  41.133 -
  41.134 -    // :TODO: assert-no-gc
  41.135 -    TypeHashTable::Insert i = qualTable_.findForAdd(key);
  41.136 -    assert(!i.found());
  41.137 -
  41.138 -    if (!qualTable_.add(i, quald))
  41.139 -        return NULL;
  41.140 -
  41.141 -    return quald;
  41.142 -}
  41.143 -
  41.144 -void
  41.145 -TypeManager::accept(VirtualObjectVisitor *visitor)
  41.146 -{
  41.147 -    visitor->visit(voidType_.address());
  41.148 -    visitor->visit(uncheckedType_.address());
  41.149 -    visitor->visit(stringType_.address());
  41.150 -    visitor->visit(importableType_.address());
  41.151 -    visitor->visit(typeType_.address());
  41.152 -    for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
  41.153 -        visitor->visit(primitiveTypes_[i].address());
  41.154 -        visitor->visit(referenceTypes_[i].address());
  41.155 -    }
  41.156 -}
  41.157 -
  41.158 -void
  41.159 -TypeManager::sweep()
  41.160 -{
  41.161 -    for (TypeHashTable::iterator i(&qualTable_); !i.empty(); i.next()) {
  41.162 -        Type *obj = *i;
  41.163 -        MarkBit bits = HeapChunk::GetMarkBit(obj);
  41.164 -        if (HeapChunk::IsWhite(bits))
  41.165 -            i.erase();
  41.166 -        else
  41.167 -            assert(HeapChunk::IsBlack(bits));
  41.168 -    }
  41.169 -    qualTable_.checkDensity();
  41.170 -}
  41.171 +/* vim: set ts=4 sw=4 tw=99 et:
  41.172 + *
  41.173 + * Copyright (C) 2012 David Anderson
  41.174 + *
  41.175 + * This file is part of SourcePawn.
  41.176 + *
  41.177 + * SourcePawn is free software: you can redistribute it and/or modify it under
  41.178 + * the terms of the GNU General Public License as published by the Free
  41.179 + * Software Foundation, either version 3 of the License, or (at your option)
  41.180 + * any later version.
  41.181 + * 
  41.182 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  41.183 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  41.184 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  41.185 + *
  41.186 + * You should have received a copy of the GNU General Public License along with
  41.187 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  41.188 + */
  41.189 +#include <string.h>
  41.190 +#include "Types.h"
  41.191 +#include "TypeManager.h"
  41.192 +#include "Zone.h"
  41.193 +#include "Strings.h"
  41.194 +#include "Spaces-inl.h"
  41.195 +#include "Heap-inl.h"
  41.196 +
  41.197 +using namespace ke;
  41.198 +
  41.199 +
  41.200 +TypeManager::TypeManager(Zone *zone)
  41.201 +  : zone_(zone),
  41.202 +    qualTable_(ZoneAllocatorPolicy())
  41.203 +{
  41.204 +}
  41.205 +
  41.206 +bool
  41.207 +TypeManager::initialize()
  41.208 +{
  41.209 +    voidType_ = Type::NewVoid(zone_);
  41.210 +    if (!voidType_)
  41.211 +        return false;
  41.212 +
  41.213 +    uncheckedType_ = Type::NewUnchecked(zone_);
  41.214 +    if (!uncheckedType_)
  41.215 +        return false;
  41.216 +
  41.217 +    stringType_ = Type::NewString(zone_);
  41.218 +    if (!stringType_)
  41.219 +        return false;
  41.220 +
  41.221 +    importableType_ = Type::NewImportable(zone_);
  41.222 +    if (!importableType_)
  41.223 +        return false;
  41.224 +
  41.225 +    typeType_ = Type::NewType(zone_);
  41.226 +    if (!typeType_)
  41.227 +        return false;
  41.228 +
  41.229 +    if ((primitiveTypes_[PrimitiveType_Int32] = Type::NewPrimitive(zone_, PrimitiveType_Int32)) == NULL)
  41.230 +        return false;
  41.231 +    if ((primitiveTypes_[PrimitiveType_Float] = Type::NewPrimitive(zone_, PrimitiveType_Float)) == NULL)
  41.232 +        return false;
  41.233 +    if ((primitiveTypes_[PrimitiveType_Native] = Type::NewPrimitive(zone_, PrimitiveType_Native)) == NULL)
  41.234 +        return false;
  41.235 +    if ((primitiveTypes_[PrimitiveType_Char] = Type::NewPrimitive(zone_, PrimitiveType_Char)) == NULL)
  41.236 +        return false;
  41.237 +    if ((primitiveTypes_[PrimitiveType_Bool] = Type::NewPrimitive(zone_, PrimitiveType_Bool)) == NULL)
  41.238 +        return false;
  41.239 +
  41.240 +    Local<Type> type(zone_);
  41.241 +    for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
  41.242 +        type = primitiveTypes_[i];
  41.243 +        if ((referenceTypes_[i] = ReferenceType::New(zone_, type)) == NULL)
  41.244 +            return false;
  41.245 +    }
  41.246 +
  41.247 +    if (!qualTable_.init(32))
  41.248 +        return false;
  41.249 +
  41.250 +    return true;
  41.251 +}
  41.252 +
  41.253 +ArrayType *
  41.254 +TypeManager::newArray(Handle<Type> contained, int elements)
  41.255 +{
  41.256 +    // :TODO: cache this.
  41.257 +    return ArrayType::New(zone_, contained, elements);
  41.258 +}
  41.259 +
  41.260 +ArrayType *
  41.261 +TypeManager::newExternalArray(Handle<Type> contained)
  41.262 +{
  41.263 +    return ArrayType::NewExternal(zone_, contained);
  41.264 +}
  41.265 +
  41.266 +ReferenceType *
  41.267 +TypeManager::getReference(Handle<Type> type, bool isConst)
  41.268 +{
  41.269 +    if (!isConst && type->isPrimitive())
  41.270 +        return referenceTypes_[type->primitive()];
  41.271 +
  41.272 +    // :TODO: cache this.
  41.273 +    return ReferenceType::New(zone_, type);
  41.274 +}
  41.275 +
  41.276 +EnumType *
  41.277 +TypeManager::newEnum(Handle<String> name)
  41.278 +{
  41.279 +    return EnumType::New(zone_, name);
  41.280 +}
  41.281 +
  41.282 +Type *
  41.283 +TypeManager::qualify(Handle<Type> argType, TypeQualifiers quals)
  41.284 +{
  41.285 +    Local<Type> type(zone_, argType->unqualified());
  41.286 +
  41.287 +    if (!quals)
  41.288 +        return type;
  41.289 +
  41.290 +    LookupKey key(type, quals);
  41.291 +
  41.292 +    // We can't use findForAdd because a GC could rehash the table.
  41.293 +    TypeHashTable::Result r = qualTable_.find(key);
  41.294 +    if (r.found())
  41.295 +        return *r;
  41.296 +
  41.297 +    Type *quald = Type::NewQualified(zone_, quals, type);
  41.298 +    if (!quald)
  41.299 +        return NULL;
  41.300 +
  41.301 +    // :TODO: assert-no-gc
  41.302 +    TypeHashTable::Insert i = qualTable_.findForAdd(key);
  41.303 +    assert(!i.found());
  41.304 +
  41.305 +    if (!qualTable_.add(i, quald))
  41.306 +        return NULL;
  41.307 +
  41.308 +    return quald;
  41.309 +}
  41.310 +
  41.311 +void
  41.312 +TypeManager::accept(VirtualObjectVisitor *visitor)
  41.313 +{
  41.314 +    visitor->visit(voidType_.address());
  41.315 +    visitor->visit(uncheckedType_.address());
  41.316 +    visitor->visit(stringType_.address());
  41.317 +    visitor->visit(importableType_.address());
  41.318 +    visitor->visit(typeType_.address());
  41.319 +    for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
  41.320 +        visitor->visit(primitiveTypes_[i].address());
  41.321 +        visitor->visit(referenceTypes_[i].address());
  41.322 +    }
  41.323 +}
  41.324 +
  41.325 +void
  41.326 +TypeManager::sweep()
  41.327 +{
  41.328 +    for (TypeHashTable::iterator i(&qualTable_); !i.empty(); i.next()) {
  41.329 +        Type *obj = *i;
  41.330 +        MarkBit bits = HeapChunk::GetMarkBit(obj);
  41.331 +        if (HeapChunk::IsWhite(bits))
  41.332 +            i.erase();
  41.333 +        else
  41.334 +            assert(HeapChunk::IsBlack(bits));
  41.335 +    }
  41.336 +    qualTable_.checkDensity();
  41.337 +}
    42.1 --- a/src/TypeManager.h	Mon Jun 10 00:46:29 2013 +0100
    42.2 +++ b/src/TypeManager.h	Mon Jun 10 01:04:43 2013 +0100
    42.3 @@ -1,115 +1,115 @@
    42.4 -/* vim: set ts=4 sw=4 tw=99 et:
    42.5 - *
    42.6 - * Copyright (C) 2012 David Anderson
    42.7 - *
    42.8 - * This file is part of SourcePawn.
    42.9 - *
   42.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   42.11 - * the terms of the GNU General Public License as published by the Free
   42.12 - * Software Foundation, either version 3 of the License, or (at your option)
   42.13 - * any later version.
   42.14 - * 
   42.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   42.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   42.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   42.18 - *
   42.19 - * You should have received a copy of the GNU General Public License along with
   42.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   42.21 - */
   42.22 -#ifndef _include_jitcraft_type_manager_h_
   42.23 -#define _include_jitcraft_type_manager_h_
   42.24 -
   42.25 -#include "Barriers.h"
   42.26 -#include "Types.h"
   42.27 -#include "HashTable.h"
   42.28 -#include "AllocatorPolicies.h"
   42.29 -#include "VirtualObjectVisitor.h"
   42.30 -
   42.31 -namespace ke {
   42.32 -
   42.33 -class String;
   42.34 -
   42.35 -class TypeManager
   42.36 -{
   42.37 -    struct LookupKey
   42.38 -    {
   42.39 -        Handle<Type> type;
   42.40 -        TypeQualifiers quals;
   42.41 -
   42.42 -        LookupKey(Handle<Type> type, TypeQualifiers quals)
   42.43 -          : type(type),
   42.44 -            quals(quals)
   42.45 -        {
   42.46 -        }
   42.47 -    };
   42.48 -
   42.49 -    struct Policy
   42.50 -    {
   42.51 -        typedef Type * Payload;
   42.52 -
   42.53 -        static uint32 hash(const LookupKey &key) {
   42.54 -            // We'll need to rehash with moving GC.
   42.55 -            return HashPointer(key.type);
   42.56 -        }
   42.57 -        
   42.58 -        static bool matches(const LookupKey &key, Type *type) {
   42.59 -            assert(type->hasTypeQualifiers());
   42.60 -            return key.type == type->unqualified() &&
   42.61 -                   key.quals == type->quals();                   
   42.62 -        }
   42.63 -    };
   42.64 -
   42.65 -    typedef HashTable<Policy, ZoneAllocatorPolicy> TypeHashTable;
   42.66 -
   42.67 -  public:
   42.68 -    TypeManager(Zone *zone);
   42.69 -
   42.70 -    bool initialize();
   42.71 -
   42.72 -    Type *getPrimitive(PrimitiveType type) {
   42.73 -        return primitiveTypes_[type];
   42.74 -    }
   42.75 -
   42.76 -    Type *getString() {
   42.77 -        return stringType_;
   42.78 -    }
   42.79 -    Type *getVoid() {
   42.80 -        return voidType_;
   42.81 -    }
   42.82 -    Type *getUnchecked() {
   42.83 -        return uncheckedType_;
   42.84 -    }
   42.85 -    Type *getImportable() {
   42.86 -        return importableType_;
   42.87 -    }
   42.88 -    Type *getType() {
   42.89 -        return typeType_;
   42.90 -    }
   42.91 -    ReferenceType *getReference(Handle<Type> type, bool isConst);
   42.92 -    ArrayType *newArray(Handle<Type> contained, int elements);
   42.93 -    ArrayType *newExternalArray(Handle<Type> contained);
   42.94 -    EnumType *newEnum(Handle<String> name);
   42.95 -    
   42.96 -    void accept(VirtualObjectVisitor *visitor);
   42.97 -    void sweep();
   42.98 -
   42.99 -    Type *qualify(Handle<Type> type, TypeQualifiers quals);
  42.100 -
  42.101 -  private:
  42.102 -    Zone *zone_;
  42.103 -
  42.104 -    // Primitive type cache.
  42.105 -    Unbarriered<Type> voidType_;
  42.106 -    Unbarriered<Type> stringType_;
  42.107 -    Unbarriered<Type> uncheckedType_;
  42.108 -    Unbarriered<Type> importableType_;
  42.109 -    Unbarriered<Type> typeType_;
  42.110 -    Unbarriered<Type> primitiveTypes_[PrimitiveTypes_Total];
  42.111 -    Unbarriered<ReferenceType> referenceTypes_[PrimitiveTypes_Total];
  42.112 -
  42.113 -    TypeHashTable qualTable_;
  42.114 -};
  42.115 -
  42.116 -}
  42.117 -
  42.118 -#endif // _include_jitcraft_type_manager_h_
  42.119 +/* vim: set ts=4 sw=4 tw=99 et:
  42.120 + *
  42.121 + * Copyright (C) 2012 David Anderson
  42.122 + *
  42.123 + * This file is part of SourcePawn.
  42.124 + *
  42.125 + * SourcePawn is free software: you can redistribute it and/or modify it under
  42.126 + * the terms of the GNU General Public License as published by the Free
  42.127 + * Software Foundation, either version 3 of the License, or (at your option)
  42.128 + * any later version.
  42.129 + * 
  42.130 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  42.131 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  42.132 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  42.133 + *
  42.134 + * You should have received a copy of the GNU General Public License along with
  42.135 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  42.136 + */
  42.137 +#ifndef _include_jitcraft_type_manager_h_
  42.138 +#define _include_jitcraft_type_manager_h_
  42.139 +
  42.140 +#include "Barriers.h"
  42.141 +#include "Types.h"
  42.142 +#include "HashTable.h"
  42.143 +#include "AllocatorPolicies.h"
  42.144 +#include "VirtualObjectVisitor.h"
  42.145 +
  42.146 +namespace ke {
  42.147 +
  42.148 +class String;
  42.149 +
  42.150 +class TypeManager
  42.151 +{
  42.152 +    struct LookupKey
  42.153 +    {
  42.154 +        Handle<Type> type;
  42.155 +        TypeQualifiers quals;
  42.156 +
  42.157 +        LookupKey(Handle<Type> type, TypeQualifiers quals)
  42.158 +          : type(type),
  42.159 +            quals(quals)
  42.160 +        {
  42.161 +        }
  42.162 +    };
  42.163 +
  42.164 +    struct Policy
  42.165 +    {
  42.166 +        typedef Type * Payload;
  42.167 +
  42.168 +        static uint32 hash(const LookupKey &key) {
  42.169 +            // We'll need to rehash with moving GC.
  42.170 +            return HashPointer(key.type);
  42.171 +        }
  42.172 +        
  42.173 +        static bool matches(const LookupKey &key, Type *type) {
  42.174 +            assert(type->hasTypeQualifiers());
  42.175 +            return key.type == type->unqualified() &&
  42.176 +                   key.quals == type->quals();                   
  42.177 +        }
  42.178 +    };
  42.179 +
  42.180 +    typedef HashTable<Policy, ZoneAllocatorPolicy> TypeHashTable;
  42.181 +
  42.182 +  public:
  42.183 +    TypeManager(Zone *zone);
  42.184 +
  42.185 +    bool initialize();
  42.186 +
  42.187 +    Type *getPrimitive(PrimitiveType type) {
  42.188 +        return primitiveTypes_[type];
  42.189 +    }
  42.190 +
  42.191 +    Type *getString() {
  42.192 +        return stringType_;
  42.193 +    }
  42.194 +    Type *getVoid() {
  42.195 +        return voidType_;
  42.196 +    }
  42.197 +    Type *getUnchecked() {
  42.198 +        return uncheckedType_;
  42.199 +    }
  42.200 +    Type *getImportable() {
  42.201 +        return importableType_;
  42.202 +    }
  42.203 +    Type *getType() {
  42.204 +        return typeType_;
  42.205 +    }
  42.206 +    ReferenceType *getReference(Handle<Type> type, bool isConst);
  42.207 +    ArrayType *newArray(Handle<Type> contained, int elements);
  42.208 +    ArrayType *newExternalArray(Handle<Type> contained);
  42.209 +    EnumType *newEnum(Handle<String> name);
  42.210 +    
  42.211 +    void accept(VirtualObjectVisitor *visitor);
  42.212 +    void sweep();
  42.213 +
  42.214 +    Type *qualify(Handle<Type> type, TypeQualifiers quals);
  42.215 +
  42.216 +  private:
  42.217 +    Zone *zone_;
  42.218 +
  42.219 +    // Primitive type cache.
  42.220 +    Unbarriered<Type> voidType_;
  42.221 +    Unbarriered<Type> stringType_;
  42.222 +    Unbarriered<Type> uncheckedType_;
  42.223 +    Unbarriered<Type> importableType_;
  42.224 +    Unbarriered<Type> typeType_;
  42.225 +    Unbarriered<Type> primitiveTypes_[PrimitiveTypes_Total];
  42.226 +    Unbarriered<ReferenceType> referenceTypes_[PrimitiveTypes_Total];
  42.227 +
  42.228 +    TypeHashTable qualTable_;
  42.229 +};
  42.230 +
  42.231 +}
  42.232 +
  42.233 +#endif // _include_jitcraft_type_manager_h_
    43.1 --- a/src/Types.cpp	Mon Jun 10 00:46:29 2013 +0100
    43.2 +++ b/src/Types.cpp	Mon Jun 10 01:04:43 2013 +0100
    43.3 @@ -1,333 +1,333 @@
    43.4 -/* vim: set ts=4 sw=4 tw=99 et:
    43.5 - *
    43.6 - * Copyright (C) 2012 David Anderson
    43.7 - *
    43.8 - * This file is part of SourcePawn.
    43.9 - *
   43.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   43.11 - * the terms of the GNU General Public License as published by the Free
   43.12 - * Software Foundation, either version 3 of the License, or (at your option)
   43.13 - * any later version.
   43.14 - * 
   43.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   43.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   43.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   43.18 - *
   43.19 - * You should have received a copy of the GNU General Public License along with
   43.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   43.21 - */
   43.22 -#include <string.h>
   43.23 -#include "Types.h"
   43.24 -#include "Zone.h"
   43.25 -#include "Strings.h"
   43.26 -#include "Array.h"
   43.27 -#include "Structures.h"
   43.28 -#include "Heap-inl.h"
   43.29 -
   43.30 -using namespace ke;
   43.31 -
   43.32 -void
   43.33 -Type::init(Kind kind, Type *root)
   43.34 -{
   43.35 -    this->kind_ = kind;
   43.36 -    this->root_ = root ? root : this;
   43.37 -}
   43.38 -
   43.39 -Type *
   43.40 -Type::NewVoid(Zone *zone)
   43.41 -{
   43.42 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   43.43 -    if (!type)
   43.44 -        return NULL;
   43.45 -
   43.46 -    type->init(VOID);
   43.47 -    return type;
   43.48 -}
   43.49 -
   43.50 -Type *
   43.51 -Type::NewImportable(Zone *zone)
   43.52 -{
   43.53 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   43.54 -    if (!type)
   43.55 -        return NULL;
   43.56 -
   43.57 -    type->init(IMPORTABLE);
   43.58 -    return type;
   43.59 -}
   43.60 -
   43.61 -Type *
   43.62 -Type::NewString(Zone *zone)
   43.63 -{
   43.64 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   43.65 -    if (!type)
   43.66 -        return NULL;
   43.67 -
   43.68 -    type->init(STRING);
   43.69 -    return type;
   43.70 -}
   43.71 -
   43.72 -Type *
   43.73 -Type::NewUnchecked(Zone *zone)
   43.74 -{
   43.75 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   43.76 -    if (!type)
   43.77 -        return NULL;
   43.78 -
   43.79 -    type->init(UNCHECKED);
   43.80 -    return type;
   43.81 -}
   43.82 -
   43.83 -Type *
   43.84 -Type::NewType(Zone *zone)
   43.85 -{
   43.86 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   43.87 -    if (!type)
   43.88 -        return NULL;
   43.89 -
   43.90 -    type->init(TYPE);
   43.91 -    return type;
   43.92 -}
   43.93 -
   43.94 -Type *
   43.95 -Type::NewPrimitive(Zone *zone, PrimitiveType prim)
   43.96 -{
   43.97 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   43.98 -    if (!type)
   43.99 -        return NULL;
  43.100 -
  43.101 -    type->init(PRIMITIVE);
  43.102 -    type->primitive_ = prim;
  43.103 -    return type;
  43.104 -}
  43.105 -
  43.106 -Type *
  43.107 -Type::NewQualified(Zone *zone, TypeQualifiers qual, Handle<Type> root)
  43.108 -{
  43.109 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  43.110 -    if (!type)
  43.111 -        return NULL;
  43.112 -
  43.113 -    type->init(QUALTYPE, root);
  43.114 -    type->quals_ = qual;
  43.115 -    return type;
  43.116 -}
  43.117 -
  43.118 -ArrayType *
  43.119 -ArrayType::New(Zone *zone, Handle<Type> contained, int elements)
  43.120 -{
  43.121 -    if (contained->isArray() &&
  43.122 -        ArrayType::cast(contained)->levels() == MAX_ARRAY_DEPTH)
  43.123 -    {
  43.124 -        zone->reportError(Message_MaximumArrayDepth);
  43.125 -        return NULL;
  43.126 -    }
  43.127 -
  43.128 -    Local<ArrayType> type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old));
  43.129 -    if (!type)
  43.130 -        return NULL;
  43.131 -
  43.132 -    type->init(ARRAY);
  43.133 -    type->contained_ = contained;
  43.134 -    type->elements_ = elements;
  43.135 -    if (!contained->isArray())
  43.136 -        type->levels_ = 1;
  43.137 -    else
  43.138 -        type->levels_ = ArrayType::cast(contained)->levels() + 1;
  43.139 -
  43.140 -    type->newMap_ = ArrayMap::New(zone, type);
  43.141 -    if (!type->newMap_)
  43.142 -        return NULL;
  43.143 -
  43.144 -    return type;
  43.145 -}
  43.146 -
  43.147 -ArrayType *
  43.148 -ArrayType::NewExternal(Zone *zone, Handle<Type> contained)
  43.149 -{
  43.150 -    Local<ArrayType> type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old));
  43.151 -    if (!type)
  43.152 -        return NULL;
  43.153 -
  43.154 -    assert(contained->isPrimitive());
  43.155 -
  43.156 -    type->init(EXTERNAL_ARRAY);
  43.157 -    type->contained_ = contained;
  43.158 -    type->elements_ = DYNAMIC_ARRAY_SIZE;
  43.159 -    type->levels_ = 1;
  43.160 -    return type;
  43.161 -}
  43.162 -
  43.163 -ReferenceType *
  43.164 -ReferenceType::New(Zone *zone, Handle<Type> contained)
  43.165 -{
  43.166 -    Local<ReferenceType> type(zone, (ReferenceType *)zone->allocate(MapKind_ReferenceType, sizeof(ReferenceType), Heap::Tenure_Old));
  43.167 -    if (!type)
  43.168 -        return NULL;
  43.169 -
  43.170 -    type->init(REFERENCE);
  43.171 -    type->contained_ = contained;
  43.172 -    return type;
  43.173 -}
  43.174 -
  43.175 -EnumType *
  43.176 -EnumType::New(Zone *zone, Handle<String> name)
  43.177 -{
  43.178 -    Local<EnumType> type(zone, (EnumType *)zone->allocate(MapKind_EnumType, sizeof(EnumType), Heap::Tenure_Old));
  43.179 -    if (!type)
  43.180 -        return NULL;
  43.181 -
  43.182 -    type->init(ENUM);
  43.183 -    type->name_ = name;
  43.184 -    type->fields_ = NULL;
  43.185 -    return type;
  43.186 -}
  43.187 -
  43.188 -StructType *
  43.189 -StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
  43.190 -{
  43.191 -    Local<StructType> type(zone, (StructType *)zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old));
  43.192 -    if (!type)
  43.193 -        return NULL;
  43.194 -
  43.195 -    type->init(STRUCT);
  43.196 -    type->newMap_ = NULL;
  43.197 -    type->fields_ = fields;
  43.198 -    type->name_ = name;
  43.199 -
  43.200 -    // Fill in field offsets.
  43.201 -    StructureBufferBuilder builder;
  43.202 -    Local<Type> fieldType(zone);
  43.203 -    for (size_t i = 0; i < fields->length(); i++) {
  43.204 -        Descriptor *desc = Descriptor::cast(fields->at(i));
  43.205 -        fieldType = desc->type();
  43.206 -
  43.207 -        unsigned offset;
  43.208 -        if (!builder.add(fieldType, &offset))
  43.209 -            return NULL;
  43.210 -        desc->setOffset(offset);
  43.211 -    }
  43.212 -
  43.213 -    Local<StructMap> map(zone, StructMap::New(zone, builder, type));
  43.214 -    if (!map)
  43.215 -        return NULL;
  43.216 -
  43.217 -    type->newMap_ = map;
  43.218 -
  43.219 -    return type;
  43.220 -}
  43.221 -
  43.222 -Descriptor *
  43.223 -StructType::lookupField(String *name, unsigned *index)
  43.224 -{
  43.225 -    // :TODO: assert no GC
  43.226 -    for (unsigned i = 0; i < fields_->length(); i++) {
  43.227 -        Descriptor *desc = Descriptor::cast(fields_->at(i));
  43.228 -        if (desc->name() == name) {
  43.229 -            if (index)
  43.230 -                *index = i;
  43.231 -            return desc;
  43.232 -        }
  43.233 -    }
  43.234 -
  43.235 -    return NULL;
  43.236 -}
  43.237 -
  43.238 -FunctionType *
  43.239 -FunctionType::New(Zone *zone, Handle<String> name, TokenKind token)
  43.240 -{
  43.241 -    Local<FunctionType> type(zone, (FunctionType *)zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old));
  43.242 -    if (!type)
  43.243 -        return NULL;
  43.244 -
  43.245 -    type->init(FUNCTION);
  43.246 -    type->parameters_ = NULL;
  43.247 -    type->defaults_ = NULL;
  43.248 -    type->returnType_ = NULL;
  43.249 -    type->name_ = name;
  43.250 -    type->token_ = token;
  43.251 -    return type;
  43.252 -}
  43.253 -
  43.254 -static size_t
  43.255 -FormatVA(char *buffer, size_t maxlen, const char *text, va_list ap)
  43.256 -{
  43.257 -    size_t len = vsnprintf(buffer, maxlen, text, ap);
  43.258 -    if (len >= maxlen) {
  43.259 -        buffer[maxlen - 1] = '\0';
  43.260 -        return maxlen - 1;
  43.261 -    }
  43.262 -    return len;
  43.263 -}
  43.264 -
  43.265 -static size_t
  43.266 -Format(char *buffer, size_t maxlen, const char *text, ...)
  43.267 -{
  43.268 -    va_list ap;
  43.269 -    va_start(ap, text);
  43.270 -    size_t len = FormatVA(buffer, maxlen, text, ap);
  43.271 -    va_end(ap);
  43.272 -    return len;
  43.273 -}
  43.274 -
  43.275 -static size_t
  43.276 -FormatTypeName(Type *type, char *buffer, size_t maxlen)
  43.277 -{
  43.278 -    if (type->isArray()) {
  43.279 -        ArrayType *atype = ArrayType::cast(type);
  43.280 -        Type *innermost = atype->innermost();
  43.281 -
  43.282 -        size_t len = FormatTypeName(innermost, buffer, maxlen);
  43.283 -        for (;;) {
  43.284 -            if (atype->isFixedLength())
  43.285 -                len += Format(buffer + len, maxlen - len, "[%d]", atype->fixedLength());
  43.286 -            else
  43.287 -                len += Format(buffer + len, maxlen - len, "[]");
  43.288 -            if (!atype->contained()->isArray())
  43.289 -                break;
  43.290 -            atype = ArrayType::cast(atype->contained());
  43.291 -        }
  43.292 -        return len;
  43.293 -    }
  43.294 -    if (type->hasTypeQualifiers()) {
  43.295 -        size_t len = 0;
  43.296 -        if (type->quals() & TypeQual_Const)
  43.297 -            len += Format(buffer, maxlen, "const ");
  43.298 -        return len + FormatTypeName(type->unqualified(), buffer + len, maxlen - len);
  43.299 -    }
  43.300 -    if (type->isFunction())
  43.301 -        return Format(buffer, maxlen, "function");
  43.302 -    if (type->isVoid())
  43.303 -        return Format(buffer, maxlen, "void");
  43.304 -    if (type->isUnchecked())
  43.305 -        return Format(buffer, maxlen, "unchecked");
  43.306 -    if (type->isImportable())
  43.307 -        return Format(buffer, maxlen, "import");
  43.308 -    if (type->isEnum())
  43.309 -        return Format(buffer, maxlen, "%s", EnumType::cast(type)->name()->chars());
  43.310 -    if (type->isStruct())
  43.311 -        return Format(buffer, maxlen, "%s", StructType::cast(type)->name()->chars());
  43.312 -    if (type->isReference()) {
  43.313 -        ReferenceType *ref = ReferenceType::cast(type);
  43.314 -        size_t len = Format(buffer, maxlen, "&");
  43.315 -        return len + FormatTypeName(ref->contained(), buffer + len, maxlen - len);
  43.316 -    }
  43.317 -    switch (type->primitive()) {
  43.318 -      case PrimitiveType_Bool:
  43.319 -        return Format(buffer, maxlen, "bool");
  43.320 -      case PrimitiveType_Char:
  43.321 -        return Format(buffer, maxlen, "char");
  43.322 -      case PrimitiveType_Int32:
  43.323 -        return Format(buffer, maxlen, "int");
  43.324 -      case PrimitiveType_Float:
  43.325 -        return Format(buffer, maxlen, "float");
  43.326 -      default:
  43.327 -        return Format(buffer, maxlen, "<UNKNOWN>");
  43.328 -    }
  43.329 -}
  43.330 -
  43.331 -const char *
  43.332 -ke::GetTypeName(Type *type, char *buffer, size_t maxlen)
  43.333 -{
  43.334 -    FormatTypeName(type, buffer, maxlen);
  43.335 -    return buffer;
  43.336 -}
  43.337 +/* vim: set ts=4 sw=4 tw=99 et:
  43.338 + *
  43.339 + * Copyright (C) 2012 David Anderson
  43.340 + *
  43.341 + * This file is part of SourcePawn.
  43.342 + *
  43.343 + * SourcePawn is free software: you can redistribute it and/or modify it under
  43.344 + * the terms of the GNU General Public License as published by the Free
  43.345 + * Software Foundation, either version 3 of the License, or (at your option)
  43.346 + * any later version.
  43.347 + * 
  43.348 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  43.349 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  43.350 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  43.351 + *
  43.352 + * You should have received a copy of the GNU General Public License along with
  43.353 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  43.354 + */
  43.355 +#include <string.h>
  43.356 +#include "Types.h"
  43.357 +#include "Zone.h"
  43.358 +#include "Strings.h"
  43.359 +#include "Array.h"
  43.360 +#include "Structures.h"
  43.361 +#include "Heap-inl.h"
  43.362 +
  43.363 +using namespace ke;
  43.364 +
  43.365 +void
  43.366 +Type::init(Kind kind, Type *root)
  43.367 +{
  43.368 +    this->kind_ = kind;
  43.369 +    this->root_ = root ? root : this;
  43.370 +}
  43.371 +
  43.372 +Type *
  43.373 +Type::NewVoid(Zone *zone)
  43.374 +{
  43.375 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  43.376 +    if (!type)
  43.377 +        return NULL;
  43.378 +
  43.379 +    type->init(VOID);
  43.380 +    return type;
  43.381 +}
  43.382 +
  43.383 +Type *
  43.384 +Type::NewImportable(Zone *zone)
  43.385 +{
  43.386 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  43.387 +    if (!type)
  43.388 +        return NULL;
  43.389 +
  43.390 +    type->init(IMPORTABLE);
  43.391 +    return type;
  43.392 +}
  43.393 +
  43.394 +Type *
  43.395 +Type::NewString(Zone *zone)
  43.396 +{
  43.397 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  43.398 +    if (!type)
  43.399 +        return NULL;
  43.400 +
  43.401 +    type->init(STRING);
  43.402 +    return type;
  43.403 +}
  43.404 +
  43.405 +Type *
  43.406 +Type::NewUnchecked(Zone *zone)
  43.407 +{
  43.408 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  43.409 +    if (!type)
  43.410 +        return NULL;
  43.411 +
  43.412 +    type->init(UNCHECKED);
  43.413 +    return type;
  43.414 +}
  43.415 +
  43.416 +Type *
  43.417 +Type::NewType(Zone *zone)
  43.418 +{
  43.419 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  43.420 +    if (!type)
  43.421 +        return NULL;
  43.422 +
  43.423 +    type->init(TYPE);
  43.424 +    return type;
  43.425 +}
  43.426 +
  43.427 +Type *
  43.428 +Type::NewPrimitive(Zone *zone, PrimitiveType prim)
  43.429 +{
  43.430 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  43.431 +    if (!type)
  43.432 +        return NULL;
  43.433 +
  43.434 +    type->init(PRIMITIVE);
  43.435 +    type->primitive_ = prim;
  43.436 +    return type;
  43.437 +}
  43.438 +
  43.439 +Type *
  43.440 +Type::NewQualified(Zone *zone, TypeQualifiers qual, Handle<Type> root)
  43.441 +{
  43.442 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  43.443 +    if (!type)
  43.444 +        return NULL;
  43.445 +
  43.446 +    type->init(QUALTYPE, root);
  43.447 +    type->quals_ = qual;
  43.448 +    return type;
  43.449 +}
  43.450 +
  43.451 +ArrayType *
  43.452 +ArrayType::New(Zone *zone, Handle<Type> contained, int elements)
  43.453 +{
  43.454 +    if (contained->isArray() &&
  43.455 +        ArrayType::cast(contained)->levels() == MAX_ARRAY_DEPTH)
  43.456 +    {
  43.457 +        zone->reportError(Message_MaximumArrayDepth);
  43.458 +        return NULL;
  43.459 +    }
  43.460 +
  43.461 +    Local<ArrayType> type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old));
  43.462 +    if (!type)
  43.463 +        return NULL;
  43.464 +
  43.465 +    type->init(ARRAY);
  43.466 +    type->contained_ = contained;
  43.467 +    type->elements_ = elements;
  43.468 +    if (!contained->isArray())
  43.469 +        type->levels_ = 1;
  43.470 +    else
  43.471 +        type->levels_ = ArrayType::cast(contained)->levels() + 1;
  43.472 +
  43.473 +    type->newMap_ = ArrayMap::New(zone, type);
  43.474 +    if (!type->newMap_)
  43.475 +        return NULL;
  43.476 +
  43.477 +    return type;
  43.478 +}
  43.479 +
  43.480 +ArrayType *
  43.481 +ArrayType::NewExternal(Zone *zone, Handle<Type> contained)
  43.482 +{
  43.483 +    Local<ArrayType> type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old));
  43.484 +    if (!type)
  43.485 +        return NULL;
  43.486 +
  43.487 +    assert(contained->isPrimitive());
  43.488 +
  43.489 +    type->init(EXTERNAL_ARRAY);
  43.490 +    type->contained_ = contained;
  43.491 +    type->elements_ = DYNAMIC_ARRAY_SIZE;
  43.492 +    type->levels_ = 1;
  43.493 +    return type;
  43.494 +}
  43.495 +
  43.496 +ReferenceType *
  43.497 +ReferenceType::New(Zone *zone, Handle<Type> contained)
  43.498 +{
  43.499 +    Local<ReferenceType> type(zone, (ReferenceType *)zone->allocate(MapKind_ReferenceType, sizeof(ReferenceType), Heap::Tenure_Old));
  43.500 +    if (!type)
  43.501 +        return NULL;
  43.502 +
  43.503 +    type->init(REFERENCE);
  43.504 +    type->contained_ = contained;
  43.505 +    return type;
  43.506 +}
  43.507 +
  43.508 +EnumType *
  43.509 +EnumType::New(Zone *zone, Handle<String> name)
  43.510 +{
  43.511 +    Local<EnumType> type(zone, (EnumType *)zone->allocate(MapKind_EnumType, sizeof(EnumType), Heap::Tenure_Old));
  43.512 +    if (!type)
  43.513 +        return NULL;
  43.514 +
  43.515 +    type->init(ENUM);
  43.516 +    type->name_ = name;
  43.517 +    type->fields_ = NULL;
  43.518 +    return type;
  43.519 +}
  43.520 +
  43.521 +StructType *
  43.522 +StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
  43.523 +{
  43.524 +    Local<StructType> type(zone, (StructType *)zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old));
  43.525 +    if (!type)
  43.526 +        return NULL;
  43.527 +
  43.528 +    type->init(STRUCT);
  43.529 +    type->newMap_ = NULL;
  43.530 +    type->fields_ = fields;
  43.531 +    type->name_ = name;
  43.532 +
  43.533 +    // Fill in field offsets.
  43.534 +    StructureBufferBuilder builder;
  43.535 +    Local<Type> fieldType(zone);
  43.536 +    for (size_t i = 0; i < fields->length(); i++) {
  43.537 +        Descriptor *desc = Descriptor::cast(fields->at(i));
  43.538 +        fieldType = desc->type();
  43.539 +
  43.540 +        unsigned offset;
  43.541 +        if (!builder.add(fieldType, &offset))
  43.542 +            return NULL;
  43.543 +        desc->setOffset(offset);
  43.544 +    }
  43.545 +
  43.546 +    Local<StructMap> map(zone, StructMap::New(zone, builder, type));
  43.547 +    if (!map)
  43.548 +        return NULL;
  43.549 +
  43.550 +    type->newMap_ = map;
  43.551 +
  43.552 +    return type;
  43.553 +}
  43.554 +
  43.555 +Descriptor *
  43.556 +StructType::lookupField(String *name, unsigned *index)
  43.557 +{
  43.558 +    // :TODO: assert no GC
  43.559 +    for (unsigned i = 0; i < fields_->length(); i++) {
  43.560 +        Descriptor *desc = Descriptor::cast(fields_->at(i));
  43.561 +        if (desc->name() == name) {
  43.562 +            if (index)
  43.563 +                *index = i;
  43.564 +            return desc;
  43.565 +        }
  43.566 +    }
  43.567 +
  43.568 +    return NULL;
  43.569 +}
  43.570 +
  43.571 +FunctionType *
  43.572 +FunctionType::New(Zone *zone, Handle<String> name, TokenKind token)
  43.573 +{
  43.574 +    Local<FunctionType> type(zone, (FunctionType *)zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old));
  43.575 +    if (!type)
  43.576 +        return NULL;
  43.577 +
  43.578 +    type->init(FUNCTION);
  43.579 +    type->parameters_ = NULL;
  43.580 +    type->defaults_ = NULL;
  43.581 +    type->returnType_ = NULL;
  43.582 +    type->name_ = name;
  43.583 +    type->token_ = token;
  43.584 +    return type;
  43.585 +}
  43.586 +
  43.587 +static size_t
  43.588 +FormatVA(char *buffer, size_t maxlen, const char *text, va_list ap)
  43.589 +{
  43.590 +    size_t len = vsnprintf(buffer, maxlen, text, ap);
  43.591 +    if (len >= maxlen) {
  43.592 +        buffer[maxlen - 1] = '\0';
  43.593 +        return maxlen - 1;
  43.594 +    }
  43.595 +    return len;
  43.596 +}
  43.597 +
  43.598 +static size_t
  43.599 +Format(char *buffer, size_t maxlen, const char *text, ...)
  43.600 +{
  43.601 +    va_list ap;
  43.602 +    va_start(ap, text);
  43.603 +    size_t len = FormatVA(buffer, maxlen, text, ap);
  43.604 +    va_end(ap);
  43.605 +    return len;
  43.606 +}
  43.607 +
  43.608 +static size_t
  43.609 +FormatTypeName(Type *type, char *buffer, size_t maxlen)
  43.610 +{
  43.611 +    if (type->isArray()) {
  43.612 +        ArrayType *atype = ArrayType::cast(type);
  43.613 +        Type *innermost = atype->innermost();
  43.614 +
  43.615 +        size_t len = FormatTypeName(innermost, buffer, maxlen);
  43.616 +        for (;;) {
  43.617 +            if (atype->isFixedLength())
  43.618 +                len += Format(buffer + len, maxlen - len, "[%d]", atype->fixedLength());
  43.619 +            else
  43.620 +                len += Format(buffer + len, maxlen - len, "[]");
  43.621 +            if (!atype->contained()->isArray())
  43.622 +                break;
  43.623 +            atype = ArrayType::cast(atype->contained());
  43.624 +        }
  43.625 +        return len;
  43.626 +    }
  43.627 +    if (type->hasTypeQualifiers()) {
  43.628 +        size_t len = 0;
  43.629 +        if (type->quals() & TypeQual_Const)
  43.630 +            len += Format(buffer, maxlen, "const ");
  43.631 +        return len + FormatTypeName(type->unqualified(), buffer + len, maxlen - len);
  43.632 +    }
  43.633 +    if (type->isFunction())
  43.634 +        return Format(buffer, maxlen, "function");
  43.635 +    if (type->isVoid())
  43.636 +        return Format(buffer, maxlen, "void");
  43.637 +    if (type->isUnchecked())
  43.638 +        return Format(buffer, maxlen, "unchecked");
  43.639 +    if (type->isImportable())
  43.640 +        return Format(buffer, maxlen, "import");
  43.641 +    if (type->isEnum())
  43.642 +        return Format(buffer, maxlen, "%s", EnumType::cast(type)->name()->chars());
  43.643 +    if (type->isStruct())
  43.644 +        return Format(buffer, maxlen, "%s", StructType::cast(type)->name()->chars());
  43.645 +    if (type->isReference()) {
  43.646 +        ReferenceType *ref = ReferenceType::cast(type);
  43.647 +        size_t len = Format(buffer, maxlen, "&");
  43.648 +        return len + FormatTypeName(ref->contained(), buffer + len, maxlen - len);
  43.649 +    }
  43.650 +    switch (type->primitive()) {
  43.651 +      case PrimitiveType_Bool:
  43.652 +        return Format(buffer, maxlen, "bool");
  43.653 +      case PrimitiveType_Char:
  43.654 +        return Format(buffer, maxlen, "char");
  43.655 +      case PrimitiveType_Int32:
  43.656 +        return Format(buffer, maxlen, "int");
  43.657 +      case PrimitiveType_Float:
  43.658 +        return Format(buffer, maxlen, "float");
  43.659 +      default:
  43.660 +        return Format(buffer, maxlen, "<UNKNOWN>");
  43.661 +    }
  43.662 +}
  43.663 +
  43.664 +const char *
  43.665 +ke::GetTypeName(Type *type, char *buffer, size_t maxlen)
  43.666 +{
  43.667 +    FormatTypeName(type, buffer, maxlen);
  43.668 +    return buffer;
  43.669 +}
    44.1 --- a/src/Zone.cpp	Mon Jun 10 00:46:29 2013 +0100
    44.2 +++ b/src/Zone.cpp	Mon Jun 10 01:04:43 2013 +0100
    44.3 @@ -1,368 +1,368 @@
    44.4 -/* vim: set ts=4 sw=4 tw=99 et:
    44.5 - *
    44.6 - * Copyright (C) 2012 David Anderson
    44.7 - *
    44.8 - * This file is part of JITCraft.
    44.9 - *
   44.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   44.11 - * the terms of the GNU General Public License as published by the Free
   44.12 - * Software Foundation, either version 3 of the License, or (at your option)
   44.13 - * any later version.
   44.14 - * 
   44.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   44.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   44.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   44.18 - *
   44.19 - * You should have received a copy of the GNU General Public License along with
   44.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   44.21 - */
   44.22 -#include <stdlib.h>
   44.23 -#include "Zone.h"
   44.24 -#include "StringPool.h"
   44.25 -#include "TypeManager.h"
   44.26 -#include "GlobalRoots.h"
   44.27 -#include "AllocatorPolicies.h"
   44.28 -#include "Array.h"
   44.29 -#include "NativeTable.h"
   44.30 -#include "Packages.h"
   44.31 -#include "Spaces-inl.h"
   44.32 -#include "Heap-inl.h"
   44.33 -
   44.34 -using namespace ke;
   44.35 -
   44.36 -Zone *ke::SingleThreadedZone;
   44.37 -
   44.38 -void * const NullAddress::Sentinel = NULL;
   44.39 -
   44.40 -Zone::Zone()
   44.41 -  : stack_(thisFromCtor()),
   44.42 -    heap_(thisFromCtor()),
   44.43 -    types_(NULL),
   44.44 -    symbols_(NULL),
   44.45 -    globalRoots_(NULL),
   44.46 -    nativeTable_(NULL),
   44.47 -    packages_(NULL),
   44.48 -    lastLocalRoot_(NULL),
   44.49 -    specialRoots_(NULL),
   44.50 -    hasPendingException_(false),
   44.51 -    reporter_(NULL)
   44.52 -{
   44.53 -}
   44.54 -
   44.55 -Zone::~Zone()
   44.56 -{
   44.57 -    delete nativeTable_;
   44.58 -    delete types_;
   44.59 -    delete symbols_;
   44.60 -    delete packages_;
   44.61 -    delete globalRoots_;
   44.62 -}
   44.63 -
   44.64 -bool
   44.65 -Zone::initialize()
   44.66 -{
   44.67 -    if (!stack_.initialize())
   44.68 -        return false;
   44.69 -    if (!heap_.initialize())
   44.70 -        return false;
   44.71 -
   44.72 -    symbols_ = new StringPool(this);
   44.73 -    if (!symbols_ || !symbols_->initialize())
   44.74 -        return false;
   44.75 -
   44.76 -    globalRoots_ = new GlobalRoots(this);
   44.77 -    if (!globalRoots_ || !globalRoots_->initialize())
   44.78 -        return false;
   44.79 -
   44.80 -    nativeTable_ = new NativeTable(this);
   44.81 -    if (!nativeTable_ || !nativeTable_->initialize())
   44.82 -        return false;
   44.83 -
   44.84 -    packages_ = new PackageCache(this);
   44.85 -    if (!packages_ || !packages_->initialize())
   44.86 -        return false;
   44.87 -
   44.88 -    MapKind maps[] =
   44.89 -    {
   44.90 -        MapKind_Type,
   44.91 -        MapKind_ArrayType,
   44.92 -        MapKind_FunctionType,
   44.93 -        MapKind_StructType,
   44.94 -        MapKind_ReferenceType,
   44.95 -        MapKind_EnumType,
   44.96 -        MapKind_FixedArray,
   44.97 -        MapKind_ByteArray,
   44.98 -        MapKind_Code,
   44.99 -        MapKind_Reference,
  44.100 -        MapKind_MetaArray,
  44.101 -        MapKind_MetaStruct,
  44.102 -        MapKind_MetaEnvironment,
  44.103 -        MapKind_Module,
  44.104 -        MapKind_Function,
  44.105 -        MapKind_String,
  44.106 -        MapKind_Native,
  44.107 -        MapKind_Descriptor,
  44.108 -        MapKind_Box,
  44.109 -        MapKind_List,
  44.110 -        MapKind_Package,
  44.111 -        MapKind_FreeRegion,
  44.112 -        MapKind_EnvironmentSlotDescriptorArray
  44.113 -    };
  44.114 -
  44.115 -    maps_[MapKind_Meta] = heap_.metaMap();
  44.116 -    for (size_t i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) {
  44.117 -        if ((maps_[maps[i]] = allocateMap(maps[i], sizeof(Map))) == NULL)
  44.118 -            return false;
  44.119 -    }
  44.120 -
  44.121 -    types_ = new TypeManager(this);
  44.122 -    if (!types_ || !types_->initialize())
  44.123 -        return false;
  44.124 -
  44.125 -    // Create the cached array maps for generic arrays. This is for the API
  44.126 -    // version of Invoke(), which needs to make arrays very quickly from C++.
  44.127 -    {
  44.128 -        // Generic "cell" array (contents do not matter, just non-gc things).
  44.129 -        Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
  44.130 -        if (!type)
  44.131 -            return false;
  44.132 -
  44.133 -        type = types_->newExternalArray(type);
  44.134 -        if (!type)
  44.135 -            return false;
  44.136 -
  44.137 -        // :TODO:
  44.138 -#if 0
  44.139 -        externalGenericArrayMap_ = ArrayMap::Attach(this, type);
  44.140 -        if (!externalGenericArrayMap_)
  44.141 -            return false;
  44.142 -#endif
  44.143 -
  44.144 -        type = types_->getPrimitive(PrimitiveType_Char);
  44.145 -        if (!type)
  44.146 -            return false;
  44.147 -
  44.148 -        type = types_->newExternalArray(type);
  44.149 -        if (!type)
  44.150 -            return false;
  44.151 -
  44.152 -        // :TODO:
  44.153 -#if 0
  44.154 -        externalCharArrayMap_ = ArrayMap::Attach(this, type);
  44.155 -        if (!externalCharArrayMap_)
  44.156 -            return false;
  44.157 -#endif
  44.158 -    }
  44.159 -
  44.160 -    return true;
  44.161 -}
  44.162 -
  44.163 -Map *
  44.164 -Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
  44.165 -{
  44.166 -    assert(maps_[parent]);
  44.167 -    Map *map = heap_.allocateMap(kind, bytes);
  44.168 -    if (!map)
  44.169 -        return NULL;
  44.170 -    map->init(maps_[parent]);
  44.171 -    return map;
  44.172 -}
  44.173 -
  44.174 -void
  44.175 -Zone::accept(VirtualObjectVisitor *visitor)
  44.176 -{
  44.177 -    for (unsigned i = 0; i < MapKinds_Total; i++)
  44.178 -        visitor->visit(maps_[i].address());
  44.179 -    visitor->visit(externalCharArrayMap_.address());
  44.180 -    visitor->visit(externalGenericArrayMap_.address());
  44.181 -    types()->accept(visitor);
  44.182 -
  44.183 -    Local<Object> *local = lastLocalRoot_;
  44.184 -    while (local) {
  44.185 -        visitor->visit(local->address());
  44.186 -        local = local->prev();
  44.187 -    }
  44.188 -
  44.189 -    globalRoots_->accept(visitor);
  44.190 -    rootScopes_.accept(visitor);
  44.191 -    nativeTable_->accept(visitor);
  44.192 -    packages_->accept(visitor);
  44.193 -
  44.194 -    stack_.accept(visitor);
  44.195 -}
  44.196 -
  44.197 -void
  44.198 -Zone::sweepWeakRoots()
  44.199 -{
  44.200 -    symbols_->sweep();
  44.201 -    types()->sweep();
  44.202 -}
  44.203 -
  44.204 -String *
  44.205 -Zone::makeSymbol(const char *str, size_t length)
  44.206 -{
  44.207 -    return symbols_->add(str, length);
  44.208 -}
  44.209 -
  44.210 -String *
  44.211 -Zone::makeSymbol(const char *str)
  44.212 -{
  44.213 -    return makeSymbol(str, strlen(str));
  44.214 -}
  44.215 -
  44.216 -bool
  44.217 -Zone::hasPendingException()
  44.218 -{
  44.219 -    return hasPendingException_;
  44.220 -}
  44.221 -
  44.222 -void
  44.223 -Zone::reportOutOfMemory()
  44.224 -{
  44.225 -    
  44.226 -}
  44.227 -
  44.228 -void
  44.229 -Zone::reportError(Message message, ...)
  44.230 -{
  44.231 -    va_list ap;
  44.232 -    va_start(ap, message);
  44.233 -    reportErrorVA(message, ap);
  44.234 -    va_end(ap);
  44.235 -}
  44.236 -
  44.237 -#if defined(_MSC_VER)
  44.238 -# define VA_COPY(to, from)  to = from
  44.239 -#else
  44.240 -# define VA_COPY(to, from)  va_copy(to, from)
  44.241 -#endif
  44.242 -
  44.243 -char *
  44.244 -ke::BuildErrorMessage(const char *format, va_list ap)
  44.245 -{
  44.246 -    va_list use;
  44.247 -    VA_COPY(use, ap);
  44.248 -
  44.249 -    // We over-allocate and zero terminate ahead of time, since LIBCRT's
  44.250 -    // version of vsnprintf is screwy.
  44.251 -    size_t size = 255;
  44.252 -    char *buffer = (char *)calloc(size + 1, 1);
  44.253 -    if (!buffer)
  44.254 -        return NULL;
  44.255 -
  44.256 -    for (;;) {
  44.257 -        int r = vsnprintf(buffer, size, format, use);
  44.258 -
  44.259 -        if (r > -1 && size_t(r) < size)
  44.260 -            return buffer;
  44.261 -       
  44.262 -#if defined(_MSC_VER)
  44.263 -        if (r < 0)
  44.264 -            size *= 2;
  44.265 -#else
  44.266 -        if (r > -1)
  44.267 -            size = size_t(r) + 1;
  44.268 -        else
  44.269 -            size *= 2;
  44.270 -#endif
  44.271 -
  44.272 -        free(buffer);
  44.273 -        if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
  44.274 -            return NULL;
  44.275 -
  44.276 -        VA_COPY(use, ap);
  44.277 -    }
  44.278 -}
  44.279 -
  44.280 -void
  44.281 -ke::FreeErrorMessage(const char *message)
  44.282 -{
  44.283 -    free((void *)message);
  44.284 -}
  44.285 -
  44.286 -void
  44.287 -Zone::reportErrorVA(Message message, va_list ap)
  44.288 -{
  44.289 -    char *report = BuildErrorMessage(Messages[message].format, ap);
  44.290 -    if (!report) {
  44.291 -        reportOutOfMemory();
  44.292 -        return;
  44.293 -    }
  44.294 -
  44.295 -    if (reporter_) {
  44.296 -        // Reporters can re-enter. When we start having actual exception
  44.297 -        // objects that can be caught and inspected, this code will have to
  44.298 -        // save and restore the exception state.
  44.299 -        reporter_->onUncaughtException(report);
  44.300 -    }
  44.301 -
  44.302 -    hasPendingException_ = true;
  44.303 -
  44.304 -    FreeErrorMessage(report);
  44.305 -}
  44.306 -
  44.307 -void
  44.308 -Zone::installErrorReporter(Ke::IMessageReporter *reporter)
  44.309 -{
  44.310 -    reporter_ = reporter;
  44.311 -}
  44.312 -
  44.313 -void
  44.314 -ZoneAllocatorPolicy::reportOutOfMemory()
  44.315 -{
  44.316 -    ZONE()->reportOutOfMemory();
  44.317 -}
  44.318 -
  44.319 -void
  44.320 -ZoneAllocatorPolicy::reportAllocationOverflow()
  44.321 -{
  44.322 -    ZONE()->reportAllocationOverflow();
  44.323 -}
  44.324 -
  44.325 -void
  44.326 -Zone::reportAllocationOverflow()
  44.327 -{
  44.328 -    reportError(Message_AllocationOverflow);
  44.329 -}
  44.330 -
  44.331 -void
  44.332 -Zone::clearPendingException()
  44.333 -{
  44.334 -    hasPendingException_ = false;
  44.335 -}
  44.336 -
  44.337 -void
  44.338 -Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener)
  44.339 -{
  44.340 -    publicFunctionListener_ = listener;
  44.341 -}
  44.342 -
  44.343 -void *
  44.344 -Zone::malloc(size_t size)
  44.345 -{
  44.346 -    void *ptr = ::malloc(size);
  44.347 -    if (!ptr)
  44.348 -        reportOutOfMemory();
  44.349 -    return ptr;
  44.350 -}
  44.351 -
  44.352 -void *
  44.353 -Zone::realloc(void *ptr, size_t size)
  44.354 -{
  44.355 -    ptr = ::realloc(ptr, size);
  44.356 -    if (!ptr)
  44.357 -        reportOutOfMemory();
  44.358 -    return ptr;
  44.359 -}
  44.360 -
  44.361 -AutoRooted::AutoRooted(Zone *zone)
  44.362 -  : zone_(zone),
  44.363 -    prev_(*zone->lastSpecialRoot())
  44.364 -{
  44.365 -    *zone->lastSpecialRoot() = this;
  44.366 -}
  44.367 -
  44.368 -AutoRooted::~AutoRooted()
  44.369 -{
  44.370 -    *zone_->lastSpecialRoot() = prev_;
  44.371 -}
  44.372 +/* vim: set ts=4 sw=4 tw=99 et:
  44.373 + *
  44.374 + * Copyright (C) 2012 David Anderson
  44.375 + *
  44.376 + * This file is part of JITCraft.
  44.377 + *
  44.378 + * JITCraft is free software: you can redistribute it and/or modify it under
  44.379 + * the terms of the GNU General Public License as published by the Free
  44.380 + * Software Foundation, either version 3 of the License, or (at your option)
  44.381 + * any later version.
  44.382 + * 
  44.383 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  44.384 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  44.385 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  44.386 + *
  44.387 + * You should have received a copy of the GNU General Public License along with
  44.388 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  44.389 + */
  44.390 +#include <stdlib.h>
  44.391 +#include "Zone.h"
  44.392 +#include "StringPool.h"
  44.393 +#include "TypeManager.h"
  44.394 +#include "GlobalRoots.h"
  44.395 +#include "AllocatorPolicies.h"
  44.396 +#include "Array.h"
  44.397 +#include "NativeTable.h"
  44.398 +#include "Packages.h"
  44.399 +#include "Spaces-inl.h"
  44.400 +#include "Heap-inl.h"
  44.401 +
  44.402 +using namespace ke;
  44.403 +
  44.404 +Zone *ke::SingleThreadedZone;
  44.405 +
  44.406 +void * const NullAddress::Sentinel = NULL;
  44.407 +
  44.408 +Zone::Zone()
  44.409 +  : stack_(thisFromCtor()),
  44.410 +    heap_(thisFromCtor()),
  44.411 +    types_(NULL),
  44.412 +    symbols_(NULL),
  44.413 +    globalRoots_(NULL),
  44.414 +    nativeTable_(NULL),
  44.415 +    packages_(NULL),
  44.416 +    lastLocalRoot_(NULL),
  44.417 +    specialRoots_(NULL),
  44.418 +    hasPendingException_(false),
  44.419 +    reporter_(NULL)
  44.420 +{
  44.421 +}
  44.422 +
  44.423 +Zone::~Zone()
  44.424 +{
  44.425 +    delete nativeTable_;
  44.426 +    delete types_;
  44.427 +    delete symbols_;
  44.428 +    delete packages_;
  44.429 +    delete globalRoots_;
  44.430 +}
  44.431 +
  44.432 +bool
  44.433 +Zone::initialize()
  44.434 +{
  44.435 +    if (!stack_.initialize())
  44.436 +        return false;
  44.437 +    if (!heap_.initialize())
  44.438 +        return false;
  44.439 +
  44.440 +    symbols_ = new StringPool(this);
  44.441 +    if (!symbols_ || !symbols_->initialize())
  44.442 +        return false;
  44.443 +
  44.444 +    globalRoots_ = new GlobalRoots(this);
  44.445 +    if (!globalRoots_ || !globalRoots_->initialize())
  44.446 +        return false;
  44.447 +
  44.448 +    nativeTable_ = new NativeTable(this);
  44.449 +    if (!nativeTable_ || !nativeTable_->initialize())
  44.450 +        return false;
  44.451 +
  44.452 +    packages_ = new PackageCache(this);
  44.453 +    if (!packages_ || !packages_->initialize())
  44.454 +        return false;
  44.455 +
  44.456 +    MapKind maps[] =
  44.457 +    {
  44.458 +        MapKind_Type,
  44.459 +        MapKind_ArrayType,
  44.460 +        MapKind_FunctionType,
  44.461 +        MapKind_StructType,
  44.462 +        MapKind_ReferenceType,
  44.463 +        MapKind_EnumType,
  44.464 +        MapKind_FixedArray,
  44.465 +        MapKind_ByteArray,
  44.466 +        MapKind_Code,
  44.467 +        MapKind_Reference,
  44.468 +        MapKind_MetaArray,
  44.469 +        MapKind_MetaStruct,
  44.470 +        MapKind_MetaEnvironment,
  44.471 +        MapKind_Module,
  44.472 +        MapKind_Function,
  44.473 +        MapKind_String,
  44.474 +        MapKind_Native,
  44.475 +        MapKind_Descriptor,
  44.476 +        MapKind_Box,
  44.477 +        MapKind_List,
  44.478 +        MapKind_Package,
  44.479 +        MapKind_FreeRegion,
  44.480 +        MapKind_EnvironmentSlotDescriptorArray
  44.481 +    };
  44.482 +
  44.483 +    maps_[MapKind_Meta] = heap_.metaMap();
  44.484 +    for (size_t i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) {
  44.485 +        if ((maps_[maps[i]] = allocateMap(maps[i], sizeof(Map))) == NULL)
  44.486 +            return false;
  44.487 +    }
  44.488 +
  44.489 +    types_ = new TypeManager(this);
  44.490 +    if (!types_ || !types_->initialize())
  44.491 +        return false;
  44.492 +
  44.493 +    // Create the cached array maps for generic arrays. This is for the API
  44.494 +    // version of Invoke(), which needs to make arrays very quickly from C++.
  44.495 +    {
  44.496 +        // Generic "cell" array (contents do not matter, just non-gc things).
  44.497 +        Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
  44.498 +        if (!type)
  44.499 +            return false;
  44.500 +
  44.501 +        type = types_->newExternalArray(type);
  44.502 +        if (!type)
  44.503 +            return false;
  44.504 +
  44.505 +        // :TODO:
  44.506 +#if 0
  44.507 +        externalGenericArrayMap_ = ArrayMap::Attach(this, type);
  44.508 +        if (!externalGenericArrayMap_)
  44.509 +            return false;
  44.510 +#endif
  44.511 +
  44.512 +        type = types_->getPrimitive(PrimitiveType_Char);
  44.513 +        if (!type)
  44.514 +            return false;
  44.515 +
  44.516 +        type = types_->newExternalArray(type);
  44.517 +        if (!type)
  44.518 +            return false;
  44.519 +
  44.520 +        // :TODO:
  44.521 +#if 0
  44.522 +        externalCharArrayMap_ = ArrayMap::Attach(this, type);
  44.523 +        if (!externalCharArrayMap_)
  44.524 +            return false;
  44.525 +#endif
  44.526 +    }
  44.527 +
  44.528 +    return true;
  44.529 +}
  44.530 +
  44.531 +Map *
  44.532 +Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
  44.533 +{
  44.534 +    assert(maps_[parent]);
  44.535 +    Map *map = heap_.allocateMap(kind, bytes);
  44.536 +    if (!map)
  44.537 +        return NULL;
  44.538 +    map->init(maps_[parent]);
  44.539 +    return map;
  44.540 +}
  44.541 +
  44.542 +void
  44.543 +Zone::accept(VirtualObjectVisitor *visitor)
  44.544 +{
  44.545 +    for (unsigned i = 0; i < MapKinds_Total; i++)
  44.546 +        visitor->visit(maps_[i].address());
  44.547 +    visitor->visit(externalCharArrayMap_.address());
  44.548 +    visitor->visit(externalGenericArrayMap_.address());
  44.549 +    types()->accept(visitor);
  44.550 +
  44.551 +    Local<Object> *local = lastLocalRoot_;
  44.552 +    while (local) {
  44.553 +        visitor->visit(local->address());
  44.554 +        local = local->prev();
  44.555 +    }
  44.556 +
  44.557 +    globalRoots_->accept(visitor);
  44.558 +    rootScopes_.accept(visitor);
  44.559 +    nativeTable_->accept(visitor);
  44.560 +    packages_->accept(visitor);
  44.561 +
  44.562 +    stack_.accept(visitor);
  44.563 +}
  44.564 +
  44.565 +void
  44.566 +Zone::sweepWeakRoots()
  44.567 +{
  44.568 +    symbols_->sweep();
  44.569 +    types()->sweep();
  44.570 +}
  44.571 +
  44.572 +String *
  44.573 +Zone::makeSymbol(const char *str, size_t length)
  44.574 +{
  44.575 +    return symbols_->add(str, length);
  44.576 +}
  44.577 +
  44.578 +String *
  44.579 +Zone::makeSymbol(const char *str)
  44.580 +{
  44.581 +    return makeSymbol(str, strlen(str));
  44.582 +}
  44.583 +
  44.584 +bool
  44.585 +Zone::hasPendingException()
  44.586 +{
  44.587 +    return hasPendingException_;
  44.588 +}
  44.589 +
  44.590 +void
  44.591 +Zone::reportOutOfMemory()
  44.592 +{
  44.593 +    
  44.594 +}
  44.595 +
  44.596 +void
  44.597 +Zone::reportError(Message message, ...)
  44.598 +{
  44.599 +    va_list ap;
  44.600 +    va_start(ap, message);
  44.601 +    reportErrorVA(message, ap);
  44.602 +    va_end(ap);
  44.603 +}
  44.604 +
  44.605 +#if defined(_MSC_VER)
  44.606 +# define VA_COPY(to, from)  to = from
  44.607 +#else
  44.608 +# define VA_COPY(to, from)  va_copy(to, from)
  44.609 +#endif
  44.610 +
  44.611 +char *
  44.612 +ke::BuildErrorMessage(const char *format, va_list ap)
  44.613 +{
  44.614 +    va_list use;
  44.615 +    VA_COPY(use, ap);
  44.616 +
  44.617 +    // We over-allocate and zero terminate ahead of time, since LIBCRT's
  44.618 +    // version of vsnprintf is screwy.
  44.619 +    size_t size = 255;
  44.620 +    char *buffer = (char *)calloc(size + 1, 1);
  44.621 +    if (!buffer)
  44.622 +        return NULL;
  44.623 +
  44.624 +    for (;;) {
  44.625 +        int r = vsnprintf(buffer, size, format, use);
  44.626 +
  44.627 +        if (r > -1 && size_t(r) < size)
  44.628 +            return buffer;
  44.629 +       
  44.630 +#if defined(_MSC_VER)
  44.631 +        if (r < 0)
  44.632 +            size *= 2;
  44.633 +#else
  44.634 +        if (r > -1)
  44.635 +            size = size_t(r) + 1;
  44.636 +        else
  44.637 +            size *= 2;
  44.638 +#endif
  44.639 +
  44.640 +        free(buffer);
  44.641 +        if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
  44.642 +            return NULL;
  44.643 +
  44.644 +        VA_COPY(use, ap);
  44.645 +    }
  44.646 +}
  44.647 +
  44.648 +void
  44.649 +ke::FreeErrorMessage(const char *message)
  44.650 +{
  44.651 +    free((void *)message);
  44.652 +}
  44.653 +
  44.654 +void
  44.655 +Zone::reportErrorVA(Message message, va_list ap)
  44.656 +{
  44.657 +    char *report = BuildErrorMessage(Messages[message].format, ap);
  44.658 +    if (!report) {
  44.659 +        reportOutOfMemory();
  44.660 +        return;
  44.661 +    }
  44.662 +
  44.663 +    if (reporter_) {
  44.664 +        // Reporters can re-enter. When we start having actual exception
  44.665 +        // objects that can be caught and inspected, this code will have to
  44.666 +        // save and restore the exception state.
  44.667 +        reporter_->onUncaughtException(report);
  44.668 +    }
  44.669 +
  44.670 +    hasPendingException_ = true;
  44.671 +
  44.672 +    FreeErrorMessage(report);
  44.673 +}
  44.674 +
  44.675 +void
  44.676 +Zone::installErrorReporter(Ke::IMessageReporter *reporter)
  44.677 +{
  44.678 +    reporter_ = reporter;
  44.679 +}
  44.680 +
  44.681 +void
  44.682 +ZoneAllocatorPolicy::reportOutOfMemory()
  44.683 +{
  44.684 +    ZONE()->reportOutOfMemory();
  44.685 +}
  44.686 +
  44.687 +void
  44.688 +ZoneAllocatorPolicy::reportAllocationOverflow()
  44.689 +{
  44.690 +    ZONE()->reportAllocationOverflow();
  44.691 +}
  44.692 +
  44.693 +void
  44.694 +Zone::reportAllocationOverflow()
  44.695 +{
  44.696 +    reportError(Message_AllocationOverflow);
  44.697 +}
  44.698 +
  44.699 +void
  44.700 +Zone::clearPendingException()
  44.701 +{
  44.702 +    hasPendingException_ = false;
  44.703 +}
  44.704 +
  44.705 +void
  44.706 +Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener)
  44.707 +{
  44.708 +    publicFunctionListener_ = listener;
  44.709 +}
  44.710 +
  44.711 +void *
  44.712 +Zone::malloc(size_t size)
  44.713 +{
  44.714 +    void *ptr = ::malloc(size);
  44.715 +    if (!ptr)
  44.716 +        reportOutOfMemory();
  44.717 +    return ptr;
  44.718 +}
  44.719 +
  44.720 +void *
  44.721 +Zone::realloc(void *ptr, size_t size)
  44.722 +{
  44.723 +    ptr = ::realloc(ptr, size);
  44.724 +    if (!ptr)
  44.725 +        reportOutOfMemory();
  44.726 +    return ptr;
  44.727 +}
  44.728 +
  44.729 +AutoRooted::AutoRooted(Zone *zone)
  44.730 +  : zone_(zone),
  44.731 +    prev_(*zone->lastSpecialRoot())
  44.732 +{
  44.733 +    *zone->lastSpecialRoot() = this;
  44.734 +}
  44.735 +
  44.736 +AutoRooted::~AutoRooted()
  44.737 +{
  44.738 +    *zone_->lastSpecialRoot() = prev_;
  44.739 +}
    45.1 --- a/src/Zone.h	Mon Jun 10 00:46:29 2013 +0100
    45.2 +++ b/src/Zone.h	Mon Jun 10 01:04:43 2013 +0100
    45.3 @@ -1,221 +1,221 @@
    45.4 -/* vim: set ts=4 sw=4 tw=99 et:
    45.5 - *
    45.6 - * Copyright (C) 2012 David Anderson
    45.7 - *
    45.8 - * This file is part of SourcePawn.
    45.9 - *
   45.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   45.11 - * the terms of the GNU General Public License as published by the Free
   45.12 - * Software Foundation, either version 3 of the License, or (at your option)
   45.13 - * any later version.
   45.14 - * 
   45.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   45.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   45.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   45.18 - *
   45.19 - * You should have received a copy of the GNU General Public License along with
   45.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   45.21 - */
   45.22 -#ifndef _include_jitcraft_thread_h_
   45.23 -#define _include_jitcraft_thread_h_
   45.24 -
   45.25 -#include <stdarg.h>
   45.26 -#include "PoolAllocator.h"
   45.27 -#include "Stack.h"
   45.28 -#include "Heap.h"
   45.29 -#include "Barriers.h"
   45.30 -#include "Handles.h"
   45.31 -#include "Messages.h"
   45.32 -#include "RootScopes.h"
   45.33 -#include "VirtualObjectVisitor.h"
   45.34 -
   45.35 -namespace ke {
   45.36 -
   45.37 -class TypeManager;
   45.38 -class String;
   45.39 -class StringPool;
   45.40 -class GlobalRoots;
   45.41 -class ArrayMap;
   45.42 -class Exception;
   45.43 -class NativeTable;
   45.44 -class PackageCache;
   45.45 -
   45.46 -class Zone
   45.47 -{
   45.48 -    PoolAllocator pool_;
   45.49 -    Stack stack_;
   45.50 -    Heap heap_;
   45.51 -
   45.52 -    // Map cache.
   45.53 -    Unbarriered<Map> maps_[MapKinds_Total];
   45.54 -    Unbarriered<ArrayMap> externalGenericArrayMap_;
   45.55 -    Unbarriered<ArrayMap> externalCharArrayMap_;
   45.56 -
   45.57 -    TypeManager *types_;
   45.58 -    StringPool *symbols_;
   45.59 -    GlobalRoots *globalRoots_;
   45.60 -    NativeTable *nativeTable_;
   45.61 -    PackageCache *packages_;
   45.62 -
   45.63 -    // Root list.
   45.64 -    Local<Object> *lastLocalRoot_;
   45.65 -    RootScopeManager rootScopes_;
   45.66 -    AutoRooted *specialRoots_;
   45.67 -
   45.68 -    // Exception stuff.
   45.69 -    bool hasPendingException_;
   45.70 -    Ke::IMessageReporter *reporter_;
   45.71 -
   45.72 -    Ke::IPublicFunctionListener *publicFunctionListener_;
   45.73 -
   45.74 -  private:
   45.75 -    Zone *thisFromCtor() {
   45.76 -        return this;
   45.77 -    }
   45.78 -
   45.79 -  public:
   45.80 -    Zone();
   45.81 -    ~Zone();
   45.82 -    bool initialize();
   45.83 -
   45.84 -    PoolAllocator &pool() {
   45.85 -        return pool_;
   45.86 -    }
   45.87 -    Stack &stack() {
   45.88 -        return stack_;
   45.89 -    }
   45.90 -    Heap &heap() {
   45.91 -        return heap_;
   45.92 -    }
   45.93 -    Object *allocate(MapKind kind, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
   45.94 -        assert(maps_[kind]);
   45.95 -        Local<Map> map(this, maps_[kind]);
   45.96 -        return allocate(map, bytes, tenure);
   45.97 -    }
   45.98 -    Object *allocate(Handle<Map> map, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
   45.99 -        return heap_.allocate(map, bytes, tenure);
  45.100 -    }
  45.101 -    Map *getMap(MapKind kind) {
  45.102 -        return maps_[kind];
  45.103 -    }
  45.104 -    Map *allocateMap(MapKind kind, size_t bytes, MapKind parent = MapKind_Meta);
  45.105 -
  45.106 -    ArrayMap *externalGenericArrayMap() {
  45.107 -        return externalGenericArrayMap_;
  45.108 -    }
  45.109 -    ArrayMap *externalCharArrayMap() {
  45.110 -        return externalCharArrayMap_;
  45.111 -    }
  45.112 -
  45.113 -    TypeManager *types() const {
  45.114 -        return types_;
  45.115 -    }
  45.116 -    AutoRooted **lastSpecialRoot() {
  45.117 -        return &specialRoots_;
  45.118 -    }
  45.119 -    Local<Object> **lastLocalRoot() {
  45.120 -        return &lastLocalRoot_;
  45.121 -    }
  45.122 -    Object **makeScopedRoot(Object *ptr) {
  45.123 -        return rootScopes_.make(ptr);
  45.124 -    }
  45.125 -    RootScopeManager &rootScopes() {
  45.126 -        return rootScopes_;
  45.127 -    }
  45.128 -    StringPool *symbols() {
  45.129 -        return symbols_;
  45.130 -    }
  45.131 -    GlobalRoots *globalRoots() {
  45.132 -        return globalRoots_;
  45.133 -    }
  45.134 -    NativeTable *nativeTable() {
  45.135 -        return nativeTable_;
  45.136 -    }
  45.137 -    PackageCache *packages() {
  45.138 -        return packages_;
  45.139 -    }
  45.140 -
  45.141 -    String *makeSymbol(const char *string, size_t length);
  45.142 -    String *makeSymbol(const char *string);
  45.143 -
  45.144 -    void reportOutOfMemory();
  45.145 -    void reportAllocationOverflow();
  45.146 -    void reportError(Message message, ...);
  45.147 -    void reportErrorVA(Message message, va_list ap);
  45.148 -    bool hasPendingException();
  45.149 -    void clearPendingException();
  45.150 -    void installErrorReporter(Ke::IMessageReporter *reporter);
  45.151 -    Ke::IMessageReporter *errorReporter() {
  45.152 -        return reporter_;
  45.153 -    }
  45.154 -
  45.155 -    void accept(VirtualObjectVisitor *visitor);
  45.156 -    void sweepWeakRoots();
  45.157 -
  45.158 -    void setPublicFunctionListener(Ke::IPublicFunctionListener *listener);
  45.159 -    void registerPublic(Handle<Function> fun);
  45.160 -    void unregisterPublic(Handle<Function> fun);
  45.161 -
  45.162 -    // Helpers that report OOM.
  45.163 -    void *malloc(size_t size);
  45.164 -    void *realloc(void *ptr, size_t size);
  45.165 -};
  45.166 -
  45.167 -// In a multi-threaded system, this would be a TLS variable.
  45.168 -// In the interest of simplicity, we are single-threaded for now.
  45.169 -extern Zone *SingleThreadedZone;
  45.170 -
  45.171 -// Exposed for the compiler.
  45.172 -char *BuildErrorMessage(const char *format, va_list ap);
  45.173 -void FreeErrorMessage(const char *message);
  45.174 -
  45.175 -static inline Zone *ZONE()
  45.176 -{
  45.177 -    return SingleThreadedZone;
  45.178 -}
  45.179 -
  45.180 -template <typename T>
  45.181 -Local<T>::Local(Zone *zone, T *thing)
  45.182 -  : zone_(zone),
  45.183 -    thing_(thing),
  45.184 -    prev_(*zone->lastLocalRoot())
  45.185 -{
  45.186 -    *zone->lastLocalRoot() = toRaw();
  45.187 -}
  45.188 -
  45.189 -template <typename T>
  45.190 -
  45.191 -Local<T>::~Local()
  45.192 -{
  45.193 -    assert(*zone_->lastLocalRoot() == toRaw());
  45.194 -    *zone_->lastLocalRoot() = prev_;
  45.195 -}
  45.196 -
  45.197 -template <typename T>
  45.198 -ScopedRoot<T>::ScopedRoot()
  45.199 -  : thingp_(make(NULL))
  45.200 -{
  45.201 -}
  45.202 -
  45.203 -template <typename T>
  45.204 -ScopedRoot<T>::ScopedRoot(T *thing)
  45.205 -  : thingp_(make(thing))
  45.206 -{
  45.207 -    // Type check that T is an Object.
  45.208 -    (void)static_cast<Object *>(thing);
  45.209 -}
  45.210 -
  45.211 -template <typename T> T **
  45.212 -ScopedRoot<T>::make(T *other)
  45.213 -{
  45.214 -    return reinterpret_cast<T **>(ZONE()->makeScopedRoot(other));
  45.215 -}
  45.216 -
  45.217 -RootScope::RootScope(Zone *zone)
  45.218 -  : Ke::HandleScope(zone, zone->rootScopes().position(), *zone->rootScopes().scope())
  45.219 -{
  45.220 -}
  45.221 -
  45.222 -}
  45.223 -
  45.224 -#endif // _include_jitcraft_thread_h_
  45.225 +/* vim: set ts=4 sw=4 tw=99 et:
  45.226 + *
  45.227 + * Copyright (C) 2012 David Anderson
  45.228 + *
  45.229 + * This file is part of SourcePawn.
  45.230 + *
  45.231 + * SourcePawn is free software: you can redistribute it and/or modify it under
  45.232 + * the terms of the GNU General Public License as published by the Free
  45.233 + * Software Foundation, either version 3 of the License, or (at your option)
  45.234 + * any later version.
  45.235 + * 
  45.236 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  45.237 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  45.238 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  45.239 + *
  45.240 + * You should have received a copy of the GNU General Public License along with
  45.241 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  45.242 + */
  45.243 +#ifndef _include_jitcraft_thread_h_
  45.244 +#define _include_jitcraft_thread_h_
  45.245 +
  45.246 +#include <stdarg.h>
  45.247 +#include "PoolAllocator.h"
  45.248 +#include "Stack.h"
  45.249 +#include "Heap.h"
  45.250 +#include "Barriers.h"
  45.251 +#include "Handles.h"
  45.252 +#include "Messages.h"
  45.253 +#include "RootScopes.h"
  45.254 +#include "VirtualObjectVisitor.h"
  45.255 +
  45.256 +namespace ke {
  45.257 +
  45.258 +class TypeManager;
  45.259 +class String;
  45.260 +class StringPool;
  45.261 +class GlobalRoots;
  45.262 +class ArrayMap;
  45.263 +class Exception;
  45.264 +class NativeTable;
  45.265 +class PackageCache;
  45.266 +
  45.267 +class Zone
  45.268 +{
  45.269 +    PoolAllocator pool_;
  45.270 +    Stack stack_;
  45.271 +    Heap heap_;
  45.272 +
  45.273 +    // Map cache.
  45.274 +    Unbarriered<Map> maps_[MapKinds_Total];
  45.275 +    Unbarriered<ArrayMap> externalGenericArrayMap_;
  45.276 +    Unbarriered<ArrayMap> externalCharArrayMap_;
  45.277 +
  45.278 +    TypeManager *types_;
  45.279 +    StringPool *symbols_;
  45.280 +    GlobalRoots *globalRoots_;
  45.281 +    NativeTable *nativeTable_;
  45.282 +    PackageCache *packages_;
  45.283 +
  45.284 +    // Root list.
  45.285 +    Local<Object> *lastLocalRoot_;
  45.286 +    RootScopeManager rootScopes_;
  45.287 +    AutoRooted *specialRoots_;
  45.288 +
  45.289 +    // Exception stuff.
  45.290 +    bool hasPendingException_;
  45.291 +    Ke::IMessageReporter *reporter_;
  45.292 +
  45.293 +    Ke::IPublicFunctionListener *publicFunctionListener_;
  45.294 +
  45.295 +  private:
  45.296 +    Zone *thisFromCtor() {
  45.297 +        return this;
  45.298 +    }
  45.299 +
  45.300 +  public:
  45.301 +    Zone();
  45.302 +    ~Zone();
  45.303 +    bool initialize();
  45.304 +
  45.305 +    PoolAllocator &pool() {
  45.306 +        return pool_;
  45.307 +    }
  45.308 +    Stack &stack() {
  45.309 +        return stack_;
  45.310 +    }
  45.311 +    Heap &heap() {
  45.312 +        return heap_;
  45.313 +    }
  45.314 +    Object *allocate(MapKind kind, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
  45.315 +        assert(maps_[kind]);
  45.316 +        Local<Map> map(this, maps_[kind]);
  45.317 +        return allocate(map, bytes, tenure);
  45.318 +    }
  45.319 +    Object *allocate(Handle<Map> map, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
  45.320 +        return heap_.allocate(map, bytes, tenure);
  45.321 +    }
  45.322 +    Map *getMap(MapKind kind) {
  45.323 +        return maps_[kind];
  45.324 +    }
  45.325 +    Map *allocateMap(MapKind kind, size_t bytes, MapKind parent = MapKind_Meta);
  45.326 +
  45.327 +    ArrayMap *externalGenericArrayMap() {
  45.328 +        return externalGenericArrayMap_;
  45.329 +    }
  45.330 +    ArrayMap *externalCharArrayMap() {
  45.331 +        return externalCharArrayMap_;
  45.332 +    }
  45.333 +
  45.334 +    TypeManager *types() const {
  45.335 +        return types_;
  45.336 +    }
  45.337 +    AutoRooted **lastSpecialRoot() {
  45.338 +        return &specialRoots_;
  45.339 +    }
  45.340 +    Local<Object> **lastLocalRoot() {
  45.341 +        return &lastLocalRoot_;
  45.342 +    }
  45.343 +    Object **makeScopedRoot(Object *ptr) {
  45.344 +        return rootScopes_.make(ptr);
  45.345 +    }
  45.346 +    RootScopeManager &rootScopes() {
  45.347 +        return rootScopes_;
  45.348 +    }
  45.349 +    StringPool *symbols() {
  45.350 +        return symbols_;
  45.351 +    }
  45.352 +    GlobalRoots *globalRoots() {
  45.353 +        return globalRoots_;
  45.354 +    }
  45.355 +    NativeTable *nativeTable() {
  45.356 +        return nativeTable_;
  45.357 +    }
  45.358 +    PackageCache *packages() {
  45.359 +        return packages_;
  45.360 +    }
  45.361 +
  45.362 +    String *makeSymbol(const char *string, size_t length);
  45.363 +    String *makeSymbol(const char *string);
  45.364 +
  45.365 +    void reportOutOfMemory();
  45.366 +    void reportAllocationOverflow();
  45.367 +    void reportError(Message message, ...);
  45.368 +    void reportErrorVA(Message message, va_list ap);
  45.369 +    bool hasPendingException();
  45.370 +    void clearPendingException();
  45.371 +    void installErrorReporter(Ke::IMessageReporter *reporter);
  45.372 +    Ke::IMessageReporter *errorReporter() {
  45.373 +        return reporter_;
  45.374 +    }
  45.375 +
  45.376 +    void accept(VirtualObjectVisitor *visitor);
  45.377 +    void sweepWeakRoots();
  45.378 +
  45.379 +    void setPublicFunctionListener(Ke::IPublicFunctionListener *listener);
  45.380 +    void registerPublic(Handle<Function> fun);
  45.381 +    void unregisterPublic(Handle<Function> fun);
  45.382 +
  45.383 +    // Helpers that report OOM.
  45.384 +    void *malloc(size_t size);
  45.385 +    void *realloc(void *ptr, size_t size);
  45.386 +};
  45.387 +
  45.388 +// In a multi-threaded system, this would be a TLS variable.
  45.389 +// In the interest of simplicity, we are single-threaded for now.
  45.390 +extern Zone *SingleThreadedZone;
  45.391 +
  45.392 +// Exposed for the compiler.
  45.393 +char *BuildErrorMessage(const char *format, va_list ap);
  45.394 +void FreeErrorMessage(const char *message);
  45.395 +
  45.396 +static inline Zone *ZONE()
  45.397 +{
  45.398 +    return SingleThreadedZone;
  45.399 +}
  45.400 +
  45.401 +template <typename T>
  45.402 +Local<T>::Local(Zone *zone, T *thing)
  45.403 +  : zone_(zone),
  45.404 +    thing_(thing),
  45.405 +    prev_(*zone->lastLocalRoot())
  45.406 +{
  45.407 +    *zone->lastLocalRoot() = toRaw();
  45.408 +}
  45.409 +
  45.410 +template <typename T>
  45.411 +
  45.412 +Local<T>::~Local()
  45.413 +{
  45.414 +    assert(*zone_->lastLocalRoot() == toRaw());
  45.415 +    *zone_->lastLocalRoot() = prev_;
  45.416 +}
  45.417 +
  45.418 +template <typename T>
  45.419 +ScopedRoot<T>::ScopedRoot()
  45.420 +  : thingp_(make(NULL))
  45.421 +{
  45.422 +}
  45.423 +
  45.424 +template <typename T>
  45.425 +ScopedRoot<T>::ScopedRoot(T *thing)
  45.426 +  : thingp_(make(thing))
  45.427 +{
  45.428 +    // Type check that T is an Object.
  45.429 +    (void)static_cast<Object *>(thing);
  45.430 +}
  45.431 +
  45.432 +template <typename T> T **
  45.433 +ScopedRoot<T>::make(T *other)
  45.434 +{
  45.435 +    return reinterpret_cast<T **>(ZONE()->makeScopedRoot(other));
  45.436 +}
  45.437 +
  45.438 +RootScope::RootScope(Zone *zone)
  45.439 +  : Ke::HandleScope(zone, zone->rootScopes().position(), *zone->rootScopes().scope())
  45.440 +{
  45.441 +}
  45.442 +
  45.443 +}
  45.444 +
  45.445 +#endif // _include_jitcraft_thread_h_
    46.1 --- a/src/compiler/AST.h	Mon Jun 10 00:46:29 2013 +0100
    46.2 +++ b/src/compiler/AST.h	Mon Jun 10 01:04:43 2013 +0100
    46.3 @@ -1,1169 +1,1169 @@
    46.4 -/* vim: set ts=4 sw=4 tw=99 et:
    46.5 - *
    46.6 - * Copyright (C) 2012 David Anderson
    46.7 - *
    46.8 - * This file is part of SourcePawn.
    46.9 - *
   46.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   46.11 - * the terms of the GNU General Public License as published by the Free
   46.12 - * Software Foundation, either version 3 of the License, or (at your option)
   46.13 - * any later version.
   46.14 - * 
   46.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   46.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   46.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   46.18 - *
   46.19 - * You should have received a copy of the GNU General Public License along with
   46.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   46.21 - */
   46.22 -#ifndef _include_sourcepawn_ast_h_
   46.23 -#define _include_sourcepawn_ast_h_
   46.24 -
   46.25 -#include "../PoolAllocator.h"
   46.26 -#include "../Vector.h"
   46.27 -#include "Token.h"
   46.28 -#include "NameBinding.h"
   46.29 -#include "Symbols.h"
   46.30 -
   46.31 -namespace ke {
   46.32 -
   46.33 -class Scope;
   46.34 -class Importable;
   46.35 -struct PathComponent;
   46.36 -
   46.37 -#define ASTKINDS(_)             \
   46.38 -    _(VariableDeclaration)      \
   46.39 -    _(ForStatement)             \
   46.40 -    _(ReturnStatement)          \
   46.41 -    _(IntegerLiteral)           \
   46.42 -    _(FloatLiteral)             \
   46.43 -    _(StringLiteral)            \
   46.44 -    _(BinaryExpression)         \
   46.45 -    _(BlockStatement)           \
   46.46 -    _(Assignment)               \
   46.47 -    _(NameProxy)                \
   46.48 -    _(ExpressionStatement)      \
   46.49 -    _(FunctionStatement)        \
   46.50 -    _(CallExpression)           \
   46.51 -    _(IfStatement)              \
   46.52 -    _(IndexExpression)          \
   46.53 -    _(FieldExpression)          \
   46.54 -    _(EnumStatement)            \
   46.55 -    _(WhileStatement)           \
   46.56 -    _(BreakStatement)           \
   46.57 -    _(ContinueStatement)        \
   46.58 -    _(FunctionTypeStatement)    \
   46.59 -    _(IncDecExpression)         \
   46.60 -    _(UnaryExpression)          \
   46.61 -    _(TernaryExpression)        \
   46.62 -    _(BooleanLiteral)           \
   46.63 -    _(StructureStatement)       \
   46.64 -    _(SwitchStatement)          \
   46.65 -    _(ArrayLiteral)             \
   46.66 -    _(ImportStatement)
   46.67 -
   46.68 -// Forward declarations.
   46.69 -#define _(name) class name;
   46.70 -ASTKINDS(_)
   46.71 -#undef _
   46.72 -
   46.73 -class AstVisitor;
   46.74 -
   46.75 -// Interface for AST nodes.
   46.76 -class AstNode : public PoolObject
   46.77 -{
   46.78 -    SourcePosition pos_;
   46.79 -
   46.80 -  public:
   46.81 -    enum Kind {
   46.82 -#       define _(name) k##name,
   46.83 -        ASTKINDS(_)
   46.84 -#       undef _
   46.85 -        AstKind_Invalid
   46.86 -    };
   46.87 -
   46.88 -    AstNode(const SourcePosition &pos)
   46.89 -      : pos_(pos)
   46.90 -    {
   46.91 -    }
   46.92 -    
   46.93 -    virtual Kind kind() const = 0;
   46.94 -
   46.95 -#define _(name)     bool is##name() { return kind() == k##name; }                   \
   46.96 -                    name *to##name() { assert(is##name()); return (name *)this; }   \
   46.97 -                    name *as##name() { if (!is##name()) return NULL; return to##name(); }
   46.98 -    ASTKINDS(_)
   46.99 -#undef _
  46.100 -
  46.101 -    virtual void accept(AstVisitor *visitor) = 0;
  46.102 -
  46.103 -    const SourcePosition &pos() const {
  46.104 -        return pos_;
  46.105 -    }
  46.106 -};
  46.107 -
  46.108 -#define DECLARE_NODE(type)                      \
  46.109 -    Kind kind() const {                         \
  46.110 -        return k##type;                         \
  46.111 -    }                                           \
  46.112 -    void accept(AstVisitor *visitor) {          \
  46.113 -        visitor->visit##type(this);             \
  46.114 -    }
  46.115 -
  46.116 -class AstVisitor
  46.117 -{
  46.118 -  public:
  46.119 -#define _(name) virtual void visit##name(name *node) { assert(false); }
  46.120 -    ASTKINDS(_)
  46.121 -#undef _
  46.122 -};
  46.123 -
  46.124 -class Statement : public AstNode
  46.125 -{
  46.126 -  public:
  46.127 -    Statement(const SourcePosition &pos)
  46.128 -      : AstNode(pos)
  46.129 -    {
  46.130 -    }
  46.131 -};
  46.132 -
  46.133 -class Expression : public AstNode
  46.134 -{
  46.135 -  public:
  46.136 -    Expression(const SourcePosition &pos)
  46.137 -      : AstNode(pos)
  46.138 -    {
  46.139 -    }
  46.140 -};
  46.141 -
  46.142 -typedef PoolList<Statement *> StatementList;
  46.143 -typedef PoolList<Expression *> ExpressionList;
  46.144 -
  46.145 -class VariableDeclaration : public Statement
  46.146 -{
  46.147 -    TypeQualifiers qual_;
  46.148 -    ScopedRoot<String> name_;
  46.149 -    Expression *initialization_;
  46.150 -    ExpressionList *dims_;
  46.151 -    Expression *type_;
  46.152 -    VariableSymbol *sym_;
  46.153 -
  46.154 -  public:
  46.155 -    VariableDeclaration(const SourcePosition &pos, TypeQualifiers qual, Handle<String> name,
  46.156 -                        Expression *type, ExpressionList *dims, Expression *initialization)
  46.157 -      : Statement(pos),
  46.158 -        qual_(qual),
  46.159 -        name_(name),
  46.160 -        initialization_(initialization),
  46.161 -        dims_(dims),
  46.162 -        type_(type),
  46.163 -        sym_(NULL)
  46.164 -    {
  46.165 -    }
  46.166 -
  46.167 -    DECLARE_NODE(VariableDeclaration);
  46.168 -
  46.169 -    Expression *initialization() const {
  46.170 -        return initialization_;
  46.171 -    }
  46.172 -    Handle<String> name() {
  46.173 -        return name_;
  46.174 -    }
  46.175 -    Expression *declType() const {
  46.176 -        return type_;
  46.177 -    }
  46.178 -    void setSymbol(VariableSymbol *sym) {
  46.179 -        assert(!sym_);
  46.180 -        sym_ = sym;
  46.181 -    }
  46.182 -    VariableSymbol *sym() const {
  46.183 -        return sym_;
  46.184 -    }
  46.185 -    Expression *type() const {
  46.186 -        return type_;
  46.187 -    }
  46.188 -    ExpressionList *dims() const {
  46.189 -        return dims_;
  46.190 -    }
  46.191 -    TypeQualifiers quals() const {
  46.192 -        return qual_;
  46.193 -    }
  46.194 -};
  46.195 -
  46.196 -class Parameter : public PoolObject
  46.197 -{
  46.198 -    ScopedRoot<String> name_;
  46.199 -    Expression *type_;
  46.200 -    bool reference_;
  46.201 -    Expression *initializer_;
  46.202 -    VariableSymbol *sym_;
  46.203 -    SourcePosition pos_;
  46.204 -    ExpressionList *dims_;
  46.205 -    TypeQualifiers quals_;
  46.206 -
  46.207 -  public:
  46.208 -    Parameter(Handle<String> name, Expression *type, bool reference, TypeQualifiers quals,
  46.209 -              ExpressionList *dims, Expression *initializer, const SourcePosition &pos)
  46.210 -      : name_(name),
  46.211 -        type_(type),
  46.212 -        reference_(reference),
  46.213 -        initializer_(initializer),
  46.214 -        sym_(NULL),
  46.215 -        pos_(pos),
  46.216 -        dims_(dims),
  46.217 -        quals_(quals)
  46.218 -    {
  46.219 -    }
  46.220 -
  46.221 -    Expression *type() const {
  46.222 -        return type_;
  46.223 -    }
  46.224 -    Handle<String> name() const {
  46.225 -        return name_;
  46.226 -    }
  46.227 -    bool reference() const {
  46.228 -        return reference_;
  46.229 -    }
  46.230 -    TypeQualifiers quals() const {
  46.231 -        return quals_;
  46.232 -    }
  46.233 -    ExpressionList *dims() const {
  46.234 -        return dims_;
  46.235 -    }
  46.236 -    Expression *initializer() const {
  46.237 -        return initializer_;
  46.238 -    }
  46.239 -    void setSymbol(VariableSymbol *sym) {
  46.240 -        assert(!sym_);
  46.241 -        sym_ = sym;
  46.242 -    }
  46.243 -    VariableSymbol *sym() const {
  46.244 -        return sym_;
  46.245 -    }
  46.246 -    const SourcePosition &pos() const {
  46.247 -        return pos_;
  46.248 -    }
  46.249 -};
  46.250 -
  46.251 -class NameProxy : public Expression
  46.252 -{
  46.253 -    ScopedRoot<String> name_;
  46.254 -    Symbol *binding_;
  46.255 -
  46.256 -  public:
  46.257 -    NameProxy(const SourcePosition &pos, Handle<String> name)
  46.258 -      : Expression(pos),
  46.259 -        name_(name),
  46.260 -        binding_(NULL)
  46.261 -    {
  46.262 -    }
  46.263 -
  46.264 -    DECLARE_NODE(NameProxy);
  46.265 -    
  46.266 -    Handle<String> name() const {
  46.267 -        return name_;
  46.268 -    }
  46.269 -    Symbol *sym() const {
  46.270 -        return binding_;
  46.271 -    }
  46.272 -    void bind(Symbol *sym) {
  46.273 -        binding_ = sym;
  46.274 -    }
  46.275 -};
  46.276 -
  46.277 -class BooleanLiteral : public Expression
  46.278 -{
  46.279 -    TokenKind token_;
  46.280 -
  46.281 -  public:
  46.282 -    BooleanLiteral(const SourcePosition &pos, TokenKind token)
  46.283 -      : Expression(pos),
  46.284 -        token_(token)
  46.285 -    {
  46.286 -    }
  46.287 -
  46.288 -    DECLARE_NODE(BooleanLiteral);
  46.289 -    TokenKind token() const {
  46.290 -        return token_;
  46.291 -    }
  46.292 -};
  46.293 -
  46.294 -class IntegerLiteral : public Expression
  46.295 -{
  46.296 -    int value_;
  46.297 -
  46.298 -  public:
  46.299 -    IntegerLiteral(const SourcePosition &pos, int value)
  46.300 -      : Expression(pos),
  46.301 -        value_(value)
  46.302 -    {
  46.303 -    }
  46.304 -
  46.305 -    DECLARE_NODE(IntegerLiteral);
  46.306 -
  46.307 -    int value() const {
  46.308 -        return value_;
  46.309 -    }
  46.310 -};
  46.311 -
  46.312 -class FloatLiteral : public Expression
  46.313 -{
  46.314 -    double value_;
  46.315 -
  46.316 -  public:
  46.317 -    FloatLiteral(const SourcePosition &pos, double value)
  46.318 -      : Expression(pos),
  46.319 -        value_(value)
  46.320 -    {
  46.321 -    }
  46.322 -
  46.323 -    DECLARE_NODE(FloatLiteral);
  46.324 -
  46.325 -    double value() const {
  46.326 -        return value_;
  46.327 -    }
  46.328 -};
  46.329 -
  46.330 -class StringLiteral : public Expression
  46.331 -{
  46.332 -    ScopedRoot<String> string_;
  46.333 -
  46.334 -  public:
  46.335 -    StringLiteral(const SourcePosition &pos, String *string)
  46.336 -      : Expression(pos),
  46.337 -        string_(string)
  46.338 -    {
  46.339 -    }
  46.340 -
  46.341 -    DECLARE_NODE(StringLiteral);
  46.342 -
  46.343 -    String *string() const {
  46.344 -        return string_;
  46.345 -    }
  46.346 -};
  46.347 -
  46.348 -class ArrayLiteral : public Expression
  46.349 -{
  46.350 -    TokenKind token_;
  46.351 -    ExpressionList *expressions_;
  46.352 -
  46.353 -  public:
  46.354 -    ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
  46.355 -      : Expression(pos),
  46.356 -        token_(token),
  46.357 -        expressions_(expressions)
  46.358 -    {
  46.359 -    }
  46.360 -
  46.361 -    DECLARE_NODE(ArrayLiteral);
  46.362 -
  46.363 -    TokenKind token() const {
  46.364 -        return token_;
  46.365 -    }
  46.366 -    ExpressionList *expressions() const {
  46.367 -        return expressions_;
  46.368 -    }
  46.369 -    bool isFixed() const {
  46.370 -        return token_ == TOK_LBRACE;
  46.371 -    }
  46.372 -};
  46.373 -
  46.374 -class UnaryExpression : public Expression
  46.375 -{
  46.376 -    Expression *expression_;
  46.377 -    TokenKind token_;
  46.378 -    NameProxy *tag_;
  46.379 -
  46.380 -  public:
  46.381 -    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
  46.382 -      : Expression(pos),
  46.383 -        expression_(expr),
  46.384 -        token_(token),
  46.385 -        tag_(NULL)
  46.386 -    {
  46.387 -    }
  46.388 -
  46.389 -    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr,
  46.390 -                    NameProxy *tag)
  46.391 -      : Expression(pos),
  46.392 -        expression_(expr),
  46.393 -        token_(token),
  46.394 -        tag_(tag)
  46.395 -    {
  46.396 -    }
  46.397 -
  46.398 -    DECLARE_NODE(UnaryExpression);
  46.399 -
  46.400 -    Expression *expression() const {
  46.401 -        return expression_;
  46.402 -    }
  46.403 -    TokenKind token() const {
  46.404 -        return token_;
  46.405 -    }
  46.406 -    NameProxy *tag() const {
  46.407 -        return tag_;
  46.408 -    }
  46.409 -};
  46.410 -
  46.411 -class BinaryExpression : public Expression
  46.412 -{
  46.413 -    Expression *left_;
  46.414 -    Expression *right_;
  46.415 -    TokenKind token_;
  46.416 -
  46.417 -  public:
  46.418 -    BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
  46.419 -      : Expression(pos),
  46.420 -        left_(left),
  46.421 -        right_(right),
  46.422 -        token_(token)
  46.423 -    {
  46.424 -    }
  46.425 -
  46.426 -    DECLARE_NODE(BinaryExpression);
  46.427 -
  46.428 -    Expression *left() const {
  46.429 -        return left_;
  46.430 -    }
  46.431 -    Expression *right() const {
  46.432 -        return right_;
  46.433 -    }
  46.434 -    TokenKind token() const {
  46.435 -        return token_;
  46.436 -    }
  46.437 -};
  46.438 -
  46.439 -class TernaryExpression : public Expression
  46.440 -{
  46.441 -    Expression *condition_;
  46.442 -    Expression *left_;
  46.443 -    Expression *right_;
  46.444 -
  46.445 -  public:
  46.446 -    TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
  46.447 -      : Expression(pos),
  46.448 -        condition_(condition),
  46.449 -        left_(left),
  46.450 -        right_(right)
  46.451 -    {
  46.452 -    }
  46.453 -
  46.454 -    DECLARE_NODE(TernaryExpression);
  46.455 -
  46.456 -    Expression *condition() const {
  46.457 -        return condition_;
  46.458 -    }
  46.459 -    Expression *left() const {
  46.460 -        return left_;
  46.461 -    }
  46.462 -    Expression *right() const {
  46.463 -        return right_;
  46.464 -    }
  46.465 -};
  46.466 -
  46.467 -class IndexExpression : public Expression
  46.468 -{
  46.469 -    Expression *left_;
  46.470 -    Expression *right_;
  46.471 -
  46.472 -  public:
  46.473 -    IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
  46.474 -      : Expression(pos),
  46.475 -        left_(left),
  46.476 -        right_(right)
  46.477 -    {
  46.478 -    }
  46.479 -
  46.480 -    DECLARE_NODE(IndexExpression);
  46.481 -
  46.482 -    Expression *left() const {
  46.483 -        return left_;
  46.484 -    }
  46.485 -    Expression *right() const {
  46.486 -        return right_;
  46.487 -    }
  46.488 -};
  46.489 -
  46.490 -class FieldExpression : public Expression
  46.491 -{
  46.492 -    Expression *left_;
  46.493 -    ScopedRoot<String> field_;
  46.494 -
  46.495 -  public:
  46.496 -    FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
  46.497 -      : Expression(pos),
  46.498 -        left_(left),
  46.499 -        field_(field)
  46.500 -    {
  46.501 -    }
  46.502 -
  46.503 -    DECLARE_NODE(FieldExpression);
  46.504 -
  46.505 -    Expression *left() const {
  46.506 -        return left_;
  46.507 -    }
  46.508 -    Handle<String> field() const {
  46.509 -        return field_;
  46.510 -    }
  46.511 -};
  46.512 -
  46.513 -class CallExpression : public Expression
  46.514 -{
  46.515 -    Expression *callee_;
  46.516 -    ExpressionList *arguments_;
  46.517 -
  46.518 -  public:
  46.519 -    CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
  46.520 -      : Expression(pos),
  46.521 -        callee_(callee),
  46.522 -        arguments_(arguments)
  46.523 -    {
  46.524 -    }
  46.525 -
  46.526 -    DECLARE_NODE(CallExpression);
  46.527 -
  46.528 -    Expression *callee() const {
  46.529 -        return callee_;
  46.530 -    }
  46.531 -    ExpressionList *arguments() const {
  46.532 -        return arguments_;
  46.533 -    }
  46.534 -};
  46.535 -
  46.536 -class ForStatement : public Statement
  46.537 -{
  46.538 -    Statement *initialization_;
  46.539 -    Expression *condition_;
  46.540 -    Statement *update_;
  46.541 -    Statement *body_;
  46.542 -    Scope *scope_;
  46.543 -
  46.544 -  public:
  46.545 -    ForStatement(const SourcePosition &pos, Statement *initialization,
  46.546 -                 Expression *condition, Statement *update, Statement *body)
  46.547 -      : Statement(pos),
  46.548 -        initialization_(initialization),
  46.549 -        condition_(condition),
  46.550 -        update_(update),
  46.551 -        body_(body),
  46.552 -        scope_(NULL)
  46.553 -    {
  46.554 -    }
  46.555 -
  46.556 -    DECLARE_NODE(ForStatement);
  46.557 -
  46.558 -    Statement *initialization() const {
  46.559 -        return initialization_;
  46.560 -    }
  46.561 -    Expression *condition() const {
  46.562 -        return condition_;
  46.563 -    }
  46.564 -    Statement *update() const {
  46.565 -        return update_;
  46.566 -    }
  46.567 -    Statement *body() const {
  46.568 -        return body_;
  46.569 -    }
  46.570 -    Scope *scope() const {
  46.571 -        return scope_;
  46.572 -    }
  46.573 -    void setScope(Scope *scope) {
  46.574 -        scope_ = scope;
  46.575 -    }
  46.576 -};
  46.577 -
  46.578 -class WhileStatement : public Statement
  46.579 -{
  46.580 -    TokenKind token_;
  46.581 -    Expression *condition_;
  46.582 -    Statement *body_;
  46.583 -
  46.584 -  public:
  46.585 -    WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
  46.586 -      : Statement(pos),
  46.587 -        token_(kind),
  46.588 -        condition_(condition),
  46.589 -        body_(body)
  46.590 -    {
  46.591 -    }
  46.592 -    
  46.593 -    DECLARE_NODE(WhileStatement);
  46.594 -
  46.595 -    TokenKind token() const {
  46.596 -        return token_;
  46.597 -    }
  46.598 -    Expression *condition() const {
  46.599 -        return condition_;
  46.600 -    }
  46.601 -    Statement *body() const {
  46.602 -        return body_;
  46.603 -    }
  46.604 -};
  46.605 -
  46.606 -class ReturnStatement : public Statement
  46.607 -{
  46.608 -    Expression *expression_;
  46.609 -
  46.610 -  public:
  46.611 -    ReturnStatement(const SourcePosition &pos, Expression *expression)
  46.612 -      : Statement(pos),
  46.613 -        expression_(expression)
  46.614 -    {
  46.615 -    }
  46.616 -
  46.617 -    DECLARE_NODE(ReturnStatement);
  46.618 -
  46.619 -    Expression *expression() const {
  46.620 -        return expression_;
  46.621 -    }
  46.622 -};
  46.623 -
  46.624 -class BreakStatement : public Statement
  46.625 -{
  46.626 -  public:
  46.627 -    BreakStatement(const SourcePosition &pos)
  46.628 -      : Statement(pos)
  46.629 -    {
  46.630 -    }
  46.631 -
  46.632 -    DECLARE_NODE(BreakStatement);
  46.633 -};
  46.634 -
  46.635 -class ContinueStatement : public Statement
  46.636 -{
  46.637 -  public:
  46.638 -    ContinueStatement(const SourcePosition &pos)
  46.639 -      : Statement(pos)
  46.640 -    {
  46.641 -    }
  46.642 -
  46.643 -    DECLARE_NODE(ContinueStatement);
  46.644 -};
  46.645 -
  46.646 -class Assignment : public Expression
  46.647 -{
  46.648 -    TokenKind token_;
  46.649 -    Expression *lvalue_;
  46.650 -    Expression *expression_;
  46.651 -
  46.652 -  public:
  46.653 -    Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
  46.654 -      : Expression(pos),
  46.655 -        token_(token),
  46.656 -        lvalue_(left),
  46.657 -        expression_(right)
  46.658 -    {
  46.659 -    }
  46.660 -
  46.661 -    DECLARE_NODE(Assignment);
  46.662 -
  46.663 -    TokenKind token() const {
  46.664 -        return token_;
  46.665 -    }
  46.666 -    Expression *lvalue() const {
  46.667 -        return lvalue_;
  46.668 -    }
  46.669 -    Expression *expression() const {
  46.670 -        return expression_;
  46.671 -    }
  46.672 -};
  46.673 -
  46.674 -class ExpressionStatement : public Statement
  46.675 -{
  46.676 -    Expression *expression_;
  46.677 -
  46.678 -  public:
  46.679 -    ExpressionStatement(Expression *expression)
  46.680 -      : Statement(expression->pos()),
  46.681 -        expression_(expression)
  46.682 -    {
  46.683 -    }
  46.684 -
  46.685 -    DECLARE_NODE(ExpressionStatement);
  46.686 -
  46.687 -    Expression *expression() const {
  46.688 -        return expression_;
  46.689 -    }
  46.690 -};
  46.691 -
  46.692 -class BlockStatement : public Statement
  46.693 -{
  46.694 -    StatementList *statements_;
  46.695 -    Scope *scope_;
  46.696 -    TokenKind type_;
  46.697 -
  46.698 -  public:
  46.699 -    BlockStatement(const SourcePosition &pos, StatementList *statements, TokenKind kind)
  46.700 -      : Statement(pos),
  46.701 -        statements_(statements),
  46.702 -        scope_(NULL),
  46.703 -        type_(kind)
  46.704 -    {
  46.705 -    }
  46.706 -
  46.707 -    DECLARE_NODE(BlockStatement);
  46.708 -
  46.709 -    StatementList *statements() const {
  46.710 -        return statements_;
  46.711 -    }
  46.712 -    Scope *scope() const {
  46.713 -        return scope_;
  46.714 -    }
  46.715 -    void setScope(Scope *scope) {
  46.716 -        scope_ = scope;
  46.717 -    }
  46.718 -    TokenKind type() const {
  46.719 -        return type_;
  46.720 -    }
  46.721 -};
  46.722 -
  46.723 -typedef PoolList<Parameter *> ParameterList;
  46.724 -
  46.725 -class FunctionSignature
  46.726 -{
  46.727 -  public:
  46.728 -    FunctionSignature(Expression *returnType, ParameterList *parameters, bool variadic)
  46.729 -      : returnType_(returnType),
  46.730 -        parameters_(parameters),
  46.731 -        variadic_(variadic)
  46.732 -    {
  46.733 -    }
  46.734 -
  46.735 -    Expression *returnType() const {
  46.736 -        return returnType_;
  46.737 -    }
  46.738 -    ParameterList *parameters() const {
  46.739 -        return parameters_;
  46.740 -    }
  46.741 -    bool variadic() const {
  46.742 -        return variadic_;
  46.743 -    }
  46.744 -
  46.745 -  private:
  46.746 -    Expression *returnType_;
  46.747 -    ParameterList *parameters_;
  46.748 -    bool variadic_;
  46.749 -};
  46.750 -
  46.751 -class FunctionTypeStatement : public Statement
  46.752 -{
  46.753 -  public:
  46.754 -    FunctionTypeStatement(const SourcePosition &pos, Handle<String> name, const FunctionSignature &signature)
  46.755 -      : Statement(pos),
  46.756 -        name_(name),
  46.757 -        signature_(signature)
  46.758 -    {
  46.759 -    }
  46.760 -
  46.761 -    DECLARE_NODE(FunctionTypeStatement);
  46.762 -
  46.763 -    Handle<String> name() const {
  46.764 -        return name_;
  46.765 -    }
  46.766 -    const FunctionSignature &signature() const {
  46.767 -        return signature_;
  46.768 -    }
  46.769 -
  46.770 -  private:
  46.771 -    ScopedRoot<String> name_;
  46.772 -    FunctionSignature signature_;
  46.773 -    
  46.774 -};
  46.775 -
  46.776 -class FunctionStatement : public Statement
  46.777 -{
  46.778 -    ScopedRoot<String> name_;
  46.779 -    TokenKind kind_;
  46.780 -    Statement *body_;
  46.781 -    FunctionSignature signature_;
  46.782 -    bool explicitReturn_;
  46.783 -    FunctionSymbol *sym_;
  46.784 -    Scope *argScope_;
  46.785 -    Scope *varScope_;
  46.786 -
  46.787 -  public:
  46.788 -    FunctionStatement(const SourcePosition &pos, Handle<String> name, TokenKind kind,
  46.789 -                      Statement *body, const FunctionSignature &signature, bool explicitReturn)
  46.790 -      : Statement(pos),
  46.791 -        name_(name),
  46.792 -        kind_(kind),
  46.793 -        body_(body),
  46.794 -        signature_(signature),
  46.795 -        explicitReturn_(explicitReturn),
  46.796 -        sym_(NULL),
  46.797 -        argScope_(NULL),
  46.798 -        varScope_(NULL)
  46.799 -    {
  46.800 -    }
  46.801 -
  46.802 -    DECLARE_NODE(FunctionStatement);
  46.803 -
  46.804 -    Handle<String> name() const {
  46.805 -        return name_;
  46.806 -    }
  46.807 -    Statement *body() const {
  46.808 -        return body_;
  46.809 -    }
  46.810 -    const FunctionSignature &signature() {
  46.811 -        return signature_;
  46.812 -    }
  46.813 -    bool hasExplicitReturn() const {
  46.814 -        return explicitReturn_;
  46.815 -    }
  46.816 -    TokenKind token() const {
  46.817 -        return kind_;
  46.818 -    }
  46.819 -    void setSymbol(FunctionSymbol *sym) {
  46.820 -        assert(!sym_);
  46.821 -        sym_ = sym;
  46.822 -    }
  46.823 -    FunctionSymbol *sym() const {
  46.824 -        return sym_;
  46.825 -    }
  46.826 -    void setScopes(Scope *argScope, Scope *varScope) {
  46.827 -        argScope_ = argScope;
  46.828 -        varScope_ = varScope;
  46.829 -    }
  46.830 -    Scope *argScope() const {
  46.831 -        return argScope_;
  46.832 -    }
  46.833 -    Scope *varScope() const {
  46.834 -        return varScope_;
  46.835 -    }
  46.836 -};
  46.837 -
  46.838 -class IfStatement : public Statement
  46.839 -{
  46.840 -    Expression *condition_;
  46.841 -    Statement *ifTrue_;
  46.842 -    Statement *ifFalse_;
  46.843 -
  46.844 -  public:
  46.845 -    IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
  46.846 -      : Statement(pos),
  46.847 -        condition_(condition),
  46.848 -        ifTrue_(ifTrue),
  46.849 -        ifFalse_(NULL)
  46.850 -    {
  46.851 -    }
  46.852 -
  46.853 -    DECLARE_NODE(IfStatement);
  46.854 -
  46.855 -    Expression *condition() const {
  46.856 -        return condition_;
  46.857 -    }
  46.858 -    Statement *ifTrue() const {
  46.859 -        return ifTrue_;
  46.860 -    }
  46.861 -    Statement *ifFalse() const {
  46.862 -        return ifFalse_;
  46.863 -    }
  46.864 -    void setIfFalse(Statement *ifFalse) {
  46.865 -        ifFalse_ = ifFalse;
  46.866 -    }
  46.867 -};
  46.868 -
  46.869 -class EnumStatement : public Statement
  46.870 -{
  46.871 -    ScopedRoot<String> name_;
  46.872 -    TypeSymbol *sym_;
  46.873 -
  46.874 -  public:
  46.875 -    struct Entry {
  46.876 -        ScopedRoot<String> name;
  46.877 -        Expression *expr;
  46.878 -        SourcePosition pos;
  46.879 -        ConstantSymbol *sym;
  46.880 -
  46.881 -        Entry(Handle<String> name, Expression *expr, const SourcePosition &pos)
  46.882 -          : name(name),
  46.883 -            expr(expr),
  46.884 -            pos(pos),
  46.885 -            sym(NULL)
  46.886 -        {
  46.887 -        }
  46.888 -    };
  46.889 -
  46.890 -    typedef PoolList<Entry> EntryList;
  46.891 -
  46.892 -  public:
  46.893 -    EnumStatement(const SourcePosition &pos, TokenKind visibility, Handle<String> name, EntryList *entries)
  46.894 -      : Statement(pos),
  46.895 -        name_(name),
  46.896 -        sym_(NULL),
  46.897 -        entries_(entries),
  46.898 -        visibility_(visibility)
  46.899 -    {
  46.900 -    }
  46.901 -
  46.902 -    DECLARE_NODE(EnumStatement);
  46.903 -
  46.904 -    Handle<String> name() const {
  46.905 -        return name_;
  46.906 -    }
  46.907 -    EntryList *entries() const {
  46.908 -        return entries_;
  46.909 -    }
  46.910 -    void setSymbol(TypeSymbol *sym) {
  46.911 -        assert(!sym_);
  46.912 -        sym_ = sym;
  46.913 -    }
  46.914 -    TypeSymbol *sym() const {
  46.915 -        return sym_;
  46.916 -    }
  46.917 -    TokenKind visibility() const {
  46.918 -        return visibility_;
  46.919 -    }
  46.920 -
  46.921 -  private:
  46.922 -    EntryList *entries_;
  46.923 -    TokenKind visibility_;
  46.924 -};
  46.925 -
  46.926 -class IncDecExpression : public Expression
  46.927 -{
  46.928 -    TokenKind token_;
  46.929 -    Expression *expression_;
  46.930 -    bool postfix_;
  46.931 -
  46.932 -  public:
  46.933 -    IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
  46.934 -      : Expression(pos),
  46.935 -        token_(token),
  46.936 -        expression_(expression),
  46.937 -        postfix_(postfix)
  46.938 -    {
  46.939 -    }
  46.940 -
  46.941 -    DECLARE_NODE(IncDecExpression);
  46.942 -
  46.943 -    TokenKind token() const {
  46.944 -        return token_;
  46.945 -    }
  46.946 -    Expression *expression() const {
  46.947 -        return expression_;
  46.948 -    }
  46.949 -    bool postfix() const {
  46.950 -        return postfix_;
  46.951 -    }
  46.952 -};
  46.953 -
  46.954 -class Case : public PoolObject
  46.955 -{
  46.956 -  public:
  46.957 -    Case(Expression *expression, ExpressionList *others, Statement *statement)
  46.958 -      : expression_(expression),
  46.959 -        others_(others),
  46.960 -        statement_(statement)
  46.961 -    {
  46.962 -    }
  46.963 -
  46.964 -    Expression *expression() const {
  46.965 -        return expression_;
  46.966 -    }
  46.967 -    PoolList<Expression *> *others() const {
  46.968 -        return others_;
  46.969 -    }
  46.970 -    Statement *statement() const {
  46.971 -        return statement_;
  46.972 -    }
  46.973 -
  46.974 -  private:
  46.975 -    Expression *expression_;
  46.976 -    PoolList <Expression *> *others_;
  46.977 -    Statement *statement_;
  46.978 -};
  46.979 -
  46.980 -struct CaseValue
  46.981 -{
  46.982 -    BoxedPrimitive box;
  46.983 -    size_t statement;
  46.984 -
  46.985 -    CaseValue(size_t statement)
  46.986 -      : statement(statement)
  46.987 -    {
  46.988 -    }
  46.989 -};
  46.990 -
  46.991 -typedef PoolList<CaseValue> CaseValueList;
  46.992 -
  46.993 -class SwitchStatement : public Statement
  46.994 -{
  46.995 -  public:
  46.996 -    SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
  46.997 -                    Statement *def)
  46.998 -      : Statement(pos),
  46.999 -        expression_(expression),
 46.1000 -        cases_(cases),
 46.1001 -        default_(def),
 46.1002 -        table_(NULL)
 46.1003 -    {
 46.1004 -    }
 46.1005 -
 46.1006 -    DECLARE_NODE(SwitchStatement);
 46.1007 -
 46.1008 -    Expression *expression() const {
 46.1009 -        return expression_;
 46.1010 -    }
 46.1011 -    PoolList<Case *> *cases() const {
 46.1012 -        return cases_;
 46.1013 -    }
 46.1014 -    Statement *defaultCase() const {
 46.1015 -        return default_;
 46.1016 -    }
 46.1017 -    void setCaseValueList(CaseValueList *list) {
 46.1018 -        table_ = list;
 46.1019 -    }
 46.1020 -    CaseValueList *caseValueList() const {
 46.1021 -        return table_;
 46.1022 -    }
 46.1023 -
 46.1024 -  private:
 46.1025 -    Expression *expression_;
 46.1026 -    PoolList<Case *> *cases_;
 46.1027 -    Statement *default_;
 46.1028 -    CaseValueList *table_;
 46.1029 -};
 46.1030 -
 46.1031 -class StructureStatement : public Statement
 46.1032 -{
 46.1033 -  public:
 46.1034 -    class Field : public PoolObject
 46.1035 -    {
 46.1036 -        SourcePosition pos_;
 46.1037 -        Expression *type_;
 46.1038 -        ScopedRoot<String> name_;
 46.1039 -
 46.1040 -      public:
 46.1041 -        Field(const SourcePosition &pos,
 46.1042 -              Expression *type,
 46.1043 -              Handle<String> name)
 46.1044 -          : pos_(pos),
 46.1045 -            type_(type),
 46.1046 -            name_(name)
 46.1047 -        {
 46.1048 -        }
 46.1049 -
 46.1050 -        const SourcePosition &pos() const {
 46.1051 -            return pos_;
 46.1052 -        }
 46.1053 -        Handle<String> name() const {
 46.1054 -            return name_;
 46.1055 -        }
 46.1056 -        Expression *type() const {
 46.1057 -            return type_;
 46.1058 -        }
 46.1059 -    };
 46.1060 -
 46.1061 -    typedef PoolList<StructureStatement::Field *> FieldList;
 46.1062 -
 46.1063 -  public:
 46.1064 -    StructureStatement(const SourcePosition &pos, Handle<String> name, FieldList *fields)
 46.1065 -      : Statement(pos),
 46.1066 -        name_(name),
 46.1067 -        fields_(fields),
 46.1068 -        sym_(NULL)
 46.1069 -    {
 46.1070 -    }
 46.1071 -
 46.1072 -    DECLARE_NODE(StructureStatement);
 46.1073 -
 46.1074 -    FieldList *fields() const {
 46.1075 -        return fields_;
 46.1076 -    }
 46.1077 -    Handle<String> name() const {
 46.1078 -        return name_;
 46.1079 -    }
 46.1080 -    void setSymbol(TypeSymbol *sym) {
 46.1081 -        assert(!sym_);
 46.1082 -        sym_ = sym;
 46.1083 -    }
 46.1084 -    TypeSymbol *sym() const {
 46.1085 -        return sym_;
 46.1086 -    }
 46.1087 -
 46.1088 -  private:
 46.1089 -    ScopedRoot<String> name_;
 46.1090 -    FieldList *fields_;
 46.1091 -    TypeSymbol *sym_;
 46.1092 -};
 46.1093 -
 46.1094 -typedef PoolList<ScopedRoot<String> *> NameList;
 46.1095 -
 46.1096 -class ImportStatement : public Statement
 46.1097 -{
 46.1098 -  public:
 46.1099 -    ImportStatement(const SourcePosition &pos, PathComponent *path, NameList *names)
 46.1100 -      : Statement(pos),
 46.1101 -        path_(path),
 46.1102 -        names_(names)
 46.1103 -    {
 46.1104 -    }
 46.1105 -
 46.1106 -    DECLARE_NODE(ImportStatement);
 46.1107 -
 46.1108 -    PathComponent *path() const {
 46.1109 -        return path_;
 46.1110 -    }
 46.1111 -    void setSource(Importable *source) {
 46.1112 -        source_ = source;
 46.1113 -    }
 46.1114 -    Handle<Importable> source() {
 46.1115 -        return source_;
 46.1116 -    }
 46.1117 -    unsigned importIndex() const {
 46.1118 -        return importIndex_;
 46.1119 -    }
 46.1120 -    void setImportIndex(unsigned index) {
 46.1121 -        importIndex_ = index;
 46.1122 -    }
 46.1123 -    NameList *names() const {
 46.1124 -        return names_;
 46.1125 -    }
 46.1126 -
 46.1127 -    bool importAllNames() const {
 46.1128 -        return names_ && names_->empty();
 46.1129 -    }
 46.1130 -
 46.1131 -  private:
 46.1132 -    PathComponent *path_;
 46.1133 -    ScopedRoot<Importable> source_;
 46.1134 -    unsigned importIndex_;
 46.1135 -    NameList *names_;
 46.1136 -};
 46.1137 -
 46.1138 -typedef StructureStatement::FieldList FieldList;
 46.1139 -typedef PoolList<NameProxy *> NameProxyList;
 46.1140 -
 46.1141 -#undef DECLARE_NODE
 46.1142 -
 46.1143 -class ParseTree : public PoolObject
 46.1144 -{
 46.1145 -    StatementList *statements_;
 46.1146 -    NameProxyList *unbound_;
 46.1147 -    PoolList<ImportStatement *> *imports_;
 46.1148 -
 46.1149 -  public:
 46.1150 -    ParseTree(StatementList *statements, NameProxyList *unbound, PoolList<ImportStatement *> *imports)
 46.1151 -      : statements_(statements),
 46.1152 -        unbound_(unbound),
 46.1153 -        imports_(imports)
 46.1154 -    {
 46.1155 -    }
 46.1156 -
 46.1157 -    void dump(FILE *fp);
 46.1158 -
 46.1159 -    StatementList *statements() const {
 46.1160 -        return statements_;
 46.1161 -    }
 46.1162 -    NameProxyList *unbound() const {
 46.1163 -        return unbound_;
 46.1164 -    }
 46.1165 -    PoolList<ImportStatement *> *imports() const {
 46.1166 -        return imports_;
 46.1167 -    }
 46.1168 -};
 46.1169 -
 46.1170 -}
 46.1171 -
 46.1172 -#endif // _include_sourcepawn_ast_h_
 46.1173 +/* vim: set ts=4 sw=4 tw=99 et:
 46.1174 + *
 46.1175 + * Copyright (C) 2012 David Anderson
 46.1176 + *
 46.1177 + * This file is part of SourcePawn.
 46.1178 + *
 46.1179 + * SourcePawn is free software: you can redistribute it and/or modify it under
 46.1180 + * the terms of the GNU General Public License as published by the Free
 46.1181 + * Software Foundation, either version 3 of the License, or (at your option)
 46.1182 + * any later version.
 46.1183 + * 
 46.1184 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
 46.1185 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 46.1186 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 46.1187 + *
 46.1188 + * You should have received a copy of the GNU General Public License along with
 46.1189 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
 46.1190 + */
 46.1191 +#ifndef _include_sourcepawn_ast_h_
 46.1192 +#define _include_sourcepawn_ast_h_
 46.1193 +
 46.1194 +#include "../PoolAllocator.h"
 46.1195 +#include "../Vector.h"
 46.1196 +#include "Token.h"
 46.1197 +#include "NameBinding.h"
 46.1198 +#include "Symbols.h"
 46.1199 +
 46.1200 +namespace ke {
 46.1201 +
 46.1202 +class Scope;
 46.1203 +class Importable;
 46.1204 +struct PathComponent;
 46.1205 +
 46.1206 +#define ASTKINDS(_)             \
 46.1207 +    _(VariableDeclaration)      \
 46.1208 +    _(ForStatement)             \
 46.1209 +    _(ReturnStatement)          \
 46.1210 +    _(IntegerLiteral)           \
 46.1211 +    _(FloatLiteral)             \
 46.1212 +    _(StringLiteral)            \
 46.1213 +    _(BinaryExpression)         \
 46.1214 +    _(BlockStatement)           \
 46.1215 +    _(Assignment)               \
 46.1216 +    _(NameProxy)                \
 46.1217 +    _(ExpressionStatement)      \
 46.1218 +    _(FunctionStatement)        \
 46.1219 +    _(CallExpression)           \
 46.1220 +    _(IfStatement)              \
 46.1221 +    _(IndexExpression)          \
 46.1222 +    _(FieldExpression)          \
 46.1223 +    _(EnumStatement)            \
 46.1224 +    _(WhileStatement)           \
 46.1225 +    _(BreakStatement)           \
 46.1226 +    _(ContinueStatement)        \
 46.1227 +    _(FunctionTypeStatement)    \
 46.1228 +    _(IncDecExpression)         \
 46.1229 +    _(UnaryExpression)          \
 46.1230 +    _(TernaryExpression)        \
 46.1231 +    _(BooleanLiteral)           \
 46.1232 +    _(StructureStatement)       \
 46.1233 +    _(SwitchStatement)          \
 46.1234 +    _(ArrayLiteral)             \
 46.1235 +    _(ImportStatement)
 46.1236 +
 46.1237 +// Forward declarations.
 46.1238 +#define _(name) class name;
 46.1239 +ASTKINDS(_)
 46.1240 +#undef _
 46.1241 +
 46.1242 +class AstVisitor;
 46.1243 +
 46.1244 +// Interface for AST nodes.
 46.1245 +class AstNode : public PoolObject
 46.1246 +{
 46.1247 +    SourcePosition pos_;
 46.1248 +
 46.1249 +  public:
 46.1250 +    enum Kind {
 46.1251 +#       define _(name) k##name,
 46.1252 +        ASTKINDS(_)
 46.1253 +#       undef _
 46.1254 +        AstKind_Invalid
 46.1255 +    };
 46.1256 +
 46.1257 +    AstNode(const SourcePosition &pos)
 46.1258 +      : pos_(pos)
 46.1259 +    {
 46.1260 +    }
 46.1261 +    
 46.1262 +    virtual Kind kind() const = 0;
 46.1263 +
 46.1264 +#define _(name)     bool is##name() { return kind() == k##name; }                   \
 46.1265 +                    name *to##name() { assert(is##name()); return (name *)this; }   \
 46.1266 +                    name *as##name() { if (!is##name()) return NULL; return to##name(); }
 46.1267 +    ASTKINDS(_)
 46.1268 +#undef _
 46.1269 +
 46.1270 +    virtual void accept(AstVisitor *visitor) = 0;
 46.1271 +
 46.1272 +    const SourcePosition &pos() const {
 46.1273 +        return pos_;
 46.1274 +    }
 46.1275 +};
 46.1276 +
 46.1277 +#define DECLARE_NODE(type)                      \
 46.1278 +    Kind kind() const {                         \
 46.1279 +        return k##type;                         \
 46.1280 +    }                                           \
 46.1281 +    void accept(AstVisitor *visitor) {          \
 46.1282 +        visitor->visit##type(this);             \
 46.1283 +    }
 46.1284 +
 46.1285 +class AstVisitor
 46.1286 +{
 46.1287 +  public:
 46.1288 +#define _(name) virtual void visit##name(name *node) { assert(false); }
 46.1289 +    ASTKINDS(_)
 46.1290 +#undef _
 46.1291 +};
 46.1292 +
 46.1293 +class Statement : public AstNode
 46.1294 +{
 46.1295 +  public:
 46.1296 +    Statement(const SourcePosition &pos)
 46.1297 +      : AstNode(pos)
 46.1298 +    {
 46.1299 +    }
 46.1300 +};
 46.1301 +
 46.1302 +class Expression : public AstNode
 46.1303 +{
 46.1304 +  public:
 46.1305 +    Expression(const SourcePosition &pos)
 46.1306 +      : AstNode(pos)
 46.1307 +    {
 46.1308 +    }
 46.1309 +};
 46.1310 +
 46.1311 +typedef PoolList<Statement *> StatementList;
 46.1312 +typedef PoolList<Expression *> ExpressionList;
 46.1313 +
 46.1314 +class VariableDeclaration : public Statement
 46.1315 +{
 46.1316 +    TypeQualifiers qual_;
 46.1317 +    ScopedRoot<String> name_;
 46.1318 +    Expression *initialization_;
 46.1319 +    ExpressionList *dims_;
 46.1320 +    Expression *type_;
 46.1321 +    VariableSymbol *sym_;
 46.1322 +
 46.1323 +  public:
 46.1324 +    VariableDeclaration(const SourcePosition &pos, TypeQualifiers qual, Handle<String> name,
 46.1325 +                        Expression *type, ExpressionList *dims, Expression *initialization)
 46.1326 +      : Statement(pos),
 46.1327 +        qual_(qual),
 46.1328 +        name_(name),
 46.1329 +        initialization_(initialization),
 46.1330 +        dims_(dims),
 46.1331 +        type_(type),
 46.1332 +        sym_(NULL)
 46.1333 +    {
 46.1334 +    }
 46.1335 +
 46.1336 +    DECLARE_NODE(VariableDeclaration);
 46.1337 +
 46.1338 +    Expression *initialization() const {
 46.1339 +        return initialization_;
 46.1340 +    }
 46.1341 +    Handle<String> name() {
 46.1342 +        return name_;
 46.1343 +    }
 46.1344 +    Expression *declType() const {
 46.1345 +        return type_;
 46.1346 +    }
 46.1347 +    void setSymbol(VariableSymbol *sym) {
 46.1348 +        assert(!sym_);
 46.1349 +        sym_ = sym;
 46.1350 +    }
 46.1351 +    VariableSymbol *sym() const {
 46.1352 +        return sym_;
 46.1353 +    }
 46.1354 +    Expression *type() const {
 46.1355 +        return type_;
 46.1356 +    }
 46.1357 +    ExpressionList *dims() const {
 46.1358 +        return dims_;
 46.1359 +    }
 46.1360 +    TypeQualifiers quals() const {
 46.1361 +        return qual_;
 46.1362 +    }
 46.1363 +};
 46.1364 +
 46.1365 +class Parameter : public PoolObject
 46.1366 +{
 46.1367 +    ScopedRoot<String> name_;
 46.1368 +    Expression *type_;
 46.1369 +    bool reference_;
 46.1370 +    Expression *initializer_;
 46.1371 +    VariableSymbol *sym_;
 46.1372 +    SourcePosition pos_;
 46.1373 +    ExpressionList *dims_;
 46.1374 +    TypeQualifiers quals_;
 46.1375 +
 46.1376 +  public:
 46.1377 +    Parameter(Handle<String> name, Expression *type, bool reference, TypeQualifiers quals,
 46.1378 +              ExpressionList *dims, Expression *initializer, const SourcePosition &pos)
 46.1379 +      : name_(name),
 46.1380 +        type_(type),
 46.1381 +        reference_(reference),
 46.1382 +        initializer_(initializer),
 46.1383 +        sym_(NULL),
 46.1384 +        pos_(pos),
 46.1385 +        dims_(dims),
 46.1386 +        quals_(quals)
 46.1387 +    {
 46.1388 +    }
 46.1389 +
 46.1390 +    Expression *type() const {
 46.1391 +        return type_;
 46.1392 +    }
 46.1393 +    Handle<String> name() const {
 46.1394 +        return name_;
 46.1395 +    }
 46.1396 +    bool reference() const {
 46.1397 +        return reference_;
 46.1398 +    }
 46.1399 +    TypeQualifiers quals() const {
 46.1400 +        return quals_;
 46.1401 +    }
 46.1402 +    ExpressionList *dims() const {
 46.1403 +        return dims_;
 46.1404 +    }
 46.1405 +    Expression *initializer() const {
 46.1406 +        return initializer_;
 46.1407 +    }
 46.1408 +    void setSymbol(VariableSymbol *sym) {
 46.1409 +        assert(!sym_);
 46.1410 +        sym_ = sym;
 46.1411 +    }
 46.1412 +    VariableSymbol *sym() const {
 46.1413 +        return sym_;
 46.1414 +    }
 46.1415 +    const SourcePosition &pos() const {
 46.1416 +        return pos_;
 46.1417 +    }
 46.1418 +};
 46.1419 +
 46.1420 +class NameProxy : public Expression
 46.1421 +{
 46.1422 +    ScopedRoot<String> name_;
 46.1423 +    Symbol *binding_;
 46.1424 +
 46.1425 +  public:
 46.1426 +    NameProxy(const SourcePosition &pos, Handle<String> name)
 46.1427 +      : Expression(pos),
 46.1428 +        name_(name),
 46.1429 +        binding_(NULL)
 46.1430 +    {
 46.1431 +    }
 46.1432 +
 46.1433 +    DECLARE_NODE(NameProxy);
 46.1434 +    
 46.1435 +    Handle<String> name() const {
 46.1436 +        return name_;
 46.1437 +    }
 46.1438 +    Symbol *sym() const {
 46.1439 +        return binding_;
 46.1440 +    }
 46.1441 +    void bind(Symbol *sym) {
 46.1442 +        binding_ = sym;
 46.1443 +    }
 46.1444 +};
 46.1445 +
 46.1446 +class BooleanLiteral : public Expression
 46.1447 +{
 46.1448 +    TokenKind token_;
 46.1449 +
 46.1450 +  public:
 46.1451 +    BooleanLiteral(const SourcePosition &pos, TokenKind token)
 46.1452 +      : Expression(pos),
 46.1453 +        token_(token)
 46.1454 +    {
 46.1455 +    }
 46.1456 +
 46.1457 +    DECLARE_NODE(BooleanLiteral);
 46.1458 +    TokenKind token() const {
 46.1459 +        return token_;
 46.1460 +    }
 46.1461 +};
 46.1462 +
 46.1463 +class IntegerLiteral : public Expression
 46.1464 +{
 46.1465 +    int value_;
 46.1466 +
 46.1467 +  public:
 46.1468 +    IntegerLiteral(const SourcePosition &pos, int value)
 46.1469 +      : Expression(pos),
 46.1470 +        value_(value)
 46.1471 +    {
 46.1472 +    }
 46.1473 +
 46.1474 +    DECLARE_NODE(IntegerLiteral);
 46.1475 +
 46.1476 +    int value() const {
 46.1477 +        return value_;
 46.1478 +    }
 46.1479 +};
 46.1480 +
 46.1481 +class FloatLiteral : public Expression
 46.1482 +{
 46.1483 +    double value_;
 46.1484 +
 46.1485 +  public:
 46.1486 +    FloatLiteral(const SourcePosition &pos, double value)
 46.1487 +      : Expression(pos),
 46.1488 +        value_(value)
 46.1489 +    {
 46.1490 +    }
 46.1491 +
 46.1492 +    DECLARE_NODE(FloatLiteral);
 46.1493 +
 46.1494 +    double value() const {
 46.1495 +        return value_;
 46.1496 +    }
 46.1497 +};
 46.1498 +
 46.1499 +class StringLiteral : public Expression
 46.1500 +{
 46.1501 +    ScopedRoot<String> string_;
 46.1502 +
 46.1503 +  public:
 46.1504 +    StringLiteral(const SourcePosition &pos, String *string)
 46.1505 +      : Expression(pos),
 46.1506 +        string_(string)
 46.1507 +    {
 46.1508 +    }
 46.1509 +
 46.1510 +    DECLARE_NODE(StringLiteral);
 46.1511 +
 46.1512 +    String *string() const {
 46.1513 +        return string_;
 46.1514 +    }
 46.1515 +};
 46.1516 +
 46.1517 +class ArrayLiteral : public Expression
 46.1518 +{
 46.1519 +    TokenKind token_;
 46.1520 +    ExpressionList *expressions_;
 46.1521 +
 46.1522 +  public:
 46.1523 +    ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
 46.1524 +      : Expression(pos),
 46.1525 +        token_(token),
 46.1526 +        expressions_(expressions)
 46.1527 +    {
 46.1528 +    }
 46.1529 +
 46.1530 +    DECLARE_NODE(ArrayLiteral);
 46.1531 +
 46.1532 +    TokenKind token() const {
 46.1533 +        return token_;
 46.1534 +    }
 46.1535 +    ExpressionList *expressions() const {
 46.1536 +        return expressions_;
 46.1537 +    }
 46.1538 +    bool isFixed() const {
 46.1539 +        return token_ == TOK_LBRACE;
 46.1540 +    }
 46.1541 +};
 46.1542 +
 46.1543 +class UnaryExpression : public Expression
 46.1544 +{
 46.1545 +    Expression *expression_;
 46.1546 +    TokenKind token_;
 46.1547 +    NameProxy *tag_;
 46.1548 +
 46.1549 +  public:
 46.1550 +    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
 46.1551 +      : Expression(pos),
 46.1552 +        expression_(expr),
 46.1553 +        token_(token),
 46.1554 +        tag_(NULL)
 46.1555 +    {
 46.1556 +    }
 46.1557 +
 46.1558 +    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr,
 46.1559 +                    NameProxy *tag)
 46.1560 +      : Expression(pos),
 46.1561 +        expression_(expr),
 46.1562 +        token_(token),
 46.1563 +        tag_(tag)
 46.1564 +    {
 46.1565 +    }
 46.1566 +
 46.1567 +    DECLARE_NODE(UnaryExpression);
 46.1568 +
 46.1569 +    Expression *expression() const {
 46.1570 +        return expression_;
 46.1571 +    }
 46.1572 +    TokenKind token() const {
 46.1573 +        return token_;
 46.1574 +    }
 46.1575 +    NameProxy *tag() const {
 46.1576 +        return tag_;
 46.1577 +    }
 46.1578 +};
 46.1579 +
 46.1580 +class BinaryExpression : public Expression
 46.1581 +{
 46.1582 +    Expression *left_;
 46.1583 +    Expression *right_;
 46.1584 +    TokenKind token_;
 46.1585 +
 46.1586 +  public:
 46.1587 +    BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
 46.1588 +      : Expression(pos),
 46.1589 +        left_(left),
 46.1590 +        right_(right),
 46.1591 +        token_(token)
 46.1592 +    {
 46.1593 +    }
 46.1594 +
 46.1595 +    DECLARE_NODE(BinaryExpression);
 46.1596 +
 46.1597 +    Expression *left() const {
 46.1598 +        return left_;
 46.1599 +    }
 46.1600 +    Expression *right() const {
 46.1601 +        return right_;
 46.1602 +    }
 46.1603 +    TokenKind token() const {
 46.1604 +        return token_;
 46.1605 +    }
 46.1606 +};
 46.1607 +
 46.1608 +class TernaryExpression : public Expression
 46.1609 +{
 46.1610 +    Expression *condition_;
 46.1611 +    Expression *left_;
 46.1612 +    Expression *right_;
 46.1613 +
 46.1614 +  public:
 46.1615 +    TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
 46.1616 +      : Expression(pos),
 46.1617 +        condition_(condition),
 46.1618 +        left_(left),
 46.1619 +        right_(right)
 46.1620 +    {
 46.1621 +    }
 46.1622 +
 46.1623 +    DECLARE_NODE(TernaryExpression);
 46.1624 +
 46.1625 +    Expression *condition() const {
 46.1626 +        return condition_;
 46.1627 +    }
 46.1628 +    Expression *left() const {
 46.1629 +        return left_;
 46.1630 +    }
 46.1631 +    Expression *right() const {
 46.1632 +        return right_;
 46.1633 +    }
 46.1634 +};
 46.1635 +
 46.1636 +class IndexExpression : public Expression
 46.1637 +{
 46.1638 +    Expression *left_;
 46.1639 +    Expression *right_;
 46.1640 +
 46.1641 +  public:
 46.1642 +    IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
 46.1643 +      : Expression(pos),
 46.1644 +        left_(left),
 46.1645 +        right_(right)
 46.1646 +    {
 46.1647 +    }
 46.1648 +
 46.1649 +    DECLARE_NODE(IndexExpression);
 46.1650 +
 46.1651 +    Expression *left() const {
 46.1652 +        return left_;
 46.1653 +    }
 46.1654 +    Expression *right() const {
 46.1655 +        return right_;
 46.1656 +    }
 46.1657 +};
 46.1658 +
 46.1659 +class FieldExpression : public Expression
 46.1660 +{
 46.1661 +    Expression *left_;
 46.1662 +    ScopedRoot<String> field_;
 46.1663 +
 46.1664 +  public:
 46.1665 +    FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
 46.1666 +      : Expression(pos),
 46.1667 +        left_(left),
 46.1668 +        field_(field)
 46.1669 +    {
 46.1670 +    }
 46.1671 +
 46.1672 +    DECLARE_NODE(FieldExpression);
 46.1673 +
 46.1674 +    Expression *left() const {
 46.1675 +        return left_;
 46.1676 +    }
 46.1677 +    Handle<String> field() const {
 46.1678 +        return field_;
 46.1679 +    }
 46.1680 +};
 46.1681 +
 46.1682 +class CallExpression : public Expression
 46.1683 +{
 46.1684 +    Expression *callee_;
 46.1685 +    ExpressionList *arguments_;
 46.1686 +
 46.1687 +  public:
 46.1688 +    CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
 46.1689 +      : Expression(pos),
 46.1690 +        callee_(callee),
 46.1691 +        arguments_(arguments)
 46.1692 +    {
 46.1693 +    }
 46.1694 +
 46.1695 +    DECLARE_NODE(CallExpression);
 46.1696 +
 46.1697 +    Expression *callee() const {
 46.1698 +        return callee_;
 46.1699 +    }
 46.1700 +    ExpressionList *arguments() const {
 46.1701 +        return arguments_;
 46.1702 +    }
 46.1703 +};
 46.1704 +
 46.1705 +class ForStatement : public Statement
 46.1706 +{
 46.1707 +    Statement *initialization_;
 46.1708 +    Expression *condition_;
 46.1709 +    Statement *update_;
 46.1710 +    Statement *body_;
 46.1711 +    Scope *scope_;
 46.1712 +
 46.1713 +  public:
 46.1714 +    ForStatement(const SourcePosition &pos, Statement *initialization,
 46.1715 +                 Expression *condition, Statement *update, Statement *body)
 46.1716 +      : Statement(pos),
 46.1717 +        initialization_(initialization),
 46.1718 +        condition_(condition),
 46.1719 +        update_(update),
 46.1720 +        body_(body),
 46.1721 +        scope_(NULL)
 46.1722 +    {
 46.1723 +    }
 46.1724 +
 46.1725 +    DECLARE_NODE(ForStatement);
 46.1726 +
 46.1727 +    Statement *initialization() const {
 46.1728 +        return initialization_;
 46.1729 +    }
 46.1730 +    Expression *condition() const {
 46.1731 +        return condition_;
 46.1732 +    }
 46.1733 +    Statement *update() const {
 46.1734 +        return update_;
 46.1735 +    }
 46.1736 +    Statement *body() const {
 46.1737 +        return body_;
 46.1738 +    }
 46.1739 +    Scope *scope() const {
 46.1740 +        return scope_;
 46.1741 +    }
 46.1742 +    void setScope(Scope *scope) {
 46.1743 +        scope_ = scope;
 46.1744 +    }
 46.1745 +};
 46.1746 +
 46.1747 +class WhileStatement : public Statement
 46.1748 +{
 46.1749 +    TokenKind token_;
 46.1750 +    Expression *condition_;
 46.1751 +    Statement *body_;
 46.1752 +
 46.1753 +  public:
 46.1754 +    WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
 46.1755 +      : Statement(pos),
 46.1756 +        token_(kind),
 46.1757 +        condition_(condition),
 46.1758 +        body_(body)
 46.1759 +    {
 46.1760 +    }
 46.1761 +    
 46.1762 +    DECLARE_NODE(WhileStatement);
 46.1763 +
 46.1764 +    TokenKind token() const {
 46.1765 +        return token_;
 46.1766 +    }
 46.1767 +    Expression *condition() const {
 46.1768 +        return condition_;
 46.1769 +    }
 46.1770 +    Statement *body() const {
 46.1771 +        return body_;
 46.1772 +    }
 46.1773 +};
 46.1774 +
 46.1775 +class ReturnStatement : public Statement
 46.1776 +{
 46.1777 +    Expression *expression_;
 46.1778 +
 46.1779 +  public:
 46.1780 +    ReturnStatement(const SourcePosition &pos, Expression *expression)
 46.1781 +      : Statement(pos),
 46.1782 +        expression_(expression)
 46.1783 +    {
 46.1784 +    }
 46.1785 +
 46.1786 +    DECLARE_NODE(ReturnStatement);
 46.1787 +
 46.1788 +    Expression *expression() const {
 46.1789 +        return expression_;
 46.1790 +    }
 46.1791 +};
 46.1792 +
 46.1793 +class BreakStatement : public Statement
 46.1794 +{
 46.1795 +  public:
 46.1796 +    BreakStatement(const SourcePosition &pos)
 46.1797 +      : Statement(pos)
 46.1798 +    {
 46.1799 +    }
 46.1800 +
 46.1801 +    DECLARE_NODE(BreakStatement);
 46.1802 +};
 46.1803 +
 46.1804 +class ContinueStatement : public Statement
 46.1805 +{
 46.1806 +  public:
 46.1807 +    ContinueStatement(const SourcePosition &pos)
 46.1808 +      : Statement(pos)
 46.1809 +    {
 46.1810 +    }
 46.1811 +
 46.1812 +    DECLARE_NODE(ContinueStatement);
 46.1813 +};
 46.1814 +
 46.1815 +class Assignment : public Expression
 46.1816 +{
 46.1817 +    TokenKind token_;
 46.1818 +    Expression *lvalue_;
 46.1819 +    Expression *expression_;
 46.1820 +
 46.1821 +  public:
 46.1822 +    Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
 46.1823 +      : Expression(pos),
 46.1824 +        token_(token),
 46.1825 +        lvalue_(left),
 46.1826 +        expression_(right)
 46.1827 +    {
 46.1828 +    }
 46.1829 +
 46.1830 +    DECLARE_NODE(Assignment);
 46.1831 +
 46.1832 +    TokenKind token() const {
 46.1833 +        return token_;
 46.1834 +    }
 46.1835 +    Expression *lvalue() const {
 46.1836 +        return lvalue_;
 46.1837 +    }
 46.1838 +    Expression *expression() const {
 46.1839 +        return expression_;
 46.1840 +    }
 46.1841 +};
 46.1842 +
 46.1843 +class ExpressionStatement : public Statement
 46.1844 +{
 46.1845 +    Expression *expression_;
 46.1846 +
 46.1847 +  public:
 46.1848 +    ExpressionStatement(Expression *expression)
 46.1849 +      : Statement(expression->pos()),
 46.1850 +        expression_(expression)
 46.1851 +    {
 46.1852 +    }
 46.1853 +
 46.1854 +    DECLARE_NODE(ExpressionStatement);
 46.1855 +
 46.1856 +    Expression *expression() const {
 46.1857 +        return expression_;
 46.1858 +    }
 46.1859 +};
 46.1860 +
 46.1861 +class BlockStatement : public Statement
 46.1862 +{
 46.1863 +    StatementList *statements_;
 46.1864 +    Scope *scope_;
 46.1865 +    TokenKind type_;
 46.1866 +
 46.1867 +  public:
 46.1868 +    BlockStatement(const SourcePosition &pos, StatementList *statements, TokenKind kind)
 46.1869 +      : Statement(pos),
 46.1870 +        statements_(statements),
 46.1871 +        scope_(NULL),
 46.1872 +        type_(kind)
 46.1873 +    {
 46.1874 +    }
 46.1875 +
 46.1876 +    DECLARE_NODE(BlockStatement);
 46.1877 +
 46.1878 +    StatementList *statements() const {
 46.1879 +        return statements_;
 46.1880 +    }
 46.1881 +    Scope *scope() const {
 46.1882 +        return scope_;
 46.1883 +    }
 46.1884 +    void setScope(Scope *scope) {
 46.1885 +        scope_ = scope;
 46.1886 +    }
 46.1887 +    TokenKind type() const {
 46.1888 +        return type_;
 46.1889 +    }
 46.1890 +};
 46.1891 +
 46.1892 +typedef PoolList<Parameter *> ParameterList;
 46.1893 +
 46.1894 +class FunctionSignature
 46.1895 +{
 46.1896 +  public:
 46.1897 +    FunctionSignature(Expression *returnType, ParameterList *parameters, bool variadic)
 46.1898 +      : returnType_(returnType),
 46.1899 +        parameters_(parameters),
 46.1900 +        variadic_(variadic)
 46.1901 +    {
 46.1902 +    }
 46.1903 +
 46.1904 +    Expression *returnType() const {
 46.1905 +        return returnType_;
 46.1906 +    }
 46.1907 +    ParameterList *parameters() const {
 46.1908 +        return parameters_;
 46.1909 +    }
 46.1910 +    bool variadic() const {
 46.1911 +        return variadic_;
 46.1912 +    }
 46.1913 +
 46.1914 +  private:
 46.1915 +    Expression *returnType_;
 46.1916 +    ParameterList *parameters_;
 46.1917 +    bool variadic_;
 46.1918 +};
 46.1919 +
 46.1920 +class FunctionTypeStatement : public Statement
 46.1921 +{
 46.1922 +  public:
 46.1923 +    FunctionTypeStatement(const SourcePosition &pos, Handle<String> name, const FunctionSignature &signature)
 46.1924 +      : Statement(pos),
 46.1925 +        name_(name),
 46.1926 +        signature_(signature)
 46.1927 +    {
 46.1928 +    }
 46.1929 +
 46.1930 +    DECLARE_NODE(FunctionTypeStatement);
 46.1931 +
 46.1932 +    Handle<String> name() const {
 46.1933 +        return name_;
 46.1934 +    }
 46.1935 +    const FunctionSignature &signature() const {
 46.1936 +        return signature_;
 46.1937 +    }
 46.1938 +
 46.1939 +  private:
 46.1940 +    ScopedRoot<String> name_;
 46.1941 +    FunctionSignature signature_;
 46.1942 +    
 46.1943 +};
 46.1944 +
 46.1945 +class FunctionStatement : public Statement
 46.1946 +{
 46.1947 +    ScopedRoot<String> name_;
 46.1948 +    TokenKind kind_;
 46.1949 +    Statement *body_;
 46.1950 +    FunctionSignature signature_;
 46.1951 +    bool explicitReturn_;
 46.1952 +    FunctionSymbol *sym_;
 46.1953 +    Scope *argScope_;
 46.1954 +    Scope *varScope_;
 46.1955 +
 46.1956 +  public:
 46.1957 +    FunctionStatement(const SourcePosition &pos, Handle<String> name, TokenKind kind,
 46.1958 +                      Statement *body, const FunctionSignature &signature, bool explicitReturn)
 46.1959 +      : Statement(pos),
 46.1960 +        name_(name),
 46.1961 +        kind_(kind),
 46.1962 +        body_(body),
 46.1963 +        signature_(signature),
 46.1964 +        explicitReturn_(explicitReturn),
 46.1965 +        sym_(NULL),
 46.1966 +        argScope_(NULL),
 46.1967 +        varScope_(NULL)
 46.1968 +    {
 46.1969 +    }
 46.1970 +
 46.1971 +    DECLARE_NODE(FunctionStatement);
 46.1972 +
 46.1973 +    Handle<String> name() const {
 46.1974 +        return name_;
 46.1975 +    }
 46.1976 +    Statement *body() const {
 46.1977 +        return body_;
 46.1978 +    }
 46.1979 +    const FunctionSignature &signature() {
 46.1980 +        return signature_;
 46.1981 +    }
 46.1982 +    bool hasExplicitReturn() const {
 46.1983 +        return explicitReturn_;
 46.1984 +    }
 46.1985 +    TokenKind token() const {
 46.1986 +        return kind_;
 46.1987 +    }
 46.1988 +    void setSymbol(FunctionSymbol *sym) {
 46.1989 +        assert(!sym_);
 46.1990 +        sym_ = sym;
 46.1991 +    }
 46.1992 +    FunctionSymbol *sym() const {
 46.1993 +        return sym_;
 46.1994 +    }
 46.1995 +    void setScopes(Scope *argScope, Scope *varScope) {
 46.1996 +        argScope_ = argScope;
 46.1997 +        varScope_ = varScope;
 46.1998 +    }
 46.1999 +    Scope *argScope() const {
 46.2000 +        return argScope_;
 46.2001 +    }
 46.2002 +    Scope *varScope() const {
 46.2003 +        return varScope_;
 46.2004 +    }
 46.2005 +};
 46.2006 +
 46.2007 +class IfStatement : public Statement
 46.2008 +{
 46.2009 +    Expression *condition_;
 46.2010 +    Statement *ifTrue_;
 46.2011 +    Statement *ifFalse_;
 46.2012 +
 46.2013 +  public:
 46.2014 +    IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
 46.2015 +      : Statement(pos),
 46.2016 +        condition_(condition),
 46.2017 +        ifTrue_(ifTrue),
 46.2018 +        ifFalse_(NULL)
 46.2019 +    {
 46.2020 +    }
 46.2021 +
 46.2022 +    DECLARE_NODE(IfStatement);
 46.2023 +
 46.2024 +    Expression *condition() const {
 46.2025 +        return condition_;
 46.2026 +    }
 46.2027 +    Statement *ifTrue() const {
 46.2028 +        return ifTrue_;
 46.2029 +    }
 46.2030 +    Statement *ifFalse() const {
 46.2031 +        return ifFalse_;
 46.2032 +    }
 46.2033 +    void setIfFalse(Statement *ifFalse) {
 46.2034 +        ifFalse_ = ifFalse;
 46.2035 +    }
 46.2036 +};
 46.2037 +
 46.2038 +class EnumStatement : public Statement
 46.2039 +{
 46.2040 +    ScopedRoot<String> name_;
 46.2041 +    TypeSymbol *sym_;
 46.2042 +
 46.2043 +  public:
 46.2044 +    struct Entry {
 46.2045 +        ScopedRoot<String> name;
 46.2046 +        Expression *expr;
 46.2047 +        SourcePosition pos;
 46.2048 +        ConstantSymbol *sym;
 46.2049 +
 46.2050 +        Entry(Handle<String> name, Expression *expr, const SourcePosition &pos)
 46.2051 +          : name(name),
 46.2052 +            expr(expr),
 46.2053 +            pos(pos),
 46.2054 +            sym(NULL)
 46.2055 +        {
 46.2056 +        }
 46.2057 +    };
 46.2058 +
 46.2059 +    typedef PoolList<Entry> EntryList;
 46.2060 +
 46.2061 +  public:
 46.2062 +    EnumStatement(const SourcePosition &pos, TokenKind visibility, Handle<String> name, EntryList *entries)
 46.2063 +      : Statement(pos),
 46.2064 +        name_(name),
 46.2065 +        sym_(NULL),
 46.2066 +        entries_(entries),
 46.2067 +        visibility_(visibility)
 46.2068 +    {
 46.2069 +    }
 46.2070 +
 46.2071 +    DECLARE_NODE(EnumStatement);
 46.2072 +
 46.2073 +    Handle<String> name() const {
 46.2074 +        return name_;
 46.2075 +    }
 46.2076 +    EntryList *entries() const {
 46.2077 +        return entries_;
 46.2078 +    }
 46.2079 +    void setSymbol(TypeSymbol *sym) {
 46.2080 +        assert(!sym_);
 46.2081 +        sym_ = sym;
 46.2082 +    }
 46.2083 +    TypeSymbol *sym() const {
 46.2084 +        return sym_;
 46.2085 +    }
 46.2086 +    TokenKind visibility() const {
 46.2087 +        return visibility_;
 46.2088 +    }
 46.2089 +
 46.2090 +  private:
 46.2091 +    EntryList *entries_;
 46.2092 +    TokenKind visibility_;
 46.2093 +};
 46.2094 +
 46.2095 +class IncDecExpression : public Expression
 46.2096 +{
 46.2097 +    TokenKind token_;
 46.2098 +    Expression *expression_;
 46.2099 +    bool postfix_;
 46.2100 +
 46.2101 +  public:
 46.2102 +    IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
 46.2103 +      : Expression(pos),
 46.2104 +        token_(token),
 46.2105 +        expression_(expression),
 46.2106 +        postfix_(postfix)
 46.2107 +    {
 46.2108 +    }
 46.2109 +
 46.2110 +    DECLARE_NODE(IncDecExpression);
 46.2111 +
 46.2112 +    TokenKind token() const {
 46.2113 +        return token_;
 46.2114 +    }
 46.2115 +    Expression *expression() const {
 46.2116 +        return expression_;
 46.2117 +    }
 46.2118 +    bool postfix() const {
 46.2119 +        return postfix_;
 46.2120 +    }
 46.2121 +};
 46.2122 +
 46.2123 +class Case : public PoolObject
 46.2124 +{
 46.2125 +  public:
 46.2126 +    Case(Expression *expression, ExpressionList *others, Statement *statement)
 46.2127 +      : expression_(expression),
 46.2128 +        others_(others),
 46.2129 +        statement_(statement)
 46.2130 +    {
 46.2131 +    }
 46.2132 +
 46.2133 +    Expression *expression() const {
 46.2134 +        return expression_;
 46.2135 +    }
 46.2136 +    PoolList<Expression *> *others() const {
 46.2137 +        return others_;
 46.2138 +    }
 46.2139 +    Statement *statement() const {
 46.2140 +        return statement_;
 46.2141 +    }
 46.2142 +
 46.2143 +  private:
 46.2144 +    Expression *expression_;
 46.2145 +    PoolList <Expression *> *others_;
 46.2146 +    Statement *statement_;
 46.2147 +};
 46.2148 +
 46.2149 +struct CaseValue
 46.2150 +{
 46.2151 +    BoxedPrimitive box;
 46.2152 +    size_t statement;
 46.2153 +
 46.2154 +    CaseValue(size_t statement)
 46.2155 +      : statement(statement)
 46.2156 +    {
 46.2157 +    }
 46.2158 +};
 46.2159 +
 46.2160 +typedef PoolList<CaseValue> CaseValueList;
 46.2161 +
 46.2162 +class SwitchStatement : public Statement
 46.2163 +{
 46.2164 +  public:
 46.2165 +    SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
 46.2166 +                    Statement *def)
 46.2167 +      : Statement(pos),
 46.2168 +        expression_(expression),
 46.2169 +        cases_(cases),
 46.2170 +        default_(def),
 46.2171 +        table_(NULL)
 46.2172 +    {
 46.2173 +    }
 46.2174 +
 46.2175 +    DECLARE_NODE(SwitchStatement);
 46.2176 +
 46.2177 +    Expression *expression() const {
 46.2178 +        return expression_;
 46.2179 +    }
 46.2180 +    PoolList<Case *> *cases() const {
 46.2181 +        return cases_;
 46.2182 +    }
 46.2183 +    Statement *defaultCase() const {
 46.2184 +        return default_;
 46.2185 +    }
 46.2186 +    void setCaseValueList(CaseValueList *list) {
 46.2187 +        table_ = list;
 46.2188 +    }
 46.2189 +    CaseValueList *caseValueList() const {
 46.2190 +        return table_;
 46.2191 +    }
 46.2192 +
 46.2193 +  private:
 46.2194 +    Expression *expression_;
 46.2195 +    PoolList<Case *> *cases_;
 46.2196 +    Statement *default_;
 46.2197 +    CaseValueList *table_;
 46.2198 +};
 46.2199 +
 46.2200 +class StructureStatement : public Statement
 46.2201 +{
 46.2202 +  public:
 46.2203 +    class Field : public PoolObject
 46.2204 +    {
 46.2205 +        SourcePosition pos_;
 46.2206 +        Expression *type_;
 46.2207 +        ScopedRoot<String> name_;
 46.2208 +
 46.2209 +      public:
 46.2210 +        Field(const SourcePosition &pos,
 46.2211 +              Expression *type,
 46.2212 +              Handle<String> name)
 46.2213 +          : pos_(pos),
 46.2214 +            type_(type),
 46.2215 +            name_(name)
 46.2216 +        {
 46.2217 +        }
 46.2218 +
 46.2219 +        const SourcePosition &pos() const {
 46.2220 +            return pos_;
 46.2221 +        }
 46.2222 +        Handle<String> name() const {
 46.2223 +            return name_;
 46.2224 +        }
 46.2225 +        Expression *type() const {
 46.2226 +            return type_;
 46.2227 +        }
 46.2228 +    };
 46.2229 +
 46.2230 +    typedef PoolList<StructureStatement::Field *> FieldList;
 46.2231 +
 46.2232 +  public:
 46.2233 +    StructureStatement(const SourcePosition &pos, Handle<String> name, FieldList *fields)
 46.2234 +      : Statement(pos),
 46.2235 +        name_(name),
 46.2236 +        fields_(fields),
 46.2237 +        sym_(NULL)
 46.2238 +    {
 46.2239 +    }
 46.2240 +
 46.2241 +    DECLARE_NODE(StructureStatement);
 46.2242 +
 46.2243 +    FieldList *fields() const {
 46.2244 +        return fields_;
 46.2245 +    }
 46.2246 +    Handle<String> name() const {
 46.2247 +        return name_;
 46.2248 +    }
 46.2249 +    void setSymbol(TypeSymbol *sym) {
 46.2250 +        assert(!sym_);
 46.2251 +        sym_ = sym;
 46.2252 +    }
 46.2253 +    TypeSymbol *sym() const {
 46.2254 +        return sym_;
 46.2255 +    }
 46.2256 +
 46.2257 +  private:
 46.2258 +    ScopedRoot<String> name_;
 46.2259 +    FieldList *fields_;
 46.2260 +    TypeSymbol *sym_;
 46.2261 +};
 46.2262 +
 46.2263 +typedef PoolList<ScopedRoot<String> *> NameList;
 46.2264 +
 46.2265 +class ImportStatement : public Statement
 46.2266 +{
 46.2267 +  public:
 46.2268 +    ImportStatement(const SourcePosition &pos, PathComponent *path, NameList *names)
 46.2269 +      : Statement(pos),
 46.2270 +        path_(path),
 46.2271 +        names_(names)
 46.2272 +    {
 46.2273 +    }
 46.2274 +
 46.2275 +    DECLARE_NODE(ImportStatement);
 46.2276 +
 46.2277 +    PathComponent *path() const {
 46.2278 +        return path_;
 46.2279 +    }
 46.2280 +    void setSource(Importable *source) {
 46.2281 +        source_ = source;
 46.2282 +    }
 46.2283 +    Handle<Importable> source() {
 46.2284 +        return source_;
 46.2285 +    }
 46.2286 +    unsigned importIndex() const {
 46.2287 +        return importIndex_;
 46.2288 +    }
 46.2289 +    void setImportIndex(unsigned index) {
 46.2290 +        importIndex_ = index;
 46.2291 +    }
 46.2292 +    NameList *names() const {
 46.2293 +        return names_;
 46.2294 +    }
 46.2295 +
 46.2296 +    bool importAllNames() const {
 46.2297 +        return names_ && names_->empty();
 46.2298 +    }
 46.2299 +
 46.2300 +  private:
 46.2301 +    PathComponent *path_;
 46.2302 +    ScopedRoot<Importable> source_;
 46.2303 +    unsigned importIndex_;
 46.2304 +    NameList *names_;
 46.2305 +};
 46.2306 +
 46.2307 +typedef StructureStatement::FieldList FieldList;
 46.2308 +typedef PoolList<NameProxy *> NameProxyList;
 46.2309 +
 46.2310 +#undef DECLARE_NODE
 46.2311 +
 46.2312 +class ParseTree : public PoolObject
 46.2313 +{
 46.2314 +    StatementList *statements_;
 46.2315 +    NameProxyList *unbound_;
 46.2316 +    PoolList<ImportStatement *> *imports_;
 46.2317 +
 46.2318 +  public:
 46.2319 +    ParseTree(StatementList *statements, NameProxyList *unbound, PoolList<ImportStatement *> *imports)
 46.2320 +      : statements_(statements),
 46.2321 +        unbound_(unbound),
 46.2322 +        imports_(imports)
 46.2323 +    {
 46.2324 +    }
 46.2325 +
 46.2326 +    void dump(FILE *fp);
 46.2327 +
 46.2328 +    StatementList *statements() const {
 46.2329 +        return statements_;
 46.2330 +    }
 46.2331 +    NameProxyList *unbound() const {
 46.2332 +        return unbound_;
 46.2333 +    }
 46.2334 +    PoolList<ImportStatement *> *imports() const {
 46.2335 +        return imports_;
 46.2336 +    }
 46.2337 +};
 46.2338 +
 46.2339 +}
 46.2340 +
 46.2341 +#endif // _include_sourcepawn_ast_h_
    47.1 --- a/src/compiler/BytecodeEmitter.cpp	Mon Jun 10 00:46:29 2013 +0100
    47.2 +++ b/src/compiler/BytecodeEmitter.cpp	Mon Jun 10 01:04:43 2013 +0100
    47.3 @@ -1,386 +1,386 @@
    47.4 -/* vim: set ts=4 sw=4 tw=99 et:
    47.5 - *
    47.6 - * Copyright (C) 2012 David Anderson
    47.7 - *
    47.8 - * This file is part of JITCraft.
    47.9 - *
   47.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   47.11 - * the terms of the GNU General Public License as published by the Free
   47.12 - * Software Foundation, either version 3 of the License, or (at your option)
   47.13 - * any later version.
   47.14 - * 
   47.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   47.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   47.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   47.18 - *
   47.19 - * You should have received a copy of the GNU General Public License along with
   47.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   47.21 - */
   47.22 -#include <stdlib.h>
   47.23 -#include <string.h>
   47.24 -#include "../Utility.h"
   47.25 -#include "../Types.h"
   47.26 -#include "../Zone.h"
   47.27 -#include "../Strings.h"
   47.28 -#include "../Zone.h"
   47.29 -#include "BytecodeEmitter.h"
   47.30 -#include "Symbols.h"
   47.31 -#include "Scopes.h"
   47.32 -#include "../Spaces-inl.h"
   47.33 -#include "../Heap-inl.h"
   47.34 -
   47.35 -using namespace ke;
   47.36 -
   47.37 -StringTable::StringTable()
   47.38 -  : set_(ZoneAllocatorPolicy()),
   47.39 -    initialized_(false)
   47.40 -{
   47.41 -}
   47.42 -
   47.43 -bool
   47.44 -StringTable::initialize()
   47.45 -{
   47.46 -    assert(!initialized_);
   47.47 -    initialized_ = true;
   47.48 -    if (!set_.init(16))
   47.49 -        return false;
   47.50 -    return true;
   47.51 -}
   47.52 -
   47.53 -bool
   47.54 -StringTable::add(Handle<String> name, unsigned *indexp)
   47.55 -{
   47.56 -    if (!initialized_ && !initialize())
   47.57 -        return false;
   47.58 -
   47.59 -    Set::Insert p = set_.findForAdd(*name);
   47.60 -    if (p.found()) {
   47.61 -        *indexp = p->index;
   47.62 -        return true;
   47.63 -    }
   47.64 -
   47.65 -    if (strings_.length() > INT_MAX) {
   47.66 -        ZONE()->reportAllocationOverflow();
   47.67 -        return false;
   47.68 -    }
   47.69 -
   47.70 -    Entry e(name, strings_.length());
   47.71 -    if (!strings_.append(e))
   47.72 -        return false;
   47.73 -
   47.74 -    if (!set_.add(p, e))
   47.75 -        return false;
   47.76 -
   47.77 -    *indexp = e.index;
   47.78 -
   47.79 -    return true;
   47.80 -}
   47.81 -
   47.82 -void
   47.83 -StringTable::accept(VirtualObjectVisitor *visitor)
   47.84 -{
   47.85 -    for (size_t i = 0; i < strings_.length(); i++)
   47.86 -        visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
   47.87 -}
   47.88 -
   47.89 -BytecodeEmitter::BytecodeEmitter()
   47.90 -  : AutoRooted(ZONE()),
   47.91 -    buffer_(inline_buffer_),
   47.92 -    buffer_pos_(buffer_),
   47.93 -    buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
   47.94 -    oom_(false),
   47.95 -    maxStackDepth_(0),
   47.96 -    loopDepth_(0),
   47.97 -    maxLoopDepth_(0)
   47.98 -{
   47.99 -    lastCodePosition_ = 0;
  47.100 -    firstLine_ = 1;
  47.101 -}
  47.102 -
  47.103 -BytecodeEmitter::~BytecodeEmitter()
  47.104 -{
  47.105 -    for (size_t i = 0; i < oopRecords_.length(); i++)
  47.106 -        delete oopRecords_[i];
  47.107 -}
  47.108 -
  47.109 -void
  47.110 -BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
  47.111 -{
  47.112 -    for (size_t i = 0; i < objects_.length(); i++)
  47.113 -        visitor->visit(&objects_[i]);
  47.114 -
  47.115 -    strings_.accept(visitor);
  47.116 -}
  47.117 -
  47.118 -bool
  47.119 -BytecodeEmitter::growBuffer(size_t nbytes)
  47.120 -{
  47.121 -    if (oom_) {
  47.122 -        buffer_pos_ = buffer_;
  47.123 -        return false;
  47.124 -    }
  47.125 -
  47.126 -    size_t newSize = size_t((buffer_end_ - buffer_) * 2);
  47.127 -    if (newSize >= MAX_LENGTH) {
  47.128 -        oom_ = true;
  47.129 -        buffer_pos_ = buffer_;
  47.130 -        ZONE()->reportOutOfMemory();
  47.131 -        return false;
  47.132 -    }
  47.133 -
  47.134 -    bytecode *newBuffer;
  47.135 -    if (buffer_ == inline_buffer_)
  47.136 -        newBuffer = (bytecode *)malloc(newSize);
  47.137 -    else
  47.138 -        newBuffer = (bytecode *)realloc(buffer_, newSize);
  47.139 -
  47.140 -    // If we can't allocate a buffer, reset the buffer to the start and set
  47.141 -    // a flag to indicate out-of-memory.
  47.142 -    if (!newBuffer) {
  47.143 -        oom_ = true;
  47.144 -        buffer_pos_ = buffer_;
  47.145 -        ZONE()->reportOutOfMemory();
  47.146 -        return false;
  47.147 -    }
  47.148 -
  47.149 -    if (buffer_ == inline_buffer_)
  47.150 -        memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
  47.151 -
  47.152 -    buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
  47.153 -    buffer_ = newBuffer;
  47.154 -    buffer_end_ = buffer_ + newSize;
  47.155 -    assert(buffer_pos_ + nbytes < buffer_end_);
  47.156 -
  47.157 -    return true;
  47.158 -}
  47.159 -
  47.160 -void
  47.161 -BytecodeEmitter::recordOops()
  47.162 -{
  47.163 -    OopRecord *record = new OopRecord(oopMap_.length(), position());
  47.164 -
  47.165 -    if (!record->slots.ensure(record->depth)) {
  47.166 -        oom_ = true;
  47.167 -        return;
  47.168 -    }
  47.169 -
  47.170 -    bool hadOops = false;
  47.171 -    for (size_t i = 0; i < oopMap_.length(); i++) {
  47.172 -        bool bit = oopMap_[i];
  47.173 -        record->slots.infallibleAppend(bit);
  47.174 -        hadOops |= bit;
  47.175 -    }
  47.176 -
  47.177 -    if (!hadOops) {
  47.178 -        delete record;
  47.179 -        return;
  47.180 -    }
  47.181 -
  47.182 -    oom_ &= oopRecords_.append(record);
  47.183 -}
  47.184 -
  47.185 -void
  47.186 -BytecodeEmitter::note_position(const SourcePosition &pos)
  47.187 -{
  47.188 -    assert(pos.line > 0);
  47.189 -    assert(unsigned(pos.line) >= firstLine_);
  47.190 -
  47.191 -    unsigned lineDelta = unsigned(pos.line) - firstLine_;
  47.192 -    unsigned pcDelta = unsigned(position()) - lastCodePosition_;
  47.193 -
  47.194 -    sourcemap_.writeUint32(pcDelta);
  47.195 -    sourcemap_.writeUint32(lineDelta);
  47.196 -    sourcemap_.writeUint32(pos.col);
  47.197 -
  47.198 -    lastCodePosition_ = unsigned(position());
  47.199 -}
  47.200 -
  47.201 -void
  47.202 -BytecodeEmitter::getglobal(Symbol *sym)
  47.203 -{
  47.204 -    ensure(OP_GETGLOBAL_LENGTH);
  47.205 -    writeOp(OP_GETGLOBAL);
  47.206 -    writeUint32(addString(sym->name()));
  47.207 -    if (sym->type()->isTraceable())
  47.208 -        markOop(1);
  47.209 -}
  47.210 -void
  47.211 -BytecodeEmitter::setglobal(Symbol *sym)
  47.212 -{
  47.213 -    ensure(OP_SETGLOBAL_LENGTH);
  47.214 -    writeOp(OP_SETGLOBAL);
  47.215 -    writeUint32(addString(sym->name()));
  47.216 -    if (sym->type()->isTraceable())
  47.217 -        markOop(1);
  47.218 -}
  47.219 -
  47.220 -void
  47.221 -BytecodeEmitter::getlocal(VariableSymbol *var)
  47.222 -{
  47.223 -    assert(var->storage() == VariableSymbol::Local);
  47.224 -    ensure(OP_GETLOCAL_LENGTH);
  47.225 -    writeOp(OP_GETLOCAL);
  47.226 -    writeUint32(var->slot());
  47.227 -    if (var->type()->isTraceable())
  47.228 -        markOop(1);
  47.229 -}
  47.230 -
  47.231 -void
  47.232 -BytecodeEmitter::setlocal(VariableSymbol *var)
  47.233 -{
  47.234 -    assert(var->storage() == VariableSymbol::Local);
  47.235 -    ensure(OP_SETLOCAL_LENGTH);
  47.236 -    writeOp(OP_SETLOCAL);
  47.237 -    writeUint32(var->slot());
  47.238 -    if (var->type()->isTraceable())
  47.239 -        markOop(1);
  47.240 -}
  47.241 -
  47.242 -void
  47.243 -BytecodeEmitter::getarg(VariableSymbol *var)
  47.244 -{
  47.245 -    assert(var->storage() == VariableSymbol::Arg);
  47.246 -    ensure(OP_GETARG_LENGTH);
  47.247 -    writeOp(OP_GETARG);
  47.248 -    writeUint32(var->slot());
  47.249 -    if (var->type()->isTraceable())
  47.250 -        markOop(1);
  47.251 -}
  47.252 -
  47.253 -void
  47.254 -BytecodeEmitter::setarg(VariableSymbol *var)
  47.255 -{
  47.256 -    assert(var->storage() == VariableSymbol::Arg);
  47.257 -    ensure(OP_SETARG_LENGTH);
  47.258 -    writeOp(OP_SETARG);
  47.259 -    writeUint32(var->slot());
  47.260 -    if (var->type()->isTraceable())
  47.261 -        markOop(1);
  47.262 -}
  47.263 -
  47.264 -bool
  47.265 -BytecodeEmitter::allocate(VariableSymbol *sym)
  47.266 -{
  47.267 -    assert(sym->isVariable());
  47.268 -    assert(sym->scope()->kind() == Scope::BLOCK);
  47.269 -
  47.270 -    switch (sym->scope()->kind()) {
  47.271 -      case Scope::BLOCK:
  47.272 -      {
  47.273 -        // See overall comment on overflows.
  47.274 -        assert(locals_.length() < UINT_MAX);
  47.275 -        sym->allocate(VariableSymbol::Local, locals_.length());
  47.276 -        if (!locals_.append(sym))
  47.277 -            return false;
  47.278 -        break;
  47.279 -      }
  47.280 -
  47.281 -      default:
  47.282 -        assert(false);
  47.283 -        return false;
  47.284 -    }
  47.285 -
  47.286 -    return true;
  47.287 -}
  47.288 -
  47.289 -void
  47.290 -BytecodeEmitter::newref(VariableSymbol *var)
  47.291 -{
  47.292 -    recordOops();
  47.293 -    if (var->storage() == VariableSymbol::Local) {
  47.294 -        ensure(OP_VARREF_LIFO_LENGTH);
  47.295 -        writeOp(OP_VARREF_LIFO);
  47.296 -    } else {
  47.297 -        assert(var->storage() == VariableSymbol::Arg);
  47.298 -        ensure(OP_ARGREF_LIFO_LENGTH);
  47.299 -        writeOp(OP_ARGREF_LIFO);
  47.300 -    }
  47.301 -    writeUint32(var->slot());
  47.302 -    markOop(1);
  47.303 -}
  47.304 -
  47.305 -Code *
  47.306 -BytecodeEmitter::finish()
  47.307 -{
  47.308 -    stop();
  47.309 -
  47.310 -    Zone *zone = ZONE();
  47.311 -    if (oom() || zone->hasPendingException())
  47.312 -        return NULL;
  47.313 -
  47.314 -    Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
  47.315 -    if (!bytes)
  47.316 -        return NULL;
  47.317 -    memcpy(bytes->raw(), buffer(), length());
  47.318 -
  47.319 -    Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
  47.320 -    if (!objects)
  47.321 -        return NULL;
  47.322 -
  47.323 -    for (size_t i = 0; i < objects_.length(); i++)
  47.324 -        objects->set(zone, i, objects_[i]);
  47.325 -
  47.326 -    // If any stack slots hold gc pointers at potential failure points in the
  47.327 -    // bytecode, record them now. We do this by building a list of tuples;
  47.328 -    // each tuple contains the pc offset, and a bitset containing which stack
  47.329 -    // slots must be scanned by the gc.
  47.330 -    Local<ByteArray> safepoints(zone);
  47.331 -    if (oopRecords_.length()) {
  47.332 -        size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
  47.333 -        size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
  47.334 -        safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
  47.335 -        if (!safepoints)
  47.336 -            return NULL;
  47.337 -
  47.338 -        Address cursor = safepoints->raw();
  47.339 -        for (size_t i = 0; i < oopRecords_.length(); i++) {
  47.340 -            OopRecord *record = oopRecords_[i];
  47.341 -            assert(record->depth <= maxStackDepth());
  47.342 -
  47.343 -            *reinterpret_cast<unsigned *>(cursor) = record->offset;
  47.344 -
  47.345 -            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
  47.346 -            for (unsigned i = 0; i < record->depth; i++)
  47.347 -                bits[i / 8] |= (1 << (i % 8));
  47.348 -
  47.349 -            cursor += bytesPerSafepoint;
  47.350 -        }
  47.351 -
  47.352 -        assert(cursor == safepoints->raw() + gcmapSize);
  47.353 -    }
  47.354 -
  47.355 -    Local<ByteArray> sourcemap(zone);
  47.356 -    if (sourcemap_.length()) {
  47.357 -        sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
  47.358 -        if (!sourcemap)
  47.359 -            return NULL;
  47.360 -
  47.361 -        memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
  47.362 -    }
  47.363 -
  47.364 -    Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
  47.365 -    if (!strings)
  47.366 -        return NULL;
  47.367 -    for (size_t i = 0; i < strings_.stringCount(); i++)
  47.368 -        strings->set(zone, i, strings_.stringAt(i));
  47.369 -
  47.370 -    Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
  47.371 -    if (!locals)
  47.372 -        return NULL;
  47.373 -    for (size_t i = 0; i < locals_.length(); i++)
  47.374 -        locals->set(zone, i, locals_[i]->type());
  47.375 -
  47.376 -    Local<Code> code(zone);
  47.377 -
  47.378 -    code = Code::New(zone,
  47.379 -                     bytes,
  47.380 -                     locals,
  47.381 -                     objects,
  47.382 -                     strings,
  47.383 -                     maxStackDepth(),
  47.384 -                     maxLoopDepth_,
  47.385 -                     safepoints,
  47.386 -                     sourcemap);
  47.387 -
  47.388 -    return code;
  47.389 -}
  47.390 +/* vim: set ts=4 sw=4 tw=99 et:
  47.391 + *
  47.392 + * Copyright (C) 2012 David Anderson
  47.393 + *
  47.394 + * This file is part of JITCraft.
  47.395 + *
  47.396 + * JITCraft is free software: you can redistribute it and/or modify it under
  47.397 + * the terms of the GNU General Public License as published by the Free
  47.398 + * Software Foundation, either version 3 of the License, or (at your option)
  47.399 + * any later version.
  47.400 + * 
  47.401 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  47.402 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  47.403 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  47.404 + *
  47.405 + * You should have received a copy of the GNU General Public License along with
  47.406 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  47.407 + */
  47.408 +#include <stdlib.h>
  47.409 +#include <string.h>
  47.410 +#include "../Utility.h"
  47.411 +#include "../Types.h"
  47.412 +#include "../Zone.h"
  47.413 +#include "../Strings.h"
  47.414 +#include "../Zone.h"
  47.415 +#include "BytecodeEmitter.h"
  47.416 +#include "Symbols.h"
  47.417 +#include "Scopes.h"
  47.418 +#include "../Spaces-inl.h"
  47.419 +#include "../Heap-inl.h"
  47.420 +
  47.421 +using namespace ke;
  47.422 +
  47.423 +StringTable::StringTable()
  47.424 +  : set_(ZoneAllocatorPolicy()),
  47.425 +    initialized_(false)
  47.426 +{
  47.427 +}
  47.428 +
  47.429 +bool
  47.430 +StringTable::initialize()
  47.431 +{
  47.432 +    assert(!initialized_);
  47.433 +    initialized_ = true;
  47.434 +    if (!set_.init(16))
  47.435 +        return false;
  47.436 +    return true;
  47.437 +}
  47.438 +
  47.439 +bool
  47.440 +StringTable::add(Handle<String> name, unsigned *indexp)
  47.441 +{
  47.442 +    if (!initialized_ && !initialize())
  47.443 +        return false;
  47.444 +
  47.445 +    Set::Insert p = set_.findForAdd(*name);
  47.446 +    if (p.found()) {
  47.447 +        *indexp = p->index;
  47.448 +        return true;
  47.449 +    }
  47.450 +
  47.451 +    if (strings_.length() > INT_MAX) {
  47.452 +        ZONE()->reportAllocationOverflow();
  47.453 +        return false;
  47.454 +    }
  47.455 +
  47.456 +    Entry e(name, strings_.length());
  47.457 +    if (!strings_.append(e))
  47.458 +        return false;
  47.459 +
  47.460 +    if (!set_.add(p, e))
  47.461 +        return false;
  47.462 +
  47.463 +    *indexp = e.index;
  47.464 +
  47.465 +    return true;
  47.466 +}
  47.467 +
  47.468 +void
  47.469 +StringTable::accept(VirtualObjectVisitor *visitor)
  47.470 +{
  47.471 +    for (size_t i = 0; i < strings_.length(); i++)
  47.472 +        visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
  47.473 +}
  47.474 +
  47.475 +BytecodeEmitter::BytecodeEmitter()
  47.476 +  : AutoRooted(ZONE()),
  47.477 +    buffer_(inline_buffer_),
  47.478 +    buffer_pos_(buffer_),
  47.479 +    buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
  47.480 +    oom_(false),
  47.481 +    maxStackDepth_(0),
  47.482 +    loopDepth_(0),
  47.483 +    maxLoopDepth_(0)
  47.484 +{
  47.485 +    lastCodePosition_ = 0;
  47.486 +    firstLine_ = 1;
  47.487 +}
  47.488 +
  47.489 +BytecodeEmitter::~BytecodeEmitter()
  47.490 +{
  47.491 +    for (size_t i = 0; i < oopRecords_.length(); i++)
  47.492 +        delete oopRecords_[i];
  47.493 +}
  47.494 +
  47.495 +void
  47.496 +BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
  47.497 +{
  47.498 +    for (size_t i = 0; i < objects_.length(); i++)
  47.499 +        visitor->visit(&objects_[i]);
  47.500 +
  47.501 +    strings_.accept(visitor);
  47.502 +}
  47.503 +
  47.504 +bool
  47.505 +BytecodeEmitter::growBuffer(size_t nbytes)
  47.506 +{
  47.507 +    if (oom_) {
  47.508 +        buffer_pos_ = buffer_;
  47.509 +        return false;
  47.510 +    }
  47.511 +
  47.512 +    size_t newSize = size_t((buffer_end_ - buffer_) * 2);
  47.513 +    if (newSize >= MAX_LENGTH) {
  47.514 +        oom_ = true;
  47.515 +        buffer_pos_ = buffer_;
  47.516 +        ZONE()->reportOutOfMemory();
  47.517 +        return false;
  47.518 +    }
  47.519 +
  47.520 +    bytecode *newBuffer;
  47.521 +    if (buffer_ == inline_buffer_)
  47.522 +        newBuffer = (bytecode *)malloc(newSize);
  47.523 +    else
  47.524 +        newBuffer = (bytecode *)realloc(buffer_, newSize);
  47.525 +
  47.526 +    // If we can't allocate a buffer, reset the buffer to the start and set
  47.527 +    // a flag to indicate out-of-memory.
  47.528 +    if (!newBuffer) {
  47.529 +        oom_ = true;
  47.530 +        buffer_pos_ = buffer_;
  47.531 +        ZONE()->reportOutOfMemory();
  47.532 +        return false;
  47.533 +    }
  47.534 +
  47.535 +    if (buffer_ == inline_buffer_)
  47.536 +        memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
  47.537 +
  47.538 +    buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
  47.539 +    buffer_ = newBuffer;
  47.540 +    buffer_end_ = buffer_ + newSize;
  47.541 +    assert(buffer_pos_ + nbytes < buffer_end_);
  47.542 +
  47.543 +    return true;
  47.544 +}
  47.545 +
  47.546 +void
  47.547 +BytecodeEmitter::recordOops()
  47.548 +{
  47.549 +    OopRecord *record = new OopRecord(oopMap_.length(), position());
  47.550 +
  47.551 +    if (!record->slots.ensure(record->depth)) {
  47.552 +        oom_ = true;
  47.553 +        return;
  47.554 +    }
  47.555 +
  47.556 +    bool hadOops = false;
  47.557 +    for (size_t i = 0; i < oopMap_.length(); i++) {
  47.558 +        bool bit = oopMap_[i];
  47.559 +        record->slots.infallibleAppend(bit);
  47.560 +        hadOops |= bit;
  47.561 +    }
  47.562 +
  47.563 +    if (!hadOops) {
  47.564 +        delete record;
  47.565 +        return;
  47.566 +    }
  47.567 +
  47.568 +    oom_ &= oopRecords_.append(record);
  47.569 +}
  47.570 +
  47.571 +void
  47.572 +BytecodeEmitter::note_position(const SourcePosition &pos)
  47.573 +{
  47.574 +    assert(pos.line > 0);
  47.575 +    assert(unsigned(pos.line) >= firstLine_);
  47.576 +
  47.577 +    unsigned lineDelta = unsigned(pos.line) - firstLine_;
  47.578 +    unsigned pcDelta = unsigned(position()) - lastCodePosition_;
  47.579 +
  47.580 +    sourcemap_.writeUint32(pcDelta);
  47.581 +    sourcemap_.writeUint32(lineDelta);
  47.582 +    sourcemap_.writeUint32(pos.col);
  47.583 +
  47.584 +    lastCodePosition_ = unsigned(position());
  47.585 +}
  47.586 +
  47.587 +void
  47.588 +BytecodeEmitter::getglobal(Symbol *sym)
  47.589 +{
  47.590 +    ensure(OP_GETGLOBAL_LENGTH);
  47.591 +    writeOp(OP_GETGLOBAL);
  47.592 +    writeUint32(addString(sym->name()));
  47.593 +    if (sym->type()->isTraceable())
  47.594 +        markOop(1);
  47.595 +}
  47.596 +void
  47.597 +BytecodeEmitter::setglobal(Symbol *sym)
  47.598 +{
  47.599 +    ensure(OP_SETGLOBAL_LENGTH);
  47.600 +    writeOp(OP_SETGLOBAL);
  47.601 +    writeUint32(addString(sym->name()));
  47.602 +    if (sym->type()->isTraceable())
  47.603 +        markOop(1);
  47.604 +}
  47.605 +
  47.606 +void
  47.607 +BytecodeEmitter::getlocal(VariableSymbol *var)
  47.608 +{
  47.609 +    assert(var->storage() == VariableSymbol::Local);
  47.610 +    ensure(OP_GETLOCAL_LENGTH);
  47.611 +    writeOp(OP_GETLOCAL);
  47.612 +    writeUint32(var->slot());
  47.613 +    if (var->type()->isTraceable())
  47.614 +        markOop(1);
  47.615 +}
  47.616 +
  47.617 +void
  47.618 +BytecodeEmitter::setlocal(VariableSymbol *var)
  47.619 +{
  47.620 +    assert(var->storage() == VariableSymbol::Local);
  47.621 +    ensure(OP_SETLOCAL_LENGTH);
  47.622 +    writeOp(OP_SETLOCAL);
  47.623 +    writeUint32(var->slot());
  47.624 +    if (var->type()->isTraceable())
  47.625 +        markOop(1);
  47.626 +}
  47.627 +
  47.628 +void
  47.629 +BytecodeEmitter::getarg(VariableSymbol *var)
  47.630 +{
  47.631 +    assert(var->storage() == VariableSymbol::Arg);
  47.632 +    ensure(OP_GETARG_LENGTH);
  47.633 +    writeOp(OP_GETARG);
  47.634 +    writeUint32(var->slot());
  47.635 +    if (var->type()->isTraceable())
  47.636 +        markOop(1);
  47.637 +}
  47.638 +
  47.639 +void
  47.640 +BytecodeEmitter::setarg(VariableSymbol *var)
  47.641 +{
  47.642 +    assert(var->storage() == VariableSymbol::Arg);
  47.643 +    ensure(OP_SETARG_LENGTH);
  47.644 +    writeOp(OP_SETARG);
  47.645 +    writeUint32(var->slot());
  47.646 +    if (var->type()->isTraceable())
  47.647 +        markOop(1);
  47.648 +}
  47.649 +
  47.650 +bool
  47.651 +BytecodeEmitter::allocate(VariableSymbol *sym)
  47.652 +{
  47.653 +    assert(sym->isVariable());
  47.654 +    assert(sym->scope()->kind() == Scope::BLOCK);
  47.655 +
  47.656 +    switch (sym->scope()->kind()) {
  47.657 +      case Scope::BLOCK:
  47.658 +      {
  47.659 +        // See overall comment on overflows.
  47.660 +        assert(locals_.length() < UINT_MAX);
  47.661 +        sym->allocate(VariableSymbol::Local, locals_.length());
  47.662 +        if (!locals_.append(sym))
  47.663 +            return false;
  47.664 +        break;
  47.665 +      }
  47.666 +
  47.667 +      default:
  47.668 +        assert(false);
  47.669 +        return false;
  47.670 +    }
  47.671 +
  47.672 +    return true;
  47.673 +}
  47.674 +
  47.675 +void
  47.676 +BytecodeEmitter::newref(VariableSymbol *var)
  47.677 +{
  47.678 +    recordOops();
  47.679 +    if (var->storage() == VariableSymbol::Local) {
  47.680 +        ensure(OP_VARREF_LIFO_LENGTH);
  47.681 +        writeOp(OP_VARREF_LIFO);
  47.682 +    } else {
  47.683 +        assert(var->storage() == VariableSymbol::Arg);
  47.684 +        ensure(OP_ARGREF_LIFO_LENGTH);
  47.685 +        writeOp(OP_ARGREF_LIFO);
  47.686 +    }
  47.687 +    writeUint32(var->slot());
  47.688 +    markOop(1);
  47.689 +}
  47.690 +
  47.691 +Code *
  47.692 +BytecodeEmitter::finish()
  47.693 +{
  47.694 +    stop();
  47.695 +
  47.696 +    Zone *zone = ZONE();
  47.697 +    if (oom() || zone->hasPendingException())
  47.698 +        return NULL;
  47.699 +
  47.700 +    Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
  47.701 +    if (!bytes)
  47.702 +        return NULL;
  47.703 +    memcpy(bytes->raw(), buffer(), length());
  47.704 +
  47.705 +    Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
  47.706 +    if (!objects)
  47.707 +        return NULL;
  47.708 +
  47.709 +    for (size_t i = 0; i < objects_.length(); i++)
  47.710 +        objects->set(zone, i, objects_[i]);
  47.711 +
  47.712 +    // If any stack slots hold gc pointers at potential failure points in the
  47.713 +    // bytecode, record them now. We do this by building a list of tuples;
  47.714 +    // each tuple contains the pc offset, and a bitset containing which stack
  47.715 +    // slots must be scanned by the gc.
  47.716 +    Local<ByteArray> safepoints(zone);
  47.717 +    if (oopRecords_.length()) {
  47.718 +        size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
  47.719 +        size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
  47.720 +        safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
  47.721 +        if (!safepoints)
  47.722 +            return NULL;
  47.723 +
  47.724 +        Address cursor = safepoints->raw();
  47.725 +        for (size_t i = 0; i < oopRecords_.length(); i++) {
  47.726 +            OopRecord *record = oopRecords_[i];
  47.727 +            assert(record->depth <= maxStackDepth());
  47.728 +
  47.729 +            *reinterpret_cast<unsigned *>(cursor) = record->offset;
  47.730 +
  47.731 +            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
  47.732 +            for (unsigned i = 0; i < record->depth; i++)
  47.733 +                bits[i / 8] |= (1 << (i % 8));
  47.734 +
  47.735 +            cursor += bytesPerSafepoint;
  47.736 +        }
  47.737 +
  47.738 +        assert(cursor == safepoints->raw() + gcmapSize);
  47.739 +    }
  47.740 +
  47.741 +    Local<ByteArray> sourcemap(zone);
  47.742 +    if (sourcemap_.length()) {
  47.743 +        sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
  47.744 +        if (!sourcemap)
  47.745 +            return NULL;
  47.746 +
  47.747 +        memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
  47.748 +    }
  47.749 +
  47.750 +    Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
  47.751 +    if (!strings)
  47.752 +        return NULL;
  47.753 +    for (size_t i = 0; i < strings_.stringCount(); i++)
  47.754 +        strings->set(zone, i, strings_.stringAt(i));
  47.755 +
  47.756 +    Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
  47.757 +    if (!locals)
  47.758 +        return NULL;
  47.759 +    for (size_t i = 0; i < locals_.length(); i++)
  47.760 +        locals->set(zone, i, locals_[i]->type());
  47.761 +
  47.762 +    Local<Code> code(zone);
  47.763 +
  47.764 +    code = Code::New(zone,
  47.765 +                     bytes,
  47.766 +                     locals,
  47.767 +                     objects,
  47.768 +                     strings,
  47.769 +                     maxStackDepth(),
  47.770 +                     maxLoopDepth_,
  47.771 +                     safepoints,
  47.772 +                     sourcemap);
  47.773 +
  47.774 +    return code;
  47.775 +}
    48.1 --- a/src/compiler/BytecodeEmitter.h	Mon Jun 10 00:46:29 2013 +0100
    48.2 +++ b/src/compiler/BytecodeEmitter.h	Mon Jun 10 01:04:43 2013 +0100
    48.3 @@ -1,717 +1,717 @@
    48.4 -/* vim: set ts=4 sw=4 tw=99 et:
    48.5 - *
    48.6 - * Copyright (C) 2012 David Anderson
    48.7 - *
    48.8 - * This file is part of JITCraft.
    48.9 - *
   48.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   48.11 - * the terms of the GNU General Public License as published by the Free
   48.12 - * Software Foundation, either version 3 of the License, or (at your option)
   48.13 - * any later version.
   48.14 - * 
   48.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   48.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   48.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   48.18 - *
   48.19 - * You should have received a copy of the GNU General Public License along with
   48.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   48.21 - */
   48.22 -#ifndef _include_bytecode_emitter_h_
   48.23 -#define _include_bytecode_emitter_h_
   48.24 -
   48.25 -#include <assert.h>
   48.26 -#include <limits.h>
   48.27 -#include "../Opcodes.h"
   48.28 -#include "../Handles.h"
   48.29 -#include "../CompactBuffer.h"
   48.30 -#include "../Array.h"
   48.31 -#include "../HashTable.h"
   48.32 -#include "../VirtualObjectVisitor.h"
   48.33 -
   48.34 -namespace ke {
   48.35 -
   48.36 -// An overarching note on overflows: Though we should use CheckedInt, we rely
   48.37 -// on a source-length cap covering all possible overflow checks. As long as
   48.38 -// the source length is capped to INT_MAX, the number of AST nodes will be
   48.39 -// strictly beneath that cap, and so to will most things generated by the
   48.40 -// AST. For example, local and argument counts, number of functions, fields
   48.41 -// in a struct, et cetera. Not everything can be covered by this cap: the
   48.42 -// stack depth, number of bytecodes for example. In these cases we explicitly
   48.43 -// test for overflow of INT_MAX and in other cases we assert.
   48.44 -//
   48.45 -// In the future, we should of course use a checked int wrapper.
   48.46 -
   48.47 -class Type;
   48.48 -class Map;
   48.49 -class ArrayMap;
   48.50 -class Symbol;
   48.51 -class VariableSymbol;
   48.52 -
   48.53 -struct OopRecord
   48.54 -{
   48.55 -    unsigned depth;
   48.56 -    unsigned offset;
   48.57 -    Vector<bool> slots;
   48.58 -
   48.59 -    OopRecord(unsigned length, unsigned offset)
   48.60 -      : depth(length),
   48.61 -        offset(offset)
   48.62 -    {
   48.63 -    }
   48.64 -};
   48.65 -
   48.66 -class StringTable
   48.67 -{
   48.68 -    struct Entry
   48.69 -    {
   48.70 -        String *string;
   48.71 -        unsigned index;
   48.72 -
   48.73 -        Entry()
   48.74 -          : string(NULL),
   48.75 -            index(0)
   48.76 -        {
   48.77 -        }
   48.78 -
   48.79 -        Entry(String *string, unsigned index)
   48.80 -          : string(string),
   48.81 -            index(index)
   48.82 -        {
   48.83 -        }
   48.84 -    };
   48.85 -
   48.86 -    struct Policy
   48.87 -    {
   48.88 -        typedef Entry Payload;
   48.89 -
   48.90 -        static uint32 hash(String *string) {
   48.91 -            return HashPointer(string);
   48.92 -        }
   48.93 -        
   48.94 -        static bool matches(String *key, Entry &e) {
   48.95 -            return key == e.string;
   48.96 -        }
   48.97 -    };
   48.98 -
   48.99 -    typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
  48.100 -
  48.101 -  public:
  48.102 -    StringTable();
  48.103 -    bool initialize();
  48.104 -    void accept(VirtualObjectVisitor *visitor);
  48.105 -
  48.106 -    bool add(Handle<String> name, unsigned *indexp);
  48.107 -    size_t stringCount() const {
  48.108 -        return strings_.length();
  48.109 -    }
  48.110 -    String *stringAt(size_t i) const {
  48.111 -        return strings_[i].string;
  48.112 -    }
  48.113 -
  48.114 -  private:
  48.115 -    Set set_;
  48.116 -    Vector<Entry> strings_;
  48.117 -    bool initialized_;
  48.118 -};
  48.119 -
  48.120 -// The bytecode emitter assists in building Code objects, by emitting opcodes
  48.121 -// and tracking stack information. Since the SemA creates temporary pool/root
  48.122 -// scopes, we cannot use ScopedRoot or PoolObjects. Instead, BCE gets a
  48.123 -// special marking function.
  48.124 -class BytecodeEmitter : public AutoRooted
  48.125 -{
  48.126 -  private:
  48.127 -    bytecode *buffer_;
  48.128 -    bytecode *buffer_pos_;
  48.129 -    bytecode *buffer_end_;
  48.130 -    bytecode inline_buffer_[512];
  48.131 -    bool oom_;
  48.132 -    unsigned maxStackDepth_;
  48.133 -    Vector<bool> oopMap_;
  48.134 -    Vector<OopRecord *> oopRecords_;
  48.135 -    CompactBufferWriter sourcemap_;
  48.136 -    unsigned lastCodePosition_;
  48.137 -    unsigned firstLine_;
  48.138 -    StringTable strings_;
  48.139 -    Vector<Symbol *> locals_;
  48.140 -    Vector<Object *> objects_;
  48.141 -    unsigned loopDepth_;
  48.142 -    unsigned maxLoopDepth_;
  48.143 -
  48.144 -  private:
  48.145 -    // The maximum size of a code object must be such that the distance between
  48.146 -    // two instructions fits into a signed, 31-bit integer. This ensures that
  48.147 -    // all code-bounded buffers (like the number of object literals or
  48.148 -    // safepoints) does not need to be bounds checked. It also means we can add
  48.149 -    // any two offsets and be guaranteed that they don't overflow.
  48.150 -    static const size_t MAX_LENGTH = INT_MAX / 2;
  48.151 -
  48.152 -  private:
  48.153 -    bool growBuffer(size_t bytes);
  48.154 -
  48.155 -    // Checking the return value is not necessary, since the inline buffer is
  48.156 -    // used as a ballast.
  48.157 -    bool ensure(size_t bytes) {
  48.158 -        if (buffer_pos_ + bytes > buffer_end_)
  48.159 -            return growBuffer(bytes);
  48.160 -        return true;
  48.161 -    }
  48.162 -
  48.163 -    void writeUint8(unsigned value) {
  48.164 -        assert(value <= UCHAR_MAX);
  48.165 -        *buffer_pos_++ = value;
  48.166 -    }
  48.167 -    void writeFloat(float value) {
  48.168 -        *(float *)buffer_pos_ = value;
  48.169 -        buffer_pos_ += sizeof(float);
  48.170 -    }
  48.171 -    void writeInt32(int value) {
  48.172 -        *(int *)buffer_pos_ = value;
  48.173 -        buffer_pos_ += sizeof(int);
  48.174 -    }
  48.175 -    void writeUint32(unsigned value) {
  48.176 -        *(unsigned *)buffer_pos_ = value;
  48.177 -        buffer_pos_ += sizeof(unsigned);
  48.178 -    }
  48.179 -    void writeOp(Opcode op) {
  48.180 -        if (oom_)
  48.181 -            return;
  48.182 -
  48.183 -        writeUint8(op);
  48.184 -        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
  48.185 -            oopMap_.pop();
  48.186 -        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
  48.187 -            oopMap_.append(false);
  48.188 -        if (oopMap_.length() > maxStackDepth_)
  48.189 -            maxStackDepth_ = oopMap_.length();
  48.190 -    }
  48.191 -    void writeObject(Object *obj) {
  48.192 -        assert(obj);
  48.193 -
  48.194 -        writeUint32(objects_.length());
  48.195 -        if (!objects_.append(obj))
  48.196 -            oom_ = true;
  48.197 -    }
  48.198 -
  48.199 -    int position() const {
  48.200 -        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
  48.201 -        return int(buffer_pos_ - buffer_);
  48.202 -    }
  48.203 -
  48.204 -  public:
  48.205 -    BytecodeEmitter();
  48.206 -    ~BytecodeEmitter();
  48.207 -
  48.208 -    void accept(VirtualObjectVisitor *visitor);
  48.209 -
  48.210 -    bytecode *buffer() const {
  48.211 -        return buffer_;
  48.212 -    }
  48.213 -    unsigned length() const {
  48.214 -        return unsigned(buffer_pos_ - buffer_);
  48.215 -    }
  48.216 -    bool oom() const {
  48.217 -        return oom_ || sourcemap_.oom();
  48.218 -    }
  48.219 -    unsigned stackDepth() const {
  48.220 -        return oopMap_.length();
  48.221 -    }
  48.222 -    unsigned maxStackDepth() const {
  48.223 -        return maxStackDepth_;
  48.224 -    }
  48.225 -
  48.226 -    void drop(unsigned amt) {
  48.227 -        assert(amt <= stackDepth());
  48.228 -        for (unsigned i = 0; i < amt; i++)
  48.229 -            oopMap_.pop();
  48.230 -    }
  48.231 -
  48.232 -    void note_position(const SourcePosition &pos);
  48.233 -    void setFirstLine(unsigned line) {
  48.234 -        assert(!sourcemap_.length());
  48.235 -        firstLine_ = line;
  48.236 -    }
  48.237 -
  48.238 -  public:
  48.239 -    // A label represents a local control-flow target in the bytecode. A label
  48.240 -    // may be in three states:
  48.241 -    //
  48.242 -    // (1) Empty - the label is not used yet.
  48.243 -    // (2) Pending - the label has incoming jumps, but the actual location of
  48.244 -    //               is not yet known. The list of jumps is threaded through
  48.245 -    //               the four bytes reserved for each emitted jump target. In
  48.246 -    //               this case, the offset field is the location of the most
  48.247 -    //               recently emitted incoming jump.
  48.248 -    // (3) Bound   - the label's position has been pinned.
  48.249 -    //
  48.250 -    // A jump can be emitted to a label in any state. Binding a label
  48.251 -    // immediately backpatches all pending incoming jumps. A label must be
  48.252 -    // bound if it is used.
  48.253 -    class Label
  48.254 -    {
  48.255 -        int offset_ : 31;
  48.256 -        bool bound_ : 1;
  48.257 -
  48.258 -        void setOffset(int offset) {
  48.259 -            offset_ = offset;
  48.260 -            assert(offset_ == offset);
  48.261 -        }
  48.262 -
  48.263 -      public:
  48.264 -        static const int INVALID_OFFSET = -1;
  48.265 -
  48.266 -      public:
  48.267 -        Label()
  48.268 -          : offset_(INVALID_OFFSET),
  48.269 -            bound_(false)
  48.270 -        {
  48.271 -        }
  48.272 -        ~Label()
  48.273 -        {
  48.274 -            assert(bound_ || offset_ == INVALID_OFFSET);
  48.275 -        }
  48.276 -        
  48.277 -        bool bound() const {
  48.278 -            return bound_;
  48.279 -        }
  48.280 -        int offset() const {
  48.281 -            return offset_;
  48.282 -        }
  48.283 -        void bind(int offset) {
  48.284 -            assert(!bound_);
  48.285 -            setOffset(offset);
  48.286 -            bound_ = true;
  48.287 -        }
  48.288 -        int link(int offset) {
  48.289 -            assert(!bound_);
  48.290 -            int old = offset_;
  48.291 -            setOffset(offset);
  48.292 -            return old;
  48.293 -        }
  48.294 -    };
  48.295 -
  48.296 -  private:
  48.297 -    int patchJumpAt(int at, int to) {
  48.298 -        assert(at >= 0 && at < position());
  48.299 -        int old = *(int *)(buffer_ + at + 1);
  48.300 -        *(int *)(buffer_ + at + 1) = (to - at);
  48.301 -        return old;
  48.302 -    }
  48.303 -
  48.304 -    void singleByteOp(Opcode op) {
  48.305 -        assert(OpcodeInfo[op].length == 1);
  48.306 -        ensure(OpcodeInfo[op].length);
  48.307 -        writeOp(op);
  48.308 -    }
  48.309 -
  48.310 -    // Mark a stack slot as having an object pointer.
  48.311 -    void markOop(unsigned depth, bool oop = true) {
  48.312 -        if (oom_)
  48.313 -            return;
  48.314 -        oopMap_[oopMap_.length() - depth] = oop;
  48.315 -    }
  48.316 -    bool getOop(unsigned depth) {
  48.317 -        if (oom_)
  48.318 -            return false;
  48.319 -        return oopMap_[oopMap_.length() - depth];
  48.320 -    }
  48.321 -
  48.322 -    // Mark the current bytecode position as either re-entrant (meaning, it
  48.323 -    // can leave the interpreter or call to another function), or causing GC.
  48.324 -    // This will record which stack slots have objects and associate that
  48.325 -    // information with the current pc.
  48.326 -    void recordOops();
  48.327 -
  48.328 -  public:
  48.329 -    void int_(int value) {
  48.330 -        ensure(OP_INT);
  48.331 -        writeOp(OP_INT);
  48.332 -        writeInt32(value);
  48.333 -    }
  48.334 -    void return_() {
  48.335 -        ensure(OP_RETURN);
  48.336 -        writeOp(OP_RETURN);
  48.337 -    }
  48.338 -    void getlocal(VariableSymbol *var);
  48.339 -    void setlocal(VariableSymbol *var);
  48.340 -    void getarg(VariableSymbol *var);
  48.341 -    void setarg(VariableSymbol *var);
  48.342 -
  48.343 -    void j(Opcode op, Label *label) {
  48.344 -        // Since jumps can skip around the stream, do not try to do anything
  48.345 -        // in a potentially truncated state.
  48.346 -        if (oom())
  48.347 -            return;
  48.348 -
  48.349 -        assert(op == OP_JT || op == OP_JF || op == OP_JUMP ||
  48.350 -               op == OP_CONTINUE || op == OP_BREAK);
  48.351 -        ensure(OP_JUMP_LENGTH);
  48.352 -
  48.353 -        if (label->bound()) {
  48.354 -            // We can immediately emit this jump.
  48.355 -            int distance = label->offset() - position();
  48.356 -            writeOp(op);
  48.357 -            writeInt32(distance);
  48.358 -        } else {
  48.359 -            // We can't emit this jump yet. Add a placeholder.
  48.360 -            int old = label->link(position());
  48.361 -            writeOp(op);
  48.362 -            writeInt32(old);
  48.363 -        }
  48.364 -    }
  48.365 -    void bind(Label *label) {
  48.366 -        if (oom())
  48.367 -            return;
  48.368 -
  48.369 -        assert(!label->bound());
  48.370 -
  48.371 -        int offset = label->offset();
  48.372 -        while (offset != Label::INVALID_OFFSET)
  48.373 -            offset = patchJumpAt(offset, position());
  48.374 -
  48.375 -        label->bind(position());
  48.376 -    }
  48.377 -    void jump(Label *label) {
  48.378 -        j(OP_JUMP, label);
  48.379 -    }
  48.380 -
  48.381 -    void binary(Opcode op) {
  48.382 -        singleByteOp(op);
  48.383 -    }
  48.384 -    void unary(Opcode op) {
  48.385 -        singleByteOp(op);
  48.386 -    }
  48.387 -
  48.388 -    void pop() {
  48.389 -        singleByteOp(OP_POP);
  48.390 -    }
  48.391 -    void stop() {
  48.392 -        singleByteOp(OP_STOP);
  48.393 -    }
  48.394 -    void call(Handle<FunctionType> fun, unsigned argc) {
  48.395 -        recordOops();
  48.396 -
  48.397 -        if (fun->isNative()) {
  48.398 -            ensure(OP_CALLNATIVE_LENGTH);
  48.399 -            writeOp(OP_CALLNATIVE);
  48.400 -            writeUint32(argc);
  48.401 -            drop(argc + 1);
  48.402 -        } else {
  48.403 -            ensure(OP_CALL_LENGTH);
  48.404 -            writeOp(OP_CALL);
  48.405 -            drop(argc + 1);
  48.406 -
  48.407 -            if (fun->returnType()->isVoid())
  48.408 -                drop(1);
  48.409 -            else if (fun->returnType()->isTraceable())
  48.410 -                markOop(1);
  48.411 -        }
  48.412 -    }
  48.413 -
  48.414 -    void getelem(Type *type) {
  48.415 -        singleByteOp(OP_GETELEM);
  48.416 -
  48.417 -        if (type->isTraceable())
  48.418 -            markOop(1);
  48.419 -    }
  48.420 -    void setelem(Type *type) {
  48.421 -        singleByteOp(OP_SETELEM);
  48.422 -    }
  48.423 -
  48.424 -    void getfield(unsigned index, Type *type) {
  48.425 -        ensure(OP_GETFIELD_LENGTH);
  48.426 -        writeOp(OP_GETFIELD);
  48.427 -        writeUint32(index);
  48.428 -
  48.429 -        if (type->isTraceable())
  48.430 -            markOop(1);
  48.431 -    }
  48.432 -    void setfield(unsigned index, Type *type) {
  48.433 -        ensure(OP_SETFIELD_LENGTH);
  48.434 -        writeOp(OP_SETFIELD);
  48.435 -        writeUint32(index);
  48.436 -
  48.437 -        if (type->isTraceable())
  48.438 -            markOop(1);
  48.439 -    }
  48.440 -
  48.441 -    int enterloop() {
  48.442 -        int offset = position();
  48.443 -
  48.444 -        ensure(OP_ENTERLOOP);
  48.445 -        writeOp(OP_ENTERLOOP);
  48.446 -        writeUint8(0);
  48.447 -
  48.448 -        loopDepth_++;
  48.449 -        if (loopDepth_ > maxLoopDepth_)
  48.450 -            maxLoopDepth_ = loopDepth_;
  48.451 -
  48.452 -        return offset;
  48.453 -    }
  48.454 -    void leaveloop() {
  48.455 -        singleByteOp(OP_LEAVELOOP);
  48.456 -
  48.457 -        assert(loopDepth_);
  48.458 -        loopDepth_--;
  48.459 -    }
  48.460 -    void setLoopUsesLifoStack(int pos) {
  48.461 -        assert(pos >= 0 && pos < position());
  48.462 -        assert(*(buffer() + pos) == OP_ENTERLOOP);
  48.463 -        *(buffer() + pos + 1) = 1;
  48.464 -    }
  48.465 -
  48.466 -    void float_(float value) {
  48.467 -        ensure(OP_FLOAT_LENGTH);
  48.468 -        writeOp(OP_FLOAT);
  48.469 -        writeFloat(value);
  48.470 -    }
  48.471 -    void cvt_i2f() {
  48.472 -        singleByteOp(OP_CVT_I2F);
  48.473 -    }
  48.474 -    void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
  48.475 -        assert(op == OP_NEWFIXED ||
  48.476 -               op == OP_NEWEMPTY ||
  48.477 -               op == OP_NEWSIZED);
  48.478 -
  48.479 -        recordOops();
  48.480 -        ensure(OpcodeInfo[op].length);
  48.481 -        writeOp(op);
  48.482 -        writeUint8(tenure);
  48.483 -        writeObject(map);
  48.484 -
  48.485 -        if (op == OP_NEWSIZED)
  48.486 -            drop(map->type()->levels());
  48.487 -
  48.488 -        markOop(1);
  48.489 -    }
  48.490 -    void newstruct(Handle<Map> map, Heap::Tenure tenure) {
  48.491 -        recordOops();
  48.492 -        ensure(OP_NEWSTRUCT_LENGTH);
  48.493 -        writeOp(OP_NEWSTRUCT);
  48.494 -        writeUint8(tenure);
  48.495 -        writeObject(map);
  48.496 -        markOop(1);
  48.497 -    }
  48.498 -    void deparray(ArrayMap *map) {
  48.499 -        recordOops();
  48.500 -        ensure(OP_DEPARRAY_LENGTH);
  48.501 -        writeOp(OP_DEPARRAY);
  48.502 -        writeObject(map);
  48.503 -        markOop(1);
  48.504 -    }
  48.505 -    void savelifo(unsigned slot) {
  48.506 -        ensure(OP_SAVELIFO_LENGTH);
  48.507 -        writeOp(OP_SAVELIFO);
  48.508 -        writeUint32(slot);
  48.509 -    }
  48.510 -    void unwindlifo(unsigned slot) {
  48.511 -        ensure(OP_UNWINDLIFO_LENGTH);
  48.512 -        writeOp(OP_UNWINDLIFO);
  48.513 -        writeUint32(slot);
  48.514 -    }
  48.515 -
  48.516 -    void newref(VariableSymbol *var);
  48.517 -
  48.518 -    void slotref_lifo() {
  48.519 -        recordOops();
  48.520 -        singleByteOp(OP_SLOTREF_LIFO);
  48.521 -        markOop(1);
  48.522 -    }
  48.523 -    void getref(Type *type) {
  48.524 -        if (type->pod() == PrimitiveType_Int32) {
  48.525 -            singleByteOp(OP_GETREF_I);
  48.526 -        } else {
  48.527 -            assert(type->pod() == PrimitiveType_Float);
  48.528 -            singleByteOp(OP_GETREF_F);
  48.529 -        }
  48.530 -    }
  48.531 -    void setref(Type *type) {
  48.532 -        if (type->pod() == PrimitiveType_Int32) {
  48.533 -            singleByteOp(OP_SETREF_I);
  48.534 -        } else {
  48.535 -            assert(type->pod() == PrimitiveType_Float);
  48.536 -            singleByteOp(OP_SETREF_F);
  48.537 -        }
  48.538 -    }
  48.539 -    void object(Handle<Object> obj) {
  48.540 -        assert(obj);
  48.541 -
  48.542 -        ensure(OP_OBJECT_LENGTH);
  48.543 -        writeOp(OP_OBJECT);
  48.544 -        writeObject(obj);
  48.545 -        markOop(1);
  48.546 -    }
  48.547 -    void duparray() {
  48.548 -        singleByteOp(OP_DUPARRAY);
  48.549 -        markOop(1);
  48.550 -    }
  48.551 -    void copyarray() {
  48.552 -        singleByteOp(OP_COPYARRAY);
  48.553 -        markOop(1);
  48.554 -    }
  48.555 -    void copystruct() {
  48.556 -        singleByteOp(OP_COPYSTRUCT);
  48.557 -        markOop(1);
  48.558 -    }
  48.559 -    void sizeof_() {
  48.560 -        singleByteOp(OP_SIZEOF);
  48.561 -    }
  48.562 -
  48.563 -    void dup() {
  48.564 -        bool oop = getOop(1);
  48.565 -        singleByteOp(OP_DUP);
  48.566 -        markOop(1, oop);
  48.567 -    }
  48.568 -    void dup2() {
  48.569 -        bool oop2 = getOop(2);
  48.570 -        bool oop1 = getOop(1);
  48.571 -
  48.572 -        singleByteOp(OP_DUP2);
  48.573 -
  48.574 -        markOop(2, oop2);
  48.575 -        markOop(1, oop1);
  48.576 -    }
  48.577 -    void swap() {
  48.578 -        bool oop2 = getOop(2);
  48.579 -        bool oop1 = getOop(1);
  48.580 -
  48.581 -        singleByteOp(OP_SWAP);
  48.582 -
  48.583 -        markOop(2, oop1);
  48.584 -        markOop(1, oop2);
  48.585 -    }
  48.586 -    void roll3() {
  48.587 -        bool oop3 = getOop(3);
  48.588 -        bool oop2 = getOop(2);
  48.589 -        bool oop1 = getOop(1);
  48.590 -
  48.591 -        singleByteOp(OP_ROLL3);
  48.592 -
  48.593 -        markOop(3, oop2);
  48.594 -        markOop(2, oop1);
  48.595 -        markOop(1, oop3);
  48.596 -    }
  48.597 -    void pick2() {
  48.598 -        bool oop2 = getOop(2);
  48.599 -        bool oop1 = getOop(1);
  48.600 -
  48.601 -        singleByteOp(OP_PICK2);
  48.602 -
  48.603 -        markOop(3, oop2);
  48.604 -        markOop(2, oop1);
  48.605 -        markOop(1, oop2);
  48.606 -    }
  48.607 -    void pick3() {
  48.608 -        bool oop3 = getOop(3);
  48.609 -        bool oop2 = getOop(2);
  48.610 -        bool oop1 = getOop(1);
  48.611 -
  48.612 -        singleByteOp(OP_PICK3);
  48.613 -
  48.614 -        markOop(4, oop3);
  48.615 -        markOop(3, oop2);
  48.616 -        markOop(2, oop1);
  48.617 -        markOop(1, oop3);
  48.618 -    }
  48.619 -
  48.620 -    void returnvoid() {
  48.621 -        singleByteOp(OP_RETURNVOID);
  48.622 -    }
  48.623 -    void bitnot() {
  48.624 -        singleByteOp(OP_BITNOT);
  48.625 -    }
  48.626 -    void not_() {
  48.627 -        singleByteOp(OP_NOT);
  48.628 -    }
  48.629 -    void not_f() {
  48.630 -        singleByteOp(OP_NOT_F);
  48.631 -    }
  48.632 -    void neg() {
  48.633 -        singleByteOp(OP_NEG);
  48.634 -    }
  48.635 -    void neg_f() {
  48.636 -        singleByteOp(OP_NEG_F);
  48.637 -    }
  48.638 -    void true_() {
  48.639 -        singleByteOp(OP_TRUE);
  48.640 -    }
  48.641 -    void false_() {
  48.642 -        singleByteOp(OP_FALSE);
  48.643 -    }
  48.644 -    
  48.645 -    unsigned addString(Handle<String> name) {
  48.646 -        unsigned index;
  48.647 -        if (!strings_.add(name, &index)) {
  48.648 -            oom_ |= true;
  48.649 -            return 0;
  48.650 -        }
  48.651 -        return index;
  48.652 -    }
  48.653 -
  48.654 -    void getglobal(Symbol *sym);
  48.655 -    void setglobal(Symbol *sym);
  48.656 -
  48.657 -    void public_() {
  48.658 -        recordOops();
  48.659 -        singleByteOp(OP_PUBLIC);
  48.660 -    }
  48.661 -
  48.662 -    void bitcast(Type *type) {
  48.663 -        ensure(OP_BITCAST_LENGTH);
  48.664 -        writeOp(OP_BITCAST);
  48.665 -        writeObject(type);
  48.666 -    }
  48.667 -
  48.668 -    void tableswitch(int low, int high, Label *def, Label **labels) {
  48.669 -        unsigned tablesize = TableSwitchEntries(low, high);
  48.670 -        assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
  48.671 -
  48.672 -        ensure(OP_TABLESWITCH_LENGTH);
  48.673 -        writeOp(OP_TABLESWITCH);
  48.674 -        writeInt32(low);
  48.675 -        writeInt32(high);
  48.676 -        jump(def);
  48.677 -
  48.678 -        // When labels are patched, we assume each position is a jump. Rather
  48.679 -        // than hack position offsets to make labels work without actual
  48.680 -        // incoming jumps, we emit a jump inline.
  48.681 -        for (unsigned i = 0; i < tablesize; i++)
  48.682 -            jump(labels[i]);
  48.683 -    }
  48.684 -
  48.685 -    void import(unsigned index) {
  48.686 -        ensure(OP_IMPORT_LENGTH);
  48.687 -        writeOp(OP_IMPORT);
  48.688 -        writeUint32(index);
  48.689 -        markOop(1);
  48.690 -    }
  48.691 -
  48.692 -    bool allocate(VariableSymbol *sym);
  48.693 -
  48.694 -    Code *finish();
  48.695 -
  48.696 -    // Helpers.
  48.697 -#if 0
  48.698 -    void get(Variable *var) {
  48.699 -        if (var->location() == Variable::STACK) {
  48.700 -            getlocal(var);
  48.701 -        } else {
  48.702 -            assert(var->location() == Variable::PARAMETER);
  48.703 -            getarg(var);
  48.704 -        }
  48.705 -    }
  48.706 -    void set(Variable *var) {
  48.707 -        assert(!var->type()->isReference());
  48.708 -        if (var->location() == Variable::STACK) {
  48.709 -            setlocal(var);
  48.710 -        } else {
  48.711 -            assert(var->location() == Variable::PARAMETER);
  48.712 -            setarg(var);
  48.713 -        }
  48.714 -    }
  48.715 -#endif
  48.716 -};
  48.717 -
  48.718 -}
  48.719 -
  48.720 -#endif // _include_bytecode_emitter_h_
  48.721 +/* vim: set ts=4 sw=4 tw=99 et:
  48.722 + *
  48.723 + * Copyright (C) 2012 David Anderson
  48.724 + *
  48.725 + * This file is part of JITCraft.
  48.726 + *
  48.727 + * JITCraft is free software: you can redistribute it and/or modify it under
  48.728 + * the terms of the GNU General Public License as published by the Free
  48.729 + * Software Foundation, either version 3 of the License, or (at your option)
  48.730 + * any later version.
  48.731 + * 
  48.732 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  48.733 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  48.734 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  48.735 + *
  48.736 + * You should have received a copy of the GNU General Public License along with
  48.737 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  48.738 + */
  48.739 +#ifndef _include_bytecode_emitter_h_
  48.740 +#define _include_bytecode_emitter_h_
  48.741 +
  48.742 +#include <assert.h>
  48.743 +#include <limits.h>
  48.744 +#include "../Opcodes.h"
  48.745 +#include "../Handles.h"
  48.746 +#include "../CompactBuffer.h"
  48.747 +#include "../Array.h"
  48.748 +#include "../HashTable.h"
  48.749 +#include "../VirtualObjectVisitor.h"
  48.750 +
  48.751 +namespace ke {
  48.752 +
  48.753 +// An overarching note on overflows: Though we should use CheckedInt, we rely
  48.754 +// on a source-length cap covering all possible overflow checks. As long as
  48.755 +// the source length is capped to INT_MAX, the number of AST nodes will be
  48.756 +// strictly beneath that cap, and so to will most things generated by the
  48.757 +// AST. For example, local and argument counts, number of functions, fields
  48.758 +// in a struct, et cetera. Not everything can be covered by this cap: the
  48.759 +// stack depth, number of bytecodes for example. In these cases we explicitly
  48.760 +// test for overflow of INT_MAX and in other cases we assert.
  48.761 +//
  48.762 +// In the future, we should of course use a checked int wrapper.
  48.763 +
  48.764 +class Type;
  48.765 +class Map;
  48.766 +class ArrayMap;
  48.767 +class Symbol;
  48.768 +class VariableSymbol;
  48.769 +
  48.770 +struct OopRecord
  48.771 +{
  48.772 +    unsigned depth;
  48.773 +    unsigned offset;
  48.774 +    Vector<bool> slots;
  48.775 +
  48.776 +    OopRecord(unsigned length, unsigned offset)
  48.777 +      : depth(length),
  48.778 +        offset(offset)
  48.779 +    {
  48.780 +    }
  48.781 +};
  48.782 +
  48.783 +class StringTable
  48.784 +{
  48.785 +    struct Entry
  48.786 +    {
  48.787 +        String *string;
  48.788 +        unsigned index;
  48.789 +
  48.790 +        Entry()
  48.791 +          : string(NULL),
  48.792 +            index(0)
  48.793 +        {
  48.794 +        }
  48.795 +
  48.796 +        Entry(String *string, unsigned index)
  48.797 +          : string(string),
  48.798 +            index(index)
  48.799 +        {
  48.800 +        }
  48.801 +    };
  48.802 +
  48.803 +    struct Policy
  48.804 +    {
  48.805 +        typedef Entry Payload;
  48.806 +
  48.807 +        static uint32 hash(String *string) {
  48.808 +            return HashPointer(string);
  48.809 +        }
  48.810 +        
  48.811 +        static bool matches(String *key, Entry &e) {
  48.812 +            return key == e.string;
  48.813 +        }
  48.814 +    };
  48.815 +
  48.816 +    typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
  48.817 +
  48.818 +  public:
  48.819 +    StringTable();
  48.820 +    bool initialize();
  48.821 +    void accept(VirtualObjectVisitor *visitor);
  48.822 +
  48.823 +    bool add(Handle<String> name, unsigned *indexp);
  48.824 +    size_t stringCount() const {
  48.825 +        return strings_.length();
  48.826 +    }
  48.827 +    String *stringAt(size_t i) const {
  48.828 +        return strings_[i].string;
  48.829 +    }
  48.830 +
  48.831 +  private:
  48.832 +    Set set_;
  48.833 +    Vector<Entry> strings_;
  48.834 +    bool initialized_;
  48.835 +};
  48.836 +
  48.837 +// The bytecode emitter assists in building Code objects, by emitting opcodes
  48.838 +// and tracking stack information. Since the SemA creates temporary pool/root
  48.839 +// scopes, we cannot use ScopedRoot or PoolObjects. Instead, BCE gets a
  48.840 +// special marking function.
  48.841 +class BytecodeEmitter : public AutoRooted
  48.842 +{
  48.843 +  private:
  48.844 +    bytecode *buffer_;
  48.845 +    bytecode *buffer_pos_;
  48.846 +    bytecode *buffer_end_;
  48.847 +    bytecode inline_buffer_[512];
  48.848 +    bool oom_;
  48.849 +    unsigned maxStackDepth_;
  48.850 +    Vector<bool> oopMap_;
  48.851 +    Vector<OopRecord *> oopRecords_;
  48.852 +    CompactBufferWriter sourcemap_;
  48.853 +    unsigned lastCodePosition_;
  48.854 +    unsigned firstLine_;
  48.855 +    StringTable strings_;
  48.856 +    Vector<Symbol *> locals_;
  48.857 +    Vector<Object *> objects_;
  48.858 +    unsigned loopDepth_;
  48.859 +    unsigned maxLoopDepth_;
  48.860 +
  48.861 +  private:
  48.862 +    // The maximum size of a code object must be such that the distance between
  48.863 +    // two instructions fits into a signed, 31-bit integer. This ensures that
  48.864 +    // all code-bounded buffers (like the number of object literals or
  48.865 +    // safepoints) does not need to be bounds checked. It also means we can add
  48.866 +    // any two offsets and be guaranteed that they don't overflow.
  48.867 +    static const size_t MAX_LENGTH = INT_MAX / 2;
  48.868 +
  48.869 +  private:
  48.870 +    bool growBuffer(size_t bytes);
  48.871 +
  48.872 +    // Checking the return value is not necessary, since the inline buffer is
  48.873 +    // used as a ballast.
  48.874 +    bool ensure(size_t bytes) {
  48.875 +        if (buffer_pos_ + bytes > buffer_end_)
  48.876 +            return growBuffer(bytes);
  48.877 +        return true;
  48.878 +    }
  48.879 +
  48.880 +    void writeUint8(unsigned value) {
  48.881 +        assert(value <= UCHAR_MAX);
  48.882 +        *buffer_pos_++ = value;
  48.883 +    }
  48.884 +    void writeFloat(float value) {
  48.885 +        *(float *)buffer_pos_ = value;
  48.886 +        buffer_pos_ += sizeof(float);
  48.887 +    }
  48.888 +    void writeInt32(int value) {
  48.889 +        *(int *)buffer_pos_ = value;
  48.890 +        buffer_pos_ += sizeof(int);
  48.891 +    }
  48.892 +    void writeUint32(unsigned value) {
  48.893 +        *(unsigned *)buffer_pos_ = value;
  48.894 +        buffer_pos_ += sizeof(unsigned);
  48.895 +    }
  48.896 +    void writeOp(Opcode op) {
  48.897 +        if (oom_)
  48.898 +            return;
  48.899 +
  48.900 +        writeUint8(op);
  48.901 +        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
  48.902 +            oopMap_.pop();
  48.903 +        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
  48.904 +            oopMap_.append(false);
  48.905 +        if (oopMap_.length() > maxStackDepth_)
  48.906 +            maxStackDepth_ = oopMap_.length();
  48.907 +    }
  48.908 +    void writeObject(Object *obj) {
  48.909 +        assert(obj);
  48.910 +
  48.911 +        writeUint32(objects_.length());
  48.912 +        if (!objects_.append(obj))
  48.913 +            oom_ = true;
  48.914 +    }
  48.915 +
  48.916 +    int position() const {
  48.917 +        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
  48.918 +        return int(buffer_pos_ - buffer_);
  48.919 +    }
  48.920 +
  48.921 +  public:
  48.922 +    BytecodeEmitter();
  48.923 +    ~BytecodeEmitter();
  48.924 +
  48.925 +    void accept(VirtualObjectVisitor *visitor);
  48.926 +
  48.927 +    bytecode *buffer() const {
  48.928 +        return buffer_;
  48.929 +    }
  48.930 +    unsigned length() const {
  48.931 +        return unsigned(buffer_pos_ - buffer_);
  48.932 +    }
  48.933 +    bool oom() const {
  48.934 +        return oom_ || sourcemap_.oom();
  48.935 +    }
  48.936 +    unsigned stackDepth() const {
  48.937 +        return oopMap_.length();
  48.938 +    }
  48.939 +    unsigned maxStackDepth() const {
  48.940 +        return maxStackDepth_;
  48.941 +    }
  48.942 +
  48.943 +    void drop(unsigned amt) {
  48.944 +        assert(amt <= stackDepth());
  48.945 +        for (unsigned i = 0; i < amt; i++)
  48.946 +            oopMap_.pop();
  48.947 +    }
  48.948 +
  48.949 +    void note_position(const SourcePosition &pos);
  48.950 +    void setFirstLine(unsigned line) {
  48.951 +        assert(!sourcemap_.length());
  48.952 +        firstLine_ = line;
  48.953 +    }
  48.954 +
  48.955 +  public:
  48.956 +    // A label represents a local control-flow target in the bytecode. A label
  48.957 +    // may be in three states:
  48.958 +    //
  48.959 +    // (1) Empty - the label is not used yet.
  48.960 +    // (2) Pending - the label has incoming jumps, but the actual location of
  48.961 +    //               is not yet known. The list of jumps is threaded through
  48.962 +    //               the four bytes reserved for each emitted jump target. In
  48.963 +    //               this case, the offset field is the location of the most
  48.964 +    //               recently emitted incoming jump.
  48.965 +    // (3) Bound   - the label's position has been pinned.
  48.966 +    //
  48.967 +    // A jump can be emitted to a label in any state. Binding a label
  48.968 +    // immediately backpatches all pending incoming jumps. A label must be
  48.969 +    // bound if it is used.
  48.970 +    class Label
  48.971 +    {
  48.972 +        int offset_ : 31;
  48.973 +        bool bound_ : 1;
  48.974 +
  48.975 +        void setOffset(int offset) {
  48.976 +            offset_ = offset;
  48.977 +            assert(offset_ == offset);
  48.978 +        }
  48.979 +
  48.980 +      public:
  48.981 +        static const int INVALID_OFFSET = -1;
  48.982 +
  48.983 +      public:
  48.984 +        Label()
  48.985 +          : offset_(INVALID_OFFSET),
  48.986 +            bound_(false)
  48.987 +        {
  48.988 +        }
  48.989 +        ~Label()
  48.990 +        {
  48.991 +            assert(bound_ || offset_ == INVALID_OFFSET);
  48.992 +        }
  48.993 +        
  48.994 +        bool bound() const {
  48.995 +            return bound_;
  48.996 +        }
  48.997 +        int offset() const {
  48.998 +            return offset_;
  48.999 +        }
 48.1000 +        void bind(int offset) {
 48.1001 +            assert(!bound_);
 48.1002 +            setOffset(offset);
 48.1003 +            bound_ = true;
 48.1004 +        }
 48.1005 +        int link(int offset) {
 48.1006 +            assert(!bound_);
 48.1007 +            int old = offset_;
 48.1008 +            setOffset(offset);
 48.1009 +            return old;
 48.1010 +        }
 48.1011 +    };
 48.1012 +
 48.1013 +  private:
 48.1014 +    int patchJumpAt(int at, int to) {
 48.1015 +        assert(at >= 0 && at < position());
 48.1016 +        int old = *(int *)(buffer_ + at + 1);
 48.1017 +        *(int *)(buffer_ + at + 1) = (to - at);
 48.1018 +        return old;
 48.1019 +    }
 48.1020 +
 48.1021 +    void singleByteOp(Opcode op) {
 48.1022 +        assert(OpcodeInfo[op].length == 1);
 48.1023 +        ensure(OpcodeInfo[op].length);
 48.1024 +        writeOp(op);
 48.1025 +    }
 48.1026 +
 48.1027 +    // Mark a stack slot as having an object pointer.
 48.1028 +    void markOop(unsigned depth, bool oop = true) {
 48.1029 +        if (oom_)
 48.1030 +            return;
 48.1031 +        oopMap_[oopMap_.length() - depth] = oop;
 48.1032 +    }
 48.1033 +    bool getOop(unsigned depth) {
 48.1034 +        if (oom_)
 48.1035 +            return false;
 48.1036 +        return oopMap_[oopMap_.length() - depth];
 48.1037 +    }
 48.1038 +
 48.1039 +    // Mark the current bytecode position as either re-entrant (meaning, it
 48.1040 +    // can leave the interpreter or call to another function), or causing GC.
 48.1041 +    // This will record which stack slots have objects and associate that
 48.1042 +    // information with the current pc.
 48.1043 +    void recordOops();
 48.1044 +
 48.1045 +  public:
 48.1046 +    void int_(int value) {
 48.1047 +        ensure(OP_INT);
 48.1048 +        writeOp(OP_INT);
 48.1049 +        writeInt32(value);
 48.1050 +    }
 48.1051 +    void return_() {
 48.1052 +        ensure(OP_RETURN);
 48.1053 +        writeOp(OP_RETURN);
 48.1054 +    }
 48.1055 +    void getlocal(VariableSymbol *var);
 48.1056 +    void setlocal(VariableSymbol *var);
 48.1057 +    void getarg(VariableSymbol *var);
 48.1058 +    void setarg(VariableSymbol *var);
 48.1059 +
 48.1060 +    void j(Opcode op, Label *label) {
 48.1061 +        // Since jumps can skip around the stream, do not try to do anything
 48.1062 +        // in a potentially truncated state.
 48.1063 +        if (oom())
 48.1064 +            return;
 48.1065 +
 48.1066 +        assert(op == OP_JT || op == OP_JF || op == OP_JUMP ||
 48.1067 +               op == OP_CONTINUE || op == OP_BREAK);
 48.1068 +        ensure(OP_JUMP_LENGTH);
 48.1069 +
 48.1070 +        if (label->bound()) {
 48.1071 +            // We can immediately emit this jump.
 48.1072 +            int distance = label->offset() - position();
 48.1073 +            writeOp(op);
 48.1074 +            writeInt32(distance);
 48.1075 +        } else {
 48.1076 +            // We can't emit this jump yet. Add a placeholder.
 48.1077 +            int old = label->link(position());
 48.1078 +            writeOp(op);
 48.1079 +            writeInt32(old);
 48.1080 +        }
 48.1081 +    }
 48.1082 +    void bind(Label *label) {
 48.1083 +        if (oom())
 48.1084 +            return;
 48.1085 +
 48.1086 +        assert(!label->bound());
 48.1087 +
 48.1088 +        int offset = label->offset();
 48.1089 +        while (offset != Label::INVALID_OFFSET)
 48.1090 +            offset = patchJumpAt(offset, position());
 48.1091 +
 48.1092 +        label->bind(position());
 48.1093 +    }
 48.1094 +    void jump(Label *label) {
 48.1095 +        j(OP_JUMP, label);
 48.1096 +    }
 48.1097 +
 48.1098 +    void binary(Opcode op) {
 48.1099 +        singleByteOp(op);
 48.1100 +    }
 48.1101 +    void unary(Opcode op) {
 48.1102 +        singleByteOp(op);
 48.1103 +    }
 48.1104 +
 48.1105 +    void pop() {
 48.1106 +        singleByteOp(OP_POP);
 48.1107 +    }
 48.1108 +    void stop() {
 48.1109 +        singleByteOp(OP_STOP);
 48.1110 +    }
 48.1111 +    void call(Handle<FunctionType> fun, unsigned argc) {
 48.1112 +        recordOops();
 48.1113 +
 48.1114 +        if (fun->isNative()) {
 48.1115 +            ensure(OP_CALLNATIVE_LENGTH);
 48.1116 +            writeOp(OP_CALLNATIVE);
 48.1117 +            writeUint32(argc);
 48.1118 +            drop(argc + 1);
 48.1119 +        } else {
 48.1120 +            ensure(OP_CALL_LENGTH);
 48.1121 +            writeOp(OP_CALL);
 48.1122 +            drop(argc + 1);
 48.1123 +
 48.1124 +            if (fun->returnType()->isVoid())
 48.1125 +                drop(1);
 48.1126 +            else if (fun->returnType()->isTraceable())
 48.1127 +                markOop(1);
 48.1128 +        }
 48.1129 +    }
 48.1130 +
 48.1131 +    void getelem(Type *type) {
 48.1132 +        singleByteOp(OP_GETELEM);
 48.1133 +
 48.1134 +        if (type->isTraceable())
 48.1135 +            markOop(1);
 48.1136 +    }
 48.1137 +    void setelem(Type *type) {
 48.1138 +        singleByteOp(OP_SETELEM);
 48.1139 +    }
 48.1140 +
 48.1141 +    void getfield(unsigned index, Type *type) {
 48.1142 +        ensure(OP_GETFIELD_LENGTH);
 48.1143 +        writeOp(OP_GETFIELD);
 48.1144 +        writeUint32(index);
 48.1145 +
 48.1146 +        if (type->isTraceable())
 48.1147 +            markOop(1);
 48.1148 +    }
 48.1149 +    void setfield(unsigned index, Type *type) {
 48.1150 +        ensure(OP_SETFIELD_LENGTH);
 48.1151 +        writeOp(OP_SETFIELD);
 48.1152 +        writeUint32(index);
 48.1153 +
 48.1154 +        if (type->isTraceable())
 48.1155 +            markOop(1);
 48.1156 +    }
 48.1157 +
 48.1158 +    int enterloop() {
 48.1159 +        int offset = position();
 48.1160 +
 48.1161 +        ensure(OP_ENTERLOOP);
 48.1162 +        writeOp(OP_ENTERLOOP);
 48.1163 +        writeUint8(0);
 48.1164 +
 48.1165 +        loopDepth_++;
 48.1166 +        if (loopDepth_ > maxLoopDepth_)
 48.1167 +            maxLoopDepth_ = loopDepth_;
 48.1168 +
 48.1169 +        return offset;
 48.1170 +    }
 48.1171 +    void leaveloop() {
 48.1172 +        singleByteOp(OP_LEAVELOOP);
 48.1173 +
 48.1174 +        assert(loopDepth_);
 48.1175 +        loopDepth_--;
 48.1176 +    }
 48.1177 +    void setLoopUsesLifoStack(int pos) {
 48.1178 +        assert(pos >= 0 && pos < position());
 48.1179 +        assert(*(buffer() + pos) == OP_ENTERLOOP);
 48.1180 +        *(buffer() + pos + 1) = 1;
 48.1181 +    }
 48.1182 +
 48.1183 +    void float_(float value) {
 48.1184 +        ensure(OP_FLOAT_LENGTH);
 48.1185 +        writeOp(OP_FLOAT);
 48.1186 +        writeFloat(value);
 48.1187 +    }
 48.1188 +    void cvt_i2f() {
 48.1189 +        singleByteOp(OP_CVT_I2F);
 48.1190 +    }
 48.1191 +    void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
 48.1192 +        assert(op == OP_NEWFIXED ||
 48.1193 +               op == OP_NEWEMPTY ||
 48.1194 +               op == OP_NEWSIZED);
 48.1195 +
 48.1196 +        recordOops();
 48.1197 +        ensure(OpcodeInfo[op].length);
 48.1198 +        writeOp(op);
 48.1199 +        writeUint8(tenure);
 48.1200 +        writeObject(map);
 48.1201 +
 48.1202 +        if (op == OP_NEWSIZED)
 48.1203 +            drop(map->type()->levels());
 48.1204 +
 48.1205 +        markOop(1);
 48.1206 +    }
 48.1207 +    void newstruct(Handle<Map> map, Heap::Tenure tenure) {
 48.1208 +        recordOops();
 48.1209 +        ensure(OP_NEWSTRUCT_LENGTH);
 48.1210 +        writeOp(OP_NEWSTRUCT);
 48.1211 +        writeUint8(tenure);
 48.1212 +        writeObject(map);
 48.1213 +        markOop(1);
 48.1214 +    }
 48.1215 +    void deparray(ArrayMap *map) {
 48.1216 +        recordOops();
 48.1217 +        ensure(OP_DEPARRAY_LENGTH);
 48.1218 +        writeOp(OP_DEPARRAY);
 48.1219 +        writeObject(map);
 48.1220 +        markOop(1);
 48.1221 +    }
 48.1222 +    void savelifo(unsigned slot) {
 48.1223 +        ensure(OP_SAVELIFO_LENGTH);
 48.1224 +        writeOp(OP_SAVELIFO);
 48.1225 +        writeUint32(slot);
 48.1226 +    }
 48.1227 +    void unwindlifo(unsigned slot) {
 48.1228 +        ensure(OP_UNWINDLIFO_LENGTH);
 48.1229 +        writeOp(OP_UNWINDLIFO);
 48.1230 +        writeUint32(slot);
 48.1231 +    }
 48.1232 +
 48.1233 +    void newref(VariableSymbol *var);
 48.1234 +
 48.1235 +    void slotref_lifo() {
 48.1236 +        recordOops();
 48.1237 +        singleByteOp(OP_SLOTREF_LIFO);
 48.1238 +        markOop(1);
 48.1239 +    }
 48.1240 +    void getref(Type *type) {
 48.1241 +        if (type->pod() == PrimitiveType_Int32) {
 48.1242 +            singleByteOp(OP_GETREF_I);
 48.1243 +        } else {
 48.1244 +            assert(type->pod() == PrimitiveType_Float);
 48.1245 +            singleByteOp(OP_GETREF_F);
 48.1246 +        }
 48.1247 +    }
 48.1248 +    void setref(Type *type) {
 48.1249 +        if (type->pod() == PrimitiveType_Int32) {
 48.1250 +            singleByteOp(OP_SETREF_I);
 48.1251 +        } else {
 48.1252 +            assert(type->pod() == PrimitiveType_Float);
 48.1253 +            singleByteOp(OP_SETREF_F);
 48.1254 +        }
 48.1255 +    }
 48.1256 +    void object(Handle<Object> obj) {
 48.1257 +        assert(obj);
 48.1258 +
 48.1259 +        ensure(OP_OBJECT_LENGTH);
 48.1260 +        writeOp(OP_OBJECT);
 48.1261 +        writeObject(obj);
 48.1262 +        markOop(1);
 48.1263 +    }
 48.1264 +    void duparray() {
 48.1265 +        singleByteOp(OP_DUPARRAY);
 48.1266 +        markOop(1);
 48.1267 +    }
 48.1268 +    void copyarray() {
 48.1269 +        singleByteOp(OP_COPYARRAY);
 48.1270 +        markOop(1);
 48.1271 +    }
 48.1272 +    void copystruct() {
 48.1273 +        singleByteOp(OP_COPYSTRUCT);
 48.1274 +        markOop(1);
 48.1275 +    }
 48.1276 +    void sizeof_() {
 48.1277 +        singleByteOp(OP_SIZEOF);
 48.1278 +    }
 48.1279 +
 48.1280 +    void dup() {
 48.1281 +        bool oop = getOop(1);
 48.1282 +        singleByteOp(OP_DUP);
 48.1283 +        markOop(1, oop);
 48.1284 +    }
 48.1285 +    void dup2() {
 48.1286 +        bool oop2 = getOop(2);
 48.1287 +        bool oop1 = getOop(1);
 48.1288 +
 48.1289 +        singleByteOp(OP_DUP2);
 48.1290 +
 48.1291 +        markOop(2, oop2);
 48.1292 +        markOop(1, oop1);
 48.1293 +    }
 48.1294 +    void swap() {
 48.1295 +        bool oop2 = getOop(2);
 48.1296 +        bool oop1 = getOop(1);
 48.1297 +
 48.1298 +        singleByteOp(OP_SWAP);
 48.1299 +
 48.1300 +        markOop(2, oop1);
 48.1301 +        markOop(1, oop2);
 48.1302 +    }
 48.1303 +    void roll3() {
 48.1304 +        bool oop3 = getOop(3);
 48.1305 +        bool oop2 = getOop(2);
 48.1306 +        bool oop1 = getOop(1);
 48.1307 +
 48.1308 +        singleByteOp(OP_ROLL3);
 48.1309 +
 48.1310 +        markOop(3, oop2);
 48.1311 +        markOop(2, oop1);
 48.1312 +        markOop(1, oop3);
 48.1313 +    }
 48.1314 +    void pick2() {
 48.1315 +        bool oop2 = getOop(2);
 48.1316 +        bool oop1 = getOop(1);
 48.1317 +
 48.1318 +        singleByteOp(OP_PICK2);
 48.1319 +
 48.1320 +        markOop(3, oop2);
 48.1321 +        markOop(2, oop1);
 48.1322 +        markOop(1, oop2);
 48.1323 +    }
 48.1324 +    void pick3() {
 48.1325 +        bool oop3 = getOop(3);
 48.1326 +        bool oop2 = getOop(2);
 48.1327 +        bool oop1 = getOop(1);
 48.1328 +
 48.1329 +        singleByteOp(OP_PICK3);
 48.1330 +
 48.1331 +        markOop(4, oop3);
 48.1332 +        markOop(3, oop2);
 48.1333 +        markOop(2, oop1);
 48.1334 +        markOop(1, oop3);
 48.1335 +    }
 48.1336 +
 48.1337 +    void returnvoid() {
 48.1338 +        singleByteOp(OP_RETURNVOID);
 48.1339 +    }
 48.1340 +    void bitnot() {
 48.1341 +        singleByteOp(OP_BITNOT);
 48.1342 +    }
 48.1343 +    void not_() {
 48.1344 +        singleByteOp(OP_NOT);
 48.1345 +    }
 48.1346 +    void not_f() {
 48.1347 +        singleByteOp(OP_NOT_F);
 48.1348 +    }
 48.1349 +    void neg() {
 48.1350 +        singleByteOp(OP_NEG);
 48.1351 +    }
 48.1352 +    void neg_f() {
 48.1353 +        singleByteOp(OP_NEG_F);
 48.1354 +    }
 48.1355 +    void true_() {
 48.1356 +        singleByteOp(OP_TRUE);
 48.1357 +    }
 48.1358 +    void false_() {
 48.1359 +        singleByteOp(OP_FALSE);
 48.1360 +    }
 48.1361 +    
 48.1362 +    unsigned addString(Handle<String> name) {
 48.1363 +        unsigned index;
 48.1364 +        if (!strings_.add(name, &index)) {
 48.1365 +            oom_ |= true;
 48.1366 +            return 0;
 48.1367 +        }
 48.1368 +        return index;
 48.1369 +    }
 48.1370 +
 48.1371 +    void getglobal(Symbol *sym);
 48.1372 +    void setglobal(Symbol *sym);
 48.1373 +
 48.1374 +    void public_() {
 48.1375 +        recordOops();
 48.1376 +        singleByteOp(OP_PUBLIC);
 48.1377 +    }
 48.1378 +
 48.1379 +    void bitcast(Type *type) {
 48.1380 +        ensure(OP_BITCAST_LENGTH);
 48.1381 +        writeOp(OP_BITCAST);
 48.1382 +        writeObject(type);
 48.1383 +    }
 48.1384 +
 48.1385 +    void tableswitch(int low, int high, Label *def, Label **labels) {
 48.1386 +        unsigned tablesize = TableSwitchEntries(low, high);
 48.1387 +        assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
 48.1388 +
 48.1389 +        ensure(OP_TABLESWITCH_LENGTH);
 48.1390 +        writeOp(OP_TABLESWITCH);
 48.1391 +        writeInt32(low);
 48.1392 +        writeInt32(high);
 48.1393 +        jump(def);
 48.1394 +
 48.1395 +        // When labels are patched, we assume each position is a jump. Rather
 48.1396 +        // than hack position offsets to make labels work without actual
 48.1397 +        // incoming jumps, we emit a jump inline.
 48.1398 +        for (unsigned i = 0; i < tablesize; i++)
 48.1399 +            jump(labels[i]);
 48.1400 +    }
 48.1401 +
 48.1402 +    void import(unsigned index) {
 48.1403 +        ensure(OP_IMPORT_LENGTH);
 48.1404 +        writeOp(OP_IMPORT);
 48.1405 +        writeUint32(index);
 48.1406 +        markOop(1);
 48.1407 +    }
 48.1408 +
 48.1409 +    bool allocate(VariableSymbol *sym);
 48.1410 +
 48.1411 +    Code *finish();
 48.1412 +
 48.1413 +    // Helpers.
 48.1414 +#if 0
 48.1415 +    void get(Variable *var) {
 48.1416 +        if (var->location() == Variable::STACK) {
 48.1417 +            getlocal(var);
 48.1418 +        } else {
 48.1419 +            assert(var->location() == Variable::PARAMETER);
 48.1420 +            getarg(var);
 48.1421 +        }
 48.1422 +    }
 48.1423 +    void set(Variable *var) {
 48.1424 +        assert(!var->type()->isReference());
 48.1425 +        if (var->location() == Variable::STACK) {
 48.1426 +            setlocal(var);
 48.1427 +        } else {
 48.1428 +            assert(var->location() == Variable::PARAMETER);
 48.1429 +            setarg(var);
 48.1430 +        }
 48.1431 +    }
 48.1432 +#endif
 48.1433 +};
 48.1434 +
 48.1435 +}
 48.1436 +
 48.1437 +#endif // _include_bytecode_emitter_h_
    49.1 --- a/src/compiler/CompileContext.h	Mon Jun 10 00:46:29 2013 +0100
    49.2 +++ b/src/compiler/CompileContext.h	Mon Jun 10 01:04:43 2013 +0100
    49.3 @@ -1,170 +1,170 @@
    49.4 -/*
    49.5 - * Copyright (C) 2012 David Anderson
    49.6 - *
    49.7 - * This file is part of SourcePawn.
    49.8 - *
    49.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   49.10 - * the terms of the GNU General Public License as published by the Free
   49.11 - * Software Foundation, either version 3 of the License, or (at your option)
   49.12 - * any later version.
   49.13 - * 
   49.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   49.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   49.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   49.17 - *
   49.18 - * You should have received a copy of the GNU General Public License along with
   49.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   49.20 - */
   49.21 -#ifndef _include_jitcraft_compile_context_h_
   49.22 -#define _include_jitcraft_compile_context_h_
   49.23 -
   49.24 -#include <stdarg.h>
   49.25 -#include <string>
   49.26 -#include "../Messages.h"
   49.27 -#include "../PoolAllocator.h"
   49.28 -#include "../Handles.h"
   49.29 -#include "../Modules.h"
   49.30 -#include "../Packages.h"
   49.31 -
   49.32 -namespace ke {
   49.33 -
   49.34 -class Zone;
   49.35 -class ParseTree;
   49.36 -class String;
   49.37 -class ImportScope;
   49.38 -class GlobalScope;
   49.39 -struct SourcePosition;
   49.40 -struct TranslationUnit;
   49.41 -class ImportStatement;
   49.42 -
   49.43 -struct CompileError
   49.44 -{
   49.45 -    CompileError()
   49.46 -      : message(NULL)
   49.47 -    {
   49.48 -    }
   49.49 -    CompileError(unsigned line, unsigned col, const char *message)
   49.50 -      : line(line),
   49.51 -        col(col),
   49.52 -        message(message)
   49.53 -    {
   49.54 -    }
   49.55 -
   49.56 -    unsigned line;
   49.57 -    unsigned col;
   49.58 -    const char *message;
   49.59 -};
   49.60 -
   49.61 -struct TranslationUnit : public PoolObject
   49.62 -{
   49.63 -    TranslationUnit(Handle<Module> module)
   49.64 -      : tree_(NULL),
   49.65 -        importScope_(NULL),
   49.66 -        globalScope_(NULL),
   49.67 -        module_(module),
   49.68 -        enoughMemory_(true),
   49.69 -        dependencyFailed_(false)
   49.70 -    {
   49.71 -    }
   49.72 -    
   49.73 -    void destroy();
   49.74 -
   49.75 -    ParseTree *tree_;
   49.76 -    PoolList<TranslationUnit *> dependents_;
   49.77 -    ImportScope *importScope_;
   49.78 -    GlobalScope *globalScope_;
   49.79 -    ScopedRoot<Module> module_;
   49.80 -
   49.81 -    ParseTree *tree() const {
   49.82 -        return tree_;
   49.83 -    }
   49.84 -    PoolList<TranslationUnit *> &dependents() {
   49.85 -        return dependents_;
   49.86 -    }
   49.87 -    bool failed() const {
   49.88 -        return errors_.length() ||
   49.89 -               !enoughMemory_ ||
   49.90 -               dependencyFailed_;
   49.91 -    }
   49.92 -    void setImportScope(ImportScope *scope) {
   49.93 -        assert(!importScope_);
   49.94 -        importScope_ = scope;
   49.95 -    }
   49.96 -    void setGlobalScope(GlobalScope *scope) {
   49.97 -        assert(!globalScope_);
   49.98 -        globalScope_ = scope;
   49.99 -    }
  49.100 -    ImportScope *importScope() const {
  49.101 -        return importScope_;
  49.102 -    }
  49.103 -    GlobalScope *globalScope() const {
  49.104 -        return globalScope_;
  49.105 -    }
  49.106 -    Handle<Module> module() {
  49.107 -        return module_;
  49.108 -    }
  49.109 -
  49.110 -    void setDependencyFailed() {
  49.111 -        dependencyFailed_ = true;
  49.112 -    }
  49.113 -    void setOutOfMemory() {
  49.114 -        enoughMemory_ = false;
  49.115 -    }
  49.116 -    void appendError(const char *report, unsigned line, unsigned col) {
  49.117 -        enoughMemory_ |= errors_.append(CompileError(line, col, report));
  49.118 -    }
  49.119 -    const Vector<CompileError> *errors() {
  49.120 -        return &errors_;
  49.121 -    }
  49.122 -
  49.123 -  private:
  49.124 -    bool enoughMemory_;
  49.125 -    bool dependencyFailed_;
  49.126 -    Vector<CompileError> errors_;
  49.127 -};
  49.128 -
  49.129 -class CompileContext
  49.130 -{
  49.131 -    Zone *zone_;
  49.132 -    Vector<TranslationUnit *> units_;
  49.133 -    Vector<TranslationUnit *> unparsed_;
  49.134 -    TranslationUnit *active_;
  49.135 -
  49.136 -  private:
  49.137 -    char *loadSource(Handle<Module> module, size_t *length);
  49.138 -    bool parse(TranslationUnit *unit);
  49.139 -    bool evaluateImports(TranslationUnit *unit);
  49.140 -    bool propagateFailure();
  49.141 -    bool add(Handle<Module> module);
  49.142 -
  49.143 -  public:
  49.144 -    CompileContext(Zone *zone);
  49.145 -    ~CompileContext();
  49.146 -
  49.147 -    bool initialize(Handle<Package> package, const char *name);
  49.148 -    bool compile();
  49.149 -    void enter(TranslationUnit *unit);
  49.150 -    void leave();
  49.151 -
  49.152 -    void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
  49.153 -    void reportError(const SourcePosition &pos, Message msg, ...);
  49.154 -};
  49.155 -
  49.156 -class AutoEnterCompileContext
  49.157 -{
  49.158 -    CompileContext &cc_;
  49.159 -
  49.160 -  public:
  49.161 -    AutoEnterCompileContext(CompileContext &cc, TranslationUnit *unit)
  49.162 -      : cc_(cc)
  49.163 -    {
  49.164 -      cc_.enter(unit);
  49.165 -    }
  49.166 -    ~AutoEnterCompileContext() {
  49.167 -      cc_.leave();
  49.168 -    }
  49.169 -};
  49.170 -
  49.171 -} // namespace ke
  49.172 -
  49.173 -#endif // _include_jitcraft_compile_context_h_
  49.174 +/*
  49.175 + * Copyright (C) 2012 David Anderson
  49.176 + *
  49.177 + * This file is part of SourcePawn.
  49.178 + *
  49.179 + * SourcePawn is free software: you can redistribute it and/or modify it under
  49.180 + * the terms of the GNU General Public License as published by the Free
  49.181 + * Software Foundation, either version 3 of the License, or (at your option)
  49.182 + * any later version.
  49.183 + * 
  49.184 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  49.185 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  49.186 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  49.187 + *
  49.188 + * You should have received a copy of the GNU General Public License along with
  49.189 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  49.190 + */
  49.191 +#ifndef _include_jitcraft_compile_context_h_
  49.192 +#define _include_jitcraft_compile_context_h_
  49.193 +
  49.194 +#include <stdarg.h>
  49.195 +#include <string>
  49.196 +#include "../Messages.h"
  49.197 +#include "../PoolAllocator.h"
  49.198 +#include "../Handles.h"
  49.199 +#include "../Modules.h"
  49.200 +#include "../Packages.h"
  49.201 +
  49.202 +namespace ke {
  49.203 +
  49.204 +class Zone;
  49.205 +class ParseTree;
  49.206 +class String;
  49.207 +class ImportScope;
  49.208 +class GlobalScope;
  49.209 +struct SourcePosition;
  49.210 +struct TranslationUnit;
  49.211 +class ImportStatement;
  49.212 +
  49.213 +struct CompileError
  49.214 +{
  49.215 +    CompileError()
  49.216 +      : message(NULL)
  49.217 +    {
  49.218 +    }
  49.219 +    CompileError(unsigned line, unsigned col, const char *message)
  49.220 +      : line(line),
  49.221 +        col(col),
  49.222 +        message(message)
  49.223 +    {
  49.224 +    }
  49.225 +
  49.226 +    unsigned line;
  49.227 +    unsigned col;
  49.228 +    const char *message;
  49.229 +};
  49.230 +
  49.231 +struct TranslationUnit : public PoolObject
  49.232 +{
  49.233 +    TranslationUnit(Handle<Module> module)
  49.234 +      : tree_(NULL),
  49.235 +        importScope_(NULL),
  49.236 +        globalScope_(NULL),
  49.237 +        module_(module),
  49.238 +        enoughMemory_(true),
  49.239 +        dependencyFailed_(false)
  49.240 +    {
  49.241 +    }
  49.242 +    
  49.243 +    void destroy();
  49.244 +
  49.245 +    ParseTree *tree_;
  49.246 +    PoolList<TranslationUnit *> dependents_;
  49.247 +    ImportScope *importScope_;
  49.248 +    GlobalScope *globalScope_;
  49.249 +    ScopedRoot<Module> module_;
  49.250 +
  49.251 +    ParseTree *tree() const {
  49.252 +        return tree_;
  49.253 +    }
  49.254 +    PoolList<TranslationUnit *> &dependents() {
  49.255 +        return dependents_;
  49.256 +    }
  49.257 +    bool failed() const {
  49.258 +        return errors_.length() ||
  49.259 +               !enoughMemory_ ||
  49.260 +               dependencyFailed_;
  49.261 +    }
  49.262 +    void setImportScope(ImportScope *scope) {
  49.263 +        assert(!importScope_);
  49.264 +        importScope_ = scope;
  49.265 +    }
  49.266 +    void setGlobalScope(GlobalScope *scope) {
  49.267 +        assert(!globalScope_);
  49.268 +        globalScope_ = scope;
  49.269 +    }
  49.270 +    ImportScope *importScope() const {
  49.271 +        return importScope_;
  49.272 +    }
  49.273 +    GlobalScope *globalScope() const {
  49.274 +        return globalScope_;
  49.275 +    }
  49.276 +    Handle<Module> module() {
  49.277 +        return module_;
  49.278 +    }
  49.279 +
  49.280 +    void setDependencyFailed() {
  49.281 +        dependencyFailed_ = true;
  49.282 +    }
  49.283 +    void setOutOfMemory() {
  49.284 +        enoughMemory_ = false;
  49.285 +    }
  49.286 +    void appendError(const char *report, unsigned line, unsigned col) {
  49.287 +        enoughMemory_ |= errors_.append(CompileError(line, col, report));
  49.288 +    }
  49.289 +    const Vector<CompileError> *errors() {
  49.290 +        return &errors_;
  49.291 +    }
  49.292 +
  49.293 +  private:
  49.294 +    bool enoughMemory_;
  49.295 +    bool dependencyFailed_;
  49.296 +    Vector<CompileError> errors_;
  49.297 +};
  49.298 +
  49.299 +class CompileContext
  49.300 +{
  49.301 +    Zone *zone_;
  49.302 +    Vector<TranslationUnit *> units_;
  49.303 +    Vector<TranslationUnit *> unparsed_;
  49.304 +    TranslationUnit *active_;
  49.305 +
  49.306 +  private:
  49.307 +    char *loadSource(Handle<Module> module, size_t *length);
  49.308 +    bool parse(TranslationUnit *unit);
  49.309 +    bool evaluateImports(TranslationUnit *unit);
  49.310 +    bool propagateFailure();
  49.311 +    bool add(Handle<Module> module);
  49.312 +
  49.313 +  public:
  49.314 +    CompileContext(Zone *zone);
  49.315 +    ~CompileContext();
  49.316 +
  49.317 +    bool initialize(Handle<Package> package, const char *name);
  49.318 +    bool compile();
  49.319 +    void enter(TranslationUnit *unit);
  49.320 +    void leave();
  49.321 +
  49.322 +    void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
  49.323 +    void reportError(const SourcePosition &pos, Message msg, ...);
  49.324 +};
  49.325 +
  49.326 +class AutoEnterCompileContext
  49.327 +{
  49.328 +    CompileContext &cc_;
  49.329 +
  49.330 +  public:
  49.331 +    AutoEnterCompileContext(CompileContext &cc, TranslationUnit *unit)
  49.332 +      : cc_(cc)
  49.333 +    {
  49.334 +      cc_.enter(unit);
  49.335 +    }
  49.336 +    ~AutoEnterCompileContext() {
  49.337 +      cc_.leave();
  49.338 +    }
  49.339 +};
  49.340 +
  49.341 +} // namespace ke
  49.342 +
  49.343 +#endif // _include_jitcraft_compile_context_h_
    50.1 --- a/src/compiler/ConstantEvaluator.cpp	Mon Jun 10 00:46:29 2013 +0100
    50.2 +++ b/src/compiler/ConstantEvaluator.cpp	Mon Jun 10 01:04:43 2013 +0100
    50.3 @@ -1,94 +1,94 @@
    50.4 -/* vim: set ts=4 sw=4 tw=99 et:
    50.5 - *
    50.6 - * Copyright (C) 2012 David Anderson
    50.7 - *
    50.8 - * This file is part of SourcePawn.
    50.9 - *
   50.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   50.11 - * the terms of the GNU General Public License as published by the Free
   50.12 - * Software Foundation, either version 3 of the License, or (at your option)
   50.13 - * any later version.
   50.14 - * 
   50.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   50.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   50.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   50.18 - *
   50.19 - * You should have received a copy of the GNU General Public License along with
   50.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   50.21 - */
   50.22 -#include "AST.h"
   50.23 -#include "ConstantEvaluator.h"
   50.24 -#include "../Heap-inl.h"
   50.25 -#include "../Handles-inl.h"
   50.26 -
   50.27 -using namespace ke;
   50.28 -
   50.29 -static inline bool
   50.30 -EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
   50.31 -                        BoxedPrimitive *out)
   50.32 -{
   50.33 -    switch (kind) {
   50.34 -      case TOK_PLUS:
   50.35 -        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
   50.36 -        return true;
   50.37 -
   50.38 -      case TOK_SHL:
   50.39 -        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
   50.40 -        return true;
   50.41 -
   50.42 -      default:
   50.43 -        return false;
   50.44 -    }
   50.45 -}
   50.46 -
   50.47 -static inline bool
   50.48 -EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
   50.49 -{
   50.50 -  switch (kind) {
   50.51 -    case TOK_MINUS:
   50.52 -      *out = BoxedPrimitive::Int(-inner.toInt());
   50.53 -      return true;
   50.54 -
   50.55 -    default:
   50.56 -      return false;
   50.57 -  }
   50.58 -}
   50.59 -
   50.60 -bool
   50.61 -ke::EvaluateForConstant(Expression *expr, BoxedPrimitive *out)
   50.62 -{
   50.63 -    switch (expr->kind()) {
   50.64 -      case AstNode::kBinaryExpression:
   50.65 -      {
   50.66 -        BoxedPrimitive left;
   50.67 -        BoxedPrimitive right;
   50.68 -        BinaryExpression *b = expr->toBinaryExpression();
   50.69 -        if (!EvaluateForConstant(b->left(), &left) ||
   50.70 -            !EvaluateForConstant(b->right(), &right))
   50.71 -        {
   50.72 -            return false;
   50.73 -        }
   50.74 -        return EvaluateBinaryOperation(b->token(), left, right, out);
   50.75 -      }
   50.76 -
   50.77 -      case AstNode::kUnaryExpression:
   50.78 -      {
   50.79 -        BoxedPrimitive inner;
   50.80 -        UnaryExpression *u = expr->toUnaryExpression();
   50.81 -        if (!EvaluateForConstant(u->expression(), &inner))
   50.82 -            return false;
   50.83 -        return EvaluateUnaryOperation(u->token(), inner, out);
   50.84 -      }
   50.85 -
   50.86 -      case AstNode::kBooleanLiteral:
   50.87 -        *out = BoxedPrimitive::Int(expr->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
   50.88 -        return true;
   50.89 -
   50.90 -      case AstNode::kIntegerLiteral:
   50.91 -        *out = BoxedPrimitive::Int(expr->toIntegerLiteral()->value());
   50.92 -        return true;
   50.93 -
   50.94 -      default:
   50.95 -        return false;
   50.96 -    }
   50.97 -}
   50.98 +/* vim: set ts=4 sw=4 tw=99 et:
   50.99 + *
  50.100 + * Copyright (C) 2012 David Anderson
  50.101 + *
  50.102 + * This file is part of SourcePawn.
  50.103 + *
  50.104 + * SourcePawn is free software: you can redistribute it and/or modify it under
  50.105 + * the terms of the GNU General Public License as published by the Free
  50.106 + * Software Foundation, either version 3 of the License, or (at your option)
  50.107 + * any later version.
  50.108 + * 
  50.109 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  50.110 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  50.111 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  50.112 + *
  50.113 + * You should have received a copy of the GNU General Public License along with
  50.114 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  50.115 + */
  50.116 +#include "AST.h"
  50.117 +#include "ConstantEvaluator.h"
  50.118 +#include "../Heap-inl.h"
  50.119 +#include "../Handles-inl.h"
  50.120 +
  50.121 +using namespace ke;
  50.122 +
  50.123 +static inline bool
  50.124 +EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
  50.125 +                        BoxedPrimitive *out)
  50.126 +{
  50.127 +    switch (kind) {
  50.128 +      case TOK_PLUS:
  50.129 +        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
  50.130 +        return true;
  50.131 +
  50.132 +      case TOK_SHL:
  50.133 +        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
  50.134 +        return true;
  50.135 +
  50.136 +      default:
  50.137 +        return false;
  50.138 +    }
  50.139 +}
  50.140 +
  50.141 +static inline bool
  50.142 +EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
  50.143 +{
  50.144 +  switch (kind) {
  50.145 +    case TOK_MINUS:
  50.146 +      *out = BoxedPrimitive::Int(-inner.toInt());
  50.147 +      return true;
  50.148 +
  50.149 +    default:
  50.150 +      return false;
  50.151 +  }
  50.152 +}
  50.153 +
  50.154 +bool
  50.155 +ke::EvaluateForConstant(Expression *expr, BoxedPrimitive *out)
  50.156 +{
  50.157 +    switch (expr->kind()) {
  50.158 +      case AstNode::kBinaryExpression:
  50.159 +      {
  50.160 +        BoxedPrimitive left;
  50.161 +        BoxedPrimitive right;
  50.162 +        BinaryExpression *b = expr->toBinaryExpression();
  50.163 +        if (!EvaluateForConstant(b->left(), &left) ||
  50.164 +            !EvaluateForConstant(b->right(), &right))
  50.165 +        {
  50.166 +            return false;
  50.167 +        }
  50.168 +        return EvaluateBinaryOperation(b->token(), left, right, out);
  50.169 +      }
  50.170 +
  50.171 +      case AstNode::kUnaryExpression:
  50.172 +      {
  50.173 +        BoxedPrimitive inner;
  50.174 +        UnaryExpression *u = expr->toUnaryExpression();
  50.175 +        if (!EvaluateForConstant(u->expression(), &inner))
  50.176 +            return false;
  50.177 +        return EvaluateUnaryOperation(u->token(), inner, out);
  50.178 +      }
  50.179 +
  50.180 +      case AstNode::kBooleanLiteral:
  50.181 +        *out = BoxedPrimitive::Int(expr->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
  50.182 +        return true;
  50.183 +
  50.184 +      case AstNode::kIntegerLiteral:
  50.185 +        *out = BoxedPrimitive::Int(expr->toIntegerLiteral()->value());
  50.186 +        return true;
  50.187 +
  50.188 +      default:
  50.189 +        return false;
  50.190 +    }
  50.191 +}
    51.1 --- a/src/compiler/ConstantEvaluator.h	Mon Jun 10 00:46:29 2013 +0100
    51.2 +++ b/src/compiler/ConstantEvaluator.h	Mon Jun 10 01:04:43 2013 +0100
    51.3 @@ -1,32 +1,32 @@
    51.4 -/* vim: set ts=4 sw=4 tw=99 et:
    51.5 - *
    51.6 - * Copyright (C) 2012 David Anderson
    51.7 - *
    51.8 - * This file is part of SourcePawn.
    51.9 - *
   51.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   51.11 - * the terms of the GNU General Public License as published by the Free
   51.12 - * Software Foundation, either version 3 of the License, or (at your option)
   51.13 - * any later version.
   51.14 - * 
   51.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   51.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   51.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   51.18 - *
   51.19 - * You should have received a copy of the GNU General Public License along with
   51.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   51.21 - */
   51.22 -#ifndef _include_sp2_constant_evaluator_h_
   51.23 -#define _include_sp2_constant_evaluator_h_
   51.24 -
   51.25 -#include "../Types.h"
   51.26 -
   51.27 -namespace ke {
   51.28 -
   51.29 -class Expression;
   51.30 -
   51.31 -bool EvaluateForConstant(Expression *expr, BoxedPrimitive *out);
   51.32 -
   51.33 -}
   51.34 -
   51.35 -#endif // _include_sp2_constant_evaluator_h_
   51.36 +/* vim: set ts=4 sw=4 tw=99 et:
   51.37 + *
   51.38 + * Copyright (C) 2012 David Anderson
   51.39 + *
   51.40 + * This file is part of SourcePawn.
   51.41 + *
   51.42 + * SourcePawn is free software: you can redistribute it and/or modify it under
   51.43 + * the terms of the GNU General Public License as published by the Free
   51.44 + * Software Foundation, either version 3 of the License, or (at your option)
   51.45 + * any later version.
   51.46 + * 
   51.47 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   51.48 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   51.49 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   51.50 + *
   51.51 + * You should have received a copy of the GNU General Public License along with
   51.52 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   51.53 + */
   51.54 +#ifndef _include_sp2_constant_evaluator_h_
   51.55 +#define _include_sp2_constant_evaluator_h_
   51.56 +
   51.57 +#include "../Types.h"
   51.58 +
   51.59 +namespace ke {
   51.60 +
   51.61 +class Expression;
   51.62 +
   51.63 +bool EvaluateForConstant(Expression *expr, BoxedPrimitive *out);
   51.64 +
   51.65 +}
   51.66 +
   51.67 +#endif // _include_sp2_constant_evaluator_h_
    52.1 --- a/src/compiler/HIR.cpp	Mon Jun 10 00:46:29 2013 +0100
    52.2 +++ b/src/compiler/HIR.cpp	Mon Jun 10 01:04:43 2013 +0100
    52.3 @@ -1,556 +1,556 @@
    52.4 -/* vim: set ts=4 sw=4 tw=99 et:
    52.5 - *
    52.6 - * Copyright (C) 2012 David Anderson
    52.7 - *
    52.8 - * This file is part of JITCraft.
    52.9 - *
   52.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   52.11 - * the terms of the GNU General Public License as published by the Free
   52.12 - * Software Foundation, either version 3 of the License, or (at your option)
   52.13 - * any later version.
   52.14 - * 
   52.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   52.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   52.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   52.18 - *
   52.19 - * You should have received a copy of the GNU General Public License along with
   52.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   52.21 - */
   52.22 -#include "AST.h"
   52.23 -#include "HIR.h"
   52.24 -#include "BytecodeEmitter.h"
   52.25 -#include "../Strings.h"
   52.26 -#include "../Heap-inl.h"
   52.27 -#include "../Handles-inl.h"
   52.28 -
   52.29 -using namespace ke;
   52.30 -
   52.31 -class HIRTranslator : public HIRVisitor
   52.32 -{
   52.33 -  public:
   52.34 -    HIRTranslator(Zone *zone, BytecodeEmitter &emitter)
   52.35 -      : zone_(zone),
   52.36 -        emitter_(emitter)
   52.37 -    {
   52.38 -    }
   52.39 -
   52.40 -    void translate(HIR *hir) {
   52.41 -        hir->accept(this);
   52.42 -    }
   52.43 -
   52.44 -    void visitBoolean(HBoolean *hir);
   52.45 -    void visitFloat(HFloat *hir);
   52.46 -    void visitInteger(HInteger *hir);
   52.47 -    void visitArray(HArray *hir);
   52.48 -    void visitCall(HCall *call);
   52.49 -    void visitStore(HStore *store);
   52.50 -    void visitUnary(HUnary *unary);
   52.51 -    void visitBinary(HBinary *binary);
   52.52 -    void visitLocal(HLocal *local);
   52.53 -    void visitGlobal(HGlobal *global);
   52.54 -    void visitConvert(HConvert *convert);
   52.55 -    void visitIndex(HIndex *index);
   52.56 -    void visitField(HField *field);
   52.57 -    void visitPostIncDec(HPostIncDec *hir);
   52.58 -    void visitToRef(HToRef *hir);
   52.59 -    void visitNewDependentArray(HNewDependentArray *hir);
   52.60 -    void visitImport(HImport *import);
   52.61 -
   52.62 -  private:
   52.63 -    Zone *zone_;
   52.64 -    BytecodeEmitter &emitter_;
   52.65 -};
   52.66 -
   52.67 -#define __ emitter_.
   52.68 -
   52.69 -void
   52.70 -HIRTranslator::visitBoolean(HBoolean *hir)
   52.71 -{
   52.72 -    if (hir->value())
   52.73 -        __ true_();
   52.74 -    else
   52.75 -        __ false_();
   52.76 -}
   52.77 -
   52.78 -void
   52.79 -HIRTranslator::visitFloat(HFloat *hir)
   52.80 -{
   52.81 -    __ float_(hir->value());
   52.82 -}
   52.83 -
   52.84 -void
   52.85 -HIRTranslator::visitInteger(HInteger *hir)
   52.86 -{
   52.87 -    __ int_(hir->value());
   52.88 -}
   52.89 -
   52.90 -void
   52.91 -HIRTranslator::visitArray(HArray *hir)
   52.92 -{
   52.93 -    __ object(hir->array());
   52.94 -
   52.95 -    if (hir->duplicate())
   52.96 -        __ duparray(); 
   52.97 -}
   52.98 -
   52.99 -void
  52.100 -HIRTranslator::visitCall(HCall *call)
  52.101 -{
  52.102 -    Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
  52.103 -    
  52.104 -    assert(call->args()->length() == fun->parameters()->length());
  52.105 -
  52.106 -    __ note_position(call->node()->pos());
  52.107 -
  52.108 -    unsigned argc = call->args()->length();
  52.109 -    for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) {
  52.110 -        HIR *hir = call->args()->at(i);
  52.111 -        hir->accept(this);
  52.112 -    }
  52.113 -
  52.114 -    call->callee()->accept(this);
  52.115 -    __ call(fun, argc);
  52.116 -}
  52.117 -
  52.118 -void
  52.119 -HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  52.120 -{
  52.121 -}
  52.122 -
  52.123 -void
  52.124 -HGlobal::hold(BytecodeEmitter &emitter_)
  52.125 -{
  52.126 -}
  52.127 -
  52.128 -void
  52.129 -HGlobal::swapAndPick(BytecodeEmitter &emitter_)
  52.130 -{
  52.131 -    __ dup();
  52.132 -}
  52.133 -
  52.134 -void
  52.135 -HGlobal::store(BytecodeEmitter &emitter_)
  52.136 -{
  52.137 -    __ setglobal(sym_);
  52.138 -}
  52.139 -
  52.140 -void
  52.141 -HGlobal::load(BytecodeEmitter &emitter_)
  52.142 -{
  52.143 -    __ getglobal(sym_);
  52.144 -}
  52.145 -
  52.146 -bool
  52.147 -HGlobal::ref(BytecodeEmitter &emitter_)
  52.148 -{
  52.149 -    return false;
  52.150 -}
  52.151 -
  52.152 -static inline Type *
  52.153 -MaybeDereference(Type *type)
  52.154 -{
  52.155 -    if (type->isReference())
  52.156 -        return ReferenceType::cast(type)->contained();
  52.157 -    return type;
  52.158 -}
  52.159 -
  52.160 -HLocal::HLocal(AstNode *node, VariableSymbol *sym)
  52.161 -  : HLValue(node, MaybeDereference(sym->type())),
  52.162 -    sym_(sym)
  52.163 -{
  52.164 -}
  52.165 -
  52.166 -void
  52.167 -HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  52.168 -{
  52.169 -    if (sym_->type()->isReference()) {
  52.170 -        if (sym_->storage() == VariableSymbol::Local)
  52.171 -            __ getlocal(sym_);
  52.172 -        else if (sym_->storage() == VariableSymbol::Arg)
  52.173 -            __ getarg(sym_);
  52.174 -        else
  52.175 -            assert(false);
  52.176 -    }
  52.177 -}
  52.178 -
  52.179 -void
  52.180 -HLocal::hold(BytecodeEmitter &emitter_)
  52.181 -{
  52.182 -    if (sym_->type()->isReference())
  52.183 -        __ dup();
  52.184 -}
  52.185 -
  52.186 -void
  52.187 -HLocal::swapAndPick(BytecodeEmitter &emitter_)
  52.188 -{
  52.189 -    if (sym_->type()->isReference()) {
  52.190 -        __ swap();
  52.191 -        __ pick2();
  52.192 -    } else {
  52.193 -        __ dup();
  52.194 -    }
  52.195 -}
  52.196 -
  52.197 -void
  52.198 -HLocal::store(BytecodeEmitter &emitter_)
  52.199 -{
  52.200 -    if (sym_->type()->isReference()) {
  52.201 -        __ setref(ReferenceType::cast(sym_->type())->contained());
  52.202 -    } else {
  52.203 -        if (sym_->storage() == VariableSymbol::Local)
  52.204 -            __ setlocal(sym_);
  52.205 -        else if (sym_->storage() == VariableSymbol::Arg)
  52.206 -            __ setarg(sym_);
  52.207 -        else
  52.208 -            assert(false);
  52.209 -    }
  52.210 -}
  52.211 -
  52.212 -void
  52.213 -HLocal::load(BytecodeEmitter &emitter_)
  52.214 -{
  52.215 -    if (sym_->type()->isReference())
  52.216 -        __ getref(ReferenceType::cast(sym_->type())->contained());
  52.217 -    else if (sym_->storage() == VariableSymbol::Local)
  52.218 -        __ getlocal(sym_);
  52.219 -    else if (sym_->storage() == VariableSymbol::Arg)
  52.220 -        __ getarg(sym_);
  52.221 -    else
  52.222 -        assert(false);
  52.223 -}
  52.224 -
  52.225 -bool
  52.226 -HLocal::ref(BytecodeEmitter &emitter_)
  52.227 -{
  52.228 -    if (sym_->storage() == VariableSymbol::Heap) {
  52.229 -        // Closing over a reference should never pass SemA.
  52.230 -        assert(!sym_->type()->isReference());
  52.231 -
  52.232 -        // We don't support direct references to heap-allocated locals. This
  52.233 -        // should probably be banned in SemA? But for now, just assert. :TODO:
  52.234 -        assert(false);
  52.235 -        return false;
  52.236 -    }
  52.237 -        
  52.238 -    if (sym_->type()->isReference()) {
  52.239 -        if (sym_->storage() == VariableSymbol::Local)
  52.240 -            __ getlocal(sym_);
  52.241 -        else if (sym_->storage() == VariableSymbol::Arg)
  52.242 -            __ getarg(sym_);
  52.243 -        else
  52.244 -            assert(false);
  52.245 -    } else {
  52.246 -        __ newref(sym_);
  52.247 -    }
  52.248 -
  52.249 -    return true;
  52.250 -}
  52.251 -
  52.252 -void
  52.253 -HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  52.254 -{
  52.255 -    __ note_position(node()->pos());
  52.256 -    left_->accept(visitor);
  52.257 -    right_->accept(visitor);
  52.258 -}
  52.259 -
  52.260 -void
  52.261 -HIndex::hold(BytecodeEmitter &emitter_)
  52.262 -{
  52.263 -    __ dup2();
  52.264 -}
  52.265 -
  52.266 -void
  52.267 -HIndex::swapAndPick(BytecodeEmitter &emitter_)
  52.268 -{
  52.269 -    // BASE INDEX VALUE
  52.270 -    __ roll3();         // INDEX VALUE BASE
  52.271 -    __ roll3();         // VALUE BASE INDEX
  52.272 -    __ pick3();         // VALUE BASE INDEX VALUE
  52.273 -}
  52.274 -
  52.275 -void
  52.276 -HIndex::store(BytecodeEmitter &emitter_)
  52.277 -{
  52.278 -    __ setelem(type());
  52.279 -}
  52.280 -
  52.281 -void
  52.282 -HIndex::load(BytecodeEmitter &emitter_)
  52.283 -{
  52.284 -    __ getelem(type());
  52.285 -}
  52.286 -
  52.287 -bool
  52.288 -HIndex::ref(BytecodeEmitter &emitter_)
  52.289 -{
  52.290 -    return false;
  52.291 -}
  52.292 -
  52.293 -void
  52.294 -HField::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  52.295 -{
  52.296 -    __ note_position(node()->pos());
  52.297 -    base_->accept(visitor);
  52.298 -}
  52.299 -
  52.300 -void
  52.301 -HField::hold(BytecodeEmitter &emitter_)
  52.302 -{
  52.303 -    __ dup();
  52.304 -}
  52.305 -
  52.306 -void
  52.307 -HField::swapAndPick(BytecodeEmitter &emitter_)
  52.308 -{
  52.309 -    // BASE VALUE
  52.310 -    __ swap();      // VALUE BASE
  52.311 -    __ pick2();     // VALUE BASE VALUE
  52.312 -}
  52.313 -
  52.314 -void
  52.315 -HField::store(BytecodeEmitter &emitter_)
  52.316 -{
  52.317 -    __ setfield(index_, type());
  52.318 -}
  52.319 -
  52.320 -void
  52.321 -HField::load(BytecodeEmitter &emitter_)
  52.322 -{
  52.323 -    __ getfield(index_, type());
  52.324 -}
  52.325 -
  52.326 -bool
  52.327 -HField::ref(BytecodeEmitter &emitter_)
  52.328 -{
  52.329 -    return false;
  52.330 -}
  52.331 -
  52.332 -void
  52.333 -HIRTranslator::visitLocal(HLocal *local)
  52.334 -{
  52.335 -    local->bind(this, emitter_);
  52.336 -    local->load(emitter_);
  52.337 -}
  52.338 -
  52.339 -void
  52.340 -HIRTranslator::visitIndex(HIndex *index)
  52.341 -{
  52.342 -    index->bind(this, emitter_);
  52.343 -    index->load(emitter_);
  52.344 -}
  52.345 -
  52.346 -void
  52.347 -HIRTranslator::visitField(HField *field)
  52.348 -{
  52.349 -    field->bind(this, emitter_);
  52.350 -    field->load(emitter_);
  52.351 -}
  52.352 -
  52.353 -void
  52.354 -HIRTranslator::visitGlobal(HGlobal *global)
  52.355 -{
  52.356 -    global->bind(this, emitter_);
  52.357 -    global->load(emitter_);
  52.358 -}
  52.359 -
  52.360 -static inline Opcode
  52.361 -TokenToOpcode(TokenKind kind)
  52.362 -{
  52.363 -    switch (kind) {
  52.364 -      case TOK_PLUS:
  52.365 -      case TOK_ASSIGN_ADD:
  52.366 -      case TOK_INCREMENT:
  52.367 -        return OP_ADD;
  52.368 -      case TOK_MINUS:
  52.369 -      case TOK_ASSIGN_SUB:
  52.370 -      case TOK_DECREMENT:
  52.371 -        return OP_SUB;
  52.372 -      case TOK_STAR:
  52.373 -      case TOK_ASSIGN_MUL:
  52.374 -        return OP_MUL;
  52.375 -      case TOK_SLASH:
  52.376 -      case TOK_ASSIGN_DIV:
  52.377 -        return OP_DIV;
  52.378 -      case TOK_PERCENT:
  52.379 -      case TOK_ASSIGN_MOD:
  52.380 -        return OP_MOD;
  52.381 -      case TOK_SHR:
  52.382 -      case TOK_ASSIGN_SHR:
  52.383 -        return OP_SHR;
  52.384 -      case TOK_USHR:
  52.385 -      case TOK_ASSIGN_USHR:
  52.386 -        return OP_USHR;
  52.387 -      case TOK_SHL:
  52.388 -      case TOK_ASSIGN_SHL:
  52.389 -        return OP_SHL;
  52.390 -      case TOK_BITAND:
  52.391 -      case TOK_ASSIGN_BITAND:
  52.392 -        return OP_BITAND;
  52.393 -      case TOK_BITOR:
  52.394 -      case TOK_ASSIGN_BITOR:
  52.395 -        return OP_BITOR;
  52.396 -      case TOK_GT:
  52.397 -          return OP_GT;
  52.398 -      case TOK_GE:
  52.399 -          return OP_GE;
  52.400 -      case TOK_LT:
  52.401 -          return OP_LT;
  52.402 -      case TOK_LE:
  52.403 -          return OP_LE;
  52.404 -      case TOK_EQUALS:
  52.405 -          return OP_EQ;
  52.406 -      case TOK_NOTEQUALS:
  52.407 -          return OP_NE;
  52.408 -      default:
  52.409 -        assert(kind == TOK_BITXOR);
  52.410 -        return OP_BITXOR;
  52.411 -    }
  52.412 -}
  52.413 -
  52.414 -void
  52.415 -HIRTranslator::visitStore(HStore *store)
  52.416 -{
  52.417 -    store->lval()->bind(this, emitter_);
  52.418 -
  52.419 -    if (store->kind() == TOK_ASSIGN) {
  52.420 -        // Fixed-length arrays and structs have copy semantics.
  52.421 -        Local<Type> type(zone_, store->lval()->type());
  52.422 -        if (type->isArray() && ArrayType::cast(type)->isFixedLength()) {
  52.423 -            store->lval()->load(emitter_);
  52.424 -            store->rval()->accept(this);
  52.425 -            __ copyarray();
  52.426 -        } else if (type->isStruct()) {
  52.427 -            store->lval()->load(emitter_);
  52.428 -            store->rval()->accept(this);
  52.429 -            __ copystruct();
  52.430 -        } else {
  52.431 -            store->rval()->accept(this);
  52.432 -            store->lval()->store(emitter_);
  52.433 -        }
  52.434 -    } else {
  52.435 -        // Advanced case: dup the ref, load, op, store.
  52.436 -        store->lval()->hold(emitter_);
  52.437 -        store->lval()->load(emitter_);
  52.438 -        store->rval()->accept(this);
  52.439 -        __ binary(TokenToOpcode(store->kind()));
  52.440 -        store->lval()->store(emitter_);
  52.441 -    }
  52.442 -}
  52.443 -
  52.444 -void
  52.445 -HIRTranslator::visitPostIncDec(HPostIncDec *hir)
  52.446 -{
  52.447 -    hir->lval()->bind(this, emitter_);
  52.448 -    hir->lval()->hold(emitter_);
  52.449 -    hir->lval()->load(emitter_);
  52.450 -    hir->lval()->swapAndPick(emitter_);
  52.451 -    hir->rval()->accept(this);
  52.452 -    __ binary(TokenToOpcode(hir->kind()));
  52.453 -    hir->lval()->store(emitter_);
  52.454 -    __ pop();
  52.455 -}
  52.456 -
  52.457 -void
  52.458 -HIRTranslator::visitBinary(HBinary *binary)
  52.459 -{
  52.460 -    binary->left()->accept(this);
  52.461 -    binary->right()->accept(this);
  52.462 -
  52.463 -    // We define three sets of math operators:
  52.464 -    //
  52.465 -    //  (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce
  52.466 -    //      the same type.
  52.467 -    //  (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce
  52.468 -    //      a boolean.
  52.469 -    //  (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two
  52.470 -    //      equal integer types and return that integer type.
  52.471 -    //
  52.472 -    Opcode op = TokenToOpcode(binary->token());
  52.473 -
  52.474 -    if (op == OP_DIV)
  52.475 -        __ note_position(binary->node()->pos());
  52.476 -
  52.477 -    if (op >= OP_ADD && op <= OP_NE) {
  52.478 -        if (binary->type()->isFloat())
  52.479 -            op = Opcode(int(op) + int(OP_ADD_F - OP_ADD));
  52.480 -    } else {
  52.481 -        assert(binary->type()->isInt32());
  52.482 -    }
  52.483 -
  52.484 -    __ binary(op);
  52.485 -}
  52.486 -
  52.487 -void
  52.488 -HIRTranslator::visitUnary(HUnary *unary)
  52.489 -{
  52.490 -    unary->in()->accept(this);
  52.491 -
  52.492 -    switch (unary->token()) {
  52.493 -      case TOK_TILDE:
  52.494 -        __ bitnot();
  52.495 -        break;
  52.496 -
  52.497 -      case TOK_MINUS:
  52.498 -        if (unary->type()->isFloat())
  52.499 -            __ neg_f();
  52.500 -        else
  52.501 -            __ neg();
  52.502 -        break;
  52.503 -
  52.504 -      default:
  52.505 -        assert(unary->token() == TOK_LABEL);
  52.506 -        __ bitcast(unary->type());
  52.507 -        break;
  52.508 -    }
  52.509 -}
  52.510 -
  52.511 -void
  52.512 -HIRTranslator::visitConvert(HConvert *convert)
  52.513 -{
  52.514 -    convert->in()->accept(this);
  52.515 -    __ unary(convert->opcode());
  52.516 -}
  52.517 -
  52.518 -void
  52.519 -HIRTranslator::visitToRef(HToRef *hir)
  52.520 -{
  52.521 -    HIR *in = hir->in();
  52.522 -
  52.523 -    // See if we can bind a direct reference.
  52.524 -    if (in->isLValue() && in->toLValue()->ref(emitter_))
  52.525 -        return;
  52.526 -
  52.527 -    // No, we can't. So instead we create an on-stack reference.
  52.528 -    in->accept(this);
  52.529 -    __ slotref_lifo();
  52.530 -}
  52.531 -
  52.532 -void
  52.533 -HIRTranslator::visitNewDependentArray(HNewDependentArray *hir)
  52.534 -{
  52.535 -    hir->base()->accept(this);
  52.536 -    hir->index()->accept(this);
  52.537 -
  52.538 -    Local<ArrayType> type(zone_, ArrayType::cast(hir->type()));
  52.539 -
  52.540 -    // The dependent map is used for the opcode, but is not attached.
  52.541 -    Local<ArrayMap> map(zone_, ArrayMap::NewDependent(zone_, type));
  52.542 -    if (!map)
  52.543 -        return;
  52.544 -
  52.545 -    __ deparray(map);
  52.546 -}
  52.547 -
  52.548 -void
  52.549 -HIRTranslator::visitImport(HImport *import)
  52.550 -{
  52.551 -    __ import(import->index());
  52.552 -}
  52.553 -
  52.554 -void
  52.555 -ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
  52.556 -{
  52.557 -    HIRTranslator translator(zone, emitter);
  52.558 -    translator.translate(hir);
  52.559 -}
  52.560 +/* vim: set ts=4 sw=4 tw=99 et:
  52.561 + *
  52.562 + * Copyright (C) 2012 David Anderson
  52.563 + *
  52.564 + * This file is part of JITCraft.
  52.565 + *
  52.566 + * JITCraft is free software: you can redistribute it and/or modify it under
  52.567 + * the terms of the GNU General Public License as published by the Free
  52.568 + * Software Foundation, either version 3 of the License, or (at your option)
  52.569 + * any later version.
  52.570 + * 
  52.571 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  52.572 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  52.573 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  52.574 + *
  52.575 + * You should have received a copy of the GNU General Public License along with
  52.576 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  52.577 + */
  52.578 +#include "AST.h"
  52.579 +#include "HIR.h"
  52.580 +#include "BytecodeEmitter.h"
  52.581 +#include "../Strings.h"
  52.582 +#include "../Heap-inl.h"
  52.583 +#include "../Handles-inl.h"
  52.584 +
  52.585 +using namespace ke;
  52.586 +
  52.587 +class HIRTranslator : public HIRVisitor
  52.588 +{
  52.589 +  public:
  52.590 +    HIRTranslator(Zone *zone, BytecodeEmitter &emitter)
  52.591 +      : zone_(zone),
  52.592 +        emitter_(emitter)
  52.593 +    {
  52.594 +    }
  52.595 +
  52.596 +    void translate(HIR *hir) {
  52.597 +        hir->accept(this);
  52.598 +    }
  52.599 +
  52.600 +    void visitBoolean(HBoolean *hir);
  52.601 +    void visitFloat(HFloat *hir);
  52.602 +    void visitInteger(HInteger *hir);
  52.603 +    void visitArray(HArray *hir);
  52.604 +    void visitCall(HCall *call);
  52.605 +    void visitStore(HStore *store);
  52.606 +    void visitUnary(HUnary *unary);
  52.607 +    void visitBinary(HBinary *binary);
  52.608 +    void visitLocal(HLocal *local);
  52.609 +    void visitGlobal(HGlobal *global);
  52.610 +    void visitConvert(HConvert *convert);
  52.611 +    void visitIndex(HIndex *index);
  52.612 +    void visitField(HField *field);
  52.613 +    void visitPostIncDec(HPostIncDec *hir);
  52.614 +    void visitToRef(HToRef *hir);
  52.615 +    void visitNewDependentArray(HNewDependentArray *hir);
  52.616 +    void visitImport(HImport *import);
  52.617 +
  52.618 +  private:
  52.619 +    Zone *zone_;
  52.620 +    BytecodeEmitter &emitter_;
  52.621 +};
  52.622 +
  52.623 +#define __ emitter_.
  52.624 +
  52.625 +void
  52.626 +HIRTranslator::visitBoolean(HBoolean *hir)
  52.627 +{
  52.628 +    if (hir->value())
  52.629 +        __ true_();
  52.630 +    else
  52.631 +        __ false_();
  52.632 +}
  52.633 +
  52.634 +void
  52.635 +HIRTranslator::visitFloat(HFloat *hir)
  52.636 +{
  52.637 +    __ float_(hir->value());
  52.638 +}
  52.639 +
  52.640 +void
  52.641 +HIRTranslator::visitInteger(HInteger *hir)
  52.642 +{
  52.643 +    __ int_(hir->value());
  52.644 +}
  52.645 +
  52.646 +void
  52.647 +HIRTranslator::visitArray(HArray *hir)
  52.648 +{
  52.649 +    __ object(hir->array());
  52.650 +
  52.651 +    if (hir->duplicate())
  52.652 +        __ duparray(); 
  52.653 +}
  52.654 +
  52.655 +void
  52.656 +HIRTranslator::visitCall(HCall *call)
  52.657 +{
  52.658 +    Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
  52.659 +    
  52.660 +    assert(call->args()->length() == fun->parameters()->length());
  52.661 +
  52.662 +    __ note_position(call->node()->pos());
  52.663 +
  52.664 +    unsigned argc = call->args()->length();
  52.665 +    for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) {
  52.666 +        HIR *hir = call->args()->at(i);
  52.667 +        hir->accept(this);
  52.668 +    }
  52.669 +
  52.670 +    call->callee()->accept(this);
  52.671 +    __ call(fun, argc);
  52.672 +}
  52.673 +
  52.674 +void
  52.675 +HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  52.676 +{
  52.677 +}
  52.678 +
  52.679 +void
  52.680 +HGlobal::hold(BytecodeEmitter &emitter_)
  52.681 +{
  52.682 +}
  52.683 +
  52.684 +void
  52.685 +HGlobal::swapAndPick(BytecodeEmitter &emitter_)
  52.686 +{
  52.687 +    __ dup();
  52.688 +}
  52.689 +
  52.690 +void
  52.691 +HGlobal::store(BytecodeEmitter &emitter_)
  52.692 +{
  52.693 +    __ setglobal(sym_);
  52.694 +}
  52.695 +
  52.696 +void
  52.697 +HGlobal::load(BytecodeEmitter &emitter_)
  52.698 +{
  52.699 +    __ getglobal(sym_);
  52.700 +}
  52.701 +
  52.702 +bool
  52.703 +HGlobal::ref(BytecodeEmitter &emitter_)
  52.704 +{
  52.705 +    return false;
  52.706 +}
  52.707 +
  52.708 +static inline Type *
  52.709 +MaybeDereference(Type *type)
  52.710 +{
  52.711 +    if (type->isReference())
  52.712 +        return ReferenceType::cast(type)->contained();
  52.713 +    return type;
  52.714 +}
  52.715 +
  52.716 +HLocal::HLocal(AstNode *node, VariableSymbol *sym)
  52.717 +  : HLValue(node, MaybeDereference(sym->type())),
  52.718 +    sym_(sym)
  52.719 +{
  52.720 +}
  52.721 +
  52.722 +void
  52.723 +HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  52.724 +{
  52.725 +    if (sym_->type()->isReference()) {
  52.726 +        if (sym_->storage() == VariableSymbol::Local)
  52.727 +            __ getlocal(sym_);
  52.728 +        else if (sym_->storage() == VariableSymbol::Arg)
  52.729 +            __ getarg(sym_);
  52.730 +        else
  52.731 +            assert(false);
  52.732 +    }
  52.733 +}
  52.734 +
  52.735 +void
  52.736 +HLocal::hold(BytecodeEmitter &emitter_)
  52.737 +{
  52.738 +    if (sym_->type()->isReference())
  52.739 +        __ dup();
  52.740 +}
  52.741 +
  52.742 +void
  52.743 +HLocal::swapAndPick(BytecodeEmitter &emitter_)
  52.744 +{
  52.745 +    if (sym_->type()->isReference()) {
  52.746 +        __ swap();
  52.747 +        __ pick2();
  52.748 +    } else {
  52.749 +        __ dup();
  52.750 +    }
  52.751 +}
  52.752 +
  52.753 +void
  52.754 +HLocal::store(BytecodeEmitter &emitter_)
  52.755 +{
  52.756 +    if (sym_->type()->isReference()) {
  52.757 +        __ setref(ReferenceType::cast(sym_->type())->contained());
  52.758 +    } else {
  52.759 +        if (sym_->storage() == VariableSymbol::Local)
  52.760 +            __ setlocal(sym_);
  52.761 +        else if (sym_->storage() == VariableSymbol::Arg)
  52.762 +            __ setarg(sym_);
  52.763 +        else
  52.764 +            assert(false);
  52.765 +    }
  52.766 +}
  52.767 +
  52.768 +void
  52.769 +HLocal::load(BytecodeEmitter &emitter_)
  52.770 +{
  52.771 +    if (sym_->type()->isReference())
  52.772 +        __ getref(ReferenceType::cast(sym_->type())->contained());
  52.773 +    else if (sym_->storage() == VariableSymbol::Local)
  52.774 +        __ getlocal(sym_);
  52.775 +    else if (sym_->storage() == VariableSymbol::Arg)
  52.776 +        __ getarg(sym_);
  52.777 +    else
  52.778 +        assert(false);
  52.779 +}
  52.780 +
  52.781 +bool
  52.782 +HLocal::ref(BytecodeEmitter &emitter_)
  52.783 +{
  52.784 +    if (sym_->storage() == VariableSymbol::Heap) {
  52.785 +        // Closing over a reference should never pass SemA.
  52.786 +        assert(!sym_->type()->isReference());
  52.787 +
  52.788 +        // We don't support direct references to heap-allocated locals. This
  52.789 +        // should probably be banned in SemA? But for now, just assert. :TODO:
  52.790 +        assert(false);
  52.791 +        return false;
  52.792 +    }
  52.793 +        
  52.794 +    if (sym_->type()->isReference()) {
  52.795 +        if (sym_->storage() == VariableSymbol::Local)
  52.796 +            __ getlocal(sym_);
  52.797 +        else if (sym_->storage() == VariableSymbol::Arg)
  52.798 +            __ getarg(sym_);
  52.799 +        else
  52.800 +            assert(false);
  52.801 +    } else {
  52.802 +        __ newref(sym_);
  52.803 +    }
  52.804 +
  52.805 +    return true;
  52.806 +}
  52.807 +
  52.808 +void
  52.809 +HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  52.810 +{
  52.811 +    __ note_position(node()->pos());
  52.812 +    left_->accept(visitor);
  52.813 +    right_->accept(visitor);
  52.814 +}
  52.815 +
  52.816 +void
  52.817 +HIndex::hold(BytecodeEmitter &emitter_)
  52.818 +{
  52.819 +    __ dup2();
  52.820 +}
  52.821 +
  52.822 +void
  52.823 +HIndex::swapAndPick(BytecodeEmitter &emitter_)
  52.824 +{
  52.825 +    // BASE INDEX VALUE
  52.826 +    __ roll3();         // INDEX VALUE BASE
  52.827 +    __ roll3();         // VALUE BASE INDEX
  52.828 +    __ pick3();         // VALUE BASE INDEX VALUE
  52.829 +}
  52.830 +
  52.831 +void
  52.832 +HIndex::store(BytecodeEmitter &emitter_)
  52.833 +{
  52.834 +    __ setelem(type());
  52.835 +}
  52.836 +
  52.837 +void
  52.838 +HIndex::load(BytecodeEmitter &emitter_)
  52.839 +{
  52.840 +    __ getelem(type());
  52.841 +}
  52.842 +
  52.843 +bool
  52.844 +HIndex::ref(BytecodeEmitter &emitter_)
  52.845 +{
  52.846 +    return false;
  52.847 +}
  52.848 +
  52.849 +void
  52.850 +HField::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
  52.851 +{
  52.852 +    __ note_position(node()->pos());
  52.853 +    base_->accept(visitor);
  52.854 +}
  52.855 +
  52.856 +void
  52.857 +HField::hold(BytecodeEmitter &emitter_)
  52.858 +{
  52.859 +    __ dup();
  52.860 +}
  52.861 +
  52.862 +void
  52.863 +HField::swapAndPick(BytecodeEmitter &emitter_)
  52.864 +{
  52.865 +    // BASE VALUE
  52.866 +    __ swap();      // VALUE BASE
  52.867 +    __ pick2();     // VALUE BASE VALUE
  52.868 +}
  52.869 +
  52.870 +void
  52.871 +HField::store(BytecodeEmitter &emitter_)
  52.872 +{
  52.873 +    __ setfield(index_, type());
  52.874 +}
  52.875 +
  52.876 +void
  52.877 +HField::load(BytecodeEmitter &emitter_)
  52.878 +{
  52.879 +    __ getfield(index_, type());
  52.880 +}
  52.881 +
  52.882 +bool
  52.883 +HField::ref(BytecodeEmitter &emitter_)
  52.884 +{
  52.885 +    return false;
  52.886 +}
  52.887 +
  52.888 +void
  52.889 +HIRTranslator::visitLocal(HLocal *local)
  52.890 +{
  52.891 +    local->bind(this, emitter_);
  52.892 +    local->load(emitter_);
  52.893 +}
  52.894 +
  52.895 +void
  52.896 +HIRTranslator::visitIndex(HIndex *index)
  52.897 +{
  52.898 +    index->bind(this, emitter_);
  52.899 +    index->load(emitter_);
  52.900 +}
  52.901 +
  52.902 +void
  52.903 +HIRTranslator::visitField(HField *field)
  52.904 +{
  52.905 +    field->bind(this, emitter_);
  52.906 +    field->load(emitter_);
  52.907 +}
  52.908 +
  52.909 +void
  52.910 +HIRTranslator::visitGlobal(HGlobal *global)
  52.911 +{
  52.912 +    global->bind(this, emitter_);
  52.913 +    global->load(emitter_);
  52.914 +}
  52.915 +
  52.916 +static inline Opcode
  52.917 +TokenToOpcode(TokenKind kind)
  52.918 +{
  52.919 +    switch (kind) {
  52.920 +      case TOK_PLUS:
  52.921 +      case TOK_ASSIGN_ADD:
  52.922 +      case TOK_INCREMENT:
  52.923 +        return OP_ADD;
  52.924 +      case TOK_MINUS:
  52.925 +      case TOK_ASSIGN_SUB:
  52.926 +      case TOK_DECREMENT:
  52.927 +        return OP_SUB;
  52.928 +      case TOK_STAR:
  52.929 +      case TOK_ASSIGN_MUL:
  52.930 +        return OP_MUL;
  52.931 +      case TOK_SLASH:
  52.932 +      case TOK_ASSIGN_DIV:
  52.933 +        return OP_DIV;
  52.934 +      case TOK_PERCENT:
  52.935 +      case TOK_ASSIGN_MOD:
  52.936 +        return OP_MOD;
  52.937 +      case TOK_SHR:
  52.938 +      case TOK_ASSIGN_SHR:
  52.939 +        return OP_SHR;
  52.940 +      case TOK_USHR:
  52.941 +      case TOK_ASSIGN_USHR:
  52.942 +        return OP_USHR;
  52.943 +      case TOK_SHL:
  52.944 +      case TOK_ASSIGN_SHL:
  52.945 +        return OP_SHL;
  52.946 +      case TOK_BITAND:
  52.947 +      case TOK_ASSIGN_BITAND:
  52.948 +        return OP_BITAND;
  52.949 +      case TOK_BITOR:
  52.950 +      case TOK_ASSIGN_BITOR:
  52.951 +        return OP_BITOR;
  52.952 +      case TOK_GT:
  52.953 +          return OP_GT;
  52.954 +      case TOK_GE:
  52.955 +          return OP_GE;
  52.956 +      case TOK_LT:
  52.957 +          return OP_LT;
  52.958 +      case TOK_LE:
  52.959 +          return OP_LE;
  52.960 +      case TOK_EQUALS:
  52.961 +          return OP_EQ;
  52.962 +      case TOK_NOTEQUALS:
  52.963 +          return OP_NE;
  52.964 +      default:
  52.965 +        assert(kind == TOK_BITXOR);
  52.966 +        return OP_BITXOR;
  52.967 +    }
  52.968 +}
  52.969 +
  52.970 +void
  52.971 +HIRTranslator::visitStore(HStore *store)
  52.972 +{
  52.973 +    store->lval()->bind(this, emitter_);
  52.974 +
  52.975 +    if (store->kind() == TOK_ASSIGN) {
  52.976 +        // Fixed-length arrays and structs have copy semantics.
  52.977 +        Local<Type> type(zone_, store->lval()->type());
  52.978 +        if (type->isArray() && ArrayType::cast(type)->isFixedLength()) {
  52.979 +            store->lval()->load(emitter_);
  52.980 +            store->rval()->accept(this);
  52.981 +            __ copyarray();
  52.982 +        } else if (type->isStruct()) {
  52.983 +            store->lval()->load(emitter_);
  52.984 +            store->rval()->accept(this);
  52.985 +            __ copystruct();
  52.986 +        } else {
  52.987 +            store->rval()->accept(this);
  52.988 +            store->lval()->store(emitter_);
  52.989 +        }
  52.990 +    } else {
  52.991 +        // Advanced case: dup the ref, load, op, store.
  52.992 +        store->lval()->hold(emitter_);
  52.993 +        store->lval()->load(emitter_);
  52.994 +        store->rval()->accept(this);
  52.995 +        __ binary(TokenToOpcode(store->kind()));
  52.996 +        store->lval()->store(emitter_);
  52.997 +    }
  52.998 +}
  52.999 +
 52.1000 +void
 52.1001 +HIRTranslator::visitPostIncDec(HPostIncDec *hir)
 52.1002 +{
 52.1003 +    hir->lval()->bind(this, emitter_);
 52.1004 +    hir->lval()->hold(emitter_);
 52.1005 +    hir->lval()->load(emitter_);
 52.1006 +    hir->lval()->swapAndPick(emitter_);
 52.1007 +    hir->rval()->accept(this);
 52.1008 +    __ binary(TokenToOpcode(hir->kind()));
 52.1009 +    hir->lval()->store(emitter_);
 52.1010 +    __ pop();
 52.1011 +}
 52.1012 +
 52.1013 +void
 52.1014 +HIRTranslator::visitBinary(HBinary *binary)
 52.1015 +{
 52.1016 +    binary->left()->accept(this);
 52.1017 +    binary->right()->accept(this);
 52.1018 +
 52.1019 +    // We define three sets of math operators:
 52.1020 +    //
 52.1021 +    //  (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce
 52.1022 +    //      the same type.
 52.1023 +    //  (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce
 52.1024 +    //      a boolean.
 52.1025 +    //  (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two
 52.1026 +    //      equal integer types and return that integer type.
 52.1027 +    //
 52.1028 +    Opcode op = TokenToOpcode(binary->token());
 52.1029 +
 52.1030 +    if (op == OP_DIV)
 52.1031 +        __ note_position(binary->node()->pos());
 52.1032 +
 52.1033 +    if (op >= OP_ADD && op <= OP_NE) {
 52.1034 +        if (binary->type()->isFloat())
 52.1035 +            op = Opcode(int(op) + int(OP_ADD_F - OP_ADD));
 52.1036 +    } else {
 52.1037 +        assert(binary->type()->isInt32());
 52.1038 +    }
 52.1039 +
 52.1040 +    __ binary(op);
 52.1041 +}
 52.1042 +
 52.1043 +void
 52.1044 +HIRTranslator::visitUnary(HUnary *unary)
 52.1045 +{
 52.1046 +    unary->in()->accept(this);
 52.1047 +
 52.1048 +    switch (unary->token()) {
 52.1049 +      case TOK_TILDE:
 52.1050 +        __ bitnot();
 52.1051 +        break;
 52.1052 +
 52.1053 +      case TOK_MINUS:
 52.1054 +        if (unary->type()->isFloat())
 52.1055 +            __ neg_f();
 52.1056 +        else
 52.1057 +            __ neg();
 52.1058 +        break;
 52.1059 +
 52.1060 +      default:
 52.1061 +        assert(unary->token() == TOK_LABEL);
 52.1062 +        __ bitcast(unary->type());
 52.1063 +        break;
 52.1064 +    }
 52.1065 +}
 52.1066 +
 52.1067 +void
 52.1068 +HIRTranslator::visitConvert(HConvert *convert)
 52.1069 +{
 52.1070 +    convert->in()->accept(this);
 52.1071 +    __ unary(convert->opcode());
 52.1072 +}
 52.1073 +
 52.1074 +void
 52.1075 +HIRTranslator::visitToRef(HToRef *hir)
 52.1076 +{
 52.1077 +    HIR *in = hir->in();
 52.1078 +
 52.1079 +    // See if we can bind a direct reference.
 52.1080 +    if (in->isLValue() && in->toLValue()->ref(emitter_))
 52.1081 +        return;
 52.1082 +
 52.1083 +    // No, we can't. So instead we create an on-stack reference.
 52.1084 +    in->accept(this);
 52.1085 +    __ slotref_lifo();
 52.1086 +}
 52.1087 +
 52.1088 +void
 52.1089 +HIRTranslator::visitNewDependentArray(HNewDependentArray *hir)
 52.1090 +{
 52.1091 +    hir->base()->accept(this);
 52.1092 +    hir->index()->accept(this);
 52.1093 +
 52.1094 +    Local<ArrayType> type(zone_, ArrayType::cast(hir->type()));
 52.1095 +
 52.1096 +    // The dependent map is used for the opcode, but is not attached.
 52.1097 +    Local<ArrayMap> map(zone_, ArrayMap::NewDependent(zone_, type));
 52.1098 +    if (!map)
 52.1099 +        return;
 52.1100 +
 52.1101 +    __ deparray(map);
 52.1102 +}
 52.1103 +
 52.1104 +void
 52.1105 +HIRTranslator::visitImport(HImport *import)
 52.1106 +{
 52.1107 +    __ import(import->index());
 52.1108 +}
 52.1109 +
 52.1110 +void
 52.1111 +ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
 52.1112 +{
 52.1113 +    HIRTranslator translator(zone, emitter);
 52.1114 +    translator.translate(hir);
 52.1115 +}
    53.1 --- a/src/compiler/HIR.h	Mon Jun 10 00:46:29 2013 +0100
    53.2 +++ b/src/compiler/HIR.h	Mon Jun 10 01:04:43 2013 +0100
    53.3 @@ -1,607 +1,607 @@
    53.4 -/*
    53.5 - * Copyright (C) 2012 David Anderson
    53.6 - *
    53.7 - * This file is part of SourcePawn.
    53.8 - *
    53.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   53.10 - * the terms of the GNU General Public License as published by the Free
   53.11 - * Software Foundation, either version 3 of the License, or (at your option)
   53.12 - * any later version.
   53.13 - * 
   53.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   53.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   53.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   53.17 - *
   53.18 - * You should have received a copy of the GNU General Public License along with
   53.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   53.20 - */
   53.21 -#ifndef _include_sp2_hir_h_
   53.22 -#define _include_sp2_hir_h_
   53.23 -
   53.24 -#include "../Types.h"
   53.25 -#include "../PoolAllocator.h"
   53.26 -#include "../Opcodes.h"
   53.27 -#include "Symbols.h"
   53.28 -
   53.29 -namespace ke {
   53.30 -
   53.31 -#define HIR_OPS(_)                      \
   53.32 -    _(Call)                             \
   53.33 -    _(Boolean)                          \
   53.34 -    _(Integer)                          \
   53.35 -    _(Float)                            \
   53.36 -    _(String)                           \
   53.37 -    _(Import)                           \
   53.38 -    _(Array)                            \
   53.39 -    _(Store)                            \
   53.40 -    _(ToRef)                            \
   53.41 -    _(NewDependentArray)                \
   53.42 -    /* Special LValue types */          \
   53.43 -    _(Index)                            \
   53.44 -    _(Local)                            \
   53.45 -    _(Global)                           \
   53.46 -    _(Field)                            \
   53.47 -    /* End LValues */                   \
   53.48 -    _(Unary)                            \
   53.49 -    _(Binary)                           \
   53.50 -    _(Convert)                          \
   53.51 -    _(PostIncDec)
   53.52 -
   53.53 -// Forward declarations.
   53.54 -#define _(name)    class H##name;
   53.55 -HIR_OPS(_)
   53.56 -#undef _
   53.57 -
   53.58 -class HIRVisitor;
   53.59 -class AstNode;
   53.60 -class HLValue;
   53.61 -class Array;
   53.62 -
   53.63 -class HIR : public PoolObject
   53.64 -{
   53.65 -  public:
   53.66 -    enum HOp {
   53.67 -#define _(name) k##name,
   53.68 -        HIR_OPS(_)
   53.69 -#undef _
   53.70 -        kTotalOps
   53.71 -    };
   53.72 -
   53.73 -  public:
   53.74 -    HIR(AstNode *node, Type *type)
   53.75 -      : node_(node),
   53.76 -        type_(type)
   53.77 -    {
   53.78 -    }
   53.79 -
   53.80 -    Handle<Type> type() {
   53.81 -        return type_;
   53.82 -    }
   53.83 -    AstNode *node() const {
   53.84 -        return node_;
   53.85 -    }
   53.86 -
   53.87 -    virtual bool isLValue() const {
   53.88 -        return false;
   53.89 -    }
   53.90 -
   53.91 -    virtual HOp op() const = 0;
   53.92 -    virtual void accept(HIRVisitor *visitor) = 0;
   53.93 -
   53.94 -#define _(name)                                         \
   53.95 -    bool is##name() const {                             \
   53.96 -        return op() == k##name;                         \
   53.97 -    }                                                   \
   53.98 -    H##name *to##name() {                               \
   53.99 -        assert(is##name());                             \
  53.100 -        return reinterpret_cast<H##name *>(this);       \
  53.101 -    }
  53.102 -    HIR_OPS(_)
  53.103 -#undef _
  53.104 -
  53.105 -    HLValue *toLValue() {
  53.106 -        assert(isLValue());
  53.107 -        return reinterpret_cast<HLValue *>(this);
  53.108 -    }
  53.109 -
  53.110 -  private:
  53.111 -    AstNode *node_;
  53.112 -    ScopedRoot<Type> type_;
  53.113 -};
  53.114 -
  53.115 -class BytecodeEmitter;
  53.116 -
  53.117 -class HIRVisitor
  53.118 -{
  53.119 -  public:
  53.120 -#define _(name)                                 \
  53.121 -    virtual void visit##name(H##name *hir) {    \
  53.122 -        assert(false);                          \
  53.123 -    }
  53.124 -    HIR_OPS(_)
  53.125 -#undef _
  53.126 -};
  53.127 -
  53.128 -typedef PoolList<HIR *> HIRList;
  53.129 -
  53.130 -#define DEFINE_HIR(name)                        \
  53.131 -    virtual HOp op() const {                    \
  53.132 -        return k##name;                         \
  53.133 -    }                                           \
  53.134 -    virtual void accept(HIRVisitor *visitor) {  \
  53.135 -        visitor->visit##name(this);             \
  53.136 -    }
  53.137 -
  53.138 -class HBoolean : public HIR
  53.139 -{
  53.140 -  public:
  53.141 -    HBoolean(AstNode *node, Type *type, bool value)
  53.142 -      : HIR(node, type),
  53.143 -        value_(value)
  53.144 -    {
  53.145 -    }
  53.146 -
  53.147 -    DEFINE_HIR(Boolean);
  53.148 -    bool value() const {
  53.149 -        return value_;
  53.150 -    }
  53.151 -
  53.152 -  private:
  53.153 -    bool value_;
  53.154 -};
  53.155 -
  53.156 -class HInteger : public HIR
  53.157 -{
  53.158 -  public:
  53.159 -    HInteger(AstNode *node, Type *type, int value)
  53.160 -      : HIR(node, type),
  53.161 -        value_(value)
  53.162 -    {
  53.163 -    }
  53.164 -
  53.165 -    DEFINE_HIR(Integer);
  53.166 -    int value() const {
  53.167 -        return value_;
  53.168 -    }
  53.169 -
  53.170 -  private:
  53.171 -    int value_;
  53.172 -};
  53.173 -
  53.174 -class HString : public HIR
  53.175 -{
  53.176 -  public:
  53.177 -    HString(AstNode *node, Type *type, String *string)
  53.178 -      : HIR(node, type),
  53.179 -        string_(string)
  53.180 -    {
  53.181 -    }
  53.182 -
  53.183 -    DEFINE_HIR(String);
  53.184 -    Handle<String> string() const {
  53.185 -        return string_;
  53.186 -    }
  53.187 -
  53.188 -  private:
  53.189 -    ScopedRoot<String> string_;
  53.190 -};
  53.191 -
  53.192 -class HImport : public HIR
  53.193 -{
  53.194 -  public:
  53.195 -    HImport(AstNode *node, Type *type, unsigned index)
  53.196 -      : HIR(node, type),
  53.197 -        index_(index)
  53.198 -    {
  53.199 -    }
  53.200 -
  53.201 -    DEFINE_HIR(Import);
  53.202 -    unsigned index() const {
  53.203 -        return index_;
  53.204 -    }
  53.205 -
  53.206 -  private:
  53.207 -    unsigned index_;
  53.208 -};
  53.209 -
  53.210 -class HArray : public HIR
  53.211 -{
  53.212 -  public:
  53.213 -    HArray(AstNode *node, Type *type, Array *array, bool duplicate)
  53.214 -      : HIR(node, type),
  53.215 -        array_(array),
  53.216 -        duplicate_(duplicate)
  53.217 -    {
  53.218 -    }
  53.219 -
  53.220 -    DEFINE_HIR(Array);
  53.221 -    Handle<Array> array() const {
  53.222 -        return array_;
  53.223 -    }
  53.224 -    bool duplicate() const {
  53.225 -        return duplicate_;
  53.226 -    }
  53.227 -
  53.228 -  private:
  53.229 -    ScopedRoot<Array> array_;
  53.230 -    bool duplicate_;
  53.231 -};
  53.232 -
  53.233 -class HConvert : public HIR
  53.234 -{
  53.235 -  public:
  53.236 -    HConvert(AstNode *node, Type *type, Opcode op, HIR *in)
  53.237 -      : HIR(node, type),
  53.238 -        op_(op),
  53.239 -        in_(in)
  53.240 -    {
  53.241 -    }
  53.242 -
  53.243 -    DEFINE_HIR(Convert);
  53.244 -    Opcode opcode() const {
  53.245 -        return op_;
  53.246 -    }
  53.247 -    HIR *in() const {
  53.248 -        return in_;
  53.249 -    }
  53.250 -
  53.251 -  private:
  53.252 -    Opcode op_;
  53.253 -    HIR *in_;
  53.254 -};
  53.255 -
  53.256 -class HLValue : public HIR
  53.257 -{
  53.258 -  public:
  53.259 -    HLValue(AstNode *node, Type *type)
  53.260 -      : HIR(node, type)
  53.261 -    {
  53.262 -    }
  53.263 -
  53.264 -    // Pushes a reference to the LValue on the stack.
  53.265 -    virtual void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) = 0;
  53.266 -    
  53.267 -    // Duplicates a stack reference.
  53.268 -    virtual void hold(BytecodeEmitter &emitter_) = 0;
  53.269 -
  53.270 -    // Reorders the stack for a post-increment operation:
  53.271 -    //   REF VAL -> VAL REF VAL
  53.272 -    virtual void swapAndPick(BytecodeEmitter &emitter_) = 0;
  53.273 -
  53.274 -    // Given a stack layout of the form:
  53.275 -    //  [-1]    value
  53.276 -    //  [-2..n] ref
  53.277 -    //
  53.278 -    // Emits a store to the reference.
  53.279 -    virtual void store(BytecodeEmitter &emitter_) = 0;
  53.280 -    virtual void load(BytecodeEmitter &emitter_) = 0;
  53.281 -
  53.282 -    // Try to make a direct reference, if semantics allow it. False if the
  53.283 -    // caller must allocate a reference to the stack.
  53.284 -    virtual bool ref(BytecodeEmitter &emitter_) = 0;
  53.285 -
  53.286 -    bool isLValue() const {
  53.287 -        return true;
  53.288 -    }
  53.289 -};
  53.290 -
  53.291 -class HLocal : public HLValue
  53.292 -{
  53.293 -  public:
  53.294 -    HLocal(AstNode *node, VariableSymbol *sym);
  53.295 -
  53.296 -    DEFINE_HIR(Local);
  53.297 -
  53.298 -    // Pushes a reference to the LValue on the stack.
  53.299 -    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  53.300 -    void hold(BytecodeEmitter &emitter_);
  53.301 -    void swapAndPick(BytecodeEmitter &emitter_);
  53.302 -    void store(BytecodeEmitter &emitter_);
  53.303 -    void load(BytecodeEmitter &emitter_);
  53.304 -    bool ref(BytecodeEmitter &emitter_);
  53.305 -
  53.306 -    VariableSymbol *sym() const {
  53.307 -        return sym_;
  53.308 -    }
  53.309 -
  53.310 -  private:
  53.311 -    VariableSymbol *sym_;
  53.312 -};
  53.313 -
  53.314 -class HIndex : public HLValue
  53.315 -{
  53.316 -  public:
  53.317 -    HIndex(AstNode *node, Type *type, HIR *left, HIR *right)
  53.318 -      : HLValue(node, type),
  53.319 -        left_(left),
  53.320 -        right_(right)
  53.321 -    {
  53.322 -    }
  53.323 -
  53.324 -    DEFINE_HIR(Index);
  53.325 -
  53.326 -    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  53.327 -    void hold(BytecodeEmitter &emitter_);
  53.328 -    void swapAndPick(BytecodeEmitter &emitter_);
  53.329 -    void store(BytecodeEmitter &emitter_);
  53.330 -    void load(BytecodeEmitter &emitter_);
  53.331 -    bool ref(BytecodeEmitter &emitter_);
  53.332 -
  53.333 -    HIR *base() const {
  53.334 -        return left_;
  53.335 -    }
  53.336 -    HIR *index() const {
  53.337 -        return right_;
  53.338 -    }
  53.339 -
  53.340 -  private:
  53.341 -    HIR *left_;
  53.342 -    HIR *right_;
  53.343 -};
  53.344 -
  53.345 -class HField : public HLValue
  53.346 -{
  53.347 -  public:
  53.348 -    HField(AstNode *node, HIR *left, Type *type, unsigned index)
  53.349 -      : HLValue(node, type),
  53.350 -        base_(left),
  53.351 -        index_(index)
  53.352 -    {
  53.353 -    }
  53.354 -
  53.355 -    DEFINE_HIR(Field);
  53.356 -
  53.357 -    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  53.358 -    void hold(BytecodeEmitter &emitter_);
  53.359 -    void swapAndPick(BytecodeEmitter &emitter_);
  53.360 -    void store(BytecodeEmitter &emitter_);
  53.361 -    void load(BytecodeEmitter &emitter_);
  53.362 -    bool ref(BytecodeEmitter &emitter_);
  53.363 -
  53.364 -    HIR *base() const {
  53.365 -        return base_;
  53.366 -    }
  53.367 -    unsigned index() const {
  53.368 -        return index_;
  53.369 -    }
  53.370 -
  53.371 -  private:
  53.372 -    HIR *base_;
  53.373 -    unsigned index_;
  53.374 -};
  53.375 -
  53.376 -class HGlobal : public HLValue
  53.377 -{
  53.378 -  public:
  53.379 -    HGlobal(AstNode *node, Symbol *sym)
  53.380 -      : HLValue(node, sym->type()),
  53.381 -        sym_(sym)
  53.382 -    {
  53.383 -    }
  53.384 -
  53.385 -    DEFINE_HIR(Global);
  53.386 -
  53.387 -    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  53.388 -    void hold(BytecodeEmitter &emitter_);
  53.389 -    void swapAndPick(BytecodeEmitter &emitter_);
  53.390 -    void store(BytecodeEmitter &emitter_);
  53.391 -    void load(BytecodeEmitter &emitter_);
  53.392 -    bool ref(BytecodeEmitter &emitter_);
  53.393 -
  53.394 -    Symbol *sym() const {
  53.395 -        return sym_;
  53.396 -    }
  53.397 -
  53.398 -  private:
  53.399 -    Symbol *sym_;
  53.400 -};
  53.401 -
  53.402 -class HBinary : public HIR
  53.403 -{
  53.404 -  public:
  53.405 -    HBinary(AstNode *node, Type *type, TokenKind token, HIR *left, HIR *right)
  53.406 -      : HIR(node, type),
  53.407 -        token_(token),
  53.408 -        left_(left),
  53.409 -        right_(right)
  53.410 -    {
  53.411 -    }
  53.412 -
  53.413 -    DEFINE_HIR(Binary);
  53.414 -    TokenKind token() const {
  53.415 -        return token_;
  53.416 -    }
  53.417 -    HIR *left() const {
  53.418 -        return left_;
  53.419 -    }
  53.420 -    HIR *right() const {
  53.421 -        return right_;
  53.422 -    }
  53.423 -
  53.424 -  private:
  53.425 -    TokenKind token_;
  53.426 -    HIR *left_;
  53.427 -    HIR *right_;
  53.428 -};
  53.429 -
  53.430 -class HFloat : public HIR
  53.431 -{
  53.432 -  public:
  53.433 -    HFloat(AstNode *node, Type *type, float value)
  53.434 -      : HIR(node, type),
  53.435 -        value_(value)
  53.436 -    {
  53.437 -    }
  53.438 -
  53.439 -    DEFINE_HIR(Float);
  53.440 -    float value() const {
  53.441 -        return value_;
  53.442 -    }
  53.443 -
  53.444 -  private:
  53.445 -    float value_;
  53.446 -};
  53.447 -
  53.448 -class HUnary : public HIR
  53.449 -{
  53.450 -  public:
  53.451 -    HUnary(AstNode *node, Type *type, TokenKind tok, HIR *in)
  53.452 -      : HIR(node, type),
  53.453 -        in_(in),
  53.454 -        token_(tok)
  53.455 -    {
  53.456 -    }
  53.457 -
  53.458 -    DEFINE_HIR(Unary);
  53.459 -    HIR *in() const {
  53.460 -        return in_;
  53.461 -    }
  53.462 -    TokenKind token() const {
  53.463 -        return token_;
  53.464 -    }
  53.465 -
  53.466 -  private:
  53.467 -    HIR *in_;
  53.468 -    TokenKind token_;
  53.469 -};
  53.470 -
  53.471 -class HStore : public HIR
  53.472 -{
  53.473 -  public:
  53.474 -    HStore(AstNode *node, HLValue *lval, HIR *rval)
  53.475 -      : HIR(node, lval->type()),
  53.476 -        kind_(TOK_ASSIGN),
  53.477 -        lval_(lval),
  53.478 -        rval_(rval)
  53.479 -    {
  53.480 -    }
  53.481 -
  53.482 -    HStore(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval)
  53.483 -      : HIR(node, lval->type()),
  53.484 -        kind_(kind),
  53.485 -        lval_(lval),
  53.486 -        rval_(rval)
  53.487 -    {
  53.488 -    }
  53.489 -
  53.490 -    DEFINE_HIR(Store);
  53.491 -
  53.492 -    HLValue *lval() const {
  53.493 -        return lval_;
  53.494 -    }
  53.495 -    HIR *rval() const {
  53.496 -        return rval_;
  53.497 -    }
  53.498 -    TokenKind kind() const {
  53.499 -        return kind_;
  53.500 -    }
  53.501 -
  53.502 -  private:
  53.503 -    TokenKind kind_;
  53.504 -    HLValue *lval_;
  53.505 -    HIR *rval_;
  53.506 -};
  53.507 -
  53.508 -class HPostIncDec : public HIR
  53.509 -{
  53.510 -  public:
  53.511 -    HPostIncDec(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval)
  53.512 -      : HIR(node, lval->type()),
  53.513 -        kind_(kind),
  53.514 -        lval_(lval),
  53.515 -        rval_(rval)
  53.516 -    {
  53.517 -    }
  53.518 -
  53.519 -    DEFINE_HIR(PostIncDec);
  53.520 -
  53.521 -    HLValue *lval() const {
  53.522 -        return lval_;
  53.523 -    }
  53.524 -    HIR *rval() const {
  53.525 -        return rval_;
  53.526 -    }
  53.527 -    TokenKind kind() const {
  53.528 -        return kind_;
  53.529 -    }
  53.530 -
  53.531 -  private:
  53.532 -    TokenKind kind_;
  53.533 -    HLValue *lval_;
  53.534 -    HIR *rval_;
  53.535 -};
  53.536 -
  53.537 -class HCall : public HIR
  53.538 -{
  53.539 -  public:
  53.540 -    HCall(AstNode *node, Type *type, HIR *callee, HIRList *args)
  53.541 -      : HIR(node, type),
  53.542 -        callee_(callee),
  53.543 -        args_(args)
  53.544 -    {
  53.545 -    }
  53.546 -
  53.547 -    DEFINE_HIR(Call);
  53.548 -
  53.549 -    HIR *callee() const {
  53.550 -        return callee_;
  53.551 -    }
  53.552 -    HIRList *args() const {
  53.553 -        return args_;
  53.554 -    }
  53.555 -
  53.556 -  private:
  53.557 -    HIR *callee_;
  53.558 -    HIRList *args_;
  53.559 -};
  53.560 -
  53.561 -class HToRef : public HIR
  53.562 -{
  53.563 -  public:
  53.564 -    HToRef(AstNode *node, Type *type, HIR *in)
  53.565 -      : HIR(node, type),
  53.566 -        in_(in)
  53.567 -    {
  53.568 -    }
  53.569 -
  53.570 -    DEFINE_HIR(ToRef);
  53.571 -
  53.572 -    HIR *in() const {
  53.573 -        return in_;
  53.574 -    }
  53.575 -
  53.576 -  private:
  53.577 -    HIR *in_;
  53.578 -};
  53.579 -
  53.580 -class HNewDependentArray : public HIR
  53.581 -{
  53.582 -  public:
  53.583 -    HNewDependentArray(AstNode *node, Type *type, HIR *base, HIR *index)
  53.584 -      : HIR(node, type),
  53.585 -        base_(base),
  53.586 -        index_(index)
  53.587 -    {
  53.588 -    }
  53.589 -
  53.590 -    DEFINE_HIR(NewDependentArray);
  53.591 -
  53.592 -    HIR *base() const {
  53.593 -        return base_;
  53.594 -    }
  53.595 -    HIR *index() const {
  53.596 -        return index_;
  53.597 -    }
  53.598 -
  53.599 -  private:
  53.600 -    HIR *base_;
  53.601 -    HIR *index_;
  53.602 -};
  53.603 -
  53.604 -#undef DEFINE_HIR
  53.605 -
  53.606 -void EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir);
  53.607 -
  53.608 -}
  53.609 -
  53.610 -#endif // _include_sp2_hir_h_
  53.611 +/*
  53.612 + * Copyright (C) 2012 David Anderson
  53.613 + *
  53.614 + * This file is part of SourcePawn.
  53.615 + *
  53.616 + * SourcePawn is free software: you can redistribute it and/or modify it under
  53.617 + * the terms of the GNU General Public License as published by the Free
  53.618 + * Software Foundation, either version 3 of the License, or (at your option)
  53.619 + * any later version.
  53.620 + * 
  53.621 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  53.622 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  53.623 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  53.624 + *
  53.625 + * You should have received a copy of the GNU General Public License along with
  53.626 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  53.627 + */
  53.628 +#ifndef _include_sp2_hir_h_
  53.629 +#define _include_sp2_hir_h_
  53.630 +
  53.631 +#include "../Types.h"
  53.632 +#include "../PoolAllocator.h"
  53.633 +#include "../Opcodes.h"
  53.634 +#include "Symbols.h"
  53.635 +
  53.636 +namespace ke {
  53.637 +
  53.638 +#define HIR_OPS(_)                      \
  53.639 +    _(Call)                             \
  53.640 +    _(Boolean)                          \
  53.641 +    _(Integer)                          \
  53.642 +    _(Float)                            \
  53.643 +    _(String)                           \
  53.644 +    _(Import)                           \
  53.645 +    _(Array)                            \
  53.646 +    _(Store)                            \
  53.647 +    _(ToRef)                            \
  53.648 +    _(NewDependentArray)                \
  53.649 +    /* Special LValue types */          \
  53.650 +    _(Index)                            \
  53.651 +    _(Local)                            \
  53.652 +    _(Global)                           \
  53.653 +    _(Field)                            \
  53.654 +    /* End LValues */                   \
  53.655 +    _(Unary)                            \
  53.656 +    _(Binary)                           \
  53.657 +    _(Convert)                          \
  53.658 +    _(PostIncDec)
  53.659 +
  53.660 +// Forward declarations.
  53.661 +#define _(name)    class H##name;
  53.662 +HIR_OPS(_)
  53.663 +#undef _
  53.664 +
  53.665 +class HIRVisitor;
  53.666 +class AstNode;
  53.667 +class HLValue;
  53.668 +class Array;
  53.669 +
  53.670 +class HIR : public PoolObject
  53.671 +{
  53.672 +  public:
  53.673 +    enum HOp {
  53.674 +#define _(name) k##name,
  53.675 +        HIR_OPS(_)
  53.676 +#undef _
  53.677 +        kTotalOps
  53.678 +    };
  53.679 +
  53.680 +  public:
  53.681 +    HIR(AstNode *node, Type *type)
  53.682 +      : node_(node),
  53.683 +        type_(type)
  53.684 +    {
  53.685 +    }
  53.686 +
  53.687 +    Handle<Type> type() {
  53.688 +        return type_;
  53.689 +    }
  53.690 +    AstNode *node() const {
  53.691 +        return node_;
  53.692 +    }
  53.693 +
  53.694 +    virtual bool isLValue() const {
  53.695 +        return false;
  53.696 +    }
  53.697 +
  53.698 +    virtual HOp op() const = 0;
  53.699 +    virtual void accept(HIRVisitor *visitor) = 0;
  53.700 +
  53.701 +#define _(name)                                         \
  53.702 +    bool is##name() const {                             \
  53.703 +        return op() == k##name;                         \
  53.704 +    }                                                   \
  53.705 +    H##name *to##name() {                               \
  53.706 +        assert(is##name());                             \
  53.707 +        return reinterpret_cast<H##name *>(this);       \
  53.708 +    }
  53.709 +    HIR_OPS(_)
  53.710 +#undef _
  53.711 +
  53.712 +    HLValue *toLValue() {
  53.713 +        assert(isLValue());
  53.714 +        return reinterpret_cast<HLValue *>(this);
  53.715 +    }
  53.716 +
  53.717 +  private:
  53.718 +    AstNode *node_;
  53.719 +    ScopedRoot<Type> type_;
  53.720 +};
  53.721 +
  53.722 +class BytecodeEmitter;
  53.723 +
  53.724 +class HIRVisitor
  53.725 +{
  53.726 +  public:
  53.727 +#define _(name)                                 \
  53.728 +    virtual void visit##name(H##name *hir) {    \
  53.729 +        assert(false);                          \
  53.730 +    }
  53.731 +    HIR_OPS(_)
  53.732 +#undef _
  53.733 +};
  53.734 +
  53.735 +typedef PoolList<HIR *> HIRList;
  53.736 +
  53.737 +#define DEFINE_HIR(name)                        \
  53.738 +    virtual HOp op() const {                    \
  53.739 +        return k##name;                         \
  53.740 +    }                                           \
  53.741 +    virtual void accept(HIRVisitor *visitor) {  \
  53.742 +        visitor->visit##name(this);             \
  53.743 +    }
  53.744 +
  53.745 +class HBoolean : public HIR
  53.746 +{
  53.747 +  public:
  53.748 +    HBoolean(AstNode *node, Type *type, bool value)
  53.749 +      : HIR(node, type),
  53.750 +        value_(value)
  53.751 +    {
  53.752 +    }
  53.753 +
  53.754 +    DEFINE_HIR(Boolean);
  53.755 +    bool value() const {
  53.756 +        return value_;
  53.757 +    }
  53.758 +
  53.759 +  private:
  53.760 +    bool value_;
  53.761 +};
  53.762 +
  53.763 +class HInteger : public HIR
  53.764 +{
  53.765 +  public:
  53.766 +    HInteger(AstNode *node, Type *type, int value)
  53.767 +      : HIR(node, type),
  53.768 +        value_(value)
  53.769 +    {
  53.770 +    }
  53.771 +
  53.772 +    DEFINE_HIR(Integer);
  53.773 +    int value() const {
  53.774 +        return value_;
  53.775 +    }
  53.776 +
  53.777 +  private:
  53.778 +    int value_;
  53.779 +};
  53.780 +
  53.781 +class HString : public HIR
  53.782 +{
  53.783 +  public:
  53.784 +    HString(AstNode *node, Type *type, String *string)
  53.785 +      : HIR(node, type),
  53.786 +        string_(string)
  53.787 +    {
  53.788 +    }
  53.789 +
  53.790 +    DEFINE_HIR(String);
  53.791 +    Handle<String> string() const {
  53.792 +        return string_;
  53.793 +    }
  53.794 +
  53.795 +  private:
  53.796 +    ScopedRoot<String> string_;
  53.797 +};
  53.798 +
  53.799 +class HImport : public HIR
  53.800 +{
  53.801 +  public:
  53.802 +    HImport(AstNode *node, Type *type, unsigned index)
  53.803 +      : HIR(node, type),
  53.804 +        index_(index)
  53.805 +    {
  53.806 +    }
  53.807 +
  53.808 +    DEFINE_HIR(Import);
  53.809 +    unsigned index() const {
  53.810 +        return index_;
  53.811 +    }
  53.812 +
  53.813 +  private:
  53.814 +    unsigned index_;
  53.815 +};
  53.816 +
  53.817 +class HArray : public HIR
  53.818 +{
  53.819 +  public:
  53.820 +    HArray(AstNode *node, Type *type, Array *array, bool duplicate)
  53.821 +      : HIR(node, type),
  53.822 +        array_(array),
  53.823 +        duplicate_(duplicate)
  53.824 +    {
  53.825 +    }
  53.826 +
  53.827 +    DEFINE_HIR(Array);
  53.828 +    Handle<Array> array() const {
  53.829 +        return array_;
  53.830 +    }
  53.831 +    bool duplicate() const {
  53.832 +        return duplicate_;
  53.833 +    }
  53.834 +
  53.835 +  private:
  53.836 +    ScopedRoot<Array> array_;
  53.837 +    bool duplicate_;
  53.838 +};
  53.839 +
  53.840 +class HConvert : public HIR
  53.841 +{
  53.842 +  public:
  53.843 +    HConvert(AstNode *node, Type *type, Opcode op, HIR *in)
  53.844 +      : HIR(node, type),
  53.845 +        op_(op),
  53.846 +        in_(in)
  53.847 +    {
  53.848 +    }
  53.849 +
  53.850 +    DEFINE_HIR(Convert);
  53.851 +    Opcode opcode() const {
  53.852 +        return op_;
  53.853 +    }
  53.854 +    HIR *in() const {
  53.855 +        return in_;
  53.856 +    }
  53.857 +
  53.858 +  private:
  53.859 +    Opcode op_;
  53.860 +    HIR *in_;
  53.861 +};
  53.862 +
  53.863 +class HLValue : public HIR
  53.864 +{
  53.865 +  public:
  53.866 +    HLValue(AstNode *node, Type *type)
  53.867 +      : HIR(node, type)
  53.868 +    {
  53.869 +    }
  53.870 +
  53.871 +    // Pushes a reference to the LValue on the stack.
  53.872 +    virtual void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) = 0;
  53.873 +    
  53.874 +    // Duplicates a stack reference.
  53.875 +    virtual void hold(BytecodeEmitter &emitter_) = 0;
  53.876 +
  53.877 +    // Reorders the stack for a post-increment operation:
  53.878 +    //   REF VAL -> VAL REF VAL
  53.879 +    virtual void swapAndPick(BytecodeEmitter &emitter_) = 0;
  53.880 +
  53.881 +    // Given a stack layout of the form:
  53.882 +    //  [-1]    value
  53.883 +    //  [-2..n] ref
  53.884 +    //
  53.885 +    // Emits a store to the reference.
  53.886 +    virtual void store(BytecodeEmitter &emitter_) = 0;
  53.887 +    virtual void load(BytecodeEmitter &emitter_) = 0;
  53.888 +
  53.889 +    // Try to make a direct reference, if semantics allow it. False if the
  53.890 +    // caller must allocate a reference to the stack.
  53.891 +    virtual bool ref(BytecodeEmitter &emitter_) = 0;
  53.892 +
  53.893 +    bool isLValue() const {
  53.894 +        return true;
  53.895 +    }
  53.896 +};
  53.897 +
  53.898 +class HLocal : public HLValue
  53.899 +{
  53.900 +  public:
  53.901 +    HLocal(AstNode *node, VariableSymbol *sym);
  53.902 +
  53.903 +    DEFINE_HIR(Local);
  53.904 +
  53.905 +    // Pushes a reference to the LValue on the stack.
  53.906 +    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  53.907 +    void hold(BytecodeEmitter &emitter_);
  53.908 +    void swapAndPick(BytecodeEmitter &emitter_);
  53.909 +    void store(BytecodeEmitter &emitter_);
  53.910 +    void load(BytecodeEmitter &emitter_);
  53.911 +    bool ref(BytecodeEmitter &emitter_);
  53.912 +
  53.913 +    VariableSymbol *sym() const {
  53.914 +        return sym_;
  53.915 +    }
  53.916 +
  53.917 +  private:
  53.918 +    VariableSymbol *sym_;
  53.919 +};
  53.920 +
  53.921 +class HIndex : public HLValue
  53.922 +{
  53.923 +  public:
  53.924 +    HIndex(AstNode *node, Type *type, HIR *left, HIR *right)
  53.925 +      : HLValue(node, type),
  53.926 +        left_(left),
  53.927 +        right_(right)
  53.928 +    {
  53.929 +    }
  53.930 +
  53.931 +    DEFINE_HIR(Index);
  53.932 +
  53.933 +    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  53.934 +    void hold(BytecodeEmitter &emitter_);
  53.935 +    void swapAndPick(BytecodeEmitter &emitter_);
  53.936 +    void store(BytecodeEmitter &emitter_);
  53.937 +    void load(BytecodeEmitter &emitter_);
  53.938 +    bool ref(BytecodeEmitter &emitter_);
  53.939 +
  53.940 +    HIR *base() const {
  53.941 +        return left_;
  53.942 +    }
  53.943 +    HIR *index() const {
  53.944 +        return right_;
  53.945 +    }
  53.946 +
  53.947 +  private:
  53.948 +    HIR *left_;
  53.949 +    HIR *right_;
  53.950 +};
  53.951 +
  53.952 +class HField : public HLValue
  53.953 +{
  53.954 +  public:
  53.955 +    HField(AstNode *node, HIR *left, Type *type, unsigned index)
  53.956 +      : HLValue(node, type),
  53.957 +        base_(left),
  53.958 +        index_(index)
  53.959 +    {
  53.960 +    }
  53.961 +
  53.962 +    DEFINE_HIR(Field);
  53.963 +
  53.964 +    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  53.965 +    void hold(BytecodeEmitter &emitter_);
  53.966 +    void swapAndPick(BytecodeEmitter &emitter_);
  53.967 +    void store(BytecodeEmitter &emitter_);
  53.968 +    void load(BytecodeEmitter &emitter_);
  53.969 +    bool ref(BytecodeEmitter &emitter_);
  53.970 +
  53.971 +    HIR *base() const {
  53.972 +        return base_;
  53.973 +    }
  53.974 +    unsigned index() const {
  53.975 +        return index_;
  53.976 +    }
  53.977 +
  53.978 +  private:
  53.979 +    HIR *base_;
  53.980 +    unsigned index_;
  53.981 +};
  53.982 +
  53.983 +class HGlobal : public HLValue
  53.984 +{
  53.985 +  public:
  53.986 +    HGlobal(AstNode *node, Symbol *sym)
  53.987 +      : HLValue(node, sym->type()),
  53.988 +        sym_(sym)
  53.989 +    {
  53.990 +    }
  53.991 +
  53.992 +    DEFINE_HIR(Global);
  53.993 +
  53.994 +    void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
  53.995 +    void hold(BytecodeEmitter &emitter_);
  53.996 +    void swapAndPick(BytecodeEmitter &emitter_);
  53.997 +    void store(BytecodeEmitter &emitter_);
  53.998 +    void load(BytecodeEmitter &emitter_);
  53.999 +    bool ref(BytecodeEmitter &emitter_);
 53.1000 +
 53.1001 +    Symbol *sym() const {
 53.1002 +        return sym_;
 53.1003 +    }
 53.1004 +
 53.1005 +  private:
 53.1006 +    Symbol *sym_;
 53.1007 +};
 53.1008 +
 53.1009 +class HBinary : public HIR
 53.1010 +{
 53.1011 +  public:
 53.1012 +    HBinary(AstNode *node, Type *type, TokenKind token, HIR *left, HIR *right)
 53.1013 +      : HIR(node, type),
 53.1014 +        token_(token),
 53.1015 +        left_(left),
 53.1016 +        right_(right)
 53.1017 +    {
 53.1018 +    }
 53.1019 +
 53.1020 +    DEFINE_HIR(Binary);
 53.1021 +    TokenKind token() const {
 53.1022 +        return token_;
 53.1023 +    }
 53.1024 +    HIR *left() const {
 53.1025 +        return left_;
 53.1026 +    }
 53.1027 +    HIR *right() const {
 53.1028 +        return right_;
 53.1029 +    }
 53.1030 +
 53.1031 +  private:
 53.1032 +    TokenKind token_;
 53.1033 +    HIR *left_;
 53.1034 +    HIR *right_;
 53.1035 +};
 53.1036 +
 53.1037 +class HFloat : public HIR
 53.1038 +{
 53.1039 +  public:
 53.1040 +    HFloat(AstNode *node, Type *type, float value)
 53.1041 +      : HIR(node, type),
 53.1042 +        value_(value)
 53.1043 +    {
 53.1044 +    }
 53.1045 +
 53.1046 +    DEFINE_HIR(Float);
 53.1047 +    float value() const {
 53.1048 +        return value_;
 53.1049 +    }
 53.1050 +
 53.1051 +  private:
 53.1052 +    float value_;
 53.1053 +};
 53.1054 +
 53.1055 +class HUnary : public HIR
 53.1056 +{
 53.1057 +  public:
 53.1058 +    HUnary(AstNode *node, Type *type, TokenKind tok, HIR *in)
 53.1059 +      : HIR(node, type),
 53.1060 +        in_(in),
 53.1061 +        token_(tok)
 53.1062 +    {
 53.1063 +    }
 53.1064 +
 53.1065 +    DEFINE_HIR(Unary);
 53.1066 +    HIR *in() const {
 53.1067 +        return in_;
 53.1068 +    }
 53.1069 +    TokenKind token() const {
 53.1070 +        return token_;
 53.1071 +    }
 53.1072 +
 53.1073 +  private:
 53.1074 +    HIR *in_;
 53.1075 +    TokenKind token_;
 53.1076 +};
 53.1077 +
 53.1078 +class HStore : public HIR
 53.1079 +{
 53.1080 +  public:
 53.1081 +    HStore(AstNode *node, HLValue *lval, HIR *rval)
 53.1082 +      : HIR(node, lval->type()),
 53.1083 +        kind_(TOK_ASSIGN),
 53.1084 +        lval_(lval),
 53.1085 +        rval_(rval)
 53.1086 +    {
 53.1087 +    }
 53.1088 +
 53.1089 +    HStore(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval)
 53.1090 +      : HIR(node, lval->type()),
 53.1091 +        kind_(kind),
 53.1092 +        lval_(lval),
 53.1093 +        rval_(rval)
 53.1094 +    {
 53.1095 +    }
 53.1096 +
 53.1097 +    DEFINE_HIR(Store);
 53.1098 +
 53.1099 +    HLValue *lval() const {
 53.1100 +        return lval_;
 53.1101 +    }
 53.1102 +    HIR *rval() const {
 53.1103 +        return rval_;
 53.1104 +    }
 53.1105 +    TokenKind kind() const {
 53.1106 +        return kind_;
 53.1107 +    }
 53.1108 +
 53.1109 +  private:
 53.1110 +    TokenKind kind_;
 53.1111 +    HLValue *lval_;
 53.1112 +    HIR *rval_;
 53.1113 +};
 53.1114 +
 53.1115 +class HPostIncDec : public HIR
 53.1116 +{
 53.1117 +  public:
 53.1118 +    HPostIncDec(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval)
 53.1119 +      : HIR(node, lval->type()),
 53.1120 +        kind_(kind),
 53.1121 +        lval_(lval),
 53.1122 +        rval_(rval)
 53.1123 +    {
 53.1124 +    }
 53.1125 +
 53.1126 +    DEFINE_HIR(PostIncDec);
 53.1127 +
 53.1128 +    HLValue *lval() const {
 53.1129 +        return lval_;
 53.1130 +    }
 53.1131 +    HIR *rval() const {
 53.1132 +        return rval_;
 53.1133 +    }
 53.1134 +    TokenKind kind() const {
 53.1135 +        return kind_;
 53.1136 +    }
 53.1137 +
 53.1138 +  private:
 53.1139 +    TokenKind kind_;
 53.1140 +    HLValue *lval_;
 53.1141 +    HIR *rval_;
 53.1142 +};
 53.1143 +
 53.1144 +class HCall : public HIR
 53.1145 +{
 53.1146 +  public:
 53.1147 +    HCall(AstNode *node, Type *type, HIR *callee, HIRList *args)
 53.1148 +      : HIR(node, type),
 53.1149 +        callee_(callee),
 53.1150 +        args_(args)
 53.1151 +    {
 53.1152 +    }
 53.1153 +
 53.1154 +    DEFINE_HIR(Call);
 53.1155 +
 53.1156 +    HIR *callee() const {
 53.1157 +        return callee_;
 53.1158 +    }
 53.1159 +    HIRList *args() const {
 53.1160 +        return args_;
 53.1161 +    }
 53.1162 +
 53.1163 +  private:
 53.1164 +    HIR *callee_;
 53.1165 +    HIRList *args_;
 53.1166 +};
 53.1167 +
 53.1168 +class HToRef : public HIR
 53.1169 +{
 53.1170 +  public:
 53.1171 +    HToRef(AstNode *node, Type *type, HIR *in)
 53.1172 +      : HIR(node, type),
 53.1173 +        in_(in)
 53.1174 +    {
 53.1175 +    }
 53.1176 +
 53.1177 +    DEFINE_HIR(ToRef);
 53.1178 +
 53.1179 +    HIR *in() const {
 53.1180 +        return in_;
 53.1181 +    }
 53.1182 +
 53.1183 +  private:
 53.1184 +    HIR *in_;
 53.1185 +};
 53.1186 +
 53.1187 +class HNewDependentArray : public HIR
 53.1188 +{
 53.1189 +  public:
 53.1190 +    HNewDependentArray(AstNode *node, Type *type, HIR *base, HIR *index)
 53.1191 +      : HIR(node, type),
 53.1192 +        base_(base),
 53.1193 +        index_(index)
 53.1194 +    {
 53.1195 +    }
 53.1196 +
 53.1197 +    DEFINE_HIR(NewDependentArray);
 53.1198 +
 53.1199 +    HIR *base() const {
 53.1200 +        return base_;
 53.1201 +    }
 53.1202 +    HIR *index() const {
 53.1203 +        return index_;
 53.1204 +    }
 53.1205 +
 53.1206 +  private:
 53.1207 +    HIR *base_;
 53.1208 +    HIR *index_;
 53.1209 +};
 53.1210 +
 53.1211 +#undef DEFINE_HIR
 53.1212 +
 53.1213 +void EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir);
 53.1214 +
 53.1215 +}
 53.1216 +
 53.1217 +#endif // _include_sp2_hir_h_
    54.1 --- a/src/compiler/NameBinding.cpp	Mon Jun 10 00:46:29 2013 +0100
    54.2 +++ b/src/compiler/NameBinding.cpp	Mon Jun 10 01:04:43 2013 +0100
    54.3 @@ -1,1297 +1,1297 @@
    54.4 -/* vim: set ts=4 sw=4 tw=99 et:
    54.5 - *
    54.6 - * Copyright (C) 2012 David Anderson
    54.7 - *
    54.8 - * This file is part of SourcePawn.
    54.9 - *
   54.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   54.11 - * the terms of the GNU General Public License as published by the Free
   54.12 - * Software Foundation, either version 3 of the License, or (at your option)
   54.13 - * any later version.
   54.14 - * 
   54.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   54.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   54.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   54.18 - *
   54.19 - * You should have received a copy of the GNU General Public License along with
   54.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   54.21 - */
   54.22 -#include "../Strings.h"
   54.23 -#include "../Zone.h"
   54.24 -#include "../TypeManager.h"
   54.25 -#include "NameBinding.h"
   54.26 -#include "Scopes.h"
   54.27 -#include "ConstantEvaluator.h"
   54.28 -#include "../Spaces-inl.h"
   54.29 -#include "../Heap-inl.h"
   54.30 -
   54.31 -using namespace ke;
   54.32 -
   54.33 -// Create symbol tables and symbols for every scope and declaration. For type
   54.34 -// declarations and methods, we also pre-allocate a Type object, so that
   54.35 -// circular dependencies between types will work.
   54.36 -class NamePopulator : public AstVisitor
   54.37 -{
   54.38 -  private:
   54.39 -    // This class is analagous to a Scope, however, it allows us to create
   54.40 -    // scopes lazily. If a scope is requested, and the current environment
   54.41 -    // has no scope, then a scope is created. If no scope is ever requested,
   54.42 -    // a scope does not need to be created.
   54.43 -    class SymbolEnv
   54.44 -    {
   54.45 -      public:
   54.46 -        SymbolEnv(SymbolEnv **prevp, Scope *scope = NULL)
   54.47 -          : envp_(prevp),
   54.48 -            prev_(*prevp),
   54.49 -            scope_(scope)
   54.50 -        {
   54.51 -            *envp_ = this;
   54.52 -        }
   54.53 -        ~SymbolEnv() {
   54.54 -            *envp_ = prev_;
   54.55 -        }
   54.56 -
   54.57 -        Scope *scope() {
   54.58 -            return scope_;
   54.59 -        }
   54.60 -        void setScope(Scope *scope) {
   54.61 -            assert(!scope_);
   54.62 -            scope_ = scope;
   54.63 -        }
   54.64 -        SymbolEnv *prev() const {
   54.65 -            return prev_;
   54.66 -        }
   54.67 -
   54.68 -      private:
   54.69 -        SymbolEnv **envp_;
   54.70 -        SymbolEnv *prev_;
   54.71 -        Scope *scope_;
   54.72 -    };
   54.73 -
   54.74 -    enum ReturnStatus {
   54.75 -        NoReturn,
   54.76 -        VoidReturn,
   54.77 -        ValueReturn
   54.78 -    };
   54.79 -
   54.80 -    class FunctionScope
   54.81 -    {
   54.82 -      public:
   54.83 -        FunctionScope(FunctionScope **prevp)
   54.84 -          : prevp_(prevp),
   54.85 -            prev_(*prevp),
   54.86 -            status_(NoReturn)
   54.87 -        {
   54.88 -            *prevp_ = this;
   54.89 -        }
   54.90 -        ~FunctionScope() {
   54.91 -            *prevp_ = prev_;
   54.92 -        }
   54.93 -        ReturnStatus returns() const {
   54.94 -            return status_;
   54.95 -        }
   54.96 -        void returns(ReturnStatus status) {
   54.97 -            if (status > status_)
   54.98 -                status_ = status;
   54.99 -        }
  54.100 -      private:
  54.101 -        FunctionScope **prevp_;
  54.102 -        FunctionScope *prev_;
  54.103 -        ReturnStatus status_;
  54.104 -    };
  54.105 -
  54.106 -  public:
  54.107 -    NamePopulator(Zone *zone, CompileContext &cc, TranslationUnit *unit)
  54.108 -      : zone_(zone),
  54.109 -        pool_(zone->pool()),
  54.110 -        cc_(cc),
  54.111 -        unit_(unit),
  54.112 -        env_(NULL),
  54.113 -        fun_(NULL)
  54.114 -    {
  54.115 -    }
  54.116 -
  54.117 -    void analyze() {
  54.118 -        ImportScope *importScope = ImportScope::New(pool_);
  54.119 -        if (!importScope)
  54.120 -            return;
  54.121 -
  54.122 -        // At the import level, we declare system types.
  54.123 -        if (!declareSystemTypes(importScope))
  54.124 -            return;
  54.125 -
  54.126 -        GlobalScope *globalScope = GlobalScope::New(pool_, importScope);
  54.127 -        if (!globalScope)
  54.128 -            return;
  54.129 -
  54.130 -        unit_->setImportScope(importScope);
  54.131 -        unit_->setGlobalScope(globalScope);
  54.132 -
  54.133 -        SymbolEnv env(&env_, globalScope);
  54.134 -
  54.135 -        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
  54.136 -            Statement *stmt = unit_->tree()->statements()->at(i);
  54.137 -            stmt->accept(this);
  54.138 -        }
  54.139 -
  54.140 -        return;
  54.141 -    }
  54.142 -
  54.143 -    bool declareSystemType(ImportScope *scope, const char *name, Handle<Type> effective) {
  54.144 -        Local<String> tag(zone_, zone_->makeSymbol(name));
  54.145 -        if (!tag)
  54.146 -            return false;
  54.147 -
  54.148 -        Local<Type> type(zone_, zone_->types()->getType());
  54.149 -
  54.150 -        TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type, effective);
  54.151 -        return scope->addSymbol(sym);
  54.152 -    }
  54.153 -
  54.154 -    bool declareSystemType(ImportScope *scope, const char *name, PrimitiveType prim) {
  54.155 -        Local<Type> primitive(zone_, zone_->types()->getPrimitive(prim));
  54.156 -        assert(primitive);
  54.157 -        return declareSystemType(scope, name, primitive);
  54.158 -    }
  54.159 -
  54.160 -    bool declareSystemTypes(ImportScope *scope) {
  54.161 -        if (!declareSystemType(scope, "float", PrimitiveType_Float))
  54.162 -            return false;
  54.163 -        if (!declareSystemType(scope, "_", PrimitiveType_Int32))
  54.164 -            return false;
  54.165 -        if (!declareSystemType(scope, "int", PrimitiveType_Int32))
  54.166 -            return false;
  54.167 -        if (!declareSystemType(scope, "bool", PrimitiveType_Bool))
  54.168 -            return false;
  54.169 -        if (!declareSystemType(scope, "char", PrimitiveType_Char))
  54.170 -            return false;
  54.171 -
  54.172 -        Local<Type> voidType(zone_, zone_->types()->getVoid());
  54.173 -        if (!declareSystemType(scope, "void", voidType))
  54.174 -            return false;
  54.175 -
  54.176 -        return true;
  54.177 -    }
  54.178 -
  54.179 -    void visitVariableDeclaration(VariableDeclaration *node) {
  54.180 -        Scope *scope = env_->scope();
  54.181 -        if (!scope || scope->kind() != Scope::GLOBAL) {
  54.182 -            if ((scope = getOrCreateBlockScope()) == NULL)
  54.183 -                return;
  54.184 -        }
  54.185 -
  54.186 -        if (scope->kind() == Scope::GLOBAL) {
  54.187 -            // The symbol must be added now, since it could be an export.
  54.188 -            VariableSymbol *sym = new (pool_) VariableSymbol(scope, node->name(), node->pos());
  54.189 -            node->setSymbol(sym);
  54.190 -
  54.191 -            if (!registerName(scope, sym))
  54.192 -                return;
  54.193 -        } else {
  54.194 -            // We ensure the scope will exist at the name binding phase, but
  54.195 -            // we don't actually register the variable symbol yet. Otherwise,
  54.196 -            // when binding the initializer, we could encounter:
  54.197 -            //    new x = x;
  54.198 -            //
  54.199 -            // And we don't necessarily want this to bind.
  54.200 -        }
  54.201 -
  54.202 -        if (node->initialization())
  54.203 -            node->initialization()->accept(this);
  54.204 -    }
  54.205 -
  54.206 -    void visitEnumStatement(EnumStatement *node) {
  54.207 -        Local<String> name(zone_, node->name());
  54.208 -        Local<Type> type(zone_);
  54.209 -        if (name)
  54.210 -            type = zone_->types()->newEnum(name);
  54.211 -        else
  54.212 -            type = zone_->types()->getPrimitive(PrimitiveType_Int32);
  54.213 -
  54.214 -        if (!type)
  54.215 -            return;
  54.216 -
  54.217 -        Scope *scope = getGlobalOrCreateBlockScope();
  54.218 -        if (!scope)
  54.219 -            return;
  54.220 -
  54.221 -        if (name) {
  54.222 -            Local<Type> symType(zone_, zone_->types()->getType());
  54.223 -            TypeSymbol *sym = new (pool_) TypeSymbol(scope, name, symType, type);
  54.224 -            if (!registerName(scope, sym))
  54.225 -                return;
  54.226 -
  54.227 -            if (scope->kind() == Scope::GLOBAL) {
  54.228 -                if (!unit_->globalScope()->exported()->append(sym))
  54.229 -                    return;
  54.230 -            }
  54.231 -        }
  54.232 -
  54.233 -        // We want each field of the expression to qualify as a constant expression.
  54.234 -        if ((type = zone_->types()->qualify(type, TypeQual_ConstExpr)) == NULL)
  54.235 -            return;
  54.236 -        
  54.237 -        int value = 0;
  54.238 -        for (size_t i = 0; i < node->entries()->length(); i++) {
  54.239 -            EnumStatement::Entry &entry = node->entries()->at(i);
  54.240 -            BoxedPrimitive box = BoxedPrimitive::Int(value);
  54.241 -            if (entry.expr) {
  54.242 -                if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
  54.243 -                    cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
  54.244 -                    return;
  54.245 -                }
  54.246 -
  54.247 -                assert(box.type() == PrimitiveType_Int32);
  54.248 -                value = box.toInt();
  54.249 -            }
  54.250 -         
  54.251 -            ConstantSymbol *sym = new (pool_) ConstantSymbol(scope, entry.name, entry.pos, type, box);
  54.252 -            if (!registerName(scope, sym))
  54.253 -                return;
  54.254 -            if (scope->kind() == Scope::GLOBAL) {
  54.255 -                if (!unit_->globalScope()->exported()->append(sym))
  54.256 -                    return;
  54.257 -            }
  54.258 -
  54.259 -            entry.sym = sym;
  54.260 -            value++;
  54.261 -        }
  54.262 -    }
  54.263 -
  54.264 -    void visitFunctionStatement(FunctionStatement *node) {
  54.265 -        // We create function types ahead of time, not for any particular
  54.266 -        // reason. It makes things consistent with FunctionTypeStatement,
  54.267 -        // which actually does produce a type.
  54.268 -        Local<FunctionType> type(zone_, FunctionType::New(zone_, node->name(), node->token()));
  54.269 -        if (!type)
  54.270 -            return;
  54.271 -
  54.272 -        assert(env_->scope());
  54.273 -
  54.274 -        // Function statements are always named, so add the name to the outer scope.
  54.275 -        FunctionSymbol *sym = new (pool_) FunctionSymbol(env_->scope(), node->name(), node->pos(), type);
  54.276 -        if (!registerName(env_->scope(), sym))
  54.277 -            return;
  54.278 -
  54.279 -        if (node->token() == TOK_PUBLIC ||
  54.280 -            node->token() == TOK_FORWARD ||
  54.281 -            node->token() == TOK_NATIVE)
  54.282 -        {
  54.283 -            // We're in the global scope, for sure.
  54.284 -            assert(env_->scope()->kind() == Scope::GLOBAL);
  54.285 -
  54.286 -            if (!unit_->globalScope()->exported()->append(sym))
  54.287 -                return;
  54.288 -        }
  54.289 -
  54.290 -        node->setSymbol(sym);
  54.291 -
  54.292 -        // Scope for the function's arguments.
  54.293 -        SymbolEnv argEnv(&env_);
  54.294 -        if (!registerArguments(node->signature()))
  54.295 -            return;
  54.296 -
  54.297 -        // Scope for function body.
  54.298 -        SymbolEnv localEnv(&env_);
  54.299 -        FunctionScope fun(&fun_);
  54.300 -        if (node->body())
  54.301 -            node->body()->accept(this);
  54.302 -
  54.303 -        // Function statements have quirky semantics around their return
  54.304 -        // type. For reasonable compatibility with SP1, we use the following
  54.305 -        // heuristics for when no explicit type is declared.
  54.306 -        if (!node->signature().returnType()) {
  54.307 -            Local<Type> type(zone_);
  54.308 -            if (node->token() == TOK_FORWARD || node->token() == TOK_NATIVE) {
  54.309 -                // If the function type is a native or forward, we always
  54.310 -                // assume it returns an int32.
  54.311 -                type = zone_->types()->getPrimitive(PrimitiveType_Int32);
  54.312 -            } else if (fun.returns() != ValueReturn) {
  54.313 -                // This function never returns a value, so mark it as
  54.314 -                // returning void.
  54.315 -                type = zone_->types()->getVoid();
  54.316 -            }
  54.317 -            // No need to NULL check here, we'll catch OOM later.
  54.318 -            node->sym()->type()->setReturnType(type);
  54.319 -        }
  54.320 -
  54.321 -        node->setScopes(argEnv.scope(), localEnv.scope());
  54.322 -    }
  54.323 -
  54.324 -    void visitStructureStatement(StructureStatement *node) {
  54.325 -        assert(false);
  54.326 -    }
  54.327 -
  54.328 -    void visiFunctionTypeStatementt(FunctionTypeStatement *node) {
  54.329 -        assert(false);
  54.330 -    }
  54.331 -
  54.332 -    void visitNameProxy(NameProxy *name) {
  54.333 -    }
  54.334 -    void visitAssignment(Assignment *node) {
  54.335 -        node->lvalue()->accept(this);
  54.336 -        node->expression()->accept(this);
  54.337 -    }
  54.338 -    void visitBinaryExpression(BinaryExpression *node) {
  54.339 -        node->left()->accept(this);
  54.340 -        node->right()->accept(this);
  54.341 -    }
  54.342 -    void visitReturnStatement(ReturnStatement *node) {
  54.343 -        if (node->expression())
  54.344 -            fun_->returns(ValueReturn);
  54.345 -        else
  54.346 -            fun_->returns(VoidReturn);
  54.347 -    }
  54.348 -    void visitForStatement(ForStatement *node) {
  54.349 -        SymbolEnv env(&env_);
  54.350 -
  54.351 -        if (node->initialization())
  54.352 -            node->initialization()->accept(this);
  54.353 -        if (node->condition())
  54.354 -            node->condition()->accept(this);
  54.355 -        if (node->update())
  54.356 -            node->update()->accept(this);
  54.357 -        node->body()->accept(this);
  54.358 -
  54.359 -        node->setScope(env.scope());
  54.360 -    }
  54.361 -    void visitBlockStatement(BlockStatement *node) {
  54.362 -        if (node->type() == TOK_NEW) {
  54.363 -            // Don't create a symbol environment for this block, since it
  54.364 -            // was created solely to house multiple variable decls.
  54.365 -            for (size_t i = 0; i < node->statements()->length(); i++)
  54.366 -                node->statements()->at(i)->accept(this);
  54.367 -        } else {
  54.368 -            assert(node->type() == TOK_LBRACE);
  54.369 -
  54.370 -            SymbolEnv env(&env_);
  54.371 -
  54.372 -            for (size_t i = 0; i < node->statements()->length(); i++)
  54.373 -                node->statements()->at(i)->accept(this);
  54.374 -        
  54.375 -            if (node->type() == TOK_NEW) {
  54.376 -                assert(!env.scope());
  54.377 -                return;
  54.378 -            }
  54.379 -
  54.380 -            node->setScope(env.scope());
  54.381 -        }
  54.382 -    }
  54.383 -    void visitIntegerLiteral(IntegerLiteral *node) {
  54.384 -    }
  54.385 -    void visitExpressionStatement(ExpressionStatement *node) {
  54.386 -        node->expression()->accept(this);
  54.387 -    }
  54.388 -    void visitCallExpression(CallExpression *node) {
  54.389 -        node->callee()->accept(this);
  54.390 -        for (size_t i = 0; i < node->arguments()->length(); i++)
  54.391 -            node->arguments()->at(i)->accept(this);
  54.392 -    }
  54.393 -    void visitIfStatement(IfStatement *node) {
  54.394 -        node->ifTrue()->accept(this);
  54.395 -        if (node->ifFalse())
  54.396 -            node->ifFalse()->accept(this);
  54.397 -    }
  54.398 -    void visitIndexExpression(IndexExpression *node) {
  54.399 -        node->left()->accept(this);
  54.400 -        node->right()->accept(this);
  54.401 -    }
  54.402 -    void visitFloatLiteral(FloatLiteral *node) {
  54.403 -    }
  54.404 -    void visitWhileStatement(WhileStatement *node) {
  54.405 -        node->condition()->accept(this);
  54.406 -        node->body()->accept(this);
  54.407 -    }
  54.408 -    void visitBreakStatement(BreakStatement *node) {
  54.409 -    }
  54.410 -    void visitContinueStatement(ContinueStatement *node) {
  54.411 -    }
  54.412 -    void visitStringLiteral(StringLiteral *node) {
  54.413 -    }
  54.414 -    void visitIncDecExpression(IncDecExpression *node) {
  54.415 -        node->expression()->accept(this);
  54.416 -    }
  54.417 -    void visitUnaryExpression(UnaryExpression *node) {
  54.418 -        node->expression()->accept(this);
  54.419 -    }
  54.420 -    void visitTernaryExpression(TernaryExpression *node) {
  54.421 -        assert(false);
  54.422 -    }
  54.423 -    void visitBooleanLiteral(BooleanLiteral *node) {
  54.424 -    }
  54.425 -    void visitFieldExpression(FieldExpression *node) {
  54.426 -    }
  54.427 -    void visitSwitchStatement(SwitchStatement *node) {
  54.428 -        if (node->defaultCase())
  54.429 -            node->defaultCase()->accept(this);
  54.430 -
  54.431 -        for (size_t i = 0; i < node->cases()->length(); i++)
  54.432 -            node->cases()->at(i)->statement()->accept(this);
  54.433 -    }
  54.434 -    void visitArrayLiteral(ArrayLiteral *node) {
  54.435 -    }
  54.436 -    void visitImportStatement(ImportStatement *node) {
  54.437 -    }
  54.438 -
  54.439 -  private:
  54.440 -    Scope *getGlobalOrCreateBlockScope() {
  54.441 -        if (env_->scope()) {
  54.442 -            assert(env_->scope()->kind() == Scope::BLOCK ||
  54.443 -                   env_->scope()->kind() == Scope::GLOBAL);
  54.444 -            return env_->scope();
  54.445 -        }
  54.446 -        return getOrCreateBlockScope();
  54.447 -    }
  54.448 -    Scope *getOrCreateBlockScope() {
  54.449 -        if (env_->scope()) {
  54.450 -            assert(env_->scope()->kind() == Scope::BLOCK);
  54.451 -            return env_->scope();
  54.452 -        }
  54.453 -        
  54.454 -        LocalScope *scope = LocalScope::New(pool_);
  54.455 -        if (!scope)
  54.456 -            return NULL;
  54.457 -
  54.458 -        env_->setScope(scope);
  54.459 -        return scope;
  54.460 -    }
  54.461 -
  54.462 -    bool registerName(Scope *scope, Symbol *sym) {
  54.463 -        if (!scope)
  54.464 -            return false;
  54.465 -
  54.466 -        if (Symbol *other = scope->localLookup(sym->name())) {
  54.467 -            // Report, but allow errors to continue.
  54.468 -            cc_.reportError(sym->pos(), Message_RedeclaredName,
  54.469 -                            sym->name()->chars(),
  54.470 -                            other->pos().line,
  54.471 -                            other->pos().col);
  54.472 -            return true;
  54.473 -        }
  54.474 -
  54.475 -        return scope->addSymbol(sym);
  54.476 -    }
  54.477 -
  54.478 -    bool registerArguments(const FunctionSignature &sig) {
  54.479 -        if (!sig.parameters()->length())
  54.480 -            return true;
  54.481 -
  54.482 -        ArgumentScope *argScope = ArgumentScope::New(pool_);
  54.483 -        if (!argScope)
  54.484 -            return false;
  54.485 -        env_->setScope(argScope);
  54.486 -
  54.487 -        for (size_t i = 0; i < sig.parameters()->length(); i++) {
  54.488 -            Parameter *param = sig.parameters()->at(i);
  54.489 -            VariableSymbol *sym = new (pool_) VariableSymbol(argScope, param->name(), param->pos());
  54.490 -            if (!registerName(env_->scope(), sym))
  54.491 -                return false;
  54.492 -            param->setSymbol(sym);
  54.493 -        }
  54.494 -
  54.495 -        return true;
  54.496 -    }
  54.497 -
  54.498 -  private:
  54.499 -    Zone *zone_;
  54.500 -    PoolAllocator &pool_;
  54.501 -    CompileContext &cc_;
  54.502 -    TranslationUnit *unit_;
  54.503 -    SymbolEnv *env_;
  54.504 -    FunctionScope *fun_;
  54.505 -};
  54.506 -
  54.507 -void
  54.508 -ke::PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
  54.509 -{
  54.510 -    AutoEnterCompileContext enter(cc, unit);
  54.511 -    NamePopulator populator(zone, cc, unit);
  54.512 -    populator.analyze();
  54.513 -}
  54.514 -
  54.515 -static const int INFER_ARRAY_SIZE = 0;
  54.516 -static const int EVAL_ARRAY_SIZE = -1;
  54.517 -static const int DYNAMIC_ARRAY_SIZE = -2;
  54.518 -
  54.519 -class NameBinderBase : public AstVisitor
  54.520 -{
  54.521 -  public:
  54.522 -    NameBinderBase(Zone *zone, CompileContext &cc, TranslationUnit *unit)
  54.523 -      : zone_(zone),
  54.524 -        pool_(zone->pool()),
  54.525 -        cc_(cc),
  54.526 -        unit_(unit)
  54.527 -    {
  54.528 -    }
  54.529 -
  54.530 -  protected:
  54.531 -    Type *buildVariableType(VariableDeclaration *node) {
  54.532 -        Local<Type> type(zone_, bindType(node->type(), node->quals()));
  54.533 -        if (!type)
  54.534 -            return NULL;
  54.535 -
  54.536 -        // We don't allow array typedefs yet.
  54.537 -        assert(!type->isArray());
  54.538 -
  54.539 -        if (node->dims()) {
  54.540 -            int dims[MAX_ARRAY_DEPTH];
  54.541 -            int levels = evaluateDimensions(node->pos(), type, node->dims(), dims);
  54.542 -            if (levels < 0)
  54.543 -                return NULL;
  54.544 -
  54.545 -            // Do some extra inference based on the initializer, if present.
  54.546 -            Expression *init = node->initialization();
  54.547 -            if (init) {
  54.548 -                if (init->isArrayLiteral() && init->toArrayLiteral()->isFixed()) {
  54.549 -                    Local<Type> contained(zone_, type->isArray()
  54.550 -                                                 ? ArrayType::cast(type)->contained()
  54.551 -                                                 : type);
  54.552 -                    if (!inferFixedArrayDimensions(init->toArrayLiteral(), contained, dims, levels))
  54.553 -                        return NULL;
  54.554 -                } else if (init->isStringLiteral()) {
  54.555 -                    dims[levels - 1] = init->toStringLiteral()->string()->length() + 1;
  54.556 -                }
  54.557 -            }
  54.558 -
  54.559 -            // If we got extra dimensions, we need to build a new type.
  54.560 -            if (node->dims()) {
  54.561 -                if ((type = buildArrayType(type, node->quals(), dims, node->dims()->length())) == NULL)
  54.562 -                    return NULL;
  54.563 -            }
  54.564 -        }
  54.565 -
  54.566 -        return type;
  54.567 -    }
  54.568 -
  54.569 -    int evaluateDimensions(const SourcePosition &pos, Handle<Type> typeArg, ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) {
  54.570 -        unsigned level = 0;
  54.571 -        Local<Type> type(zone_, typeArg);
  54.572 -        while (type->isArray()) {
  54.573 -            ArrayType *atype = ArrayType::cast(type);
  54.574 -            dims[level] = atype->isFixedLength()
  54.575 -                          ? atype->fixedLength()
  54.576 -                          : DYNAMIC_ARRAY_SIZE;
  54.577 -            type = atype->contained();
  54.578 -            level++;
  54.579 -        }
  54.580 -
  54.581 -        if (!exprs)
  54.582 -            return level;
  54.583 -
  54.584 -        if (level + exprs->length() > MAX_ARRAY_DEPTH) {
  54.585 -            cc_.reportError(pos, Message_MaximumArrayDepth);
  54.586 -            return -1;
  54.587 -        }
  54.588 -
  54.589 -        bool hadEmptySize = false;
  54.590 -        for (size_t i = 0; i < exprs->length(); i++) {
  54.591 -            Expression *expr = exprs->at(i);
  54.592 -            if (!expr) {
  54.593 -                dims[i] = INFER_ARRAY_SIZE;
  54.594 -                hadEmptySize = true;
  54.595 -                continue;
  54.596 -            }
  54.597 -
  54.598 -            BoxedPrimitive box;
  54.599 -            if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
  54.600 -                int size = box.toInt();
  54.601 -                if (size <= 0) {
  54.602 -                    cc_.reportError(expr->pos(), Message_BadArraySize);
  54.603 -                    return false;
  54.604 -                }
  54.605 -
  54.606 -                dims[i] = size;
  54.607 -                continue;
  54.608 -            }
  54.609 -
  54.610 -            if (hadEmptySize) {
  54.611 -                cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
  54.612 -                return false;
  54.613 -            }
  54.614 -
  54.615 -            dims[i] = EVAL_ARRAY_SIZE;
  54.616 -        }
  54.617 -
  54.618 -        return level + exprs->length();
  54.619 -    }
  54.620 -
  54.621 -    // This function computes missing dimension sizes based on a literal
  54.622 -    // initializer. We don't really handle any size rules here; we just
  54.623 -    // do a really dumb inference.
  54.624 -    bool inferFixedArrayDimensions(ArrayLiteral *lit, Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], int levels) {
  54.625 -        for (int i = 0; i < levels; i++) {
  54.626 -            if (dims[i] == EVAL_ARRAY_SIZE || dims[i] == DYNAMIC_ARRAY_SIZE) {
  54.627 -                // The following are invalid:
  54.628 -                //   new x[<expr>] = {...}
  54.629 -                //   new Type:x = {...}  // where Type is a non-fixed array type
  54.630 -                cc_.reportError(lit->pos(), Message_CannotInitializeEvalArray);
  54.631 -                return false;
  54.632 -            }
  54.633 -
  54.634 -            if (dims[i] == INFER_ARRAY_SIZE) {
  54.635 -                // Character arrays are always dynamic when inferred from string literals.
  54.636 -                if (i == levels - 1 && contained->isChar())
  54.637 -                    dims[i] = DYNAMIC_ARRAY_SIZE;
  54.638 -                else
  54.639 -                    dims[i] = lit->expressions()->length();
  54.640 -            }
  54.641 -
  54.642 -            if (i != levels - 1) {
  54.643 -                // Fixed array literals are guaranteed to have at least one expression.
  54.644 -                Expression *next = lit->expressions()->at(0);
  54.645 -                if (!next->isArrayLiteral()) {
  54.646 -                    // Whelp... this array is just malformed. Not the best error message
  54.647 -                    // but whatever.
  54.648 -                    cc_.reportError(next->pos(), Message_ArraySizeCannotBeDetermined);
  54.649 -                    return false;
  54.650 -                }
  54.651 -                lit = next->toArrayLiteral();
  54.652 -            }
  54.653 -        }
  54.654 -
  54.655 -        return true;
  54.656 -    }
  54.657 -
  54.658 -    ArrayType *buildArrayType(Handle<Type> contained, TypeQualifiers quals, int dims[MAX_ARRAY_DEPTH], size_t postlevels) {
  54.659 -        Local<Type> type(zone_, contained);
  54.660 -
  54.661 -        for (size_t i = postlevels - 1; i < postlevels; i--) {
  54.662 -            int size = dims[i] > 0
  54.663 -                       ? dims[i]
  54.664 -                       : ArrayType::DYNAMIC_ARRAY_SIZE;
  54.665 -            
  54.666 -            if ((type = zone_->types()->newArray(contained, size)) == NULL)
  54.667 -                return NULL;
  54.668 -            if ((type = zone_->types()->qualify(type, quals)) == NULL)
  54.669 -                return NULL;
  54.670 -        }
  54.671 -        return ArrayType::cast(type);
  54.672 -    }
  54.673 -
  54.674 -    bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
  54.675 -        Local<Type> type(zone_);
  54.676 -        if (!fun->returnType()) {
  54.677 -            if ((type = bindType(sig.returnType(), TypeQual_None)) == NULL)
  54.678 -                return false;
  54.679 -            fun->setReturnType(type);
  54.680 -        }
  54.681 -
  54.682 -        if (sig.variadic())
  54.683 -            fun->setVariadic();
  54.684 -
  54.685 -        Local<FixedArray> params(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
  54.686 -        if (!params)
  54.687 -            return false;
  54.688 -
  54.689 -        for (size_t i = 0; i < sig.parameters()->length(); i++) {
  54.690 -            Parameter *param = sig.parameters()->at(i);
  54.691 -            if ((type = bindType(param->type(), param->quals())) == NULL)
  54.692 -                return false;
  54.693 -
  54.694 -            assert(!type->isArray());
  54.695 -
  54.696 -            if (param->dims()) {
  54.697 -                int dims[MAX_ARRAY_DEPTH];
  54.698 -                int levels = evaluateDimensions(param->pos(), type, param->dims(), dims);
  54.699 -                if (levels < 0)
  54.700 -                    return false;
  54.701 -
  54.702 -                // If we got extra dimensions, we need to build a new type.
  54.703 -                // Unlike variables, we do not infer anything about array
  54.704 -                // sizes from its default initializer.
  54.705 -                if (param->dims()) {
  54.706 -                    if ((type = buildArrayType(type, param->quals(), dims, param->dims()->length())) == NULL)
  54.707 -                        return false;
  54.708 -                }
  54.709 -
  54.710 -                if (ArrayType::cast(type)->innermost()->isVoid()) {
  54.711 -                    cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
  54.712 -                    return false;
  54.713 -                }
  54.714 -            }
  54.715 -
  54.716 -            if (param->reference()) {
  54.717 -                if (!type->isPod()) {
  54.718 -                    cc_.reportError(param->pos(), Message_ArrayCantBeReference);
  54.719 -                    return false;
  54.720 -                }
  54.721 -                if (param->quals() & TypeQual_Const) {
  54.722 -                    cc_.reportError(param->pos(), Message_CannotConstReference);
  54.723 -                    return false;
  54.724 -                }
  54.725 -                if ((type = zone_->types()->getReference(type, false)) == NULL)
  54.726 -                    return false;
  54.727 -            }
  54.728 -            if (param->quals() & TypeQual_Const) {
  54.729 -                if (!type->isArray() && !type->isStruct()) {
  54.730 -                    cc_.reportError(param->pos(), Message_InvalidConstOnFormal);
  54.731 -                    return false;
  54.732 -                }
  54.733 -            }
  54.734 -
  54.735 -            if (type->isVoid()) {
  54.736 -                cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
  54.737 -                return false;
  54.738 -            }
  54.739 -
  54.740 -            params->set(zone_, i, type);
  54.741 -            param->sym()->setType(type);
  54.742 -        }
  54.743 -
  54.744 -        fun->setParameterTypes(params);
  54.745 -
  54.746 -        return true;
  54.747 -    }
  54.748 -
  54.749 -    Type *bindType(Expression *expr, TypeQualifiers quals) {
  54.750 -        Local<Type> type(zone_);
  54.751 -
  54.752 -        if (!expr) {
  54.753 -            // If no type was declared, we return int32.
  54.754 -            type = zone_->types()->getPrimitive(PrimitiveType_Int32);
  54.755 -        } else {
  54.756 -            expr->accept(this);
  54.757 -
  54.758 -            NameProxy *proxy = expr->asNameProxy();
  54.759 -            assert(proxy);
  54.760 -
  54.761 -            Symbol *sym = proxy->sym();
  54.762 -            if (!sym)
  54.763 -                return NULL;
  54.764 -
  54.765 -            if (!sym->isType()) {
  54.766 -                cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars());
  54.767 -                return NULL;
  54.768 -            }
  54.769 -
  54.770 -            type = sym->toType()->effective();
  54.771 -        }
  54.772 -
  54.773 -        return zone_->types()->qualify(type, quals);
  54.774 -    }
  54.775 -
  54.776 -  protected:
  54.777 -    Zone *zone_;
  54.778 -    PoolAllocator &pool_;
  54.779 -    CompileContext &cc_;
  54.780 -    TranslationUnit *unit_;
  54.781 -};
  54.782 -
  54.783 -class GlobalBuilder : public NameBinderBase
  54.784 -{
  54.785 -    typedef ScopedRoot<Descriptor> ScopedDescriptor;
  54.786 -    struct PrimitiveFill {
  54.787 -        ScopedDescriptor *desc;
  54.788 -        BoxedPrimitive prim;
  54.789 -
  54.790 -        PrimitiveFill(ScopedDescriptor *desc, BoxedPrimitive prim)
  54.791 -          : desc(desc),
  54.792 -            prim(prim)
  54.793 -        {
  54.794 -        }
  54.795 -    };
  54.796 -
  54.797 -  public:
  54.798 -    GlobalBuilder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
  54.799 -      : NameBinderBase(zone, cc, unit),
  54.800 -        globalScope_(unit->globalScope())
  54.801 -    {
  54.802 -    }
  54.803 -
  54.804 -    Struct *build() {
  54.805 -        for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
  54.806 -            unit_->tree()->imports()->at(i)->accept(this);
  54.807 -
  54.808 -        // Next, enter the global scope and walk all statements.
  54.809 -        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
  54.810 -            Statement *stmt = unit_->tree()->statements()->at(i);
  54.811 -            stmt->accept(this);
  54.812 -        }
  54.813 -
  54.814 -        Local<Struct> globals(zone_, createGlobals());
  54.815 -        if (!globals)
  54.816 -            return NULL;
  54.817 -
  54.818 -        populate(globals);
  54.819 -
  54.820 -        return globals;
  54.821 -    }
  54.822 -
  54.823 -  private:
  54.824 -    Struct *createGlobals() {
  54.825 -        Local<FixedArray> descs(zone_, FixedArray::New(zone_, descriptors_.length(), Heap::Tenure_Old));
  54.826 -        if (!descs)
  54.827 -            return NULL;
  54.828 -
  54.829 -        for (unsigned i = 0; i < descriptors_.length(); i++)
  54.830 -            descs->set(zone_, i, *descriptors_[i]);
  54.831 -
  54.832 -        Local<String> name(zone_, unit_->module()->name());
  54.833 -        Local<StructType> type(zone_, StructType::New(zone_, name, descs));
  54.834 -        if (!type)
  54.835 -            return NULL;
  54.836 -
  54.837 -        Local<StructMap> map(zone_, type->newMap());
  54.838 -        return Struct::New(zone_, map, Heap::Tenure_Old);
  54.839 -    }
  54.840 -
  54.841 -    void populate(Handle<Struct> globals) {
  54.842 -        // This is a huge hack, but it's probably better than a full extra
  54.843 -        // pass. The problem is that until we have all the descriptors, we
  54.844 -        // can't start setting constexprs in the struct, and we need to set
  54.845 -        // them now so they're available during full semantic analysis. To
  54.846 -        // work around this, we build up the list of values we need to set
  54.847 -        // as we build up descriptors, and then populate the global struct
  54.848 -        // with this set.
  54.849 -        //
  54.850 -        // Note, this code is also kind of dead until we support linking. We
  54.851 -        // handle constexprs explicitly in importFrom(), by sniffing out the
  54.852 -        // symbol type. That code will go away later.
  54.853 -        for (size_t i = 0; i < primitiveFills_.length(); i++) {
  54.854 -            const PrimitiveFill &fill = primitiveFills_[i];
  54.855 -            assert(fill.prim.type() == PrimitiveType_Int32);
  54.856 -            globals->set(*fill.desc, fill.prim.toInt());
  54.857 -        }
  54.858 -    }
  54.859 -
  54.860 -  public:
  54.861 -    void visitEnumStatement(EnumStatement *stmt) {
  54.862 -        if (stmt->visibility() != TOK_PUBLIC || !stmt->name())
  54.863 -            return;
  54.864 -
  54.865 -        Local<Type> type(zone_, zone_->types()->getType());
  54.866 -        Descriptor *desc = Descriptor::New(zone_, stmt->name(), type, Descriptor::Public);
  54.867 -        if (!desc)
  54.868 -            return;
  54.869 -        if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
  54.870 -            return;
  54.871 -
  54.872 -        for (size_t i = 0; i < stmt->entries()->length(); i++) {
  54.873 -            EnumStatement::Entry &e = stmt->entries()->at(i);
  54.874 -            ScopedDescriptor *desc = new (pool_) ScopedDescriptor(Descriptor::New(zone_, e.name, e.sym->type(), Descriptor::Public));
  54.875 -            if (!desc || !descriptors_.append(desc))
  54.876 -                return;
  54.877 -
  54.878 -            // Save the value so we can export it immediately.
  54.879 -            if (!primitiveFills_.append(PrimitiveFill(desc, e.sym->value())))
  54.880 -                return;
  54.881 -        }
  54.882 -    }
  54.883 -
  54.884 -    void visitNameProxy(NameProxy *proxy) {
  54.885 -        Scope *scope = unit_->globalScope();
  54.886 -        Symbol *sym = scope->lookup(proxy->name());
  54.887 -        if (!sym)
  54.888 -            cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
  54.889 -        proxy->bind(sym);
  54.890 -    }
  54.891 -
  54.892 -    void visitFunctionStatement(FunctionStatement *node) {
  54.893 -        Local<FunctionType> type(zone_, node->sym()->type());
  54.894 -        if (!fillFunctionType(type, node->signature()))
  54.895 -            return;
  54.896 -
  54.897 -        unsigned offset;
  54.898 -        if (!builder_.add(type, &offset))
  54.899 -            return;
  54.900 -
  54.901 -        Descriptor::Visibility visibility = (node->token() == TOK_NATIVE || node->token() == TOK_FORWARD)
  54.902 -                                            ? Descriptor::Public
  54.903 -                                            : Descriptor::Private;
  54.904 -
  54.905 -        Descriptor *desc = Descriptor::New(zone_, node->name(), type, visibility);
  54.906 -        if (!desc)
  54.907 -            return;
  54.908 -        if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
  54.909 -            return;
  54.910 -    }
  54.911 -
  54.912 -    void visitVariableDeclaration(VariableDeclaration *node) {
  54.913 -        Local<Type> type(zone_, buildVariableType(node));
  54.914 -        if (!type)
  54.915 -            return;
  54.916 -
  54.917 -        // If we're in global scope, and we received a |const| qualifier, then
  54.918 -        // we extend this to array references as well. This is to sort of mimic
  54.919 -        // SP1 functionality, but also means that you cannot have changeable
  54.920 -        // const pointers in global scope.
  54.921 -        if ((node->quals() & TypeQual_Const) && type->isArray()) {
  54.922 -            if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL)
  54.923 -                return;
  54.924 -        }
  54.925 -
  54.926 -        node->sym()->setType(type);
  54.927 -
  54.928 -        unsigned offset;
  54.929 -        if (!builder_.add(type, &offset))
  54.930 -            return;
  54.931 -
  54.932 -        Descriptor *desc = Descriptor::New(zone_, node->name(), type, Descriptor::Private);
  54.933 -        if (!desc)
  54.934 -            return;
  54.935 -        if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
  54.936 -            return;
  54.937 -    }
  54.938 -
  54.939 -    void visitImportStatement(ImportStatement *node) {
  54.940 -        if (!node->names()) {
  54.941 -            PathComponent *path = node->path();
  54.942 -            while (path->next)
  54.943 -                path = path->next;
  54.944 -
  54.945 -            // Imports automatically go into the importScope. For now, we
  54.946 -            // error if there are any duplicate symbols entered into the
  54.947 -            // importScope.
  54.948 -            if (unit_->importScope()->localLookup(path->name)) {
  54.949 -                cc_.reportError(node->pos(), Message_DuplicateImport, path->name->chars());
  54.950 -                return;
  54.951 -            }
  54.952 -
  54.953 -            Local<Type> type(zone_, zone_->types()->getImportable());
  54.954 -            ImportSymbol *sym = new (pool_) ImportSymbol(unit_->importScope(), path->name, node->pos(), type, node->importIndex());
  54.955 -            if (!unit_->importScope()->addSymbol(sym))
  54.956 -                return;
  54.957 -        } else if (node->importAllNames()) {
  54.958 -            Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
  54.959 -            if (importable->isPackage()) {
  54.960 -                assert(false);
  54.961 -            } else {
  54.962 -                Local<Module> module(zone_, Module::cast(importable));
  54.963 -                if (!module->globals())
  54.964 -                    importAllFromTranslationUnit(node, module->translationUnit());
  54.965 -                else
  54.966 -                    assert(false);
  54.967 -            }
  54.968 -        } else {
  54.969 -            Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
  54.970 -            if (importable->isPackage()) {
  54.971 -                assert(false);
  54.972 -            } else {
  54.973 -                Local<Module> module(zone_, Module::cast(importable));
  54.974 -
  54.975 -                // Always grab from the translation unit if we can, for now.
  54.976 -                if (module->translationUnit())
  54.977 -                    importFromTranslationUnit(node, module->translationUnit());
  54.978 -                else
  54.979 -                    assert(false);
  54.980 -            }
  54.981 -        }
  54.982 -    }
  54.983 -
  54.984 -  private:
  54.985 -    bool importFrom(ImportStatement *node, Symbol *import) {
  54.986 -        assert(import->type());
  54.987 -
  54.988 -        // Check for duplicate import names.
  54.989 -        if (unit_->importScope()->localLookup(import->name())) {
  54.990 -            cc_.reportError(node->pos(), Message_DuplicateImport, import->name()->chars());
  54.991 -            return false;
  54.992 -        }
  54.993 -
  54.994 -        Symbol *sym;
  54.995 -        if (import->isType()) {
  54.996 -            // Fuck it, make a TypeSymbol instead of an ImplicitSymbol. This
  54.997 -            // makes bindType() much simpler. We may run into problems
  54.998 -            // implementing linking, but it seems unlikely, as long as we are
  54.999 -            // exporting Types in module structs.
 54.1000 -            Local<Type> type(zone_, zone_->types()->getType());
 54.1001 -            sym = new (pool_) TypeSymbol(unit_->importScope(),
 54.1002 -                                         import->name(),
 54.1003 -                                         type,
 54.1004 -                                         import->toType()->effective());
 54.1005 -        } else if (import->isConstant()) {
 54.1006 -            // Same deal. No reason to lookup in the module globals if we
 54.1007 -            // already have a symbol.
 54.1008 -            sym = new (pool_) ConstantSymbol(unit_->importScope(),
 54.1009 -                                             import->name(),
 54.1010 -                                             node->pos(),
 54.1011 -                                             import->type(),
 54.1012 -                                             import->toConstant()->value());
 54.1013 -        } else {
 54.1014 -            sym = new (pool_) ImplicitSymbol(unit_->importScope(),
 54.1015 -                                             import->name(),
 54.1016 -                                             node->pos(),
 54.1017 -                                             import->type(),
 54.1018 -                                             node->importIndex());
 54.1019 -        }
 54.1020 -
 54.1021 -        if (!unit_->importScope()->addSymbol(sym))
 54.1022 -            return false;
 54.1023 -
 54.1024 -        return true;
 54.1025 -    }
 54.1026 -
 54.1027 -    void importFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
 54.1028 -        assert(!other->failed());
 54.1029 -
 54.1030 -        for (size_t i = 0; i < node->names()->length(); i++) {
 54.1031 -            Handle<String> name = *node->names()->at(i);
 54.1032 -
 54.1033 -            // See if the name exists in the other translation unit.
 54.1034 -            Symbol *import = other->globalScope()->findExported(name);
 54.1035 -            if (!import) {
 54.1036 -                FixedArray *path = unit_->module()->importPathAt(node->importIndex());
 54.1037 -                cc_.reportError(node->pos(), Message_NotFoundInImportable,
 54.1038 -                                name->chars(),
 54.1039 -                                String::cast(path->at(path->length() - 1))->chars());
 54.1040 -                return;
 54.1041 -            }
 54.1042 -
 54.1043 -            if (!importFrom(node, import))
 54.1044 -                return;
 54.1045 -        }
 54.1046 -    }
 54.1047 -
 54.1048 -    void importAllFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
 54.1049 -        assert(!other->failed());
 54.1050 -
 54.1051 -        for (size_t i = 0; i < other->globalScope()->exported()->length(); i++) {
 54.1052 -            Symbol *import = other->globalScope()->exported()->at(i);
 54.1053 -            if (!importFrom(node, import))
 54.1054 -                return;
 54.1055 -        }
 54.1056 -    }
 54.1057 -
 54.1058 -  private:
 54.1059 -    StructureBufferBuilder builder_;
 54.1060 -    Vector<ScopedRoot<Descriptor> *> descriptors_;
 54.1061 -    GlobalScope *globalScope_;
 54.1062 -    Vector<PrimitiveFill> primitiveFills_;
 54.1063 -};
 54.1064 -    
 54.1065 -class NameBinder : public NameBinderBase
 54.1066 -{
 54.1067 -  public:
 54.1068 -    class AutoLinkScope
 54.1069 -    {
 54.1070 -      public:
 54.1071 -        AutoLinkScope(AutoLinkScope **prevp, Scope *scope)
 54.1072 -          : prevp_(prevp),
 54.1073 -            prev_(*prevp),
 54.1074 -            scope_(scope)
 54.1075 -        {
 54.1076 -            if (scope_) {
 54.1077 -                *prevp_ = this;
 54.1078 -                if (prev_)
 54.1079 -                    scope_->setParent(prev_->scope());
 54.1080 -            }
 54.1081 -        }
 54.1082 -        ~AutoLinkScope() {
 54.1083 -            if (scope_) {
 54.1084 -                assert(*prevp_ == this);
 54.1085 -                *prevp_ = prev_;
 54.1086 -            }
 54.1087 -        }
 54.1088 -        Scope *scope() const {
 54.1089 -            return scope_;
 54.1090 -        }
 54.1091 -
 54.1092 -      private:
 54.1093 -        AutoLinkScope **prevp_;
 54.1094 -        AutoLinkScope *prev_;
 54.1095 -        Scope *scope_;
 54.1096 -    };
 54.1097 -
 54.1098 -  public:
 54.1099 -    NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.1100 -      : NameBinderBase(zone, cc, unit),
 54.1101 -        link_(NULL)
 54.1102 -    {
 54.1103 -    }
 54.1104 -
 54.1105 -    void bind() {
 54.1106 -        // Start with the import scope, and collect all imported names.
 54.1107 -        AutoLinkScope importScope(&link_, unit_->importScope());
 54.1108 -
 54.1109 -        for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
 54.1110 -            unit_->tree()->imports()->at(i)->accept(this);
 54.1111 -
 54.1112 -        // Next, enter the global scope and walk all statements.
 54.1113 -        AutoLinkScope globalScope(&link_, unit_->globalScope());
 54.1114 -        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
 54.1115 -            Statement *stmt = unit_->tree()->statements()->at(i);
 54.1116 -            stmt->accept(this);
 54.1117 -        }
 54.1118 -    }
 54.1119 -
 54.1120 -    void visitVariableDeclaration(VariableDeclaration *node) {
 54.1121 -        // Bind the initializer before registering the declaration, so that we
 54.1122 -        // can error on bogus initializers (new x = x).
 54.1123 -        if (node->initialization())
 54.1124 -            node->initialization()->accept(this);
 54.1125 -
 54.1126 -        // If the node already has a symbol (meaning it was a global), then
 54.1127 -        // we don't have to do anything more.
 54.1128 -        if (node->sym())
 54.1129 -            return;
 54.1130 -
 54.1131 -        Local<Type> type(zone_, buildVariableType(node));
 54.1132 -        if (!type)
 54.1133 -            return;
 54.1134 -
 54.1135 -        VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type);
 54.1136 -        node->setSymbol(sym);
 54.1137 -       
 54.1138 -        if (Symbol *other = link_->scope()->localLookup(sym->name())) {
 54.1139 -            // Report, but allow errors to continue.
 54.1140 -            cc_.reportError(sym->pos(), Message_RedeclaredName,
 54.1141 -                            sym->name()->chars(),
 54.1142 -                            other->pos().line,
 54.1143 -                            other->pos().col);
 54.1144 -            return;
 54.1145 -        }
 54.1146 -        
 54.1147 -        link_->scope()->addSymbol(sym);
 54.1148 -    }
 54.1149 -    void visitEnumStatement(EnumStatement *node) {
 54.1150 -    }
 54.1151 -    void visitFunctionStatement(FunctionStatement *node) {
 54.1152 -        AutoLinkScope argScope(&link_, node->argScope());
 54.1153 -        AutoLinkScope varScope(&link_, node->varScope());
 54.1154 -
 54.1155 -        // If the function is in the global scope, we've already computed its
 54.1156 -        // type.
 54.1157 -        if (node->sym()->scope()->kind() != Scope::GLOBAL) {
 54.1158 -            Local<FunctionType> type(zone_, node->sym()->type());
 54.1159 -            if (!fillFunctionType(type, node->signature()))
 54.1160 -                return;
 54.1161 -        }
 54.1162 -
 54.1163 -        if (node->body())
 54.1164 -            node->body()->accept(this);
 54.1165 -    }
 54.1166 -    void visitStructureStatement(StructureStatement *node) {
 54.1167 -        assert(false);
 54.1168 -    }
 54.1169 -    void visitFunctionTypeStatement(FunctionTypeStatement *node) {
 54.1170 -        assert(false);
 54.1171 -    }
 54.1172 -
 54.1173 -    void visitNameProxy(NameProxy *proxy) {
 54.1174 -        // We could have already bound globals.
 54.1175 -        if (proxy->sym())
 54.1176 -            return;
 54.1177 -
 54.1178 -        Scope *scope = link_->scope();
 54.1179 -        Symbol *sym = scope->lookup(proxy->name());
 54.1180 -        if (!sym)
 54.1181 -            cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
 54.1182 -        proxy->bind(sym);
 54.1183 -    }
 54.1184 -    void visitAssignment(Assignment *node) {
 54.1185 -        node->lvalue()->accept(this);
 54.1186 -        node->expression()->accept(this);
 54.1187 -    }
 54.1188 -    void visitBinaryExpression(BinaryExpression *node) {
 54.1189 -        node->left()->accept(this);
 54.1190 -        node->right()->accept(this);
 54.1191 -    }
 54.1192 -    void visitReturnStatement(ReturnStatement *node) {
 54.1193 -        node->expression()->accept(this);
 54.1194 -    }
 54.1195 -    void visitForStatement(ForStatement *node) {
 54.1196 -        AutoLinkScope scope(&link_, node->scope());
 54.1197 -
 54.1198 -        if (node->initialization())
 54.1199 -            node->initialization()->accept(this);
 54.1200 -        if (node->condition())
 54.1201 -            node->condition()->accept(this);
 54.1202 -        if (node->update())
 54.1203 -            node->update()->accept(this);
 54.1204 -        node->body()->accept(this);
 54.1205 -    }
 54.1206 -    void visitBlockStatement(BlockStatement *node) {
 54.1207 -        AutoLinkScope scope(&link_, node->scope());
 54.1208 -        for (size_t i = 0; i < node->statements()->length(); i++)
 54.1209 -            node->statements()->at(i)->accept(this);
 54.1210 -    }
 54.1211 -    void visitIntegerLiteral(IntegerLiteral *node) {
 54.1212 -    }
 54.1213 -    void visitExpressionStatement(ExpressionStatement *node) {
 54.1214 -        node->expression()->accept(this);
 54.1215 -    }
 54.1216 -    void visitCallExpression(CallExpression *node) {
 54.1217 -        node->callee()->accept(this);
 54.1218 -        for (size_t i = 0; i < node->arguments()->length(); i++)
 54.1219 -            node->arguments()->at(i)->accept(this);
 54.1220 -    }
 54.1221 -    void visitIfStatement(IfStatement *node) {
 54.1222 -        node->condition()->accept(this);
 54.1223 -        node->ifTrue()->accept(this);
 54.1224 -        if (node->ifFalse())
 54.1225 -            node->ifFalse()->accept(this);
 54.1226 -    }
 54.1227 -    void visitIndexExpression(IndexExpression *node) {
 54.1228 -        node->left()->accept(this);
 54.1229 -        node->right()->accept(this);
 54.1230 -    }
 54.1231 -    void visitFloatLiteral(FloatLiteral *node) {
 54.1232 -    }
 54.1233 -    void visitWhileStatement(WhileStatement *node) {
 54.1234 -        node->condition()->accept(this);
 54.1235 -        node->body()->accept(this);
 54.1236 -    }
 54.1237 -    void visitBreakStatement(BreakStatement *node) {
 54.1238 -    }
 54.1239 -    void visitContinueStatement(ContinueStatement *node) {
 54.1240 -    }
 54.1241 -    void visitStringLiteral(StringLiteral *node) {
 54.1242 -    }
 54.1243 -    void visitIncDecExpression(IncDecExpression *node) {
 54.1244 -        node->expression()->accept(this);
 54.1245 -    }
 54.1246 -    void visitUnaryExpression(UnaryExpression *node) {
 54.1247 -        if (node->tag())
 54.1248 -            node->tag()->accept(this);
 54.1249 -        node->expression()->accept(this);
 54.1250 -    }
 54.1251 -    void visitTernaryExpression(TernaryExpression *node) {
 54.1252 -        node->condition()->accept(this);
 54.1253 -        node->left()->accept(this);
 54.1254 -        node->right()->accept(this);
 54.1255 -    }
 54.1256 -    void visitBooleanLiteral(BooleanLiteral *node) {
 54.1257 -    }
 54.1258 -    void visitFieldExpression(FieldExpression *node) {
 54.1259 -        node->left()->accept(this);
 54.1260 -    }
 54.1261 -    void visitSwitchStatement(SwitchStatement *node) {
 54.1262 -        node->expression()->accept(this);
 54.1263 -        node->defaultCase()->accept(this);
 54.1264 -        for (size_t i = 0; i < node->cases()->length(); i++) {
 54.1265 -            // We don't test case expressions because they are literals.
 54.1266 -            Case *c = node->cases()->at(i);
 54.1267 -            c->statement()->accept(this);
 54.1268 -        }
 54.1269 -    }
 54.1270 -    void visitArrayLiteral(ArrayLiteral *node) {
 54.1271 -        for (size_t i = 0; i < node->expressions()->length(); i++)
 54.1272 -            node->expressions()->at(i)->accept(this);
 54.1273 -    }
 54.1274 -    void visitImportStatement(ImportStatement *node) {
 54.1275 -    }
 54.1276 -
 54.1277 -  private:
 54.1278 -    AutoLinkScope *link_;
 54.1279 -};
 54.1280 -
 54.1281 -void
 54.1282 -ke::BindGlobals(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.1283 -{
 54.1284 -    AutoEnterCompileContext enter(cc, unit);
 54.1285 -
 54.1286 -    GlobalBuilder builder(zone, cc, unit);
 54.1287 -    Local<Struct> globals(zone, builder.build());
 54.1288 -    if (!globals || unit->failed())
 54.1289 -        return;
 54.1290 -
 54.1291 -    unit->module()->setGlobals(globals);
 54.1292 -}
 54.1293 -
 54.1294 -void
 54.1295 -ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.1296 -{
 54.1297 -    AutoEnterCompileContext enter(cc, unit);
 54.1298 -    NameBinder binder(zone, cc, unit);
 54.1299 -    binder.bind();
 54.1300 -}
 54.1301 +/* vim: set ts=4 sw=4 tw=99 et:
 54.1302 + *
 54.1303 + * Copyright (C) 2012 David Anderson
 54.1304 + *
 54.1305 + * This file is part of SourcePawn.
 54.1306 + *
 54.1307 + * SourcePawn is free software: you can redistribute it and/or modify it under
 54.1308 + * the terms of the GNU General Public License as published by the Free
 54.1309 + * Software Foundation, either version 3 of the License, or (at your option)
 54.1310 + * any later version.
 54.1311 + * 
 54.1312 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
 54.1313 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 54.1314 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 54.1315 + *
 54.1316 + * You should have received a copy of the GNU General Public License along with
 54.1317 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
 54.1318 + */
 54.1319 +#include "../Strings.h"
 54.1320 +#include "../Zone.h"
 54.1321 +#include "../TypeManager.h"
 54.1322 +#include "NameBinding.h"
 54.1323 +#include "Scopes.h"
 54.1324 +#include "ConstantEvaluator.h"
 54.1325 +#include "../Spaces-inl.h"
 54.1326 +#include "../Heap-inl.h"
 54.1327 +
 54.1328 +using namespace ke;
 54.1329 +
 54.1330 +// Create symbol tables and symbols for every scope and declaration. For type
 54.1331 +// declarations and methods, we also pre-allocate a Type object, so that
 54.1332 +// circular dependencies between types will work.
 54.1333 +class NamePopulator : public AstVisitor
 54.1334 +{
 54.1335 +  private:
 54.1336 +    // This class is analagous to a Scope, however, it allows us to create
 54.1337 +    // scopes lazily. If a scope is requested, and the current environment
 54.1338 +    // has no scope, then a scope is created. If no scope is ever requested,
 54.1339 +    // a scope does not need to be created.
 54.1340 +    class SymbolEnv
 54.1341 +    {
 54.1342 +      public:
 54.1343 +        SymbolEnv(SymbolEnv **prevp, Scope *scope = NULL)
 54.1344 +          : envp_(prevp),
 54.1345 +            prev_(*prevp),
 54.1346 +            scope_(scope)
 54.1347 +        {
 54.1348 +            *envp_ = this;
 54.1349 +        }
 54.1350 +        ~SymbolEnv() {
 54.1351 +            *envp_ = prev_;
 54.1352 +        }
 54.1353 +
 54.1354 +        Scope *scope() {
 54.1355 +            return scope_;
 54.1356 +        }
 54.1357 +        void setScope(Scope *scope) {
 54.1358 +            assert(!scope_);
 54.1359 +            scope_ = scope;
 54.1360 +        }
 54.1361 +        SymbolEnv *prev() const {
 54.1362 +            return prev_;
 54.1363 +        }
 54.1364 +
 54.1365 +      private:
 54.1366 +        SymbolEnv **envp_;
 54.1367 +        SymbolEnv *prev_;
 54.1368 +        Scope *scope_;
 54.1369 +    };
 54.1370 +
 54.1371 +    enum ReturnStatus {
 54.1372 +        NoReturn,
 54.1373 +        VoidReturn,
 54.1374 +        ValueReturn
 54.1375 +    };
 54.1376 +
 54.1377 +    class FunctionScope
 54.1378 +    {
 54.1379 +      public:
 54.1380 +        FunctionScope(FunctionScope **prevp)
 54.1381 +          : prevp_(prevp),
 54.1382 +            prev_(*prevp),
 54.1383 +            status_(NoReturn)
 54.1384 +        {
 54.1385 +            *prevp_ = this;
 54.1386 +        }
 54.1387 +        ~FunctionScope() {
 54.1388 +            *prevp_ = prev_;
 54.1389 +        }
 54.1390 +        ReturnStatus returns() const {
 54.1391 +            return status_;
 54.1392 +        }
 54.1393 +        void returns(ReturnStatus status) {
 54.1394 +            if (status > status_)
 54.1395 +                status_ = status;
 54.1396 +        }
 54.1397 +      private:
 54.1398 +        FunctionScope **prevp_;
 54.1399 +        FunctionScope *prev_;
 54.1400 +        ReturnStatus status_;
 54.1401 +    };
 54.1402 +
 54.1403 +  public:
 54.1404 +    NamePopulator(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.1405 +      : zone_(zone),
 54.1406 +        pool_(zone->pool()),
 54.1407 +        cc_(cc),
 54.1408 +        unit_(unit),
 54.1409 +        env_(NULL),
 54.1410 +        fun_(NULL)
 54.1411 +    {
 54.1412 +    }
 54.1413 +
 54.1414 +    void analyze() {
 54.1415 +        ImportScope *importScope = ImportScope::New(pool_);
 54.1416 +        if (!importScope)
 54.1417 +            return;
 54.1418 +
 54.1419 +        // At the import level, we declare system types.
 54.1420 +        if (!declareSystemTypes(importScope))
 54.1421 +            return;
 54.1422 +
 54.1423 +        GlobalScope *globalScope = GlobalScope::New(pool_, importScope);
 54.1424 +        if (!globalScope)
 54.1425 +            return;
 54.1426 +
 54.1427 +        unit_->setImportScope(importScope);
 54.1428 +        unit_->setGlobalScope(globalScope);
 54.1429 +
 54.1430 +        SymbolEnv env(&env_, globalScope);
 54.1431 +
 54.1432 +        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
 54.1433 +            Statement *stmt = unit_->tree()->statements()->at(i);
 54.1434 +            stmt->accept(this);
 54.1435 +        }
 54.1436 +
 54.1437 +        return;
 54.1438 +    }
 54.1439 +
 54.1440 +    bool declareSystemType(ImportScope *scope, const char *name, Handle<Type> effective) {
 54.1441 +        Local<String> tag(zone_, zone_->makeSymbol(name));
 54.1442 +        if (!tag)
 54.1443 +            return false;
 54.1444 +
 54.1445 +        Local<Type> type(zone_, zone_->types()->getType());
 54.1446 +
 54.1447 +        TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type, effective);
 54.1448 +        return scope->addSymbol(sym);
 54.1449 +    }
 54.1450 +
 54.1451 +    bool declareSystemType(ImportScope *scope, const char *name, PrimitiveType prim) {
 54.1452 +        Local<Type> primitive(zone_, zone_->types()->getPrimitive(prim));
 54.1453 +        assert(primitive);
 54.1454 +        return declareSystemType(scope, name, primitive);
 54.1455 +    }
 54.1456 +
 54.1457 +    bool declareSystemTypes(ImportScope *scope) {
 54.1458 +        if (!declareSystemType(scope, "float", PrimitiveType_Float))
 54.1459 +            return false;
 54.1460 +        if (!declareSystemType(scope, "_", PrimitiveType_Int32))
 54.1461 +            return false;
 54.1462 +        if (!declareSystemType(scope, "int", PrimitiveType_Int32))
 54.1463 +            return false;
 54.1464 +        if (!declareSystemType(scope, "bool", PrimitiveType_Bool))
 54.1465 +            return false;
 54.1466 +        if (!declareSystemType(scope, "char", PrimitiveType_Char))
 54.1467 +            return false;
 54.1468 +
 54.1469 +        Local<Type> voidType(zone_, zone_->types()->getVoid());
 54.1470 +        if (!declareSystemType(scope, "void", voidType))
 54.1471 +            return false;
 54.1472 +
 54.1473 +        return true;
 54.1474 +    }
 54.1475 +
 54.1476 +    void visitVariableDeclaration(VariableDeclaration *node) {
 54.1477 +        Scope *scope = env_->scope();
 54.1478 +        if (!scope || scope->kind() != Scope::GLOBAL) {
 54.1479 +            if ((scope = getOrCreateBlockScope()) == NULL)
 54.1480 +                return;
 54.1481 +        }
 54.1482 +
 54.1483 +        if (scope->kind() == Scope::GLOBAL) {
 54.1484 +            // The symbol must be added now, since it could be an export.
 54.1485 +            VariableSymbol *sym = new (pool_) VariableSymbol(scope, node->name(), node->pos());
 54.1486 +            node->setSymbol(sym);
 54.1487 +
 54.1488 +            if (!registerName(scope, sym))
 54.1489 +                return;
 54.1490 +        } else {
 54.1491 +            // We ensure the scope will exist at the name binding phase, but
 54.1492 +            // we don't actually register the variable symbol yet. Otherwise,
 54.1493 +            // when binding the initializer, we could encounter:
 54.1494 +            //    new x = x;
 54.1495 +            //
 54.1496 +            // And we don't necessarily want this to bind.
 54.1497 +        }
 54.1498 +
 54.1499 +        if (node->initialization())
 54.1500 +            node->initialization()->accept(this);
 54.1501 +    }
 54.1502 +
 54.1503 +    void visitEnumStatement(EnumStatement *node) {
 54.1504 +        Local<String> name(zone_, node->name());
 54.1505 +        Local<Type> type(zone_);
 54.1506 +        if (name)
 54.1507 +            type = zone_->types()->newEnum(name);
 54.1508 +        else
 54.1509 +            type = zone_->types()->getPrimitive(PrimitiveType_Int32);
 54.1510 +
 54.1511 +        if (!type)
 54.1512 +            return;
 54.1513 +
 54.1514 +        Scope *scope = getGlobalOrCreateBlockScope();
 54.1515 +        if (!scope)
 54.1516 +            return;
 54.1517 +
 54.1518 +        if (name) {
 54.1519 +            Local<Type> symType(zone_, zone_->types()->getType());
 54.1520 +            TypeSymbol *sym = new (pool_) TypeSymbol(scope, name, symType, type);
 54.1521 +            if (!registerName(scope, sym))
 54.1522 +                return;
 54.1523 +
 54.1524 +            if (scope->kind() == Scope::GLOBAL) {
 54.1525 +                if (!unit_->globalScope()->exported()->append(sym))
 54.1526 +                    return;
 54.1527 +            }
 54.1528 +        }
 54.1529 +
 54.1530 +        // We want each field of the expression to qualify as a constant expression.
 54.1531 +        if ((type = zone_->types()->qualify(type, TypeQual_ConstExpr)) == NULL)
 54.1532 +            return;
 54.1533 +        
 54.1534 +        int value = 0;
 54.1535 +        for (size_t i = 0; i < node->entries()->length(); i++) {
 54.1536 +            EnumStatement::Entry &entry = node->entries()->at(i);
 54.1537 +            BoxedPrimitive box = BoxedPrimitive::Int(value);
 54.1538 +            if (entry.expr) {
 54.1539 +                if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
 54.1540 +                    cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
 54.1541 +                    return;
 54.1542 +                }
 54.1543 +
 54.1544 +                assert(box.type() == PrimitiveType_Int32);
 54.1545 +                value = box.toInt();
 54.1546 +            }
 54.1547 +         
 54.1548 +            ConstantSymbol *sym = new (pool_) ConstantSymbol(scope, entry.name, entry.pos, type, box);
 54.1549 +            if (!registerName(scope, sym))
 54.1550 +                return;
 54.1551 +            if (scope->kind() == Scope::GLOBAL) {
 54.1552 +                if (!unit_->globalScope()->exported()->append(sym))
 54.1553 +                    return;
 54.1554 +            }
 54.1555 +
 54.1556 +            entry.sym = sym;
 54.1557 +            value++;
 54.1558 +        }
 54.1559 +    }
 54.1560 +
 54.1561 +    void visitFunctionStatement(FunctionStatement *node) {
 54.1562 +        // We create function types ahead of time, not for any particular
 54.1563 +        // reason. It makes things consistent with FunctionTypeStatement,
 54.1564 +        // which actually does produce a type.
 54.1565 +        Local<FunctionType> type(zone_, FunctionType::New(zone_, node->name(), node->token()));
 54.1566 +        if (!type)
 54.1567 +            return;
 54.1568 +
 54.1569 +        assert(env_->scope());
 54.1570 +
 54.1571 +        // Function statements are always named, so add the name to the outer scope.
 54.1572 +        FunctionSymbol *sym = new (pool_) FunctionSymbol(env_->scope(), node->name(), node->pos(), type);
 54.1573 +        if (!registerName(env_->scope(), sym))
 54.1574 +            return;
 54.1575 +
 54.1576 +        if (node->token() == TOK_PUBLIC ||
 54.1577 +            node->token() == TOK_FORWARD ||
 54.1578 +            node->token() == TOK_NATIVE)
 54.1579 +        {
 54.1580 +            // We're in the global scope, for sure.
 54.1581 +            assert(env_->scope()->kind() == Scope::GLOBAL);
 54.1582 +
 54.1583 +            if (!unit_->globalScope()->exported()->append(sym))
 54.1584 +                return;
 54.1585 +        }
 54.1586 +
 54.1587 +        node->setSymbol(sym);
 54.1588 +
 54.1589 +        // Scope for the function's arguments.
 54.1590 +        SymbolEnv argEnv(&env_);
 54.1591 +        if (!registerArguments(node->signature()))
 54.1592 +            return;
 54.1593 +
 54.1594 +        // Scope for function body.
 54.1595 +        SymbolEnv localEnv(&env_);
 54.1596 +        FunctionScope fun(&fun_);
 54.1597 +        if (node->body())
 54.1598 +            node->body()->accept(this);
 54.1599 +
 54.1600 +        // Function statements have quirky semantics around their return
 54.1601 +        // type. For reasonable compatibility with SP1, we use the following
 54.1602 +        // heuristics for when no explicit type is declared.
 54.1603 +        if (!node->signature().returnType()) {
 54.1604 +            Local<Type> type(zone_);
 54.1605 +            if (node->token() == TOK_FORWARD || node->token() == TOK_NATIVE) {
 54.1606 +                // If the function type is a native or forward, we always
 54.1607 +                // assume it returns an int32.
 54.1608 +                type = zone_->types()->getPrimitive(PrimitiveType_Int32);
 54.1609 +            } else if (fun.returns() != ValueReturn) {
 54.1610 +                // This function never returns a value, so mark it as
 54.1611 +                // returning void.
 54.1612 +                type = zone_->types()->getVoid();
 54.1613 +            }
 54.1614 +            // No need to NULL check here, we'll catch OOM later.
 54.1615 +            node->sym()->type()->setReturnType(type);
 54.1616 +        }
 54.1617 +
 54.1618 +        node->setScopes(argEnv.scope(), localEnv.scope());
 54.1619 +    }
 54.1620 +
 54.1621 +    void visitStructureStatement(StructureStatement *node) {
 54.1622 +        assert(false);
 54.1623 +    }
 54.1624 +
 54.1625 +    void visiFunctionTypeStatementt(FunctionTypeStatement *node) {
 54.1626 +        assert(false);
 54.1627 +    }
 54.1628 +
 54.1629 +    void visitNameProxy(NameProxy *name) {
 54.1630 +    }
 54.1631 +    void visitAssignment(Assignment *node) {
 54.1632 +        node->lvalue()->accept(this);
 54.1633 +        node->expression()->accept(this);
 54.1634 +    }
 54.1635 +    void visitBinaryExpression(BinaryExpression *node) {
 54.1636 +        node->left()->accept(this);
 54.1637 +        node->right()->accept(this);
 54.1638 +    }
 54.1639 +    void visitReturnStatement(ReturnStatement *node) {
 54.1640 +        if (node->expression())
 54.1641 +            fun_->returns(ValueReturn);
 54.1642 +        else
 54.1643 +            fun_->returns(VoidReturn);
 54.1644 +    }
 54.1645 +    void visitForStatement(ForStatement *node) {
 54.1646 +        SymbolEnv env(&env_);
 54.1647 +
 54.1648 +        if (node->initialization())
 54.1649 +            node->initialization()->accept(this);
 54.1650 +        if (node->condition())
 54.1651 +            node->condition()->accept(this);
 54.1652 +        if (node->update())
 54.1653 +            node->update()->accept(this);
 54.1654 +        node->body()->accept(this);
 54.1655 +
 54.1656 +        node->setScope(env.scope());
 54.1657 +    }
 54.1658 +    void visitBlockStatement(BlockStatement *node) {
 54.1659 +        if (node->type() == TOK_NEW) {
 54.1660 +            // Don't create a symbol environment for this block, since it
 54.1661 +            // was created solely to house multiple variable decls.
 54.1662 +            for (size_t i = 0; i < node->statements()->length(); i++)
 54.1663 +                node->statements()->at(i)->accept(this);
 54.1664 +        } else {
 54.1665 +            assert(node->type() == TOK_LBRACE);
 54.1666 +
 54.1667 +            SymbolEnv env(&env_);
 54.1668 +
 54.1669 +            for (size_t i = 0; i < node->statements()->length(); i++)
 54.1670 +                node->statements()->at(i)->accept(this);
 54.1671 +        
 54.1672 +            if (node->type() == TOK_NEW) {
 54.1673 +                assert(!env.scope());
 54.1674 +                return;
 54.1675 +            }
 54.1676 +
 54.1677 +            node->setScope(env.scope());
 54.1678 +        }
 54.1679 +    }
 54.1680 +    void visitIntegerLiteral(IntegerLiteral *node) {
 54.1681 +    }
 54.1682 +    void visitExpressionStatement(ExpressionStatement *node) {
 54.1683 +        node->expression()->accept(this);
 54.1684 +    }
 54.1685 +    void visitCallExpression(CallExpression *node) {
 54.1686 +        node->callee()->accept(this);
 54.1687 +        for (size_t i = 0; i < node->arguments()->length(); i++)
 54.1688 +            node->arguments()->at(i)->accept(this);
 54.1689 +    }
 54.1690 +    void visitIfStatement(IfStatement *node) {
 54.1691 +        node->ifTrue()->accept(this);
 54.1692 +        if (node->ifFalse())
 54.1693 +            node->ifFalse()->accept(this);
 54.1694 +    }
 54.1695 +    void visitIndexExpression(IndexExpression *node) {
 54.1696 +        node->left()->accept(this);
 54.1697 +        node->right()->accept(this);
 54.1698 +    }
 54.1699 +    void visitFloatLiteral(FloatLiteral *node) {
 54.1700 +    }
 54.1701 +    void visitWhileStatement(WhileStatement *node) {
 54.1702 +        node->condition()->accept(this);
 54.1703 +        node->body()->accept(this);
 54.1704 +    }
 54.1705 +    void visitBreakStatement(BreakStatement *node) {
 54.1706 +    }
 54.1707 +    void visitContinueStatement(ContinueStatement *node) {
 54.1708 +    }
 54.1709 +    void visitStringLiteral(StringLiteral *node) {
 54.1710 +    }
 54.1711 +    void visitIncDecExpression(IncDecExpression *node) {
 54.1712 +        node->expression()->accept(this);
 54.1713 +    }
 54.1714 +    void visitUnaryExpression(UnaryExpression *node) {
 54.1715 +        node->expression()->accept(this);
 54.1716 +    }
 54.1717 +    void visitTernaryExpression(TernaryExpression *node) {
 54.1718 +        assert(false);
 54.1719 +    }
 54.1720 +    void visitBooleanLiteral(BooleanLiteral *node) {
 54.1721 +    }
 54.1722 +    void visitFieldExpression(FieldExpression *node) {
 54.1723 +    }
 54.1724 +    void visitSwitchStatement(SwitchStatement *node) {
 54.1725 +        if (node->defaultCase())
 54.1726 +            node->defaultCase()->accept(this);
 54.1727 +
 54.1728 +        for (size_t i = 0; i < node->cases()->length(); i++)
 54.1729 +            node->cases()->at(i)->statement()->accept(this);
 54.1730 +    }
 54.1731 +    void visitArrayLiteral(ArrayLiteral *node) {
 54.1732 +    }
 54.1733 +    void visitImportStatement(ImportStatement *node) {
 54.1734 +    }
 54.1735 +
 54.1736 +  private:
 54.1737 +    Scope *getGlobalOrCreateBlockScope() {
 54.1738 +        if (env_->scope()) {
 54.1739 +            assert(env_->scope()->kind() == Scope::BLOCK ||
 54.1740 +                   env_->scope()->kind() == Scope::GLOBAL);
 54.1741 +            return env_->scope();
 54.1742 +        }
 54.1743 +        return getOrCreateBlockScope();
 54.1744 +    }
 54.1745 +    Scope *getOrCreateBlockScope() {
 54.1746 +        if (env_->scope()) {
 54.1747 +            assert(env_->scope()->kind() == Scope::BLOCK);
 54.1748 +            return env_->scope();
 54.1749 +        }
 54.1750 +        
 54.1751 +        LocalScope *scope = LocalScope::New(pool_);
 54.1752 +        if (!scope)
 54.1753 +            return NULL;
 54.1754 +
 54.1755 +        env_->setScope(scope);
 54.1756 +        return scope;
 54.1757 +    }
 54.1758 +
 54.1759 +    bool registerName(Scope *scope, Symbol *sym) {
 54.1760 +        if (!scope)
 54.1761 +            return false;
 54.1762 +
 54.1763 +        if (Symbol *other = scope->localLookup(sym->name())) {
 54.1764 +            // Report, but allow errors to continue.
 54.1765 +            cc_.reportError(sym->pos(), Message_RedeclaredName,
 54.1766 +                            sym->name()->chars(),
 54.1767 +                            other->pos().line,
 54.1768 +                            other->pos().col);
 54.1769 +            return true;
 54.1770 +        }
 54.1771 +
 54.1772 +        return scope->addSymbol(sym);
 54.1773 +    }
 54.1774 +
 54.1775 +    bool registerArguments(const FunctionSignature &sig) {
 54.1776 +        if (!sig.parameters()->length())
 54.1777 +            return true;
 54.1778 +
 54.1779 +        ArgumentScope *argScope = ArgumentScope::New(pool_);
 54.1780 +        if (!argScope)
 54.1781 +            return false;
 54.1782 +        env_->setScope(argScope);
 54.1783 +
 54.1784 +        for (size_t i = 0; i < sig.parameters()->length(); i++) {
 54.1785 +            Parameter *param = sig.parameters()->at(i);
 54.1786 +            VariableSymbol *sym = new (pool_) VariableSymbol(argScope, param->name(), param->pos());
 54.1787 +            if (!registerName(env_->scope(), sym))
 54.1788 +                return false;
 54.1789 +            param->setSymbol(sym);
 54.1790 +        }
 54.1791 +
 54.1792 +        return true;
 54.1793 +    }
 54.1794 +
 54.1795 +  private:
 54.1796 +    Zone *zone_;
 54.1797 +    PoolAllocator &pool_;
 54.1798 +    CompileContext &cc_;
 54.1799 +    TranslationUnit *unit_;
 54.1800 +    SymbolEnv *env_;
 54.1801 +    FunctionScope *fun_;
 54.1802 +};
 54.1803 +
 54.1804 +void
 54.1805 +ke::PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.1806 +{
 54.1807 +    AutoEnterCompileContext enter(cc, unit);
 54.1808 +    NamePopulator populator(zone, cc, unit);
 54.1809 +    populator.analyze();
 54.1810 +}
 54.1811 +
 54.1812 +static const int INFER_ARRAY_SIZE = 0;
 54.1813 +static const int EVAL_ARRAY_SIZE = -1;
 54.1814 +static const int DYNAMIC_ARRAY_SIZE = -2;
 54.1815 +
 54.1816 +class NameBinderBase : public AstVisitor
 54.1817 +{
 54.1818 +  public:
 54.1819 +    NameBinderBase(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.1820 +      : zone_(zone),
 54.1821 +        pool_(zone->pool()),
 54.1822 +        cc_(cc),
 54.1823 +        unit_(unit)
 54.1824 +    {
 54.1825 +    }
 54.1826 +
 54.1827 +  protected:
 54.1828 +    Type *buildVariableType(VariableDeclaration *node) {
 54.1829 +        Local<Type> type(zone_, bindType(node->type(), node->quals()));
 54.1830 +        if (!type)
 54.1831 +            return NULL;
 54.1832 +
 54.1833 +        // We don't allow array typedefs yet.
 54.1834 +        assert(!type->isArray());
 54.1835 +
 54.1836 +        if (node->dims()) {
 54.1837 +            int dims[MAX_ARRAY_DEPTH];
 54.1838 +            int levels = evaluateDimensions(node->pos(), type, node->dims(), dims);
 54.1839 +            if (levels < 0)
 54.1840 +                return NULL;
 54.1841 +
 54.1842 +            // Do some extra inference based on the initializer, if present.
 54.1843 +            Expression *init = node->initialization();
 54.1844 +            if (init) {
 54.1845 +                if (init->isArrayLiteral() && init->toArrayLiteral()->isFixed()) {
 54.1846 +                    Local<Type> contained(zone_, type->isArray()
 54.1847 +                                                 ? ArrayType::cast(type)->contained()
 54.1848 +                                                 : type);
 54.1849 +                    if (!inferFixedArrayDimensions(init->toArrayLiteral(), contained, dims, levels))
 54.1850 +                        return NULL;
 54.1851 +                } else if (init->isStringLiteral()) {
 54.1852 +                    dims[levels - 1] = init->toStringLiteral()->string()->length() + 1;
 54.1853 +                }
 54.1854 +            }
 54.1855 +
 54.1856 +            // If we got extra dimensions, we need to build a new type.
 54.1857 +            if (node->dims()) {
 54.1858 +                if ((type = buildArrayType(type, node->quals(), dims, node->dims()->length())) == NULL)
 54.1859 +                    return NULL;
 54.1860 +            }
 54.1861 +        }
 54.1862 +
 54.1863 +        return type;
 54.1864 +    }
 54.1865 +
 54.1866 +    int evaluateDimensions(const SourcePosition &pos, Handle<Type> typeArg, ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) {
 54.1867 +        unsigned level = 0;
 54.1868 +        Local<Type> type(zone_, typeArg);
 54.1869 +        while (type->isArray()) {
 54.1870 +            ArrayType *atype = ArrayType::cast(type);
 54.1871 +            dims[level] = atype->isFixedLength()
 54.1872 +                          ? atype->fixedLength()
 54.1873 +                          : DYNAMIC_ARRAY_SIZE;
 54.1874 +            type = atype->contained();
 54.1875 +            level++;
 54.1876 +        }
 54.1877 +
 54.1878 +        if (!exprs)
 54.1879 +            return level;
 54.1880 +
 54.1881 +        if (level + exprs->length() > MAX_ARRAY_DEPTH) {
 54.1882 +            cc_.reportError(pos, Message_MaximumArrayDepth);
 54.1883 +            return -1;
 54.1884 +        }
 54.1885 +
 54.1886 +        bool hadEmptySize = false;
 54.1887 +        for (size_t i = 0; i < exprs->length(); i++) {
 54.1888 +            Expression *expr = exprs->at(i);
 54.1889 +            if (!expr) {
 54.1890 +                dims[i] = INFER_ARRAY_SIZE;
 54.1891 +                hadEmptySize = true;
 54.1892 +                continue;
 54.1893 +            }
 54.1894 +
 54.1895 +            BoxedPrimitive box;
 54.1896 +            if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
 54.1897 +                int size = box.toInt();
 54.1898 +                if (size <= 0) {
 54.1899 +                    cc_.reportError(expr->pos(), Message_BadArraySize);
 54.1900 +                    return false;
 54.1901 +                }
 54.1902 +
 54.1903 +                dims[i] = size;
 54.1904 +                continue;
 54.1905 +            }
 54.1906 +
 54.1907 +            if (hadEmptySize) {
 54.1908 +                cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
 54.1909 +                return false;
 54.1910 +            }
 54.1911 +
 54.1912 +            dims[i] = EVAL_ARRAY_SIZE;
 54.1913 +        }
 54.1914 +
 54.1915 +        return level + exprs->length();
 54.1916 +    }
 54.1917 +
 54.1918 +    // This function computes missing dimension sizes based on a literal
 54.1919 +    // initializer. We don't really handle any size rules here; we just
 54.1920 +    // do a really dumb inference.
 54.1921 +    bool inferFixedArrayDimensions(ArrayLiteral *lit, Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], int levels) {
 54.1922 +        for (int i = 0; i < levels; i++) {
 54.1923 +            if (dims[i] == EVAL_ARRAY_SIZE || dims[i] == DYNAMIC_ARRAY_SIZE) {
 54.1924 +                // The following are invalid:
 54.1925 +                //   new x[<expr>] = {...}
 54.1926 +                //   new Type:x = {...}  // where Type is a non-fixed array type
 54.1927 +                cc_.reportError(lit->pos(), Message_CannotInitializeEvalArray);
 54.1928 +                return false;
 54.1929 +            }
 54.1930 +
 54.1931 +            if (dims[i] == INFER_ARRAY_SIZE) {
 54.1932 +                // Character arrays are always dynamic when inferred from string literals.
 54.1933 +                if (i == levels - 1 && contained->isChar())
 54.1934 +                    dims[i] = DYNAMIC_ARRAY_SIZE;
 54.1935 +                else
 54.1936 +                    dims[i] = lit->expressions()->length();
 54.1937 +            }
 54.1938 +
 54.1939 +            if (i != levels - 1) {
 54.1940 +                // Fixed array literals are guaranteed to have at least one expression.
 54.1941 +                Expression *next = lit->expressions()->at(0);
 54.1942 +                if (!next->isArrayLiteral()) {
 54.1943 +                    // Whelp... this array is just malformed. Not the best error message
 54.1944 +                    // but whatever.
 54.1945 +                    cc_.reportError(next->pos(), Message_ArraySizeCannotBeDetermined);
 54.1946 +                    return false;
 54.1947 +                }
 54.1948 +                lit = next->toArrayLiteral();
 54.1949 +            }
 54.1950 +        }
 54.1951 +
 54.1952 +        return true;
 54.1953 +    }
 54.1954 +
 54.1955 +    ArrayType *buildArrayType(Handle<Type> contained, TypeQualifiers quals, int dims[MAX_ARRAY_DEPTH], size_t postlevels) {
 54.1956 +        Local<Type> type(zone_, contained);
 54.1957 +
 54.1958 +        for (size_t i = postlevels - 1; i < postlevels; i--) {
 54.1959 +            int size = dims[i] > 0
 54.1960 +                       ? dims[i]
 54.1961 +                       : ArrayType::DYNAMIC_ARRAY_SIZE;
 54.1962 +            
 54.1963 +            if ((type = zone_->types()->newArray(contained, size)) == NULL)
 54.1964 +                return NULL;
 54.1965 +            if ((type = zone_->types()->qualify(type, quals)) == NULL)
 54.1966 +                return NULL;
 54.1967 +        }
 54.1968 +        return ArrayType::cast(type);
 54.1969 +    }
 54.1970 +
 54.1971 +    bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
 54.1972 +        Local<Type> type(zone_);
 54.1973 +        if (!fun->returnType()) {
 54.1974 +            if ((type = bindType(sig.returnType(), TypeQual_None)) == NULL)
 54.1975 +                return false;
 54.1976 +            fun->setReturnType(type);
 54.1977 +        }
 54.1978 +
 54.1979 +        if (sig.variadic())
 54.1980 +            fun->setVariadic();
 54.1981 +
 54.1982 +        Local<FixedArray> params(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
 54.1983 +        if (!params)
 54.1984 +            return false;
 54.1985 +
 54.1986 +        for (size_t i = 0; i < sig.parameters()->length(); i++) {
 54.1987 +            Parameter *param = sig.parameters()->at(i);
 54.1988 +            if ((type = bindType(param->type(), param->quals())) == NULL)
 54.1989 +                return false;
 54.1990 +
 54.1991 +            assert(!type->isArray());
 54.1992 +
 54.1993 +            if (param->dims()) {
 54.1994 +                int dims[MAX_ARRAY_DEPTH];
 54.1995 +                int levels = evaluateDimensions(param->pos(), type, param->dims(), dims);
 54.1996 +                if (levels < 0)
 54.1997 +                    return false;
 54.1998 +
 54.1999 +                // If we got extra dimensions, we need to build a new type.
 54.2000 +                // Unlike variables, we do not infer anything about array
 54.2001 +                // sizes from its default initializer.
 54.2002 +                if (param->dims()) {
 54.2003 +                    if ((type = buildArrayType(type, param->quals(), dims, param->dims()->length())) == NULL)
 54.2004 +                        return false;
 54.2005 +                }
 54.2006 +
 54.2007 +                if (ArrayType::cast(type)->innermost()->isVoid()) {
 54.2008 +                    cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
 54.2009 +                    return false;
 54.2010 +                }
 54.2011 +            }
 54.2012 +
 54.2013 +            if (param->reference()) {
 54.2014 +                if (!type->isPod()) {
 54.2015 +                    cc_.reportError(param->pos(), Message_ArrayCantBeReference);
 54.2016 +                    return false;
 54.2017 +                }
 54.2018 +                if (param->quals() & TypeQual_Const) {
 54.2019 +                    cc_.reportError(param->pos(), Message_CannotConstReference);
 54.2020 +                    return false;
 54.2021 +                }
 54.2022 +                if ((type = zone_->types()->getReference(type, false)) == NULL)
 54.2023 +                    return false;
 54.2024 +            }
 54.2025 +            if (param->quals() & TypeQual_Const) {
 54.2026 +                if (!type->isArray() && !type->isStruct()) {
 54.2027 +                    cc_.reportError(param->pos(), Message_InvalidConstOnFormal);
 54.2028 +                    return false;
 54.2029 +                }
 54.2030 +            }
 54.2031 +
 54.2032 +            if (type->isVoid()) {
 54.2033 +                cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
 54.2034 +                return false;
 54.2035 +            }
 54.2036 +
 54.2037 +            params->set(zone_, i, type);
 54.2038 +            param->sym()->setType(type);
 54.2039 +        }
 54.2040 +
 54.2041 +        fun->setParameterTypes(params);
 54.2042 +
 54.2043 +        return true;
 54.2044 +    }
 54.2045 +
 54.2046 +    Type *bindType(Expression *expr, TypeQualifiers quals) {
 54.2047 +        Local<Type> type(zone_);
 54.2048 +
 54.2049 +        if (!expr) {
 54.2050 +            // If no type was declared, we return int32.
 54.2051 +            type = zone_->types()->getPrimitive(PrimitiveType_Int32);
 54.2052 +        } else {
 54.2053 +            expr->accept(this);
 54.2054 +
 54.2055 +            NameProxy *proxy = expr->asNameProxy();
 54.2056 +            assert(proxy);
 54.2057 +
 54.2058 +            Symbol *sym = proxy->sym();
 54.2059 +            if (!sym)
 54.2060 +                return NULL;
 54.2061 +
 54.2062 +            if (!sym->isType()) {
 54.2063 +                cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars());
 54.2064 +                return NULL;
 54.2065 +            }
 54.2066 +
 54.2067 +            type = sym->toType()->effective();
 54.2068 +        }
 54.2069 +
 54.2070 +        return zone_->types()->qualify(type, quals);
 54.2071 +    }
 54.2072 +
 54.2073 +  protected:
 54.2074 +    Zone *zone_;
 54.2075 +    PoolAllocator &pool_;
 54.2076 +    CompileContext &cc_;
 54.2077 +    TranslationUnit *unit_;
 54.2078 +};
 54.2079 +
 54.2080 +class GlobalBuilder : public NameBinderBase
 54.2081 +{
 54.2082 +    typedef ScopedRoot<Descriptor> ScopedDescriptor;
 54.2083 +    struct PrimitiveFill {
 54.2084 +        ScopedDescriptor *desc;
 54.2085 +        BoxedPrimitive prim;
 54.2086 +
 54.2087 +        PrimitiveFill(ScopedDescriptor *desc, BoxedPrimitive prim)
 54.2088 +          : desc(desc),
 54.2089 +            prim(prim)
 54.2090 +        {
 54.2091 +        }
 54.2092 +    };
 54.2093 +
 54.2094 +  public:
 54.2095 +    GlobalBuilder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.2096 +      : NameBinderBase(zone, cc, unit),
 54.2097 +        globalScope_(unit->globalScope())
 54.2098 +    {
 54.2099 +    }
 54.2100 +
 54.2101 +    Struct *build() {
 54.2102 +        for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
 54.2103 +            unit_->tree()->imports()->at(i)->accept(this);
 54.2104 +
 54.2105 +        // Next, enter the global scope and walk all statements.
 54.2106 +        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
 54.2107 +            Statement *stmt = unit_->tree()->statements()->at(i);
 54.2108 +            stmt->accept(this);
 54.2109 +        }
 54.2110 +
 54.2111 +        Local<Struct> globals(zone_, createGlobals());
 54.2112 +        if (!globals)
 54.2113 +            return NULL;
 54.2114 +
 54.2115 +        populate(globals);
 54.2116 +
 54.2117 +        return globals;
 54.2118 +    }
 54.2119 +
 54.2120 +  private:
 54.2121 +    Struct *createGlobals() {
 54.2122 +        Local<FixedArray> descs(zone_, FixedArray::New(zone_, descriptors_.length(), Heap::Tenure_Old));
 54.2123 +        if (!descs)
 54.2124 +            return NULL;
 54.2125 +
 54.2126 +        for (unsigned i = 0; i < descriptors_.length(); i++)
 54.2127 +            descs->set(zone_, i, *descriptors_[i]);
 54.2128 +
 54.2129 +        Local<String> name(zone_, unit_->module()->name());
 54.2130 +        Local<StructType> type(zone_, StructType::New(zone_, name, descs));
 54.2131 +        if (!type)
 54.2132 +            return NULL;
 54.2133 +
 54.2134 +        Local<StructMap> map(zone_, type->newMap());
 54.2135 +        return Struct::New(zone_, map, Heap::Tenure_Old);
 54.2136 +    }
 54.2137 +
 54.2138 +    void populate(Handle<Struct> globals) {
 54.2139 +        // This is a huge hack, but it's probably better than a full extra
 54.2140 +        // pass. The problem is that until we have all the descriptors, we
 54.2141 +        // can't start setting constexprs in the struct, and we need to set
 54.2142 +        // them now so they're available during full semantic analysis. To
 54.2143 +        // work around this, we build up the list of values we need to set
 54.2144 +        // as we build up descriptors, and then populate the global struct
 54.2145 +        // with this set.
 54.2146 +        //
 54.2147 +        // Note, this code is also kind of dead until we support linking. We
 54.2148 +        // handle constexprs explicitly in importFrom(), by sniffing out the
 54.2149 +        // symbol type. That code will go away later.
 54.2150 +        for (size_t i = 0; i < primitiveFills_.length(); i++) {
 54.2151 +            const PrimitiveFill &fill = primitiveFills_[i];
 54.2152 +            assert(fill.prim.type() == PrimitiveType_Int32);
 54.2153 +            globals->set(*fill.desc, fill.prim.toInt());
 54.2154 +        }
 54.2155 +    }
 54.2156 +
 54.2157 +  public:
 54.2158 +    void visitEnumStatement(EnumStatement *stmt) {
 54.2159 +        if (stmt->visibility() != TOK_PUBLIC || !stmt->name())
 54.2160 +            return;
 54.2161 +
 54.2162 +        Local<Type> type(zone_, zone_->types()->getType());
 54.2163 +        Descriptor *desc = Descriptor::New(zone_, stmt->name(), type, Descriptor::Public);
 54.2164 +        if (!desc)
 54.2165 +            return;
 54.2166 +        if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
 54.2167 +            return;
 54.2168 +
 54.2169 +        for (size_t i = 0; i < stmt->entries()->length(); i++) {
 54.2170 +            EnumStatement::Entry &e = stmt->entries()->at(i);
 54.2171 +            ScopedDescriptor *desc = new (pool_) ScopedDescriptor(Descriptor::New(zone_, e.name, e.sym->type(), Descriptor::Public));
 54.2172 +            if (!desc || !descriptors_.append(desc))
 54.2173 +                return;
 54.2174 +
 54.2175 +            // Save the value so we can export it immediately.
 54.2176 +            if (!primitiveFills_.append(PrimitiveFill(desc, e.sym->value())))
 54.2177 +                return;
 54.2178 +        }
 54.2179 +    }
 54.2180 +
 54.2181 +    void visitNameProxy(NameProxy *proxy) {
 54.2182 +        Scope *scope = unit_->globalScope();
 54.2183 +        Symbol *sym = scope->lookup(proxy->name());
 54.2184 +        if (!sym)
 54.2185 +            cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
 54.2186 +        proxy->bind(sym);
 54.2187 +    }
 54.2188 +
 54.2189 +    void visitFunctionStatement(FunctionStatement *node) {
 54.2190 +        Local<FunctionType> type(zone_, node->sym()->type());
 54.2191 +        if (!fillFunctionType(type, node->signature()))
 54.2192 +            return;
 54.2193 +
 54.2194 +        unsigned offset;
 54.2195 +        if (!builder_.add(type, &offset))
 54.2196 +            return;
 54.2197 +
 54.2198 +        Descriptor::Visibility visibility = (node->token() == TOK_NATIVE || node->token() == TOK_FORWARD)
 54.2199 +                                            ? Descriptor::Public
 54.2200 +                                            : Descriptor::Private;
 54.2201 +
 54.2202 +        Descriptor *desc = Descriptor::New(zone_, node->name(), type, visibility);
 54.2203 +        if (!desc)
 54.2204 +            return;
 54.2205 +        if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
 54.2206 +            return;
 54.2207 +    }
 54.2208 +
 54.2209 +    void visitVariableDeclaration(VariableDeclaration *node) {
 54.2210 +        Local<Type> type(zone_, buildVariableType(node));
 54.2211 +        if (!type)
 54.2212 +            return;
 54.2213 +
 54.2214 +        // If we're in global scope, and we received a |const| qualifier, then
 54.2215 +        // we extend this to array references as well. This is to sort of mimic
 54.2216 +        // SP1 functionality, but also means that you cannot have changeable
 54.2217 +        // const pointers in global scope.
 54.2218 +        if ((node->quals() & TypeQual_Const) && type->isArray()) {
 54.2219 +            if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL)
 54.2220 +                return;
 54.2221 +        }
 54.2222 +
 54.2223 +        node->sym()->setType(type);
 54.2224 +
 54.2225 +        unsigned offset;
 54.2226 +        if (!builder_.add(type, &offset))
 54.2227 +            return;
 54.2228 +
 54.2229 +        Descriptor *desc = Descriptor::New(zone_, node->name(), type, Descriptor::Private);
 54.2230 +        if (!desc)
 54.2231 +            return;
 54.2232 +        if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
 54.2233 +            return;
 54.2234 +    }
 54.2235 +
 54.2236 +    void visitImportStatement(ImportStatement *node) {
 54.2237 +        if (!node->names()) {
 54.2238 +            PathComponent *path = node->path();
 54.2239 +            while (path->next)
 54.2240 +                path = path->next;
 54.2241 +
 54.2242 +            // Imports automatically go into the importScope. For now, we
 54.2243 +            // error if there are any duplicate symbols entered into the
 54.2244 +            // importScope.
 54.2245 +            if (unit_->importScope()->localLookup(path->name)) {
 54.2246 +                cc_.reportError(node->pos(), Message_DuplicateImport, path->name->chars());
 54.2247 +                return;
 54.2248 +            }
 54.2249 +
 54.2250 +            Local<Type> type(zone_, zone_->types()->getImportable());
 54.2251 +            ImportSymbol *sym = new (pool_) ImportSymbol(unit_->importScope(), path->name, node->pos(), type, node->importIndex());
 54.2252 +            if (!unit_->importScope()->addSymbol(sym))
 54.2253 +                return;
 54.2254 +        } else if (node->importAllNames()) {
 54.2255 +            Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
 54.2256 +            if (importable->isPackage()) {
 54.2257 +                assert(false);
 54.2258 +            } else {
 54.2259 +                Local<Module> module(zone_, Module::cast(importable));
 54.2260 +                if (!module->globals())
 54.2261 +                    importAllFromTranslationUnit(node, module->translationUnit());
 54.2262 +                else
 54.2263 +                    assert(false);
 54.2264 +            }
 54.2265 +        } else {
 54.2266 +            Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
 54.2267 +            if (importable->isPackage()) {
 54.2268 +                assert(false);
 54.2269 +            } else {
 54.2270 +                Local<Module> module(zone_, Module::cast(importable));
 54.2271 +
 54.2272 +                // Always grab from the translation unit if we can, for now.
 54.2273 +                if (module->translationUnit())
 54.2274 +                    importFromTranslationUnit(node, module->translationUnit());
 54.2275 +                else
 54.2276 +                    assert(false);
 54.2277 +            }
 54.2278 +        }
 54.2279 +    }
 54.2280 +
 54.2281 +  private:
 54.2282 +    bool importFrom(ImportStatement *node, Symbol *import) {
 54.2283 +        assert(import->type());
 54.2284 +
 54.2285 +        // Check for duplicate import names.
 54.2286 +        if (unit_->importScope()->localLookup(import->name())) {
 54.2287 +            cc_.reportError(node->pos(), Message_DuplicateImport, import->name()->chars());
 54.2288 +            return false;
 54.2289 +        }
 54.2290 +
 54.2291 +        Symbol *sym;
 54.2292 +        if (import->isType()) {
 54.2293 +            // Fuck it, make a TypeSymbol instead of an ImplicitSymbol. This
 54.2294 +            // makes bindType() much simpler. We may run into problems
 54.2295 +            // implementing linking, but it seems unlikely, as long as we are
 54.2296 +            // exporting Types in module structs.
 54.2297 +            Local<Type> type(zone_, zone_->types()->getType());
 54.2298 +            sym = new (pool_) TypeSymbol(unit_->importScope(),
 54.2299 +                                         import->name(),
 54.2300 +                                         type,
 54.2301 +                                         import->toType()->effective());
 54.2302 +        } else if (import->isConstant()) {
 54.2303 +            // Same deal. No reason to lookup in the module globals if we
 54.2304 +            // already have a symbol.
 54.2305 +            sym = new (pool_) ConstantSymbol(unit_->importScope(),
 54.2306 +                                             import->name(),
 54.2307 +                                             node->pos(),
 54.2308 +                                             import->type(),
 54.2309 +                                             import->toConstant()->value());
 54.2310 +        } else {
 54.2311 +            sym = new (pool_) ImplicitSymbol(unit_->importScope(),
 54.2312 +                                             import->name(),
 54.2313 +                                             node->pos(),
 54.2314 +                                             import->type(),
 54.2315 +                                             node->importIndex());
 54.2316 +        }
 54.2317 +
 54.2318 +        if (!unit_->importScope()->addSymbol(sym))
 54.2319 +            return false;
 54.2320 +
 54.2321 +        return true;
 54.2322 +    }
 54.2323 +
 54.2324 +    void importFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
 54.2325 +        assert(!other->failed());
 54.2326 +
 54.2327 +        for (size_t i = 0; i < node->names()->length(); i++) {
 54.2328 +            Handle<String> name = *node->names()->at(i);
 54.2329 +
 54.2330 +            // See if the name exists in the other translation unit.
 54.2331 +            Symbol *import = other->globalScope()->findExported(name);
 54.2332 +            if (!import) {
 54.2333 +                FixedArray *path = unit_->module()->importPathAt(node->importIndex());
 54.2334 +                cc_.reportError(node->pos(), Message_NotFoundInImportable,
 54.2335 +                                name->chars(),
 54.2336 +                                String::cast(path->at(path->length() - 1))->chars());
 54.2337 +                return;
 54.2338 +            }
 54.2339 +
 54.2340 +            if (!importFrom(node, import))
 54.2341 +                return;
 54.2342 +        }
 54.2343 +    }
 54.2344 +
 54.2345 +    void importAllFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
 54.2346 +        assert(!other->failed());
 54.2347 +
 54.2348 +        for (size_t i = 0; i < other->globalScope()->exported()->length(); i++) {
 54.2349 +            Symbol *import = other->globalScope()->exported()->at(i);
 54.2350 +            if (!importFrom(node, import))
 54.2351 +                return;
 54.2352 +        }
 54.2353 +    }
 54.2354 +
 54.2355 +  private:
 54.2356 +    StructureBufferBuilder builder_;
 54.2357 +    Vector<ScopedRoot<Descriptor> *> descriptors_;
 54.2358 +    GlobalScope *globalScope_;
 54.2359 +    Vector<PrimitiveFill> primitiveFills_;
 54.2360 +};
 54.2361 +    
 54.2362 +class NameBinder : public NameBinderBase
 54.2363 +{
 54.2364 +  public:
 54.2365 +    class AutoLinkScope
 54.2366 +    {
 54.2367 +      public:
 54.2368 +        AutoLinkScope(AutoLinkScope **prevp, Scope *scope)
 54.2369 +          : prevp_(prevp),
 54.2370 +            prev_(*prevp),
 54.2371 +            scope_(scope)
 54.2372 +        {
 54.2373 +            if (scope_) {
 54.2374 +                *prevp_ = this;
 54.2375 +                if (prev_)
 54.2376 +                    scope_->setParent(prev_->scope());
 54.2377 +            }
 54.2378 +        }
 54.2379 +        ~AutoLinkScope() {
 54.2380 +            if (scope_) {
 54.2381 +                assert(*prevp_ == this);
 54.2382 +                *prevp_ = prev_;
 54.2383 +            }
 54.2384 +        }
 54.2385 +        Scope *scope() const {
 54.2386 +            return scope_;
 54.2387 +        }
 54.2388 +
 54.2389 +      private:
 54.2390 +        AutoLinkScope **prevp_;
 54.2391 +        AutoLinkScope *prev_;
 54.2392 +        Scope *scope_;
 54.2393 +    };
 54.2394 +
 54.2395 +  public:
 54.2396 +    NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.2397 +      : NameBinderBase(zone, cc, unit),
 54.2398 +        link_(NULL)
 54.2399 +    {
 54.2400 +    }
 54.2401 +
 54.2402 +    void bind() {
 54.2403 +        // Start with the import scope, and collect all imported names.
 54.2404 +        AutoLinkScope importScope(&link_, unit_->importScope());
 54.2405 +
 54.2406 +        for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
 54.2407 +            unit_->tree()->imports()->at(i)->accept(this);
 54.2408 +
 54.2409 +        // Next, enter the global scope and walk all statements.
 54.2410 +        AutoLinkScope globalScope(&link_, unit_->globalScope());
 54.2411 +        for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
 54.2412 +            Statement *stmt = unit_->tree()->statements()->at(i);
 54.2413 +            stmt->accept(this);
 54.2414 +        }
 54.2415 +    }
 54.2416 +
 54.2417 +    void visitVariableDeclaration(VariableDeclaration *node) {
 54.2418 +        // Bind the initializer before registering the declaration, so that we
 54.2419 +        // can error on bogus initializers (new x = x).
 54.2420 +        if (node->initialization())
 54.2421 +            node->initialization()->accept(this);
 54.2422 +
 54.2423 +        // If the node already has a symbol (meaning it was a global), then
 54.2424 +        // we don't have to do anything more.
 54.2425 +        if (node->sym())
 54.2426 +            return;
 54.2427 +
 54.2428 +        Local<Type> type(zone_, buildVariableType(node));
 54.2429 +        if (!type)
 54.2430 +            return;
 54.2431 +
 54.2432 +        VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type);
 54.2433 +        node->setSymbol(sym);
 54.2434 +       
 54.2435 +        if (Symbol *other = link_->scope()->localLookup(sym->name())) {
 54.2436 +            // Report, but allow errors to continue.
 54.2437 +            cc_.reportError(sym->pos(), Message_RedeclaredName,
 54.2438 +                            sym->name()->chars(),
 54.2439 +                            other->pos().line,
 54.2440 +                            other->pos().col);
 54.2441 +            return;
 54.2442 +        }
 54.2443 +        
 54.2444 +        link_->scope()->addSymbol(sym);
 54.2445 +    }
 54.2446 +    void visitEnumStatement(EnumStatement *node) {
 54.2447 +    }
 54.2448 +    void visitFunctionStatement(FunctionStatement *node) {
 54.2449 +        AutoLinkScope argScope(&link_, node->argScope());
 54.2450 +        AutoLinkScope varScope(&link_, node->varScope());
 54.2451 +
 54.2452 +        // If the function is in the global scope, we've already computed its
 54.2453 +        // type.
 54.2454 +        if (node->sym()->scope()->kind() != Scope::GLOBAL) {
 54.2455 +            Local<FunctionType> type(zone_, node->sym()->type());
 54.2456 +            if (!fillFunctionType(type, node->signature()))
 54.2457 +                return;
 54.2458 +        }
 54.2459 +
 54.2460 +        if (node->body())
 54.2461 +            node->body()->accept(this);
 54.2462 +    }
 54.2463 +    void visitStructureStatement(StructureStatement *node) {
 54.2464 +        assert(false);
 54.2465 +    }
 54.2466 +    void visitFunctionTypeStatement(FunctionTypeStatement *node) {
 54.2467 +        assert(false);
 54.2468 +    }
 54.2469 +
 54.2470 +    void visitNameProxy(NameProxy *proxy) {
 54.2471 +        // We could have already bound globals.
 54.2472 +        if (proxy->sym())
 54.2473 +            return;
 54.2474 +
 54.2475 +        Scope *scope = link_->scope();
 54.2476 +        Symbol *sym = scope->lookup(proxy->name());
 54.2477 +        if (!sym)
 54.2478 +            cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
 54.2479 +        proxy->bind(sym);
 54.2480 +    }
 54.2481 +    void visitAssignment(Assignment *node) {
 54.2482 +        node->lvalue()->accept(this);
 54.2483 +        node->expression()->accept(this);
 54.2484 +    }
 54.2485 +    void visitBinaryExpression(BinaryExpression *node) {
 54.2486 +        node->left()->accept(this);
 54.2487 +        node->right()->accept(this);
 54.2488 +    }
 54.2489 +    void visitReturnStatement(ReturnStatement *node) {
 54.2490 +        node->expression()->accept(this);
 54.2491 +    }
 54.2492 +    void visitForStatement(ForStatement *node) {
 54.2493 +        AutoLinkScope scope(&link_, node->scope());
 54.2494 +
 54.2495 +        if (node->initialization())
 54.2496 +            node->initialization()->accept(this);
 54.2497 +        if (node->condition())
 54.2498 +            node->condition()->accept(this);
 54.2499 +        if (node->update())
 54.2500 +            node->update()->accept(this);
 54.2501 +        node->body()->accept(this);
 54.2502 +    }
 54.2503 +    void visitBlockStatement(BlockStatement *node) {
 54.2504 +        AutoLinkScope scope(&link_, node->scope());
 54.2505 +        for (size_t i = 0; i < node->statements()->length(); i++)
 54.2506 +            node->statements()->at(i)->accept(this);
 54.2507 +    }
 54.2508 +    void visitIntegerLiteral(IntegerLiteral *node) {
 54.2509 +    }
 54.2510 +    void visitExpressionStatement(ExpressionStatement *node) {
 54.2511 +        node->expression()->accept(this);
 54.2512 +    }
 54.2513 +    void visitCallExpression(CallExpression *node) {
 54.2514 +        node->callee()->accept(this);
 54.2515 +        for (size_t i = 0; i < node->arguments()->length(); i++)
 54.2516 +            node->arguments()->at(i)->accept(this);
 54.2517 +    }
 54.2518 +    void visitIfStatement(IfStatement *node) {
 54.2519 +        node->condition()->accept(this);
 54.2520 +        node->ifTrue()->accept(this);
 54.2521 +        if (node->ifFalse())
 54.2522 +            node->ifFalse()->accept(this);
 54.2523 +    }
 54.2524 +    void visitIndexExpression(IndexExpression *node) {
 54.2525 +        node->left()->accept(this);
 54.2526 +        node->right()->accept(this);
 54.2527 +    }
 54.2528 +    void visitFloatLiteral(FloatLiteral *node) {
 54.2529 +    }
 54.2530 +    void visitWhileStatement(WhileStatement *node) {
 54.2531 +        node->condition()->accept(this);
 54.2532 +        node->body()->accept(this);
 54.2533 +    }
 54.2534 +    void visitBreakStatement(BreakStatement *node) {
 54.2535 +    }
 54.2536 +    void visitContinueStatement(ContinueStatement *node) {
 54.2537 +    }
 54.2538 +    void visitStringLiteral(StringLiteral *node) {
 54.2539 +    }
 54.2540 +    void visitIncDecExpression(IncDecExpression *node) {
 54.2541 +        node->expression()->accept(this);
 54.2542 +    }
 54.2543 +    void visitUnaryExpression(UnaryExpression *node) {
 54.2544 +        if (node->tag())
 54.2545 +            node->tag()->accept(this);
 54.2546 +        node->expression()->accept(this);
 54.2547 +    }
 54.2548 +    void visitTernaryExpression(TernaryExpression *node) {
 54.2549 +        node->condition()->accept(this);
 54.2550 +        node->left()->accept(this);
 54.2551 +        node->right()->accept(this);
 54.2552 +    }
 54.2553 +    void visitBooleanLiteral(BooleanLiteral *node) {
 54.2554 +    }
 54.2555 +    void visitFieldExpression(FieldExpression *node) {
 54.2556 +        node->left()->accept(this);
 54.2557 +    }
 54.2558 +    void visitSwitchStatement(SwitchStatement *node) {
 54.2559 +        node->expression()->accept(this);
 54.2560 +        node->defaultCase()->accept(this);
 54.2561 +        for (size_t i = 0; i < node->cases()->length(); i++) {
 54.2562 +            // We don't test case expressions because they are literals.
 54.2563 +            Case *c = node->cases()->at(i);
 54.2564 +            c->statement()->accept(this);
 54.2565 +        }
 54.2566 +    }
 54.2567 +    void visitArrayLiteral(ArrayLiteral *node) {
 54.2568 +        for (size_t i = 0; i < node->expressions()->length(); i++)
 54.2569 +            node->expressions()->at(i)->accept(this);
 54.2570 +    }
 54.2571 +    void visitImportStatement(ImportStatement *node) {
 54.2572 +    }
 54.2573 +
 54.2574 +  private:
 54.2575 +    AutoLinkScope *link_;
 54.2576 +};
 54.2577 +
 54.2578 +void
 54.2579 +ke::BindGlobals(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.2580 +{
 54.2581 +    AutoEnterCompileContext enter(cc, unit);
 54.2582 +
 54.2583 +    GlobalBuilder builder(zone, cc, unit);
 54.2584 +    Local<Struct> globals(zone, builder.build());
 54.2585 +    if (!globals || unit->failed())
 54.2586 +        return;
 54.2587 +
 54.2588 +    unit->module()->setGlobals(globals);
 54.2589 +}
 54.2590 +
 54.2591 +void
 54.2592 +ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 54.2593 +{
 54.2594 +    AutoEnterCompileContext enter(cc, unit);
 54.2595 +    NameBinder binder(zone, cc, unit);
 54.2596 +    binder.bind();
 54.2597 +}
    55.1 --- a/src/compiler/NameBinding.h	Mon Jun 10 00:46:29 2013 +0100
    55.2 +++ b/src/compiler/NameBinding.h	Mon Jun 10 01:04:43 2013 +0100
    55.3 @@ -1,48 +1,48 @@
    55.4 -/* vim: set ts=4 sw=4 tw=99 et:
    55.5 - *
    55.6 - * Copyright (C) 2012 David Anderson
    55.7 - *
    55.8 - * This file is part of SourcePawn.
    55.9 - *
   55.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   55.11 - * the terms of the GNU General Public License as published by the Free
   55.12 - * Software Foundation, either version 3 of the License, or (at your option)
   55.13 - * any later version.
   55.14 - * 
   55.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   55.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   55.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   55.18 - *
   55.19 - * You should have received a copy of the GNU General Public License along with
   55.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   55.21 - */
   55.22 -#ifndef _include_name_binding_h_
   55.23 -#define _include_name_binding_h_
   55.24 -
   55.25 -#include "../PoolAllocator.h"
   55.26 -#include "../Types.h"
   55.27 -#include "Scanner.h"
   55.28 -
   55.29 -namespace ke {
   55.30 -
   55.31 -class Zone;
   55.32 -class CompileContext;
   55.33 -struct TranslationUnit;
   55.34 -
   55.35 -// Creates symbols and types for names that are global or can be derived from
   55.36 -// a global. This phase also populates global scopes with lists of exported
   55.37 -// symbols.
   55.38 -void PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   55.39 -
   55.40 -// Because of the way globals work in Pawn, we need a precursor step to
   55.41 -// actually enter global symbols into the global struct. They're already in
   55.42 -// the global symbol table, so we know they won't clash. This process also
   55.43 -// binds any remaining types on global variables.
   55.44 -void BindGlobals(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   55.45 -
   55.46 -// Bind all outstanding names and finalize all unfinished types.
   55.47 -void BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   55.48 -
   55.49 -}
   55.50 -
   55.51 -#endif // _include_name_binding_h_
   55.52 +/* vim: set ts=4 sw=4 tw=99 et:
   55.53 + *
   55.54 + * Copyright (C) 2012 David Anderson
   55.55 + *
   55.56 + * This file is part of SourcePawn.
   55.57 + *
   55.58 + * SourcePawn is free software: you can redistribute it and/or modify it under
   55.59 + * the terms of the GNU General Public License as published by the Free
   55.60 + * Software Foundation, either version 3 of the License, or (at your option)
   55.61 + * any later version.
   55.62 + * 
   55.63 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   55.64 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   55.65 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   55.66 + *
   55.67 + * You should have received a copy of the GNU General Public License along with
   55.68 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   55.69 + */
   55.70 +#ifndef _include_name_binding_h_
   55.71 +#define _include_name_binding_h_
   55.72 +
   55.73 +#include "../PoolAllocator.h"
   55.74 +#include "../Types.h"
   55.75 +#include "Scanner.h"
   55.76 +
   55.77 +namespace ke {
   55.78 +
   55.79 +class Zone;
   55.80 +class CompileContext;
   55.81 +struct TranslationUnit;
   55.82 +
   55.83 +// Creates symbols and types for names that are global or can be derived from
   55.84 +// a global. This phase also populates global scopes with lists of exported
   55.85 +// symbols.
   55.86 +void PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   55.87 +
   55.88 +// Because of the way globals work in Pawn, we need a precursor step to
   55.89 +// actually enter global symbols into the global struct. They're already in
   55.90 +// the global symbol table, so we know they won't clash. This process also
   55.91 +// binds any remaining types on global variables.
   55.92 +void BindGlobals(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   55.93 +
   55.94 +// Bind all outstanding names and finalize all unfinished types.
   55.95 +void BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   55.96 +
   55.97 +}
   55.98 +
   55.99 +#endif // _include_name_binding_h_
    56.1 --- a/src/compiler/Parser.cpp	Mon Jun 10 00:46:29 2013 +0100
    56.2 +++ b/src/compiler/Parser.cpp	Mon Jun 10 01:04:43 2013 +0100
    56.3 @@ -1,1787 +1,1787 @@
    56.4 -/* vim: set ts=4 sw=4 tw=99 et:
    56.5 - *
    56.6 - * Copyright (C) 2012 David Anderson
    56.7 - *
    56.8 - * This file is part of SourcePawn.
    56.9 - *
   56.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   56.11 - * the terms of the GNU General Public License as published by the Free
   56.12 - * Software Foundation, either version 3 of the License, or (at your option)
   56.13 - * any later version.
   56.14 - * 
   56.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   56.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   56.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   56.18 - *
   56.19 - * You should have received a copy of the GNU General Public License along with
   56.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   56.21 - */
   56.22 -#include <string.h>
   56.23 -#include "../Zone.h"
   56.24 -#include "../FixedArray.h"
   56.25 -#include "../Heap.h"
   56.26 -#include "../Strings.h"
   56.27 -#include "../TypeManager.h"
   56.28 -#include "Parser.h"
   56.29 -#include "../Heap-inl.h"
   56.30 -
   56.31 -using namespace ke;
   56.32 -
   56.33 -Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length)
   56.34 -  : zone_(zone),
   56.35 -    cc_(cc),
   56.36 -    pool_(zone_->pool()),
   56.37 -    scanner_(cc, stream, length),
   56.38 -    unbound_(NULL)
   56.39 -{
   56.40 -    unbound_ = new (pool_) PoolList<NameProxy *>();
   56.41 -    imports_ = new (pool_) PoolList<ImportStatement *>();
   56.42 -}
   56.43 -
   56.44 -bool
   56.45 -Parser::peek(TokenKind kind)
   56.46 -{
   56.47 -    return scanner_.peek() == kind;
   56.48 -}
   56.49 -
   56.50 -bool
   56.51 -Parser::match(TokenKind kind)
   56.52 -{
   56.53 -    if (!peek(kind))
   56.54 -        return false;
   56.55 -    scanner_.scan();
   56.56 -    return true;
   56.57 -}
   56.58 -
   56.59 -bool
   56.60 -Parser::matchSemicolon()
   56.61 -{
   56.62 -    return expect(TOK_SEMICOLON);
   56.63 -}
   56.64 -
   56.65 -bool
   56.66 -Parser::expect(TokenKind kind)
   56.67 -{
   56.68 -    TokenKind got = scanner_.scan();
   56.69 -    if (got == kind)
   56.70 -        return true;
   56.71 -    cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]);
   56.72 -    return false;
   56.73 -}
   56.74 -
   56.75 -bool
   56.76 -Parser::matchName(String **name, TokenKind kind)
   56.77 -{
   56.78 -    assert(kind == TOK_NAME || kind == TOK_LABEL);
   56.79 -    *name = NULL;
   56.80 -    if (!match(kind))
   56.81 -        return false;
   56.82 -    *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
   56.83 -    return true;
   56.84 -}
   56.85 -
   56.86 -String *
   56.87 -Parser::expectName()
   56.88 -{
   56.89 -    if (!expect(TOK_NAME))
   56.90 -        return NULL;
   56.91 -    return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
   56.92 -}
   56.93 -
   56.94 -Expression *
   56.95 -Parser::primitive()
   56.96 -{
   56.97 -    TokenKind kind = scanner_.peek();
   56.98 -    switch (kind) {
   56.99 -      case TOK_FLOAT_LITERAL:
  56.100 -      {
  56.101 -        scanner_.scan();
  56.102 -        double value = Scanner::ParseDouble(scanner_.literal());
  56.103 -        return new (pool_) FloatLiteral(scanner_.begin(), value);
  56.104 -      }
  56.105 -
  56.106 -      case TOK_HEX_LITERAL:
  56.107 -      {
  56.108 -        scanner_.scan();
  56.109 -        int value = strtol(scanner_.literal(), NULL, 16);
  56.110 -        return new (pool_) IntegerLiteral(scanner_.begin(), value);
  56.111 -      }
  56.112 -
  56.113 -      case TOK_INTEGER_LITERAL:
  56.114 -      {
  56.115 -        scanner_.scan();
  56.116 -        int value = atoi(scanner_.literal());
  56.117 -        return new (pool_) IntegerLiteral(scanner_.begin(), value);
  56.118 -      }
  56.119 -
  56.120 -      case TOK_TRUE:
  56.121 -      case TOK_FALSE:
  56.122 -        scanner_.scan();
  56.123 -        return new (pool_) BooleanLiteral(scanner_.begin(), kind);
  56.124 -
  56.125 -      case TOK_STRING_LITERAL:
  56.126 -      {
  56.127 -        scanner_.scan();
  56.128 -        Local<String> string(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
  56.129 -        return new (pool_) StringLiteral(scanner_.begin(), string);
  56.130 -      }
  56.131 -
  56.132 -      default:
  56.133 -      {
  56.134 -        if (kind != TOK_ERROR)
  56.135 -            cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]);
  56.136 -        return NULL;
  56.137 -      }
  56.138 -    }
  56.139 -}
  56.140 -
  56.141 -Expression *
  56.142 -Parser::fixedArrayLiteral()
  56.143 -{
  56.144 -    SourcePosition pos = scanner_.begin();
  56.145 -
  56.146 -    ExpressionList *list = new (pool_) ExpressionList();
  56.147 -    do {
  56.148 -        // { } is an illegal array literal.
  56.149 -        if (list->length() > 0 && match(TOK_LBRACE))
  56.150 -            break;
  56.151 -
  56.152 -        Expression *expr = NULL;
  56.153 -        if (peek(TOK_LBRACE))
  56.154 -            expr = fixedArrayLiteral();
  56.155 -        else
  56.156 -            expr = primitive();
  56.157 -        if (!expr)
  56.158 -            return NULL;
  56.159 -
  56.160 -        if (!list->append(expr))
  56.161 -            return NULL;
  56.162 -
  56.163 -        if (!match(TOK_COMMA)) {
  56.164 -            if (!expect(TOK_RBRACE))
  56.165 -                return NULL;
  56.166 -            break;
  56.167 -        }
  56.168 -    } while (true);
  56.169 -
  56.170 -    return new (pool_) ArrayLiteral(pos, TOK_LBRACE, list);
  56.171 -}
  56.172 -
  56.173 -Expression *
  56.174 -Parser::prefix()
  56.175 -{
  56.176 -    switch (scanner_.peek()) {
  56.177 -      case TOK_LPAREN:
  56.178 -      {
  56.179 -        scanner_.scan();
  56.180 -        Expression *expr = expression();
  56.181 -        if (!expr)
  56.182 -            return NULL;
  56.183 -        if (!expect(TOK_RPAREN))
  56.184 -            return NULL;
  56.185 -        return expr;
  56.186 -      }
  56.187 -
  56.188 -      case TOK_NAME:
  56.189 -      {
  56.190 -        Local<String> name(zone_, expectName());
  56.191 -        if (!name)
  56.192 -            return NULL;
  56.193 -        return new (pool_) NameProxy(scanner_.begin(), name);
  56.194 -      }
  56.195 -
  56.196 -      default:
  56.197 -        return primitive();
  56.198 -    }
  56.199 -}
  56.200 -
  56.201 -// Parses only old-style declarations.
  56.202 -bool
  56.203 -Parser::typeAndName(Expression **type, String **namep)
  56.204 -{
  56.205 -    if (match(TOK_LABEL)) {
  56.206 -        // Old-style declaration:
  56.207 -        //   new X:type
  56.208 -        Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
  56.209 -        if (!name)
  56.210 -            return false;
  56.211 -
  56.212 -        *type = new (pool_) NameProxy(scanner_.begin(), name);
  56.213 -        *namep = expectName();
  56.214 -        return !!*namep;
  56.215 -    }
  56.216 -    
  56.217 -    *type = NULL;
  56.218 -    *namep = expectName();
  56.219 -
  56.220 -    return !!*namep;
  56.221 -}
  56.222 -
  56.223 -// Parses both old and new style declarations.
  56.224 -bool
  56.225 -Parser::fullTypeAndName(Expression **type, String **namep, DeclKind kind)
  56.226 -{
  56.227 -    //   decl    ::= newdecl | olddecl
  56.228 -    //   newdecl ::= Type Ident
  56.229 -    //   olddecl ::= Label? (Ident | "...")
  56.230 -    //   type    ::= Ident
  56.231 -    //   label   ::= Ident ":"
  56.232 -    //
  56.233 -    if (match(TOK_LABEL)) {
  56.234 -        // We something of the form:
  56.235 -        //     Label Ident
  56.236 -        // or: Label "..."
  56.237 -        Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
  56.238 -        if (!name)
  56.239 -            return false;
  56.240 -
  56.241 -        *type = new (pool_) NameProxy(scanner_.begin(), name);
  56.242 -        if (kind == DeclArg && match(TOK_ELLIPSES)) {
  56.243 -            *namep = NULL;
  56.244 -        } else {
  56.245 -            if ((*namep = expectName()) == NULL)
  56.246 -                return false;
  56.247 -        }
  56.248 -        return true;
  56.249 -    }
  56.250 -
  56.251 -    Local<String> name(zone_, expectName());
  56.252 -    if (!name)
  56.253 -        return false;
  56.254 -
  56.255 -    if (peek(TOK_NAME) || (kind == DeclArg && peek(TOK_ELLIPSES))) {
  56.256 -        // We got something of the form:
  56.257 -        //    Ident Ident
  56.258 -        *type = new (pool_) NameProxy(scanner_.begin(), name);
  56.259 -        if (peek(TOK_NAME)) {
  56.260 -            if ((*namep = expectName()) == NULL)
  56.261 -                return false;
  56.262 -        } else {
  56.263 -            *namep = NULL;
  56.264 -        }
  56.265 -        return true;
  56.266 -    }
  56.267 -
  56.268 -    // We got something of the form:
  56.269 -    //    Ident
  56.270 -    *type = NULL;
  56.271 -    *namep = name;
  56.272 -    return true;
  56.273 -}
  56.274 -
  56.275 -Expression *
  56.276 -Parser::call(Expression *callee)
  56.277 -{
  56.278 -    ExpressionList *arguments = new (pool_) ExpressionList();
  56.279 -
  56.280 -    SourcePosition pos = scanner_.begin();
  56.281 -    expect(TOK_LPAREN);
  56.282 -    
  56.283 -    if (!match(TOK_RPAREN)) {
  56.284 -        while (true) {
  56.285 -            Expression *expr = expression();
  56.286 -            if (!expr)
  56.287 -                return NULL;
  56.288 -
  56.289 -            if (!arguments->append(expr))
  56.290 -                return NULL;
  56.291 -
  56.292 -            if (!match(TOK_COMMA))
  56.293 -                break;
  56.294 -        }
  56.295 -
  56.296 -        if (!expect(TOK_RPAREN))
  56.297 -            return NULL;
  56.298 -    }
  56.299 -
  56.300 -    return new (pool_) CallExpression(pos, callee, arguments);
  56.301 -}
  56.302 -
  56.303 -Expression *
  56.304 -Parser::index(Expression *left)
  56.305 -{
  56.306 -    expect(TOK_LBRACKET);
  56.307 -    
  56.308 -    SourcePosition pos = scanner_.begin();
  56.309 -    Expression *expr = expression();
  56.310 -    if (!expr)
  56.311 -        return NULL;
  56.312 -
  56.313 -    if (!expect(TOK_RBRACKET))
  56.314 -        return NULL;
  56.315 -
  56.316 -    return new (pool_) IndexExpression(pos, left, expr);
  56.317 -}
  56.318 -
  56.319 -Expression *
  56.320 -Parser::field(Expression *left)
  56.321 -{
  56.322 -    expect(TOK_DOT);
  56.323 -
  56.324 -    SourcePosition pos = scanner_.begin();
  56.325 -    Local<String> name(zone_, expectName());
  56.326 -    if (!name)
  56.327 -        return NULL;
  56.328 -
  56.329 -    return new (pool_) FieldExpression(pos, left, name);
  56.330 -}
  56.331 -
  56.332 -Expression *
  56.333 -Parser::primary()
  56.334 -{
  56.335 -    Expression *expr = prefix();
  56.336 -    if (!expr)
  56.337 -        return NULL;
  56.338 -
  56.339 -    for (;;) {
  56.340 -        switch (scanner_.peek()) {
  56.341 -          case TOK_LPAREN:
  56.342 -            if ((expr = call(expr)) == NULL)
  56.343 -                return NULL;
  56.344 -            break;
  56.345 -
  56.346 -          case TOK_LBRACKET:
  56.347 -            if ((expr = index(expr)) == NULL)
  56.348 -                return NULL;
  56.349 -            break;
  56.350 -
  56.351 -          case TOK_DOT:
  56.352 -            if ((expr = field(expr)) == NULL)
  56.353 -                return NULL;
  56.354 -            break;
  56.355 -
  56.356 -          default:
  56.357 -            return expr;
  56.358 -        }
  56.359 -    }
  56.360 -}
  56.361 -
  56.362 -Expression *
  56.363 -Parser::unary()
  56.364 -{
  56.365 -    TokenKind token = scanner_.peek();
  56.366 -
  56.367 -    SourcePosition pos = scanner_.begin();
  56.368 -    switch (token) {
  56.369 -      case TOK_INCREMENT:
  56.370 -      case TOK_DECREMENT:
  56.371 -      {
  56.372 -        scanner_.scan();
  56.373 -        Expression *expr = unary();
  56.374 -        if (!expr)
  56.375 -            return NULL;
  56.376 -        return new (pool_) IncDecExpression(pos, token, expr, false);
  56.377 -      }
  56.378 -
  56.379 -      case TOK_MINUS:
  56.380 -      case TOK_NOT:
  56.381 -      case TOK_TILDE:
  56.382 -      {
  56.383 -        scanner_.scan();
  56.384 -        Expression *expr = unary();
  56.385 -        if (!expr)
  56.386 -            return NULL;
  56.387 -        return new (pool_) UnaryExpression(pos, token, expr);
  56.388 -      }
  56.389 -
  56.390 -      case TOK_SIZEOF:
  56.391 -      {
  56.392 -        scanner_.scan();
  56.393 -        if (!expect(TOK_LPAREN))
  56.394 -            return NULL;
  56.395 -        Expression *expr = unary();
  56.396 -        if (!expr)
  56.397 -            return NULL;
  56.398 -        if (!expect(TOK_RPAREN))
  56.399 -            return NULL;
  56.400 -        return new (pool_) UnaryExpression(pos, token, expr);
  56.401 -      }
  56.402 -
  56.403 -      case TOK_LABEL:
  56.404 -      {
  56.405 -        scanner_.scan();
  56.406 -        Local<String> tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
  56.407 -        if (!tag)
  56.408 -            return NULL;
  56.409 -
  56.410 -        NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), tag);
  56.411 -
  56.412 -        Expression *expr = unary();
  56.413 -        if (!expr)
  56.414 -            return NULL;
  56.415 -
  56.416 -        return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, proxy);
  56.417 -      }
  56.418 -
  56.419 -      default:
  56.420 -        break;
  56.421 -    }
  56.422 -
  56.423 -    Expression *expr = primary();
  56.424 -
  56.425 -    token = scanner_.peek();
  56.426 -    if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
  56.427 -        scanner_.scan();
  56.428 -        return new (pool_) IncDecExpression(pos, token, expr, true);
  56.429 -    }
  56.430 -
  56.431 -    return expr;
  56.432 -}
  56.433 -
  56.434 -Expression *
  56.435 -Parser::multiplication()
  56.436 -{
  56.437 -    Expression *left = unary();
  56.438 -    do {
  56.439 -        if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT))
  56.440 -            break;
  56.441 -        SourcePosition pos = scanner_.begin();
  56.442 -        TokenKind kind = scanner_.last();
  56.443 -        Expression *right = unary();
  56.444 -        if (!right)
  56.445 -            return NULL;
  56.446 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  56.447 -    } while (left);
  56.448 -    return left;
  56.449 -}
  56.450 -
  56.451 -Expression *
  56.452 -Parser::addition()
  56.453 -{
  56.454 -    Expression *left = multiplication();
  56.455 -    while (left) {
  56.456 -        if (!match(TOK_PLUS) && !match(TOK_MINUS))
  56.457 -            break;
  56.458 -        SourcePosition pos = scanner_.begin();
  56.459 -        TokenKind kind = scanner_.last();
  56.460 -        Expression *right = multiplication();
  56.461 -        if (!right)
  56.462 -            return NULL;
  56.463 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  56.464 -    }
  56.465 -    return left;
  56.466 -}
  56.467 -
  56.468 -Expression *
  56.469 -Parser::shift()
  56.470 -{
  56.471 -    Expression *left = addition();
  56.472 -    while (left) {
  56.473 -        if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR))
  56.474 -            break;
  56.475 -        SourcePosition pos = scanner_.begin();
  56.476 -        TokenKind kind = scanner_.last();
  56.477 -        Expression *right = addition();
  56.478 -        if (!right)
  56.479 -            return NULL;
  56.480 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  56.481 -    }
  56.482 -    return left;
  56.483 -}
  56.484 -
  56.485 -Expression *
  56.486 -Parser::bitand_()
  56.487 -{
  56.488 -    Expression *left = shift();
  56.489 -    while (left) {
  56.490 -        if (!match(TOK_BITAND))
  56.491 -            break;
  56.492 -        SourcePosition pos = scanner_.begin();
  56.493 -        Expression *right = shift();
  56.494 -        if (!right)
  56.495 -            return NULL;
  56.496 -        left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right);
  56.497 -    }
  56.498 -    return left;
  56.499 -}
  56.500 -
  56.501 -Expression *
  56.502 -Parser::bitxor()
  56.503 -{
  56.504 -    Expression *left = bitand_();
  56.505 -    while (left) {
  56.506 -        if (!match(TOK_BITXOR))
  56.507 -            break;
  56.508 -        SourcePosition pos = scanner_.begin();
  56.509 -        Expression *right = shift();
  56.510 -        if (!right)
  56.511 -            return NULL;
  56.512 -        left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right);
  56.513 -    }
  56.514 -    return left;
  56.515 -}
  56.516 -
  56.517 -Expression *
  56.518 -Parser::bitor_()
  56.519 -{
  56.520 -    Expression *left = bitxor();
  56.521 -    while (left) {
  56.522 -        if (!match(TOK_BITOR))
  56.523 -            break;
  56.524 -        SourcePosition pos = scanner_.begin();
  56.525 -        Expression *right = bitxor();
  56.526 -        if (!right)
  56.527 -            return NULL;
  56.528 -        left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right);
  56.529 -    }
  56.530 -    return left;
  56.531 -}
  56.532 -
  56.533 -Expression *
  56.534 -Parser::relational()
  56.535 -{
  56.536 -    Expression *left = bitor_();
  56.537 -    while (left) {
  56.538 -        TokenKind kind = scanner_.peek();
  56.539 -        if (kind < TOK_LT || kind > TOK_GE)
  56.540 -            break;
  56.541 -        scanner_.scan();
  56.542 -        SourcePosition pos = scanner_.begin();
  56.543 -        Expression *right = shift();
  56.544 -        if (!right)
  56.545 -            return NULL;
  56.546 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  56.547 -    }
  56.548 -    return left;
  56.549 -}
  56.550 -
  56.551 -Expression *
  56.552 -Parser::equals()
  56.553 -{
  56.554 -    Expression *left = relational();
  56.555 -    while (left) {
  56.556 -        if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS))
  56.557 -            break;
  56.558 -        TokenKind kind = scanner_.last();
  56.559 -        SourcePosition pos = scanner_.begin();
  56.560 -        Expression *right = relational();
  56.561 -        if (!right)
  56.562 -            return NULL;
  56.563 -        left = new (pool_) BinaryExpression(pos, kind, left, right);
  56.564 -    }
  56.565 -    return left;
  56.566 -}
  56.567 -
  56.568 -Expression *
  56.569 -Parser::and_()
  56.570 -{
  56.571 -    Expression *left = equals();
  56.572 -    while (left) {
  56.573 -        if (!match(TOK_AND))
  56.574 -            break;
  56.575 -        SourcePosition pos = scanner_.begin();
  56.576 -        Expression *right = equals();
  56.577 -        if (!right)
  56.578 -            return NULL;
  56.579 -        left = new (pool_) BinaryExpression(pos, TOK_AND, left, right);
  56.580 -    }
  56.581 -    return left;
  56.582 -}
  56.583 -
  56.584 -Expression *
  56.585 -Parser::or_()
  56.586 -{
  56.587 -    Expression *left = and_();
  56.588 -    while (left) {
  56.589 -        if (!match(TOK_OR))
  56.590 -            break;
  56.591 -        SourcePosition pos = scanner_.begin();
  56.592 -        Expression *right = and_();
  56.593 -        if (!right)
  56.594 -            return NULL;
  56.595 -        left = new (pool_) BinaryExpression(pos, TOK_OR, left, right);
  56.596 -    }
  56.597 -    return left;
  56.598 -}
  56.599 -
  56.600 -Expression *
  56.601 -Parser::ternary()
  56.602 -{
  56.603 -    Expression *cond = or_();
  56.604 -    if (!cond)
  56.605 -        return NULL;
  56.606 -    
  56.607 -    if (!match(TOK_QMARK))
  56.608 -        return cond;
  56.609 -
  56.610 -    Expression *left;
  56.611 -    SourcePosition pos = scanner_.begin();
  56.612 -    AutoAllowTags<false> disableTags(scanner_);
  56.613 -    {
  56.614 -        if ((left = expression()) == NULL)
  56.615 -            return NULL;
  56.616 -    }
  56.617 -
  56.618 -    if (!expect(TOK_COLON))
  56.619 -        return NULL;
  56.620 -
  56.621 -    Expression *right = expression();
  56.622 -    if (!right)
  56.623 -        return NULL;
  56.624 -
  56.625 -    return new (pool_) TernaryExpression(pos, cond, left, right);
  56.626 -}
  56.627 -
  56.628 -Expression *
  56.629 -Parser::assignment()
  56.630 -{
  56.631 -    Expression *left = ternary();
  56.632 -    while (left) {
  56.633 -        TokenKind token = scanner_.peek();
  56.634 -        if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
  56.635 -            break;
  56.636 -        scanner_.scan();
  56.637 -        SourcePosition pos = scanner_.begin();
  56.638 -        Expression *expr = ternary();
  56.639 -        if (!expr)
  56.640 -            return NULL;
  56.641 -
  56.642 -        left = new (pool_) Assignment(pos, token, left, expr);
  56.643 -    }
  56.644 -    return left;
  56.645 -}
  56.646 -
  56.647 -Expression *
  56.648 -Parser::expression()
  56.649 -{
  56.650 -    return assignment();
  56.651 -}
  56.652 -
  56.653 -Statement *
  56.654 -Parser::while_()
  56.655 -{
  56.656 -    // while ::= "while" "(" expr ")" statement
  56.657 -    SourcePosition pos = scanner_.begin();
  56.658 -    scanner_.scan();
  56.659 -
  56.660 -    if (!expect(TOK_LPAREN))
  56.661 -        return NULL;
  56.662 -
  56.663 -    Expression *condition = expression();
  56.664 -    if (!condition)
  56.665 -        return NULL;
  56.666 -
  56.667 -    if (!expect(TOK_RPAREN))
  56.668 -        return NULL;
  56.669 -
  56.670 -    Statement *body;
  56.671 -    if (scanner_.peek() == TOK_LBRACE)
  56.672 -        body = block();
  56.673 -    else
  56.674 -        body = localStatement();
  56.675 -    if (!body)
  56.676 -        return NULL;
  56.677 -
  56.678 -    return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body);
  56.679 -}
  56.680 -
  56.681 -Statement *
  56.682 -Parser::do_()
  56.683 -{
  56.684 -    // do ::= "do" block "while" "(" expr ")"
  56.685 -    SourcePosition pos = scanner_.begin();
  56.686 -    scanner_.scan();
  56.687 -
  56.688 -    Statement *body = block();
  56.689 -    if (!body)
  56.690 -        return NULL;
  56.691 -
  56.692 -    if (!expect(TOK_WHILE))
  56.693 -        return NULL;
  56.694 -
  56.695 -    if (!expect(TOK_LPAREN))
  56.696 -        return NULL;
  56.697 -    Expression *condition = expression();
  56.698 -    if (!condition)
  56.699 -        return NULL;
  56.700 -    if (!expect(TOK_RPAREN))
  56.701 -        return NULL;
  56.702 -
  56.703 -    return new (pool_) WhileStatement(pos, TOK_DO, condition, body);
  56.704 -}
  56.705 -
  56.706 -Statement *
  56.707 -Parser::switch_()
  56.708 -{
  56.709 -    // switch ::= "switch" "(" expr ")" "{" case* defaultcase? "}"
  56.710 -    // case ::= "case" casevals ":" statement
  56.711 -    // defaultcase ::= "default" ":" statement
  56.712 -    //
  56.713 -    expect(TOK_SWITCH);
  56.714 -
  56.715 -    SourcePosition pos = scanner_.begin();
  56.716 -
  56.717 -    if (!expect(TOK_LPAREN))
  56.718 -        return NULL;
  56.719 -    Expression *expr = expression();
  56.720 -    if (!expr)
  56.721 -        return NULL;
  56.722 -    if (!expect(TOK_RPAREN))
  56.723 -        return NULL;
  56.724 -
  56.725 -    if (!expect(TOK_LBRACE))
  56.726 -        return NULL;
  56.727 -
  56.728 -    SourcePosition defaultPos;
  56.729 -    PoolList<Case *> *cases = new (pool_) PoolList<Case *>();
  56.730 -
  56.731 -    Statement *defaultCase = NULL;
  56.732 -
  56.733 -    while (!peek(TOK_RBRACE)) {
  56.734 -        Expression *expr = NULL;
  56.735 -        ExpressionList *others = NULL;
  56.736 -        if (match(TOK_DEFAULT)) {
  56.737 -            if (defaultCase) {
  56.738 -                cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch);
  56.739 -                return NULL;
  56.740 -            }
  56.741 -
  56.742 -            defaultPos = scanner_.begin();
  56.743 -        } else {
  56.744 -            if (defaultCase) {
  56.745 -                cc_.reportError(defaultPos, Message_DefaultMustBeLastCase);
  56.746 -                return NULL;
  56.747 -            }
  56.748 -
  56.749 -            if (!expect(TOK_CASE))
  56.750 -                return NULL;
  56.751 -
  56.752 -            // A limitation in the grammar is that |case <NAME>:| will be
  56.753 -            // detected as a label.
  56.754 -            AutoAllowTags<false> disableTags(scanner_);
  56.755 -
  56.756 -            if ((expr = expression()) == NULL)
  56.757 -                return NULL;
  56.758 -
  56.759 -            if (peek(TOK_COMMA)) {
  56.760 -                others = new (pool_) ExpressionList();
  56.761 -                while (match(TOK_COMMA)) {
  56.762 -                    Expression *other = expression();
  56.763 -                    if (!other)
  56.764 -                        return NULL;
  56.765 -                    if (!others->append(other))
  56.766 -                        return NULL;
  56.767 -                }
  56.768 -            }
  56.769 -        }
  56.770 -
  56.771 -        if (!expect(TOK_COLON))
  56.772 -            return NULL;
  56.773 -
  56.774 -        Statement *statement = localStatement();
  56.775 -        if (!statement)
  56.776 -            return NULL;
  56.777 -
  56.778 -        if (!peek(TOK_CASE) &&
  56.779 -            !peek(TOK_DEFAULT) &&
  56.780 -            !peek(TOK_RBRACE))
  56.781 -        {
  56.782 -            cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase);
  56.783 -            return NULL;
  56.784 -        }
  56.785 -
  56.786 -        if (expr) {
  56.787 -            Case *caze = new (pool_) Case(expr, others, statement);
  56.788 -            if (!cases->append(caze))
  56.789 -                return NULL;
  56.790 -        } else {
  56.791 -            defaultCase = statement;
  56.792 -        }
  56.793 -    }
  56.794 -
  56.795 -    if (!expect(TOK_RBRACE))
  56.796 -        return NULL;
  56.797 -
  56.798 -    return new (pool_) SwitchStatement(pos, expr, cases, defaultCase);
  56.799 -}
  56.800 -
  56.801 -Statement *
  56.802 -Parser::forStatement()
  56.803 -{
  56.804 -    // for ::= "for" "(" forinit? ";" forcond? ";" forstep ")" statement
  56.805 -    // forint ::= "new" vardecl |
  56.806 -    //            exprstmt
  56.807 -    // forcond ::= expr
  56.808 -    // forstep ::= exprstmt
  56.809 -    //
  56.810 -    SourcePosition pos = scanner_.begin();
  56.811 -    scanner_.scan();
  56.812 -    if (!expect(TOK_LPAREN))
  56.813 -        return NULL;
  56.814 -
  56.815 -    Statement *decl = NULL;
  56.816 -    if (!match(TOK_SEMICOLON)) {
  56.817 -        if (match(TOK_NEW)) {
  56.818 -            if ((decl = vars(TypeQual_None)) == NULL)
  56.819 -                return NULL;
  56.820 -        } else {
  56.821 -            if ((decl = expressionStatement()) == NULL)
  56.822 -                return NULL;
  56.823 -        }
  56.824 -        if (!expect(TOK_SEMICOLON))
  56.825 -            return NULL;
  56.826 -    }
  56.827 -
  56.828 -    Expression *condition = NULL;
  56.829 -    if (!match(TOK_SEMICOLON)) {
  56.830 -        if ((condition = expression()) == NULL)
  56.831 -            return NULL;
  56.832 -        if (!expect(TOK_SEMICOLON))
  56.833 -            return NULL;
  56.834 -    }
  56.835 -
  56.836 -    Statement *update = NULL;
  56.837 -    if (!match(TOK_RPAREN)) {
  56.838 -        if ((update = expressionStatement()) == NULL)
  56.839 -            return NULL;
  56.840 -        if (!expect(TOK_RPAREN))
  56.841 -            return NULL;
  56.842 -    }
  56.843 -
  56.844 -    Statement *body;
  56.845 -    if (scanner_.peek() == TOK_LBRACE)
  56.846 -        body = block();
  56.847 -    else
  56.848 -        body = localStatement();
  56.849 -    if (!body)
  56.850 -        return NULL;
  56.851 -
  56.852 -    return new (pool_) ForStatement(pos, decl, condition, update, body);
  56.853 -}
  56.854 -
  56.855 -ExpressionList *
  56.856 -Parser::dimensions()
  56.857 -{
  56.858 -    // dimensions ::= ("[" expr? "]")*
  56.859 -
  56.860 -    ExpressionList *postDimensions = new (pool_) ExpressionList();
  56.861 -    while (match(TOK_LBRACKET)) {
  56.862 -        Expression *dim = NULL;
  56.863 -        if (!match(TOK_RBRACKET)) {
  56.864 -            if ((dim = expression()) == NULL)
  56.865 -                return NULL;
  56.866 -            if (!expect(TOK_RBRACKET))
  56.867 -                return NULL;
  56.868 -        }
  56.869 -
  56.870 -        if (!postDimensions->append(dim))
  56.871 -            return NULL;
  56.872 -    }
  56.873 -    return postDimensions;
  56.874 -}
  56.875 -
  56.876 -VariableDeclaration *
  56.877 -Parser::var(TypeQualifiers qual)
  56.878 -{
  56.879 -    // vardecl ::= decl ("=" expr)?
  56.880 -
  56.881 -    Expression *type;
  56.882 -    Local<String> name(zone_);
  56.883 -
  56.884 -    if (!typeAndName(&type, name.ref()))
  56.885 -        return NULL;
  56.886 -
  56.887 -    ExpressionList *dims = NULL;
  56.888 -    if (peek(TOK_LBRACKET)) {
  56.889 -        if ((dims = dimensions()) == NULL)
  56.890 -            return NULL;;
  56.891 -    }
  56.892 -
  56.893 -    SourcePosition pos = scanner_.begin();
  56.894 -    
  56.895 -    Expression *expr = NULL;
  56.896 -    if (match(TOK_ASSIGN)) {
  56.897 -        switch (scanner_.peek()) {
  56.898 -          // Note: we don't support [] literals yet.
  56.899 -          case TOK_LBRACE:
  56.900 -            scanner_.scan();
  56.901 -            if ((expr = fixedArrayLiteral()) == NULL)
  56.902 -                return NULL;
  56.903 -            break;
  56.904 -
  56.905 -          default:
  56.906 -            if ((expr = expression()) == NULL)
  56.907 -                return NULL;
  56.908 -            break;
  56.909 -        }
  56.910 -    }
  56.911 -
  56.912 -    return new (pool_) VariableDeclaration(pos, qual, name, type, dims, expr);
  56.913 -}
  56.914 -
  56.915 -Statement *
  56.916 -Parser::vars(TypeQualifiers qual)
  56.917 -{
  56.918 -    // localvars ::= ("new" | "const" | "decl") vardecl ("," vardecl)*
  56.919 -    // globalvars ::= ("public" | "const" | "new" | "public" "const") vardecl
  56.920 -    VariableDeclaration *decl = var(qual);
  56.921 -    if (!decl)
  56.922 -        return NULL;
  56.923 -
  56.924 -    if (!peek(TOK_COMMA))
  56.925 -        return decl;
  56.926 -
  56.927 -    StatementList *statements = new (pool_) StatementList();
  56.928 -    if (!statements->append(decl))
  56.929 -        return NULL;
  56.930 -
  56.931 -    while (match(TOK_COMMA)) {
  56.932 -        Statement *decl = var(qual);
  56.933 -        if (!decl)
  56.934 -            return NULL;
  56.935 -        if (!statements->append(decl))
  56.936 -            return NULL;
  56.937 -    }
  56.938 -
  56.939 -    // Create a fake-o block with no scope to create a statement list.
  56.940 -    return new (pool_) BlockStatement(decl->pos(), statements, TOK_NEW);
  56.941 -}
  56.942 -
  56.943 -Statement *
  56.944 -Parser::returnStatement()
  56.945 -{
  56.946 -    // return ::= "return" term |
  56.947 -    //            "return" "expr"
  56.948 -
  56.949 -    SourcePosition pos = scanner_.begin();
  56.950 -    if (!expect(TOK_RETURN))
  56.951 -        return NULL;
  56.952 -
  56.953 -    Expression *expr = NULL;
  56.954 -    if (scanner_.peek() != TOK_SEMICOLON) {
  56.955 -        if ((expr = expression()) == NULL)
  56.956 -            return NULL;
  56.957 -
  56.958 -        // We only care about non-void returns when determining whether a
  56.959 -        // tagless function is non-void.
  56.960 -        encounteredReturn_ = true;
  56.961 -    }
  56.962 -
  56.963 -    return new (pool_) ReturnStatement(pos, expr);
  56.964 -}
  56.965 -
  56.966 -Statement *
  56.967 -Parser::expressionStatement()
  56.968 -{
  56.969 -    // exprstmt ::= expr
  56.970 -    Expression *left = assignment();
  56.971 -    if (!left)
  56.972 -        return NULL;
  56.973 -
  56.974 -    return new (pool_) ExpressionStatement(left);
  56.975 -}
  56.976 -
  56.977 -Statement *
  56.978 -Parser::block()
  56.979 -{
  56.980 -    // block ::= "{" statement* "}"
  56.981 -
  56.982 -    if (!expect(TOK_LBRACE))
  56.983 -        return NULL;
  56.984 -
  56.985 -    SourcePosition pos = scanner_.begin();
  56.986 -
  56.987 -    StatementList *statements = new (pool_) StatementList();
  56.988 -    while (!match(TOK_RBRACE)) {
  56.989 -        Statement *statement = localStatement();
  56.990 -        if (statement == NULL)
  56.991 -            return NULL;
  56.992 -        if (!statements->append(statement))
  56.993 -            return NULL;
  56.994 -    }
  56.995 -
  56.996 -    BlockStatement *block = new (pool_) BlockStatement(pos, statements, TOK_LBRACE);
  56.997 -    return block;
  56.998 -}
  56.999 -
 56.1000 -Statement *
 56.1001 -Parser::if_()
 56.1002 -{
 56.1003 -    // if ::= "if" "(" expr ")" statement elseif* else?
 56.1004 -    // elseif ::= "elseif" "(" expr ")" statement
 56.1005 -    // else ::= "else" statement
 56.1006 -    expect(TOK_IF);
 56.1007 -  
 56.1008 -    SourcePosition pos = scanner_.begin();
 56.1009 -    if (!expect(TOK_LPAREN))
 56.1010 -        return NULL;
 56.1011 -
 56.1012 -    Expression *cond = expression();
 56.1013 -    if (!cond)
 56.1014 -        return NULL;
 56.1015 -
 56.1016 -    if (!expect(TOK_RPAREN))
 56.1017 -        return NULL;
 56.1018 -
 56.1019 -    Statement *ifTrue = localStatement();
 56.1020 -    if (!ifTrue)
 56.1021 -        return NULL;
 56.1022 -
 56.1023 -    IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue);
 56.1024 -
 56.1025 -    IfStatement *last = outer;
 56.1026 -    while (match(TOK_ELSE)) {
 56.1027 -        if (!match(TOK_IF)) {
 56.1028 -            Statement *ifFalse = localStatement();
 56.1029 -            if (!ifFalse)
 56.1030 -                return NULL;
 56.1031 -
 56.1032 -            last->setIfFalse(ifFalse);
 56.1033 -            break;
 56.1034 -        }
 56.1035 -
 56.1036 -        SourcePosition pos = scanner_.begin();
 56.1037 -        if (!expect(TOK_LPAREN))
 56.1038 -            return NULL;
 56.1039 -
 56.1040 -        Expression *otherCond = expression();
 56.1041 -        if (!otherCond)
 56.1042 -            return NULL;
 56.1043 -
 56.1044 -        if (!expect(TOK_RPAREN))
 56.1045 -            return NULL;
 56.1046 -
 56.1047 -        Statement *otherIfTrue = localStatement();
 56.1048 -        if (!otherIfTrue)
 56.1049 -            return NULL;
 56.1050 -
 56.1051 -        IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue);
 56.1052 -        last->setIfFalse(inner);
 56.1053 -        last = inner;
 56.1054 -    }
 56.1055 -
 56.1056 -    return outer;
 56.1057 -}
 56.1058 -
 56.1059 -Statement *
 56.1060 -Parser::localStatement()
 56.1061 -{
 56.1062 -    // statement ::= stmt term
 56.1063 -    // stmt ::= do | for | if | while | struct | enum |
 56.1064 -    //          localvars | return | switch | break | continue
 56.1065 -
 56.1066 -    Statement *statement = NULL;
 56.1067 -
 56.1068 -    // Statements which must be followed by a semicolon will break out of the
 56.1069 -    // switch. If they may end in BlockStatements, they'll immediately return.
 56.1070 -
 56.1071 -    TokenKind kind = scanner_.peek();
 56.1072 -    switch (kind) {
 56.1073 -      case TOK_CONST:
 56.1074 -      case TOK_NEW:
 56.1075 -      {
 56.1076 -        TypeQualifiers quals = (kind == TOK_CONST)
 56.1077 -                              ? TypeQual_Const
 56.1078 -                              : TypeQual_None;
 56.1079 -        scanner_.scan();
 56.1080 -        if ((statement = vars(quals)) == NULL)
 56.1081 -          return NULL;
 56.1082 -        break;
 56.1083 -      }
 56.1084 -
 56.1085 -      case TOK_FOR:
 56.1086 -        return forStatement();
 56.1087 -
 56.1088 -      case TOK_WHILE:
 56.1089 -        return while_();
 56.1090 -
 56.1091 -      case TOK_BREAK:
 56.1092 -        scanner_.scan();
 56.1093 -        statement = new (pool_) BreakStatement(scanner_.begin());
 56.1094 -        break;
 56.1095 -
 56.1096 -      case TOK_CONTINUE:
 56.1097 -        scanner_.scan();
 56.1098 -        statement = new (pool_) ContinueStatement(scanner_.begin());
 56.1099 -        break;
 56.1100 -
 56.1101 -      case TOK_DO:
 56.1102 -        if ((statement = do_()) == NULL)
 56.1103 -            return NULL;
 56.1104 -        break;
 56.1105 -
 56.1106 -      case TOK_RETURN:
 56.1107 -        if ((statement = returnStatement()) == NULL)
 56.1108 -          return NULL;
 56.1109 -        break;
 56.1110 -
 56.1111 -      case TOK_ENUM:
 56.1112 -        if ((statement = enum_(TOK_NONE)) == NULL)
 56.1113 -          return NULL;
 56.1114 -        break;
 56.1115 -
 56.1116 -      case TOK_STRUCT:
 56.1117 -        if ((statement = struct_()) == NULL)
 56.1118 -          return NULL;
 56.1119 -        break;
 56.1120 -
 56.1121 -      case TOK_SWITCH:
 56.1122 -        return switch_();
 56.1123 -
 56.1124 -      case TOK_IF:
 56.1125 -        return if_();
 56.1126 -
 56.1127 -      case TOK_LBRACE:
 56.1128 -        return block();
 56.1129 -
 56.1130 -      default:
 56.1131 -        break;
 56.1132 -    }
 56.1133 -
 56.1134 -    if (!statement) {
 56.1135 -        if ((statement = expressionStatement()) == NULL)
 56.1136 -            return NULL;
 56.1137 -    }
 56.1138 -
 56.1139 -    if (!expect(TOK_SEMICOLON))
 56.1140 -        return NULL;
 56.1141 -
 56.1142 -    return statement;
 56.1143 -}
 56.1144 -
 56.1145 -Statement *
 56.1146 -Parser::struct_()
 56.1147 -{
 56.1148 -    // struct ::= "struct" name { struct_fields }
 56.1149 -    // struct_fields ::= struct_field |
 56.1150 -    //                   struct_field struct_fields
 56.1151 -    // struct_field ::= label? name term
 56.1152 -    expect(TOK_STRUCT);
 56.1153 -
 56.1154 -    Local<String> name(zone_, expectName());
 56.1155 -    if (!name)
 56.1156 -        return NULL;
 56.1157 -
 56.1158 -    SourcePosition pos = scanner_.begin();
 56.1159 -
 56.1160 -    if (!expect(TOK_LBRACE))
 56.1161 -        return NULL;
 56.1162 -
 56.1163 -    FieldList *fields = new (pool_) FieldList();
 56.1164 -
 56.1165 -    while (!peek(TOK_RBRACE)) {
 56.1166 -        Expression *type;
 56.1167 -        Local<String> fieldName(zone_);
 56.1168 -
 56.1169 -        if (!fullTypeAndName(&type, fieldName.ref(), DeclField))
 56.1170 -            return NULL;
 56.1171 -
 56.1172 -        SourcePosition pos = scanner_.begin();
 56.1173 -
 56.1174 -        if (!matchSemicolon())
 56.1175 -            return NULL;
 56.1176 -
 56.1177 -        StructureStatement::Field *field =
 56.1178 -            new (pool_) StructureStatement::Field(pos, type, fieldName);
 56.1179 -        if (!field || !fields->append(field))
 56.1180 -            return NULL;
 56.1181 -    }
 56.1182 -
 56.1183 -    if (!expect(TOK_RBRACE))
 56.1184 -        return NULL;
 56.1185 -
 56.1186 -    if (fields->empty()) {
 56.1187 -        cc_.reportError(pos, Message_StructCantBeEmpty);
 56.1188 -        return NULL;
 56.1189 -    }
 56.1190 -
 56.1191 -    return new (pool_) StructureStatement(pos, name, fields);
 56.1192 -}
 56.1193 -
 56.1194 -Statement *
 56.1195 -Parser::enum_(TokenKind kind)
 56.1196 -{
 56.1197 -    // enum ::= "enum" name? { enum_members? }
 56.1198 -    // enum_members ::= enum_member ","? |
 56.1199 -    //                  enum_member "," enum_members
 56.1200 -    // enum_member ::= ident ("=" constexpr)?
 56.1201 -    expect(TOK_ENUM);
 56.1202 -
 56.1203 -    SourcePosition pos = scanner_.begin();
 56.1204 -
 56.1205 -    Local<String> name(zone_);
 56.1206 -    if (matchName(name.ref()) && !name)
 56.1207 -        return NULL;
 56.1208 -
 56.1209 -    EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList();
 56.1210 -
 56.1211 -    if (!expect(TOK_LBRACE))
 56.1212 -        return NULL;
 56.1213 -
 56.1214 -    do {
 56.1215 -        if (scanner_.peek() == TOK_RBRACE)
 56.1216 -            break;
 56.1217 -
 56.1218 -        SourcePosition pos = scanner_.begin();
 56.1219 -        Local<String> name(zone_, expectName());
 56.1220 -        if (!name)
 56.1221 -            return NULL;
 56.1222 -
 56.1223 -        Expression *expr = NULL;
 56.1224 -        if (match(TOK_ASSIGN)) {
 56.1225 -            if ((expr = expression()) == NULL)
 56.1226 -                return NULL;
 56.1227 -        }
 56.1228 -
 56.1229 -        if (!entries->append(EnumStatement::Entry(name, expr, pos)))
 56.1230 -            return NULL;
 56.1231 -    } while (match(TOK_COMMA));
 56.1232 -    if (!expect(TOK_RBRACE))
 56.1233 -        return NULL;
 56.1234 -
 56.1235 -    return new (pool_) EnumStatement(pos, kind, name, entries);
 56.1236 -}
 56.1237 -
 56.1238 -template <class T>
 56.1239 -static inline ScopedRoot<T> *
 56.1240 -NewScopedRoot(PoolAllocator &pool, Handle<T> obj)
 56.1241 -{
 56.1242 -    return new (pool) ScopedRoot<T>(obj);
 56.1243 -}
 56.1244 -
 56.1245 -ImportStatement *
 56.1246 -Parser::import(TokenKind kind)
 56.1247 -{
 56.1248 -    SourcePosition pos = scanner_.begin();
 56.1249 -
 56.1250 -    // import       ::= "from" import_path "import" import_names
 56.1251 -    //                | "import" import_path
 56.1252 -    //                | "import" import_path ".*"
 56.1253 -    // import_path  ::= name
 56.1254 -    //                | name "." import_path
 56.1255 -    // import_names ::= "*"
 56.1256 -    //                | import_name_list
 56.1257 -    // import_name_list ::= name
 56.1258 -    //                    | name "," import_name_list
 56.1259 -
 56.1260 -    Local<String> name(zone_, expectName());
 56.1261 -    if (!name)
 56.1262 -        return NULL;
 56.1263 -
 56.1264 -    PathComponent *root = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
 56.1265 -    PathComponent *current = root;
 56.1266 -
 56.1267 -    // NULL namelist means that we do not import any names. An empty namelist
 56.1268 -    // means we import all names.
 56.1269 -    NameList *names = NULL;
 56.1270 -
 56.1271 -    while (match(TOK_DOT)) {
 56.1272 -        if (kind == TOK_IMPORT && match(TOK_STAR)) {
 56.1273 -            names = new (pool_) NameList();
 56.1274 -            break;
 56.1275 -        }
 56.1276 -
 56.1277 -        if ((name = expectName()) == NULL)
 56.1278 -            return NULL;
 56.1279 -
 56.1280 -        current->next = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
 56.1281 -        current = current->next;
 56.1282 -    }
 56.1283 -
 56.1284 -    if (kind == TOK_FROM) {
 56.1285 -        if (!expect(TOK_IMPORT))
 56.1286 -            return NULL;
 56.1287 -
 56.1288 -        names = new (pool_) NameList();
 56.1289 -
 56.1290 -        if (!match(TOK_STAR)) {
 56.1291 -            if (!matchName(name.address())) {
 56.1292 -                cc_.reportError(scanner_.begin(), Message_BadImportFrom);
 56.1293 -                return NULL;
 56.1294 -            }
 56.1295 -
 56.1296 -            if (!name || !names->append(NewScopedRoot<String>(pool_, name)))
 56.1297 -                return NULL;
 56.1298 -
 56.1299 -            while (match(TOK_COMMA)) {
 56.1300 -                if ((name = expectName()) == NULL)
 56.1301 -                    return NULL;
 56.1302 -                if (!names->append(NewScopedRoot<String>(pool_, name)))
 56.1303 -                    return NULL;
 56.1304 -            }
 56.1305 -        }
 56.1306 -    }
 56.1307 -
 56.1308 -    return new (pool_) ImportStatement(pos, root, names);
 56.1309 -}
 56.1310 -
 56.1311 -Statement *
 56.1312 -Parser::function(TokenKind token)
 56.1313 -{
 56.1314 -    Expression *returnType;
 56.1315 -    Local<String> name(zone_);
 56.1316 -
 56.1317 -    if (!fullTypeAndName(&returnType, name.ref(), DeclFun))
 56.1318 -        return NULL;
 56.1319 -
 56.1320 -    SourcePosition pos = scanner_.begin();
 56.1321 -    ParameterList *parameters = new (pool_) ParameterList();
 56.1322 -
 56.1323 -    if (!expect(TOK_LPAREN))
 56.1324 -        return NULL;
 56.1325 -
 56.1326 -    bool variadic = false;
 56.1327 -
 56.1328 -    if (!match(TOK_RPAREN)) {
 56.1329 -        while (true) {
 56.1330 -            TypeQualifiers quals = TypeQual_None;
 56.1331 -            if (match(TOK_CONST))
 56.1332 -                quals = TypeQualifiers(quals | TypeQual_Const);
 56.1333 -
 56.1334 -            bool ref = match(TOK_AMPERSAND);
 56.1335 -
 56.1336 -            SourcePosition begin = scanner_.begin();
 56.1337 -            Expression *type;
 56.1338 -            Local<String> name(zone_);
 56.1339 -            if (!fullTypeAndName(&type, name.ref(), DeclArg))
 56.1340 -                return NULL;
 56.1341 -
 56.1342 -            if (!name) {
 56.1343 -                if ((quals & TypeQual_Const) || ref) {
 56.1344 -                    cc_.reportError(begin, Message_InvalidVarArgs);
 56.1345 -                    return NULL;
 56.1346 -                }
 56.1347 -
 56.1348 -                if (token != TOK_NATIVE) {
 56.1349 -                    cc_.reportError(begin, Message_VarArgsOutsideNative);
 56.1350 -                    return NULL;
 56.1351 -                }
 56.1352 -
 56.1353 -                variadic = true;
 56.1354 -                break;
 56.1355 -            }
 56.1356 -
 56.1357 -            ExpressionList *dims = NULL;
 56.1358 -            if (peek(TOK_LBRACKET)) {
 56.1359 -                if ((dims = dimensions()) == NULL)
 56.1360 -                    return NULL;
 56.1361 -            }
 56.1362 -
 56.1363 -            Expression *expr = NULL;
 56.1364 -            if (match(TOK_ASSIGN)) {
 56.1365 -                if ((expr = expression()) == NULL)
 56.1366 -                    return NULL;
 56.1367 -            }
 56.1368 -
 56.1369 -            Parameter *parameter = new (pool_) Parameter(name, type, ref, quals, dims, expr, begin);
 56.1370 -            if (!parameters->append(parameter))
 56.1371 -                return NULL;
 56.1372 -
 56.1373 -            if (!match(TOK_COMMA))
 56.1374 -                break;
 56.1375 -        }
 56.1376 -        if (!expect(TOK_RPAREN))
 56.1377 -            return NULL;
 56.1378 -    }
 56.1379 -
 56.1380 -    encounteredReturn_ = false;
 56.1381 -
 56.1382 -    Statement *body = NULL;
 56.1383 -    if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) {
 56.1384 -        body = block();
 56.1385 -        if (!body)
 56.1386 -            return NULL;
 56.1387 -    }
 56.1388 -
 56.1389 -    FunctionSignature signature(returnType, parameters, variadic);
 56.1390 -    if (token == TOK_TYPEDEF)
 56.1391 -        return new (pool_) FunctionTypeStatement(pos, name, signature);
 56.1392 -
 56.1393 -    return new (pool_) FunctionStatement(pos, name, token, body, signature, encounteredReturn_);
 56.1394 -}
 56.1395 -
 56.1396 -static inline bool
 56.1397 -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle<Type> type)
 56.1398 -{
 56.1399 -    Local<String> tag(zone, zone->makeSymbol(name));
 56.1400 -    if (!tag)
 56.1401 -        return false;
 56.1402 -
 56.1403 -    assert(false);
 56.1404 -    return false; //return !!scope->declareType(tag, type);
 56.1405 -}
 56.1406 -
 56.1407 -static inline bool
 56.1408 -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type)
 56.1409 -{
 56.1410 -    Local<Type> primitive(zone, zone->types()->getPrimitive(type));
 56.1411 -    assert(primitive);
 56.1412 -    return DeclareIntrinsicType(zone, scope, name, primitive);
 56.1413 -}
 56.1414 -
 56.1415 -ParseTree *
 56.1416 -Parser::parse()
 56.1417 -{
 56.1418 -    StatementList *statements = new (pool_) StatementList();
 56.1419 -
 56.1420 -    for (;;) {
 56.1421 -        Statement *statement = NULL;
 56.1422 -
 56.1423 -        TokenKind kind = scanner_.peek();
 56.1424 -        switch (kind) {
 56.1425 -          case TOK_ERROR:
 56.1426 -            return NULL;
 56.1427 -
 56.1428 -          case TOK_EOF:
 56.1429 -            break;
 56.1430 -
 56.1431 -          case TOK_NAME:
 56.1432 -            if ((statement = function(TOK_NAME)) == NULL)
 56.1433 -                return NULL;
 56.1434 -            break;
 56.1435 -
 56.1436 -          case TOK_FROM:
 56.1437 -          case TOK_IMPORT:
 56.1438 -          {
 56.1439 -            scanner_.scan();
 56.1440 -            if (statements->length())
 56.1441 -                cc_.reportError(scanner_.begin(), Message_ImportsMustBeFirst);
 56.1442 -            ImportStatement *stmt = import(kind);
 56.1443 -            if (!stmt)
 56.1444 -                return NULL;
 56.1445 -            if (!imports_->append(stmt))
 56.1446 -                return NULL;
 56.1447 -            if (!matchSemicolon())
 56.1448 -                return NULL;
 56.1449 -            continue;
 56.1450 -          }
 56.1451 -
 56.1452 -          case TOK_FORWARD:
 56.1453 -          case TOK_PUBLIC:
 56.1454 -          case TOK_NATIVE:
 56.1455 -          case TOK_STOCK:
 56.1456 -          case TOK_LABEL:
 56.1457 -          case TOK_TYPEDEF:
 56.1458 -          {
 56.1459 -            if (kind != TOK_LABEL)
 56.1460 -                scanner_.scan();
 56.1461 -            if (kind == TOK_PUBLIC && peek(TOK_CONST)) {
 56.1462 -                if ((statement = var(TypeQual_Const)) == NULL)
 56.1463 -                    return NULL;
 56.1464 -                if (!matchSemicolon())
 56.1465 -                    return NULL;
 56.1466 -            } else if (kind == TOK_PUBLIC && peek(TOK_ENUM)) {
 56.1467 -                if ((statement = enum_(kind)) == NULL)
 56.1468 -                    return NULL;
 56.1469 -                if (!matchSemicolon())
 56.1470 -                    return NULL;
 56.1471 -            } else {
 56.1472 -                if ((statement = function(kind)) == NULL)
 56.1473 -                    return NULL;
 56.1474 -                if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon())
 56.1475 -                    return NULL;
 56.1476 -            }
 56.1477 -            break;
 56.1478 -          }
 56.1479 -
 56.1480 -          case TOK_CONST:
 56.1481 -          case TOK_NEW:
 56.1482 -          {
 56.1483 -            TypeQualifiers quals = (kind == TOK_CONST) ? TypeQual_Const : TypeQual_None;
 56.1484 -            // Note: at global scope, we don't accept comma-delimited
 56.1485 -            // declarations yet, to see if we can get away with forcing
 56.1486 -            // a nicer top-level style.
 56.1487 -            scanner_.scan();
 56.1488 -            if ((statement = var(quals)) == NULL)
 56.1489 -                return NULL;
 56.1490 -            if (!matchSemicolon())
 56.1491 -                return NULL;
 56.1492 -            break;
 56.1493 -          }
 56.1494 -
 56.1495 -          case TOK_ENUM:
 56.1496 -            if ((statement = enum_(TOK_NONE)) == NULL)
 56.1497 -                return NULL;
 56.1498 -            if (!matchSemicolon())
 56.1499 -                return NULL;
 56.1500 -            break;
 56.1501 -
 56.1502 -          case TOK_STRUCT:
 56.1503 -            if ((statement = struct_()) == NULL)
 56.1504 -                return NULL;
 56.1505 -            if (!matchSemicolon())
 56.1506 -                return NULL;
 56.1507 -            break;
 56.1508 -
 56.1509 -          default:
 56.1510 -            cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
 56.1511 -            return NULL;
 56.1512 -        }
 56.1513 -
 56.1514 -        if (!statement)
 56.1515 -            break;
 56.1516 -
 56.1517 -        if (!statements->append(statement))
 56.1518 -            return NULL;
 56.1519 -    }
 56.1520 -
 56.1521 -    return new (pool_) ParseTree(statements, unbound_, imports_);
 56.1522 -}
 56.1523 -
 56.1524 -class AstPrinter : public AstVisitor
 56.1525 -{
 56.1526 -    FILE *fp_;
 56.1527 -    size_t level_;
 56.1528 -
 56.1529 -  private:
 56.1530 -    void prefix() {
 56.1531 -        for (size_t i = 0; i < level_; i++)
 56.1532 -            fprintf(fp_, "  ");
 56.1533 -    }
 56.1534 -    void indent() {
 56.1535 -        level_++;
 56.1536 -    }
 56.1537 -    void unindent() {
 56.1538 -        level_--;
 56.1539 -    }
 56.1540 -
 56.1541 -  public:
 56.1542 -    AstPrinter(FILE *fp)
 56.1543 -      : fp_(fp),
 56.1544 -        level_(0)
 56.1545 -    {
 56.1546 -    }
 56.1547 -
 56.1548 -    void dump(const FunctionSignature &sig) {
 56.1549 -        prefix();
 56.1550 -        fprintf(fp_, "()\n");
 56.1551 -    }
 56.1552 -    void visitNameProxy(NameProxy *name) {
 56.1553 -        prefix();
 56.1554 -        fprintf(fp_, "[ NameProxy (%s)\n", name->name()->chars());
 56.1555 -    }
 56.1556 -    void visitCallExpression(CallExpression *node) {
 56.1557 -        prefix();
 56.1558 -        fprintf(fp_, "[ CallExpression\n");
 56.1559 -        indent();
 56.1560 -        node->callee()->accept(this);
 56.1561 -        for (size_t i = 0; i < node->arguments()->length(); i++)
 56.1562 -            node->arguments()->at(i)->accept(this);
 56.1563 -        unindent();
 56.1564 -    }
 56.1565 -    void visitFunctionTypeStatement(FunctionTypeStatement *node) {
 56.1566 -        prefix();
 56.1567 -        fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->name()->chars());
 56.1568 -        indent();
 56.1569 -        dump(node->signature());
 56.1570 -        unindent();
 56.1571 -    }
 56.1572 -    void visitFunctionStatement(FunctionStatement *node) {
 56.1573 -        prefix();
 56.1574 -        fprintf(fp_, "[ FunctionStatement (%s)\n", node->name()->chars());
 56.1575 -        indent();
 56.1576 -        dump(node->signature());
 56.1577 -        if (node->body())
 56.1578 -            node->body()->accept(this);
 56.1579 -        unindent();
 56.1580 -    }
 56.1581 -    void visitExpressionStatement(ExpressionStatement *node) {
 56.1582 -        prefix();
 56.1583 -        fprintf(fp_, "[ ExpressionStatement\n");
 56.1584 -        indent();
 56.1585 -        node->expression()->accept(this);
 56.1586 -        unindent();
 56.1587 -    }
 56.1588 -    void visitAssignment(Assignment *node) {
 56.1589 -        prefix();
 56.1590 -        fprintf(fp_, "[ Assignment\n");
 56.1591 -        indent();
 56.1592 -        node->lvalue()->accept(this);
 56.1593 -        node->expression()->accept(this);
 56.1594 -        unindent();
 56.1595 -    }
 56.1596 -    void visitTernaryExpression(TernaryExpression *node) {
 56.1597 -        prefix();
 56.1598 -        fprintf(fp_, "[ TernaryExpression\n");
 56.1599 -        indent();
 56.1600 -        node->condition()->accept(this);
 56.1601 -        node->left()->accept(this);
 56.1602 -        node->right()->accept(this);
 56.1603 -        unindent();
 56.1604 -    }
 56.1605 -    void visitBinaryExpression(BinaryExpression *node) {
 56.1606 -        prefix();
 56.1607 -        fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]);
 56.1608 -        indent();
 56.1609 -        node->left()->accept(this);
 56.1610 -        node->right()->accept(this);
 56.1611 -        unindent();
 56.1612 -    }
 56.1613 -    void visitUnaryExpression(UnaryExpression *node) {
 56.1614 -        prefix();
 56.1615 -        fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]);
 56.1616 -        indent();
 56.1617 -        node->expression()->accept(this);
 56.1618 -        unindent();
 56.1619 -    }
 56.1620 -    void visitReturnStatement(ReturnStatement *node) {
 56.1621 -        prefix();
 56.1622 -        fprintf(fp_, "[ ReturnStatement\n");
 56.1623 -        indent();
 56.1624 -        if (node->expression())
 56.1625 -            node->expression()->accept(this);
 56.1626 -        unindent();
 56.1627 -    }
 56.1628 -    void visitForStatement(ForStatement *node) {
 56.1629 -        prefix();
 56.1630 -        fprintf(fp_, "[ ForStatement\n");
 56.1631 -        indent();
 56.1632 -        if (node->initialization())
 56.1633 -            node->initialization()->accept(this);
 56.1634 -        if (node->condition())
 56.1635 -            node->condition()->accept(this);
 56.1636 -        if (node->update())
 56.1637 -            node->update()->accept(this);
 56.1638 -        node->body()->accept(this);
 56.1639 -        unindent();
 56.1640 -    }
 56.1641 -    void visitBlockStatement(BlockStatement *node) {
 56.1642 -        prefix();
 56.1643 -        fprintf(fp_, "[ BlockStatement\n");
 56.1644 -        indent();
 56.1645 -        for (size_t i = 0; i < node->statements()->length(); i++)
 56.1646 -            node->statements()->at(i)->accept(this);
 56.1647 -        unindent();
 56.1648 -    }
 56.1649 -    void visitVariableDeclaration(VariableDeclaration *node) {
 56.1650 -        prefix();
 56.1651 -        fprintf(fp_, "[ VariableDeclaration (%s)\n", node->name()->chars());
 56.1652 -        indent();
 56.1653 -        if (node->initialization())
 56.1654 -            node->initialization()->accept(this);
 56.1655 -        unindent();
 56.1656 -    }
 56.1657 -    void visitIntegerLiteral(IntegerLiteral *node) {
 56.1658 -        prefix();
 56.1659 -        fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
 56.1660 -    }
 56.1661 -    void visitBooleanLiteral(BooleanLiteral *node) {
 56.1662 -        prefix();
 56.1663 -        fprintf(fp_, "[ BooleanLiteral (%s)\n",
 56.1664 -                (node->token() == TOK_TRUE) ? "true" : "false");
 56.1665 -    }
 56.1666 -    void visitFloatLiteral(FloatLiteral *node) {
 56.1667 -        prefix();
 56.1668 -        fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
 56.1669 -    }
 56.1670 -    void visitIfStatement(IfStatement *node) {
 56.1671 -        prefix();
 56.1672 -        fprintf(fp_, "[ IfStatement\n");
 56.1673 -        indent();
 56.1674 -        node->ifTrue()->accept(this);
 56.1675 -        if (node->ifFalse())
 56.1676 -            node->ifFalse()->accept(this);
 56.1677 -        unindent();
 56.1678 -    }
 56.1679 -    void visitIndexExpression(IndexExpression *node) {
 56.1680 -        prefix();
 56.1681 -        fprintf(fp_, "[ IndexExpression\n");
 56.1682 -        indent();
 56.1683 -        node->left()->accept(this);
 56.1684 -        node->right()->accept(this);
 56.1685 -        unindent();
 56.1686 -    }
 56.1687 -    void visitEnumStatement(EnumStatement *node) {
 56.1688 -        prefix();
 56.1689 -        fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : "<anonymous>");
 56.1690 -        indent();
 56.1691 -        for (size_t i = 0; i < node->entries()->length(); i++) {
 56.1692 -            prefix();
 56.1693 -            fprintf(fp_, "%s =\n", node->entries()->at(i).name->chars());
 56.1694 -            if (node->entries()->at(i).expr) {
 56.1695 -                indent();
 56.1696 -                node->entries()->at(i).expr->accept(this);
 56.1697 -                unindent();
 56.1698 -            }
 56.1699 -        }
 56.1700 -        unindent();
 56.1701 -    }
 56.1702 -    void visitWhileStatement(WhileStatement *node) {
 56.1703 -        prefix();
 56.1704 -        fprintf(fp_, "[ WhileStatement (%s)\n",
 56.1705 -                (node->token() == TOK_DO) ? "do" : "while");
 56.1706 -        indent();
 56.1707 -        if (node->token() == TOK_DO) {
 56.1708 -            node->condition()->accept(this);
 56.1709 -            node->body()->accept(this);
 56.1710 -        } else {
 56.1711 -            node->condition()->accept(this);
 56.1712 -            node->body()->accept(this);
 56.1713 -        }
 56.1714 -        unindent();
 56.1715 -    }
 56.1716 -    void visitBreakStatement(BreakStatement *node) {
 56.1717 -        prefix();
 56.1718 -        fprintf(fp_, "[ BreakStatement\n");
 56.1719 -    }
 56.1720 -    void visitContinueStatement(ContinueStatement *node) {
 56.1721 -        prefix();
 56.1722 -        fprintf(fp_, "[ ContinueStatement\n");
 56.1723 -    }
 56.1724 -    void visitStringLiteral(StringLiteral *node) {
 56.1725 -        prefix();
 56.1726 -        fprintf(fp_, "[ StringLiteral\n");
 56.1727 -    }
 56.1728 -    void visitIncDecExpression(IncDecExpression *node) {
 56.1729 -        prefix();
 56.1730 -        fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
 56.1731 -        indent();
 56.1732 -        node->expression()->accept(this);
 56.1733 -        unindent();
 56.1734 -    }
 56.1735 -    void visitStructureStatement(StructureStatement *node) {
 56.1736 -        prefix();
 56.1737 -        fprintf(fp_, "[ StructureStatement %s\n", node->name()->chars());
 56.1738 -    }
 56.1739 -    void visitFieldExpression(FieldExpression *node) {
 56.1740 -        prefix();
 56.1741 -        fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars());
 56.1742 -        indent();
 56.1743 -        node->left()->accept(this);
 56.1744 -        unindent();
 56.1745 -    }
 56.1746 -    void visitSwitchStatement(SwitchStatement *node) {
 56.1747 -        prefix();
 56.1748 -        fprintf(fp_, "[ SwitchStatement\n");
 56.1749 -        indent();
 56.1750 -        node->expression()->accept(this);
 56.1751 -        for (size_t i = 0; i < node->cases()->length(); i++) {
 56.1752 -            Case *c = node->cases()->at(i);
 56.1753 -            c->expression()->accept(this);
 56.1754 -            if (c->others()) {
 56.1755 -                for (size_t j = 0; j < c->others()->length(); j++)
 56.1756 -                    c->others()->at(j)->accept(this);
 56.1757 -            }
 56.1758 -            indent();
 56.1759 -            c->statement()->accept(this);
 56.1760 -            unindent();
 56.1761 -        }
 56.1762 -        if (node->defaultCase())
 56.1763 -            node->defaultCase()->accept(this);
 56.1764 -        unindent();
 56.1765 -    }
 56.1766 -    void visitArrayLiteral(ArrayLiteral *node) {
 56.1767 -        prefix();
 56.1768 -        fprintf(fp_, "[ ArrayLiteral\n");
 56.1769 -        indent();
 56.1770 -        for (size_t i = 0; i < node->expressions()->length(); i++) {
 56.1771 -            Expression *expr = node->expressions()->at(i);
 56.1772 -            indent();
 56.1773 -            expr->accept(this);
 56.1774 -            unindent();
 56.1775 -        }
 56.1776 -    }
 56.1777 -    void visitImportStatement(ImportStatement *node) {
 56.1778 -        prefix();
 56.1779 -        fprintf(fp_, "[ ImportStatement\n");
 56.1780 -    }
 56.1781 -};
 56.1782 -
 56.1783 -void
 56.1784 -ParseTree::dump(FILE *fp)
 56.1785 -{
 56.1786 -    AstPrinter printer(fp);
 56.1787 -
 56.1788 -    for (size_t i = 0; i < statements_->length(); i++)
 56.1789 -        statements_->at(i)->accept(&printer);
 56.1790 -}
 56.1791 +/* vim: set ts=4 sw=4 tw=99 et:
 56.1792 + *
 56.1793 + * Copyright (C) 2012 David Anderson
 56.1794 + *
 56.1795 + * This file is part of SourcePawn.
 56.1796 + *
 56.1797 + * SourcePawn is free software: you can redistribute it and/or modify it under
 56.1798 + * the terms of the GNU General Public License as published by the Free
 56.1799 + * Software Foundation, either version 3 of the License, or (at your option)
 56.1800 + * any later version.
 56.1801 + * 
 56.1802 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
 56.1803 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 56.1804 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 56.1805 + *
 56.1806 + * You should have received a copy of the GNU General Public License along with
 56.1807 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
 56.1808 + */
 56.1809 +#include <string.h>
 56.1810 +#include "../Zone.h"
 56.1811 +#include "../FixedArray.h"
 56.1812 +#include "../Heap.h"
 56.1813 +#include "../Strings.h"
 56.1814 +#include "../TypeManager.h"
 56.1815 +#include "Parser.h"
 56.1816 +#include "../Heap-inl.h"
 56.1817 +
 56.1818 +using namespace ke;
 56.1819 +
 56.1820 +Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length)
 56.1821 +  : zone_(zone),
 56.1822 +    cc_(cc),
 56.1823 +    pool_(zone_->pool()),
 56.1824 +    scanner_(cc, stream, length),
 56.1825 +    unbound_(NULL)
 56.1826 +{
 56.1827 +    unbound_ = new (pool_) PoolList<NameProxy *>();
 56.1828 +    imports_ = new (pool_) PoolList<ImportStatement *>();
 56.1829 +}
 56.1830 +
 56.1831 +bool
 56.1832 +Parser::peek(TokenKind kind)
 56.1833 +{
 56.1834 +    return scanner_.peek() == kind;
 56.1835 +}
 56.1836 +
 56.1837 +bool
 56.1838 +Parser::match(TokenKind kind)
 56.1839 +{
 56.1840 +    if (!peek(kind))
 56.1841 +        return false;
 56.1842 +    scanner_.scan();
 56.1843 +    return true;
 56.1844 +}
 56.1845 +
 56.1846 +bool
 56.1847 +Parser::matchSemicolon()
 56.1848 +{
 56.1849 +    return expect(TOK_SEMICOLON);
 56.1850 +}
 56.1851 +
 56.1852 +bool
 56.1853 +Parser::expect(TokenKind kind)
 56.1854 +{
 56.1855 +    TokenKind got = scanner_.scan();
 56.1856 +    if (got == kind)
 56.1857 +        return true;
 56.1858 +    cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]);
 56.1859 +    return false;
 56.1860 +}
 56.1861 +
 56.1862 +bool
 56.1863 +Parser::matchName(String **name, TokenKind kind)
 56.1864 +{
 56.1865 +    assert(kind == TOK_NAME || kind == TOK_LABEL);
 56.1866 +    *name = NULL;
 56.1867 +    if (!match(kind))
 56.1868 +        return false;
 56.1869 +    *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
 56.1870 +    return true;
 56.1871 +}
 56.1872 +
 56.1873 +String *
 56.1874 +Parser::expectName()
 56.1875 +{
 56.1876 +    if (!expect(TOK_NAME))
 56.1877 +        return NULL;
 56.1878 +    return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
 56.1879 +}
 56.1880 +
 56.1881 +Expression *
 56.1882 +Parser::primitive()
 56.1883 +{
 56.1884 +    TokenKind kind = scanner_.peek();
 56.1885 +    switch (kind) {
 56.1886 +      case TOK_FLOAT_LITERAL:
 56.1887 +      {
 56.1888 +        scanner_.scan();
 56.1889 +        double value = Scanner::ParseDouble(scanner_.literal());
 56.1890 +        return new (pool_) FloatLiteral(scanner_.begin(), value);
 56.1891 +      }
 56.1892 +
 56.1893 +      case TOK_HEX_LITERAL:
 56.1894 +      {
 56.1895 +        scanner_.scan();
 56.1896 +        int value = strtol(scanner_.literal(), NULL, 16);
 56.1897 +        return new (pool_) IntegerLiteral(scanner_.begin(), value);
 56.1898 +      }
 56.1899 +
 56.1900 +      case TOK_INTEGER_LITERAL:
 56.1901 +      {
 56.1902 +        scanner_.scan();
 56.1903 +        int value = atoi(scanner_.literal());
 56.1904 +        return new (pool_) IntegerLiteral(scanner_.begin(), value);
 56.1905 +      }
 56.1906 +
 56.1907 +      case TOK_TRUE:
 56.1908 +      case TOK_FALSE:
 56.1909 +        scanner_.scan();
 56.1910 +        return new (pool_) BooleanLiteral(scanner_.begin(), kind);
 56.1911 +
 56.1912 +      case TOK_STRING_LITERAL:
 56.1913 +      {
 56.1914 +        scanner_.scan();
 56.1915 +        Local<String> string(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
 56.1916 +        return new (pool_) StringLiteral(scanner_.begin(), string);
 56.1917 +      }
 56.1918 +
 56.1919 +      default:
 56.1920 +      {
 56.1921 +        if (kind != TOK_ERROR)
 56.1922 +            cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]);
 56.1923 +        return NULL;
 56.1924 +      }
 56.1925 +    }
 56.1926 +}
 56.1927 +
 56.1928 +Expression *
 56.1929 +Parser::fixedArrayLiteral()
 56.1930 +{
 56.1931 +    SourcePosition pos = scanner_.begin();
 56.1932 +
 56.1933 +    ExpressionList *list = new (pool_) ExpressionList();
 56.1934 +    do {
 56.1935 +        // { } is an illegal array literal.
 56.1936 +        if (list->length() > 0 && match(TOK_LBRACE))
 56.1937 +            break;
 56.1938 +
 56.1939 +        Expression *expr = NULL;
 56.1940 +        if (peek(TOK_LBRACE))
 56.1941 +            expr = fixedArrayLiteral();
 56.1942 +        else
 56.1943 +            expr = primitive();
 56.1944 +        if (!expr)
 56.1945 +            return NULL;
 56.1946 +
 56.1947 +        if (!list->append(expr))
 56.1948 +            return NULL;
 56.1949 +
 56.1950 +        if (!match(TOK_COMMA)) {
 56.1951 +            if (!expect(TOK_RBRACE))
 56.1952 +                return NULL;
 56.1953 +            break;
 56.1954 +        }
 56.1955 +    } while (true);
 56.1956 +
 56.1957 +    return new (pool_) ArrayLiteral(pos, TOK_LBRACE, list);
 56.1958 +}
 56.1959 +
 56.1960 +Expression *
 56.1961 +Parser::prefix()
 56.1962 +{
 56.1963 +    switch (scanner_.peek()) {
 56.1964 +      case TOK_LPAREN:
 56.1965 +      {
 56.1966 +        scanner_.scan();
 56.1967 +        Expression *expr = expression();
 56.1968 +        if (!expr)
 56.1969 +            return NULL;
 56.1970 +        if (!expect(TOK_RPAREN))
 56.1971 +            return NULL;
 56.1972 +        return expr;
 56.1973 +      }
 56.1974 +
 56.1975 +      case TOK_NAME:
 56.1976 +      {
 56.1977 +        Local<String> name(zone_, expectName());
 56.1978 +        if (!name)
 56.1979 +            return NULL;
 56.1980 +        return new (pool_) NameProxy(scanner_.begin(), name);
 56.1981 +      }
 56.1982 +
 56.1983 +      default:
 56.1984 +        return primitive();
 56.1985 +    }
 56.1986 +}
 56.1987 +
 56.1988 +// Parses only old-style declarations.
 56.1989 +bool
 56.1990 +Parser::typeAndName(Expression **type, String **namep)
 56.1991 +{
 56.1992 +    if (match(TOK_LABEL)) {
 56.1993 +        // Old-style declaration:
 56.1994 +        //   new X:type
 56.1995 +        Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
 56.1996 +        if (!name)
 56.1997 +            return false;
 56.1998 +
 56.1999 +        *type = new (pool_) NameProxy(scanner_.begin(), name);
 56.2000 +        *namep = expectName();
 56.2001 +        return !!*namep;
 56.2002 +    }
 56.2003 +    
 56.2004 +    *type = NULL;
 56.2005 +    *namep = expectName();
 56.2006 +
 56.2007 +    return !!*namep;
 56.2008 +}
 56.2009 +
 56.2010 +// Parses both old and new style declarations.
 56.2011 +bool
 56.2012 +Parser::fullTypeAndName(Expression **type, String **namep, DeclKind kind)
 56.2013 +{
 56.2014 +    //   decl    ::= newdecl | olddecl
 56.2015 +    //   newdecl ::= Type Ident
 56.2016 +    //   olddecl ::= Label? (Ident | "...")
 56.2017 +    //   type    ::= Ident
 56.2018 +    //   label   ::= Ident ":"
 56.2019 +    //
 56.2020 +    if (match(TOK_LABEL)) {
 56.2021 +        // We something of the form:
 56.2022 +        //     Label Ident
 56.2023 +        // or: Label "..."
 56.2024 +        Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
 56.2025 +        if (!name)
 56.2026 +            return false;
 56.2027 +
 56.2028 +        *type = new (pool_) NameProxy(scanner_.begin(), name);
 56.2029 +        if (kind == DeclArg && match(TOK_ELLIPSES)) {
 56.2030 +            *namep = NULL;
 56.2031 +        } else {
 56.2032 +            if ((*namep = expectName()) == NULL)
 56.2033 +                return false;
 56.2034 +        }
 56.2035 +        return true;
 56.2036 +    }
 56.2037 +
 56.2038 +    Local<String> name(zone_, expectName());
 56.2039 +    if (!name)
 56.2040 +        return false;
 56.2041 +
 56.2042 +    if (peek(TOK_NAME) || (kind == DeclArg && peek(TOK_ELLIPSES))) {
 56.2043 +        // We got something of the form:
 56.2044 +        //    Ident Ident
 56.2045 +        *type = new (pool_) NameProxy(scanner_.begin(), name);
 56.2046 +        if (peek(TOK_NAME)) {
 56.2047 +            if ((*namep = expectName()) == NULL)
 56.2048 +                return false;
 56.2049 +        } else {
 56.2050 +            *namep = NULL;
 56.2051 +        }
 56.2052 +        return true;
 56.2053 +    }
 56.2054 +
 56.2055 +    // We got something of the form:
 56.2056 +    //    Ident
 56.2057 +    *type = NULL;
 56.2058 +    *namep = name;
 56.2059 +    return true;
 56.2060 +}
 56.2061 +
 56.2062 +Expression *
 56.2063 +Parser::call(Expression *callee)
 56.2064 +{
 56.2065 +    ExpressionList *arguments = new (pool_) ExpressionList();
 56.2066 +
 56.2067 +    SourcePosition pos = scanner_.begin();
 56.2068 +    expect(TOK_LPAREN);
 56.2069 +    
 56.2070 +    if (!match(TOK_RPAREN)) {
 56.2071 +        while (true) {
 56.2072 +            Expression *expr = expression();
 56.2073 +            if (!expr)
 56.2074 +                return NULL;
 56.2075 +
 56.2076 +            if (!arguments->append(expr))
 56.2077 +                return NULL;
 56.2078 +
 56.2079 +            if (!match(TOK_COMMA))
 56.2080 +                break;
 56.2081 +        }
 56.2082 +
 56.2083 +        if (!expect(TOK_RPAREN))
 56.2084 +            return NULL;
 56.2085 +    }
 56.2086 +
 56.2087 +    return new (pool_) CallExpression(pos, callee, arguments);
 56.2088 +}
 56.2089 +
 56.2090 +Expression *
 56.2091 +Parser::index(Expression *left)
 56.2092 +{
 56.2093 +    expect(TOK_LBRACKET);
 56.2094 +    
 56.2095 +    SourcePosition pos = scanner_.begin();
 56.2096 +    Expression *expr = expression();
 56.2097 +    if (!expr)
 56.2098 +        return NULL;
 56.2099 +
 56.2100 +    if (!expect(TOK_RBRACKET))
 56.2101 +        return NULL;
 56.2102 +
 56.2103 +    return new (pool_) IndexExpression(pos, left, expr);
 56.2104 +}
 56.2105 +
 56.2106 +Expression *
 56.2107 +Parser::field(Expression *left)
 56.2108 +{
 56.2109 +    expect(TOK_DOT);
 56.2110 +
 56.2111 +    SourcePosition pos = scanner_.begin();
 56.2112 +    Local<String> name(zone_, expectName());
 56.2113 +    if (!name)
 56.2114 +        return NULL;
 56.2115 +
 56.2116 +    return new (pool_) FieldExpression(pos, left, name);
 56.2117 +}
 56.2118 +
 56.2119 +Expression *
 56.2120 +Parser::primary()
 56.2121 +{
 56.2122 +    Expression *expr = prefix();
 56.2123 +    if (!expr)
 56.2124 +        return NULL;
 56.2125 +
 56.2126 +    for (;;) {
 56.2127 +        switch (scanner_.peek()) {
 56.2128 +          case TOK_LPAREN:
 56.2129 +            if ((expr = call(expr)) == NULL)
 56.2130 +                return NULL;
 56.2131 +            break;
 56.2132 +
 56.2133 +          case TOK_LBRACKET:
 56.2134 +            if ((expr = index(expr)) == NULL)
 56.2135 +                return NULL;
 56.2136 +            break;
 56.2137 +
 56.2138 +          case TOK_DOT:
 56.2139 +            if ((expr = field(expr)) == NULL)
 56.2140 +                return NULL;
 56.2141 +            break;
 56.2142 +
 56.2143 +          default:
 56.2144 +            return expr;
 56.2145 +        }
 56.2146 +    }
 56.2147 +}
 56.2148 +
 56.2149 +Expression *
 56.2150 +Parser::unary()
 56.2151 +{
 56.2152 +    TokenKind token = scanner_.peek();
 56.2153 +
 56.2154 +    SourcePosition pos = scanner_.begin();
 56.2155 +    switch (token) {
 56.2156 +      case TOK_INCREMENT:
 56.2157 +      case TOK_DECREMENT:
 56.2158 +      {
 56.2159 +        scanner_.scan();
 56.2160 +        Expression *expr = unary();
 56.2161 +        if (!expr)
 56.2162 +            return NULL;
 56.2163 +        return new (pool_) IncDecExpression(pos, token, expr, false);
 56.2164 +      }
 56.2165 +
 56.2166 +      case TOK_MINUS:
 56.2167 +      case TOK_NOT:
 56.2168 +      case TOK_TILDE:
 56.2169 +      {
 56.2170 +        scanner_.scan();
 56.2171 +        Expression *expr = unary();
 56.2172 +        if (!expr)
 56.2173 +            return NULL;
 56.2174 +        return new (pool_) UnaryExpression(pos, token, expr);
 56.2175 +      }
 56.2176 +
 56.2177 +      case TOK_SIZEOF:
 56.2178 +      {
 56.2179 +        scanner_.scan();
 56.2180 +        if (!expect(TOK_LPAREN))
 56.2181 +            return NULL;
 56.2182 +        Expression *expr = unary();
 56.2183 +        if (!expr)
 56.2184 +            return NULL;
 56.2185 +        if (!expect(TOK_RPAREN))
 56.2186 +            return NULL;
 56.2187 +        return new (pool_) UnaryExpression(pos, token, expr);
 56.2188 +      }
 56.2189 +
 56.2190 +      case TOK_LABEL:
 56.2191 +      {
 56.2192 +        scanner_.scan();
 56.2193 +        Local<String> tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
 56.2194 +        if (!tag)
 56.2195 +            return NULL;
 56.2196 +
 56.2197 +        NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), tag);
 56.2198 +
 56.2199 +        Expression *expr = unary();
 56.2200 +        if (!expr)
 56.2201 +            return NULL;
 56.2202 +
 56.2203 +        return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, proxy);
 56.2204 +      }
 56.2205 +
 56.2206 +      default:
 56.2207 +        break;
 56.2208 +    }
 56.2209 +
 56.2210 +    Expression *expr = primary();
 56.2211 +
 56.2212 +    token = scanner_.peek();
 56.2213 +    if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
 56.2214 +        scanner_.scan();
 56.2215 +        return new (pool_) IncDecExpression(pos, token, expr, true);
 56.2216 +    }
 56.2217 +
 56.2218 +    return expr;
 56.2219 +}
 56.2220 +
 56.2221 +Expression *
 56.2222 +Parser::multiplication()
 56.2223 +{
 56.2224 +    Expression *left = unary();
 56.2225 +    do {
 56.2226 +        if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT))
 56.2227 +            break;
 56.2228 +        SourcePosition pos = scanner_.begin();
 56.2229 +        TokenKind kind = scanner_.last();
 56.2230 +        Expression *right = unary();
 56.2231 +        if (!right)
 56.2232 +            return NULL;
 56.2233 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
 56.2234 +    } while (left);
 56.2235 +    return left;
 56.2236 +}
 56.2237 +
 56.2238 +Expression *
 56.2239 +Parser::addition()
 56.2240 +{
 56.2241 +    Expression *left = multiplication();
 56.2242 +    while (left) {
 56.2243 +        if (!match(TOK_PLUS) && !match(TOK_MINUS))
 56.2244 +            break;
 56.2245 +        SourcePosition pos = scanner_.begin();
 56.2246 +        TokenKind kind = scanner_.last();
 56.2247 +        Expression *right = multiplication();
 56.2248 +        if (!right)
 56.2249 +            return NULL;
 56.2250 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
 56.2251 +    }
 56.2252 +    return left;
 56.2253 +}
 56.2254 +
 56.2255 +Expression *
 56.2256 +Parser::shift()
 56.2257 +{
 56.2258 +    Expression *left = addition();
 56.2259 +    while (left) {
 56.2260 +        if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR))
 56.2261 +            break;
 56.2262 +        SourcePosition pos = scanner_.begin();
 56.2263 +        TokenKind kind = scanner_.last();
 56.2264 +        Expression *right = addition();
 56.2265 +        if (!right)
 56.2266 +            return NULL;
 56.2267 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
 56.2268 +    }
 56.2269 +    return left;
 56.2270 +}
 56.2271 +
 56.2272 +Expression *
 56.2273 +Parser::bitand_()
 56.2274 +{
 56.2275 +    Expression *left = shift();
 56.2276 +    while (left) {
 56.2277 +        if (!match(TOK_BITAND))
 56.2278 +            break;
 56.2279 +        SourcePosition pos = scanner_.begin();
 56.2280 +        Expression *right = shift();
 56.2281 +        if (!right)
 56.2282 +            return NULL;
 56.2283 +        left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right);
 56.2284 +    }
 56.2285 +    return left;
 56.2286 +}
 56.2287 +
 56.2288 +Expression *
 56.2289 +Parser::bitxor()
 56.2290 +{
 56.2291 +    Expression *left = bitand_();
 56.2292 +    while (left) {
 56.2293 +        if (!match(TOK_BITXOR))
 56.2294 +            break;
 56.2295 +        SourcePosition pos = scanner_.begin();
 56.2296 +        Expression *right = shift();
 56.2297 +        if (!right)
 56.2298 +            return NULL;
 56.2299 +        left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right);
 56.2300 +    }
 56.2301 +    return left;
 56.2302 +}
 56.2303 +
 56.2304 +Expression *
 56.2305 +Parser::bitor_()
 56.2306 +{
 56.2307 +    Expression *left = bitxor();
 56.2308 +    while (left) {
 56.2309 +        if (!match(TOK_BITOR))
 56.2310 +            break;
 56.2311 +        SourcePosition pos = scanner_.begin();
 56.2312 +        Expression *right = bitxor();
 56.2313 +        if (!right)
 56.2314 +            return NULL;
 56.2315 +        left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right);
 56.2316 +    }
 56.2317 +    return left;
 56.2318 +}
 56.2319 +
 56.2320 +Expression *
 56.2321 +Parser::relational()
 56.2322 +{
 56.2323 +    Expression *left = bitor_();
 56.2324 +    while (left) {
 56.2325 +        TokenKind kind = scanner_.peek();
 56.2326 +        if (kind < TOK_LT || kind > TOK_GE)
 56.2327 +            break;
 56.2328 +        scanner_.scan();
 56.2329 +        SourcePosition pos = scanner_.begin();
 56.2330 +        Expression *right = shift();
 56.2331 +        if (!right)
 56.2332 +            return NULL;
 56.2333 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
 56.2334 +    }
 56.2335 +    return left;
 56.2336 +}
 56.2337 +
 56.2338 +Expression *
 56.2339 +Parser::equals()
 56.2340 +{
 56.2341 +    Expression *left = relational();
 56.2342 +    while (left) {
 56.2343 +        if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS))
 56.2344 +            break;
 56.2345 +        TokenKind kind = scanner_.last();
 56.2346 +        SourcePosition pos = scanner_.begin();
 56.2347 +        Expression *right = relational();
 56.2348 +        if (!right)
 56.2349 +            return NULL;
 56.2350 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
 56.2351 +    }
 56.2352 +    return left;
 56.2353 +}
 56.2354 +
 56.2355 +Expression *
 56.2356 +Parser::and_()
 56.2357 +{
 56.2358 +    Expression *left = equals();
 56.2359 +    while (left) {
 56.2360 +        if (!match(TOK_AND))
 56.2361 +            break;
 56.2362 +        SourcePosition pos = scanner_.begin();
 56.2363 +        Expression *right = equals();
 56.2364 +        if (!right)
 56.2365 +            return NULL;
 56.2366 +        left = new (pool_) BinaryExpression(pos, TOK_AND, left, right);
 56.2367 +    }
 56.2368 +    return left;
 56.2369 +}
 56.2370 +
 56.2371 +Expression *
 56.2372 +Parser::or_()
 56.2373 +{
 56.2374 +    Expression *left = and_();
 56.2375 +    while (left) {
 56.2376 +        if (!match(TOK_OR))
 56.2377 +            break;
 56.2378 +        SourcePosition pos = scanner_.begin();
 56.2379 +        Expression *right = and_();
 56.2380 +        if (!right)
 56.2381 +            return NULL;
 56.2382 +        left = new (pool_) BinaryExpression(pos, TOK_OR, left, right);
 56.2383 +    }
 56.2384 +    return left;
 56.2385 +}
 56.2386 +
 56.2387 +Expression *
 56.2388 +Parser::ternary()
 56.2389 +{
 56.2390 +    Expression *cond = or_();
 56.2391 +    if (!cond)
 56.2392 +        return NULL;
 56.2393 +    
 56.2394 +    if (!match(TOK_QMARK))
 56.2395 +        return cond;
 56.2396 +
 56.2397 +    Expression *left;
 56.2398 +    SourcePosition pos = scanner_.begin();
 56.2399 +    AutoAllowTags<false> disableTags(scanner_);
 56.2400 +    {
 56.2401 +        if ((left = expression()) == NULL)
 56.2402 +            return NULL;
 56.2403 +    }
 56.2404 +
 56.2405 +    if (!expect(TOK_COLON))
 56.2406 +        return NULL;
 56.2407 +
 56.2408 +    Expression *right = expression();
 56.2409 +    if (!right)
 56.2410 +        return NULL;
 56.2411 +
 56.2412 +    return new (pool_) TernaryExpression(pos, cond, left, right);
 56.2413 +}
 56.2414 +
 56.2415 +Expression *
 56.2416 +Parser::assignment()
 56.2417 +{
 56.2418 +    Expression *left = ternary();
 56.2419 +    while (left) {
 56.2420 +        TokenKind token = scanner_.peek();
 56.2421 +        if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
 56.2422 +            break;
 56.2423 +        scanner_.scan();
 56.2424 +        SourcePosition pos = scanner_.begin();
 56.2425 +        Expression *expr = ternary();
 56.2426 +        if (!expr)
 56.2427 +            return NULL;
 56.2428 +
 56.2429 +        left = new (pool_) Assignment(pos, token, left, expr);
 56.2430 +    }
 56.2431 +    return left;
 56.2432 +}
 56.2433 +
 56.2434 +Expression *
 56.2435 +Parser::expression()
 56.2436 +{
 56.2437 +    return assignment();
 56.2438 +}
 56.2439 +
 56.2440 +Statement *
 56.2441 +Parser::while_()
 56.2442 +{
 56.2443 +    // while ::= "while" "(" expr ")" statement
 56.2444 +    SourcePosition pos = scanner_.begin();
 56.2445 +    scanner_.scan();
 56.2446 +
 56.2447 +    if (!expect(TOK_LPAREN))
 56.2448 +        return NULL;
 56.2449 +
 56.2450 +    Expression *condition = expression();
 56.2451 +    if (!condition)
 56.2452 +        return NULL;
 56.2453 +
 56.2454 +    if (!expect(TOK_RPAREN))
 56.2455 +        return NULL;
 56.2456 +
 56.2457 +    Statement *body;
 56.2458 +    if (scanner_.peek() == TOK_LBRACE)
 56.2459 +        body = block();
 56.2460 +    else
 56.2461 +        body = localStatement();
 56.2462 +    if (!body)
 56.2463 +        return NULL;
 56.2464 +
 56.2465 +    return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body);
 56.2466 +}
 56.2467 +
 56.2468 +Statement *
 56.2469 +Parser::do_()
 56.2470 +{
 56.2471 +    // do ::= "do" block "while" "(" expr ")"
 56.2472 +    SourcePosition pos = scanner_.begin();
 56.2473 +    scanner_.scan();
 56.2474 +
 56.2475 +    Statement *body = block();
 56.2476 +    if (!body)
 56.2477 +        return NULL;
 56.2478 +
 56.2479 +    if (!expect(TOK_WHILE))
 56.2480 +        return NULL;
 56.2481 +
 56.2482 +    if (!expect(TOK_LPAREN))
 56.2483 +        return NULL;
 56.2484 +    Expression *condition = expression();
 56.2485 +    if (!condition)
 56.2486 +        return NULL;
 56.2487 +    if (!expect(TOK_RPAREN))
 56.2488 +        return NULL;
 56.2489 +
 56.2490 +    return new (pool_) WhileStatement(pos, TOK_DO, condition, body);
 56.2491 +}
 56.2492 +
 56.2493 +Statement *
 56.2494 +Parser::switch_()
 56.2495 +{
 56.2496 +    // switch ::= "switch" "(" expr ")" "{" case* defaultcase? "}"
 56.2497 +    // case ::= "case" casevals ":" statement
 56.2498 +    // defaultcase ::= "default" ":" statement
 56.2499 +    //
 56.2500 +    expect(TOK_SWITCH);
 56.2501 +
 56.2502 +    SourcePosition pos = scanner_.begin();
 56.2503 +
 56.2504 +    if (!expect(TOK_LPAREN))
 56.2505 +        return NULL;
 56.2506 +    Expression *expr = expression();
 56.2507 +    if (!expr)
 56.2508 +        return NULL;
 56.2509 +    if (!expect(TOK_RPAREN))
 56.2510 +        return NULL;
 56.2511 +
 56.2512 +    if (!expect(TOK_LBRACE))
 56.2513 +        return NULL;
 56.2514 +
 56.2515 +    SourcePosition defaultPos;
 56.2516 +    PoolList<Case *> *cases = new (pool_) PoolList<Case *>();
 56.2517 +
 56.2518 +    Statement *defaultCase = NULL;
 56.2519 +
 56.2520 +    while (!peek(TOK_RBRACE)) {
 56.2521 +        Expression *expr = NULL;
 56.2522 +        ExpressionList *others = NULL;
 56.2523 +        if (match(TOK_DEFAULT)) {
 56.2524 +            if (defaultCase) {
 56.2525 +                cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch);
 56.2526 +                return NULL;
 56.2527 +            }
 56.2528 +
 56.2529 +            defaultPos = scanner_.begin();
 56.2530 +        } else {
 56.2531 +            if (defaultCase) {
 56.2532 +                cc_.reportError(defaultPos, Message_DefaultMustBeLastCase);
 56.2533 +                return NULL;
 56.2534 +            }
 56.2535 +
 56.2536 +            if (!expect(TOK_CASE))
 56.2537 +                return NULL;
 56.2538 +
 56.2539 +            // A limitation in the grammar is that |case <NAME>:| will be
 56.2540 +            // detected as a label.
 56.2541 +            AutoAllowTags<false> disableTags(scanner_);
 56.2542 +
 56.2543 +            if ((expr = expression()) == NULL)
 56.2544 +                return NULL;
 56.2545 +
 56.2546 +            if (peek(TOK_COMMA)) {
 56.2547 +                others = new (pool_) ExpressionList();
 56.2548 +                while (match(TOK_COMMA)) {
 56.2549 +                    Expression *other = expression();
 56.2550 +                    if (!other)
 56.2551 +                        return NULL;
 56.2552 +                    if (!others->append(other))
 56.2553 +                        return NULL;
 56.2554 +                }
 56.2555 +            }
 56.2556 +        }
 56.2557 +
 56.2558 +        if (!expect(TOK_COLON))
 56.2559 +            return NULL;
 56.2560 +
 56.2561 +        Statement *statement = localStatement();
 56.2562 +        if (!statement)
 56.2563 +            return NULL;
 56.2564 +
 56.2565 +        if (!peek(TOK_CASE) &&
 56.2566 +            !peek(TOK_DEFAULT) &&
 56.2567 +            !peek(TOK_RBRACE))
 56.2568 +        {
 56.2569 +            cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase);
 56.2570 +            return NULL;
 56.2571 +        }
 56.2572 +
 56.2573 +        if (expr) {
 56.2574 +            Case *caze = new (pool_) Case(expr, others, statement);
 56.2575 +            if (!cases->append(caze))
 56.2576 +                return NULL;
 56.2577 +        } else {
 56.2578 +            defaultCase = statement;
 56.2579 +        }
 56.2580 +    }
 56.2581 +
 56.2582 +    if (!expect(TOK_RBRACE))
 56.2583 +        return NULL;
 56.2584 +
 56.2585 +    return new (pool_) SwitchStatement(pos, expr, cases, defaultCase);
 56.2586 +}
 56.2587 +
 56.2588 +Statement *
 56.2589 +Parser::forStatement()
 56.2590 +{
 56.2591 +    // for ::= "for" "(" forinit? ";" forcond? ";" forstep ")" statement
 56.2592 +    // forint ::= "new" vardecl |
 56.2593 +    //            exprstmt
 56.2594 +    // forcond ::= expr
 56.2595 +    // forstep ::= exprstmt
 56.2596 +    //
 56.2597 +    SourcePosition pos = scanner_.begin();
 56.2598 +    scanner_.scan();
 56.2599 +    if (!expect(TOK_LPAREN))
 56.2600 +        return NULL;
 56.2601 +
 56.2602 +    Statement *decl = NULL;
 56.2603 +    if (!match(TOK_SEMICOLON)) {
 56.2604 +        if (match(TOK_NEW)) {
 56.2605 +            if ((decl = vars(TypeQual_None)) == NULL)
 56.2606 +                return NULL;
 56.2607 +        } else {
 56.2608 +            if ((decl = expressionStatement()) == NULL)
 56.2609 +                return NULL;
 56.2610 +        }
 56.2611 +        if (!expect(TOK_SEMICOLON))
 56.2612 +            return NULL;
 56.2613 +    }
 56.2614 +
 56.2615 +    Expression *condition = NULL;
 56.2616 +    if (!match(TOK_SEMICOLON)) {
 56.2617 +        if ((condition = expression()) == NULL)
 56.2618 +            return NULL;
 56.2619 +        if (!expect(TOK_SEMICOLON))
 56.2620 +            return NULL;
 56.2621 +    }
 56.2622 +
 56.2623 +    Statement *update = NULL;
 56.2624 +    if (!match(TOK_RPAREN)) {
 56.2625 +        if ((update = expressionStatement()) == NULL)
 56.2626 +            return NULL;
 56.2627 +        if (!expect(TOK_RPAREN))
 56.2628 +            return NULL;
 56.2629 +    }
 56.2630 +
 56.2631 +    Statement *body;
 56.2632 +    if (scanner_.peek() == TOK_LBRACE)
 56.2633 +        body = block();
 56.2634 +    else
 56.2635 +        body = localStatement();
 56.2636 +    if (!body)
 56.2637 +        return NULL;
 56.2638 +
 56.2639 +    return new (pool_) ForStatement(pos, decl, condition, update, body);
 56.2640 +}
 56.2641 +
 56.2642 +ExpressionList *
 56.2643 +Parser::dimensions()
 56.2644 +{
 56.2645 +    // dimensions ::= ("[" expr? "]")*
 56.2646 +
 56.2647 +    ExpressionList *postDimensions = new (pool_) ExpressionList();
 56.2648 +    while (match(TOK_LBRACKET)) {
 56.2649 +        Expression *dim = NULL;
 56.2650 +        if (!match(TOK_RBRACKET)) {
 56.2651 +            if ((dim = expression()) == NULL)
 56.2652 +                return NULL;
 56.2653 +            if (!expect(TOK_RBRACKET))
 56.2654 +                return NULL;
 56.2655 +        }
 56.2656 +
 56.2657 +        if (!postDimensions->append(dim))
 56.2658 +            return NULL;
 56.2659 +    }
 56.2660 +    return postDimensions;
 56.2661 +}
 56.2662 +
 56.2663 +VariableDeclaration *
 56.2664 +Parser::var(TypeQualifiers qual)
 56.2665 +{
 56.2666 +    // vardecl ::= decl ("=" expr)?
 56.2667 +
 56.2668 +    Expression *type;
 56.2669 +    Local<String> name(zone_);
 56.2670 +
 56.2671 +    if (!typeAndName(&type, name.ref()))
 56.2672 +        return NULL;
 56.2673 +
 56.2674 +    ExpressionList *dims = NULL;
 56.2675 +    if (peek(TOK_LBRACKET)) {
 56.2676 +        if ((dims = dimensions()) == NULL)
 56.2677 +            return NULL;;
 56.2678 +    }
 56.2679 +
 56.2680 +    SourcePosition pos = scanner_.begin();
 56.2681 +    
 56.2682 +    Expression *expr = NULL;
 56.2683 +    if (match(TOK_ASSIGN)) {
 56.2684 +        switch (scanner_.peek()) {
 56.2685 +          // Note: we don't support [] literals yet.
 56.2686 +          case TOK_LBRACE:
 56.2687 +            scanner_.scan();
 56.2688 +            if ((expr = fixedArrayLiteral()) == NULL)
 56.2689 +                return NULL;
 56.2690 +            break;
 56.2691 +
 56.2692 +          default:
 56.2693 +            if ((expr = expression()) == NULL)
 56.2694 +                return NULL;
 56.2695 +            break;
 56.2696 +        }
 56.2697 +    }
 56.2698 +
 56.2699 +    return new (pool_) VariableDeclaration(pos, qual, name, type, dims, expr);
 56.2700 +}
 56.2701 +
 56.2702 +Statement *
 56.2703 +Parser::vars(TypeQualifiers qual)
 56.2704 +{
 56.2705 +    // localvars ::= ("new" | "const" | "decl") vardecl ("," vardecl)*
 56.2706 +    // globalvars ::= ("public" | "const" | "new" | "public" "const") vardecl
 56.2707 +    VariableDeclaration *decl = var(qual);
 56.2708 +    if (!decl)
 56.2709 +        return NULL;
 56.2710 +
 56.2711 +    if (!peek(TOK_COMMA))
 56.2712 +        return decl;
 56.2713 +
 56.2714 +    StatementList *statements = new (pool_) StatementList();
 56.2715 +    if (!statements->append(decl))
 56.2716 +        return NULL;
 56.2717 +
 56.2718 +    while (match(TOK_COMMA)) {
 56.2719 +        Statement *decl = var(qual);
 56.2720 +        if (!decl)
 56.2721 +            return NULL;
 56.2722 +        if (!statements->append(decl))
 56.2723 +            return NULL;
 56.2724 +    }
 56.2725 +
 56.2726 +    // Create a fake-o block with no scope to create a statement list.
 56.2727 +    return new (pool_) BlockStatement(decl->pos(), statements, TOK_NEW);
 56.2728 +}
 56.2729 +
 56.2730 +Statement *
 56.2731 +Parser::returnStatement()
 56.2732 +{
 56.2733 +    // return ::= "return" term |
 56.2734 +    //            "return" "expr"
 56.2735 +
 56.2736 +    SourcePosition pos = scanner_.begin();
 56.2737 +    if (!expect(TOK_RETURN))
 56.2738 +        return NULL;
 56.2739 +
 56.2740 +    Expression *expr = NULL;
 56.2741 +    if (scanner_.peek() != TOK_SEMICOLON) {
 56.2742 +        if ((expr = expression()) == NULL)
 56.2743 +            return NULL;
 56.2744 +
 56.2745 +        // We only care about non-void returns when determining whether a
 56.2746 +        // tagless function is non-void.
 56.2747 +        encounteredReturn_ = true;
 56.2748 +    }
 56.2749 +
 56.2750 +    return new (pool_) ReturnStatement(pos, expr);
 56.2751 +}
 56.2752 +
 56.2753 +Statement *
 56.2754 +Parser::expressionStatement()
 56.2755 +{
 56.2756 +    // exprstmt ::= expr
 56.2757 +    Expression *left = assignment();
 56.2758 +    if (!left)
 56.2759 +        return NULL;
 56.2760 +
 56.2761 +    return new (pool_) ExpressionStatement(left);
 56.2762 +}
 56.2763 +
 56.2764 +Statement *
 56.2765 +Parser::block()
 56.2766 +{
 56.2767 +    // block ::= "{" statement* "}"
 56.2768 +
 56.2769 +    if (!expect(TOK_LBRACE))
 56.2770 +        return NULL;
 56.2771 +
 56.2772 +    SourcePosition pos = scanner_.begin();
 56.2773 +
 56.2774 +    StatementList *statements = new (pool_) StatementList();
 56.2775 +    while (!match(TOK_RBRACE)) {
 56.2776 +        Statement *statement = localStatement();
 56.2777 +        if (statement == NULL)
 56.2778 +            return NULL;
 56.2779 +        if (!statements->append(statement))
 56.2780 +            return NULL;
 56.2781 +    }
 56.2782 +
 56.2783 +    BlockStatement *block = new (pool_) BlockStatement(pos, statements, TOK_LBRACE);
 56.2784 +    return block;
 56.2785 +}
 56.2786 +
 56.2787 +Statement *
 56.2788 +Parser::if_()
 56.2789 +{
 56.2790 +    // if ::= "if" "(" expr ")" statement elseif* else?
 56.2791 +    // elseif ::= "elseif" "(" expr ")" statement
 56.2792 +    // else ::= "else" statement
 56.2793 +    expect(TOK_IF);
 56.2794 +  
 56.2795 +    SourcePosition pos = scanner_.begin();
 56.2796 +    if (!expect(TOK_LPAREN))
 56.2797 +        return NULL;
 56.2798 +
 56.2799 +    Expression *cond = expression();
 56.2800 +    if (!cond)
 56.2801 +        return NULL;
 56.2802 +
 56.2803 +    if (!expect(TOK_RPAREN))
 56.2804 +        return NULL;
 56.2805 +
 56.2806 +    Statement *ifTrue = localStatement();
 56.2807 +    if (!ifTrue)
 56.2808 +        return NULL;
 56.2809 +
 56.2810 +    IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue);
 56.2811 +
 56.2812 +    IfStatement *last = outer;
 56.2813 +    while (match(TOK_ELSE)) {
 56.2814 +        if (!match(TOK_IF)) {
 56.2815 +            Statement *ifFalse = localStatement();
 56.2816 +            if (!ifFalse)
 56.2817 +                return NULL;
 56.2818 +
 56.2819 +            last->setIfFalse(ifFalse);
 56.2820 +            break;
 56.2821 +        }
 56.2822 +
 56.2823 +        SourcePosition pos = scanner_.begin();
 56.2824 +        if (!expect(TOK_LPAREN))
 56.2825 +            return NULL;
 56.2826 +
 56.2827 +        Expression *otherCond = expression();
 56.2828 +        if (!otherCond)
 56.2829 +            return NULL;
 56.2830 +
 56.2831 +        if (!expect(TOK_RPAREN))
 56.2832 +            return NULL;
 56.2833 +
 56.2834 +        Statement *otherIfTrue = localStatement();
 56.2835 +        if (!otherIfTrue)
 56.2836 +            return NULL;
 56.2837 +
 56.2838 +        IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue);
 56.2839 +        last->setIfFalse(inner);
 56.2840 +        last = inner;
 56.2841 +    }
 56.2842 +
 56.2843 +    return outer;
 56.2844 +}
 56.2845 +
 56.2846 +Statement *
 56.2847 +Parser::localStatement()
 56.2848 +{
 56.2849 +    // statement ::= stmt term
 56.2850 +    // stmt ::= do | for | if | while | struct | enum |
 56.2851 +    //          localvars | return | switch | break | continue
 56.2852 +
 56.2853 +    Statement *statement = NULL;
 56.2854 +
 56.2855 +    // Statements which must be followed by a semicolon will break out of the
 56.2856 +    // switch. If they may end in BlockStatements, they'll immediately return.
 56.2857 +
 56.2858 +    TokenKind kind = scanner_.peek();
 56.2859 +    switch (kind) {
 56.2860 +      case TOK_CONST:
 56.2861 +      case TOK_NEW:
 56.2862 +      {
 56.2863 +        TypeQualifiers quals = (kind == TOK_CONST)
 56.2864 +                              ? TypeQual_Const
 56.2865 +                              : TypeQual_None;
 56.2866 +        scanner_.scan();
 56.2867 +        if ((statement = vars(quals)) == NULL)
 56.2868 +          return NULL;
 56.2869 +        break;
 56.2870 +      }
 56.2871 +
 56.2872 +      case TOK_FOR:
 56.2873 +        return forStatement();
 56.2874 +
 56.2875 +      case TOK_WHILE:
 56.2876 +        return while_();
 56.2877 +
 56.2878 +      case TOK_BREAK:
 56.2879 +        scanner_.scan();
 56.2880 +        statement = new (pool_) BreakStatement(scanner_.begin());
 56.2881 +        break;
 56.2882 +
 56.2883 +      case TOK_CONTINUE:
 56.2884 +        scanner_.scan();
 56.2885 +        statement = new (pool_) ContinueStatement(scanner_.begin());
 56.2886 +        break;
 56.2887 +
 56.2888 +      case TOK_DO:
 56.2889 +        if ((statement = do_()) == NULL)
 56.2890 +            return NULL;
 56.2891 +        break;
 56.2892 +
 56.2893 +      case TOK_RETURN:
 56.2894 +        if ((statement = returnStatement()) == NULL)
 56.2895 +          return NULL;
 56.2896 +        break;
 56.2897 +
 56.2898 +      case TOK_ENUM:
 56.2899 +        if ((statement = enum_(TOK_NONE)) == NULL)
 56.2900 +          return NULL;
 56.2901 +        break;
 56.2902 +
 56.2903 +      case TOK_STRUCT:
 56.2904 +        if ((statement = struct_()) == NULL)
 56.2905 +          return NULL;
 56.2906 +        break;
 56.2907 +
 56.2908 +      case TOK_SWITCH:
 56.2909 +        return switch_();
 56.2910 +
 56.2911 +      case TOK_IF:
 56.2912 +        return if_();
 56.2913 +
 56.2914 +      case TOK_LBRACE:
 56.2915 +        return block();
 56.2916 +
 56.2917 +      default:
 56.2918 +        break;
 56.2919 +    }
 56.2920 +
 56.2921 +    if (!statement) {
 56.2922 +        if ((statement = expressionStatement()) == NULL)
 56.2923 +            return NULL;
 56.2924 +    }
 56.2925 +
 56.2926 +    if (!expect(TOK_SEMICOLON))
 56.2927 +        return NULL;
 56.2928 +
 56.2929 +    return statement;
 56.2930 +}
 56.2931 +
 56.2932 +Statement *
 56.2933 +Parser::struct_()
 56.2934 +{
 56.2935 +    // struct ::= "struct" name { struct_fields }
 56.2936 +    // struct_fields ::= struct_field |
 56.2937 +    //                   struct_field struct_fields
 56.2938 +    // struct_field ::= label? name term
 56.2939 +    expect(TOK_STRUCT);
 56.2940 +
 56.2941 +    Local<String> name(zone_, expectName());
 56.2942 +    if (!name)
 56.2943 +        return NULL;
 56.2944 +
 56.2945 +    SourcePosition pos = scanner_.begin();
 56.2946 +
 56.2947 +    if (!expect(TOK_LBRACE))
 56.2948 +        return NULL;
 56.2949 +
 56.2950 +    FieldList *fields = new (pool_) FieldList();
 56.2951 +
 56.2952 +    while (!peek(TOK_RBRACE)) {
 56.2953 +        Expression *type;
 56.2954 +        Local<String> fieldName(zone_);
 56.2955 +
 56.2956 +        if (!fullTypeAndName(&type, fieldName.ref(), DeclField))
 56.2957 +            return NULL;
 56.2958 +
 56.2959 +        SourcePosition pos = scanner_.begin();
 56.2960 +
 56.2961 +        if (!matchSemicolon())
 56.2962 +            return NULL;
 56.2963 +
 56.2964 +        StructureStatement::Field *field =
 56.2965 +            new (pool_) StructureStatement::Field(pos, type, fieldName);
 56.2966 +        if (!field || !fields->append(field))
 56.2967 +            return NULL;
 56.2968 +    }
 56.2969 +
 56.2970 +    if (!expect(TOK_RBRACE))
 56.2971 +        return NULL;
 56.2972 +
 56.2973 +    if (fields->empty()) {
 56.2974 +        cc_.reportError(pos, Message_StructCantBeEmpty);
 56.2975 +        return NULL;
 56.2976 +    }
 56.2977 +
 56.2978 +    return new (pool_) StructureStatement(pos, name, fields);
 56.2979 +}
 56.2980 +
 56.2981 +Statement *
 56.2982 +Parser::enum_(TokenKind kind)
 56.2983 +{
 56.2984 +    // enum ::= "enum" name? { enum_members? }
 56.2985 +    // enum_members ::= enum_member ","? |
 56.2986 +    //                  enum_member "," enum_members
 56.2987 +    // enum_member ::= ident ("=" constexpr)?
 56.2988 +    expect(TOK_ENUM);
 56.2989 +
 56.2990 +    SourcePosition pos = scanner_.begin();
 56.2991 +
 56.2992 +    Local<String> name(zone_);
 56.2993 +    if (matchName(name.ref()) && !name)
 56.2994 +        return NULL;
 56.2995 +
 56.2996 +    EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList();
 56.2997 +
 56.2998 +    if (!expect(TOK_LBRACE))
 56.2999 +        return NULL;
 56.3000 +
 56.3001 +    do {
 56.3002 +        if (scanner_.peek() == TOK_RBRACE)
 56.3003 +            break;
 56.3004 +
 56.3005 +        SourcePosition pos = scanner_.begin();
 56.3006 +        Local<String> name(zone_, expectName());
 56.3007 +        if (!name)
 56.3008 +            return NULL;
 56.3009 +
 56.3010 +        Expression *expr = NULL;
 56.3011 +        if (match(TOK_ASSIGN)) {
 56.3012 +            if ((expr = expression()) == NULL)
 56.3013 +                return NULL;
 56.3014 +        }
 56.3015 +
 56.3016 +        if (!entries->append(EnumStatement::Entry(name, expr, pos)))
 56.3017 +            return NULL;
 56.3018 +    } while (match(TOK_COMMA));
 56.3019 +    if (!expect(TOK_RBRACE))
 56.3020 +        return NULL;
 56.3021 +
 56.3022 +    return new (pool_) EnumStatement(pos, kind, name, entries);
 56.3023 +}
 56.3024 +
 56.3025 +template <class T>
 56.3026 +static inline ScopedRoot<T> *
 56.3027 +NewScopedRoot(PoolAllocator &pool, Handle<T> obj)
 56.3028 +{
 56.3029 +    return new (pool) ScopedRoot<T>(obj);
 56.3030 +}
 56.3031 +
 56.3032 +ImportStatement *
 56.3033 +Parser::import(TokenKind kind)
 56.3034 +{
 56.3035 +    SourcePosition pos = scanner_.begin();
 56.3036 +
 56.3037 +    // import       ::= "from" import_path "import" import_names
 56.3038 +    //                | "import" import_path
 56.3039 +    //                | "import" import_path ".*"
 56.3040 +    // import_path  ::= name
 56.3041 +    //                | name "." import_path
 56.3042 +    // import_names ::= "*"
 56.3043 +    //                | import_name_list
 56.3044 +    // import_name_list ::= name
 56.3045 +    //                    | name "," import_name_list
 56.3046 +
 56.3047 +    Local<String> name(zone_, expectName());
 56.3048 +    if (!name)
 56.3049 +        return NULL;
 56.3050 +
 56.3051 +    PathComponent *root = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
 56.3052 +    PathComponent *current = root;
 56.3053 +
 56.3054 +    // NULL namelist means that we do not import any names. An empty namelist
 56.3055 +    // means we import all names.
 56.3056 +    NameList *names = NULL;
 56.3057 +
 56.3058 +    while (match(TOK_DOT)) {
 56.3059 +        if (kind == TOK_IMPORT && match(TOK_STAR)) {
 56.3060 +            names = new (pool_) NameList();
 56.3061 +            break;
 56.3062 +        }
 56.3063 +
 56.3064 +        if ((name = expectName()) == NULL)
 56.3065 +            return NULL;
 56.3066 +
 56.3067 +        current->next = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
 56.3068 +        current = current->next;
 56.3069 +    }
 56.3070 +
 56.3071 +    if (kind == TOK_FROM) {
 56.3072 +        if (!expect(TOK_IMPORT))
 56.3073 +            return NULL;
 56.3074 +
 56.3075 +        names = new (pool_) NameList();
 56.3076 +
 56.3077 +        if (!match(TOK_STAR)) {
 56.3078 +            if (!matchName(name.address())) {
 56.3079 +                cc_.reportError(scanner_.begin(), Message_BadImportFrom);
 56.3080 +                return NULL;
 56.3081 +            }
 56.3082 +
 56.3083 +            if (!name || !names->append(NewScopedRoot<String>(pool_, name)))
 56.3084 +                return NULL;
 56.3085 +
 56.3086 +            while (match(TOK_COMMA)) {
 56.3087 +                if ((name = expectName()) == NULL)
 56.3088 +                    return NULL;
 56.3089 +                if (!names->append(NewScopedRoot<String>(pool_, name)))
 56.3090 +                    return NULL;
 56.3091 +            }
 56.3092 +        }
 56.3093 +    }
 56.3094 +
 56.3095 +    return new (pool_) ImportStatement(pos, root, names);
 56.3096 +}
 56.3097 +
 56.3098 +Statement *
 56.3099 +Parser::function(TokenKind token)
 56.3100 +{
 56.3101 +    Expression *returnType;
 56.3102 +    Local<String> name(zone_);
 56.3103 +
 56.3104 +    if (!fullTypeAndName(&returnType, name.ref(), DeclFun))
 56.3105 +        return NULL;
 56.3106 +
 56.3107 +    SourcePosition pos = scanner_.begin();
 56.3108 +    ParameterList *parameters = new (pool_) ParameterList();
 56.3109 +
 56.3110 +    if (!expect(TOK_LPAREN))
 56.3111 +        return NULL;
 56.3112 +
 56.3113 +    bool variadic = false;
 56.3114 +
 56.3115 +    if (!match(TOK_RPAREN)) {
 56.3116 +        while (true) {
 56.3117 +            TypeQualifiers quals = TypeQual_None;
 56.3118 +            if (match(TOK_CONST))
 56.3119 +                quals = TypeQualifiers(quals | TypeQual_Const);
 56.3120 +
 56.3121 +            bool ref = match(TOK_AMPERSAND);
 56.3122 +
 56.3123 +            SourcePosition begin = scanner_.begin();
 56.3124 +            Expression *type;
 56.3125 +            Local<String> name(zone_);
 56.3126 +            if (!fullTypeAndName(&type, name.ref(), DeclArg))
 56.3127 +                return NULL;
 56.3128 +
 56.3129 +            if (!name) {
 56.3130 +                if ((quals & TypeQual_Const) || ref) {
 56.3131 +                    cc_.reportError(begin, Message_InvalidVarArgs);
 56.3132 +                    return NULL;
 56.3133 +                }
 56.3134 +
 56.3135 +                if (token != TOK_NATIVE) {
 56.3136 +                    cc_.reportError(begin, Message_VarArgsOutsideNative);
 56.3137 +                    return NULL;
 56.3138 +                }
 56.3139 +
 56.3140 +                variadic = true;
 56.3141 +                break;
 56.3142 +            }
 56.3143 +
 56.3144 +            ExpressionList *dims = NULL;
 56.3145 +            if (peek(TOK_LBRACKET)) {
 56.3146 +                if ((dims = dimensions()) == NULL)
 56.3147 +                    return NULL;
 56.3148 +            }
 56.3149 +
 56.3150 +            Expression *expr = NULL;
 56.3151 +            if (match(TOK_ASSIGN)) {
 56.3152 +                if ((expr = expression()) == NULL)
 56.3153 +                    return NULL;
 56.3154 +            }
 56.3155 +
 56.3156 +            Parameter *parameter = new (pool_) Parameter(name, type, ref, quals, dims, expr, begin);
 56.3157 +            if (!parameters->append(parameter))
 56.3158 +                return NULL;
 56.3159 +
 56.3160 +            if (!match(TOK_COMMA))
 56.3161 +                break;
 56.3162 +        }
 56.3163 +        if (!expect(TOK_RPAREN))
 56.3164 +            return NULL;
 56.3165 +    }
 56.3166 +
 56.3167 +    encounteredReturn_ = false;
 56.3168 +
 56.3169 +    Statement *body = NULL;
 56.3170 +    if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) {
 56.3171 +        body = block();
 56.3172 +        if (!body)
 56.3173 +            return NULL;
 56.3174 +    }
 56.3175 +
 56.3176 +    FunctionSignature signature(returnType, parameters, variadic);
 56.3177 +    if (token == TOK_TYPEDEF)
 56.3178 +        return new (pool_) FunctionTypeStatement(pos, name, signature);
 56.3179 +
 56.3180 +    return new (pool_) FunctionStatement(pos, name, token, body, signature, encounteredReturn_);
 56.3181 +}
 56.3182 +
 56.3183 +static inline bool
 56.3184 +DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle<Type> type)
 56.3185 +{
 56.3186 +    Local<String> tag(zone, zone->makeSymbol(name));
 56.3187 +    if (!tag)
 56.3188 +        return false;
 56.3189 +
 56.3190 +    assert(false);
 56.3191 +    return false; //return !!scope->declareType(tag, type);
 56.3192 +}
 56.3193 +
 56.3194 +static inline bool
 56.3195 +DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type)
 56.3196 +{
 56.3197 +    Local<Type> primitive(zone, zone->types()->getPrimitive(type));
 56.3198 +    assert(primitive);
 56.3199 +    return DeclareIntrinsicType(zone, scope, name, primitive);
 56.3200 +}
 56.3201 +
 56.3202 +ParseTree *
 56.3203 +Parser::parse()
 56.3204 +{
 56.3205 +    StatementList *statements = new (pool_) StatementList();
 56.3206 +
 56.3207 +    for (;;) {
 56.3208 +        Statement *statement = NULL;
 56.3209 +
 56.3210 +        TokenKind kind = scanner_.peek();
 56.3211 +        switch (kind) {
 56.3212 +          case TOK_ERROR:
 56.3213 +            return NULL;
 56.3214 +
 56.3215 +          case TOK_EOF:
 56.3216 +            break;
 56.3217 +
 56.3218 +          case TOK_NAME:
 56.3219 +            if ((statement = function(TOK_NAME)) == NULL)
 56.3220 +                return NULL;
 56.3221 +            break;
 56.3222 +
 56.3223 +          case TOK_FROM:
 56.3224 +          case TOK_IMPORT:
 56.3225 +          {
 56.3226 +            scanner_.scan();
 56.3227 +            if (statements->length())
 56.3228 +                cc_.reportError(scanner_.begin(), Message_ImportsMustBeFirst);
 56.3229 +            ImportStatement *stmt = import(kind);
 56.3230 +            if (!stmt)
 56.3231 +                return NULL;
 56.3232 +            if (!imports_->append(stmt))
 56.3233 +                return NULL;
 56.3234 +            if (!matchSemicolon())
 56.3235 +                return NULL;
 56.3236 +            continue;
 56.3237 +          }
 56.3238 +
 56.3239 +          case TOK_FORWARD:
 56.3240 +          case TOK_PUBLIC:
 56.3241 +          case TOK_NATIVE:
 56.3242 +          case TOK_STOCK:
 56.3243 +          case TOK_LABEL:
 56.3244 +          case TOK_TYPEDEF:
 56.3245 +          {
 56.3246 +            if (kind != TOK_LABEL)
 56.3247 +                scanner_.scan();
 56.3248 +            if (kind == TOK_PUBLIC && peek(TOK_CONST)) {
 56.3249 +                if ((statement = var(TypeQual_Const)) == NULL)
 56.3250 +                    return NULL;
 56.3251 +                if (!matchSemicolon())
 56.3252 +                    return NULL;
 56.3253 +            } else if (kind == TOK_PUBLIC && peek(TOK_ENUM)) {
 56.3254 +                if ((statement = enum_(kind)) == NULL)
 56.3255 +                    return NULL;
 56.3256 +                if (!matchSemicolon())
 56.3257 +                    return NULL;
 56.3258 +            } else {
 56.3259 +                if ((statement = function(kind)) == NULL)
 56.3260 +                    return NULL;
 56.3261 +                if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon())
 56.3262 +                    return NULL;
 56.3263 +            }
 56.3264 +            break;
 56.3265 +          }
 56.3266 +
 56.3267 +          case TOK_CONST:
 56.3268 +          case TOK_NEW:
 56.3269 +          {
 56.3270 +            TypeQualifiers quals = (kind == TOK_CONST) ? TypeQual_Const : TypeQual_None;
 56.3271 +            // Note: at global scope, we don't accept comma-delimited
 56.3272 +            // declarations yet, to see if we can get away with forcing
 56.3273 +            // a nicer top-level style.
 56.3274 +            scanner_.scan();
 56.3275 +            if ((statement = var(quals)) == NULL)
 56.3276 +                return NULL;
 56.3277 +            if (!matchSemicolon())
 56.3278 +                return NULL;
 56.3279 +            break;
 56.3280 +          }
 56.3281 +
 56.3282 +          case TOK_ENUM:
 56.3283 +            if ((statement = enum_(TOK_NONE)) == NULL)
 56.3284 +                return NULL;
 56.3285 +            if (!matchSemicolon())
 56.3286 +                return NULL;
 56.3287 +            break;
 56.3288 +
 56.3289 +          case TOK_STRUCT:
 56.3290 +            if ((statement = struct_()) == NULL)
 56.3291 +                return NULL;
 56.3292 +            if (!matchSemicolon())
 56.3293 +                return NULL;
 56.3294 +            break;
 56.3295 +
 56.3296 +          default:
 56.3297 +            cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
 56.3298 +            return NULL;
 56.3299 +        }
 56.3300 +
 56.3301 +        if (!statement)
 56.3302 +            break;
 56.3303 +
 56.3304 +        if (!statements->append(statement))
 56.3305 +            return NULL;
 56.3306 +    }
 56.3307 +
 56.3308 +    return new (pool_) ParseTree(statements, unbound_, imports_);
 56.3309 +}
 56.3310 +
 56.3311 +class AstPrinter : public AstVisitor
 56.3312 +{
 56.3313 +    FILE *fp_;
 56.3314 +    size_t level_;
 56.3315 +
 56.3316 +  private:
 56.3317 +    void prefix() {
 56.3318 +        for (size_t i = 0; i < level_; i++)
 56.3319 +            fprintf(fp_, "  ");
 56.3320 +    }
 56.3321 +    void indent() {
 56.3322 +        level_++;
 56.3323 +    }
 56.3324 +    void unindent() {
 56.3325 +        level_--;
 56.3326 +    }
 56.3327 +
 56.3328 +  public:
 56.3329 +    AstPrinter(FILE *fp)
 56.3330 +      : fp_(fp),
 56.3331 +        level_(0)
 56.3332 +    {
 56.3333 +    }
 56.3334 +
 56.3335 +    void dump(const FunctionSignature &sig) {
 56.3336 +        prefix();
 56.3337 +        fprintf(fp_, "()\n");
 56.3338 +    }
 56.3339 +    void visitNameProxy(NameProxy *name) {
 56.3340 +        prefix();
 56.3341 +        fprintf(fp_, "[ NameProxy (%s)\n", name->name()->chars());
 56.3342 +    }
 56.3343 +    void visitCallExpression(CallExpression *node) {
 56.3344 +        prefix();
 56.3345 +        fprintf(fp_, "[ CallExpression\n");
 56.3346 +        indent();
 56.3347 +        node->callee()->accept(this);
 56.3348 +        for (size_t i = 0; i < node->arguments()->length(); i++)
 56.3349 +            node->arguments()->at(i)->accept(this);
 56.3350 +        unindent();
 56.3351 +    }
 56.3352 +    void visitFunctionTypeStatement(FunctionTypeStatement *node) {
 56.3353 +        prefix();
 56.3354 +        fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->name()->chars());
 56.3355 +        indent();
 56.3356 +        dump(node->signature());
 56.3357 +        unindent();
 56.3358 +    }
 56.3359 +    void visitFunctionStatement(FunctionStatement *node) {
 56.3360 +        prefix();
 56.3361 +        fprintf(fp_, "[ FunctionStatement (%s)\n", node->name()->chars());
 56.3362 +        indent();
 56.3363 +        dump(node->signature());
 56.3364 +        if (node->body())
 56.3365 +            node->body()->accept(this);
 56.3366 +        unindent();
 56.3367 +    }
 56.3368 +    void visitExpressionStatement(ExpressionStatement *node) {
 56.3369 +        prefix();
 56.3370 +        fprintf(fp_, "[ ExpressionStatement\n");
 56.3371 +        indent();
 56.3372 +        node->expression()->accept(this);
 56.3373 +        unindent();
 56.3374 +    }
 56.3375 +    void visitAssignment(Assignment *node) {
 56.3376 +        prefix();
 56.3377 +        fprintf(fp_, "[ Assignment\n");
 56.3378 +        indent();
 56.3379 +        node->lvalue()->accept(this);
 56.3380 +        node->expression()->accept(this);
 56.3381 +        unindent();
 56.3382 +    }
 56.3383 +    void visitTernaryExpression(TernaryExpression *node) {
 56.3384 +        prefix();
 56.3385 +        fprintf(fp_, "[ TernaryExpression\n");
 56.3386 +        indent();
 56.3387 +        node->condition()->accept(this);
 56.3388 +        node->left()->accept(this);
 56.3389 +        node->right()->accept(this);
 56.3390 +        unindent();
 56.3391 +    }
 56.3392 +    void visitBinaryExpression(BinaryExpression *node) {
 56.3393 +        prefix();
 56.3394 +        fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]);
 56.3395 +        indent();
 56.3396 +        node->left()->accept(this);
 56.3397 +        node->right()->accept(this);
 56.3398 +        unindent();
 56.3399 +    }
 56.3400 +    void visitUnaryExpression(UnaryExpression *node) {
 56.3401 +        prefix();
 56.3402 +        fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]);
 56.3403 +        indent();
 56.3404 +        node->expression()->accept(this);
 56.3405 +        unindent();
 56.3406 +    }
 56.3407 +    void visitReturnStatement(ReturnStatement *node) {
 56.3408 +        prefix();
 56.3409 +        fprintf(fp_, "[ ReturnStatement\n");
 56.3410 +        indent();
 56.3411 +        if (node->expression())
 56.3412 +            node->expression()->accept(this);
 56.3413 +        unindent();
 56.3414 +    }
 56.3415 +    void visitForStatement(ForStatement *node) {
 56.3416 +        prefix();
 56.3417 +        fprintf(fp_, "[ ForStatement\n");
 56.3418 +        indent();
 56.3419 +        if (node->initialization())
 56.3420 +            node->initialization()->accept(this);
 56.3421 +        if (node->condition())
 56.3422 +            node->condition()->accept(this);
 56.3423 +        if (node->update())
 56.3424 +            node->update()->accept(this);
 56.3425 +        node->body()->accept(this);
 56.3426 +        unindent();
 56.3427 +    }
 56.3428 +    void visitBlockStatement(BlockStatement *node) {
 56.3429 +        prefix();
 56.3430 +        fprintf(fp_, "[ BlockStatement\n");
 56.3431 +        indent();
 56.3432 +        for (size_t i = 0; i < node->statements()->length(); i++)
 56.3433 +            node->statements()->at(i)->accept(this);
 56.3434 +        unindent();
 56.3435 +    }
 56.3436 +    void visitVariableDeclaration(VariableDeclaration *node) {
 56.3437 +        prefix();
 56.3438 +        fprintf(fp_, "[ VariableDeclaration (%s)\n", node->name()->chars());
 56.3439 +        indent();
 56.3440 +        if (node->initialization())
 56.3441 +            node->initialization()->accept(this);
 56.3442 +        unindent();
 56.3443 +    }
 56.3444 +    void visitIntegerLiteral(IntegerLiteral *node) {
 56.3445 +        prefix();
 56.3446 +        fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
 56.3447 +    }
 56.3448 +    void visitBooleanLiteral(BooleanLiteral *node) {
 56.3449 +        prefix();
 56.3450 +        fprintf(fp_, "[ BooleanLiteral (%s)\n",
 56.3451 +                (node->token() == TOK_TRUE) ? "true" : "false");
 56.3452 +    }
 56.3453 +    void visitFloatLiteral(FloatLiteral *node) {
 56.3454 +        prefix();
 56.3455 +        fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
 56.3456 +    }
 56.3457 +    void visitIfStatement(IfStatement *node) {
 56.3458 +        prefix();
 56.3459 +        fprintf(fp_, "[ IfStatement\n");
 56.3460 +        indent();
 56.3461 +        node->ifTrue()->accept(this);
 56.3462 +        if (node->ifFalse())
 56.3463 +            node->ifFalse()->accept(this);
 56.3464 +        unindent();
 56.3465 +    }
 56.3466 +    void visitIndexExpression(IndexExpression *node) {
 56.3467 +        prefix();
 56.3468 +        fprintf(fp_, "[ IndexExpression\n");
 56.3469 +        indent();
 56.3470 +        node->left()->accept(this);
 56.3471 +        node->right()->accept(this);
 56.3472 +        unindent();
 56.3473 +    }
 56.3474 +    void visitEnumStatement(EnumStatement *node) {
 56.3475 +        prefix();
 56.3476 +        fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : "<anonymous>");
 56.3477 +        indent();
 56.3478 +        for (size_t i = 0; i < node->entries()->length(); i++) {
 56.3479 +            prefix();
 56.3480 +            fprintf(fp_, "%s =\n", node->entries()->at(i).name->chars());
 56.3481 +            if (node->entries()->at(i).expr) {
 56.3482 +                indent();
 56.3483 +                node->entries()->at(i).expr->accept(this);
 56.3484 +                unindent();
 56.3485 +            }
 56.3486 +        }
 56.3487 +        unindent();
 56.3488 +    }
 56.3489 +    void visitWhileStatement(WhileStatement *node) {
 56.3490 +        prefix();
 56.3491 +        fprintf(fp_, "[ WhileStatement (%s)\n",
 56.3492 +                (node->token() == TOK_DO) ? "do" : "while");
 56.3493 +        indent();
 56.3494 +        if (node->token() == TOK_DO) {
 56.3495 +            node->condition()->accept(this);
 56.3496 +            node->body()->accept(this);
 56.3497 +        } else {
 56.3498 +            node->condition()->accept(this);
 56.3499 +            node->body()->accept(this);
 56.3500 +        }
 56.3501 +        unindent();
 56.3502 +    }
 56.3503 +    void visitBreakStatement(BreakStatement *node) {
 56.3504 +        prefix();
 56.3505 +        fprintf(fp_, "[ BreakStatement\n");
 56.3506 +    }
 56.3507 +    void visitContinueStatement(ContinueStatement *node) {
 56.3508 +        prefix();
 56.3509 +        fprintf(fp_, "[ ContinueStatement\n");
 56.3510 +    }
 56.3511 +    void visitStringLiteral(StringLiteral *node) {
 56.3512 +        prefix();
 56.3513 +        fprintf(fp_, "[ StringLiteral\n");
 56.3514 +    }
 56.3515 +    void visitIncDecExpression(IncDecExpression *node) {
 56.3516 +        prefix();
 56.3517 +        fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
 56.3518 +        indent();
 56.3519 +        node->expression()->accept(this);
 56.3520 +        unindent();
 56.3521 +    }
 56.3522 +    void visitStructureStatement(StructureStatement *node) {
 56.3523 +        prefix();
 56.3524 +        fprintf(fp_, "[ StructureStatement %s\n", node->name()->chars());
 56.3525 +    }
 56.3526 +    void visitFieldExpression(FieldExpression *node) {
 56.3527 +        prefix();
 56.3528 +        fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars());
 56.3529 +        indent();
 56.3530 +        node->left()->accept(this);
 56.3531 +        unindent();
 56.3532 +    }
 56.3533 +    void visitSwitchStatement(SwitchStatement *node) {
 56.3534 +        prefix();
 56.3535 +        fprintf(fp_, "[ SwitchStatement\n");
 56.3536 +        indent();
 56.3537 +        node->expression()->accept(this);
 56.3538 +        for (size_t i = 0; i < node->cases()->length(); i++) {
 56.3539 +            Case *c = node->cases()->at(i);
 56.3540 +            c->expression()->accept(this);
 56.3541 +            if (c->others()) {
 56.3542 +                for (size_t j = 0; j < c->others()->length(); j++)
 56.3543 +                    c->others()->at(j)->accept(this);
 56.3544 +            }
 56.3545 +            indent();
 56.3546 +            c->statement()->accept(this);
 56.3547 +            unindent();
 56.3548 +        }
 56.3549 +        if (node->defaultCase())
 56.3550 +            node->defaultCase()->accept(this);
 56.3551 +        unindent();
 56.3552 +    }
 56.3553 +    void visitArrayLiteral(ArrayLiteral *node) {
 56.3554 +        prefix();
 56.3555 +        fprintf(fp_, "[ ArrayLiteral\n");
 56.3556 +        indent();
 56.3557 +        for (size_t i = 0; i < node->expressions()->length(); i++) {
 56.3558 +            Expression *expr = node->expressions()->at(i);
 56.3559 +            indent();
 56.3560 +            expr->accept(this);
 56.3561 +            unindent();
 56.3562 +        }
 56.3563 +    }
 56.3564 +    void visitImportStatement(ImportStatement *node) {
 56.3565 +        prefix();
 56.3566 +        fprintf(fp_, "[ ImportStatement\n");
 56.3567 +    }
 56.3568 +};
 56.3569 +
 56.3570 +void
 56.3571 +ParseTree::dump(FILE *fp)
 56.3572 +{
 56.3573 +    AstPrinter printer(fp);
 56.3574 +
 56.3575 +    for (size_t i = 0; i < statements_->length(); i++)
 56.3576 +        statements_->at(i)->accept(&printer);
 56.3577 +}
    57.1 --- a/src/compiler/Parser.h	Mon Jun 10 00:46:29 2013 +0100
    57.2 +++ b/src/compiler/Parser.h	Mon Jun 10 01:04:43 2013 +0100
    57.3 @@ -1,106 +1,106 @@
    57.4 -/* vim: set ts=4 sw=4 tw=99 et:
    57.5 - *
    57.6 - * Copyright (C) 2012 David Anderson
    57.7 - *
    57.8 - * This file is part of SourcePawn.
    57.9 - *
   57.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   57.11 - * the terms of the GNU General Public License as published by the Free
   57.12 - * Software Foundation, either version 3 of the License, or (at your option)
   57.13 - * any later version.
   57.14 - * 
   57.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   57.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   57.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   57.18 - *
   57.19 - * You should have received a copy of the GNU General Public License along with
   57.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   57.21 - */
   57.22 -#ifndef _include_jitcraft_parser_h_
   57.23 -#define _include_jitcraft_parser_h_
   57.24 -
   57.25 -#include <stdio.h>
   57.26 -#include "../Strings.h"
   57.27 -#include "AST.h"
   57.28 -#include "Scanner.h"
   57.29 -#include "Scopes.h"
   57.30 -
   57.31 -namespace ke {
   57.32 -
   57.33 -class Parser
   57.34 -{
   57.35 -    Zone *zone_;
   57.36 -    CompileContext &cc_;
   57.37 -    PoolAllocator &pool_;
   57.38 -    Scanner scanner_;
   57.39 -    PoolList<NameProxy *> *unbound_;
   57.40 -    PoolList<ImportStatement *> *imports_;
   57.41 -    bool encounteredReturn_;
   57.42 -
   57.43 -  private:
   57.44 -    bool peek(TokenKind kind);
   57.45 -    bool match(TokenKind kind);
   57.46 -    bool expect(TokenKind kind);
   57.47 -    bool matchSemicolon();
   57.48 -
   57.49 -    enum DeclKind {
   57.50 -        DeclArg,
   57.51 -        DeclFun,
   57.52 -        DeclField
   57.53 -    };
   57.54 -
   57.55 -    VariableDeclaration *var(TypeQualifiers qual);
   57.56 -    Statement *vars(TypeQualifiers qual);
   57.57 -    bool matchName(String **name, TokenKind kind = TOK_NAME);
   57.58 -    bool typeAndName(Expression **type, String **namep);
   57.59 -    bool fullTypeAndName(Expression **type, String **namep, DeclKind kind);
   57.60 -
   57.61 -    ExpressionList *dimensions();
   57.62 -    String *expectName();
   57.63 -
   57.64 -    Expression *primitive();
   57.65 -    Expression *fixedArrayLiteral();
   57.66 -    Expression *call(Expression *callee);
   57.67 -    Expression *field(Expression *left);
   57.68 -    Expression *index(Expression *left);
   57.69 -    Expression *prefix();
   57.70 -    Expression *primary();
   57.71 -    Expression *unary();
   57.72 -    Expression *multiplication();
   57.73 -    Expression *addition();
   57.74 -    Expression *shift();
   57.75 -    Expression *bitand_();
   57.76 -    Expression *bitxor();
   57.77 -    Expression *bitor_();
   57.78 -    Expression *relational();
   57.79 -    Expression *equals();
   57.80 -    Expression *and_();
   57.81 -    Expression *or_();
   57.82 -    Expression *ternary();
   57.83 -    Expression *assignment();
   57.84 -    Expression *expression();
   57.85 -
   57.86 -    Statement *switch_();
   57.87 -    Statement *struct_();
   57.88 -    Statement *enum_(TokenKind kind);
   57.89 -    Statement *if_();
   57.90 -    Statement *block();
   57.91 -    Statement *function(TokenKind tok);
   57.92 -    Statement *expressionStatement();
   57.93 -    Statement *while_();
   57.94 -    Statement *do_();
   57.95 -    Statement *forStatement();
   57.96 -    Statement *localStatement();
   57.97 -    Statement *globalStatement();
   57.98 -    Statement *returnStatement();
   57.99 -    ImportStatement *import(TokenKind kind);
  57.100 -
  57.101 -  public:
  57.102 -    Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
  57.103 -
  57.104 -    ParseTree *parse();
  57.105 -};
  57.106 -
  57.107 -}
  57.108 -
  57.109 -#endif // _include_jitcraft_parser_h_
  57.110 +/* vim: set ts=4 sw=4 tw=99 et:
  57.111 + *
  57.112 + * Copyright (C) 2012 David Anderson
  57.113 + *
  57.114 + * This file is part of SourcePawn.
  57.115 + *
  57.116 + * SourcePawn is free software: you can redistribute it and/or modify it under
  57.117 + * the terms of the GNU General Public License as published by the Free
  57.118 + * Software Foundation, either version 3 of the License, or (at your option)
  57.119 + * any later version.
  57.120 + * 
  57.121 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  57.122 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  57.123 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  57.124 + *
  57.125 + * You should have received a copy of the GNU General Public License along with
  57.126 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  57.127 + */
  57.128 +#ifndef _include_jitcraft_parser_h_
  57.129 +#define _include_jitcraft_parser_h_
  57.130 +
  57.131 +#include <stdio.h>
  57.132 +#include "../Strings.h"
  57.133 +#include "AST.h"
  57.134 +#include "Scanner.h"
  57.135 +#include "Scopes.h"
  57.136 +
  57.137 +namespace ke {
  57.138 +
  57.139 +class Parser
  57.140 +{
  57.141 +    Zone *zone_;
  57.142 +    CompileContext &cc_;
  57.143 +    PoolAllocator &pool_;
  57.144 +    Scanner scanner_;
  57.145 +    PoolList<NameProxy *> *unbound_;
  57.146 +    PoolList<ImportStatement *> *imports_;
  57.147 +    bool encounteredReturn_;
  57.148 +
  57.149 +  private:
  57.150 +    bool peek(TokenKind kind);
  57.151 +    bool match(TokenKind kind);
  57.152 +    bool expect(TokenKind kind);
  57.153 +    bool matchSemicolon();
  57.154 +
  57.155 +    enum DeclKind {
  57.156 +        DeclArg,
  57.157 +        DeclFun,
  57.158 +        DeclField
  57.159 +    };
  57.160 +
  57.161 +    VariableDeclaration *var(TypeQualifiers qual);
  57.162 +    Statement *vars(TypeQualifiers qual);
  57.163 +    bool matchName(String **name, TokenKind kind = TOK_NAME);
  57.164 +    bool typeAndName(Expression **type, String **namep);
  57.165 +    bool fullTypeAndName(Expression **type, String **namep, DeclKind kind);
  57.166 +
  57.167 +    ExpressionList *dimensions();
  57.168 +    String *expectName();
  57.169 +
  57.170 +    Expression *primitive();
  57.171 +    Expression *fixedArrayLiteral();
  57.172 +    Expression *call(Expression *callee);
  57.173 +    Expression *field(Expression *left);
  57.174 +    Expression *index(Expression *left);
  57.175 +    Expression *prefix();
  57.176 +    Expression *primary();
  57.177 +    Expression *unary();
  57.178 +    Expression *multiplication();
  57.179 +    Expression *addition();
  57.180 +    Expression *shift();
  57.181 +    Expression *bitand_();
  57.182 +    Expression *bitxor();
  57.183 +    Expression *bitor_();
  57.184 +    Expression *relational();
  57.185 +    Expression *equals();
  57.186 +    Expression *and_();
  57.187 +    Expression *or_();
  57.188 +    Expression *ternary();
  57.189 +    Expression *assignment();
  57.190 +    Expression *expression();
  57.191 +
  57.192 +    Statement *switch_();
  57.193 +    Statement *struct_();
  57.194 +    Statement *enum_(TokenKind kind);
  57.195 +    Statement *if_();
  57.196 +    Statement *block();
  57.197 +    Statement *function(TokenKind tok);
  57.198 +    Statement *expressionStatement();
  57.199 +    Statement *while_();
  57.200 +    Statement *do_();
  57.201 +    Statement *forStatement();
  57.202 +    Statement *localStatement();
  57.203 +    Statement *globalStatement();
  57.204 +    Statement *returnStatement();
  57.205 +    ImportStatement *import(TokenKind kind);
  57.206 +
  57.207 +  public:
  57.208 +    Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
  57.209 +
  57.210 +    ParseTree *parse();
  57.211 +};
  57.212 +
  57.213 +}
  57.214 +
  57.215 +#endif // _include_jitcraft_parser_h_
    58.1 --- a/src/compiler/Scanner.cpp	Mon Jun 10 00:46:29 2013 +0100
    58.2 +++ b/src/compiler/Scanner.cpp	Mon Jun 10 01:04:43 2013 +0100
    58.3 @@ -1,685 +1,685 @@
    58.4 -/* vim: set ts=4 sw=4 tw=99 et:
    58.5 - *
    58.6 - * Copyright (C) 2012 David Anderson
    58.7 - *
    58.8 - * This file is part of JITCraft.
    58.9 - *
   58.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   58.11 - * the terms of the GNU General Public License as published by the Free
   58.12 - * Software Foundation, either version 3 of the License, or (at your option)
   58.13 - * any later version.
   58.14 - * 
   58.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   58.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   58.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   58.18 - *
   58.19 - * You should have received a copy of the GNU General Public License along with
   58.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   58.21 - */
   58.22 -#include <assert.h>
   58.23 -#include <ctype.h>
   58.24 -#include <math.h>
   58.25 -#include <limits.h>
   58.26 -#include <string.h>
   58.27 -#include "../Utility.h"
   58.28 -#include "../Heap-inl.h"
   58.29 -#include "../Handles-inl.h"
   58.30 -#include "Scanner.h"
   58.31 -
   58.32 -using namespace ke;
   58.33 -
   58.34 -const char *ke::TokenNames[] =
   58.35 -{
   58.36 -#define _(name, str) str,
   58.37 -    TOKENMAP(_)
   58.38 -#undef _
   58.39 -    NULL
   58.40 -};
   58.41 -
   58.42 -Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
   58.43 -  : cc_(cc),
   58.44 -    stream_(stream),
   58.45 -    length_(length),
   58.46 -    pushed_(false),
   58.47 -    allowTags_(true),
   58.48 -    saved_('\0'),
   58.49 -    pos_(stream_)
   58.50 -{
   58.51 -    cur_.line = 1;
   58.52 -    cur_.col = 1;
   58.53 -    last_ = cur_;
   58.54 -}
   58.55 -
   58.56 -char
   58.57 -Scanner::getChar()
   58.58 -{
   58.59 -    if (saved_ != '\0') {
   58.60 -        char temp = saved_;
   58.61 -        saved_ = '\0';
   58.62 -        return temp;
   58.63 -    }
   58.64 -    if (pos_ >= stream_ + length_)
   58.65 -        return '\0';
   58.66 -    last_.col = cur_.col++;
   58.67 -    return *pos_++;
   58.68 -}
   58.69 -
   58.70 -void
   58.71 -Scanner::putChar(char c)
   58.72 -{
   58.73 -    assert(saved_ == '\0');
   58.74 -    saved_ = c;
   58.75 -    cur_.col = last_.col;
   58.76 -}
   58.77 -
   58.78 -void
   58.79 -Scanner::calcNewLine(char c)
   58.80 -{
   58.81 -    cur_.line++;
   58.82 -    cur_.col = 1;
   58.83 -    last_ = cur_;
   58.84 -
   58.85 -    char o;
   58.86 -    if (c == '\r' && ((o = getChar()) != '\n'))
   58.87 -        putChar(o);
   58.88 -}
   58.89 -
   58.90 -void
   58.91 -Scanner::eatSingleLine()
   58.92 -{
   58.93 -    char c;
   58.94 -    while ((c = getChar()) != '\0') {
   58.95 -        if (c == '\n' || c == '\r') {
   58.96 -            calcNewLine(c);
   58.97 -            break;
   58.98 -        }
   58.99 -    }
  58.100 -}
  58.101 -
  58.102 -bool
  58.103 -Scanner::eatComment()
  58.104 -{
  58.105 -    char c;
  58.106 -
  58.107 -    while ((c = getChar()) != '\0') {
  58.108 -        while (c == '*') {
  58.109 -            c = getChar();
  58.110 -            if (c == '\0')
  58.111 -                return false;
  58.112 -            if (c == '/')
  58.113 -                return true;
  58.114 -        }
  58.115 -        if (c == '\r' || c == '\n')
  58.116 -            calcNewLine(c);
  58.117 -    }
  58.118 -
  58.119 -    return false;
  58.120 -}
  58.121 -
  58.122 -static inline bool
  58.123 -IsDigit(char c)
  58.124 -{
  58.125 -    return c >= '0' && c <= '9';
  58.126 -}
  58.127 -
  58.128 -// Based off the logic in sc2.c's ftoi()...
  58.129 -double
  58.130 -Scanner::ParseDouble(const char *string)
  58.131 -{
  58.132 -    const char *ptr = string;
  58.133 -
  58.134 -    double number = 0.0;
  58.135 -    while (IsDigit(*ptr)) {
  58.136 -        number = (number * 10) + (*ptr - '0');
  58.137 -        ptr++;
  58.138 -    }
  58.139 -
  58.140 -    assert(*ptr == '.');
  58.141 -    ptr++;
  58.142 -
  58.143 -    double fraction = 0.0;
  58.144 -    double multiplier = 1.0;
  58.145 -    while (IsDigit(*ptr)) {
  58.146 -        fraction = (fraction * 10) + (*ptr - '0');
  58.147 -        multiplier = multiplier / 10.0;
  58.148 -        ptr++;
  58.149 -    }
  58.150 -
  58.151 -    number += fraction * multiplier;
  58.152 -
  58.153 -    if (*ptr++ == 'e') {
  58.154 -        int sign = 1;
  58.155 -        if (*ptr == '-') {
  58.156 -            sign = -1;
  58.157 -            ptr++;
  58.158 -        }
  58.159 -
  58.160 -        int exponent = 0;
  58.161 -        while (IsDigit(*ptr)) {
  58.162 -            exponent = (exponent * 10) + (*ptr - '0');
  58.163 -            ptr++;
  58.164 -        }
  58.165 -
  58.166 -        multiplier = pow(10.0, exponent * sign);
  58.167 -        number *= multiplier;
  58.168 -    }
  58.169 -
  58.170 -    return number;
  58.171 -}
  58.172 -
  58.173 -static inline bool
  58.174 -IsHexDigit(char c)
  58.175 -{
  58.176 -    return IsDigit(c) ||
  58.177 -           (c >= 'a' && c <= 'f') ||
  58.178 -           (c >= 'A' && c <= 'F');
  58.179 -}
  58.180 -
  58.181 -// Based on the logic for litchar() in sc2.c.
  58.182 -int
  58.183 -Scanner::readEscapeCode()
  58.184 -{
  58.185 -    char c = getChar();
  58.186 -    if (c == '\\')
  58.187 -        return c;
  58.188 -
  58.189 -    switch (c) {
  58.190 -      case 'a':
  58.191 -        return '\a';
  58.192 -      case 'b':
  58.193 -        return '\b';
  58.194 -      case 'e':
  58.195 -        return 27;          // Apparently \e is non-standard.
  58.196 -      case 'f':
  58.197 -        return '\f';
  58.198 -      case 'n':
  58.199 -        return '\n';
  58.200 -      case 'r':
  58.201 -        return '\r';
  58.202 -      case 't':
  58.203 -        return '\t';
  58.204 -      case 'v':
  58.205 -        return '\v';
  58.206 -
  58.207 -      case 'x':
  58.208 -      {
  58.209 -          unsigned digits = 0;
  58.210 -          char r = 0;
  58.211 -  
  58.212 -          c = getChar();
  58.213 -          while (IsHexDigit(c) && digits < 2) {
  58.214 -              if (IsDigit(c))
  58.215 -                  c = (c << 4) + (c - '0');
  58.216 -              else
  58.217 -                  c = (c << 4) + (tolower(c) - 'a' + 10);
  58.218 -              digits++;
  58.219 -              c = getChar();
  58.220 -           }
  58.221 -                
  58.222 -          // Swallow a trailing ';'
  58.223 -          if (c != ';')
  58.224 -              putChar(c);
  58.225 -  
  58.226 -          return r;
  58.227 -      }
  58.228 -
  58.229 -      case '\'':
  58.230 -      case '\"':
  58.231 -      case '%':
  58.232 -        return c;
  58.233 -
  58.234 -      default:
  58.235 -      {
  58.236 -        if (IsDigit(c)) {
  58.237 -            // \ddd
  58.238 -            char r = 0;
  58.239 -            while (IsDigit(c)) {
  58.240 -                r = r * 10 + (c - '0');
  58.241 -                c = getChar();
  58.242 -            }
  58.243 -
  58.244 -            // Swallow a trailing ;
  58.245 -            if (c != ';')
  58.246 -                putChar(c);
  58.247 -
  58.248 -            return r;
  58.249 -        }
  58.250 -        cc_.reportError(begin(), Message_UnknownEscapeCode, c);
  58.251 -        return INT_MAX;
  58.252 -      }
  58.253 -    }
  58.254 -}
  58.255 -
  58.256 -TokenKind
  58.257 -Scanner::stringLiteral()
  58.258 -{
  58.259 -    literal_.clear();
  58.260 -
  58.261 -    for (;;) {
  58.262 -        char c = getChar();
  58.263 -        if (c == '\"')
  58.264 -            break;
  58.265 -        if (c == '\r' || c == '\n' || c == '\0') {
  58.266 -            cc_.reportError(begin(), Message_UnterminatedString);
  58.267 -            return TOK_ERROR;
  58.268 -        }
  58.269 -        if (c == '\\') {
  58.270 -            int code = readEscapeCode();
  58.271 -            if (code == INT_MAX)
  58.272 -                return TOK_ERROR;
  58.273 -            c = char(code);
  58.274 -        }
  58.275 -        if (!literal_.append(c))
  58.276 -            return TOK_ERROR;
  58.277 -    }
  58.278 -
  58.279 -    if (!literal_.append('\0'))
  58.280 -        return TOK_ERROR;
  58.281 -
  58.282 -    return TOK_STRING_LITERAL;
  58.283 -}
  58.284 -
  58.285 -TokenKind
  58.286 -Scanner::hexLiteral()
  58.287 -{
  58.288 -    literal_.clear();
  58.289 -
  58.290 -    char c;
  58.291 -    for (;;) {
  58.292 -        c = getChar();
  58.293 -        if (!IsHexDigit(c))
  58.294 -            break;
  58.295 -        if (!literal_.append(c))
  58.296 -            return TOK_ERROR;
  58.297 -    }
  58.298 -
  58.299 -    putChar(c);
  58.300 -
  58.301 -    if (!literal_.append('\0'))
  58.302 -        return TOK_ERROR;
  58.303 -    return TOK_HEX_LITERAL;
  58.304 -}
  58.305 -
  58.306 -TokenKind
  58.307 -Scanner::numberLiteral(char first)
  58.308 -{
  58.309 -    literal_.clear();
  58.310 -    if (!literal_.append(first))
  58.311 -        return TOK_ERROR;
  58.312 -
  58.313 -    char c;
  58.314 -    for (;;) {
  58.315 -        c = getChar();
  58.316 -        if (!IsDigit(c))
  58.317 -            break;
  58.318 -        if (!literal_.append(c))
  58.319 -            return TOK_ERROR;
  58.320 -    }
  58.321 -
  58.322 -    // Detect a hexadecimal string.
  58.323 -    if (literal_.length() == 1 &&
  58.324 -        literal_[0] == '0' &&
  58.325 -        (c == 'x' || c == 'X'))
  58.326 -    {
  58.327 -        return hexLiteral();
  58.328 -    }
  58.329 -
  58.330 -    if (c != '.') {
  58.331 -        putChar(c);
  58.332 -        if (!literal_.append('\0'))
  58.333 -            return TOK_ERROR;
  58.334 -        return TOK_INTEGER_LITERAL;
  58.335 -    }
  58.336 -    if (!literal_.append(c))
  58.337 -        return TOK_ERROR;
  58.338 -
  58.339 -    c = getChar();
  58.340 -    if (!IsDigit(c)) {
  58.341 -        cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
  58.342 -        return TOK_ERROR;
  58.343 -    }
  58.344 -    if (!literal_.append(c))
  58.345 -        return TOK_ERROR;
  58.346 -
  58.347 -    for (;;) {
  58.348 -        c = getChar();
  58.349 -        if (!IsDigit(c))
  58.350 -            break;
  58.351 -        if (!literal_.append(c))
  58.352 -            return TOK_ERROR;
  58.353 -    }
  58.354 -
  58.355 -    if (c != 'e') {
  58.356 -        putChar(c);
  58.357 -    } else {
  58.358 -        if (!literal_.append(c))
  58.359 -            return TOK_ERROR;
  58.360 -        c = getChar();
  58.361 -        if (c == '-') {
  58.362 -            if (!literal_.append(c))
  58.363 -                return TOK_ERROR;
  58.364 -            c = getChar();
  58.365 -        }
  58.366 -        if (!IsDigit(c)) {
  58.367 -            cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
  58.368 -            return TOK_ERROR;
  58.369 -        }
  58.370 -        if (!literal_.append(c))
  58.371 -            return TOK_ERROR;
  58.372 -        for (;;) {
  58.373 -            c = getChar();
  58.374 -            if (!IsDigit(c)) {
  58.375 -                putChar(c);
  58.376 -                break;
  58.377 -            }
  58.378 -            if (!literal_.append(c))
  58.379 -                return TOK_ERROR;
  58.380 -        }
  58.381 -    }
  58.382 -
  58.383 -    if (!literal_.append('\0'))
  58.384 -        return TOK_ERROR;
  58.385 -
  58.386 -    return TOK_FLOAT_LITERAL;
  58.387 -}
  58.388 -
  58.389 -static inline TokenKind
  58.390 -FindIdentifier(const char *str)
  58.391 -{
  58.392 -    if (!strcmp(str,  "new"))
  58.393 -        return TOK_NEW;
  58.394 -    if (!strcmp(str,  "for"))
  58.395 -        return TOK_FOR;
  58.396 -    if (!strcmp(str,  "return"))
  58.397 -        return TOK_RETURN;
  58.398 -    if (!strcmp(str,  "if"))
  58.399 -        return TOK_IF;
  58.400 -    if (!strcmp(str,  "else"))
  58.401 -        return TOK_ELSE;
  58.402 -    if (!strcmp(str,  "enum"))
  58.403 -        return TOK_ENUM;
  58.404 -    if (!strcmp(str,  "while"))
  58.405 -        return TOK_WHILE;
  58.406 -    if (!strcmp(str,  "do"))
  58.407 -        return TOK_DO;
  58.408 -    if (!strcmp(str,  "break"))
  58.409 -        return TOK_BREAK;
  58.410 -    if (!strcmp(str,  "continue"))
  58.411 -        return TOK_CONTINUE;
  58.412 -    if (!strcmp(str,  "forward"))
  58.413 -        return TOK_FORWARD;
  58.414 -    if (!strcmp(str,  "public"))
  58.415 -        return TOK_PUBLIC;
  58.416 -    if (!strcmp(str,  "const"))
  58.417 -        return TOK_CONST;
  58.418 -    if (!strcmp(str,  "native"))
  58.419 -        return TOK_NATIVE;
  58.420 -    if (!strcmp(str,  "stock"))
  58.421 -        return TOK_STOCK;
  58.422 -    if (!strcmp(str,  "true"))
  58.423 -        return TOK_TRUE;
  58.424 -    if (!strcmp(str,  "false"))
  58.425 -        return TOK_FALSE;
  58.426 -    if (!strcmp(str,  "struct"))
  58.427 -        return TOK_STRUCT;
  58.428 -    if (!strcmp(str,  "switch"))
  58.429 -        return TOK_SWITCH;
  58.430 -    if (!strcmp(str,  "case"))
  58.431 -        return TOK_CASE;
  58.432 -    if (!strcmp(str,  "default"))
  58.433 -        return TOK_DEFAULT;
  58.434 -    if (!strcmp(str,  "typedef"))
  58.435 -        return TOK_TYPEDEF;
  58.436 -    if (!strcmp(str,  "void"))
  58.437 -        return TOK_VOID;
  58.438 -    if (!strcmp(str,  "int"))
  58.439 -        return TOK_INT;
  58.440 -    if (!strcmp(str,  "sizeof"))
  58.441 -        return TOK_SIZEOF;
  58.442 -    if (!strcmp(str,  "import"))
  58.443 -        return TOK_IMPORT;
  58.444 -    if (!strcmp(str,  "from"))
  58.445 -        return TOK_FROM;
  58.446 -    return TOK_NONE;
  58.447 -}
  58.448 -
  58.449 -TokenKind
  58.450 -Scanner::identifier(char first)
  58.451 -{
  58.452 -    literal_.clear();
  58.453 -    if (!literal_.append(first))
  58.454 -        return TOK_ERROR;
  58.455 -
  58.456 -    char c;
  58.457 -    for (;;) {
  58.458 -        c = getChar();
  58.459 -        if (!isascii(c) || (!isalnum(c) && c != '_'))
  58.460 -            break;
  58.461 -        if (!literal_.append(c))
  58.462 -            return TOK_ERROR;
  58.463 -    }
  58.464 -    
  58.465 -    if (!literal_.append('\0'))
  58.466 -        return TOK_ERROR;
  58.467 -
  58.468 -    // Most keywords do not act as labels.
  58.469 -    TokenKind kind = FindIdentifier(literal());
  58.470 -    if (kind != TOK_NONE) {
  58.471 -        putChar(c);
  58.472 -        return kind;
  58.473 -    }
  58.474 -
  58.475 -    if (c == ':' && allowTags_)
  58.476 -        return TOK_LABEL;
  58.477 -
  58.478 -    putChar(c);
  58.479 -
  58.480 -    // _ is a special case which acts as a tag and a keyword.
  58.481 -    if (!strcmp(literal(), "_"))
  58.482 -        return TOK_UNDERSCORE;
  58.483 -
  58.484 -    return TOK_NAME;
  58.485 -}
  58.486 -
  58.487 -TokenKind
  58.488 -Scanner::next()
  58.489 -{
  58.490 -    assert(!pushed_);
  58.491 -
  58.492 -    for (;;) {
  58.493 -        begin_ = cur_;
  58.494 -
  58.495 -        char c = getChar();
  58.496 -        switch (c) {
  58.497 -          case '/':
  58.498 -          {
  58.499 -            c = getChar();
  58.500 -            if (c == '/') {
  58.501 -                eatSingleLine();
  58.502 -                break;
  58.503 -            }
  58.504 -            if (c == '*') {
  58.505 -                if (!eatComment()) {
  58.506 -                    cc_.reportError(begin(), Message_UnterminatedComment);
  58.507 -                    return TOK_ERROR;
  58.508 -                }
  58.509 -                break;
  58.510 -            }
  58.511 -            putChar(c);
  58.512 -            return TOK_SLASH;
  58.513 -          }
  58.514 -
  58.515 -          case '\n':
  58.516 -          case '\r':
  58.517 -            calcNewLine(c);
  58.518 -            break;
  58.519 -
  58.520 -          case ';': return TOK_SEMICOLON;
  58.521 -          case '{': return TOK_LBRACE;
  58.522 -          case '}': return TOK_RBRACE;
  58.523 -          case '(': return TOK_LPAREN;
  58.524 -          case ')': return TOK_RPAREN;
  58.525 -          case '[': return TOK_LBRACKET;
  58.526 -          case ']': return TOK_RBRACKET;
  58.527 -          case '~': return TOK_TILDE;
  58.528 -          case '?': return TOK_QMARK;
  58.529 -          case ':': return TOK_COLON;
  58.530 -
  58.531 -          case '.':
  58.532 -            c = getChar();
  58.533 -            if (c == '.') {
  58.534 -                c = getChar();
  58.535 -                if (c == '.')
  58.536 -                    return TOK_ELLIPSES;
  58.537 -                cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
  58.538 -                return TOK_ERROR;
  58.539 -            }
  58.540 -            putChar(c);
  58.541 -            return TOK_DOT;
  58.542 -
  58.543 -          case '*':
  58.544 -            c = getChar();
  58.545 -            if (c == '=')
  58.546 -                return TOK_ASSIGN_MUL;
  58.547 -            putChar(c);
  58.548 -            return TOK_STAR;
  58.549 -
  58.550 -          case '+':
  58.551 -            c = getChar();
  58.552 -            if (c == '=')
  58.553 -                return TOK_ASSIGN_ADD;
  58.554 -            if (c == '+')
  58.555 -                return TOK_INCREMENT;
  58.556 -            putChar(c);
  58.557 -            return TOK_PLUS;
  58.558 -
  58.559 -          case '&':
  58.560 -            c = getChar();
  58.561 -            if (c == '=')
  58.562 -                return TOK_ASSIGN_BITAND;
  58.563 -            if (c == '&')
  58.564 -                return TOK_AND;
  58.565 -            putChar(c);
  58.566 -            return TOK_BITAND;
  58.567 -
  58.568 -          case '|':
  58.569 -            c = getChar();
  58.570 -            if (c == '=')
  58.571 -                return TOK_ASSIGN_BITOR;
  58.572 -            if (c == '|')
  58.573 -                return TOK_OR;
  58.574 -            putChar(c);
  58.575 -            return TOK_BITOR;
  58.576 -
  58.577 -          case '^':
  58.578 -            c = getChar();
  58.579 -            if (c == '=')
  58.580 -                return TOK_ASSIGN_BITXOR;
  58.581 -            putChar(c);
  58.582 -            return TOK_BITXOR;
  58.583 -
  58.584 -          case '%':
  58.585 -            c = getChar();
  58.586 -            if (c == '=')
  58.587 -                return TOK_ASSIGN_MOD;
  58.588 -            putChar(c);
  58.589 -            return TOK_PERCENT;
  58.590 -
  58.591 -          case '-':
  58.592 -            c = getChar();
  58.593 -            if (c == '=')
  58.594 -                return TOK_ASSIGN_SUB;
  58.595 -            if (c == '-')
  58.596 -                return TOK_DECREMENT;
  58.597 -            putChar(c);
  58.598 -            return TOK_MINUS;
  58.599 -
  58.600 -          case ',': return TOK_COMMA;
  58.601 -          case '\0': return TOK_EOF;
  58.602 -
  58.603 -          case '!':
  58.604 -            c = getChar();
  58.605 -            if (c == '=')
  58.606 -                return TOK_NOTEQUALS;
  58.607 -            putChar(c);
  58.608 -            return TOK_NOT;
  58.609 -
  58.610 -          case '=':
  58.611 -            c = getChar();
  58.612 -            if (c == '=')
  58.613 -                return TOK_EQUALS;
  58.614 -            putChar(c);
  58.615 -            return TOK_ASSIGN;
  58.616 -
  58.617 -
  58.618 -          case '<':
  58.619 -            c = getChar();
  58.620 -            if (c == '=')
  58.621 -                return TOK_LE;
  58.622 -            if (c == '<') {
  58.623 -                c = getChar();
  58.624 -                if (c == '=')
  58.625 -                    return TOK_ASSIGN_SHL;
  58.626 -                putChar(c);
  58.627 -                return TOK_SHL;
  58.628 -            }
  58.629 -            putChar(c);
  58.630 -            return TOK_LT;
  58.631 -
  58.632 -          case '>':
  58.633 -            c = getChar();
  58.634 -            if (c == '=')
  58.635 -                return TOK_GE;
  58.636 -            if (c == '>') {
  58.637 -                c = getChar();
  58.638 -                if (c == '>') {
  58.639 -                    c = getChar();
  58.640 -                    if (c == '=')
  58.641 -                        return TOK_ASSIGN_USHR;
  58.642 -                    putChar(c);
  58.643 -                    return TOK_USHR;
  58.644 -                }
  58.645 -                return TOK_SHR;
  58.646 -            }
  58.647 -            putChar(c);
  58.648 -            return TOK_GT;
  58.649 -
  58.650 -          case ' ':
  58.651 -          case '\t':
  58.652 -          case '\f':
  58.653 -            break;
  58.654 -
  58.655 -          case '"':
  58.656 -            return stringLiteral();
  58.657 -
  58.658 -          default:
  58.659 -            if (c >= '0' && c <= '9')
  58.660 -                return numberLiteral(c);
  58.661 -            if (c == '_' || (isascii(c) && isalpha(c)))
  58.662 -                return identifier(c);
  58.663 -            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
  58.664 -            return TOK_ERROR;
  58.665 -        }
  58.666 -    }
  58.667 -}
  58.668 -
  58.669 -TokenKind
  58.670 -Scanner::scan()
  58.671 -{
  58.672 -    if (pushed_) {
  58.673 -        pushed_ = false;
  58.674 -        return lastToken_;
  58.675 -    }
  58.676 -    lastToken_ = next();
  58.677 -    return lastToken_;
  58.678 -}
  58.679 -
  58.680 -TokenKind
  58.681 -Scanner::peek()
  58.682 -{
  58.683 -    if (pushed_)
  58.684 -        return lastToken_;
  58.685 -    scan();
  58.686 -    pushed_ = true;
  58.687 -    return lastToken_;
  58.688 -}
  58.689 +/* vim: set ts=4 sw=4 tw=99 et:
  58.690 + *
  58.691 + * Copyright (C) 2012 David Anderson
  58.692 + *
  58.693 + * This file is part of JITCraft.
  58.694 + *
  58.695 + * JITCraft is free software: you can redistribute it and/or modify it under
  58.696 + * the terms of the GNU General Public License as published by the Free
  58.697 + * Software Foundation, either version 3 of the License, or (at your option)
  58.698 + * any later version.
  58.699 + * 
  58.700 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  58.701 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  58.702 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  58.703 + *
  58.704 + * You should have received a copy of the GNU General Public License along with
  58.705 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  58.706 + */
  58.707 +#include <assert.h>
  58.708 +#include <ctype.h>
  58.709 +#include <math.h>
  58.710 +#include <limits.h>
  58.711 +#include <string.h>
  58.712 +#include "../Utility.h"
  58.713 +#include "../Heap-inl.h"
  58.714 +#include "../Handles-inl.h"
  58.715 +#include "Scanner.h"
  58.716 +
  58.717 +using namespace ke;
  58.718 +
  58.719 +const char *ke::TokenNames[] =
  58.720 +{
  58.721 +#define _(name, str) str,
  58.722 +    TOKENMAP(_)
  58.723 +#undef _
  58.724 +    NULL
  58.725 +};
  58.726 +
  58.727 +Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
  58.728 +  : cc_(cc),
  58.729 +    stream_(stream),
  58.730 +    length_(length),
  58.731 +    pushed_(false),
  58.732 +    allowTags_(true),
  58.733 +    saved_('\0'),
  58.734 +    pos_(stream_)
  58.735 +{
  58.736 +    cur_.line = 1;
  58.737 +    cur_.col = 1;
  58.738 +    last_ = cur_;
  58.739 +}
  58.740 +
  58.741 +char
  58.742 +Scanner::getChar()
  58.743 +{
  58.744 +    if (saved_ != '\0') {
  58.745 +        char temp = saved_;
  58.746 +        saved_ = '\0';
  58.747 +        return temp;
  58.748 +    }
  58.749 +    if (pos_ >= stream_ + length_)
  58.750 +        return '\0';
  58.751 +    last_.col = cur_.col++;
  58.752 +    return *pos_++;
  58.753 +}
  58.754 +
  58.755 +void
  58.756 +Scanner::putChar(char c)
  58.757 +{
  58.758 +    assert(saved_ == '\0');
  58.759 +    saved_ = c;
  58.760 +    cur_.col = last_.col;
  58.761 +}
  58.762 +
  58.763 +void
  58.764 +Scanner::calcNewLine(char c)
  58.765 +{
  58.766 +    cur_.line++;
  58.767 +    cur_.col = 1;
  58.768 +    last_ = cur_;
  58.769 +
  58.770 +    char o;
  58.771 +    if (c == '\r' && ((o = getChar()) != '\n'))
  58.772 +        putChar(o);
  58.773 +}
  58.774 +
  58.775 +void
  58.776 +Scanner::eatSingleLine()
  58.777 +{
  58.778 +    char c;
  58.779 +    while ((c = getChar()) != '\0') {
  58.780 +        if (c == '\n' || c == '\r') {
  58.781 +            calcNewLine(c);
  58.782 +            break;
  58.783 +        }
  58.784 +    }
  58.785 +}
  58.786 +
  58.787 +bool
  58.788 +Scanner::eatComment()
  58.789 +{
  58.790 +    char c;
  58.791 +
  58.792 +    while ((c = getChar()) != '\0') {
  58.793 +        while (c == '*') {
  58.794 +            c = getChar();
  58.795 +            if (c == '\0')
  58.796 +                return false;
  58.797 +            if (c == '/')
  58.798 +                return true;
  58.799 +        }
  58.800 +        if (c == '\r' || c == '\n')
  58.801 +            calcNewLine(c);
  58.802 +    }
  58.803 +
  58.804 +    return false;
  58.805 +}
  58.806 +
  58.807 +static inline bool
  58.808 +IsDigit(char c)
  58.809 +{
  58.810 +    return c >= '0' && c <= '9';
  58.811 +}
  58.812 +
  58.813 +// Based off the logic in sc2.c's ftoi()...
  58.814 +double
  58.815 +Scanner::ParseDouble(const char *string)
  58.816 +{
  58.817 +    const char *ptr = string;
  58.818 +
  58.819 +    double number = 0.0;
  58.820 +    while (IsDigit(*ptr)) {
  58.821 +        number = (number * 10) + (*ptr - '0');
  58.822 +        ptr++;
  58.823 +    }
  58.824 +
  58.825 +    assert(*ptr == '.');
  58.826 +    ptr++;
  58.827 +
  58.828 +    double fraction = 0.0;
  58.829 +    double multiplier = 1.0;
  58.830 +    while (IsDigit(*ptr)) {
  58.831 +        fraction = (fraction * 10) + (*ptr - '0');
  58.832 +        multiplier = multiplier / 10.0;
  58.833 +        ptr++;
  58.834 +    }
  58.835 +
  58.836 +    number += fraction * multiplier;
  58.837 +
  58.838 +    if (*ptr++ == 'e') {
  58.839 +        int sign = 1;
  58.840 +        if (*ptr == '-') {
  58.841 +            sign = -1;
  58.842 +            ptr++;
  58.843 +        }
  58.844 +
  58.845 +        int exponent = 0;
  58.846 +        while (IsDigit(*ptr)) {
  58.847 +            exponent = (exponent * 10) + (*ptr - '0');
  58.848 +            ptr++;
  58.849 +        }
  58.850 +
  58.851 +        multiplier = pow(10.0, exponent * sign);
  58.852 +        number *= multiplier;
  58.853 +    }
  58.854 +
  58.855 +    return number;
  58.856 +}
  58.857 +
  58.858 +static inline bool
  58.859 +IsHexDigit(char c)
  58.860 +{
  58.861 +    return IsDigit(c) ||
  58.862 +           (c >= 'a' && c <= 'f') ||
  58.863 +           (c >= 'A' && c <= 'F');
  58.864 +}
  58.865 +
  58.866 +// Based on the logic for litchar() in sc2.c.
  58.867 +int
  58.868 +Scanner::readEscapeCode()
  58.869 +{
  58.870 +    char c = getChar();
  58.871 +    if (c == '\\')
  58.872 +        return c;
  58.873 +
  58.874 +    switch (c) {
  58.875 +      case 'a':
  58.876 +        return '\a';
  58.877 +      case 'b':
  58.878 +        return '\b';
  58.879 +      case 'e':
  58.880 +        return 27;          // Apparently \e is non-standard.
  58.881 +      case 'f':
  58.882 +        return '\f';
  58.883 +      case 'n':
  58.884 +        return '\n';
  58.885 +      case 'r':
  58.886 +        return '\r';
  58.887 +      case 't':
  58.888 +        return '\t';
  58.889 +      case 'v':
  58.890 +        return '\v';
  58.891 +
  58.892 +      case 'x':
  58.893 +      {
  58.894 +          unsigned digits = 0;
  58.895 +          char r = 0;
  58.896 +  
  58.897 +          c = getChar();
  58.898 +          while (IsHexDigit(c) && digits < 2) {
  58.899 +              if (IsDigit(c))
  58.900 +                  c = (c << 4) + (c - '0');
  58.901 +              else
  58.902 +                  c = (c << 4) + (tolower(c) - 'a' + 10);
  58.903 +              digits++;
  58.904 +              c = getChar();
  58.905 +           }
  58.906 +                
  58.907 +          // Swallow a trailing ';'
  58.908 +          if (c != ';')
  58.909 +              putChar(c);
  58.910 +  
  58.911 +          return r;
  58.912 +      }
  58.913 +
  58.914 +      case '\'':
  58.915 +      case '\"':
  58.916 +      case '%':
  58.917 +        return c;
  58.918 +
  58.919 +      default:
  58.920 +      {
  58.921 +        if (IsDigit(c)) {
  58.922 +            // \ddd
  58.923 +            char r = 0;
  58.924 +            while (IsDigit(c)) {
  58.925 +                r = r * 10 + (c - '0');
  58.926 +                c = getChar();
  58.927 +            }
  58.928 +
  58.929 +            // Swallow a trailing ;
  58.930 +            if (c != ';')
  58.931 +                putChar(c);
  58.932 +
  58.933 +            return r;
  58.934 +        }
  58.935 +        cc_.reportError(begin(), Message_UnknownEscapeCode, c);
  58.936 +        return INT_MAX;
  58.937 +      }
  58.938 +    }
  58.939 +}
  58.940 +
  58.941 +TokenKind
  58.942 +Scanner::stringLiteral()
  58.943 +{
  58.944 +    literal_.clear();
  58.945 +
  58.946 +    for (;;) {
  58.947 +        char c = getChar();
  58.948 +        if (c == '\"')
  58.949 +            break;
  58.950 +        if (c == '\r' || c == '\n' || c == '\0') {
  58.951 +            cc_.reportError(begin(), Message_UnterminatedString);
  58.952 +            return TOK_ERROR;
  58.953 +        }
  58.954 +        if (c == '\\') {
  58.955 +            int code = readEscapeCode();
  58.956 +            if (code == INT_MAX)
  58.957 +                return TOK_ERROR;
  58.958 +            c = char(code);
  58.959 +        }
  58.960 +        if (!literal_.append(c))
  58.961 +            return TOK_ERROR;
  58.962 +    }
  58.963 +
  58.964 +    if (!literal_.append('\0'))
  58.965 +        return TOK_ERROR;
  58.966 +
  58.967 +    return TOK_STRING_LITERAL;
  58.968 +}
  58.969 +
  58.970 +TokenKind
  58.971 +Scanner::hexLiteral()
  58.972 +{
  58.973 +    literal_.clear();
  58.974 +
  58.975 +    char c;
  58.976 +    for (;;) {
  58.977 +        c = getChar();
  58.978 +        if (!IsHexDigit(c))
  58.979 +            break;
  58.980 +        if (!literal_.append(c))
  58.981 +            return TOK_ERROR;
  58.982 +    }
  58.983 +
  58.984 +    putChar(c);
  58.985 +
  58.986 +    if (!literal_.append('\0'))
  58.987 +        return TOK_ERROR;
  58.988 +    return TOK_HEX_LITERAL;
  58.989 +}
  58.990 +
  58.991 +TokenKind
  58.992 +Scanner::numberLiteral(char first)
  58.993 +{
  58.994 +    literal_.clear();
  58.995 +    if (!literal_.append(first))
  58.996 +        return TOK_ERROR;
  58.997 +
  58.998 +    char c;
  58.999 +    for (;;) {
 58.1000 +        c = getChar();
 58.1001 +        if (!IsDigit(c))
 58.1002 +            break;
 58.1003 +        if (!literal_.append(c))
 58.1004 +            return TOK_ERROR;
 58.1005 +    }
 58.1006 +
 58.1007 +    // Detect a hexadecimal string.
 58.1008 +    if (literal_.length() == 1 &&
 58.1009 +        literal_[0] == '0' &&
 58.1010 +        (c == 'x' || c == 'X'))
 58.1011 +    {
 58.1012 +        return hexLiteral();
 58.1013 +    }
 58.1014 +
 58.1015 +    if (c != '.') {
 58.1016 +        putChar(c);
 58.1017 +        if (!literal_.append('\0'))
 58.1018 +            return TOK_ERROR;
 58.1019 +        return TOK_INTEGER_LITERAL;
 58.1020 +    }
 58.1021 +    if (!literal_.append(c))
 58.1022 +        return TOK_ERROR;
 58.1023 +
 58.1024 +    c = getChar();
 58.1025 +    if (!IsDigit(c)) {
 58.1026 +        cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
 58.1027 +        return TOK_ERROR;
 58.1028 +    }
 58.1029 +    if (!literal_.append(c))
 58.1030 +        return TOK_ERROR;
 58.1031 +
 58.1032 +    for (;;) {
 58.1033 +        c = getChar();
 58.1034 +        if (!IsDigit(c))
 58.1035 +            break;
 58.1036 +        if (!literal_.append(c))
 58.1037 +            return TOK_ERROR;
 58.1038 +    }
 58.1039 +
 58.1040 +    if (c != 'e') {
 58.1041 +        putChar(c);
 58.1042 +    } else {
 58.1043 +        if (!literal_.append(c))
 58.1044 +            return TOK_ERROR;
 58.1045 +        c = getChar();
 58.1046 +        if (c == '-') {
 58.1047 +            if (!literal_.append(c))
 58.1048 +                return TOK_ERROR;
 58.1049 +            c = getChar();
 58.1050 +        }
 58.1051 +        if (!IsDigit(c)) {
 58.1052 +            cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
 58.1053 +            return TOK_ERROR;
 58.1054 +        }
 58.1055 +        if (!literal_.append(c))
 58.1056 +            return TOK_ERROR;
 58.1057 +        for (;;) {
 58.1058 +            c = getChar();
 58.1059 +            if (!IsDigit(c)) {
 58.1060 +                putChar(c);
 58.1061 +                break;
 58.1062 +            }
 58.1063 +            if (!literal_.append(c))
 58.1064 +                return TOK_ERROR;
 58.1065 +        }
 58.1066 +    }
 58.1067 +
 58.1068 +    if (!literal_.append('\0'))
 58.1069 +        return TOK_ERROR;
 58.1070 +
 58.1071 +    return TOK_FLOAT_LITERAL;
 58.1072 +}
 58.1073 +
 58.1074 +static inline TokenKind
 58.1075 +FindIdentifier(const char *str)
 58.1076 +{
 58.1077 +    if (!strcmp(str,  "new"))
 58.1078 +        return TOK_NEW;
 58.1079 +    if (!strcmp(str,  "for"))
 58.1080 +        return TOK_FOR;
 58.1081 +    if (!strcmp(str,  "return"))
 58.1082 +        return TOK_RETURN;
 58.1083 +    if (!strcmp(str,  "if"))
 58.1084 +        return TOK_IF;
 58.1085 +    if (!strcmp(str,  "else"))
 58.1086 +        return TOK_ELSE;
 58.1087 +    if (!strcmp(str,  "enum"))
 58.1088 +        return TOK_ENUM;
 58.1089 +    if (!strcmp(str,  "while"))
 58.1090 +        return TOK_WHILE;
 58.1091 +    if (!strcmp(str,  "do"))
 58.1092 +        return TOK_DO;
 58.1093 +    if (!strcmp(str,  "break"))
 58.1094 +        return TOK_BREAK;
 58.1095 +    if (!strcmp(str,  "continue"))
 58.1096 +        return TOK_CONTINUE;
 58.1097 +    if (!strcmp(str,  "forward"))
 58.1098 +        return TOK_FORWARD;
 58.1099 +    if (!strcmp(str,  "public"))
 58.1100 +        return TOK_PUBLIC;
 58.1101 +    if (!strcmp(str,  "const"))
 58.1102 +        return TOK_CONST;
 58.1103 +    if (!strcmp(str,  "native"))
 58.1104 +        return TOK_NATIVE;
 58.1105 +    if (!strcmp(str,  "stock"))
 58.1106 +        return TOK_STOCK;
 58.1107 +    if (!strcmp(str,  "true"))
 58.1108 +        return TOK_TRUE;
 58.1109 +    if (!strcmp(str,  "false"))
 58.1110 +        return TOK_FALSE;
 58.1111 +    if (!strcmp(str,  "struct"))
 58.1112 +        return TOK_STRUCT;
 58.1113 +    if (!strcmp(str,  "switch"))
 58.1114 +        return TOK_SWITCH;
 58.1115 +    if (!strcmp(str,  "case"))
 58.1116 +        return TOK_CASE;
 58.1117 +    if (!strcmp(str,  "default"))
 58.1118 +        return TOK_DEFAULT;
 58.1119 +    if (!strcmp(str,  "typedef"))
 58.1120 +        return TOK_TYPEDEF;
 58.1121 +    if (!strcmp(str,  "void"))
 58.1122 +        return TOK_VOID;
 58.1123 +    if (!strcmp(str,  "int"))
 58.1124 +        return TOK_INT;
 58.1125 +    if (!strcmp(str,  "sizeof"))
 58.1126 +        return TOK_SIZEOF;
 58.1127 +    if (!strcmp(str,  "import"))
 58.1128 +        return TOK_IMPORT;
 58.1129 +    if (!strcmp(str,  "from"))
 58.1130 +        return TOK_FROM;
 58.1131 +    return TOK_NONE;
 58.1132 +}
 58.1133 +
 58.1134 +TokenKind
 58.1135 +Scanner::identifier(char first)
 58.1136 +{
 58.1137 +    literal_.clear();
 58.1138 +    if (!literal_.append(first))
 58.1139 +        return TOK_ERROR;
 58.1140 +
 58.1141 +    char c;
 58.1142 +    for (;;) {
 58.1143 +        c = getChar();
 58.1144 +        if (!isascii(c) || (!isalnum(c) && c != '_'))
 58.1145 +            break;
 58.1146 +        if (!literal_.append(c))
 58.1147 +            return TOK_ERROR;
 58.1148 +    }
 58.1149 +    
 58.1150 +    if (!literal_.append('\0'))
 58.1151 +        return TOK_ERROR;
 58.1152 +
 58.1153 +    // Most keywords do not act as labels.
 58.1154 +    TokenKind kind = FindIdentifier(literal());
 58.1155 +    if (kind != TOK_NONE) {
 58.1156 +        putChar(c);
 58.1157 +        return kind;
 58.1158 +    }
 58.1159 +
 58.1160 +    if (c == ':' && allowTags_)
 58.1161 +        return TOK_LABEL;
 58.1162 +
 58.1163 +    putChar(c);
 58.1164 +
 58.1165 +    // _ is a special case which acts as a tag and a keyword.
 58.1166 +    if (!strcmp(literal(), "_"))
 58.1167 +        return TOK_UNDERSCORE;
 58.1168 +
 58.1169 +    return TOK_NAME;
 58.1170 +}
 58.1171 +
 58.1172 +TokenKind
 58.1173 +Scanner::next()
 58.1174 +{
 58.1175 +    assert(!pushed_);
 58.1176 +
 58.1177 +    for (;;) {
 58.1178 +        begin_ = cur_;
 58.1179 +
 58.1180 +        char c = getChar();
 58.1181 +        switch (c) {
 58.1182 +          case '/':
 58.1183 +          {
 58.1184 +            c = getChar();
 58.1185 +            if (c == '/') {
 58.1186 +                eatSingleLine();
 58.1187 +                break;
 58.1188 +            }
 58.1189 +            if (c == '*') {
 58.1190 +                if (!eatComment()) {
 58.1191 +                    cc_.reportError(begin(), Message_UnterminatedComment);
 58.1192 +                    return TOK_ERROR;
 58.1193 +                }
 58.1194 +                break;
 58.1195 +            }
 58.1196 +            putChar(c);
 58.1197 +            return TOK_SLASH;
 58.1198 +          }
 58.1199 +
 58.1200 +          case '\n':
 58.1201 +          case '\r':
 58.1202 +            calcNewLine(c);
 58.1203 +            break;
 58.1204 +
 58.1205 +          case ';': return TOK_SEMICOLON;
 58.1206 +          case '{': return TOK_LBRACE;
 58.1207 +          case '}': return TOK_RBRACE;
 58.1208 +          case '(': return TOK_LPAREN;
 58.1209 +          case ')': return TOK_RPAREN;
 58.1210 +          case '[': return TOK_LBRACKET;
 58.1211 +          case ']': return TOK_RBRACKET;
 58.1212 +          case '~': return TOK_TILDE;
 58.1213 +          case '?': return TOK_QMARK;
 58.1214 +          case ':': return TOK_COLON;
 58.1215 +
 58.1216 +          case '.':
 58.1217 +            c = getChar();
 58.1218 +            if (c == '.') {
 58.1219 +                c = getChar();
 58.1220 +                if (c == '.')
 58.1221 +                    return TOK_ELLIPSES;
 58.1222 +                cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
 58.1223 +                return TOK_ERROR;
 58.1224 +            }
 58.1225 +            putChar(c);
 58.1226 +            return TOK_DOT;
 58.1227 +
 58.1228 +          case '*':
 58.1229 +            c = getChar();
 58.1230 +            if (c == '=')
 58.1231 +                return TOK_ASSIGN_MUL;
 58.1232 +            putChar(c);
 58.1233 +            return TOK_STAR;
 58.1234 +
 58.1235 +          case '+':
 58.1236 +            c = getChar();
 58.1237 +            if (c == '=')
 58.1238 +                return TOK_ASSIGN_ADD;
 58.1239 +            if (c == '+')
 58.1240 +                return TOK_INCREMENT;
 58.1241 +            putChar(c);
 58.1242 +            return TOK_PLUS;
 58.1243 +
 58.1244 +          case '&':
 58.1245 +            c = getChar();
 58.1246 +            if (c == '=')
 58.1247 +                return TOK_ASSIGN_BITAND;
 58.1248 +            if (c == '&')
 58.1249 +                return TOK_AND;
 58.1250 +            putChar(c);
 58.1251 +            return TOK_BITAND;
 58.1252 +
 58.1253 +          case '|':
 58.1254 +            c = getChar();
 58.1255 +            if (c == '=')
 58.1256 +                return TOK_ASSIGN_BITOR;
 58.1257 +            if (c == '|')
 58.1258 +                return TOK_OR;
 58.1259 +            putChar(c);
 58.1260 +            return TOK_BITOR;
 58.1261 +
 58.1262 +          case '^':
 58.1263 +            c = getChar();
 58.1264 +            if (c == '=')
 58.1265 +                return TOK_ASSIGN_BITXOR;
 58.1266 +            putChar(c);
 58.1267 +            return TOK_BITXOR;
 58.1268 +
 58.1269 +          case '%':
 58.1270 +            c = getChar();
 58.1271 +            if (c == '=')
 58.1272 +                return TOK_ASSIGN_MOD;
 58.1273 +            putChar(c);
 58.1274 +            return TOK_PERCENT;
 58.1275 +
 58.1276 +          case '-':
 58.1277 +            c = getChar();
 58.1278 +            if (c == '=')
 58.1279 +                return TOK_ASSIGN_SUB;
 58.1280 +            if (c == '-')
 58.1281 +                return TOK_DECREMENT;
 58.1282 +            putChar(c);
 58.1283 +            return TOK_MINUS;
 58.1284 +
 58.1285 +          case ',': return TOK_COMMA;
 58.1286 +          case '\0': return TOK_EOF;
 58.1287 +
 58.1288 +          case '!':
 58.1289 +            c = getChar();
 58.1290 +            if (c == '=')
 58.1291 +                return TOK_NOTEQUALS;
 58.1292 +            putChar(c);
 58.1293 +            return TOK_NOT;
 58.1294 +
 58.1295 +          case '=':
 58.1296 +            c = getChar();
 58.1297 +            if (c == '=')
 58.1298 +                return TOK_EQUALS;
 58.1299 +            putChar(c);
 58.1300 +            return TOK_ASSIGN;
 58.1301 +
 58.1302 +
 58.1303 +          case '<':
 58.1304 +            c = getChar();
 58.1305 +            if (c == '=')
 58.1306 +                return TOK_LE;
 58.1307 +            if (c == '<') {
 58.1308 +                c = getChar();
 58.1309 +                if (c == '=')
 58.1310 +                    return TOK_ASSIGN_SHL;
 58.1311 +                putChar(c);
 58.1312 +                return TOK_SHL;
 58.1313 +            }
 58.1314 +            putChar(c);
 58.1315 +            return TOK_LT;
 58.1316 +
 58.1317 +          case '>':
 58.1318 +            c = getChar();
 58.1319 +            if (c == '=')
 58.1320 +                return TOK_GE;
 58.1321 +            if (c == '>') {
 58.1322 +                c = getChar();
 58.1323 +                if (c == '>') {
 58.1324 +                    c = getChar();
 58.1325 +                    if (c == '=')
 58.1326 +                        return TOK_ASSIGN_USHR;
 58.1327 +                    putChar(c);
 58.1328 +                    return TOK_USHR;
 58.1329 +                }
 58.1330 +                return TOK_SHR;
 58.1331 +            }
 58.1332 +            putChar(c);
 58.1333 +            return TOK_GT;
 58.1334 +
 58.1335 +          case ' ':
 58.1336 +          case '\t':
 58.1337 +          case '\f':
 58.1338 +            break;
 58.1339 +
 58.1340 +          case '"':
 58.1341 +            return stringLiteral();
 58.1342 +
 58.1343 +          default:
 58.1344 +            if (c >= '0' && c <= '9')
 58.1345 +                return numberLiteral(c);
 58.1346 +            if (c == '_' || (isascii(c) && isalpha(c)))
 58.1347 +                return identifier(c);
 58.1348 +            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
 58.1349 +            return TOK_ERROR;
 58.1350 +        }
 58.1351 +    }
 58.1352 +}
 58.1353 +
 58.1354 +TokenKind
 58.1355 +Scanner::scan()
 58.1356 +{
 58.1357 +    if (pushed_) {
 58.1358 +        pushed_ = false;
 58.1359 +        return lastToken_;
 58.1360 +    }
 58.1361 +    lastToken_ = next();
 58.1362 +    return lastToken_;
 58.1363 +}
 58.1364 +
 58.1365 +TokenKind
 58.1366 +Scanner::peek()
 58.1367 +{
 58.1368 +    if (pushed_)
 58.1369 +        return lastToken_;
 58.1370 +    scan();
 58.1371 +    pushed_ = true;
 58.1372 +    return lastToken_;
 58.1373 +}
    59.1 --- a/src/compiler/Scanner.h	Mon Jun 10 00:46:29 2013 +0100
    59.2 +++ b/src/compiler/Scanner.h	Mon Jun 10 01:04:43 2013 +0100
    59.3 @@ -1,114 +1,114 @@
    59.4 -/* vim: set ts=4 sw=4 tw=99 et:
    59.5 - *
    59.6 - * Copyright (C) 2012 David Anderson
    59.7 - *
    59.8 - * This file is part of SourcePawn.
    59.9 - *
   59.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   59.11 - * the terms of the GNU General Public License as published by the Free
   59.12 - * Software Foundation, either version 3 of the License, or (at your option)
   59.13 - * any later version.
   59.14 - * 
   59.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   59.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   59.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   59.18 - *
   59.19 - * You should have received a copy of the GNU General Public License along with
   59.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   59.21 - */
   59.22 -#ifndef _include_jitcraft_scanner_h_
   59.23 -#define _include_jitcraft_scanner_h_
   59.24 -
   59.25 -#include "Token.h"
   59.26 -#include "CompileContext.h"
   59.27 -#include "../Opcodes.h"
   59.28 -#include "../Vector.h"
   59.29 -
   59.30 -namespace ke {
   59.31 -
   59.32 -class Scanner
   59.33 -{
   59.34 -    template <bool Enabled>
   59.35 -    friend class AutoAllowTags;
   59.36 -
   59.37 -    CompileContext &cc_;
   59.38 -    const char *stream_;
   59.39 -    size_t length_;
   59.40 -    bool pushed_;
   59.41 -    bool allowTags_;
   59.42 -    char saved_;
   59.43 -    const char *pos_;
   59.44 -    Vector<char> literal_;
   59.45 -    TokenKind lastToken_;
   59.46 -    SourcePosition last_;
   59.47 -    SourcePosition cur_;
   59.48 -    SourcePosition begin_;
   59.49 -
   59.50 -  private:
   59.51 -    char getChar();
   59.52 -    void putChar(char c);
   59.53 -    void eatSingleLine();
   59.54 -    bool eatComment();
   59.55 -    void calcNewLine(char c);
   59.56 -    int readEscapeCode();
   59.57 -    TokenKind stringLiteral();
   59.58 -    TokenKind hexLiteral();
   59.59 -    TokenKind numberLiteral(char first);
   59.60 -    TokenKind identifier(char first);
   59.61 -
   59.62 -    TokenKind next();
   59.63 -
   59.64 -  public:
   59.65 -    Scanner(CompileContext &cc, const char *stream, size_t length);
   59.66 -
   59.67 -    static double ParseDouble(const char *string);
   59.68 -
   59.69 -    TokenKind scan();
   59.70 -    TokenKind peek();
   59.71 -    TokenKind last() const {
   59.72 -        return lastToken_;
   59.73 -    }
   59.74 -
   59.75 -    bool tagsEnabled() const {
   59.76 -        return allowTags_;
   59.77 -    }
   59.78 -    void setTagsEnabled(bool enabled) {
   59.79 -        allowTags_ = enabled;
   59.80 -    }
   59.81 -
   59.82 -    // Beginning source position of the last instruction.
   59.83 -    SourcePosition begin() const {
   59.84 -        return begin_;
   59.85 -    }
   59.86 -
   59.87 -    // Note: the literal may have embedded NUL characters.
   59.88 -    const char *literal() const {
   59.89 -        return literal_.buffer();
   59.90 -    }
   59.91 -    size_t literal_length() const {
   59.92 -        return literal_.length() - 1;
   59.93 -    }
   59.94 -};
   59.95 -
   59.96 -template <bool Enabled>
   59.97 -class AutoAllowTags
   59.98 -{
   59.99 -    Scanner &scanner_;
  59.100 -    bool prev_;
  59.101 -
  59.102 -  public:
  59.103 -    AutoAllowTags(Scanner &scanner)
  59.104 -      : scanner_(scanner),
  59.105 -        prev_(scanner_.tagsEnabled())
  59.106 -    {
  59.107 -        scanner_.setTagsEnabled(Enabled);
  59.108 -    }
  59.109 -    ~AutoAllowTags()
  59.110 -    {
  59.111 -        scanner_.setTagsEnabled(prev_);
  59.112 -    }
  59.113 -};
  59.114 -
  59.115 -} // namespace ke
  59.116 -
  59.117 -#endif // _include_jitcraft_scanner_h_
  59.118 +/* vim: set ts=4 sw=4 tw=99 et:
  59.119 + *
  59.120 + * Copyright (C) 2012 David Anderson
  59.121 + *
  59.122 + * This file is part of SourcePawn.
  59.123 + *
  59.124 + * SourcePawn is free software: you can redistribute it and/or modify it under
  59.125 + * the terms of the GNU General Public License as published by the Free
  59.126 + * Software Foundation, either version 3 of the License, or (at your option)
  59.127 + * any later version.
  59.128 + * 
  59.129 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  59.130 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  59.131 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  59.132 + *
  59.133 + * You should have received a copy of the GNU General Public License along with
  59.134 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  59.135 + */
  59.136 +#ifndef _include_jitcraft_scanner_h_
  59.137 +#define _include_jitcraft_scanner_h_
  59.138 +
  59.139 +#include "Token.h"
  59.140 +#include "CompileContext.h"
  59.141 +#include "../Opcodes.h"
  59.142 +#include "../Vector.h"
  59.143 +
  59.144 +namespace ke {
  59.145 +
  59.146 +class Scanner
  59.147 +{
  59.148 +    template <bool Enabled>
  59.149 +    friend class AutoAllowTags;
  59.150 +
  59.151 +    CompileContext &cc_;
  59.152 +    const char *stream_;
  59.153 +    size_t length_;
  59.154 +    bool pushed_;
  59.155 +    bool allowTags_;
  59.156 +    char saved_;
  59.157 +    const char *pos_;
  59.158 +    Vector<char> literal_;
  59.159 +    TokenKind lastToken_;
  59.160 +    SourcePosition last_;
  59.161 +    SourcePosition cur_;
  59.162 +    SourcePosition begin_;
  59.163 +
  59.164 +  private:
  59.165 +    char getChar();
  59.166 +    void putChar(char c);
  59.167 +    void eatSingleLine();
  59.168 +    bool eatComment();
  59.169 +    void calcNewLine(char c);
  59.170 +    int readEscapeCode();
  59.171 +    TokenKind stringLiteral();
  59.172 +    TokenKind hexLiteral();
  59.173 +    TokenKind numberLiteral(char first);
  59.174 +    TokenKind identifier(char first);
  59.175 +
  59.176 +    TokenKind next();
  59.177 +
  59.178 +  public:
  59.179 +    Scanner(CompileContext &cc, const char *stream, size_t length);
  59.180 +
  59.181 +    static double ParseDouble(const char *string);
  59.182 +
  59.183 +    TokenKind scan();
  59.184 +    TokenKind peek();
  59.185 +    TokenKind last() const {
  59.186 +        return lastToken_;
  59.187 +    }
  59.188 +
  59.189 +    bool tagsEnabled() const {
  59.190 +        return allowTags_;
  59.191 +    }
  59.192 +    void setTagsEnabled(bool enabled) {
  59.193 +        allowTags_ = enabled;
  59.194 +    }
  59.195 +
  59.196 +    // Beginning source position of the last instruction.
  59.197 +    SourcePosition begin() const {
  59.198 +        return begin_;
  59.199 +    }
  59.200 +
  59.201 +    // Note: the literal may have embedded NUL characters.
  59.202 +    const char *literal() const {
  59.203 +        return literal_.buffer();
  59.204 +    }
  59.205 +    size_t literal_length() const {
  59.206 +        return literal_.length() - 1;
  59.207 +    }
  59.208 +};
  59.209 +
  59.210 +template <bool Enabled>
  59.211 +class AutoAllowTags
  59.212 +{
  59.213 +    Scanner &scanner_;
  59.214 +    bool prev_;
  59.215 +
  59.216 +  public:
  59.217 +    AutoAllowTags(Scanner &scanner)
  59.218 +      : scanner_(scanner),
  59.219 +        prev_(scanner_.tagsEnabled())
  59.220 +    {
  59.221 +        scanner_.setTagsEnabled(Enabled);
  59.222 +    }
  59.223 +    ~AutoAllowTags()
  59.224 +    {
  59.225 +        scanner_.setTagsEnabled(prev_);
  59.226 +    }
  59.227 +};
  59.228 +
  59.229 +} // namespace ke
  59.230 +
  59.231 +#endif // _include_jitcraft_scanner_h_
    60.1 --- a/src/compiler/Scopes.cpp	Mon Jun 10 00:46:29 2013 +0100
    60.2 +++ b/src/compiler/Scopes.cpp	Mon Jun 10 01:04:43 2013 +0100
    60.3 @@ -1,194 +1,194 @@
    60.4 -/* vim: set ts=4 sw=4 tw=99 et:
    60.5 - *
    60.6 - * Copyright (C) 2012 David Anderson
    60.7 - *
    60.8 - * This file is part of JITCraft.
    60.9 - *
   60.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   60.11 - * the terms of the GNU General Public License as published by the Free
   60.12 - * Software Foundation, either version 3 of the License, or (at your option)
   60.13 - * any later version.
   60.14 - * 
   60.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   60.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   60.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   60.18 - *
   60.19 - * You should have received a copy of the GNU General Public License along with
   60.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   60.21 - */
   60.22 -#include "../Zone.h"
   60.23 -#include "../Types.h"
   60.24 -#include "../TypeManager.h"
   60.25 -#include "../Strings.h"
   60.26 -#include "../Environments.h"
   60.27 -#include "../Structures.h"
   60.28 -#include "CompileContext.h"
   60.29 -#include "Scopes.h"
   60.30 -#include "../Spaces-inl.h"
   60.31 -#include "../Heap-inl.h"
   60.32 -
   60.33 -using namespace ke;
   60.34 -
   60.35 -Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
   60.36 -  : pool_(pool),
   60.37 -    kind_(kind),
   60.38 -    enclosing_(enclosing)
   60.39 -{
   60.40 -}
   60.41 -
   60.42 -bool
   60.43 -Scope::initialize()
   60.44 -{
   60.45 -    if (enclosing_ && !enclosing_->children_.append(this))
   60.46 -        return false;
   60.47 -    return true;
   60.48 -}
   60.49 -
   60.50 -void
   60.51 -Scope::unlink()
   60.52 -{
   60.53 -    assert(empty());
   60.54 -
   60.55 -    assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
   60.56 -    enclosing_->children_.pop();
   60.57 -
   60.58 -    // OOM here is swallowed and checked after compilation.
   60.59 -    // :TODO: make the above true.
   60.60 -    for (size_t i = 0; i < children_.length(); i++)
   60.61 -        enclosing_->children_.append(children_[i]);
   60.62 -}
   60.63 -
   60.64 -Scope *
   60.65 -Scope::unlinkIfEmpty()
   60.66 -{
   60.67 -    if (empty()) {
   60.68 -        unlink();
   60.69 -        return NULL;
   60.70 -    }
   60.71 -    return this;
   60.72 -}
   60.73 -
   60.74 -Symbol *
   60.75 -Scope::localLookup(Handle<String> name)
   60.76 -{
   60.77 -    for (size_t i = 0; i < names_.length(); i++) {
   60.78 -        if (names_[i]->name() == name)
   60.79 -            return names_[i];
   60.80 -    }
   60.81 -    return NULL;
   60.82 -}
   60.83 -
   60.84 -Symbol  *
   60.85 -Scope::lookup(Handle<String> name)
   60.86 -{
   60.87 -    for (Scope *scope = this; scope; scope = scope->enclosing()) {
   60.88 -        if (Symbol *bound = scope->localLookup(name))
   60.89 -            return bound;
   60.90 -    }
   60.91 -    return NULL;
   60.92 -}
   60.93 -
   60.94 -#if 0
   60.95 -void
   60.96 -Scope::setUsesLifoHeap()
   60.97 -{
   60.98 -    // Only one lifo slot is needed per scope.
   60.99 -#if 0
  60.100 -    if (lifoSlot_)
  60.101 -        return;
  60.102 -#endif
  60.103 -
  60.104 -    // If the parent of this scope is the function scope, then this is the
  60.105 -    // function's block scope, and the lifo slot is part of the Frame instead.
  60.106 -    // Note we can get a function scope here if we're making a temporary in a
  60.107 -    // function with no local variables.
  60.108 -    if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
  60.109 -        return;
  60.110 -
  60.111 -    Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
  60.112 -    if (!type)
  60.113 -        return;
  60.114 -
  60.115 -    Local<String> name(ZONE());
  60.116 -#if 0
  60.117 -    lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
  60.118 -    lifoSlot_->setType(type);
  60.119 -#endif
  60.120 -}
  60.121 -#endif
  60.122 -
  60.123 -bool
  60.124 -Scope::addSymbol(Symbol *sym)
  60.125 -{
  60.126 -    return names_.append(sym);
  60.127 -}
  60.128 -
  60.129 -LocalScope::LocalScope(PoolAllocator &pool)
  60.130 -  : Scope(pool, Scope::BLOCK, NULL)
  60.131 -{
  60.132 -}
  60.133 -
  60.134 -LocalScope *
  60.135 -LocalScope::New(PoolAllocator &pool)
  60.136 -{
  60.137 -    LocalScope *scope = new (pool) LocalScope(pool);
  60.138 -    if (!scope->initialize())
  60.139 -        return NULL;
  60.140 -
  60.141 -    return scope;
  60.142 -}
  60.143 -
  60.144 -ArgumentScope::ArgumentScope(PoolAllocator &pool)
  60.145 -  : Scope(pool, Scope::FUNCTION, NULL)
  60.146 -{
  60.147 -}
  60.148 -
  60.149 -ArgumentScope *
  60.150 -ArgumentScope::New(PoolAllocator &pool)
  60.151 -{
  60.152 -    ArgumentScope *scope = new (pool) ArgumentScope(pool);
  60.153 -    if (!scope->initialize())
  60.154 -        return NULL;
  60.155 -
  60.156 -    return scope;
  60.157 -}
  60.158 -
  60.159 -GlobalScope::GlobalScope(PoolAllocator &pool, ImportScope *parent)
  60.160 -  : Scope(pool, Scope::GLOBAL, parent)
  60.161 -{
  60.162 -}
  60.163 -
  60.164 -GlobalScope *
  60.165 -GlobalScope::New(PoolAllocator &pool, ImportScope *parent)
  60.166 -{
  60.167 -    GlobalScope *scope = new (pool) GlobalScope(pool, parent);
  60.168 -    if (!scope->initialize())
  60.169 -        return NULL;
  60.170 -
  60.171 -    return scope;
  60.172 -}
  60.173 -
  60.174 -Symbol *
  60.175 -GlobalScope::findExported(Handle<String> name)
  60.176 -{
  60.177 -    for (size_t i = 0; i < exported_.length(); i++) {
  60.178 -        if (exported_[i]->name() == name)
  60.179 -            return exported_[i];
  60.180 -    }
  60.181 -    return NULL;
  60.182 -}
  60.183 -
  60.184 -ImportScope::ImportScope(PoolAllocator &pool)
  60.185 -  : Scope(pool, Scope::IMPORT, NULL)
  60.186 -{
  60.187 -}
  60.188 -
  60.189 -ImportScope *
  60.190 -ImportScope::New(PoolAllocator &pool)
  60.191 -{
  60.192 -    ImportScope *scope = new (pool) ImportScope(pool);
  60.193 -    if (!scope->initialize())
  60.194 -        return NULL;
  60.195 -
  60.196 -    return scope;
  60.197 -}
  60.198 +/* vim: set ts=4 sw=4 tw=99 et:
  60.199 + *
  60.200 + * Copyright (C) 2012 David Anderson
  60.201 + *
  60.202 + * This file is part of JITCraft.
  60.203 + *
  60.204 + * JITCraft is free software: you can redistribute it and/or modify it under
  60.205 + * the terms of the GNU General Public License as published by the Free
  60.206 + * Software Foundation, either version 3 of the License, or (at your option)
  60.207 + * any later version.
  60.208 + * 
  60.209 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  60.210 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  60.211 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  60.212 + *
  60.213 + * You should have received a copy of the GNU General Public License along with
  60.214 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  60.215 + */
  60.216 +#include "../Zone.h"
  60.217 +#include "../Types.h"
  60.218 +#include "../TypeManager.h"
  60.219 +#include "../Strings.h"
  60.220 +#include "../Environments.h"
  60.221 +#include "../Structures.h"
  60.222 +#include "CompileContext.h"
  60.223 +#include "Scopes.h"
  60.224 +#include "../Spaces-inl.h"
  60.225 +#include "../Heap-inl.h"
  60.226 +
  60.227 +using namespace ke;
  60.228 +
  60.229 +Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
  60.230 +  : pool_(pool),
  60.231 +    kind_(kind),
  60.232 +    enclosing_(enclosing)
  60.233 +{
  60.234 +}
  60.235 +
  60.236 +bool
  60.237 +Scope::initialize()
  60.238 +{
  60.239 +    if (enclosing_ && !enclosing_->children_.append(this))
  60.240 +        return false;
  60.241 +    return true;
  60.242 +}
  60.243 +
  60.244 +void
  60.245 +Scope::unlink()
  60.246 +{
  60.247 +    assert(empty());
  60.248 +
  60.249 +    assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
  60.250 +    enclosing_->children_.pop();
  60.251 +
  60.252 +    // OOM here is swallowed and checked after compilation.
  60.253 +    // :TODO: make the above true.
  60.254 +    for (size_t i = 0; i < children_.length(); i++)
  60.255 +        enclosing_->children_.append(children_[i]);
  60.256 +}
  60.257 +
  60.258 +Scope *
  60.259 +Scope::unlinkIfEmpty()
  60.260 +{
  60.261 +    if (empty()) {
  60.262 +        unlink();
  60.263 +        return NULL;
  60.264 +    }
  60.265 +    return this;
  60.266 +}
  60.267 +
  60.268 +Symbol *
  60.269 +Scope::localLookup(Handle<String> name)
  60.270 +{
  60.271 +    for (size_t i = 0; i < names_.length(); i++) {
  60.272 +        if (names_[i]->name() == name)
  60.273 +            return names_[i];
  60.274 +    }
  60.275 +    return NULL;
  60.276 +}
  60.277 +
  60.278 +Symbol  *
  60.279 +Scope::lookup(Handle<String> name)
  60.280 +{
  60.281 +    for (Scope *scope = this; scope; scope = scope->enclosing()) {
  60.282 +        if (Symbol *bound = scope->localLookup(name))
  60.283 +            return bound;
  60.284 +    }
  60.285 +    return NULL;
  60.286 +}
  60.287 +
  60.288 +#if 0
  60.289 +void
  60.290 +Scope::setUsesLifoHeap()
  60.291 +{
  60.292 +    // Only one lifo slot is needed per scope.
  60.293 +#if 0
  60.294 +    if (lifoSlot_)
  60.295 +        return;
  60.296 +#endif
  60.297 +
  60.298 +    // If the parent of this scope is the function scope, then this is the
  60.299 +    // function's block scope, and the lifo slot is part of the Frame instead.
  60.300 +    // Note we can get a function scope here if we're making a temporary in a
  60.301 +    // function with no local variables.
  60.302 +    if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
  60.303 +        return;
  60.304 +
  60.305 +    Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
  60.306 +    if (!type)
  60.307 +        return;
  60.308 +
  60.309 +    Local<String> name(ZONE());
  60.310 +#if 0
  60.311 +    lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
  60.312 +    lifoSlot_->setType(type);
  60.313 +#endif
  60.314 +}
  60.315 +#endif
  60.316 +
  60.317 +bool
  60.318 +Scope::addSymbol(Symbol *sym)
  60.319 +{
  60.320 +    return names_.append(sym);
  60.321 +}
  60.322 +
  60.323 +LocalScope::LocalScope(PoolAllocator &pool)
  60.324 +  : Scope(pool, Scope::BLOCK, NULL)
  60.325 +{
  60.326 +}
  60.327 +
  60.328 +LocalScope *
  60.329 +LocalScope::New(PoolAllocator &pool)
  60.330 +{
  60.331 +    LocalScope *scope = new (pool) LocalScope(pool);
  60.332 +    if (!scope->initialize())
  60.333 +        return NULL;
  60.334 +
  60.335 +    return scope;
  60.336 +}
  60.337 +
  60.338 +ArgumentScope::ArgumentScope(PoolAllocator &pool)
  60.339 +  : Scope(pool, Scope::FUNCTION, NULL)
  60.340 +{
  60.341 +}
  60.342 +
  60.343 +ArgumentScope *
  60.344 +ArgumentScope::New(PoolAllocator &pool)
  60.345 +{
  60.346 +    ArgumentScope *scope = new (pool) ArgumentScope(pool);
  60.347 +    if (!scope->initialize())
  60.348 +        return NULL;
  60.349 +
  60.350 +    return scope;
  60.351 +}
  60.352 +
  60.353 +GlobalScope::GlobalScope(PoolAllocator &pool, ImportScope *parent)
  60.354 +  : Scope(pool, Scope::GLOBAL, parent)
  60.355 +{
  60.356 +}
  60.357 +
  60.358 +GlobalScope *
  60.359 +GlobalScope::New(PoolAllocator &pool, ImportScope *parent)
  60.360 +{
  60.361 +    GlobalScope *scope = new (pool) GlobalScope(pool, parent);
  60.362 +    if (!scope->initialize())
  60.363 +        return NULL;
  60.364 +
  60.365 +    return scope;
  60.366 +}
  60.367 +
  60.368 +Symbol *
  60.369 +GlobalScope::findExported(Handle<String> name)
  60.370 +{
  60.371 +    for (size_t i = 0; i < exported_.length(); i++) {
  60.372 +        if (exported_[i]->name() == name)
  60.373 +            return exported_[i];
  60.374 +    }
  60.375 +    return NULL;
  60.376 +}
  60.377 +
  60.378 +ImportScope::ImportScope(PoolAllocator &pool)
  60.379 +  : Scope(pool, Scope::IMPORT, NULL)
  60.380 +{
  60.381 +}
  60.382 +
  60.383 +ImportScope *
  60.384 +ImportScope::New(PoolAllocator &pool)
  60.385 +{
  60.386 +    ImportScope *scope = new (pool) ImportScope(pool);
  60.387 +    if (!scope->initialize())
  60.388 +        return NULL;
  60.389 +
  60.390 +    return scope;
  60.391 +}
    61.1 --- a/src/compiler/Scopes.h	Mon Jun 10 00:46:29 2013 +0100
    61.2 +++ b/src/compiler/Scopes.h	Mon Jun 10 01:04:43 2013 +0100
    61.3 @@ -1,125 +1,125 @@
    61.4 -/*
    61.5 - * Copyright (C) 2012 David Anderson
    61.6 - *
    61.7 - * This file is part of JITCraft.
    61.8 - *
    61.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   61.10 - * the terms of the GNU General Public License as published by the Free
   61.11 - * Software Foundation, either version 3 of the License, or (at your option)
   61.12 - * any later version.
   61.13 - * 
   61.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   61.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   61.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   61.17 - *
   61.18 - * You should have received a copy of the GNU General Public License along with
   61.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   61.20 - */
   61.21 -#ifndef _include_jitcraft_scopes_h_
   61.22 -#define _include_jitcraft_scopes_h_
   61.23 -
   61.24 -#include "../PoolAllocator.h"
   61.25 -#include "../Structures.h"
   61.26 -#include "AST.h"
   61.27 -#include "NameBinding.h"
   61.28 -
   61.29 -namespace ke {
   61.30 -
   61.31 -class CompileContext;
   61.32 -class EnvironmentMap;
   61.33 -class Struct;
   61.34 -
   61.35 -class Scope : public PoolObject
   61.36 -{
   61.37 -  protected:
   61.38 -    PoolAllocator &pool_;
   61.39 -    PoolList<Symbol *> names_;
   61.40 -    PoolList<Scope *> children_;
   61.41 -    
   61.42 -    bool empty() const {
   61.43 -        return names_.length() == 0;
   61.44 -    }
   61.45 -    void unlink();
   61.46 -
   61.47 -  public:
   61.48 -    enum Kind {
   61.49 -        IMPORT,
   61.50 -        GLOBAL,
   61.51 -        FUNCTION,
   61.52 -        BLOCK
   61.53 -    };
   61.54 -
   61.55 -  public:
   61.56 -    Scope(PoolAllocator &pool, Kind kind, Scope *enclosing);
   61.57 -    bool initialize();
   61.58 -
   61.59 -    Kind kind() const {
   61.60 -        return kind_;
   61.61 -    }
   61.62 -    Scope *enclosing() const {
   61.63 -        return enclosing_;
   61.64 -    }
   61.65 -
   61.66 -    bool addSymbol(Symbol *symbol);
   61.67 -
   61.68 -    Scope *unlinkIfEmpty();
   61.69 -    Symbol *localLookup(Handle<String> name);
   61.70 -    Symbol *lookup(Handle<String> name);
   61.71 -
   61.72 -    EnvironmentMap *createEnvironmentMap(Zone *zone);
   61.73 -
   61.74 -    void setParent(Scope *parent) {
   61.75 -        assert(!enclosing_ || enclosing_ == parent);
   61.76 -        enclosing_ = parent;
   61.77 -    }
   61.78 -
   61.79 -  private:
   61.80 -    Kind kind_;
   61.81 -    Scope *enclosing_;
   61.82 -};
   61.83 -
   61.84 -class ArgumentScope : public Scope
   61.85 -{
   61.86 -  public:
   61.87 -    static ArgumentScope *New(PoolAllocator &pool);
   61.88 -
   61.89 -  private:
   61.90 -    ArgumentScope(PoolAllocator &pool);
   61.91 -};
   61.92 -
   61.93 -class LocalScope : public Scope
   61.94 -{
   61.95 -  public:
   61.96 -    static LocalScope *New(PoolAllocator &pool);
   61.97 -
   61.98 -  private:
   61.99 -    LocalScope(PoolAllocator &pool);
  61.100 -};
  61.101 -
  61.102 -class GlobalScope : public Scope
  61.103 -{
  61.104 -  public:
  61.105 -    static GlobalScope *New(PoolAllocator &pool, ImportScope *parent);
  61.106 -
  61.107 -    PoolList<Symbol *> *exported() {
  61.108 -        return &exported_;
  61.109 -    }
  61.110 -    Symbol *findExported(Handle<String> name);
  61.111 -
  61.112 -  private:
  61.113 -    GlobalScope(PoolAllocator &pool, ImportScope *parent);
  61.114 -    PoolList<Symbol *> exported_;
  61.115 -};
  61.116 -
  61.117 -class ImportScope : public Scope
  61.118 -{
  61.119 -  public:
  61.120 -    static ImportScope *New(PoolAllocator &pool);
  61.121 -
  61.122 -  private:
  61.123 -    ImportScope(PoolAllocator &pool);
  61.124 -};
  61.125 -
  61.126 -}
  61.127 -
  61.128 -#endif // _include_jitcraft_scopes_h_
  61.129 +/*
  61.130 + * Copyright (C) 2012 David Anderson
  61.131 + *
  61.132 + * This file is part of JITCraft.
  61.133 + *
  61.134 + * JITCraft is free software: you can redistribute it and/or modify it under
  61.135 + * the terms of the GNU General Public License as published by the Free
  61.136 + * Software Foundation, either version 3 of the License, or (at your option)
  61.137 + * any later version.
  61.138 + * 
  61.139 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
  61.140 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  61.141 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  61.142 + *
  61.143 + * You should have received a copy of the GNU General Public License along with
  61.144 + * JITCraft. If not, see http://www.gnu.org/licenses/.
  61.145 + */
  61.146 +#ifndef _include_jitcraft_scopes_h_
  61.147 +#define _include_jitcraft_scopes_h_
  61.148 +
  61.149 +#include "../PoolAllocator.h"
  61.150 +#include "../Structures.h"
  61.151 +#include "AST.h"
  61.152 +#include "NameBinding.h"
  61.153 +
  61.154 +namespace ke {
  61.155 +
  61.156 +class CompileContext;
  61.157 +class EnvironmentMap;
  61.158 +class Struct;
  61.159 +
  61.160 +class Scope : public PoolObject
  61.161 +{
  61.162 +  protected:
  61.163 +    PoolAllocator &pool_;
  61.164 +    PoolList<Symbol *> names_;
  61.165 +    PoolList<Scope *> children_;
  61.166 +    
  61.167 +    bool empty() const {
  61.168 +        return names_.length() == 0;
  61.169 +    }
  61.170 +    void unlink();
  61.171 +
  61.172 +  public:
  61.173 +    enum Kind {
  61.174 +        IMPORT,
  61.175 +        GLOBAL,
  61.176 +        FUNCTION,
  61.177 +        BLOCK
  61.178 +    };
  61.179 +
  61.180 +  public:
  61.181 +    Scope(PoolAllocator &pool, Kind kind, Scope *enclosing);
  61.182 +    bool initialize();
  61.183 +
  61.184 +    Kind kind() const {
  61.185 +        return kind_;
  61.186 +    }
  61.187 +    Scope *enclosing() const {
  61.188 +        return enclosing_;
  61.189 +    }
  61.190 +
  61.191 +    bool addSymbol(Symbol *symbol);
  61.192 +
  61.193 +    Scope *unlinkIfEmpty();
  61.194 +    Symbol *localLookup(Handle<String> name);
  61.195 +    Symbol *lookup(Handle<String> name);
  61.196 +
  61.197 +    EnvironmentMap *createEnvironmentMap(Zone *zone);
  61.198 +
  61.199 +    void setParent(Scope *parent) {
  61.200 +        assert(!enclosing_ || enclosing_ == parent);
  61.201 +        enclosing_ = parent;
  61.202 +    }
  61.203 +
  61.204 +  private:
  61.205 +    Kind kind_;
  61.206 +    Scope *enclosing_;
  61.207 +};
  61.208 +
  61.209 +class ArgumentScope : public Scope
  61.210 +{
  61.211 +  public:
  61.212 +    static ArgumentScope *New(PoolAllocator &pool);
  61.213 +
  61.214 +  private:
  61.215 +    ArgumentScope(PoolAllocator &pool);
  61.216 +};
  61.217 +
  61.218 +class LocalScope : public Scope
  61.219 +{
  61.220 +  public:
  61.221 +    static LocalScope *New(PoolAllocator &pool);
  61.222 +
  61.223 +  private:
  61.224 +    LocalScope(PoolAllocator &pool);
  61.225 +};
  61.226 +
  61.227 +class GlobalScope : public Scope
  61.228 +{
  61.229 +  public:
  61.230 +    static GlobalScope *New(PoolAllocator &pool, ImportScope *parent);
  61.231 +
  61.232 +    PoolList<Symbol *> *exported() {
  61.233 +        return &exported_;
  61.234 +    }
  61.235 +    Symbol *findExported(Handle<String> name);
  61.236 +
  61.237 +  private:
  61.238 +    GlobalScope(PoolAllocator &pool, ImportScope *parent);
  61.239 +    PoolList<Symbol *> exported_;
  61.240 +};
  61.241 +
  61.242 +class ImportScope : public Scope
  61.243 +{
  61.244 +  public:
  61.245 +    static ImportScope *New(PoolAllocator &pool);
  61.246 +
  61.247 +  private:
  61.248 +    ImportScope(PoolAllocator &pool);
  61.249 +};
  61.250 +
  61.251 +}
  61.252 +
  61.253 +#endif // _include_jitcraft_scopes_h_
    62.1 --- a/src/compiler/SemanticAnalysis.cpp	Mon Jun 10 00:46:29 2013 +0100
    62.2 +++ b/src/compiler/SemanticAnalysis.cpp	Mon Jun 10 01:04:43 2013 +0100
    62.3 @@ -1,1423 +1,1423 @@
    62.4 -/* vim: set ts=4 sw=4 tw=99 et:
    62.5 - *
    62.6 - * Copyright (C) 2012 David Anderson
    62.7 - *
    62.8 - * This file is part of SourcePawn.
    62.9 - *
   62.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   62.11 - * the terms of the GNU General Public License as published by the Free
   62.12 - * Software Foundation, either version 3 of the License, or (at your option)
   62.13 - * any later version.
   62.14 - * 
   62.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   62.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   62.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   62.18 - *
   62.19 - * You should have received a copy of the GNU General Public License along with
   62.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   62.21 - */
   62.22 -#include <assert.h>
   62.23 -#include "../Zone.h"
   62.24 -#include "../Strings.h"
   62.25 -#include "../NativeTable.h"
   62.26 -#include "../TypeManager.h"
   62.27 -#include "../Modules.h"
   62.28 -#include "../Code.h"
   62.29 -#include "SemanticAnalysis.h"
   62.30 -#include "../Heap-inl.h"
   62.31 -
   62.32 -using namespace ke;
   62.33 -
   62.34 -#define __ emitter_.
   62.35 -
   62.36 -typedef BytecodeEmitter::Label Label;
   62.37 -
   62.38 -class AutoEnterScope
   62.39 -{
   62.40 -  public:
   62.41 -    AutoEnterScope(Scope **prevp, Scope *scope)
   62.42 -      : prevp_(prevp),
   62.43 -        prev_(*prevp),
   62.44 -        scope_(scope)
   62.45 -    {
   62.46 -        if (!scope_)
   62.47 -            return;
   62.48 -        prev_ = *prevp_;
   62.49 -        *prevp_ = scope;
   62.50 -        assert(prev_ == scope->enclosing());
   62.51 -    }
   62.52 -    ~AutoEnterScope()
   62.53 -    {
   62.54 -        if (scope_)
   62.55 -            *prevp_ = prev_;
   62.56 -    }
   62.57 -  private:
   62.58 -    Scope **prevp_;
   62.59 -    Scope *prev_;
   62.60 -    Scope *scope_;
   62.61 -};
   62.62 -
   62.63 -SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit)
   62.64 -  : zone_(zone),
   62.65 -    pool_(zone->pool()),
   62.66 -    cc_(cc),
   62.67 -    unit_(unit),
   62.68 -    hir_(NULL),
   62.69 -    loop_(NULL)
   62.70 -{
   62.71 -}
   62.72 -
   62.73 -SemanticAnalysis::SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun)
   62.74 -  : zone_(parent->zone_),
   62.75 -    pool_(parent->pool_),
   62.76 -    cc_(parent->cc_),
   62.77 -    unit_(parent->unit_),
   62.78 -    hir_(NULL),
   62.79 -    scope_(parent->scope_),
   62.80 -    fun_(fun),
   62.81 -    loop_(NULL),
   62.82 -    control_(NULL)
   62.83 -{
   62.84 -
   62.85 -}
   62.86 -
   62.87 -void
   62.88 -SemanticAnalysis::analyze()
   62.89 -{
   62.90 -    scope_ = unit_->globalScope();
   62.91 -
   62.92 -    for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
   62.93 -        Statement *stmt = unit_->tree()->statements()->at(i);
   62.94 -        stmt->accept(this);
   62.95 -    }
   62.96 -
   62.97 -    Local<Code> code(zone_, __ finish());
   62.98 -    if (!code)
   62.99 -        return;
  62.100 -    code->setModule(unit_->module());
  62.101 -    unit_->module()->setCode(code);
  62.102 -
  62.103 -#ifndef NDEBUG
  62.104 -//    Disassemble(code, stdout);
  62.105 -#endif
  62.106 -}
  62.107 -
  62.108 -void
  62.109 -SemanticAnalysis::visitFunctionStatement(FunctionStatement *stmt)
  62.110 -{
  62.111 -    FunctionSymbol *sym = stmt->sym();
  62.112 -    Local<FunctionType> type(zone_, sym->type());
  62.113 -
  62.114 -    assert(scope_->kind() == Scope::GLOBAL);
  62.115 -
  62.116 -    if (stmt->token() == TOK_NATIVE) {
  62.117 -        // Define the native now.
  62.118 -        size_t index;
  62.119 -        if (!zone_->nativeTable()->add(stmt->name(), &index))
  62.120 -            return;
  62.121 -
  62.122 -        Local<Native> native(zone_, Native::New(zone_, type, index));
  62.123 -        if (!native)
  62.124 -            return;
  62.125 -
  62.126 -        __ object(native);
  62.127 -        __ setglobal(sym);
  62.128 -        __ pop();
  62.129 -    }
  62.130 -
  62.131 -    // If the function is a forward or native, we don't have to do anything.
  62.132 -    if (stmt->token() == TOK_NATIVE || stmt->token() == TOK_FORWARD)
  62.133 -        return;
  62.134 -
  62.135 -    SemanticAnalysis child(this, type);
  62.136 -    Local<Function> funobj(zone_, child.compile(stmt));
  62.137 -    if (!funobj)
  62.138 -        return;
  62.139 -
  62.140 -    __ object(funobj);
  62.141 -    __ setglobal(sym);
  62.142 -    if (stmt->token() == TOK_PUBLIC)
  62.143 -        __ public_();
  62.144 -    else
  62.145 -        __ pop();
  62.146 -}
  62.147 -
  62.148 -Function *
  62.149 -SemanticAnalysis::compile(FunctionStatement *stmt)
  62.150 -{
  62.151 -    __ setFirstLine(stmt->pos().line);
  62.152 -
  62.153 -    AutoEnterScope argScope(&scope_, stmt->argScope());
  62.154 -
  62.155 -    for (size_t i = 0; i < stmt->signature().parameters()->length(); i++) {
  62.156 -        Parameter *param = stmt->signature().parameters()->at(i);
  62.157 -        param->sym()->allocate(VariableSymbol::Arg, i);
  62.158 -    }
  62.159 -
  62.160 -    AutoEnterScope varScope(&scope_, stmt->varScope());
  62.161 -    ControlStatus status = visitForControl(stmt->body());
  62.162 -
  62.163 -    if (!fun_->returnType()->isVoid()) {
  62.164 -        // If the function is not void, report if not all paths return a value.
  62.165 -        // All other incorrect return cases have been caught already.
  62.166 -        if (status.returns() == Returns_Sometimes) {
  62.167 -            cc_.reportError(stmt->pos(), Message_NotAllPathsReturnValue);
  62.168 -            return NULL;
  62.169 -        }
  62.170 -
  62.171 -        if (status.returns() == Returns_Never) {
  62.172 -            cc_.reportError(stmt->pos(), Message_MissingReturnValue);
  62.173 -            return NULL;
  62.174 -        }
  62.175 -    }
  62.176 -
  62.177 -    Local<Code> code(zone_, __ finish());
  62.178 -    if (!code)
  62.179 -        return NULL;
  62.180 -    code->setModule(unit_->module());
  62.181 -
  62.182 -    Local<Function> fun(zone_, Function::New(zone_, code, fun_, stmt->name(), stmt->pos()));
  62.183 -    if (!fun)
  62.184 -        return NULL;
  62.185 -
  62.186 -#ifndef NDEBUG
  62.187 -//    Disassemble(code, stdout);
  62.188 -#endif
  62.189 -
  62.190 -    return fun;
  62.191 -}
  62.192 -
  62.193 -void 
  62.194 -SemanticAnalysis::visitBlockStatement(BlockStatement *node)
  62.195 -{
  62.196 -    AutoEnterScope scope(&scope_, node->scope());
  62.197 -
  62.198 -    for (size_t i = 0; i < node->statements()->length(); i++) {
  62.199 -        Statement *stmt = node->statements()->at(i);
  62.200 -        __ note_position(stmt->pos());
  62.201 -        stmt->accept(this);
  62.202 -        assert(__ stackDepth() == 0);
  62.203 -    }
  62.204 -}
  62.205 -
  62.206 -void
  62.207 -SemanticAnalysis::visitEnumStatement(EnumStatement *node)
  62.208 -{
  62.209 -}
  62.210 -
  62.211 -void
  62.212 -SemanticAnalysis::visitExpressionStatement(ExpressionStatement *node)
  62.213 -{
  62.214 -    // While building HIR, we enter new pool and root scopes, since HIR
  62.215 -    // creation is purely temporary.
  62.216 -    PoolScope poolScope(zone_->pool());
  62.217 -    RootScope rootScope(zone_);
  62.218 -
  62.219 -    HIR *hir = eval(node->expression());
  62.220 -    if (!hir)
  62.221 -        return;
  62.222 -
  62.223 -    discharge(hir);
  62.224 -    if (!hir->type()->isVoid())
  62.225 -        __ pop();
  62.226 -}
  62.227 -
  62.228 -void
  62.229 -SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
  62.230 -{
  62.231 -    // If both sides terminate in a return, we consider this a return as well.
  62.232 -    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
  62.233 -        terminate(Returns_Always);
  62.234 -        return;
  62.235 -    }
  62.236 -
  62.237 -    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
  62.238 -                          ? Returns_Never
  62.239 -                          : Returns_Sometimes;
  62.240 -
  62.241 -    if (left.terminates() && right.terminates())
  62.242 -        terminate(status);
  62.243 -    else
  62.244 -        returns(status);
  62.245 -}
  62.246 -
  62.247 -SemanticAnalysis::ControlStatus
  62.248 -SemanticAnalysis::visitForControl(Statement *statement)
  62.249 -{
  62.250 -    ControlScope scope(&control_);
  62.251 -    statement->accept(this);
  62.252 -    return scope.status();
  62.253 -}
  62.254 -
  62.255 -void
  62.256 -SemanticAnalysis::visitIfStatement(IfStatement *node)
  62.257 -{
  62.258 -    Label join;
  62.259 -
  62.260 -    ControlStatus trueBranch;
  62.261 -    ControlStatus falseBranch(false, Returns_Never);
  62.262 -
  62.263 -    if (!node->ifFalse()) {
  62.264 -        Label success;
  62.265 -
  62.266 -        visitForTest(node->condition(), &success, &join, &success);
  62.267 -        __ bind(&success);
  62.268 -        trueBranch = visitForControl(node->ifTrue());
  62.269 -    } else {
  62.270 -        Label success, next;
  62.271 -
  62.272 -        visitForTest(node->condition(), &success, &next, &success);
  62.273 -        __ bind(&success);
  62.274 -        trueBranch = visitForControl(node->ifTrue());
  62.275 -        __ jump(&join);
  62.276 -        __ bind(&next);
  62.277 -        falseBranch = visitForControl(node->ifFalse());
  62.278 -    }
  62.279 -
  62.280 -    __ bind(&join);
  62.281 -
  62.282 -    control_->merge(trueBranch, falseBranch);
  62.283 -}
  62.284 -
  62.285 -void
  62.286 -SemanticAnalysis::requireLifoStack()
  62.287 -{
  62.288 -    if (!loop_)
  62.289 -        return;
  62.290 -
  62.291 -    loop_->setUsesLifoStack();
  62.292 -}
  62.293 -
  62.294 -SemanticAnalysis::ControlStatus
  62.295 -SemanticAnalysis::visitLoopBody(Statement *stmt)
  62.296 -{
  62.297 -    // We always mark off a loop body, so on each edge, we can balance the
  62.298 -    // LIFO stack. Right now, we don't have the ability to budget the LIFO
  62.299 -    // stack ahead of time. If we turn out to never need the LIFO stack, we
  62.300 -    // mark it as unnecessary. (The interpreter can't really make use of this,
  62.301 -    // but the JIT can).
  62.302 -    //
  62.303 -    // Note that balancing the LIFO stack isn't even necessary, so this
  62.304 -    // feature may be removed. All this mechanism does is mitigate the
  62.305 -    // possibility that a long-running loop will overflow the LIFO region
  62.306 -    // and therefore start requiring nursery allocations.
  62.307 -    int pos = __ enterloop();
  62.308 -    ControlStatus status = visitForControl(stmt);
  62.309 -    __ leaveloop();
  62.310 -
  62.311 -    if (loop_->usesLifoStack())
  62.312 -        __ setLoopUsesLifoStack(pos);
  62.313 -
  62.314 -    return status;
  62.315 -}
  62.316 -
  62.317 -void
  62.318 -SemanticAnalysis::visitForStatement(ForStatement *node)
  62.319 -{
  62.320 -    AutoEnterScope scope(&scope_, node->scope());
  62.321 -    PoolScope poolScope(zone_->pool());
  62.322 -    RootScope rootScope(zone_);
  62.323 -
  62.324 -    Label join, update;
  62.325 -    LoopScope loop(scope_, &join, &update, &loop_);
  62.326 -
  62.327 -    if (node->initialization())
  62.328 -        node->initialization()->accept(this);
  62.329 -
  62.330 -    Label header, test;
  62.331 -    if (node->condition())
  62.332 -        __ jump(&test);
  62.333 -
  62.334 -    __ bind(&header);
  62.335 -    ControlStatus status = visitLoopBody(node->body());
  62.336 -
  62.337 -    __ bind(&update);
  62.338 -    if (node->update())
  62.339 -        node->update()->accept(this);
  62.340 -
  62.341 -    if (node->condition()) {
  62.342 -        __ bind(&test);
  62.343 -        visitForTest(node->condition(), &header, &join, &join);
  62.344 -    } else {
  62.345 -        __ jump(&header);
  62.346 -    }
  62.347 -
  62.348 -    __ bind(&join);
  62.349 -    
  62.350 -    // If there was a condition, we treat this like a while loop. Otherwise,
  62.351 -    // the join point is only reachable if the loop contains a break. The
  62.352 -    // termination status doesn't tell us anything yet.
  62.353 -    if (node->condition() || loop.breaks())
  62.354 -        control_->merge(status, ControlStatus(false, Returns_Never));
  62.355 -    else
  62.356 -        control_->terminate(status.returns());
  62.357 -
  62.358 -    assert(__ stackDepth() == 0);
  62.359 -}
  62.360 -
  62.361 -void
  62.362 -SemanticAnalysis::visitWhileStatement(WhileStatement *node)
  62.363 -{
  62.364 -    PoolScope poolScope(zone_->pool());
  62.365 -    RootScope rootScope(zone_);
  62.366 -
  62.367 -    Label header, join;
  62.368 -
  62.369 -    __ bind(&header);
  62.370 -
  62.371 -    ControlStatus status;
  62.372 -
  62.373 -    LoopScope loop(scope_, &join, &header, &loop_);
  62.374 -    if (node->token() == TOK_WHILE) {
  62.375 -        Label body;
  62.376 -        visitForTest(node->condition(), &body, &join, &body);
  62.377 -        status = visitLoopBody(node->body());
  62.378 -        __ jump(&header);
  62.379 -    } else {
  62.380 -        status = visitLoopBody(node->body());
  62.381 -        visitForTest(node->condition(), &header, &join, &join);
  62.382 -    }
  62.383 -
  62.384 -    __ bind(&join);
  62.385 -
  62.386 -    // Detect loops that will always have a fork in the contro-flow graph.
  62.387 -    // This will be a |while| loop, or a |do-while| loop whose body does
  62.388 -    // not terminate. For now, we treat these as an |if| regardless of the
  62.389 -    // direction the branch can take. That means the control-flow is always
  62.390 -    // conditional.
  62.391 -    if (node->token() == TOK_WHILE || status.terminates() || loop.breaks()) {
  62.392 -        control_->merge(status, ControlStatus(false, Returns_Never));
  62.393 -    } else {
  62.394 -        // At this point, we've got a do-while loop with a |return| or
  62.395 -        // |continue|, meaning that the rest of the block is unreachable.
  62.396 -        control_->terminate(status.returns());
  62.397 -    }
  62.398 -
  62.399 -    assert(__ stackDepth() == 0);
  62.400 -}
  62.401 -
  62.402 -static inline Heap::Tenure
  62.403 -InferTenure(Symbol *sym)
  62.404 -{
  62.405 -    if (sym->scope()->kind() == Scope::GLOBAL)
  62.406 -        return Heap::Tenure_Old;
  62.407 -
  62.408 -    // SP2's array semantics allow any array kind to escape, so we must use
  62.409 -    // the normal heap. (Hopefully escape analysis can ease this pain later).
  62.410 -    if (sym->type()->isArray())
  62.411 -        return Heap::Tenure_Default;
  62.412 -
  62.413 -    return Heap::Tenure_Default;
  62.414 -}
  62.415 -
  62.416 -void
  62.417 -SemanticAnalysis::visitVariableDeclaration(VariableDeclaration *node)
  62.418 -{
  62.419 -    PoolScope poolScope(zone_->pool());
  62.420 -    RootScope rootScope(zone_);
  62.421 -
  62.422 -    Local<Type> type(zone_, node->sym()->type());
  62.423 -
  62.424 -    if (node->sym()->type()->isVoid()) {
  62.425 -        cc_.reportError(node->type()->pos(), Message_CannotDeclareVoid);
  62.426 -        return;
  62.427 -    }
  62.428 -
  62.429 -    if (node->initialization()) {
  62.430 -        HIR *hir = NULL;
  62.431 -
  62.432 -        if ((hir = eval(node->initialization())) == NULL)
  62.433 -            return;
  62.434 -        if ((hir = coerce(hir, type, Coerce_Decl)) == NULL)
  62.435 -            return;
  62.436 -
  62.437 -        discharge(hir);
  62.438 -    } else {
  62.439 -        if (type->isInt32() || type->isEnum() ||
  62.440 -            type->isChar() || type->isBool())
  62.441 -        {
  62.442 -            __ int_(0);
  62.443 -        } else if (type->isFloat()) {
  62.444 -            __ float_(0);
  62.445 -        } else if (type->isArray()) {
  62.446 -            Local<ArrayType> atype(zone_, ArrayType::cast(type));
  62.447 -            Local<ArrayMap> map(zone_, atype->newMap());
  62.448 -            if (!map)
  62.449 -                return;
  62.450 -
  62.451 -            if (atype->isFixedLength()) {
  62.452 -                __ newarray(OP_NEWFIXED, map, InferTenure(node->sym()));
  62.453 -            } else if (node->dims()->at(0)) {
  62.454 -                // This may not be true if we allow typedefing, so :TODO:
  62.455 -                // figure out proper semantics.
  62.456 -                assert(node->dims()->length() == atype->levels());
  62.457 -
  62.458 -                Local<Type> i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
  62.459 -                for (size_t i = 0; i < node->dims()->length(); i++) {
  62.460 -                    Expression *expr = node->dims()->at(i);
  62.461 -                    if (expr) {
  62.462 -                        HIR *hir = eval(expr);
  62.463 -                        if (!hir || ((hir = coerce(hir, i32, Coerce_Arg)) == NULL))
  62.464 -                            return;
  62.465 -                        discharge(hir);
  62.466 -                    } else {
  62.467 -                        __ int_(0);
  62.468 -                    }
  62.469 -                }
  62.470 -                __ newarray(OP_NEWSIZED, map, InferTenure(node->sym()));
  62.471 -            } else {
  62.472 -                __ newarray(OP_NEWEMPTY, map, InferTenure(node->sym()));
  62.473 -            }
  62.474 -        } else {
  62.475 -            assert(false);
  62.476 -        }
  62.477 -    }
  62.478 -
  62.479 -    if (node->sym()->scope()->kind() != Scope::GLOBAL) {
  62.480 -        if (!__ allocate(node->sym()))
  62.481 -            return;
  62.482 -    }
  62.483 -
  62.484 -    set(node->sym());
  62.485 -    __ pop();
  62.486 -}
  62.487 -
  62.488 -void
  62.489 -SemanticAnalysis::visitReturnStatement(ReturnStatement *node)
  62.490 -{
  62.491 -    control_->returns(Returns_Always);
  62.492 -
  62.493 -    if (!node->expression()) {
  62.494 -        if (!fun_->returnType()->isVoid()) {
  62.495 -            cc_.reportError(node->pos(), Message_MissingReturnValue);
  62.496 -            return;
  62.497 -        }
  62.498 -
  62.499 -        __ returnvoid();
  62.500 -        return;
  62.501 -    }
  62.502 -
  62.503 -    if (fun_->returnType()->isVoid()) {
  62.504 -        cc_.reportError(node->pos(), Message_UsedVoidReturn);
  62.505 -        return;
  62.506 -    }
  62.507 -
  62.508 -    PoolScope poolScope(zone_->pool());
  62.509 -    RootScope rootScope(zone_);
  62.510 -
  62.511 -    HIR *hir = eval(node->expression());
  62.512 -    if (!hir)
  62.513 -        return;
  62.514 -
  62.515 -    Local<Type> returnType(zone_, fun_->returnType());
  62.516 -    if ((hir = coerce(hir, returnType, Coerce_Return)) == NULL)
  62.517 -        return;
  62.518 -
  62.519 -    discharge(hir);
  62.520 -
  62.521 -    if (hir->type()->isVoid())
  62.522 -        __ returnvoid();
  62.523 -    else
  62.524 -        __ return_();
  62.525 -}
  62.526 -
  62.527 -void
  62.528 -SemanticAnalysis::visitBinaryExpression(BinaryExpression *node)
  62.529 -{
  62.530 -    HIR *left = eval(node->left());
  62.531 -    HIR *right = eval(node->right());
  62.532 -    if (!left || !right)
  62.533 -        return;
  62.534 -
  62.535 -    hir_ = binary(node, node->token(), left, right);
  62.536 -}
  62.537 -
  62.538 -bool
  62.539 -SemanticAnalysis::checkArgumentCount(Handle<FunctionType> type, unsigned actual)
  62.540 -{
  62.541 -    if (type->parameters()->length() == actual)
  62.542 -        return true;
  62.543 -
  62.544 -    if (actual > type->parameters()->length()) {
  62.545 -        if (!type->isNative() || !type->isNativeVariadic())
  62.546 -            return false;
  62.547 -        return true;
  62.548 -    }
  62.549 -
  62.550 -    if (!type->defaults())
  62.551 -        return false;
  62.552 -
  62.553 -    // Missing arguments. See if there's a default argument for each missing
  62.554 -    // actual.
  62.555 -    for (unsigned i = actual; i < type->parameters()->length(); i++) {
  62.556 -        if (!type->defaults()->at(i))
  62.557 -            return false;
  62.558 -    }
  62.559 -
  62.560 -    return true;
  62.561 -}
  62.562 -
  62.563 -static unsigned
  62.564 -BindImplicitName(Module *from, ImplicitSymbol *sym)
  62.565 -{
  62.566 -    if (sym->bound())
  62.567 -        return sym->fieldIndex();
  62.568 -
  62.569 -    Module *module = Module::cast(from->getImportAt(sym->index()));
  62.570 -    StructMap *map = module->globals()->map();
  62.571 -
  62.572 -    unsigned fieldIndex;
  62.573 -    Descriptor *desc = map->type()->lookupField(sym->name(), &fieldIndex);
  62.574 -    assert(desc && desc->type() == sym->type());
  62.575 -
  62.576 -    sym->bind(fieldIndex);
  62.577 -    return fieldIndex;
  62.578 -}
  62.579 -
  62.580 -void
  62.581 -SemanticAnalysis::visitNameProxy(NameProxy *proxy)
  62.582 -{
  62.583 -    Symbol *sym = proxy->sym();
  62.584 -
  62.585 -    switch (sym->kind()) {
  62.586 -      case Symbol::kImport:
  62.587 -      {
  62.588 -        ImportSymbol *import = sym->toImport();
  62.589 -        hir_ = new (pool_) HImport(proxy, sym->type(), import->index());
  62.590 -        break;
  62.591 -      }
  62.592 -
  62.593 -      case Symbol::kImplicit:
  62.594 -      {
  62.595 -        ImplicitSymbol *import = sym->toImplicit();
  62.596 -        unsigned fieldIndex = BindImplicitName(unit_->module(), import);
  62.597 -
  62.598 -        hir_ = new (pool_) HImport(proxy, zone_->types()->getImportable(), import->index());
  62.599 -        hir_ = new (pool_) HField(proxy, hir_, sym->type(), fieldIndex);
  62.600 -        break;
  62.601 -      }
  62.602 -
  62.603 -      case Symbol::kConstant:
  62.604 -      {
  62.605 -        ConstantSymbol *val = sym->toConstant();
  62.606 -        hir_ = new (pool_) HInteger(proxy, sym->type(), val->value().toInt());
  62.607 -        break;
  62.608 -      }
  62.609 -      
  62.610 -      // This is kind of screwy. Symbol::kFunction is like a constant we can't
  62.611 -      // evaluate yet. Maybe we should extract the GLOBAL case and say that
  62.612 -      // kFunction is only used for global functions (and use const vars for
  62.613 -      // local functions).
  62.614 -      case Symbol::kFunction:
  62.615 -      case Symbol::kVariable:
  62.616 -      {
  62.617 -        Scope *in = sym->scope();
  62.618 -        switch (in->kind()) {
  62.619 -          case Scope::GLOBAL:
  62.620 -            hir_ = new (pool_) HGlobal(proxy, sym);
  62.621 -            break;
  62.622 -
  62.623 -          case Scope::FUNCTION:
  62.624 -          {
  62.625 -            VariableSymbol *var = sym->toVariable();
  62.626 -            assert(var->storage() == VariableSymbol::Arg);
  62.627 -            hir_ = new (pool_) HLocal(proxy, var);
  62.628 -            break;
  62.629 -          }
  62.630 -
  62.631 -          default:
  62.632 -          {
  62.633 -            VariableSymbol *var = sym->toVariable();
  62.634 -            assert(in->kind() == Scope::BLOCK);
  62.635 -            assert(var->storage() == VariableSymbol::Local);
  62.636 -            hir_ = new (pool_) HLocal(proxy, var);
  62.637 -            break;
  62.638 -          }
  62.639 -        }
  62.640 -        break;
  62.641 -      }
  62.642 -
  62.643 -      default:
  62.644 -        // :TODO:
  62.645 -        assert(false);
  62.646 -    }
  62.647 -}
  62.648 -
  62.649 -void
  62.650 -SemanticAnalysis::visitBooleanLiteral(BooleanLiteral *node)
  62.651 -{
  62.652 -    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
  62.653 -    hir_ = new (pool_) HBoolean(node, type, node->token() == TOK_TRUE);
  62.654 -}
  62.655 -
  62.656 -void
  62.657 -SemanticAnalysis::visitIntegerLiteral(IntegerLiteral *lit)
  62.658 -{
  62.659 -    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
  62.660 -    hir_ = new (pool_) HInteger(lit, type, lit->value());
  62.661 -}
  62.662 -
  62.663 -void
  62.664 -SemanticAnalysis::visitFloatLiteral(FloatLiteral *node)
  62.665 -{
  62.666 -    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
  62.667 -    hir_ = new (pool_) HFloat(node, type, (float)node->value());
  62.668 -}
  62.669 -
  62.670 -void
  62.671 -SemanticAnalysis::visitStringLiteral(StringLiteral *node)
  62.672 -{
  62.673 -    Type *type = zone_->types()->getString();
  62.674 -    hir_ = new (pool_) HString(node, type, node->string());
  62.675 -}
  62.676 -
  62.677 -void
  62.678 -SemanticAnalysis::visitCallExpression(CallExpression *node)
  62.679 -{
  62.680 -    HIR *callee = eval(node->callee());
  62.681 -    if (!callee)
  62.682 -        return;
  62.683 -
  62.684 -    if (!callee->type()->isFunction()) {
  62.685 -        cc_.reportError(node->pos(), Message_CalleeNotFunction);
  62.686 -        return;
  62.687 -    }
  62.688 -
  62.689 -    Local<FunctionType> fun(zone_, FunctionType::cast(callee->type()));
  62.690 -    
  62.691 -    if (!checkArgumentCount(fun, node->arguments()->length())) {
  62.692 -        cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
  62.693 -        return;
  62.694 -    }
  62.695 -
  62.696 -    if (fun->isForward()) {
  62.697 -        cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
  62.698 -        return;
  62.699 -    }
  62.700 -
  62.701 -    HIRList *args = new (pool_) HIRList;
  62.702 -    for (unsigned i = 0; i < node->arguments()->length(); i++) {
  62.703 -        Expression *expression = node->arguments()->at(i);
  62.704 -        HIR *arg = eval(expression);
  62.705 -        if (!arg)
  62.706 -            return;
  62.707 -
  62.708 -        Handle<Type> given = arg->type();
  62.709 -        
  62.710 -        bool mustComputeReference;
  62.711 -        if (i >= fun->parameters()->length()) {
  62.712 -            // Special handling for natives. Arguments past the formal must
  62.713 -            // always have references computed. However, arrays are already
  62.714 -            // references for natives.
  62.715 -            assert(fun->isNative() && fun->isNativeVariadic());
  62.716 -            mustComputeReference = !given->isReference() &&
  62.717 -                                   !given->isArray();
  62.718 -        } else {
  62.719 -            Local<Type> actual(zone_, fun->parameterAt(i));
  62.720 -
  62.721 -            if (expression->isIndexExpression() && arg->isIndex()) {
  62.722 -                // If the expression is the form x[y], and this produced a
  62.723 -                // normal array indexing operation, then we apply some 
  62.724 -                // special rules.
  62.725 -
  62.726 -                if (actual->isReference()) {
  62.727 -                    // Disabled, since this doesn't have easily definable or
  62.728 -                    // sensible semantics with SP2 arrays, but we don't want
  62.729 -                    // to silently break SP1 semantics.
  62.730 -                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
  62.731 -                    return;
  62.732 -                }
  62.733 -
  62.734 -                // As a special rule to account for SP1 semantics, we allow x[y]
  62.735 -                // to automatically compute a sliced, read-only array view if
  62.736 -                // the desired type is an array of one more dimension than x[y]
  62.737 -                // would return.
  62.738 -                //
  62.739 -                // As an additional restriction, this is only allowed for
  62.740 -                // one-level char arrays, to minimize potential issues until
  62.741 -                // we determine whether more compatibility is needed.
  62.742 -                //
  62.743 -                // Internally, for sanity, the dependent array operation does
  62.744 -                // not necessarily create a dependent array. For extensible
  62.745 -                // arrays, we instead create a duplicate arrary of just the
  62.746 -                // sliced portion, rather than deal with the complexity of the
  62.747 -                // source array being resized.
  62.748 -                //
  62.749 -                // Note that we don't really know whether a dependent array
  62.750 -                // will be dependent at compile-time, so the dependent type's
  62.751 -                // just inherits from the source.
  62.752 -                if (actual->isArray()) {
  62.753 -                    HIndex *index = arg->toIndex();
  62.754 -                    Local<ArrayType> basetype(zone_, ArrayType::cast(index->base()->type()));
  62.755 -                    Local<ArrayType> atype(zone_, ArrayType::cast(actual));
  62.756 -
  62.757 -                    if (atype->isCharArray() && basetype->isCharArray()) {
  62.758 -                        // There is no possible way this will type check, so
  62.759 -                        // it's safe to just try something completely
  62.760 -                        // different.
  62.761 -                        Local<Type> slicetype(zone_);
  62.762 -                        if (basetype->isFixedLength()) {
  62.763 -                            // If the base type is fixed length, we need to
  62.764 -                            // compute a new dynamic array type based on the
  62.765 -                            // fixed array's contents and qualifiers.
  62.766 -                            Local<Type> contained(zone_, basetype->contained());
  62.767 -                            slicetype = zone_->types()->newArray(contained, ArrayType::DYNAMIC_ARRAY_SIZE);
  62.768 -                            if (!slicetype)
  62.769 -                                return;
  62.770 -                            slicetype = zone_->types()->qualify(slicetype, basetype->quals());
  62.771 -                            if (!slicetype)
  62.772 -                                return;
  62.773 -                        } else {
  62.774 -                            slicetype = basetype;
  62.775 -                        }
  62.776 -                        arg = new (pool_) HNewDependentArray(expression, slicetype, index->base(), index->index());
  62.777 -                        given = arg->type();
  62.778 -                    }
  62.779 -                }
  62.780 -            }
  62.781 -
  62.782 -            if (actual->isReference()) {
  62.783 -                // If the actual is a reference, the coercion rules are much
  62.784 -                // stricter; the contained types must be identical.
  62.785 -                // :TODO: make this not an assert
  62.786 -                assert(ReferenceType::cast(actual)->contained() == arg->type());
  62.787 -            } else {
  62.788 -                // When we start overloading, coercion will have to happen later.
  62.789 -                arg = coerce(arg, actual, Coerce_Arg);
  62.790 -                if (!arg)
  62.791 -                    return;
  62.792 -            }
  62.793 -
  62.794 -            mustComputeReference = actual->isReference() && !given->isReference();
  62.795 -        }
  62.796 -
  62.797 -        if (mustComputeReference) {
  62.798 -            // Refs always use the LIFO stack if they can.
  62.799 -            arg = new (pool_) HToRef(arg->node(), arg->type(), arg);
  62.800 -            requireLifoStack();
  62.801 -        }
  62.802 -
  62.803 -        if (!args->append(arg))
  62.804 -            return;
  62.805 -    }
  62.806 -
  62.807 -    hir_ = new (pool_) HCall(node, fun->returnType(), callee, args);
  62.808 -}
  62.809 -
  62.810 -void
  62.811 -SemanticAnalysis::visitAssignment(Assignment *node)
  62.812 -{
  62.813 -    HLValue *lval = lvalue(node->lvalue());
  62.814 -    if (!lval)
  62.815 -        return;
  62.816 -
  62.817 -    if (lval->type()->quals() & TypeQual_Const) {
  62.818 -        cc_.reportError(node->pos(), Message_CannotModifyConst);
  62.819 -        return;
  62.820 -    }
  62.821 -
  62.822 -    HIR *hir = eval(node->expression());
  62.823 -    if (!hir)
  62.824 -        return;
  62.825 -    if ((hir = coerce(hir, lval->type(), Coerce_Assign)) == NULL)
  62.826 -        return;
  62.827 -
  62.828 -    hir_ = new (pool_) HStore(node, node->token(), lval, hir);
  62.829 -}
  62.830 -
  62.831 -void
  62.832 -SemanticAnalysis::visitBreakStatement(BreakStatement *node)
  62.833 -{
  62.834 -    if (!loop_) {
  62.835 -        cc_.reportError(node->pos(), Message_BreakOutsideLoop);
  62.836 -        return;
  62.837 -    }
  62.838 -
  62.839 -    loop_->setBreaks();
  62.840 -    __ j(OP_BREAK, loop_->break_());
  62.841 -}
  62.842 -
  62.843 -void
  62.844 -SemanticAnalysis::visitContinueStatement(ContinueStatement *node)
  62.845 -{
  62.846 -    if (!loop_) {
  62.847 -        cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
  62.848 -        return;
  62.849 -    }
  62.850 -
  62.851 -    __ j(OP_CONTINUE, loop_->continue_());
  62.852 -}
  62.853 -
  62.854 -void
  62.855 -SemanticAnalysis::visitIndexExpression(IndexExpression *node)
  62.856 -{
  62.857 -    HIR *left = eval(node->left());
  62.858 -    if (!left)
  62.859 -        return;
  62.860 -
  62.861 -    HIR *right = eval(node->right());
  62.862 -    if (!right)
  62.863 -        return;
  62.864 -
  62.865 -    // Hrm... yes, for now, let's coerce here.
  62.866 -    Local<Type> i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
  62.867 -    if ((right = coerce(right, i32, Coerce_Arg)) == NULL)
  62.868 -        return;
  62.869 -    
  62.870 -    // Do not coerce here, there's no reason to yet.
  62.871 -    if (!left->type()->isArray()) {
  62.872 -        cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
  62.873 -        return;
  62.874 -    }
  62.875 -
  62.876 -    hir_ = new (pool_) HIndex(node,
  62.877 -                              ArrayType::cast(left->type())->contained(),
  62.878 -                              left,
  62.879 -                              right);
  62.880 -}
  62.881 -
  62.882 -void
  62.883 -SemanticAnalysis::visitIncDecExpression(IncDecExpression *node)
  62.884 -{
  62.885 -    HLValue *lval = lvalue(node->expression());
  62.886 -    if (!lval)
  62.887 -        return;
  62.888 -
  62.889 -    if (!lval->type()->isInt32() && !lval->type()->isFloat()) {
  62.890 -        assert(false);
  62.891 -        return;
  62.892 -    }
  62.893 -
  62.894 -    HIR *rval;
  62.895 -    if (lval->type()->isInt32())
  62.896 -        rval = new (pool_) HInteger(node, lval->type(), 1);
  62.897 -    else
  62.898 -        rval = new (pool_) HFloat(node, lval->type(), 1.0);
  62.899 -
  62.900 -    if (node->postfix())
  62.901 -        hir_ = new (pool_) HPostIncDec(node, node->token(), lval, rval);
  62.902 -    else
  62.903 -        hir_ = new (pool_) HStore(node, node->token(), lval, rval);
  62.904 -}
  62.905 -
  62.906 -Type *
  62.907 -SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right)
  62.908 -{
  62.909 -    Local<Type> l(zone_, left->type());
  62.910 -    Local<Type> r(zone_, right->type());
  62.911 -
  62.912 -    if (l->isPod())
  62.913 -        l = l->unqualified();
  62.914 -    if (r->isPod())
  62.915 -        r = r->unqualified();
  62.916 -
  62.917 -    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
  62.918 -        (token >= TOK_EQUALS && token <= TOK_GE))
  62.919 -    {
  62.920 -        // We allow: [float|int32] + [float|int32]
  62.921 -        if (l->isFloat() && r->isInt32())
  62.922 -            return l;
  62.923 -        if (l->isInt32() && r->isFloat())
  62.924 -            return r;
  62.925 -        if (l->isInt32() && r->isInt32())
  62.926 -            return l;
  62.927 -
  62.928 -        if (l->isChar() && r->isInt32())
  62.929 -             return r;
  62.930 -        if (l->isInt32() && r->isChar())
  62.931 -            return l;
  62.932 -    }
  62.933 -
  62.934 -    // :TODO: remove
  62.935 -    assert(*l == *r);
  62.936 -
  62.937 -    return left->type();
  62.938 -}
  62.939 -
  62.940 -HIR *
  62.941 -SemanticAnalysis::typeCheckArray(const SourcePosition &pos,
  62.942 -                                 HIR *from,
  62.943 -                                 Handle<ArrayType> argActual,
  62.944 -                                 CoercionKind kind)
  62.945 -{
  62.946 -    Local<Type> argGiven(zone_, from->type());
  62.947 -
  62.948 -    // Special case: if we receive a string literal, and this is a char array,
  62.949 -    // we allow a coercion.
  62.950 -    if (from->isString() &&
  62.951 -        argGiven->isString() &&
  62.952 -        argActual->isArray() &&
  62.953 -        ArrayType::cast(argActual)->isCharArray())
  62.954 -    {
  62.955 -        HString *hir = from->toString();
  62.956 -        Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
  62.957 -
  62.958 -        if (actual->isFixedLength()) {
  62.959 -            if (hir->string()->length() + 1 > actual->fixedLength()) {
  62.960 -                cc_.reportError(pos, Message_ArrayAssignmentTooBig);
  62.961 -                return NULL;
  62.962 -            }
  62.963 -        }
  62.964 -
  62.965 -        // Transform the string literal into an array literal. We give it the
  62.966 -        // type of the left-hand side. The constness of the destination type
  62.967 -        // will determine whether HArray duplicates it or not.
  62.968 -        Local<ArrayMap> map(zone_, actual->newMap());
  62.969 -        if (!map)
  62.970 -            return NULL;
  62.971 -
  62.972 -        Local<Array> array(zone_);
  62.973 -        array = Array::NewString(zone_,
  62.974 -                                 map,
  62.975 -                                 hir->string()->chars(),
  62.976 -                                 hir->string()->length(),
  62.977 -                                 Heap::Tenure_Old);
  62.978 -        if (!array)
  62.979 -            return NULL;
  62.980 -
  62.981 -        // Since we're creating a canonical copy of the char array, we have to
  62.982 -        // be careful that it doesn't get mutated. There are two cases where
  62.983 -        // we know it can't be mutated, and therefore don't need to specify
  62.984 -        // that it be cloned after pushing it onto the stack.
  62.985 -        //
  62.986 -        //  (1) The array type is const.
  62.987 -        //  (2) The array type is fixed-length, and the coercion is for
  62.988 -        //      assignment, meaning it will be immediately copied.
  62.989 -        //
  62.990 -        // We treat declaration separately from assignment, since for
  62.991 -        // declaration we can just immediately use the cloned version.
  62.992 -        bool shouldDuplicate = true;
  62.993 -        if ((actual->quals() & TypeQual_Const) ||
  62.994 -            (actual->isFixedLength() && kind == Coerce_Assign))
  62.995 -        {
  62.996 -            shouldDuplicate = false;
  62.997 -        }
  62.998 -
  62.999 -        return new (pool_) HArray(hir->node(), actual, array, shouldDuplicate);
 62.1000 -    }
 62.1001 -
 62.1002 -    if (!argGiven->isArray()) {
 62.1003 -        cc_.reportError(pos, Message_ExpectedArray);
 62.1004 -        return NULL;
 62.1005 -    }
 62.1006 -
 62.1007 -    Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
 62.1008 -    Local<ArrayType> given(zone_, ArrayType::cast(argGiven));
 62.1009 -
 62.1010 -    if (actual->levels() != given->levels()) {
 62.1011 -        cc_.reportError(pos, Message_ArrayDimensionsMismatch);
 62.1012 -        return NULL;
 62.1013 -    }
 62.1014 -
 62.1015 -    unsigned level = 1;
 62.1016 -    while (true) {
 62.1017 -        if (actual->isFixedLength()) {
 62.1018 -            if (!given->isFixedLength()) {
 62.1019 -                cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 62.1020 -                return NULL;
 62.1021 -            }
 62.1022 -
 62.1023 -            if (actual->isCharArray()) {
 62.1024 -                // String assignment can have a truncated |given|.
 62.1025 -                if (given->fixedLength() > actual->fixedLength()) {
 62.1026 -                    cc_.reportError(pos, Message_ArrayAssignmentTooBig);
 62.1027 -                    return NULL;
 62.1028 -                }
 62.1029 -            } else {
 62.1030 -                if (given->fixedLength() != actual->fixedLength()) {
 62.1031 -                    cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 62.1032 -                    return NULL;
 62.1033 -                }
 62.1034 -            }
 62.1035 -        } else if (given->isFixedLength()) {
 62.1036 -            // We do not allow assignments in the form:
 62.1037 -            //  [][] = [][Y]
 62.1038 -            //
 62.1039 -            // Otherwise, the following code could break the size guarantees
 62.1040 -            // of the right-hand side:
 62.1041 -            //
 62.1042 -            //  new x[][5];
 62.1043 -            //  new y[][];
 62.1044 -            //  new z[3];
 62.1045 -            //
 62.1046 -            //
 62.1047 -            //  y = x;
 62.1048 -            //  y[0] = z;
 62.1049 -            //
 62.1050 -            // Now |x[0]| contains a 3-length array.
 62.1051 -            if (level > 1) {
 62.1052 -                cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 62.1053 -                return NULL;
 62.1054 -            }
 62.1055 -        }
 62.1056 -
 62.1057 -        if (!given->contained()->isArray() || !actual->contained()->isArray())
 62.1058 -            break;
 62.1059 -
 62.1060 -        given = ArrayType::cast(given->contained());
 62.1061 -        actual = ArrayType::cast(actual->contained());
 62.1062 -    }
 62.1063 -
 62.1064 -    bool givenConst = !!(given->contained()->quals() & TypeQual_Const);
 62.1065 -    bool actualConst = !!(actual->contained()->quals() & TypeQual_Const);
 62.1066 -
 62.1067 -    // These arrays must contain the same innermost type.
 62.1068 -    if (given->contained()->unqualified() != actual->contained()->unqualified() ||
 62.1069 -        (givenConst && !actualConst))
 62.1070 -    {
 62.1071 -        char aname[255];
 62.1072 -        char gname[255];
 62.1073 -        cc_.reportError(pos, Message_TypeMismatch,
 62.1074 -                        GetTypeName(argActual, aname, sizeof(aname)),
 62.1075 -                        GetTypeName(argGiven, gname, sizeof(gname)));
 62.1076 -        return NULL;
 62.1077 -    }
 62.1078 -
 62.1079 -    return from;
 62.1080 -}
 62.1081 -
 62.1082 -HIR *
 62.1083 -SemanticAnalysis::typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to)
 62.1084 -{
 62.1085 -    char fname[255];
 62.1086 -    char tname[255];
 62.1087 -    cc_.reportError(pos, Message_InvalidCoercion,
 62.1088 -                    GetTypeName(from, fname, sizeof(fname)),
 62.1089 -                    GetTypeName(to, tname, sizeof(tname)));
 62.1090 -    return NULL;
 62.1091 -}
 62.1092 -
 62.1093 -HIR *
 62.1094 -SemanticAnalysis::coerce(HIR *hir, Handle<Type> to, CoercionKind kind)
 62.1095 -{
 62.1096 -    Local<Type> from(zone_, hir->type());
 62.1097 -
 62.1098 -    // If the source is *ever* an importable, we just fail.
 62.1099 -    if (from->isImportable())
 62.1100 -        return typeFailure(hir->node()->pos(), from, to);
 62.1101 -
 62.1102 -    if (from->isInt32() && to->isFloat())
 62.1103 -        return new (pool_) HConvert(hir->node(), to, OP_CVT_I2F, hir);
 62.1104 -    if (from->isInt32() && to->isBool())
 62.1105 -        return new (pool_) HConvert(hir->node(), to, OP_CVT_I2B, hir);
 62.1106 -
 62.1107 -    if (to->isEnum() && from->unqualified() != to->unqualified())
 62.1108 -        return typeFailure(hir->node()->pos(), from, to);
 62.1109 -    
 62.1110 -    if (to->isArray()) {
 62.1111 -        Local<ArrayType> atype(zone_, ArrayType::cast(to));
 62.1112 -        return typeCheckArray(hir->node()->pos(), hir, atype, kind);
 62.1113 -    }
 62.1114 -    
 62.1115 -    return hir;
 62.1116 -}
 62.1117 -
 62.1118 -void
 62.1119 -SemanticAnalysis::set(VariableSymbol *sym)
 62.1120 -{
 62.1121 -    if (sym->scope()->kind() == Scope::GLOBAL) {
 62.1122 -        __ setglobal(sym);
 62.1123 -    } else {
 62.1124 -        assert(sym->storage() == VariableSymbol::Local);
 62.1125 -        __ setlocal(sym);
 62.1126 -    }
 62.1127 -}
 62.1128 -
 62.1129 -HIR *
 62.1130 -SemanticAnalysis::binary(AstNode *node, TokenKind token, HIR *left, HIR *right)
 62.1131 -{
 62.1132 -    Local<Type> coercion(zone_, coercionType(token, left, right));
 62.1133 -    if (!coercion)
 62.1134 -        return NULL;
 62.1135 -    if ((left = coerce(left, coercion, Coerce_Arg)) == NULL)
 62.1136 -        return NULL;
 62.1137 -    if ((right = coerce(right, coercion, Coerce_Arg)) == NULL)
 62.1138 -        return NULL;
 62.1139 -    
 62.1140 -    switch (token) {
 62.1141 -     case TOK_PLUS:
 62.1142 -      case TOK_MINUS:
 62.1143 -      case TOK_STAR:
 62.1144 -      case TOK_SLASH:
 62.1145 -      case TOK_PERCENT:
 62.1146 -      case TOK_AMPERSAND:
 62.1147 -      case TOK_BITOR:
 62.1148 -      case TOK_BITXOR:
 62.1149 -      case TOK_SHR:
 62.1150 -      case TOK_USHR:
 62.1151 -      case TOK_SHL:
 62.1152 -        return new (pool_) HBinary(node, left->type(), token, left, right);
 62.1153 -
 62.1154 -      case TOK_EQUALS:
 62.1155 -      case TOK_NOTEQUALS:
 62.1156 -      case TOK_LT:
 62.1157 -      case TOK_LE:
 62.1158 -      case TOK_GT:
 62.1159 -      case TOK_GE:
 62.1160 -      case TOK_AND:
 62.1161 -      case TOK_OR:
 62.1162 -      {
 62.1163 -        Local<Type> result(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
 62.1164 -        return new (pool_) HBinary(node, result, token, left, right);
 62.1165 -      }
 62.1166 -
 62.1167 -      default:
 62.1168 -        assert(false);
 62.1169 -        return NULL;
 62.1170 -    }
 62.1171 -}
 62.1172 -
 62.1173 -static inline bool
 62.1174 -IsValidUncheckedType(Type *type)
 62.1175 -{
 62.1176 -    return type->isEnum() ||
 62.1177 -           type->isFloat() ||
 62.1178 -           type->isInt32() ||
 62.1179 -           type->isChar() ||
 62.1180 -           type->isUnchecked() ||
 62.1181 -           type->isBool();
 62.1182 -}
 62.1183 -
 62.1184 -void
 62.1185 -SemanticAnalysis::visitUnaryExpression(UnaryExpression *node)
 62.1186 -{
 62.1187 -    HIR *hir = eval(node->expression());
 62.1188 -    if (!hir)
 62.1189 -        return;
 62.1190 -
 62.1191 -    switch (node->token()) {
 62.1192 -      case TOK_TILDE:
 62.1193 -      {
 62.1194 -        if (!hir->type()->isInt32() && !hir->type()->isEnum()) {
 62.1195 -            char name[255];
 62.1196 -            cc_.reportError(node->pos(), Message_InvalidUnaryType,
 62.1197 -                            "~",
 62.1198 -                            GetTypeName(hir->type(), name, sizeof(name)));
 62.1199 -        }
 62.1200 -        Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
 62.1201 -        hir_ = new (pool_) HUnary(node, hir->type(), TOK_TILDE, hir);
 62.1202 -        return;
 62.1203 -      }
 62.1204 -
 62.1205 -      case TOK_MINUS:
 62.1206 -      {
 62.1207 -        if (hir->type()->isInt32() || hir->type()->isEnum()) {
 62.1208 -            Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
 62.1209 -            hir_ = new (pool_) HUnary(node, type, TOK_MINUS, hir);
 62.1210 -            return;
 62.1211 -        }
 62.1212 -        if (hir->type()->isFloat()) {
 62.1213 -            hir_ = new (pool_) HUnary(node, hir->type(), TOK_MINUS, hir);
 62.1214 -            return;
 62.1215 -        }
 62.1216 -
 62.1217 -        char name[255];
 62.1218 -        cc_.reportError(node->pos(), Message_InvalidUnaryType,
 62.1219 -                        "-",
 62.1220 -                        GetTypeName(hir->type(), name, sizeof(name)));
 62.1221 -        break;
 62.1222 -      }
 62.1223 -
 62.1224 -      default:
 62.1225 -      {
 62.1226 -        assert(node->token() == TOK_LABEL);
 62.1227 -
 62.1228 -        TypeSymbol *sym = node->tag()->sym()->asType();
 62.1229 -        if (!sym) {
 62.1230 -            cc_.reportError(node->pos(), Message_IdentifierIsNotAType,
 62.1231 -                            sym->name()->chars());
 62.1232 -            return;
 62.1233 -        }
 62.1234 -
 62.1235 -        if (!IsValidUncheckedType(sym->effective())) {
 62.1236 -            char name[255];
 62.1237 -            cc_.reportError(node->pos(), Message_InvalidUncheckedCastTo,
 62.1238 -                            GetTypeName(sym->type(), name, sizeof(name)));
 62.1239 -            return;
 62.1240 -        }
 62.1241 -        if (!IsValidUncheckedType(hir->type())) {
 62.1242 -            char name[255];
 62.1243 -            cc_.reportError(node->pos(), Message_InvalidUncheckedCastFrom,
 62.1244 -                            GetTypeName(hir->type(), name, sizeof(name)));
 62.1245 -            return;
 62.1246 -        }
 62.1247 -
 62.1248 -        hir_ = new (pool_) HUnary(node, sym->effective(), TOK_LABEL, hir);
 62.1249 -        break;
 62.1250 -      }
 62.1251 -    }
 62.1252 -}
 62.1253 -
 62.1254 -void
 62.1255 -SemanticAnalysis::import(HIR *hir, FieldExpression *node)
 62.1256 -{
 62.1257 -    // Note that we don't care if the hir type is "importable", since we
 62.1258 -    // can only do anything if the important has a constant binding.
 62.1259 -    unsigned index = hir->toImport()->index();
 62.1260 -    Local<Importable> importable(zone_, unit_->module()->getImportAt(index));
 62.1261 -
 62.1262 -    if (importable->isPackage()) {
 62.1263 -        // Look at what's already loaded and see if anything exists. We
 62.1264 -        // can't create stuff on-demand here since it's too late to add
 62.1265 -        // new translation units to the CompileContext.
 62.1266 -        Local<Package> package(zone_, Package::cast(importable));
 62.1267 -        Local<Importable> found(zone_, package->import(node->field()));
 62.1268 -        if (!found) {
 62.1269 -            cc_.reportError(node->pos(), Message_PackageDoesNotHaveMember, node->field()->chars());
 62.1270 -            return;
 62.1271 -        }
 62.1272 -
 62.1273 -        // If we did find something, make sure it is in our import list.
 62.1274 -        // If we didn't explicitly import it, we have no right to use it.
 62.1275 -        for (index = 0; index < unit_->module()->imports(); index++) {
 62.1276 -            if (unit_->module()->getImportAt(index) == importable)
 62.1277 -                break;
 62.1278 -        }
 62.1279 -
 62.1280 -        if (index == unit_->module()->imports()) {
 62.1281 -            cc_.reportError(node->pos(), Message_ImportWasNeverImported, node->field()->chars());
 62.1282 -            return;
 62.1283 -        }
 62.1284 -
 62.1285 -        // Just create a new HImport.
 62.1286 -        hir_ = new (pool_) HImport(node, hir->type(), index);
 62.1287 -    } else {
 62.1288 -        // Modules can never have sub-modules or sub-packages.
 62.1289 -        unsigned index;
 62.1290 -        Local<Module> module(zone_, Module::cast(importable));
 62.1291 -        Local<StructMap> map(zone_, module->globals()->map());
 62.1292 -        Local<Descriptor> desc(zone_, map->type()->lookupField(node->field(), &index));
 62.1293 -        if (!desc) {
 62.1294 -            cc_.reportError(node->pos(), Message_FieldNotFound, node->field()->chars());
 62.1295 -            return;
 62.1296 -        }
 62.1297 -        hir_ = new (pool_) HField(node, hir, desc->type(), index);
 62.1298 -    }
 62.1299 -}
 62.1300 -
 62.1301 -void
 62.1302 -SemanticAnalysis::visitFieldExpression(FieldExpression *node)
 62.1303 -{
 62.1304 -    HIR *hir = eval(node->left());
 62.1305 -    if (!hir)
 62.1306 -        return;
 62.1307 -
 62.1308 -    if (hir->isImport()) {
 62.1309 -        import(hir, node);
 62.1310 -        return;
 62.1311 -    }
 62.1312 -
 62.1313 -    char name[255];
 62.1314 -    cc_.reportError(node->pos(), Message_InvalidFieldExpression,
 62.1315 -                    GetTypeName(hir->type(), name, sizeof(name)));
 62.1316 -}
 62.1317 -
 62.1318 -static inline TokenKind
 62.1319 -ToCompare(Expression *expr)
 62.1320 -{
 62.1321 -    if (expr->isBinaryExpression()) {
 62.1322 -        BinaryExpression *b = expr->toBinaryExpression();
 62.1323 -        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
 62.1324 -            return b->token();
 62.1325 -    } else if (expr->isUnaryExpression()) {
 62.1326 -        UnaryExpression *u = expr->toUnaryExpression();
 62.1327 -        if (u->token() == TOK_NOT)
 62.1328 -            return TOK_NOT;
 62.1329 -    }
 62.1330 -    return TOK_EOF;
 62.1331 -}
 62.1332 -
 62.1333 -void
 62.1334 -SemanticAnalysis::visitForTest(Expression *expr,
 62.1335 -                               Label *trueBranch,
 62.1336 -                               Label *falseBranch,
 62.1337 -                               Label *fallthrough)
 62.1338 -{
 62.1339 -    Local<Type> boolType(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
 62.1340 -
 62.1341 -    TokenKind token = ToCompare(expr);
 62.1342 -    if (token == TOK_EOF || token == TOK_NOT) {
 62.1343 -        HIR *hir;
 62.1344 -        if (token == TOK_EOF)
 62.1345 -            hir = eval(expr);
 62.1346 -        else
 62.1347 -            hir = eval(expr->toUnaryExpression()->expression());
 62.1348 -        if (!hir)
 62.1349 -            return;
 62.1350 -        if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
 62.1351 -            return;
 62.1352 -
 62.1353 -        discharge(hir);
 62.1354 -
 62.1355 -        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
 62.1356 -        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
 62.1357 -        
 62.1358 -        if (fallthrough == falseBranch)
 62.1359 -            __ j(op, trueBranch);
 62.1360 -        else
 62.1361 -            __ j(op, falseBranch);
 62.1362 -        return;
 62.1363 -    }
 62.1364 -
 62.1365 -    BinaryExpression *bin = expr->toBinaryExpression();
 62.1366 -    if (token == TOK_AND || token == TOK_OR) {
 62.1367 -        Label next;
 62.1368 -        if (token == TOK_AND)
 62.1369 -            visitForTest(bin->left(), &next, falseBranch, &next);
 62.1370 -        else
 62.1371 -            visitForTest(bin->left(), trueBranch, &next, &next);
 62.1372 -        __ bind(&next);
 62.1373 -        visitForTest(bin->right(), trueBranch, falseBranch, fallthrough);
 62.1374 -        return;
 62.1375 -    }
 62.1376 -
 62.1377 -    HIR *left = eval(bin->left());
 62.1378 -    HIR *right = eval(bin->right());
 62.1379 -    if (!left || !right)
 62.1380 -        return;
 62.1381 -
 62.1382 -    HIR *hir = binary(bin, bin->token(), left, right);
 62.1383 -    if (!hir)
 62.1384 -        return;
 62.1385 -    if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
 62.1386 -        return;
 62.1387 -
 62.1388 -    discharge(hir);
 62.1389 -    if (fallthrough == trueBranch)
 62.1390 -        __ j(OP_JF, falseBranch);
 62.1391 -    else
 62.1392 -        __ j(OP_JT, trueBranch);
 62.1393 -}
 62.1394 -
 62.1395 -HLValue *
 62.1396 -SemanticAnalysis::lvalue(Expression *expr)
 62.1397 -{
 62.1398 -    HIR *hir = eval(expr);
 62.1399 -    if (!hir)
 62.1400 -        return NULL;
 62.1401 -    
 62.1402 -    if (!hir->isLValue()) {
 62.1403 -        cc_.reportError(expr->pos(), Message_ExpectedLValue);
 62.1404 -        return NULL;
 62.1405 -    }
 62.1406 -
 62.1407 -    return static_cast<HLValue *>(hir);
 62.1408 -}
 62.1409 -
 62.1410 -HIR *
 62.1411 -SemanticAnalysis::eval(Expression *expr)
 62.1412 -{
 62.1413 -    assert(!hir_);
 62.1414 -    expr->accept(this);
 62.1415 -
 62.1416 -    HIR *hir = hir_;
 62.1417 -    hir_ = NULL;
 62.1418 -
 62.1419 -    return hir;
 62.1420 -}
 62.1421 -
 62.1422 -void
 62.1423 -SemanticAnalysis::discharge(HIR *hir)
 62.1424 -{
 62.1425 -    EmitHIR(zone_, emitter_, hir);
 62.1426 -}
 62.1427 +/* vim: set ts=4 sw=4 tw=99 et:
 62.1428 + *
 62.1429 + * Copyright (C) 2012 David Anderson
 62.1430 + *
 62.1431 + * This file is part of SourcePawn.
 62.1432 + *
 62.1433 + * SourcePawn is free software: you can redistribute it and/or modify it under
 62.1434 + * the terms of the GNU General Public License as published by the Free
 62.1435 + * Software Foundation, either version 3 of the License, or (at your option)
 62.1436 + * any later version.
 62.1437 + * 
 62.1438 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
 62.1439 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 62.1440 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 62.1441 + *
 62.1442 + * You should have received a copy of the GNU General Public License along with
 62.1443 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
 62.1444 + */
 62.1445 +#include <assert.h>
 62.1446 +#include "../Zone.h"
 62.1447 +#include "../Strings.h"
 62.1448 +#include "../NativeTable.h"
 62.1449 +#include "../TypeManager.h"
 62.1450 +#include "../Modules.h"
 62.1451 +#include "../Code.h"
 62.1452 +#include "SemanticAnalysis.h"
 62.1453 +#include "../Heap-inl.h"
 62.1454 +
 62.1455 +using namespace ke;
 62.1456 +
 62.1457 +#define __ emitter_.
 62.1458 +
 62.1459 +typedef BytecodeEmitter::Label Label;
 62.1460 +
 62.1461 +class AutoEnterScope
 62.1462 +{
 62.1463 +  public:
 62.1464 +    AutoEnterScope(Scope **prevp, Scope *scope)
 62.1465 +      : prevp_(prevp),
 62.1466 +        prev_(*prevp),
 62.1467 +        scope_(scope)
 62.1468 +    {
 62.1469 +        if (!scope_)
 62.1470 +            return;
 62.1471 +        prev_ = *prevp_;
 62.1472 +        *prevp_ = scope;
 62.1473 +        assert(prev_ == scope->enclosing());
 62.1474 +    }
 62.1475 +    ~AutoEnterScope()
 62.1476 +    {
 62.1477 +        if (scope_)
 62.1478 +            *prevp_ = prev_;
 62.1479 +    }
 62.1480 +  private:
 62.1481 +    Scope **prevp_;
 62.1482 +    Scope *prev_;
 62.1483 +    Scope *scope_;
 62.1484 +};
 62.1485 +
 62.1486 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit)
 62.1487 +  : zone_(zone),
 62.1488 +    pool_(zone->pool()),
 62.1489 +    cc_(cc),
 62.1490 +    unit_(unit),
 62.1491 +    hir_(NULL),
 62.1492 +    loop_(NULL)
 62.1493 +{
 62.1494 +}
 62.1495 +
 62.1496 +SemanticAnalysis::SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun)
 62.1497 +  : zone_(parent->zone_),
 62.1498 +    pool_(parent->pool_),
 62.1499 +    cc_(parent->cc_),
 62.1500 +    unit_(parent->unit_),
 62.1501 +    hir_(NULL),
 62.1502 +    scope_(parent->scope_),
 62.1503 +    fun_(fun),
 62.1504 +    loop_(NULL),
 62.1505 +    control_(NULL)
 62.1506 +{
 62.1507 +
 62.1508 +}
 62.1509 +
 62.1510 +void
 62.1511 +SemanticAnalysis::analyze()
 62.1512 +{
 62.1513 +    scope_ = unit_->globalScope();
 62.1514 +
 62.1515 +    for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
 62.1516 +        Statement *stmt = unit_->tree()->statements()->at(i);
 62.1517 +        stmt->accept(this);
 62.1518 +    }
 62.1519 +
 62.1520 +    Local<Code> code(zone_, __ finish());
 62.1521 +    if (!code)
 62.1522 +        return;
 62.1523 +    code->setModule(unit_->module());
 62.1524 +    unit_->module()->setCode(code);
 62.1525 +
 62.1526 +#ifndef NDEBUG
 62.1527 +//    Disassemble(code, stdout);
 62.1528 +#endif
 62.1529 +}
 62.1530 +
 62.1531 +void
 62.1532 +SemanticAnalysis::visitFunctionStatement(FunctionStatement *stmt)
 62.1533 +{
 62.1534 +    FunctionSymbol *sym = stmt->sym();
 62.1535 +    Local<FunctionType> type(zone_, sym->type());
 62.1536 +
 62.1537 +    assert(scope_->kind() == Scope::GLOBAL);
 62.1538 +
 62.1539 +    if (stmt->token() == TOK_NATIVE) {
 62.1540 +        // Define the native now.
 62.1541 +        size_t index;
 62.1542 +        if (!zone_->nativeTable()->add(stmt->name(), &index))
 62.1543 +            return;
 62.1544 +
 62.1545 +        Local<Native> native(zone_, Native::New(zone_, type, index));
 62.1546 +        if (!native)
 62.1547 +            return;
 62.1548 +
 62.1549 +        __ object(native);
 62.1550 +        __ setglobal(sym);
 62.1551 +        __ pop();
 62.1552 +    }
 62.1553 +
 62.1554 +    // If the function is a forward or native, we don't have to do anything.
 62.1555 +    if (stmt->token() == TOK_NATIVE || stmt->token() == TOK_FORWARD)
 62.1556 +        return;
 62.1557 +
 62.1558 +    SemanticAnalysis child(this, type);
 62.1559 +    Local<Function> funobj(zone_, child.compile(stmt));
 62.1560 +    if (!funobj)
 62.1561 +        return;
 62.1562 +
 62.1563 +    __ object(funobj);
 62.1564 +    __ setglobal(sym);
 62.1565 +    if (stmt->token() == TOK_PUBLIC)
 62.1566 +        __ public_();
 62.1567 +    else
 62.1568 +        __ pop();
 62.1569 +}
 62.1570 +
 62.1571 +Function *
 62.1572 +SemanticAnalysis::compile(FunctionStatement *stmt)
 62.1573 +{
 62.1574 +    __ setFirstLine(stmt->pos().line);
 62.1575 +
 62.1576 +    AutoEnterScope argScope(&scope_, stmt->argScope());
 62.1577 +
 62.1578 +    for (size_t i = 0; i < stmt->signature().parameters()->length(); i++) {
 62.1579 +        Parameter *param = stmt->signature().parameters()->at(i);
 62.1580 +        param->sym()->allocate(VariableSymbol::Arg, i);
 62.1581 +    }
 62.1582 +
 62.1583 +    AutoEnterScope varScope(&scope_, stmt->varScope());
 62.1584 +    ControlStatus status = visitForControl(stmt->body());
 62.1585 +
 62.1586 +    if (!fun_->returnType()->isVoid()) {
 62.1587 +        // If the function is not void, report if not all paths return a value.
 62.1588 +        // All other incorrect return cases have been caught already.
 62.1589 +        if (status.returns() == Returns_Sometimes) {
 62.1590 +            cc_.reportError(stmt->pos(), Message_NotAllPathsReturnValue);
 62.1591 +            return NULL;
 62.1592 +        }
 62.1593 +
 62.1594 +        if (status.returns() == Returns_Never) {
 62.1595 +            cc_.reportError(stmt->pos(), Message_MissingReturnValue);
 62.1596 +            return NULL;
 62.1597 +        }
 62.1598 +    }
 62.1599 +
 62.1600 +    Local<Code> code(zone_, __ finish());
 62.1601 +    if (!code)
 62.1602 +        return NULL;
 62.1603 +    code->setModule(unit_->module());
 62.1604 +
 62.1605 +    Local<Function> fun(zone_, Function::New(zone_, code, fun_, stmt->name(), stmt->pos()));
 62.1606 +    if (!fun)
 62.1607 +        return NULL;
 62.1608 +
 62.1609 +#ifndef NDEBUG
 62.1610 +//    Disassemble(code, stdout);
 62.1611 +#endif
 62.1612 +
 62.1613 +    return fun;
 62.1614 +}
 62.1615 +
 62.1616 +void 
 62.1617 +SemanticAnalysis::visitBlockStatement(BlockStatement *node)
 62.1618 +{
 62.1619 +    AutoEnterScope scope(&scope_, node->scope());
 62.1620 +
 62.1621 +    for (size_t i = 0; i < node->statements()->length(); i++) {
 62.1622 +        Statement *stmt = node->statements()->at(i);
 62.1623 +        __ note_position(stmt->pos());
 62.1624 +        stmt->accept(this);
 62.1625 +        assert(__ stackDepth() == 0);
 62.1626 +    }
 62.1627 +}
 62.1628 +
 62.1629 +void
 62.1630 +SemanticAnalysis::visitEnumStatement(EnumStatement *node)
 62.1631 +{
 62.1632 +}
 62.1633 +
 62.1634 +void
 62.1635 +SemanticAnalysis::visitExpressionStatement(ExpressionStatement *node)
 62.1636 +{
 62.1637 +    // While building HIR, we enter new pool and root scopes, since HIR
 62.1638 +    // creation is purely temporary.
 62.1639 +    PoolScope poolScope(zone_->pool());
 62.1640 +    RootScope rootScope(zone_);
 62.1641 +
 62.1642 +    HIR *hir = eval(node->expression());
 62.1643 +    if (!hir)
 62.1644 +        return;
 62.1645 +
 62.1646 +    discharge(hir);
 62.1647 +    if (!hir->type()->isVoid())
 62.1648 +        __ pop();
 62.1649 +}
 62.1650 +
 62.1651 +void
 62.1652 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
 62.1653 +{
 62.1654 +    // If both sides terminate in a return, we consider this a return as well.
 62.1655 +    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
 62.1656 +        terminate(Returns_Always);
 62.1657 +        return;
 62.1658 +    }
 62.1659 +
 62.1660 +    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
 62.1661 +                          ? Returns_Never
 62.1662 +                          : Returns_Sometimes;
 62.1663 +
 62.1664 +    if (left.terminates() && right.terminates())
 62.1665 +        terminate(status);
 62.1666 +    else
 62.1667 +        returns(status);
 62.1668 +}
 62.1669 +
 62.1670 +SemanticAnalysis::ControlStatus
 62.1671 +SemanticAnalysis::visitForControl(Statement *statement)
 62.1672 +{
 62.1673 +    ControlScope scope(&control_);
 62.1674 +    statement->accept(this);
 62.1675 +    return scope.status();
 62.1676 +}
 62.1677 +
 62.1678 +void
 62.1679 +SemanticAnalysis::visitIfStatement(IfStatement *node)
 62.1680 +{
 62.1681 +    Label join;
 62.1682 +
 62.1683 +    ControlStatus trueBranch;
 62.1684 +    ControlStatus falseBranch(false, Returns_Never);
 62.1685 +
 62.1686 +    if (!node->ifFalse()) {
 62.1687 +        Label success;
 62.1688 +
 62.1689 +        visitForTest(node->condition(), &success, &join, &success);
 62.1690 +        __ bind(&success);
 62.1691 +        trueBranch = visitForControl(node->ifTrue());
 62.1692 +    } else {
 62.1693 +        Label success, next;
 62.1694 +
 62.1695 +        visitForTest(node->condition(), &success, &next, &success);
 62.1696 +        __ bind(&success);
 62.1697 +        trueBranch = visitForControl(node->ifTrue());
 62.1698 +        __ jump(&join);
 62.1699 +        __ bind(&next);
 62.1700 +        falseBranch = visitForControl(node->ifFalse());
 62.1701 +    }
 62.1702 +
 62.1703 +    __ bind(&join);
 62.1704 +
 62.1705 +    control_->merge(trueBranch, falseBranch);
 62.1706 +}
 62.1707 +
 62.1708 +void
 62.1709 +SemanticAnalysis::requireLifoStack()
 62.1710 +{
 62.1711 +    if (!loop_)
 62.1712 +        return;
 62.1713 +
 62.1714 +    loop_->setUsesLifoStack();
 62.1715 +}
 62.1716 +
 62.1717 +SemanticAnalysis::ControlStatus
 62.1718 +SemanticAnalysis::visitLoopBody(Statement *stmt)
 62.1719 +{
 62.1720 +    // We always mark off a loop body, so on each edge, we can balance the
 62.1721 +    // LIFO stack. Right now, we don't have the ability to budget the LIFO
 62.1722 +    // stack ahead of time. If we turn out to never need the LIFO stack, we
 62.1723 +    // mark it as unnecessary. (The interpreter can't really make use of this,
 62.1724 +    // but the JIT can).
 62.1725 +    //
 62.1726 +    // Note that balancing the LIFO stack isn't even necessary, so this
 62.1727 +    // feature may be removed. All this mechanism does is mitigate the
 62.1728 +    // possibility that a long-running loop will overflow the LIFO region
 62.1729 +    // and therefore start requiring nursery allocations.
 62.1730 +    int pos = __ enterloop();
 62.1731 +    ControlStatus status = visitForControl(stmt);
 62.1732 +    __ leaveloop();
 62.1733 +
 62.1734 +    if (loop_->usesLifoStack())
 62.1735 +        __ setLoopUsesLifoStack(pos);
 62.1736 +
 62.1737 +    return status;
 62.1738 +}
 62.1739 +
 62.1740 +void
 62.1741 +SemanticAnalysis::visitForStatement(ForStatement *node)
 62.1742 +{
 62.1743 +    AutoEnterScope scope(&scope_, node->scope());
 62.1744 +    PoolScope poolScope(zone_->pool());
 62.1745 +    RootScope rootScope(zone_);
 62.1746 +
 62.1747 +    Label join, update;
 62.1748 +    LoopScope loop(scope_, &join, &update, &loop_);
 62.1749 +
 62.1750 +    if (node->initialization())
 62.1751 +        node->initialization()->accept(this);
 62.1752 +
 62.1753 +    Label header, test;
 62.1754 +    if (node->condition())
 62.1755 +        __ jump(&test);
 62.1756 +
 62.1757 +    __ bind(&header);
 62.1758 +    ControlStatus status = visitLoopBody(node->body());
 62.1759 +
 62.1760 +    __ bind(&update);
 62.1761 +    if (node->update())
 62.1762 +        node->update()->accept(this);
 62.1763 +
 62.1764 +    if (node->condition()) {
 62.1765 +        __ bind(&test);
 62.1766 +        visitForTest(node->condition(), &header, &join, &join);
 62.1767 +    } else {
 62.1768 +        __ jump(&header);
 62.1769 +    }
 62.1770 +
 62.1771 +    __ bind(&join);
 62.1772 +    
 62.1773 +    // If there was a condition, we treat this like a while loop. Otherwise,
 62.1774 +    // the join point is only reachable if the loop contains a break. The
 62.1775 +    // termination status doesn't tell us anything yet.
 62.1776 +    if (node->condition() || loop.breaks())
 62.1777 +        control_->merge(status, ControlStatus(false, Returns_Never));
 62.1778 +    else
 62.1779 +        control_->terminate(status.returns());
 62.1780 +
 62.1781 +    assert(__ stackDepth() == 0);
 62.1782 +}
 62.1783 +
 62.1784 +void
 62.1785 +SemanticAnalysis::visitWhileStatement(WhileStatement *node)
 62.1786 +{
 62.1787 +    PoolScope poolScope(zone_->pool());
 62.1788 +    RootScope rootScope(zone_);
 62.1789 +
 62.1790 +    Label header, join;
 62.1791 +
 62.1792 +    __ bind(&header);
 62.1793 +
 62.1794 +    ControlStatus status;
 62.1795 +
 62.1796 +    LoopScope loop(scope_, &join, &header, &loop_);
 62.1797 +    if (node->token() == TOK_WHILE) {
 62.1798 +        Label body;
 62.1799 +        visitForTest(node->condition(), &body, &join, &body);
 62.1800 +        status = visitLoopBody(node->body());
 62.1801 +        __ jump(&header);
 62.1802 +    } else {
 62.1803 +        status = visitLoopBody(node->body());
 62.1804 +        visitForTest(node->condition(), &header, &join, &join);
 62.1805 +    }
 62.1806 +
 62.1807 +    __ bind(&join);
 62.1808 +
 62.1809 +    // Detect loops that will always have a fork in the contro-flow graph.
 62.1810 +    // This will be a |while| loop, or a |do-while| loop whose body does
 62.1811 +    // not terminate. For now, we treat these as an |if| regardless of the
 62.1812 +    // direction the branch can take. That means the control-flow is always
 62.1813 +    // conditional.
 62.1814 +    if (node->token() == TOK_WHILE || status.terminates() || loop.breaks()) {
 62.1815 +        control_->merge(status, ControlStatus(false, Returns_Never));
 62.1816 +    } else {
 62.1817 +        // At this point, we've got a do-while loop with a |return| or
 62.1818 +        // |continue|, meaning that the rest of the block is unreachable.
 62.1819 +        control_->terminate(status.returns());
 62.1820 +    }
 62.1821 +
 62.1822 +    assert(__ stackDepth() == 0);
 62.1823 +}
 62.1824 +
 62.1825 +static inline Heap::Tenure
 62.1826 +InferTenure(Symbol *sym)
 62.1827 +{
 62.1828 +    if (sym->scope()->kind() == Scope::GLOBAL)
 62.1829 +        return Heap::Tenure_Old;
 62.1830 +
 62.1831 +    // SP2's array semantics allow any array kind to escape, so we must use
 62.1832 +    // the normal heap. (Hopefully escape analysis can ease this pain later).
 62.1833 +    if (sym->type()->isArray())
 62.1834 +        return Heap::Tenure_Default;
 62.1835 +
 62.1836 +    return Heap::Tenure_Default;
 62.1837 +}
 62.1838 +
 62.1839 +void
 62.1840 +SemanticAnalysis::visitVariableDeclaration(VariableDeclaration *node)
 62.1841 +{
 62.1842 +    PoolScope poolScope(zone_->pool());
 62.1843 +    RootScope rootScope(zone_);
 62.1844 +
 62.1845 +    Local<Type> type(zone_, node->sym()->type());
 62.1846 +
 62.1847 +    if (node->sym()->type()->isVoid()) {
 62.1848 +        cc_.reportError(node->type()->pos(), Message_CannotDeclareVoid);
 62.1849 +        return;
 62.1850 +    }
 62.1851 +
 62.1852 +    if (node->initialization()) {
 62.1853 +        HIR *hir = NULL;
 62.1854 +
 62.1855 +        if ((hir = eval(node->initialization())) == NULL)
 62.1856 +            return;
 62.1857 +        if ((hir = coerce(hir, type, Coerce_Decl)) == NULL)
 62.1858 +            return;
 62.1859 +
 62.1860 +        discharge(hir);
 62.1861 +    } else {
 62.1862 +        if (type->isInt32() || type->isEnum() ||
 62.1863 +            type->isChar() || type->isBool())
 62.1864 +        {
 62.1865 +            __ int_(0);
 62.1866 +        } else if (type->isFloat()) {
 62.1867 +            __ float_(0);
 62.1868 +        } else if (type->isArray()) {
 62.1869 +            Local<ArrayType> atype(zone_, ArrayType::cast(type));
 62.1870 +            Local<ArrayMap> map(zone_, atype->newMap());
 62.1871 +            if (!map)
 62.1872 +                return;
 62.1873 +
 62.1874 +            if (atype->isFixedLength()) {
 62.1875 +                __ newarray(OP_NEWFIXED, map, InferTenure(node->sym()));
 62.1876 +            } else if (node->dims()->at(0)) {
 62.1877 +                // This may not be true if we allow typedefing, so :TODO:
 62.1878 +                // figure out proper semantics.
 62.1879 +                assert(node->dims()->length() == atype->levels());
 62.1880 +
 62.1881 +                Local<Type> i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
 62.1882 +                for (size_t i = 0; i < node->dims()->length(); i++) {
 62.1883 +                    Expression *expr = node->dims()->at(i);
 62.1884 +                    if (expr) {
 62.1885 +                        HIR *hir = eval(expr);
 62.1886 +                        if (!hir || ((hir = coerce(hir, i32, Coerce_Arg)) == NULL))
 62.1887 +                            return;
 62.1888 +                        discharge(hir);
 62.1889 +                    } else {
 62.1890 +                        __ int_(0);
 62.1891 +                    }
 62.1892 +                }
 62.1893 +                __ newarray(OP_NEWSIZED, map, InferTenure(node->sym()));
 62.1894 +            } else {
 62.1895 +                __ newarray(OP_NEWEMPTY, map, InferTenure(node->sym()));
 62.1896 +            }
 62.1897 +        } else {
 62.1898 +            assert(false);
 62.1899 +        }
 62.1900 +    }
 62.1901 +
 62.1902 +    if (node->sym()->scope()->kind() != Scope::GLOBAL) {
 62.1903 +        if (!__ allocate(node->sym()))
 62.1904 +            return;
 62.1905 +    }
 62.1906 +
 62.1907 +    set(node->sym());
 62.1908 +    __ pop();
 62.1909 +}
 62.1910 +
 62.1911 +void
 62.1912 +SemanticAnalysis::visitReturnStatement(ReturnStatement *node)
 62.1913 +{
 62.1914 +    control_->returns(Returns_Always);
 62.1915 +
 62.1916 +    if (!node->expression()) {
 62.1917 +        if (!fun_->returnType()->isVoid()) {
 62.1918 +            cc_.reportError(node->pos(), Message_MissingReturnValue);
 62.1919 +            return;
 62.1920 +        }
 62.1921 +
 62.1922 +        __ returnvoid();
 62.1923 +        return;
 62.1924 +    }
 62.1925 +
 62.1926 +    if (fun_->returnType()->isVoid()) {
 62.1927 +        cc_.reportError(node->pos(), Message_UsedVoidReturn);
 62.1928 +        return;
 62.1929 +    }
 62.1930 +
 62.1931 +    PoolScope poolScope(zone_->pool());
 62.1932 +    RootScope rootScope(zone_);
 62.1933 +
 62.1934 +    HIR *hir = eval(node->expression());
 62.1935 +    if (!hir)
 62.1936 +        return;
 62.1937 +
 62.1938 +    Local<Type> returnType(zone_, fun_->returnType());
 62.1939 +    if ((hir = coerce(hir, returnType, Coerce_Return)) == NULL)
 62.1940 +        return;
 62.1941 +
 62.1942 +    discharge(hir);
 62.1943 +
 62.1944 +    if (hir->type()->isVoid())
 62.1945 +        __ returnvoid();
 62.1946 +    else
 62.1947 +        __ return_();
 62.1948 +}
 62.1949 +
 62.1950 +void
 62.1951 +SemanticAnalysis::visitBinaryExpression(BinaryExpression *node)
 62.1952 +{
 62.1953 +    HIR *left = eval(node->left());
 62.1954 +    HIR *right = eval(node->right());
 62.1955 +    if (!left || !right)
 62.1956 +        return;
 62.1957 +
 62.1958 +    hir_ = binary(node, node->token(), left, right);
 62.1959 +}
 62.1960 +
 62.1961 +bool
 62.1962 +SemanticAnalysis::checkArgumentCount(Handle<FunctionType> type, unsigned actual)
 62.1963 +{
 62.1964 +    if (type->parameters()->length() == actual)
 62.1965 +        return true;
 62.1966 +
 62.1967 +    if (actual > type->parameters()->length()) {
 62.1968 +        if (!type->isNative() || !type->isNativeVariadic())
 62.1969 +            return false;
 62.1970 +        return true;
 62.1971 +    }
 62.1972 +
 62.1973 +    if (!type->defaults())
 62.1974 +        return false;
 62.1975 +
 62.1976 +    // Missing arguments. See if there's a default argument for each missing
 62.1977 +    // actual.
 62.1978 +    for (unsigned i = actual; i < type->parameters()->length(); i++) {
 62.1979 +        if (!type->defaults()->at(i))
 62.1980 +            return false;
 62.1981 +    }
 62.1982 +
 62.1983 +    return true;
 62.1984 +}
 62.1985 +
 62.1986 +static unsigned
 62.1987 +BindImplicitName(Module *from, ImplicitSymbol *sym)
 62.1988 +{
 62.1989 +    if (sym->bound())
 62.1990 +        return sym->fieldIndex();
 62.1991 +
 62.1992 +    Module *module = Module::cast(from->getImportAt(sym->index()));
 62.1993 +    StructMap *map = module->globals()->map();
 62.1994 +
 62.1995 +    unsigned fieldIndex;
 62.1996 +    Descriptor *desc = map->type()->lookupField(sym->name(), &fieldIndex);
 62.1997 +    assert(desc && desc->type() == sym->type());
 62.1998 +
 62.1999 +    sym->bind(fieldIndex);
 62.2000 +    return fieldIndex;
 62.2001 +}
 62.2002 +
 62.2003 +void
 62.2004 +SemanticAnalysis::visitNameProxy(NameProxy *proxy)
 62.2005 +{
 62.2006 +    Symbol *sym = proxy->sym();
 62.2007 +
 62.2008 +    switch (sym->kind()) {
 62.2009 +      case Symbol::kImport:
 62.2010 +      {
 62.2011 +        ImportSymbol *import = sym->toImport();
 62.2012 +        hir_ = new (pool_) HImport(proxy, sym->type(), import->index());
 62.2013 +        break;
 62.2014 +      }
 62.2015 +
 62.2016 +      case Symbol::kImplicit:
 62.2017 +      {
 62.2018 +        ImplicitSymbol *import = sym->toImplicit();
 62.2019 +        unsigned fieldIndex = BindImplicitName(unit_->module(), import);
 62.2020 +
 62.2021 +        hir_ = new (pool_) HImport(proxy, zone_->types()->getImportable(), import->index());
 62.2022 +        hir_ = new (pool_) HField(proxy, hir_, sym->type(), fieldIndex);
 62.2023 +        break;
 62.2024 +      }
 62.2025 +
 62.2026 +      case Symbol::kConstant:
 62.2027 +      {
 62.2028 +        ConstantSymbol *val = sym->toConstant();
 62.2029 +        hir_ = new (pool_) HInteger(proxy, sym->type(), val->value().toInt());
 62.2030 +        break;
 62.2031 +      }
 62.2032 +      
 62.2033 +      // This is kind of screwy. Symbol::kFunction is like a constant we can't
 62.2034 +      // evaluate yet. Maybe we should extract the GLOBAL case and say that
 62.2035 +      // kFunction is only used for global functions (and use const vars for
 62.2036 +      // local functions).
 62.2037 +      case Symbol::kFunction:
 62.2038 +      case Symbol::kVariable:
 62.2039 +      {
 62.2040 +        Scope *in = sym->scope();
 62.2041 +        switch (in->kind()) {
 62.2042 +          case Scope::GLOBAL:
 62.2043 +            hir_ = new (pool_) HGlobal(proxy, sym);
 62.2044 +            break;
 62.2045 +
 62.2046 +          case Scope::FUNCTION:
 62.2047 +          {
 62.2048 +            VariableSymbol *var = sym->toVariable();
 62.2049 +            assert(var->storage() == VariableSymbol::Arg);
 62.2050 +            hir_ = new (pool_) HLocal(proxy, var);
 62.2051 +            break;
 62.2052 +          }
 62.2053 +
 62.2054 +          default:
 62.2055 +          {
 62.2056 +            VariableSymbol *var = sym->toVariable();
 62.2057 +            assert(in->kind() == Scope::BLOCK);
 62.2058 +            assert(var->storage() == VariableSymbol::Local);
 62.2059 +            hir_ = new (pool_) HLocal(proxy, var);
 62.2060 +            break;
 62.2061 +          }
 62.2062 +        }
 62.2063 +        break;
 62.2064 +      }
 62.2065 +
 62.2066 +      default:
 62.2067 +        // :TODO:
 62.2068 +        assert(false);
 62.2069 +    }
 62.2070 +}
 62.2071 +
 62.2072 +void
 62.2073 +SemanticAnalysis::visitBooleanLiteral(BooleanLiteral *node)
 62.2074 +{
 62.2075 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
 62.2076 +    hir_ = new (pool_) HBoolean(node, type, node->token() == TOK_TRUE);
 62.2077 +}
 62.2078 +
 62.2079 +void
 62.2080 +SemanticAnalysis::visitIntegerLiteral(IntegerLiteral *lit)
 62.2081 +{
 62.2082 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
 62.2083 +    hir_ = new (pool_) HInteger(lit, type, lit->value());
 62.2084 +}
 62.2085 +
 62.2086 +void
 62.2087 +SemanticAnalysis::visitFloatLiteral(FloatLiteral *node)
 62.2088 +{
 62.2089 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
 62.2090 +    hir_ = new (pool_) HFloat(node, type, (float)node->value());
 62.2091 +}
 62.2092 +
 62.2093 +void
 62.2094 +SemanticAnalysis::visitStringLiteral(StringLiteral *node)
 62.2095 +{
 62.2096 +    Type *type = zone_->types()->getString();
 62.2097 +    hir_ = new (pool_) HString(node, type, node->string());
 62.2098 +}
 62.2099 +
 62.2100 +void
 62.2101 +SemanticAnalysis::visitCallExpression(CallExpression *node)
 62.2102 +{
 62.2103 +    HIR *callee = eval(node->callee());
 62.2104 +    if (!callee)
 62.2105 +        return;
 62.2106 +
 62.2107 +    if (!callee->type()->isFunction()) {
 62.2108 +        cc_.reportError(node->pos(), Message_CalleeNotFunction);
 62.2109 +        return;
 62.2110 +    }
 62.2111 +
 62.2112 +    Local<FunctionType> fun(zone_, FunctionType::cast(callee->type()));
 62.2113 +    
 62.2114 +    if (!checkArgumentCount(fun, node->arguments()->length())) {
 62.2115 +        cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
 62.2116 +        return;
 62.2117 +    }
 62.2118 +
 62.2119 +    if (fun->isForward()) {
 62.2120 +        cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
 62.2121 +        return;
 62.2122 +    }
 62.2123 +
 62.2124 +    HIRList *args = new (pool_) HIRList;
 62.2125 +    for (unsigned i = 0; i < node->arguments()->length(); i++) {
 62.2126 +        Expression *expression = node->arguments()->at(i);
 62.2127 +        HIR *arg = eval(expression);
 62.2128 +        if (!arg)
 62.2129 +            return;
 62.2130 +
 62.2131 +        Handle<Type> given = arg->type();
 62.2132 +        
 62.2133 +        bool mustComputeReference;
 62.2134 +        if (i >= fun->parameters()->length()) {
 62.2135 +            // Special handling for natives. Arguments past the formal must
 62.2136 +            // always have references computed. However, arrays are already
 62.2137 +            // references for natives.
 62.2138 +            assert(fun->isNative() && fun->isNativeVariadic());
 62.2139 +            mustComputeReference = !given->isReference() &&
 62.2140 +                                   !given->isArray();
 62.2141 +        } else {
 62.2142 +            Local<Type> actual(zone_, fun->parameterAt(i));
 62.2143 +
 62.2144 +            if (expression->isIndexExpression() && arg->isIndex()) {
 62.2145 +                // If the expression is the form x[y], and this produced a
 62.2146 +                // normal array indexing operation, then we apply some 
 62.2147 +                // special rules.
 62.2148 +
 62.2149 +                if (actual->isReference()) {
 62.2150 +                    // Disabled, since this doesn't have easily definable or
 62.2151 +                    // sensible semantics with SP2 arrays, but we don't want
 62.2152 +                    // to silently break SP1 semantics.
 62.2153 +                    cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
 62.2154 +                    return;
 62.2155 +                }
 62.2156 +
 62.2157 +                // As a special rule to account for SP1 semantics, we allow x[y]
 62.2158 +                // to automatically compute a sliced, read-only array view if
 62.2159 +                // the desired type is an array of one more dimension than x[y]
 62.2160 +                // would return.
 62.2161 +                //
 62.2162 +                // As an additional restriction, this is only allowed for
 62.2163 +                // one-level char arrays, to minimize potential issues until
 62.2164 +                // we determine whether more compatibility is needed.
 62.2165 +                //
 62.2166 +                // Internally, for sanity, the dependent array operation does
 62.2167 +                // not necessarily create a dependent array. For extensible
 62.2168 +                // arrays, we instead create a duplicate arrary of just the
 62.2169 +                // sliced portion, rather than deal with the complexity of the
 62.2170 +                // source array being resized.
 62.2171 +                //
 62.2172 +                // Note that we don't really know whether a dependent array
 62.2173 +                // will be dependent at compile-time, so the dependent type's
 62.2174 +                // just inherits from the source.
 62.2175 +                if (actual->isArray()) {
 62.2176 +                    HIndex *index = arg->toIndex();
 62.2177 +                    Local<ArrayType> basetype(zone_, ArrayType::cast(index->base()->type()));
 62.2178 +                    Local<ArrayType> atype(zone_, ArrayType::cast(actual));
 62.2179 +
 62.2180 +                    if (atype->isCharArray() && basetype->isCharArray()) {
 62.2181 +                        // There is no possible way this will type check, so
 62.2182 +                        // it's safe to just try something completely
 62.2183 +                        // different.
 62.2184 +                        Local<Type> slicetype(zone_);
 62.2185 +                        if (basetype->isFixedLength()) {
 62.2186 +                            // If the base type is fixed length, we need to
 62.2187 +                            // compute a new dynamic array type based on the
 62.2188 +                            // fixed array's contents and qualifiers.
 62.2189 +                            Local<Type> contained(zone_, basetype->contained());
 62.2190 +                            slicetype = zone_->types()->newArray(contained, ArrayType::DYNAMIC_ARRAY_SIZE);
 62.2191 +                            if (!slicetype)
 62.2192 +                                return;
 62.2193 +                            slicetype = zone_->types()->qualify(slicetype, basetype->quals());
 62.2194 +                            if (!slicetype)
 62.2195 +                                return;
 62.2196 +                        } else {
 62.2197 +                            slicetype = basetype;
 62.2198 +                        }
 62.2199 +                        arg = new (pool_) HNewDependentArray(expression, slicetype, index->base(), index->index());
 62.2200 +                        given = arg->type();
 62.2201 +                    }
 62.2202 +                }
 62.2203 +            }
 62.2204 +
 62.2205 +            if (actual->isReference()) {
 62.2206 +                // If the actual is a reference, the coercion rules are much
 62.2207 +                // stricter; the contained types must be identical.
 62.2208 +                // :TODO: make this not an assert
 62.2209 +                assert(ReferenceType::cast(actual)->contained() == arg->type());
 62.2210 +            } else {
 62.2211 +                // When we start overloading, coercion will have to happen later.
 62.2212 +                arg = coerce(arg, actual, Coerce_Arg);
 62.2213 +                if (!arg)
 62.2214 +                    return;
 62.2215 +            }
 62.2216 +
 62.2217 +            mustComputeReference = actual->isReference() && !given->isReference();
 62.2218 +        }
 62.2219 +
 62.2220 +        if (mustComputeReference) {
 62.2221 +            // Refs always use the LIFO stack if they can.
 62.2222 +            arg = new (pool_) HToRef(arg->node(), arg->type(), arg);
 62.2223 +            requireLifoStack();
 62.2224 +        }
 62.2225 +
 62.2226 +        if (!args->append(arg))
 62.2227 +            return;
 62.2228 +    }
 62.2229 +
 62.2230 +    hir_ = new (pool_) HCall(node, fun->returnType(), callee, args);
 62.2231 +}
 62.2232 +
 62.2233 +void
 62.2234 +SemanticAnalysis::visitAssignment(Assignment *node)
 62.2235 +{
 62.2236 +    HLValue *lval = lvalue(node->lvalue());
 62.2237 +    if (!lval)
 62.2238 +        return;
 62.2239 +
 62.2240 +    if (lval->type()->quals() & TypeQual_Const) {
 62.2241 +        cc_.reportError(node->pos(), Message_CannotModifyConst);
 62.2242 +        return;
 62.2243 +    }
 62.2244 +
 62.2245 +    HIR *hir = eval(node->expression());
 62.2246 +    if (!hir)
 62.2247 +        return;
 62.2248 +    if ((hir = coerce(hir, lval->type(), Coerce_Assign)) == NULL)
 62.2249 +        return;
 62.2250 +
 62.2251 +    hir_ = new (pool_) HStore(node, node->token(), lval, hir);
 62.2252 +}
 62.2253 +
 62.2254 +void
 62.2255 +SemanticAnalysis::visitBreakStatement(BreakStatement *node)
 62.2256 +{
 62.2257 +    if (!loop_) {
 62.2258 +        cc_.reportError(node->pos(), Message_BreakOutsideLoop);
 62.2259 +        return;
 62.2260 +    }
 62.2261 +
 62.2262 +    loop_->setBreaks();
 62.2263 +    __ j(OP_BREAK, loop_->break_());
 62.2264 +}
 62.2265 +
 62.2266 +void
 62.2267 +SemanticAnalysis::visitContinueStatement(ContinueStatement *node)
 62.2268 +{
 62.2269 +    if (!loop_) {
 62.2270 +        cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
 62.2271 +        return;
 62.2272 +    }
 62.2273 +
 62.2274 +    __ j(OP_CONTINUE, loop_->continue_());
 62.2275 +}
 62.2276 +
 62.2277 +void
 62.2278 +SemanticAnalysis::visitIndexExpression(IndexExpression *node)
 62.2279 +{
 62.2280 +    HIR *left = eval(node->left());
 62.2281 +    if (!left)
 62.2282 +        return;
 62.2283 +
 62.2284 +    HIR *right = eval(node->right());
 62.2285 +    if (!right)
 62.2286 +        return;
 62.2287 +
 62.2288 +    // Hrm... yes, for now, let's coerce here.
 62.2289 +    Local<Type> i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
 62.2290 +    if ((right = coerce(right, i32, Coerce_Arg)) == NULL)
 62.2291 +        return;
 62.2292 +    
 62.2293 +    // Do not coerce here, there's no reason to yet.
 62.2294 +    if (!left->type()->isArray()) {
 62.2295 +        cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
 62.2296 +        return;
 62.2297 +    }
 62.2298 +
 62.2299 +    hir_ = new (pool_) HIndex(node,
 62.2300 +                              ArrayType::cast(left->type())->contained(),
 62.2301 +                              left,
 62.2302 +                              right);
 62.2303 +}
 62.2304 +
 62.2305 +void
 62.2306 +SemanticAnalysis::visitIncDecExpression(IncDecExpression *node)
 62.2307 +{
 62.2308 +    HLValue *lval = lvalue(node->expression());
 62.2309 +    if (!lval)
 62.2310 +        return;
 62.2311 +
 62.2312 +    if (!lval->type()->isInt32() && !lval->type()->isFloat()) {
 62.2313 +        assert(false);
 62.2314 +        return;
 62.2315 +    }
 62.2316 +
 62.2317 +    HIR *rval;
 62.2318 +    if (lval->type()->isInt32())
 62.2319 +        rval = new (pool_) HInteger(node, lval->type(), 1);
 62.2320 +    else
 62.2321 +        rval = new (pool_) HFloat(node, lval->type(), 1.0);
 62.2322 +
 62.2323 +    if (node->postfix())
 62.2324 +        hir_ = new (pool_) HPostIncDec(node, node->token(), lval, rval);
 62.2325 +    else
 62.2326 +        hir_ = new (pool_) HStore(node, node->token(), lval, rval);
 62.2327 +}
 62.2328 +
 62.2329 +Type *
 62.2330 +SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right)
 62.2331 +{
 62.2332 +    Local<Type> l(zone_, left->type());
 62.2333 +    Local<Type> r(zone_, right->type());
 62.2334 +
 62.2335 +    if (l->isPod())
 62.2336 +        l = l->unqualified();
 62.2337 +    if (r->isPod())
 62.2338 +        r = r->unqualified();
 62.2339 +
 62.2340 +    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
 62.2341 +        (token >= TOK_EQUALS && token <= TOK_GE))
 62.2342 +    {
 62.2343 +        // We allow: [float|int32] + [float|int32]
 62.2344 +        if (l->isFloat() && r->isInt32())
 62.2345 +            return l;
 62.2346 +        if (l->isInt32() && r->isFloat())
 62.2347 +            return r;
 62.2348 +        if (l->isInt32() && r->isInt32())
 62.2349 +            return l;
 62.2350 +
 62.2351 +        if (l->isChar() && r->isInt32())
 62.2352 +             return r;
 62.2353 +        if (l->isInt32() && r->isChar())
 62.2354 +            return l;
 62.2355 +    }
 62.2356 +
 62.2357 +    // :TODO: remove
 62.2358 +    assert(*l == *r);
 62.2359 +
 62.2360 +    return left->type();
 62.2361 +}
 62.2362 +
 62.2363 +HIR *
 62.2364 +SemanticAnalysis::typeCheckArray(const SourcePosition &pos,
 62.2365 +                                 HIR *from,
 62.2366 +                                 Handle<ArrayType> argActual,
 62.2367 +                                 CoercionKind kind)
 62.2368 +{
 62.2369 +    Local<Type> argGiven(zone_, from->type());
 62.2370 +
 62.2371 +    // Special case: if we receive a string literal, and this is a char array,
 62.2372 +    // we allow a coercion.
 62.2373 +    if (from->isString() &&
 62.2374 +        argGiven->isString() &&
 62.2375 +        argActual->isArray() &&
 62.2376 +        ArrayType::cast(argActual)->isCharArray())
 62.2377 +    {
 62.2378 +        HString *hir = from->toString();
 62.2379 +        Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
 62.2380 +
 62.2381 +        if (actual->isFixedLength()) {
 62.2382 +            if (hir->string()->length() + 1 > actual->fixedLength()) {
 62.2383 +                cc_.reportError(pos, Message_ArrayAssignmentTooBig);
 62.2384 +                return NULL;
 62.2385 +            }
 62.2386 +        }
 62.2387 +
 62.2388 +        // Transform the string literal into an array literal. We give it the
 62.2389 +        // type of the left-hand side. The constness of the destination type
 62.2390 +        // will determine whether HArray duplicates it or not.
 62.2391 +        Local<ArrayMap> map(zone_, actual->newMap());
 62.2392 +        if (!map)
 62.2393 +            return NULL;
 62.2394 +
 62.2395 +        Local<Array> array(zone_);
 62.2396 +        array = Array::NewString(zone_,
 62.2397 +                                 map,
 62.2398 +                                 hir->string()->chars(),
 62.2399 +                                 hir->string()->length(),
 62.2400 +                                 Heap::Tenure_Old);
 62.2401 +        if (!array)
 62.2402 +            return NULL;
 62.2403 +
 62.2404 +        // Since we're creating a canonical copy of the char array, we have to
 62.2405 +        // be careful that it doesn't get mutated. There are two cases where
 62.2406 +        // we know it can't be mutated, and therefore don't need to specify
 62.2407 +        // that it be cloned after pushing it onto the stack.
 62.2408 +        //
 62.2409 +        //  (1) The array type is const.
 62.2410 +        //  (2) The array type is fixed-length, and the coercion is for
 62.2411 +        //      assignment, meaning it will be immediately copied.
 62.2412 +        //
 62.2413 +        // We treat declaration separately from assignment, since for
 62.2414 +        // declaration we can just immediately use the cloned version.
 62.2415 +        bool shouldDuplicate = true;
 62.2416 +        if ((actual->quals() & TypeQual_Const) ||
 62.2417 +            (actual->isFixedLength() && kind == Coerce_Assign))
 62.2418 +        {
 62.2419 +            shouldDuplicate = false;
 62.2420 +        }
 62.2421 +
 62.2422 +        return new (pool_) HArray(hir->node(), actual, array, shouldDuplicate);
 62.2423 +    }
 62.2424 +
 62.2425 +    if (!argGiven->isArray()) {
 62.2426 +        cc_.reportError(pos, Message_ExpectedArray);
 62.2427 +        return NULL;
 62.2428 +    }
 62.2429 +
 62.2430 +    Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
 62.2431 +    Local<ArrayType> given(zone_, ArrayType::cast(argGiven));
 62.2432 +
 62.2433 +    if (actual->levels() != given->levels()) {
 62.2434 +        cc_.reportError(pos, Message_ArrayDimensionsMismatch);
 62.2435 +        return NULL;
 62.2436 +    }
 62.2437 +
 62.2438 +    unsigned level = 1;
 62.2439 +    while (true) {
 62.2440 +        if (actual->isFixedLength()) {
 62.2441 +            if (!given->isFixedLength()) {
 62.2442 +                cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 62.2443 +                return NULL;
 62.2444 +            }
 62.2445 +
 62.2446 +            if (actual->isCharArray()) {
 62.2447 +                // String assignment can have a truncated |given|.
 62.2448 +                if (given->fixedLength() > actual->fixedLength()) {
 62.2449 +                    cc_.reportError(pos, Message_ArrayAssignmentTooBig);
 62.2450 +                    return NULL;
 62.2451 +                }
 62.2452 +            } else {
 62.2453 +                if (given->fixedLength() != actual->fixedLength()) {
 62.2454 +                    cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 62.2455 +                    return NULL;
 62.2456 +                }
 62.2457 +            }
 62.2458 +        } else if (given->isFixedLength()) {
 62.2459 +            // We do not allow assignments in the form:
 62.2460 +            //  [][] = [][Y]
 62.2461 +            //
 62.2462 +            // Otherwise, the following code could break the size guarantees
 62.2463 +            // of the right-hand side:
 62.2464 +            //
 62.2465 +            //  new x[][5];
 62.2466 +            //  new y[][];
 62.2467 +            //  new z[3];
 62.2468 +            //
 62.2469 +            //
 62.2470 +            //  y = x;
 62.2471 +            //  y[0] = z;
 62.2472 +            //
 62.2473 +            // Now |x[0]| contains a 3-length array.
 62.2474 +            if (level > 1) {
 62.2475 +                cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
 62.2476 +                return NULL;
 62.2477 +            }
 62.2478 +        }
 62.2479 +
 62.2480 +        if (!given->contained()->isArray() || !actual->contained()->isArray())
 62.2481 +            break;
 62.2482 +
 62.2483 +        given = ArrayType::cast(given->contained());
 62.2484 +        actual = ArrayType::cast(actual->contained());
 62.2485 +    }
 62.2486 +
 62.2487 +    bool givenConst = !!(given->contained()->quals() & TypeQual_Const);
 62.2488 +    bool actualConst = !!(actual->contained()->quals() & TypeQual_Const);
 62.2489 +
 62.2490 +    // These arrays must contain the same innermost type.
 62.2491 +    if (given->contained()->unqualified() != actual->contained()->unqualified() ||
 62.2492 +        (givenConst && !actualConst))
 62.2493 +    {
 62.2494 +        char aname[255];
 62.2495 +        char gname[255];
 62.2496 +        cc_.reportError(pos, Message_TypeMismatch,
 62.2497 +                        GetTypeName(argActual, aname, sizeof(aname)),
 62.2498 +                        GetTypeName(argGiven, gname, sizeof(gname)));
 62.2499 +        return NULL;
 62.2500 +    }
 62.2501 +
 62.2502 +    return from;
 62.2503 +}
 62.2504 +
 62.2505 +HIR *
 62.2506 +SemanticAnalysis::typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to)
 62.2507 +{
 62.2508 +    char fname[255];
 62.2509 +    char tname[255];
 62.2510 +    cc_.reportError(pos, Message_InvalidCoercion,
 62.2511 +                    GetTypeName(from, fname, sizeof(fname)),
 62.2512 +                    GetTypeName(to, tname, sizeof(tname)));
 62.2513 +    return NULL;
 62.2514 +}
 62.2515 +
 62.2516 +HIR *
 62.2517 +SemanticAnalysis::coerce(HIR *hir, Handle<Type> to, CoercionKind kind)
 62.2518 +{
 62.2519 +    Local<Type> from(zone_, hir->type());
 62.2520 +
 62.2521 +    // If the source is *ever* an importable, we just fail.
 62.2522 +    if (from->isImportable())
 62.2523 +        return typeFailure(hir->node()->pos(), from, to);
 62.2524 +
 62.2525 +    if (from->isInt32() && to->isFloat())
 62.2526 +        return new (pool_) HConvert(hir->node(), to, OP_CVT_I2F, hir);
 62.2527 +    if (from->isInt32() && to->isBool())
 62.2528 +        return new (pool_) HConvert(hir->node(), to, OP_CVT_I2B, hir);
 62.2529 +
 62.2530 +    if (to->isEnum() && from->unqualified() != to->unqualified())
 62.2531 +        return typeFailure(hir->node()->pos(), from, to);
 62.2532 +    
 62.2533 +    if (to->isArray()) {
 62.2534 +        Local<ArrayType> atype(zone_, ArrayType::cast(to));
 62.2535 +        return typeCheckArray(hir->node()->pos(), hir, atype, kind);
 62.2536 +    }
 62.2537 +    
 62.2538 +    return hir;
 62.2539 +}
 62.2540 +
 62.2541 +void
 62.2542 +SemanticAnalysis::set(VariableSymbol *sym)
 62.2543 +{
 62.2544 +    if (sym->scope()->kind() == Scope::GLOBAL) {
 62.2545 +        __ setglobal(sym);
 62.2546 +    } else {
 62.2547 +        assert(sym->storage() == VariableSymbol::Local);
 62.2548 +        __ setlocal(sym);
 62.2549 +    }
 62.2550 +}
 62.2551 +
 62.2552 +HIR *
 62.2553 +SemanticAnalysis::binary(AstNode *node, TokenKind token, HIR *left, HIR *right)
 62.2554 +{
 62.2555 +    Local<Type> coercion(zone_, coercionType(token, left, right));
 62.2556 +    if (!coercion)
 62.2557 +        return NULL;
 62.2558 +    if ((left = coerce(left, coercion, Coerce_Arg)) == NULL)
 62.2559 +        return NULL;
 62.2560 +    if ((right = coerce(right, coercion, Coerce_Arg)) == NULL)
 62.2561 +        return NULL;
 62.2562 +    
 62.2563 +    switch (token) {
 62.2564 +     case TOK_PLUS:
 62.2565 +      case TOK_MINUS:
 62.2566 +      case TOK_STAR:
 62.2567 +      case TOK_SLASH:
 62.2568 +      case TOK_PERCENT:
 62.2569 +      case TOK_AMPERSAND:
 62.2570 +      case TOK_BITOR:
 62.2571 +      case TOK_BITXOR:
 62.2572 +      case TOK_SHR:
 62.2573 +      case TOK_USHR:
 62.2574 +      case TOK_SHL:
 62.2575 +        return new (pool_) HBinary(node, left->type(), token, left, right);
 62.2576 +
 62.2577 +      case TOK_EQUALS:
 62.2578 +      case TOK_NOTEQUALS:
 62.2579 +      case TOK_LT:
 62.2580 +      case TOK_LE:
 62.2581 +      case TOK_GT:
 62.2582 +      case TOK_GE:
 62.2583 +      case TOK_AND:
 62.2584 +      case TOK_OR:
 62.2585 +      {
 62.2586 +        Local<Type> result(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
 62.2587 +        return new (pool_) HBinary(node, result, token, left, right);
 62.2588 +      }
 62.2589 +
 62.2590 +      default:
 62.2591 +        assert(false);
 62.2592 +        return NULL;
 62.2593 +    }
 62.2594 +}
 62.2595 +
 62.2596 +static inline bool
 62.2597 +IsValidUncheckedType(Type *type)
 62.2598 +{
 62.2599 +    return type->isEnum() ||
 62.2600 +           type->isFloat() ||
 62.2601 +           type->isInt32() ||
 62.2602 +           type->isChar() ||
 62.2603 +           type->isUnchecked() ||
 62.2604 +           type->isBool();
 62.2605 +}
 62.2606 +
 62.2607 +void
 62.2608 +SemanticAnalysis::visitUnaryExpression(UnaryExpression *node)
 62.2609 +{
 62.2610 +    HIR *hir = eval(node->expression());
 62.2611 +    if (!hir)
 62.2612 +        return;
 62.2613 +
 62.2614 +    switch (node->token()) {
 62.2615 +      case TOK_TILDE:
 62.2616 +      {
 62.2617 +        if (!hir->type()->isInt32() && !hir->type()->isEnum()) {
 62.2618 +            char name[255];
 62.2619 +            cc_.reportError(node->pos(), Message_InvalidUnaryType,
 62.2620 +                            "~",
 62.2621 +                            GetTypeName(hir->type(), name, sizeof(name)));
 62.2622 +        }
 62.2623 +        Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
 62.2624 +        hir_ = new (pool_) HUnary(node, hir->type(), TOK_TILDE, hir);
 62.2625 +        return;
 62.2626 +      }
 62.2627 +
 62.2628 +      case TOK_MINUS:
 62.2629 +      {
 62.2630 +        if (hir->type()->isInt32() || hir->type()->isEnum()) {
 62.2631 +            Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
 62.2632 +            hir_ = new (pool_) HUnary(node, type, TOK_MINUS, hir);
 62.2633 +            return;
 62.2634 +        }
 62.2635 +        if (hir->type()->isFloat()) {
 62.2636 +            hir_ = new (pool_) HUnary(node, hir->type(), TOK_MINUS, hir);
 62.2637 +            return;
 62.2638 +        }
 62.2639 +
 62.2640 +        char name[255];
 62.2641 +        cc_.reportError(node->pos(), Message_InvalidUnaryType,
 62.2642 +                        "-",
 62.2643 +                        GetTypeName(hir->type(), name, sizeof(name)));
 62.2644 +        break;
 62.2645 +      }
 62.2646 +
 62.2647 +      default:
 62.2648 +      {
 62.2649 +        assert(node->token() == TOK_LABEL);
 62.2650 +
 62.2651 +        TypeSymbol *sym = node->tag()->sym()->asType();
 62.2652 +        if (!sym) {
 62.2653 +            cc_.reportError(node->pos(), Message_IdentifierIsNotAType,
 62.2654 +                            sym->name()->chars());
 62.2655 +            return;
 62.2656 +        }
 62.2657 +
 62.2658 +        if (!IsValidUncheckedType(sym->effective())) {
 62.2659 +            char name[255];
 62.2660 +            cc_.reportError(node->pos(), Message_InvalidUncheckedCastTo,
 62.2661 +                            GetTypeName(sym->type(), name, sizeof(name)));
 62.2662 +            return;
 62.2663 +        }
 62.2664 +        if (!IsValidUncheckedType(hir->type())) {
 62.2665 +            char name[255];
 62.2666 +            cc_.reportError(node->pos(), Message_InvalidUncheckedCastFrom,
 62.2667 +                            GetTypeName(hir->type(), name, sizeof(name)));
 62.2668 +            return;
 62.2669 +        }
 62.2670 +
 62.2671 +        hir_ = new (pool_) HUnary(node, sym->effective(), TOK_LABEL, hir);
 62.2672 +        break;
 62.2673 +      }
 62.2674 +    }
 62.2675 +}
 62.2676 +
 62.2677 +void
 62.2678 +SemanticAnalysis::import(HIR *hir, FieldExpression *node)
 62.2679 +{
 62.2680 +    // Note that we don't care if the hir type is "importable", since we
 62.2681 +    // can only do anything if the important has a constant binding.
 62.2682 +    unsigned index = hir->toImport()->index();
 62.2683 +    Local<Importable> importable(zone_, unit_->module()->getImportAt(index));
 62.2684 +
 62.2685 +    if (importable->isPackage()) {
 62.2686 +        // Look at what's already loaded and see if anything exists. We
 62.2687 +        // can't create stuff on-demand here since it's too late to add
 62.2688 +        // new translation units to the CompileContext.
 62.2689 +        Local<Package> package(zone_, Package::cast(importable));
 62.2690 +        Local<Importable> found(zone_, package->import(node->field()));
 62.2691 +        if (!found) {
 62.2692 +            cc_.reportError(node->pos(), Message_PackageDoesNotHaveMember, node->field()->chars());
 62.2693 +            return;
 62.2694 +        }
 62.2695 +
 62.2696 +        // If we did find something, make sure it is in our import list.
 62.2697 +        // If we didn't explicitly import it, we have no right to use it.
 62.2698 +        for (index = 0; index < unit_->module()->imports(); index++) {
 62.2699 +            if (unit_->module()->getImportAt(index) == importable)
 62.2700 +                break;
 62.2701 +        }
 62.2702 +
 62.2703 +        if (index == unit_->module()->imports()) {
 62.2704 +            cc_.reportError(node->pos(), Message_ImportWasNeverImported, node->field()->chars());
 62.2705 +            return;
 62.2706 +        }
 62.2707 +
 62.2708 +        // Just create a new HImport.
 62.2709 +        hir_ = new (pool_) HImport(node, hir->type(), index);
 62.2710 +    } else {
 62.2711 +        // Modules can never have sub-modules or sub-packages.
 62.2712 +        unsigned index;
 62.2713 +        Local<Module> module(zone_, Module::cast(importable));
 62.2714 +        Local<StructMap> map(zone_, module->globals()->map());
 62.2715 +        Local<Descriptor> desc(zone_, map->type()->lookupField(node->field(), &index));
 62.2716 +        if (!desc) {
 62.2717 +            cc_.reportError(node->pos(), Message_FieldNotFound, node->field()->chars());
 62.2718 +            return;
 62.2719 +        }
 62.2720 +        hir_ = new (pool_) HField(node, hir, desc->type(), index);
 62.2721 +    }
 62.2722 +}
 62.2723 +
 62.2724 +void
 62.2725 +SemanticAnalysis::visitFieldExpression(FieldExpression *node)
 62.2726 +{
 62.2727 +    HIR *hir = eval(node->left());
 62.2728 +    if (!hir)
 62.2729 +        return;
 62.2730 +
 62.2731 +    if (hir->isImport()) {
 62.2732 +        import(hir, node);
 62.2733 +        return;
 62.2734 +    }
 62.2735 +
 62.2736 +    char name[255];
 62.2737 +    cc_.reportError(node->pos(), Message_InvalidFieldExpression,
 62.2738 +                    GetTypeName(hir->type(), name, sizeof(name)));
 62.2739 +}
 62.2740 +
 62.2741 +static inline TokenKind
 62.2742 +ToCompare(Expression *expr)
 62.2743 +{
 62.2744 +    if (expr->isBinaryExpression()) {
 62.2745 +        BinaryExpression *b = expr->toBinaryExpression();
 62.2746 +        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
 62.2747 +            return b->token();
 62.2748 +    } else if (expr->isUnaryExpression()) {
 62.2749 +        UnaryExpression *u = expr->toUnaryExpression();
 62.2750 +        if (u->token() == TOK_NOT)
 62.2751 +            return TOK_NOT;
 62.2752 +    }
 62.2753 +    return TOK_EOF;
 62.2754 +}
 62.2755 +
 62.2756 +void
 62.2757 +SemanticAnalysis::visitForTest(Expression *expr,
 62.2758 +                               Label *trueBranch,
 62.2759 +                               Label *falseBranch,
 62.2760 +                               Label *fallthrough)
 62.2761 +{
 62.2762 +    Local<Type> boolType(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
 62.2763 +
 62.2764 +    TokenKind token = ToCompare(expr);
 62.2765 +    if (token == TOK_EOF || token == TOK_NOT) {
 62.2766 +        HIR *hir;
 62.2767 +        if (token == TOK_EOF)
 62.2768 +            hir = eval(expr);
 62.2769 +        else
 62.2770 +            hir = eval(expr->toUnaryExpression()->expression());
 62.2771 +        if (!hir)
 62.2772 +            return;
 62.2773 +        if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
 62.2774 +            return;
 62.2775 +
 62.2776 +        discharge(hir);
 62.2777 +
 62.2778 +        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
 62.2779 +        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
 62.2780 +        
 62.2781 +        if (fallthrough == falseBranch)
 62.2782 +            __ j(op, trueBranch);
 62.2783 +        else
 62.2784 +            __ j(op, falseBranch);
 62.2785 +        return;
 62.2786 +    }
 62.2787 +
 62.2788 +    BinaryExpression *bin = expr->toBinaryExpression();
 62.2789 +    if (token == TOK_AND || token == TOK_OR) {
 62.2790 +        Label next;
 62.2791 +        if (token == TOK_AND)
 62.2792 +            visitForTest(bin->left(), &next, falseBranch, &next);
 62.2793 +        else
 62.2794 +            visitForTest(bin->left(), trueBranch, &next, &next);
 62.2795 +        __ bind(&next);
 62.2796 +        visitForTest(bin->right(), trueBranch, falseBranch, fallthrough);
 62.2797 +        return;
 62.2798 +    }
 62.2799 +
 62.2800 +    HIR *left = eval(bin->left());
 62.2801 +    HIR *right = eval(bin->right());
 62.2802 +    if (!left || !right)
 62.2803 +        return;
 62.2804 +
 62.2805 +    HIR *hir = binary(bin, bin->token(), left, right);
 62.2806 +    if (!hir)
 62.2807 +        return;
 62.2808 +    if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
 62.2809 +        return;
 62.2810 +
 62.2811 +    discharge(hir);
 62.2812 +    if (fallthrough == trueBranch)
 62.2813 +        __ j(OP_JF, falseBranch);
 62.2814 +    else
 62.2815 +        __ j(OP_JT, trueBranch);
 62.2816 +}
 62.2817 +
 62.2818 +HLValue *
 62.2819 +SemanticAnalysis::lvalue(Expression *expr)
 62.2820 +{
 62.2821 +    HIR *hir = eval(expr);
 62.2822 +    if (!hir)
 62.2823 +        return NULL;
 62.2824 +    
 62.2825 +    if (!hir->isLValue()) {
 62.2826 +        cc_.reportError(expr->pos(), Message_ExpectedLValue);
 62.2827 +        return NULL;
 62.2828 +    }
 62.2829 +
 62.2830 +    return static_cast<HLValue *>(hir);
 62.2831 +}
 62.2832 +
 62.2833 +HIR *
 62.2834 +SemanticAnalysis::eval(Expression *expr)
 62.2835 +{
 62.2836 +    assert(!hir_);
 62.2837 +    expr->accept(this);
 62.2838 +
 62.2839 +    HIR *hir = hir_;
 62.2840 +    hir_ = NULL;
 62.2841 +
 62.2842 +    return hir;
 62.2843 +}
 62.2844 +
 62.2845 +void
 62.2846 +SemanticAnalysis::discharge(HIR *hir)
 62.2847 +{
 62.2848 +    EmitHIR(zone_, emitter_, hir);
 62.2849 +}
    63.1 --- a/src/compiler/SemanticAnalysis.h	Mon Jun 10 00:46:29 2013 +0100
    63.2 +++ b/src/compiler/SemanticAnalysis.h	Mon Jun 10 01:04:43 2013 +0100
    63.3 @@ -1,259 +1,259 @@
    63.4 -/*
    63.5 - * Copyright (C) 2012 David Anderson
    63.6 - *
    63.7 - * This file is part of SourcePawn.
    63.8 - *
    63.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
   63.10 - * the terms of the GNU General Public License as published by the Free
   63.11 - * Software Foundation, either version 3 of the License, or (at your option)
   63.12 - * any later version.
   63.13 - * 
   63.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   63.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   63.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   63.17 - *
   63.18 - * You should have received a copy of the GNU General Public License along with
   63.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   63.20 - */
   63.21 -#ifndef _include_sp2_sema_h_
   63.22 -#define _include_sp2_sema_h_
   63.23 -
   63.24 -#include "AST.h"
   63.25 -#include "HIR.h"
   63.26 -#include "Scopes.h"
   63.27 -#include "BytecodeEmitter.h"
   63.28 -
   63.29 -namespace ke {
   63.30 -
   63.31 -// Semantic analysis occurs after all names and types have been bound. It
   63.32 -// performs the important task of validating the semantics and type safety
   63.33 -// of a parse tree.
   63.34 -// 
   63.35 -// The semantic analysis phase also produces bytecode. This occurs on a
   63.36 -// statement-by-statement basis. The result of analyzing an expression is a
   63.37 -// tree of operations which is then flattened.
   63.38 -class SemanticAnalysis : public AstVisitor
   63.39 -{
   63.40 -  public:
   63.41 -    SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit);
   63.42 -
   63.43 -    void analyze();
   63.44 -
   63.45 -  private:
   63.46 -    SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun);
   63.47 -    Function *compile(FunctionStatement *stmt);
   63.48 -
   63.49 -  public:
   63.50 -    void visitFunctionStatement(FunctionStatement *node);
   63.51 -    void visitBlockStatement(BlockStatement *node);
   63.52 -    void visitExpressionStatement(ExpressionStatement *node);
   63.53 -    void visitReturnStatement(ReturnStatement *node);
   63.54 -    void visitEnumStatement(EnumStatement *node);
   63.55 -
   63.56 -    void visitCallExpression(CallExpression *node);
   63.57 -    void visitNameProxy(NameProxy *name);
   63.58 -    void visitIntegerLiteral(IntegerLiteral *node);
   63.59 -    void visitFloatLiteral(FloatLiteral *node);
   63.60 -    void visitVariableDeclaration(VariableDeclaration *node);
   63.61 -    void visitForStatement(ForStatement *node);
   63.62 -    void visitWhileStatement(WhileStatement *node);
   63.63 -    void visitAssignment(Assignment *node);
   63.64 -    void visitBinaryExpression(BinaryExpression *node);
   63.65 -    void visitBreakStatement(BreakStatement *node);
   63.66 -    void visitContinueStatement(ContinueStatement *node);
   63.67 -    void visitIfStatement(IfStatement *node);
   63.68 -    void visitIndexExpression(IndexExpression *node);
   63.69 -    void visitIncDecExpression(IncDecExpression *node);
   63.70 -    void visitStringLiteral(StringLiteral *node);
   63.71 -    void visitUnaryExpression(UnaryExpression *node);
   63.72 -    void visitBooleanLiteral(BooleanLiteral *node);
   63.73 -    void visitFieldExpression(FieldExpression *node);
   63.74 -#if 0
   63.75 -    void visitFunctionTypeStatement(FunctionTypeStatement *node);
   63.76 -    void visitImportStatement(ImportStatement *node);
   63.77 -    void visitStructureStatement(StructureStatement *node);
   63.78 -    void visitSwitchStatement(SwitchStatement *node);
   63.79 -
   63.80 -    void visitTernaryExpression(TernaryExpression *node);
   63.81 -    void visitArrayLiteral(ArrayLiteral *node);
   63.82 -#endif
   63.83 -
   63.84 -  private:
   63.85 -    bool checkArgumentCount(Handle<FunctionType> type, unsigned actual);
   63.86 -    void import(HIR *hir, FieldExpression *node);
   63.87 -
   63.88 -  private:
   63.89 -    enum CoercionKind {
   63.90 -        Coerce_Arg,
   63.91 -        Coerce_Return,
   63.92 -        Coerce_Decl,
   63.93 -        Coerce_Assign
   63.94 -    };
   63.95 -
   63.96 -    // For a given control flow path, whether it returns.
   63.97 -    enum ReturnStatus
   63.98 -    {
   63.99 -        Returns_Never,
  63.100 -        Returns_Sometimes,
  63.101 -        Returns_Always
  63.102 -    };
  63.103 -
  63.104 -    // For a given control flow path, whether it terminates,
  63.105 -    // and if it terminates, whether it returns.
  63.106 -    class ControlStatus
  63.107 -    {
  63.108 -        bool terminates_;
  63.109 -        ReturnStatus returns_;
  63.110 -
  63.111 -      public:
  63.112 -        ControlStatus()
  63.113 -        {
  63.114 -        }
  63.115 -        ControlStatus(bool terminates, ReturnStatus returns)
  63.116 -          : terminates_(terminates),
  63.117 -            returns_(returns)
  63.118 -        {
  63.119 -        }
  63.120 -
  63.121 -        bool terminates() const {
  63.122 -            return terminates_;
  63.123 -        }
  63.124 -        ReturnStatus returns() const {
  63.125 -            return returns_;
  63.126 -        }
  63.127 -    };
  63.128 -
  63.129 -    class ControlScope
  63.130 -    {
  63.131 -        ReturnStatus returns_;
  63.132 -        ControlScope **prevp_;
  63.133 -        ControlScope *prev_;
  63.134 -        bool terminates_;
  63.135 -
  63.136 -      public:
  63.137 -        ControlScope(ControlScope **prevp)
  63.138 -          : returns_(Returns_Never),
  63.139 -            prevp_(prevp),
  63.140 -            prev_(*prevp),
  63.141 -            terminates_(false)
  63.142 -        {
  63.143 -            *prevp_ = this;
  63.144 -        }
  63.145 -        ~ControlScope() {
  63.146 -            *prevp_ = prev_;
  63.147 -        }
  63.148 -        ControlStatus status() {
  63.149 -            return ControlStatus(terminates_, returns_);
  63.150 -        }
  63.151 -
  63.152 -        void returns(ReturnStatus status) {
  63.153 -            // We allow multiple terminates, but only the first one takes
  63.154 -            // effect. For example, |break; continue;| is legal, but the
  63.155 -            // continue is unreachable.
  63.156 -            if (terminates_)
  63.157 -                return;
  63.158 -            if (status > returns_)
  63.159 -                returns_ = status;
  63.160 -        }
  63.161 -        void terminate(ReturnStatus status) {
  63.162 -            if (terminates_)
  63.163 -                return;
  63.164 -            terminates_ = true;
  63.165 -            returns_ = status;
  63.166 -        }
  63.167 -        void merge(const ControlStatus &left, const ControlStatus &right);
  63.168 -        void inherit(const ControlStatus &other);
  63.169 -    };
  63.170 -
  63.171 -
  63.172 -    void requireLifoStack();
  63.173 -    ControlStatus visitForControl(Statement *statement);
  63.174 -    ControlStatus visitLoopBody(Statement *stmt);
  63.175 -    void visitForTest(Expression *expr,
  63.176 -                      BytecodeEmitter::Label *trueBranch,
  63.177 -                      BytecodeEmitter::Label *falseBranch,
  63.178 -                      BytecodeEmitter::Label *fallthrough);
  63.179 -    void set(VariableSymbol *sym);
  63.180 -    HIR *eval(Expression *expr);
  63.181 -    HIR *binary(AstNode *node, TokenKind token, HIR *left, HIR *right);
  63.182 -    HIR *coerce(HIR *from, Handle<Type> to, CoercionKind kind);
  63.183 -    Type *coercionType(TokenKind token, HIR *left, HIR *right);
  63.184 -    HLValue *lvalue(Expression *expr);
  63.185 -    void discharge(HIR *hir);
  63.186 -    HIR *typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to);
  63.187 -
  63.188 -    HIR *typeCheckArray(const SourcePosition &pos,
  63.189 -                        HIR *from,
  63.190 -                        Handle<ArrayType> argActual,
  63.191 -                        CoercionKind kind);
  63.192 -
  63.193 -  private:
  63.194 -    // Used to target break/catch statements.
  63.195 -    class LoopScope
  63.196 -    {
  63.197 -        Scope *scope_;
  63.198 -        BytecodeEmitter::Label *bk_;
  63.199 -        BytecodeEmitter::Label *ct_;
  63.200 -        LoopScope **prevp_;
  63.201 -        LoopScope *prev_;
  63.202 -        bool usesLifoStack_;
  63.203 -        bool breaks_;
  63.204 -
  63.205 -      public:
  63.206 -        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
  63.207 -                  LoopScope **prevp)
  63.208 -          : scope_(scope),
  63.209 -            bk_(bk),
  63.210 -            ct_(ct),
  63.211 -            prevp_(prevp),
  63.212 -            prev_(*prevp),
  63.213 -            usesLifoStack_(false),
  63.214 -            breaks_(false)
  63.215 -        {
  63.216 -            *prevp_ = this;
  63.217 -        }
  63.218 -
  63.219 -        ~LoopScope()
  63.220 -        {
  63.221 -            *prevp_ = prev_;
  63.222 -        }
  63.223 -
  63.224 -        BytecodeEmitter::Label *break_() {
  63.225 -            return bk_;
  63.226 -        }
  63.227 -        BytecodeEmitter::Label *continue_() {
  63.228 -            return ct_;
  63.229 -        }
  63.230 -        Scope *scope() {
  63.231 -            return scope_;
  63.232 -        }
  63.233 -        void setUsesLifoStack() {
  63.234 -            usesLifoStack_ = true;
  63.235 -        }
  63.236 -        bool usesLifoStack() const {
  63.237 -            return usesLifoStack_;
  63.238 -        }
  63.239 -        void setBreaks() {
  63.240 -            breaks_ = true;
  63.241 -        }
  63.242 -        bool breaks() const {
  63.243 -            return breaks_;
  63.244 -        }
  63.245 -    };
  63.246 -    
  63.247 -  private:
  63.248 -    Zone *zone_;
  63.249 -    PoolAllocator &pool_;
  63.250 -    CompileContext &cc_;
  63.251 -    TranslationUnit *unit_;
  63.252 -    HIR *hir_;
  63.253 -    Scope *scope_;
  63.254 -    BytecodeEmitter emitter_;
  63.255 -    ScopedRoot<FunctionType> fun_;
  63.256 -    LoopScope *loop_;
  63.257 -    ControlScope *control_;
  63.258 -};
  63.259 -
  63.260 -} // namespace ke
  63.261 -
  63.262 -#endif // _include_sp2_sema_h_
  63.263 +/*
  63.264 + * Copyright (C) 2012 David Anderson
  63.265 + *
  63.266 + * This file is part of SourcePawn.
  63.267 + *
  63.268 + * SourcePawn is free software: you can redistribute it and/or modify it under
  63.269 + * the terms of the GNU General Public License as published by the Free
  63.270 + * Software Foundation, either version 3 of the License, or (at your option)
  63.271 + * any later version.
  63.272 + * 
  63.273 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  63.274 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  63.275 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  63.276 + *
  63.277 + * You should have received a copy of the GNU General Public License along with
  63.278 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  63.279 + */
  63.280 +#ifndef _include_sp2_sema_h_
  63.281 +#define _include_sp2_sema_h_
  63.282 +
  63.283 +#include "AST.h"
  63.284 +#include "HIR.h"
  63.285 +#include "Scopes.h"
  63.286 +#include "BytecodeEmitter.h"
  63.287 +
  63.288 +namespace ke {
  63.289 +
  63.290 +// Semantic analysis occurs after all names and types have been bound. It
  63.291 +// performs the important task of validating the semantics and type safety
  63.292 +// of a parse tree.
  63.293 +// 
  63.294 +// The semantic analysis phase also produces bytecode. This occurs on a
  63.295 +// statement-by-statement basis. The result of analyzing an expression is a
  63.296 +// tree of operations which is then flattened.
  63.297 +class SemanticAnalysis : public AstVisitor
  63.298 +{
  63.299 +  public:
  63.300 +    SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit);
  63.301 +
  63.302 +    void analyze();
  63.303 +
  63.304 +  private:
  63.305 +    SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun);
  63.306 +    Function *compile(FunctionStatement *stmt);
  63.307 +
  63.308 +  public:
  63.309 +    void visitFunctionStatement(FunctionStatement *node);
  63.310 +    void visitBlockStatement(BlockStatement *node);
  63.311 +    void visitExpressionStatement(ExpressionStatement *node);
  63.312 +    void visitReturnStatement(ReturnStatement *node);
  63.313 +    void visitEnumStatement(EnumStatement *node);
  63.314 +
  63.315 +    void visitCallExpression(CallExpression *node);
  63.316 +    void visitNameProxy(NameProxy *name);
  63.317 +    void visitIntegerLiteral(IntegerLiteral *node);
  63.318 +    void visitFloatLiteral(FloatLiteral *node);
  63.319 +    void visitVariableDeclaration(VariableDeclaration *node);
  63.320 +    void visitForStatement(ForStatement *node);
  63.321 +    void visitWhileStatement(WhileStatement *node);
  63.322 +    void visitAssignment(Assignment *node);
  63.323 +    void visitBinaryExpression(BinaryExpression *node);
  63.324 +    void visitBreakStatement(BreakStatement *node);
  63.325 +    void visitContinueStatement(ContinueStatement *node);
  63.326 +    void visitIfStatement(IfStatement *node);
  63.327 +    void visitIndexExpression(IndexExpression *node);
  63.328 +    void visitIncDecExpression(IncDecExpression *node);
  63.329 +    void visitStringLiteral(StringLiteral *node);
  63.330 +    void visitUnaryExpression(UnaryExpression *node);
  63.331 +    void visitBooleanLiteral(BooleanLiteral *node);
  63.332 +    void visitFieldExpression(FieldExpression *node);
  63.333 +#if 0
  63.334 +    void visitFunctionTypeStatement(FunctionTypeStatement *node);
  63.335 +    void visitImportStatement(ImportStatement *node);
  63.336 +    void visitStructureStatement(StructureStatement *node);
  63.337 +    void visitSwitchStatement(SwitchStatement *node);
  63.338 +
  63.339 +    void visitTernaryExpression(TernaryExpression *node);
  63.340 +    void visitArrayLiteral(ArrayLiteral *node);
  63.341 +#endif
  63.342 +
  63.343 +  private:
  63.344 +    bool checkArgumentCount(Handle<FunctionType> type, unsigned actual);
  63.345 +    void import(HIR *hir, FieldExpression *node);
  63.346 +
  63.347 +  private:
  63.348 +    enum CoercionKind {
  63.349 +        Coerce_Arg,
  63.350 +        Coerce_Return,
  63.351 +        Coerce_Decl,
  63.352 +        Coerce_Assign
  63.353 +    };
  63.354 +
  63.355 +    // For a given control flow path, whether it returns.
  63.356 +    enum ReturnStatus
  63.357 +    {
  63.358 +        Returns_Never,
  63.359 +        Returns_Sometimes,
  63.360 +        Returns_Always
  63.361 +    };
  63.362 +
  63.363 +    // For a given control flow path, whether it terminates,
  63.364 +    // and if it terminates, whether it returns.
  63.365 +    class ControlStatus
  63.366 +    {
  63.367 +        bool terminates_;
  63.368 +        ReturnStatus returns_;
  63.369 +
  63.370 +      public:
  63.371 +        ControlStatus()
  63.372 +        {
  63.373 +        }
  63.374 +        ControlStatus(bool terminates, ReturnStatus returns)
  63.375 +          : terminates_(terminates),
  63.376 +            returns_(returns)
  63.377 +        {
  63.378 +        }
  63.379 +
  63.380 +        bool terminates() const {
  63.381 +            return terminates_;
  63.382 +        }
  63.383 +        ReturnStatus returns() const {
  63.384 +            return returns_;
  63.385 +        }
  63.386 +    };
  63.387 +
  63.388 +    class ControlScope
  63.389 +    {
  63.390 +        ReturnStatus returns_;
  63.391 +        ControlScope **prevp_;
  63.392 +        ControlScope *prev_;
  63.393 +        bool terminates_;
  63.394 +
  63.395 +      public:
  63.396 +        ControlScope(ControlScope **prevp)
  63.397 +          : returns_(Returns_Never),
  63.398 +            prevp_(prevp),
  63.399 +            prev_(*prevp),
  63.400 +            terminates_(false)
  63.401 +        {
  63.402 +            *prevp_ = this;
  63.403 +        }
  63.404 +        ~ControlScope() {
  63.405 +            *prevp_ = prev_;
  63.406 +        }
  63.407 +        ControlStatus status() {
  63.408 +            return ControlStatus(terminates_, returns_);
  63.409 +        }
  63.410 +
  63.411 +        void returns(ReturnStatus status) {
  63.412 +            // We allow multiple terminates, but only the first one takes
  63.413 +            // effect. For example, |break; continue;| is legal, but the
  63.414 +            // continue is unreachable.
  63.415 +            if (terminates_)
  63.416 +                return;
  63.417 +            if (status > returns_)
  63.418 +                returns_ = status;
  63.419 +        }
  63.420 +        void terminate(ReturnStatus status) {
  63.421 +            if (terminates_)
  63.422 +                return;
  63.423 +            terminates_ = true;
  63.424 +            returns_ = status;
  63.425 +        }
  63.426 +        void merge(const ControlStatus &left, const ControlStatus &right);
  63.427 +        void inherit(const ControlStatus &other);
  63.428 +    };
  63.429 +
  63.430 +
  63.431 +    void requireLifoStack();
  63.432 +    ControlStatus visitForControl(Statement *statement);
  63.433 +    ControlStatus visitLoopBody(Statement *stmt);
  63.434 +    void visitForTest(Expression *expr,
  63.435 +                      BytecodeEmitter::Label *trueBranch,
  63.436 +                      BytecodeEmitter::Label *falseBranch,
  63.437 +                      BytecodeEmitter::Label *fallthrough);
  63.438 +    void set(VariableSymbol *sym);
  63.439 +    HIR *eval(Expression *expr);
  63.440 +    HIR *binary(AstNode *node, TokenKind token, HIR *left, HIR *right);
  63.441 +    HIR *coerce(HIR *from, Handle<Type> to, CoercionKind kind);
  63.442 +    Type *coercionType(TokenKind token, HIR *left, HIR *right);
  63.443 +    HLValue *lvalue(Expression *expr);
  63.444 +    void discharge(HIR *hir);
  63.445 +    HIR *typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to);
  63.446 +
  63.447 +    HIR *typeCheckArray(const SourcePosition &pos,
  63.448 +                        HIR *from,
  63.449 +                        Handle<ArrayType> argActual,
  63.450 +                        CoercionKind kind);
  63.451 +
  63.452 +  private:
  63.453 +    // Used to target break/catch statements.
  63.454 +    class LoopScope
  63.455 +    {
  63.456 +        Scope *scope_;
  63.457 +        BytecodeEmitter::Label *bk_;
  63.458 +        BytecodeEmitter::Label *ct_;
  63.459 +        LoopScope **prevp_;
  63.460 +        LoopScope *prev_;
  63.461 +        bool usesLifoStack_;
  63.462 +        bool breaks_;
  63.463 +
  63.464 +      public:
  63.465 +        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
  63.466 +                  LoopScope **prevp)
  63.467 +          : scope_(scope),
  63.468 +            bk_(bk),
  63.469 +            ct_(ct),
  63.470 +            prevp_(prevp),
  63.471 +            prev_(*prevp),
  63.472 +            usesLifoStack_(false),
  63.473 +            breaks_(false)
  63.474 +        {
  63.475 +            *prevp_ = this;
  63.476 +        }
  63.477 +
  63.478 +        ~LoopScope()
  63.479 +        {
  63.480 +            *prevp_ = prev_;
  63.481 +        }
  63.482 +
  63.483 +        BytecodeEmitter::Label *break_() {
  63.484 +            return bk_;
  63.485 +        }
  63.486 +        BytecodeEmitter::Label *continue_() {
  63.487 +            return ct_;
  63.488 +        }
  63.489 +        Scope *scope() {
  63.490 +            return scope_;
  63.491 +        }
  63.492 +        void setUsesLifoStack() {
  63.493 +            usesLifoStack_ = true;
  63.494 +        }
  63.495 +        bool usesLifoStack() const {
  63.496 +            return usesLifoStack_;
  63.497 +        }
  63.498 +        void setBreaks() {
  63.499 +            breaks_ = true;
  63.500 +        }
  63.501 +        bool breaks() const {
  63.502 +            return breaks_;
  63.503 +        }
  63.504 +    };
  63.505 +    
  63.506 +  private:
  63.507 +    Zone *zone_;
  63.508 +    PoolAllocator &pool_;
  63.509 +    CompileContext &cc_;
  63.510 +    TranslationUnit *unit_;
  63.511 +    HIR *hir_;
  63.512 +    Scope *scope_;
  63.513 +    BytecodeEmitter emitter_;
  63.514 +    ScopedRoot<FunctionType> fun_;
  63.515 +    LoopScope *loop_;
  63.516 +    ControlScope *control_;
  63.517 +};
  63.518 +
  63.519 +} // namespace ke
  63.520 +
  63.521 +#endif // _include_sp2_sema_h_
    64.1 --- a/src/compiler/Symbols.cpp	Mon Jun 10 00:46:29 2013 +0100
    64.2 +++ b/src/compiler/Symbols.cpp	Mon Jun 10 01:04:43 2013 +0100
    64.3 @@ -1,22 +1,22 @@
    64.4 -/* vim: set ts=4 sw=4 tw=99 et:
    64.5 - *
    64.6 - * Copyright (C) 2012 David Anderson
    64.7 - *
    64.8 - * This file is part of JITCraft.
    64.9 - *
   64.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   64.11 - * the terms of the GNU General Public License as published by the Free
   64.12 - * Software Foundation, either version 3 of the License, or (at your option)
   64.13 - * any later version.
   64.14 - * 
   64.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   64.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   64.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   64.18 - *
   64.19 - * You should have received a copy of the GNU General Public License along with
   64.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   64.21 - */
   64.22 -#include "Symbols.h"
   64.23 -#include "../Heap-inl.h"
   64.24 -#include "../Handles-inl.h"
   64.25 -
   64.26 +/* vim: set ts=4 sw=4 tw=99 et:
   64.27 + *
   64.28 + * Copyright (C) 2012 David Anderson
   64.29 + *
   64.30 + * This file is part of JITCraft.
   64.31 + *
   64.32 + * JITCraft is free software: you can redistribute it and/or modify it under
   64.33 + * the terms of the GNU General Public License as published by the Free
   64.34 + * Software Foundation, either version 3 of the License, or (at your option)
   64.35 + * any later version.
   64.36 + * 
   64.37 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   64.38 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   64.39 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   64.40 + *
   64.41 + * You should have received a copy of the GNU General Public License along with
   64.42 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   64.43 + */
   64.44 +#include "Symbols.h"
   64.45 +#include "../Heap-inl.h"
   64.46 +#include "../Handles-inl.h"
   64.47 +
    65.1 --- a/src/compiler/Symbols.h	Mon Jun 10 00:46:29 2013 +0100
    65.2 +++ b/src/compiler/Symbols.h	Mon Jun 10 01:04:43 2013 +0100
    65.3 @@ -1,278 +1,278 @@
    65.4 -/* vim: set ts=4 sw=4 tw=99 et:
    65.5 - *
    65.6 - * Copyright (C) 2012 David Anderson
    65.7 - *
    65.8 - * This file is part of SourcePawn.
    65.9 - *
   65.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   65.11 - * the terms of the GNU General Public License as published by the Free
   65.12 - * Software Foundation, either version 3 of the License, or (at your option)
   65.13 - * any later version.
   65.14 - * 
   65.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   65.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   65.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   65.18 - *
   65.19 - * You should have received a copy of the GNU General Public License along with
   65.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   65.21 - */
   65.22 -#ifndef _include_sp2_symbol_h_
   65.23 -#define _include_sp2_symbol_h_
   65.24 -
   65.25 -#include "../PoolAllocator.h"
   65.26 -#include "../Handles.h"
   65.27 -#include "../Opcodes.h"
   65.28 -#include "../Types.h"
   65.29 -#include "../Strings.h"
   65.30 -
   65.31 -namespace ke {
   65.32 -
   65.33 -class String;
   65.34 -
   65.35 -#define SYMBOL_KINDS(_) \
   65.36 -    /* Any kind of variable or argument produces a VariableSymbol. */ \
   65.37 -    _(Variable)         \
   65.38 -    /* A function declaration produces a FunctionSymbol. */ \
   65.39 -    _(Function)         \
   65.40 -    /* A named constant produces a ConstantSymbol. */ \
   65.41 -    _(Constant)         \
   65.42 -    /* A named type (class struct, typedef, etc) produces a TypeSymbol. */ \
   65.43 -    _(Type)             \
   65.44 -    /* An import name. */ \
   65.45 -    _(Import)           \
   65.46 -    /* A name implicitly derived from an import. */ \
   65.47 -    _(Implicit)
   65.48 -
   65.49 -#define _(name)     class name##Symbol;
   65.50 -SYMBOL_KINDS(_)
   65.51 -#undef _
   65.52 -
   65.53 -class Scope;
   65.54 -
   65.55 -// A symbol represents the declaration of a named entity.
   65.56 -class Symbol : public PoolObject
   65.57 -{
   65.58 -  public:
   65.59 -    enum Kind {
   65.60 -#       define _(name) k##name,
   65.61 -        SYMBOL_KINDS(_)
   65.62 -#       undef _
   65.63 -        kTotalSymbolKinds
   65.64 -    };
   65.65 -
   65.66 -  public:
   65.67 -    Symbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
   65.68 -      : scope_(scope),
   65.69 -        name_(name),
   65.70 -        pos_(pos)
   65.71 -    {
   65.72 -    }
   65.73 -
   65.74 -    virtual Kind kind() const = 0;
   65.75 -
   65.76 -    Handle<String> name() const {
   65.77 -        return name_;
   65.78 -    }
   65.79 -    const SourcePosition &pos() const {
   65.80 -        return pos_;
   65.81 -    }
   65.82 -    Handle<Type> type() const {
   65.83 -        return type_;
   65.84 -    }
   65.85 -    Scope *scope() const {
   65.86 -        return scope_;
   65.87 -    }
   65.88 -
   65.89 -  public:
   65.90 -#define _(name)                                             \
   65.91 -    bool is##name() const {                                 \
   65.92 -        return (kind() == k##name);                         \
   65.93 -    }                                                       \
   65.94 -    name##Symbol *as##name() {                              \
   65.95 -        if (is##name())                                     \
   65.96 -            return to##name();                              \
   65.97 -        return NULL;                                        \
   65.98 -    }                                                       \
   65.99 -    name##Symbol *to##name() {                              \
  65.100 -        assert(is##name());                                 \
  65.101 -        return reinterpret_cast<name##Symbol *>(this);      \
  65.102 -    }
  65.103 -    SYMBOL_KINDS(_)
  65.104 -#undef _
  65.105 -
  65.106 -  private:
  65.107 -    Scope *scope_;
  65.108 -    ScopedRoot<String> name_;
  65.109 -    SourcePosition pos_;
  65.110 -
  65.111 -  protected:
  65.112 -    ScopedRoot<Type> type_;
  65.113 -};
  65.114 -
  65.115 -class VariableSymbol : public Symbol
  65.116 -{
  65.117 -  public:
  65.118 -    enum Storage {
  65.119 -        Unknown,
  65.120 -        Local,
  65.121 -        Arg,
  65.122 -        Heap
  65.123 -    };
  65.124 -
  65.125 -  public:
  65.126 -    VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
  65.127 -      : Symbol(scope, name, pos),
  65.128 -        storage_(Unknown)
  65.129 -    {
  65.130 -    }
  65.131 -
  65.132 -    VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type)
  65.133 -      : Symbol(scope, name, pos),
  65.134 -        storage_(Unknown)
  65.135 -    {
  65.136 -        type_ = type;
  65.137 -    }
  65.138 -
  65.139 -    Kind kind() const {
  65.140 -        return kVariable;
  65.141 -    }
  65.142 -    void setType(Type *type) {
  65.143 -        assert(!type_);
  65.144 -        type_ = type;
  65.145 -    }
  65.146 -    void allocate(Storage storage, unsigned slot) {
  65.147 -        storage_ = storage;
  65.148 -        slot_ = slot;
  65.149 -    }
  65.150 -    Storage storage() const {
  65.151 -        return storage_;
  65.152 -    }
  65.153 -    unsigned slot() const {
  65.154 -        assert(storage() != Unknown);
  65.155 -        return slot_;
  65.156 -    }
  65.157 -
  65.158 -  private:
  65.159 -    Storage storage_;
  65.160 -    unsigned slot_;
  65.161 -};
  65.162 -
  65.163 -class TypeSymbol : public Symbol
  65.164 -{
  65.165 -  public:
  65.166 -    TypeSymbol(Scope *scope, Handle<String> name, Handle<Type> type, Handle<Type> effective)
  65.167 -      : Symbol(scope, name, SourcePosition()),
  65.168 -        effective_(effective)
  65.169 -    {
  65.170 -        type_ = type;
  65.171 -    }
  65.172 -
  65.173 -    Kind kind() const {
  65.174 -        return kType;
  65.175 -    }
  65.176 -    Handle<Type> effective() {
  65.177 -        return effective_;
  65.178 -    }
  65.179 -
  65.180 -  private:
  65.181 -    ScopedRoot<Type> effective_;
  65.182 -};
  65.183 -
  65.184 -class FunctionSymbol : public Symbol
  65.185 -{
  65.186 -  public:
  65.187 -    FunctionSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<FunctionType> type)
  65.188 -      : Symbol(scope, name, pos)
  65.189 -    {
  65.190 -        type_ = type;
  65.191 -    }
  65.192 -
  65.193 -    Kind kind() const {
  65.194 -        return kFunction;
  65.195 -    }
  65.196 -    FunctionType *type() const {
  65.197 -        return FunctionType::cast(type_);
  65.198 -    }
  65.199 -};
  65.200 -
  65.201 -class ConstantSymbol : public Symbol
  65.202 -{
  65.203 -  public:
  65.204 -    ConstantSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
  65.205 -                   const BoxedPrimitive &prim)
  65.206 -      : Symbol(scope, name, pos),
  65.207 -        value_(prim)
  65.208 -    {
  65.209 -        type_ = type;
  65.210 -    }
  65.211 -
  65.212 -    Kind kind() const {
  65.213 -        return kConstant;
  65.214 -    }
  65.215 -    const BoxedPrimitive &value() const {
  65.216 -        return value_;
  65.217 -    }
  65.218 -
  65.219 -  private:
  65.220 -    BoxedPrimitive value_;
  65.221 -};
  65.222 -
  65.223 -class ImportSymbol : public Symbol
  65.224 -{
  65.225 -  public:
  65.226 -    ImportSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
  65.227 -                 unsigned index)
  65.228 -      : Symbol(scope, name, pos),
  65.229 -        index_(index)
  65.230 -    {
  65.231 -        type_ = type;
  65.232 -    }
  65.233 -
  65.234 -    Kind kind() const {
  65.235 -        return kImport;
  65.236 -    }
  65.237 -    unsigned index() const {
  65.238 -        return index_;
  65.239 -    }
  65.240 -
  65.241 -  private:
  65.242 -      unsigned index_;
  65.243 -};
  65.244 -
  65.245 -class ImplicitSymbol : public Symbol
  65.246 -{
  65.247 -  public:
  65.248 -    ImplicitSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
  65.249 -                 unsigned index)
  65.250 -      : Symbol(scope, name, pos),
  65.251 -        index_(index),
  65.252 -        fieldIndex_(unsigned(-1))
  65.253 -    {
  65.254 -        type_ = type;
  65.255 -    }
  65.256 -
  65.257 -    bool bound() const {
  65.258 -        return fieldIndex_ != unsigned(-1);
  65.259 -    }
  65.260 -    Kind kind() const {
  65.261 -        return kImplicit;
  65.262 -    }
  65.263 -    unsigned index() const {
  65.264 -        return index_;
  65.265 -    }
  65.266 -    void bind(unsigned fieldIndex) {
  65.267 -        fieldIndex_ = fieldIndex;
  65.268 -    }
  65.269 -    unsigned fieldIndex() const {
  65.270 -        assert(bound());
  65.271 -        return fieldIndex_;
  65.272 -    }
  65.273 -
  65.274 -  private:
  65.275 -    unsigned index_;
  65.276 -    unsigned fieldIndex_;
  65.277 -};
  65.278 -
  65.279 -}
  65.280 -
  65.281 -#endif // _include_sp2_symbol_h_
  65.282 +/* vim: set ts=4 sw=4 tw=99 et:
  65.283 + *
  65.284 + * Copyright (C) 2012 David Anderson
  65.285 + *
  65.286 + * This file is part of SourcePawn.
  65.287 + *
  65.288 + * SourcePawn is free software: you can redistribute it and/or modify it under
  65.289 + * the terms of the GNU General Public License as published by the Free
  65.290 + * Software Foundation, either version 3 of the License, or (at your option)
  65.291 + * any later version.
  65.292 + * 
  65.293 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  65.294 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  65.295 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  65.296 + *
  65.297 + * You should have received a copy of the GNU General Public License along with
  65.298 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  65.299 + */
  65.300 +#ifndef _include_sp2_symbol_h_
  65.301 +#define _include_sp2_symbol_h_
  65.302 +
  65.303 +#include "../PoolAllocator.h"
  65.304 +#include "../Handles.h"
  65.305 +#include "../Opcodes.h"
  65.306 +#include "../Types.h"
  65.307 +#include "../Strings.h"
  65.308 +
  65.309 +namespace ke {
  65.310 +
  65.311 +class String;
  65.312 +
  65.313 +#define SYMBOL_KINDS(_) \
  65.314 +    /* Any kind of variable or argument produces a VariableSymbol. */ \
  65.315 +    _(Variable)         \
  65.316 +    /* A function declaration produces a FunctionSymbol. */ \
  65.317 +    _(Function)         \
  65.318 +    /* A named constant produces a ConstantSymbol. */ \
  65.319 +    _(Constant)         \
  65.320 +    /* A named type (class struct, typedef, etc) produces a TypeSymbol. */ \
  65.321 +    _(Type)             \
  65.322 +    /* An import name. */ \
  65.323 +    _(Import)           \
  65.324 +    /* A name implicitly derived from an import. */ \
  65.325 +    _(Implicit)
  65.326 +
  65.327 +#define _(name)     class name##Symbol;
  65.328 +SYMBOL_KINDS(_)
  65.329 +#undef _
  65.330 +
  65.331 +class Scope;
  65.332 +
  65.333 +// A symbol represents the declaration of a named entity.
  65.334 +class Symbol : public PoolObject
  65.335 +{
  65.336 +  public:
  65.337 +    enum Kind {
  65.338 +#       define _(name) k##name,
  65.339 +        SYMBOL_KINDS(_)
  65.340 +#       undef _
  65.341 +        kTotalSymbolKinds
  65.342 +    };
  65.343 +
  65.344 +  public:
  65.345 +    Symbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
  65.346 +      : scope_(scope),
  65.347 +        name_(name),
  65.348 +        pos_(pos)
  65.349 +    {
  65.350 +    }
  65.351 +
  65.352 +    virtual Kind kind() const = 0;
  65.353 +
  65.354 +    Handle<String> name() const {
  65.355 +        return name_;
  65.356 +    }
  65.357 +    const SourcePosition &pos() const {
  65.358 +        return pos_;
  65.359 +    }
  65.360 +    Handle<Type> type() const {
  65.361 +        return type_;
  65.362 +    }
  65.363 +    Scope *scope() const {
  65.364 +        return scope_;
  65.365 +    }
  65.366 +
  65.367 +  public:
  65.368 +#define _(name)                                             \
  65.369 +    bool is##name() const {                                 \
  65.370 +        return (kind() == k##name);                         \
  65.371 +    }                                                       \
  65.372 +    name##Symbol *as##name() {                              \
  65.373 +        if (is##name())                                     \
  65.374 +            return to##name();                              \
  65.375 +        return NULL;                                        \
  65.376 +    }                                                       \
  65.377 +    name##Symbol *to##name() {                              \
  65.378 +        assert(is##name());                                 \
  65.379 +        return reinterpret_cast<name##Symbol *>(this);      \
  65.380 +    }
  65.381 +    SYMBOL_KINDS(_)
  65.382 +#undef _
  65.383 +
  65.384 +  private:
  65.385 +    Scope *scope_;
  65.386 +    ScopedRoot<String> name_;
  65.387 +    SourcePosition pos_;
  65.388 +
  65.389 +  protected:
  65.390 +    ScopedRoot<Type> type_;
  65.391 +};
  65.392 +
  65.393 +class VariableSymbol : public Symbol
  65.394 +{
  65.395 +  public:
  65.396 +    enum Storage {
  65.397 +        Unknown,
  65.398 +        Local,
  65.399 +        Arg,
  65.400 +        Heap
  65.401 +    };
  65.402 +
  65.403 +  public:
  65.404 +    VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
  65.405 +      : Symbol(scope, name, pos),
  65.406 +        storage_(Unknown)
  65.407 +    {
  65.408 +    }
  65.409 +
  65.410 +    VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type)
  65.411 +      : Symbol(scope, name, pos),
  65.412 +        storage_(Unknown)
  65.413 +    {
  65.414 +        type_ = type;
  65.415 +    }
  65.416 +
  65.417 +    Kind kind() const {
  65.418 +        return kVariable;
  65.419 +    }
  65.420 +    void setType(Type *type) {
  65.421 +        assert(!type_);
  65.422 +        type_ = type;
  65.423 +    }
  65.424 +    void allocate(Storage storage, unsigned slot) {
  65.425 +        storage_ = storage;
  65.426 +        slot_ = slot;
  65.427 +    }
  65.428 +    Storage storage() const {
  65.429 +        return storage_;
  65.430 +    }
  65.431 +    unsigned slot() const {
  65.432 +        assert(storage() != Unknown);
  65.433 +        return slot_;
  65.434 +    }
  65.435 +
  65.436 +  private:
  65.437 +    Storage storage_;
  65.438 +    unsigned slot_;
  65.439 +};
  65.440 +
  65.441 +class TypeSymbol : public Symbol
  65.442 +{
  65.443 +  public:
  65.444 +    TypeSymbol(Scope *scope, Handle<String> name, Handle<Type> type, Handle<Type> effective)
  65.445 +      : Symbol(scope, name, SourcePosition()),
  65.446 +        effective_(effective)
  65.447 +    {
  65.448 +        type_ = type;
  65.449 +    }
  65.450 +
  65.451 +    Kind kind() const {
  65.452 +        return kType;
  65.453 +    }
  65.454 +    Handle<Type> effective() {
  65.455 +        return effective_;
  65.456 +    }
  65.457 +
  65.458 +  private:
  65.459 +    ScopedRoot<Type> effective_;
  65.460 +};
  65.461 +
  65.462 +class FunctionSymbol : public Symbol
  65.463 +{
  65.464 +  public:
  65.465 +    FunctionSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<FunctionType> type)
  65.466 +      : Symbol(scope, name, pos)
  65.467 +    {
  65.468 +        type_ = type;
  65.469 +    }
  65.470 +
  65.471 +    Kind kind() const {
  65.472 +        return kFunction;
  65.473 +    }
  65.474 +    FunctionType *type() const {
  65.475 +        return FunctionType::cast(type_);
  65.476 +    }
  65.477 +};
  65.478 +
  65.479 +class ConstantSymbol : public Symbol
  65.480 +{
  65.481 +  public:
  65.482 +    ConstantSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
  65.483 +                   const BoxedPrimitive &prim)
  65.484 +      : Symbol(scope, name, pos),
  65.485 +        value_(prim)
  65.486 +    {
  65.487 +        type_ = type;
  65.488 +    }
  65.489 +
  65.490 +    Kind kind() const {
  65.491 +        return kConstant;
  65.492 +    }
  65.493 +    const BoxedPrimitive &value() const {
  65.494 +        return value_;
  65.495 +    }
  65.496 +
  65.497 +  private:
  65.498 +    BoxedPrimitive value_;
  65.499 +};
  65.500 +
  65.501 +class ImportSymbol : public Symbol
  65.502 +{
  65.503 +  public:
  65.504 +    ImportSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
  65.505 +                 unsigned index)
  65.506 +      : Symbol(scope, name, pos),
  65.507 +        index_(index)
  65.508 +    {
  65.509 +        type_ = type;
  65.510 +    }
  65.511 +
  65.512 +    Kind kind() const {
  65.513 +        return kImport;
  65.514 +    }
  65.515 +    unsigned index() const {
  65.516 +        return index_;
  65.517 +    }
  65.518 +
  65.519 +  private:
  65.520 +      unsigned index_;
  65.521 +};
  65.522 +
  65.523 +class ImplicitSymbol : public Symbol
  65.524 +{
  65.525 +  public:
  65.526 +    ImplicitSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
  65.527 +                 unsigned index)
  65.528 +      : Symbol(scope, name, pos),
  65.529 +        index_(index),
  65.530 +        fieldIndex_(unsigned(-1))
  65.531 +    {
  65.532 +        type_ = type;
  65.533 +    }
  65.534 +
  65.535 +    bool bound() const {
  65.536 +        return fieldIndex_ != unsigned(-1);
  65.537 +    }
  65.538 +    Kind kind() const {
  65.539 +        return kImplicit;
  65.540 +    }
  65.541 +    unsigned index() const {
  65.542 +        return index_;
  65.543 +    }
  65.544 +    void bind(unsigned fieldIndex) {
  65.545 +        fieldIndex_ = fieldIndex;
  65.546 +    }
  65.547 +    unsigned fieldIndex() const {
  65.548 +        assert(bound());
  65.549 +        return fieldIndex_;
  65.550 +    }
  65.551 +
  65.552 +  private:
  65.553 +    unsigned index_;
  65.554 +    unsigned fieldIndex_;
  65.555 +};
  65.556 +
  65.557 +}
  65.558 +
  65.559 +#endif // _include_sp2_symbol_h_
    66.1 --- a/src/compiler/Token.h	Mon Jun 10 00:46:29 2013 +0100
    66.2 +++ b/src/compiler/Token.h	Mon Jun 10 01:04:43 2013 +0100
    66.3 @@ -1,128 +1,128 @@
    66.4 -/* vim: set ts=4 sw=4 tw=99 et:
    66.5 - * 
    66.6 - * Copyright (C) 2012 David Anderson
    66.7 - *
    66.8 - * This file is part of SourcePawn.
    66.9 - *
   66.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   66.11 - * the terms of the GNU General Public License as published by the Free
   66.12 - * Software Foundation, either version 3 of the License, or (at your option)
   66.13 - * any later version.
   66.14 - * 
   66.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   66.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   66.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   66.18 - *
   66.19 - * You should have received a copy of the GNU General Public License along with
   66.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   66.21 - */
   66.22 -#ifndef _include_jitcraft_token_h_
   66.23 -#define _include_jitcraft_token_h_
   66.24 -
   66.25 -namespace ke {
   66.26 -
   66.27 -// List of tokens the scanner can recognize.
   66.28 -//
   66.29 -// Some restrictions:
   66.30 -//   * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
   66.31 -//     op-and-assign equivalent.
   66.32 -#define TOKENMAP(_)                                     \
   66.33 -    _(NONE,               "<none>")                     \
   66.34 -    _(ERROR,              "<error>")                    \
   66.35 -    _(NEW,                "'new'")                      \
   66.36 -    _(FOR,                "'for'")                      \
   66.37 -    _(RETURN,             "'return'")                   \
   66.38 -    _(NAME,               "<name>")                     \
   66.39 -    _(INTEGER_LITERAL,    "<integer>")                  \
   66.40 -    _(HEX_LITERAL,        "<hex>")                      \
   66.41 -    _(FLOAT_LITERAL,      "<float>")                    \
   66.42 -    _(STRING_LITERAL,     "<string>")                   \
   66.43 -    _(IF,                 "<if>")                       \
   66.44 -    _(ELSE,               "<else>")                     \
   66.45 -    _(ENUM,               "<enum>")                     \
   66.46 -    _(LABEL,              "<label>")                    \
   66.47 -    _(WHILE,              "<while>")                    \
   66.48 -    _(DO,                 "<do>")                       \
   66.49 -    _(BREAK,              "<break>")                    \
   66.50 -    _(CONTINUE,           "<continue>")                 \
   66.51 -    _(FORWARD,            "<forward>")                  \
   66.52 -    _(PUBLIC,             "<public>")                   \
   66.53 -    _(CONST,              "<const>")                    \
   66.54 -    _(NATIVE,             "<native>")                   \
   66.55 -    _(STOCK,              "<stock>")                    \
   66.56 -    _(TRUE,               "<true>")                     \
   66.57 -    _(FALSE,              "<false>")                    \
   66.58 -    _(STRUCT,             "<struct>")                   \
   66.59 -    _(SWITCH,             "<switch>")                   \
   66.60 -    _(CASE,               "<case>")                     \
   66.61 -    _(DEFAULT,            "<default>")                  \
   66.62 -    _(TYPEDEF,            "<typedef>")                  \
   66.63 -    _(VOID,               "<void>")                     \
   66.64 -    _(INT,                "<int>")                      \
   66.65 -    _(SIZEOF,             "<sizeof>")                   \
   66.66 -    _(IMPORT,             "<import>")                   \
   66.67 -    _(FROM,               "<from>")                     \
   66.68 -    _(ELLIPSES,           "...")                        \
   66.69 -    _(PLUS,               "+")                          \
   66.70 -    _(MINUS,              "-")                          \
   66.71 -    _(STAR,               "*")                          \
   66.72 -    _(SLASH,              "/")                          \
   66.73 -    _(PERCENT,            "%")                          \
   66.74 -    _(AMPERSAND,          "&")                          \
   66.75 -    _(BITOR,              "|")                          \
   66.76 -    _(BITXOR,             "^")                          \
   66.77 -    _(SHR,                ">>")                         \
   66.78 -    _(USHR,               ">>>")                        \
   66.79 -    _(SHL,                "<<")                         \
   66.80 -    _(ASSIGN,             "=")                          \
   66.81 -    _(SEMICOLON,          ";")                          \
   66.82 -    _(LBRACE,             "{")                          \
   66.83 -    _(RBRACE,             "}")                          \
   66.84 -    _(LPAREN,             "(")                          \
   66.85 -    _(RPAREN,             ")")                          \
   66.86 -    _(LBRACKET,           "[")                          \
   66.87 -    _(RBRACKET,           "]")                          \
   66.88 -    _(ASSIGN_ADD,         "+=")                         \
   66.89 -    _(ASSIGN_SUB,         "-=")                         \
   66.90 -    _(ASSIGN_MUL,         "*=")                         \
   66.91 -    _(ASSIGN_DIV,         "/=")                         \
   66.92 -    _(ASSIGN_MOD,         "%=")                         \
   66.93 -    _(ASSIGN_BITAND,      "&=")                         \
   66.94 -    _(ASSIGN_BITOR,       "|=")                         \
   66.95 -    _(ASSIGN_BITXOR,      "^=")                         \
   66.96 -    _(ASSIGN_SHR,         ">>=")                        \
   66.97 -    _(ASSIGN_USHR,        ">>>=")                       \
   66.98 -    _(ASSIGN_SHL,         "<<=")                        \
   66.99 -    _(INCREMENT,          "++")                         \
  66.100 -    _(DECREMENT,          "--")                         \
  66.101 -    _(EQUALS,             "==")                         \
  66.102 -    _(NOTEQUALS,          "!=")                         \
  66.103 -    _(LT,                 "<")                          \
  66.104 -    _(LE,                 "<=")                         \
  66.105 -    _(GT,                 ">")                          \
  66.106 -    _(GE,                 ">=")                         \
  66.107 -    _(AND,                "&&")                         \
  66.108 -    _(OR,                 "||")                         \
  66.109 -    _(COMMA,              ",")                          \
  66.110 -    _(NOT,                "!")                          \
  66.111 -    _(TILDE,              "~")                          \
  66.112 -    _(QMARK,              "?")                          \
  66.113 -    _(COLON,              ":")                          \
  66.114 -    _(UNDERSCORE,         "_")                          \
  66.115 -    _(DOT,                ".")                          \
  66.116 -    _(EOF,                "<end-of-file>")
  66.117 -
  66.118 -enum TokenKind
  66.119 -{
  66.120 -#   define _(name, str) TOK_##name,
  66.121 -    TOKENMAP(_)
  66.122 -#   undef _
  66.123 -    TOK_BITAND = TOK_AMPERSAND,
  66.124 -    TOKENS_TOTAL
  66.125 -};
  66.126 -
  66.127 -extern const char *TokenNames[];
  66.128 -
  66.129 -} // namespace ke
  66.130 -
  66.131 -#endif //_include_jitcraft_token_h_
  66.132 +/* vim: set ts=4 sw=4 tw=99 et:
  66.133 + * 
  66.134 + * Copyright (C) 2012 David Anderson
  66.135 + *
  66.136 + * This file is part of SourcePawn.
  66.137 + *
  66.138 + * SourcePawn is free software: you can redistribute it and/or modify it under
  66.139 + * the terms of the GNU General Public License as published by the Free
  66.140 + * Software Foundation, either version 3 of the License, or (at your option)
  66.141 + * any later version.
  66.142 + * 
  66.143 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
  66.144 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  66.145 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  66.146 + *
  66.147 + * You should have received a copy of the GNU General Public License along with
  66.148 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
  66.149 + */
  66.150 +#ifndef _include_jitcraft_token_h_
  66.151 +#define _include_jitcraft_token_h_
  66.152 +
  66.153 +namespace ke {
  66.154 +
  66.155 +// List of tokens the scanner can recognize.
  66.156 +//
  66.157 +// Some restrictions:
  66.158 +//   * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
  66.159 +//     op-and-assign equivalent.
  66.160 +#define TOKENMAP(_)                                     \
  66.161 +    _(NONE,               "<none>")                     \
  66.162 +    _(ERROR,              "<error>")                    \
  66.163 +    _(NEW,                "'new'")                      \
  66.164 +    _(FOR,                "'for'")                      \
  66.165 +    _(RETURN,             "'return'")                   \
  66.166 +    _(NAME,               "<name>")                     \
  66.167 +    _(INTEGER_LITERAL,    "<integer>")                  \
  66.168 +    _(HEX_LITERAL,        "<hex>")                      \
  66.169 +    _(FLOAT_LITERAL,      "<float>")                    \
  66.170 +    _(STRING_LITERAL,     "<string>")                   \
  66.171 +    _(IF,                 "<if>")                       \
  66.172 +    _(ELSE,               "<else>")                     \
  66.173 +    _(ENUM,               "<enum>")                     \
  66.174 +    _(LABEL,              "<label>")                    \
  66.175 +    _(WHILE,              "<while>")                    \
  66.176 +    _(DO,                 "<do>")                       \
  66.177 +    _(BREAK,              "<break>")                    \
  66.178 +    _(CONTINUE,           "<continue>")                 \
  66.179 +    _(FORWARD,            "<forward>")                  \
  66.180 +    _(PUBLIC,             "<public>")                   \
  66.181 +    _(CONST,              "<const>")                    \
  66.182 +    _(NATIVE,             "<native>")                   \
  66.183 +    _(STOCK,              "<stock>")                    \
  66.184 +    _(TRUE,               "<true>")                     \
  66.185 +    _(FALSE,              "<false>")                    \
  66.186 +    _(STRUCT,             "<struct>")                   \
  66.187 +    _(SWITCH,             "<switch>")                   \
  66.188 +    _(CASE,               "<case>")                     \
  66.189 +    _(DEFAULT,            "<default>")                  \
  66.190 +    _(TYPEDEF,            "<typedef>")                  \
  66.191 +    _(VOID,               "<void>")                     \
  66.192 +    _(INT,                "<int>")                      \
  66.193 +    _(SIZEOF,             "<sizeof>")                   \
  66.194 +    _(IMPORT,             "<import>")                   \
  66.195 +    _(FROM,               "<from>")                     \
  66.196 +    _(ELLIPSES,           "...")                        \
  66.197 +    _(PLUS,               "+")                          \
  66.198 +    _(MINUS,              "-")                          \
  66.199 +    _(STAR,               "*")                          \
  66.200 +    _(SLASH,              "/")                          \
  66.201 +    _(PERCENT,            "%")                          \
  66.202 +    _(AMPERSAND,          "&")                          \
  66.203 +    _(BITOR,              "|")                          \
  66.204 +    _(BITXOR,             "^")                          \
  66.205 +    _(SHR,                ">>")                         \
  66.206 +    _(USHR,               ">>>")                        \
  66.207 +    _(SHL,                "<<")                         \
  66.208 +    _(ASSIGN,             "=")                          \
  66.209 +    _(SEMICOLON,          ";")                          \
  66.210 +    _(LBRACE,             "{")                          \
  66.211 +    _(RBRACE,             "}")                          \
  66.212 +    _(LPAREN,             "(")                          \
  66.213 +    _(RPAREN,             ")")                          \
  66.214 +    _(LBRACKET,           "[")                          \
  66.215 +    _(RBRACKET,           "]")                          \
  66.216 +    _(ASSIGN_ADD,         "+=")                         \
  66.217 +    _(ASSIGN_SUB,         "-=")                         \
  66.218 +    _(ASSIGN_MUL,         "*=")                         \
  66.219 +    _(ASSIGN_DIV,         "/=")                         \
  66.220 +    _(ASSIGN_MOD,         "%=")                         \
  66.221 +    _(ASSIGN_BITAND,      "&=")                         \
  66.222 +    _(ASSIGN_BITOR,       "|=")                         \
  66.223 +    _(ASSIGN_BITXOR,      "^=")                         \
  66.224 +    _(ASSIGN_SHR,         ">>=")                        \
  66.225 +    _(ASSIGN_USHR,        ">>>=")                       \
  66.226 +    _(ASSIGN_SHL,         "<<=")                        \
  66.227 +    _(INCREMENT,          "++")                         \
  66.228 +    _(DECREMENT,          "--")                         \
  66.229 +    _(EQUALS,             "==")                         \
  66.230 +    _(NOTEQUALS,          "!=")                         \
  66.231 +    _(LT,                 "<")                          \
  66.232 +    _(LE,                 "<=")                         \
  66.233 +    _(GT,                 ">")                          \
  66.234 +    _(GE,                 ">=")                         \
  66.235 +    _(AND,                "&&")                         \
  66.236 +    _(OR,                 "||")                         \
  66.237 +    _(COMMA,              ",")                          \
  66.238 +    _(NOT,                "!")                          \
  66.239 +    _(TILDE,              "~")                          \
  66.240 +    _(QMARK,              "?")                          \
  66.241 +    _(COLON,              ":")                          \
  66.242 +    _(UNDERSCORE,         "_")                          \
  66.243 +    _(DOT,                ".")                          \
  66.244 +    _(EOF,                "<end-of-file>")
  66.245 +
  66.246 +enum TokenKind
  66.247 +{
  66.248 +#   define _(name, str) TOK_##name,
  66.249 +    TOKENMAP(_)
  66.250 +#   undef _
  66.251 +    TOK_BITAND = TOK_AMPERSAND,
  66.252 +    TOKENS_TOTAL
  66.253 +};
  66.254 +
  66.255 +extern const char *TokenNames[];
  66.256 +
  66.257 +} // namespace ke
  66.258 +
  66.259 +#endif //_include_jitcraft_token_h_
    67.1 --- a/tests/basic/assignadd.out	Mon Jun 10 00:46:29 2013 +0100
    67.2 +++ b/tests/basic/assignadd.out	Mon Jun 10 01:04:43 2013 +0100
    67.3 @@ -1,1 +1,1 @@
    67.4 -1683
    67.5 +1683
    68.1 --- a/tests/basic/assignadd.sp	Mon Jun 10 00:46:29 2013 +0100
    68.2 +++ b/tests/basic/assignadd.sp	Mon Jun 10 01:04:43 2013 +0100
    68.3 @@ -1,10 +1,10 @@
    68.4 -native PrintNum(num);
    68.5 -
    68.6 -public main()
    68.7 -{
    68.8 -    new x[3];
    68.9 -    for (new i = 0; i < 100; i += 3) {
   68.10 -        x[2] += i;
   68.11 -    }
   68.12 -    PrintNum(x[2]);
   68.13 -}
   68.14 +native PrintNum(num);
   68.15 +
   68.16 +public main()
   68.17 +{
   68.18 +    new x[3];
   68.19 +    for (new i = 0; i < 100; i += 3) {
   68.20 +        x[2] += i;
   68.21 +    }
   68.22 +    PrintNum(x[2]);
   68.23 +}
    69.1 --- a/tests/basic/bitops.out	Mon Jun 10 00:46:29 2013 +0100
    69.2 +++ b/tests/basic/bitops.out	Mon Jun 10 01:04:43 2013 +0100
    69.3 @@ -1,1 +1,1 @@
    69.4 -35503
    69.5 +35503
    70.1 --- a/tests/basic/bitops.sp	Mon Jun 10 00:46:29 2013 +0100
    70.2 +++ b/tests/basic/bitops.sp	Mon Jun 10 01:04:43 2013 +0100
    70.3 @@ -1,16 +1,16 @@
    70.4 -native PrintNum(num);
    70.5 -
    70.6 -public main()
    70.7 -{
    70.8 -    new result = 5192342;
    70.9 -    for (new i = 0; i < 1000; i = i + 1) {
   70.10 -        result = result | i;
   70.11 -        result = result & 9129345;
   70.12 -        result = result ^ (i * 73);
   70.13 -
   70.14 -        new bit = result & 1;
   70.15 -        result = (result >>> 1) | (bit << 31);
   70.16 -        result = result | (i >> 6);
   70.17 -    }
   70.18 -    PrintNum(result);
   70.19 -}
   70.20 +native PrintNum(num);
   70.21 +
   70.22 +public main()
   70.23 +{
   70.24 +    new result = 5192342;
   70.25 +    for (new i = 0; i < 1000; i = i + 1) {
   70.26 +        result = result | i;
   70.27 +        result = result & 9129345;
   70.28 +        result = result ^ (i * 73);
   70.29 +
   70.30 +        new bit = result & 1;
   70.31 +        result = (result >>> 1) | (bit << 31);
   70.32 +        result = result | (i >> 6);
   70.33 +    }
   70.34 +    PrintNum(result);
   70.35 +}
    71.1 --- a/tests/basic/break-continue-in-for.out	Mon Jun 10 00:46:29 2013 +0100
    71.2 +++ b/tests/basic/break-continue-in-for.out	Mon Jun 10 01:04:43 2013 +0100
    71.3 @@ -1,1 +1,1 @@
    71.4 -58
    71.5 +58
    72.1 --- a/tests/basic/break-continue-in-for.sp	Mon Jun 10 00:46:29 2013 +0100
    72.2 +++ b/tests/basic/break-continue-in-for.sp	Mon Jun 10 01:04:43 2013 +0100
    72.3 @@ -1,15 +1,15 @@
    72.4 -native PrintNum(num);
    72.5 -
    72.6 -public main()
    72.7 -{
    72.8 -   new i;
    72.9 -   for (; i < 100; i = i + 1) {
   72.10 -       if (i >= 57)
   72.11 -           break;
   72.12 -       if (i >= 26) {
   72.13 -           i = i + 1;
   72.14 -           continue;
   72.15 -       }
   72.16 -   }
   72.17 -   PrintNum(i);
   72.18 -}
   72.19 +native PrintNum(num);
   72.20 +
   72.21 +public main()
   72.22 +{
   72.23 +   new i;
   72.24 +   for (; i < 100; i = i + 1) {
   72.25 +       if (i >= 57)
   72.26 +           break;
   72.27 +       if (i >= 26) {
   72.28 +           i = i + 1;
   72.29 +           continue;
   72.30 +       }
   72.31 +   }
   72.32 +   PrintNum(i);
   72.33 +}
    73.1 --- a/tests/basic/const-arg-1.err	Mon Jun 10 00:46:29 2013 +0100
    73.2 +++ b/tests/basic/const-arg-1.err	Mon Jun 10 01:04:43 2013 +0100
    73.3 @@ -1,1 +1,1 @@
    73.4 -  line 3, col 12: cannot change constant value or structure
    73.5 +  line 3, col 12: cannot change constant value or structure
    74.1 --- a/tests/basic/const-arg-1.sp	Mon Jun 10 00:46:29 2013 +0100
    74.2 +++ b/tests/basic/const-arg-1.sp	Mon Jun 10 01:04:43 2013 +0100
    74.3 @@ -1,4 +1,4 @@
    74.4 -f(const char:text[])
    74.5 -{
    74.6 -    text[0] = 0;
    74.7 -}
    74.8 +f(const char:text[])
    74.9 +{
   74.10 +    text[0] = 0;
   74.11 +}
    75.1 --- a/tests/basic/const-arg-2.err	Mon Jun 10 00:46:29 2013 +0100
    75.2 +++ b/tests/basic/const-arg-2.err	Mon Jun 10 01:04:43 2013 +0100
    75.3 @@ -1,1 +1,1 @@
    75.4 -  line 1, col 7: const parameters must be arrays or structs
    75.5 +  line 1, col 7: const parameters must be arrays or structs
    76.1 --- a/tests/basic/const-arg-2.sp	Mon Jun 10 00:46:29 2013 +0100
    76.2 +++ b/tests/basic/const-arg-2.sp	Mon Jun 10 01:04:43 2013 +0100
    76.3 @@ -1,3 +1,3 @@
    76.4 -f(const a)
    76.5 -{
    76.6 -}
    76.7 +f(const a)
    76.8 +{
    76.9 +}
    77.1 --- a/tests/basic/const-arg-3.err	Mon Jun 10 00:46:29 2013 +0100
    77.2 +++ b/tests/basic/const-arg-3.err	Mon Jun 10 01:04:43 2013 +0100
    77.3 @@ -1,1 +1,1 @@
    77.4 -  line 1, col 7: constant outparams are not allowed
    77.5 +  line 1, col 7: constant outparams are not allowed
    78.1 --- a/tests/basic/const-arg-3.sp	Mon Jun 10 00:46:29 2013 +0100
    78.2 +++ b/tests/basic/const-arg-3.sp	Mon Jun 10 01:04:43 2013 +0100
    78.3 @@ -1,3 +1,3 @@
    78.4 -f(const &a)
    78.5 -{
    78.6 -}
    78.7 +f(const &a)
    78.8 +{
    78.9 +}
    79.1 --- a/tests/basic/const-arg-4.err	Mon Jun 10 00:46:29 2013 +0100
    79.2 +++ b/tests/basic/const-arg-4.err	Mon Jun 10 01:04:43 2013 +0100
    79.3 @@ -1,1 +1,1 @@
    79.4 -  line 8, col 7: type mismatch (expected 'char[]', got 'const char[]')
    79.5 +  line 8, col 7: type mismatch (expected 'char[]', got 'const char[]')
    80.1 --- a/tests/basic/const-arg-4.sp	Mon Jun 10 00:46:29 2013 +0100
    80.2 +++ b/tests/basic/const-arg-4.sp	Mon Jun 10 01:04:43 2013 +0100
    80.3 @@ -1,9 +1,9 @@
    80.4 -f(char:text[])
    80.5 -{
    80.6 -}
    80.7 -
    80.8 -main()
    80.9 -{
   80.10 -    const char:text[] = "";
   80.11 -    f(text);
   80.12 -}
   80.13 +f(char:text[])
   80.14 +{
   80.15 +}
   80.16 +
   80.17 +main()
   80.18 +{
   80.19 +    const char:text[] = "";
   80.20 +    f(text);
   80.21 +}
    81.1 --- a/tests/basic/const-arg-5.out	Mon Jun 10 00:46:29 2013 +0100
    81.2 +++ b/tests/basic/const-arg-5.out	Mon Jun 10 01:04:43 2013 +0100
    81.3 @@ -1,1 +1,1 @@
    81.4 -9798
    81.5 +9798
    82.1 --- a/tests/basic/const-arg-5.sp	Mon Jun 10 00:46:29 2013 +0100
    82.2 +++ b/tests/basic/const-arg-5.sp	Mon Jun 10 01:04:43 2013 +0100
    82.3 @@ -1,14 +1,14 @@
    82.4 -native PrintNum(num);
    82.5 -
    82.6 -
    82.7 -f(const char:text[])
    82.8 -{
    82.9 -    PrintNum(text[0]);
   82.10 -}
   82.11 -
   82.12 -public main()
   82.13 -{
   82.14 -    new char:q[20] = "blub";
   82.15 -    f("asdf");
   82.16 -    f(q);
   82.17 -}
   82.18 +native PrintNum(num);
   82.19 +
   82.20 +
   82.21 +f(const char:text[])
   82.22 +{
   82.23 +    PrintNum(text[0]);
   82.24 +}
   82.25 +
   82.26 +public main()
   82.27 +{
   82.28 +    new char:q[20] = "blub";
   82.29 +    f("asdf");
   82.30 +    f(q);
   82.31 +}
    83.1 --- a/tests/basic/const-global-1.err	Mon Jun 10 00:46:29 2013 +0100
    83.2 +++ b/tests/basic/const-global-1.err	Mon Jun 10 01:04:43 2013 +0100
    83.3 @@ -1,1 +1,1 @@
    83.4 -  line 4, col 7: cannot change constant value or structure
    83.5 +  line 4, col 7: cannot change constant value or structure
    84.1 --- a/tests/basic/const-global-1.sp	Mon Jun 10 00:46:29 2013 +0100
    84.2 +++ b/tests/basic/const-global-1.sp	Mon Jun 10 01:04:43 2013 +0100
    84.3 @@ -1,5 +1,5 @@
    84.4 -const a = 5;
    84.5 -public main()
    84.6 -{
    84.7 -    a = 10;
    84.8 -}
    84.9 +const a = 5;
   84.10 +public main()
   84.11 +{
   84.12 +    a = 10;
   84.13 +}
    85.1 --- a/tests/basic/const-global-2.err	Mon Jun 10 00:46:29 2013 +0100
    85.2 +++ b/tests/basic/const-global-2.err	Mon Jun 10 01:04:43 2013 +0100
    85.3 @@ -1,1 +1,1 @@
    85.4 -  line 5, col 12: cannot change constant value or structure
    85.5 +  line 5, col 12: cannot change constant value or structure
    86.1 --- a/tests/basic/const-global-2.sp	Mon Jun 10 00:46:29 2013 +0100
    86.2 +++ b/tests/basic/const-global-2.sp	Mon Jun 10 01:04:43 2013 +0100
    86.3 @@ -1,6 +1,6 @@
    86.4 -const char:text[] = "Adsf";
    86.5 -
    86.6 -public main()
    86.7 -{
    86.8 -    text[0] = 0;
    86.9 -}
   86.10 +const char:text[] = "Adsf";
   86.11 +
   86.12 +public main()
   86.13 +{
   86.14 +    text[0] = 0;
   86.15 +}
    87.1 --- a/tests/basic/const-global-3.err	Mon Jun 10 00:46:29 2013 +0100
    87.2 +++ b/tests/basic/const-global-3.err	Mon Jun 10 01:04:43 2013 +0100
    87.3 @@ -1,1 +1,1 @@
    87.4 -  line 4, col 10: cannot change constant value or structure
    87.5 +  line 4, col 10: cannot change constant value or structure
    88.1 --- a/tests/basic/const-global-3.sp	Mon Jun 10 00:46:29 2013 +0100
    88.2 +++ b/tests/basic/const-global-3.sp	Mon Jun 10 01:04:43 2013 +0100
    88.3 @@ -1,5 +1,5 @@
    88.4 -const char:text[] = "";
    88.5 -public main()
    88.6 -{
    88.7 -    text = "a";
    88.8 -}
    88.9 +const char:text[] = "";
   88.10 +public main()
   88.11 +{
   88.12 +    text = "a";
   88.13 +}
    89.1 --- a/tests/basic/const-local-1.err	Mon Jun 10 00:46:29 2013 +0100
    89.2 +++ b/tests/basic/const-local-1.err	Mon Jun 10 01:04:43 2013 +0100
    89.3 @@ -1,1 +1,1 @@
    89.4 -  line 4, col 7: cannot change constant value or structure
    89.5 +  line 4, col 7: cannot change constant value or structure
    90.1 --- a/tests/basic/const-local-1.sp	Mon Jun 10 00:46:29 2013 +0100
    90.2 +++ b/tests/basic/const-local-1.sp	Mon Jun 10 01:04:43 2013 +0100
    90.3 @@ -1,6 +1,6 @@
    90.4 -public main()
    90.5 -{
    90.6 -    const a = 5;
    90.7 -    a = 10;
    90.8 -}
    90.9 -
   90.10 +public main()
   90.11 +{
   90.12 +    const a = 5;
   90.13 +    a = 10;
   90.14 +}
   90.15 +
    91.1 --- a/tests/basic/const-local-2.err	Mon Jun 10 00:46:29 2013 +0100
    91.2 +++ b/tests/basic/const-local-2.err	Mon Jun 10 01:04:43 2013 +0100
    91.3 @@ -1,1 +1,1 @@
    91.4 -  line 4, col 12: cannot change constant value or structure
    91.5 +  line 4, col 12: cannot change constant value or structure
    92.1 --- a/tests/basic/const-local-2.sp	Mon Jun 10 00:46:29 2013 +0100
    92.2 +++ b/tests/basic/const-local-2.sp	Mon Jun 10 01:04:43 2013 +0100
    92.3 @@ -1,5 +1,5 @@
    92.4 -public main()
    92.5 -{
    92.6 -    const char:text[] = "hello, gabe newell!";
    92.7 -    text[5] = 10;
    92.8 -}
    92.9 +public main()
   92.10 +{
   92.11 +    const char:text[] = "hello, gabe newell!";
   92.12 +    text[5] = 10;
   92.13 +}
    93.1 --- a/tests/basic/const-local-3.out	Mon Jun 10 00:46:29 2013 +0100
    93.2 +++ b/tests/basic/const-local-3.out	Mon Jun 10 01:04:43 2013 +0100
    93.3 @@ -1,1 +1,1 @@
    93.4 -107
    93.5 +107
    94.1 --- a/tests/basic/const-local-3.sp	Mon Jun 10 00:46:29 2013 +0100
    94.2 +++ b/tests/basic/const-local-3.sp	Mon Jun 10 01:04:43 2013 +0100
    94.3 @@ -1,9 +1,9 @@
    94.4 -native PrintNum(num);
    94.5 -
    94.6 -public main()
    94.7 -{
    94.8 -    const char:a[] = "what";
    94.9 -    const char:b[] = "k";
   94.10 -    a = b;
   94.11 -    PrintNum(a[0]);
   94.12 -}
   94.13 +native PrintNum(num);
   94.14 +
   94.15 +public main()
   94.16 +{
   94.17 +    const char:a[] = "what";
   94.18 +    const char:b[] = "k";
   94.19 +    a = b;
   94.20 +    PrintNum(a[0]);
   94.21 +}
    95.1 --- a/tests/basic/continue-in-while.out	Mon Jun 10 00:46:29 2013 +0100
    95.2 +++ b/tests/basic/continue-in-while.out	Mon Jun 10 01:04:43 2013 +0100
    95.3 @@ -1,1 +1,1 @@
    95.4 -222
    95.5 +222
    96.1 --- a/tests/basic/continue-in-while.sp	Mon Jun 10 00:46:29 2013 +0100
    96.2 +++ b/tests/basic/continue-in-while.sp	Mon Jun 10 01:04:43 2013 +0100
    96.3 @@ -1,13 +1,13 @@
    96.4 -native PrintNum(num);
    96.5 -
    96.6 -public main()
    96.7 -{
    96.8 -   new i = 0;
    96.9 -   while (1) {
   96.10 -      i = i + 37;
   96.11 -      if (i < 200)
   96.12 -         continue;
   96.13 -      break;
   96.14 -   }
   96.15 -   PrintNum(i);
   96.16 -}
   96.17 +native PrintNum(num);
   96.18 +
   96.19 +public main()
   96.20 +{
   96.21 +   new i = 0;
   96.22 +   while (1) {
   96.23 +      i = i + 37;
   96.24 +      if (i < 200)
   96.25 +         continue;
   96.26 +      break;
   96.27 +   }
   96.28 +   PrintNum(i);
   96.29 +}
    97.1 --- a/tests/basic/decl-void.err	Mon Jun 10 00:46:29 2013 +0100
    97.2 +++ b/tests/basic/decl-void.err	Mon Jun 10 01:04:43 2013 +0100
    97.3 @@ -1,1 +1,1 @@
    97.4 -  line 1, col 4: expected token '<name>', got '<void>'
    97.5 +  line 1, col 4: expected token '<name>', got '<void>'
    98.1 --- a/tests/basic/decl-void.sp	Mon Jun 10 00:46:29 2013 +0100
    98.2 +++ b/tests/basic/decl-void.sp	Mon Jun 10 01:04:43 2013 +0100
    98.3 @@ -1,2 +1,2 @@
    98.4 -new void:x;
    98.5 -
    98.6 +new void:x;
    98.7 +
    99.1 --- a/tests/basic/dependent-strings.out	Mon Jun 10 00:46:29 2013 +0100
    99.2 +++ b/tests/basic/dependent-strings.out	Mon Jun 10 01:04:43 2013 +0100
    99.3 @@ -1,2 +1,2 @@
    99.4 -Pab
    99.5 -ake
    99.6 +Pab
    99.7 +ake
   100.1 --- a/tests/basic/dependent-strings.sp	Mon Jun 10 00:46:29 2013 +0100
   100.2 +++ b/tests/basic/dependent-strings.sp	Mon Jun 10 01:04:43 2013 +0100
   100.3 @@ -1,20 +1,20 @@
   100.4 -native PrintString(const char:text[]);
   100.5 -
   100.6 -f(char:str[])
   100.7 -{
   100.8 -    str[0] = 80;
   100.9 -}
  100.10 -
  100.11 -public main()
  100.12 -{
  100.13 -    new char:fixed[100] = "crab\n";
  100.14 -    new char:dynamo[];
  100.15 -
  100.16 -    dynamo = "cake\n";
  100.17 -
  100.18 -    f(fixed[1]);
  100.19 -    f(dynamo[1]);
  100.20 -    PrintString(fixed[1]);
  100.21 -    PrintString(dynamo[1]);
  100.22 -}
  100.23 -
  100.24 +native PrintString(const char:text[]);
  100.25 +
  100.26 +f(char:str[])
  100.27 +{
  100.28 +    str[0] = 80;
  100.29 +}
  100.30 +
  100.31 +public main()
  100.32 +{
  100.33 +    new char:fixed[100] = "crab\n";
  100.34 +    new char:dynamo[];
  100.35 +
  100.36 +    dynamo = "cake\n";
  100.37 +
  100.38 +    f(fixed[1]);
  100.39 +    f(dynamo[1]);
  100.40 +    PrintString(fixed[1]);
  100.41 +    PrintString(dynamo[1]);
  100.42 +}
  100.43 +
   101.1 --- a/tests/basic/divide-by-zero.err	Mon Jun 10 00:46:29 2013 +0100
   101.2 +++ b/tests/basic/divide-by-zero.err	Mon Jun 10 01:04:43 2013 +0100
   101.3 @@ -1,3 +1,3 @@
   101.4 -Uncaught exception: integer divide by zero
   101.5 -[0] f (divide-by-zero.sp line 1)
   101.6 -[1] main (divide-by-zero.sp line 3)
   101.7 +Uncaught exception: integer divide by zero
   101.8 +[0] f (divide-by-zero.sp line 1)
   101.9 +[1] main (divide-by-zero.sp line 3)
   102.1 --- a/tests/basic/divide-by-zero.sp	Mon Jun 10 00:46:29 2013 +0100
   102.2 +++ b/tests/basic/divide-by-zero.sp	Mon Jun 10 01:04:43 2013 +0100
   102.3 @@ -1,14 +1,14 @@
   102.4 -native PrintToNum(num);
   102.5 -
   102.6 -f(a, b) {
   102.7 -    return a /b ;
   102.8 -}
   102.9 -
  102.10 -public main()
  102.11 -{
  102.12 -    for (new i = 0; i < 100; i++) {
  102.13 -        f(i + 5, i - 8);
  102.14 -    }
  102.15 -    return 10;
  102.16 -}
  102.17 -
  102.18 +native PrintToNum(num);
  102.19 +
  102.20 +f(a, b) {
  102.21 +    return a /b ;
  102.22 +}
  102.23 +
  102.24 +public main()
  102.25 +{
  102.26 +    for (new i = 0; i < 100; i++) {
  102.27 +        f(i + 5, i - 8);
  102.28 +    }
  102.29 +    return 10;
  102.30 +}
  102.31 +
   103.1 --- a/tests/basic/do.out	Mon Jun 10 00:46:29 2013 +0100
   103.2 +++ b/tests/basic/do.out	Mon Jun 10 01:04:43 2013 +0100
   103.3 @@ -1,1 +1,1 @@
   103.4 -37
   103.5 +37
   104.1 --- a/tests/basic/do.sp	Mon Jun 10 00:46:29 2013 +0100
   104.2 +++ b/tests/basic/do.sp	Mon Jun 10 01:04:43 2013 +0100
   104.3 @@ -1,10 +1,10 @@
   104.4 -native PrintNum(num);
   104.5 -
   104.6 -public main()
   104.7 -{
   104.8 -   new i = 0;
   104.9 -   do  {
  104.10 -      i = i + 37;
  104.11 -   } while (i < 5);
  104.12 -   PrintNum(i);
  104.13 -}
  104.14 +native PrintNum(num);
  104.15 +
  104.16 +public main()
  104.17 +{
  104.18 +   new i = 0;
  104.19 +   do  {
  104.20 +      i = i + 37;
  104.21 +   } while (i < 5);
  104.22 +   PrintNum(i);
  104.23 +}
   105.1 --- a/tests/basic/enum-bad.err	Mon Jun 10 00:46:29 2013 +0100
   105.2 +++ b/tests/basic/enum-bad.err	Mon Jun 10 01:04:43 2013 +0100
   105.3 @@ -1,1 +1,1 @@
   105.4 -  line 6, col 13: cannot coerce type 'int' to type 'X'
   105.5 +  line 6, col 13: cannot coerce type 'int' to type 'X'
   106.1 --- a/tests/basic/enum-bad.sp	Mon Jun 10 00:46:29 2013 +0100
   106.2 +++ b/tests/basic/enum-bad.sp	Mon Jun 10 01:04:43 2013 +0100
   106.3 @@ -1,7 +1,7 @@
   106.4 -enum X {
   106.5 -};
   106.6 -
   106.7 -public main()
   106.8 -{
   106.9 -    new X:x = 5;
  106.10 -}
  106.11 +enum X {
  106.12 +};
  106.13 +
  106.14 +public main()
  106.15 +{
  106.16 +    new X:x = 5;
  106.17 +}
   107.1 --- a/tests/basic/enum-redecl.err	Mon Jun 10 00:46:29 2013 +0100
   107.2 +++ b/tests/basic/enum-redecl.err	Mon Jun 10 01:04:43 2013 +0100
   107.3 @@ -1,1 +1,1 @@
   107.4 -  line 4, col 4: name 'Y' was redeclared (previous at line 2, col 4)
   107.5 +  line 4, col 4: name 'Y' was redeclared (previous at line 2, col 4)
   108.1 --- a/tests/basic/enum-redecl.sp	Mon Jun 10 00:46:29 2013 +0100
   108.2 +++ b/tests/basic/enum-redecl.sp	Mon Jun 10 01:04:43 2013 +0100
   108.3 @@ -1,6 +1,6 @@
   108.4 -enum X {
   108.5 -  Y,
   108.6 -  Z,
   108.7 -  Y
   108.8 -};
   108.9 -
  108.10 +enum X {
  108.11 +  Y,
  108.12 +  Z,
  108.13 +  Y
  108.14 +};
  108.15 +
   109.1 --- a/tests/basic/enum-use.out	Mon Jun 10 00:46:29 2013 +0100
   109.2 +++ b/tests/basic/enum-use.out	Mon Jun 10 01:04:43 2013 +0100
   109.3 @@ -1,1 +1,1 @@
   109.4 -01570157
   109.5 +01570157
   110.1 --- a/tests/basic/enum-use.sp	Mon Jun 10 00:46:29 2013 +0100
   110.2 +++ b/tests/basic/enum-use.sp	Mon Jun 10 01:04:43 2013 +0100
   110.3 @@ -1,28 +1,28 @@
   110.4 -native PrintNum(num);
   110.5 -
   110.6 -enum Crab {
   110.7 -   CrabOne,
   110.8 -   CrabTwo,
   110.9 -   CrabThree=5,
  110.10 -   CrabFour=7
  110.11 -};
  110.12 -
  110.13 -enum {
  110.14 -   CrabFive,
  110.15 -   CrabSix,
  110.16 -   CrabSeven=5,
  110.17 -   CrabEight=7
  110.18 -};
  110.19 -
  110.20 -public main()
  110.21 -{
  110.22 -   PrintNum(CrabOne);
  110.23 -   PrintNum(CrabTwo);
  110.24 -   PrintNum(CrabThree);
  110.25 -   PrintNum(CrabFour);
  110.26 -   PrintNum(CrabFive);
  110.27 -   PrintNum(CrabSix);
  110.28 -   PrintNum(CrabSeven);
  110.29 -   PrintNum(CrabEight);
  110.30 -}
  110.31 -
  110.32 +native PrintNum(num);
  110.33 +
  110.34 +enum Crab {
  110.35 +   CrabOne,
  110.36 +   CrabTwo,
  110.37 +   CrabThree=5,
  110.38 +   CrabFour=7
  110.39 +};
  110.40 +
  110.41 +enum {
  110.42 +   CrabFive,
  110.43 +   CrabSix,
  110.44 +   CrabSeven=5,
  110.45 +   CrabEight=7
  110.46 +};
  110.47 +
  110.48 +public main()
  110.49 +{
  110.50 +   PrintNum(CrabOne);
  110.51 +   PrintNum(CrabTwo);
  110.52 +   PrintNum(CrabThree);
  110.53 +   PrintNum(CrabFour);
  110.54 +   PrintNum(CrabFive);
  110.55 +   PrintNum(CrabSix);
  110.56 +   PrintNum(CrabSeven);
  110.57 +   PrintNum(CrabEight);
  110.58 +}
  110.59 +
   111.1 --- a/tests/basic/float-arrays.out	Mon Jun 10 00:46:29 2013 +0100
   111.2 +++ b/tests/basic/float-arrays.out	Mon Jun 10 01:04:43 2013 +0100
   111.3 @@ -1,1 +1,1 @@
   111.4 -11.500000
   111.5 +11.500000
   112.1 --- a/tests/basic/float-arrays.sp	Mon Jun 10 00:46:29 2013 +0100
   112.2 +++ b/tests/basic/float-arrays.sp	Mon Jun 10 01:04:43 2013 +0100
   112.3 @@ -1,9 +1,9 @@
   112.4 -native PrintFloat(float:num);
   112.5 -
   112.6 -public main()
   112.7 -{
   112.8 -   new float:vec[3];
   112.9 -   for (new i = 0; i < 3; i = i + 1)
  112.10 -     vec[i] = i + 9.5;
  112.11 -   PrintFloat(vec[2]);
  112.12 -}
  112.13 +native PrintFloat(float:num);
  112.14 +
  112.15 +public main()
  112.16 +{
  112.17 +   new float:vec[3];
  112.18 +   for (new i = 0; i < 3; i = i + 1)
  112.19 +     vec[i] = i + 9.5;
  112.20 +   PrintFloat(vec[2]);
  112.21 +}
   113.1 --- a/tests/basic/floats.out	Mon Jun 10 00:46:29 2013 +0100
   113.2 +++ b/tests/basic/floats.out	Mon Jun 10 01:04:43 2013 +0100
   113.3 @@ -1,1 +1,1 @@
   113.4 -5012.000000
   113.5 +5012.000000
   114.1 --- a/tests/basic/floats.sp	Mon Jun 10 00:46:29 2013 +0100
   114.2 +++ b/tests/basic/floats.sp	Mon Jun 10 01:04:43 2013 +0100
   114.3 @@ -1,9 +1,9 @@
   114.4 -native PrintFloat(float:num);
   114.5 -
   114.6 -public main()
   114.7 -{
   114.8 -   new float:f = 12.0;
   114.9 -   for (new i = 0; i < 100; i = i + 1)
  114.10 -      f = f + 0.5 + i;
  114.11 -   PrintFloat(f);
  114.12 -}
  114.13 +native PrintFloat(float:num);
  114.14 +
  114.15 +public main()
  114.16 +{
  114.17 +   new float:f = 12.0;
  114.18 +   for (new i = 0; i < 100; i = i + 1)
  114.19 +      f = f + 0.5 + i;
  114.20 +   PrintFloat(f);
  114.21 +}
   115.1 --- a/tests/basic/import-sysroot-all.out	Mon Jun 10 00:46:29 2013 +0100
   115.2 +++ b/tests/basic/import-sysroot-all.out	Mon Jun 10 01:04:43 2013 +0100
   115.3 @@ -1,1 +1,1 @@
   115.4 -5 is 5.000000
   115.5 +5 is 5.000000
   116.1 --- a/tests/basic/import-sysroot-all.sp	Mon Jun 10 00:46:29 2013 +0100
   116.2 +++ b/tests/basic/import-sysroot-all.sp	Mon Jun 10 01:04:43 2013 +0100
   116.3 @@ -1,9 +1,9 @@
   116.4 -from shell import *;
   116.5 -
   116.6 -public main()
   116.7 -{
   116.8 -    PrintNum(5);
   116.9 -    PrintString(" is ");
  116.10 -    PrintFloat(5.0);
  116.11 -}
  116.12 -
  116.13 +from shell import *;
  116.14 +
  116.15 +public main()
  116.16 +{
  116.17 +    PrintNum(5);
  116.18 +    PrintString(" is ");
  116.19 +    PrintFloat(5.0);
  116.20 +}
  116.21 +
   117.1 --- a/tests/basic/import-sysroot-module.out	Mon Jun 10 00:46:29 2013 +0100
   117.2 +++ b/tests/basic/import-sysroot-module.out	Mon Jun 10 01:04:43 2013 +0100
   117.3 @@ -1,1 +1,1 @@
   117.4 -5 is 5.000000
   117.5 +5 is 5.000000
   118.1 --- a/tests/basic/import-sysroot-module.sp	Mon Jun 10 00:46:29 2013 +0100
   118.2 +++ b/tests/basic/import-sysroot-module.sp	Mon Jun 10 01:04:43 2013 +0100
   118.3 @@ -1,9 +1,9 @@
   118.4 -import shell;
   118.5 -
   118.6 -public main()
   118.7 -{
   118.8 -    shell.PrintNum(5);
   118.9 -    shell.PrintString(" is ");
  118.10 -    shell.PrintFloat(5.0);
  118.11 -}
  118.12 -
  118.13 +import shell;
  118.14 +
  118.15 +public main()
  118.16 +{
  118.17 +    shell.PrintNum(5);
  118.18 +    shell.PrintString(" is ");
  118.19 +    shell.PrintFloat(5.0);
  118.20 +}
  118.21 +
   119.1 --- a/tests/basic/import-sysroot-select.out	Mon Jun 10 00:46:29 2013 +0100
   119.2 +++ b/tests/basic/import-sysroot-select.out	Mon Jun 10 01:04:43 2013 +0100
   119.3 @@ -1,1 +1,1 @@
   119.4 -5 is 5.000000
   119.5 +5 is 5.000000
   120.1 --- a/tests/basic/import-sysroot-select.sp	Mon Jun 10 00:46:29 2013 +0100
   120.2 +++ b/tests/basic/import-sysroot-select.sp	Mon Jun 10 01:04:43 2013 +0100
   120.3 @@ -1,9 +1,9 @@
   120.4 -from shell import PrintNum, PrintString, PrintFloat;
   120.5 -
   120.6 -public main()
   120.7 -{
   120.8 -    PrintNum(5);
   120.9 -    PrintString(" is ");
  120.10 -    PrintFloat(5.0);
  120.11 -}
  120.12 -
  120.13 +from shell import PrintNum, PrintString, PrintFloat;
  120.14 +
  120.15 +public main()
  120.16 +{
  120.17 +    PrintNum(5);
  120.18 +    PrintString(" is ");
  120.19 +    PrintFloat(5.0);
  120.20 +}
  120.21 +
   121.1 --- a/tests/basic/import_enum_a.out	Mon Jun 10 00:46:29 2013 +0100
   121.2 +++ b/tests/basic/import_enum_a.out	Mon Jun 10 01:04:43 2013 +0100
   121.3 @@ -1,1 +1,1 @@
   121.4 -2
   121.5 +2
   122.1 --- a/tests/basic/import_enum_a.sp	Mon Jun 10 00:46:29 2013 +0100
   122.2 +++ b/tests/basic/import_enum_a.sp	Mon Jun 10 01:04:43 2013 +0100
   122.3 @@ -1,10 +1,10 @@
   122.4 -import shell;
   122.5 -import import_enum_b.*;
   122.6 -
   122.7 -public main()
   122.8 -{
   122.9 -    new Crab:crab = TotalCrab;
  122.10 -
  122.11 -    shell.PrintNum(crab);
  122.12 -}
  122.13 -
  122.14 +import shell;
  122.15 +import import_enum_b.*;
  122.16 +
  122.17 +public main()
  122.18 +{
  122.19 +    new Crab:crab = TotalCrab;
  122.20 +
  122.21 +    shell.PrintNum(crab);
  122.22 +}
  122.23 +
   123.1 --- a/tests/basic/import_enum_b.sp	Mon Jun 10 00:46:29 2013 +0100
   123.2 +++ b/tests/basic/import_enum_b.sp	Mon Jun 10 01:04:43 2013 +0100
   123.3 @@ -1,7 +1,7 @@
   123.4 -public enum Crab
   123.5 -{
   123.6 -    A,
   123.7 -    B,
   123.8 -    TotalCrab
   123.9 -};
  123.10 -
  123.11 +public enum Crab
  123.12 +{
  123.13 +    A,
  123.14 +    B,
  123.15 +    TotalCrab
  123.16 +};
  123.17 +
   124.1 --- a/tests/basic/passarray.out	Mon Jun 10 00:46:29 2013 +0100
   124.2 +++ b/tests/basic/passarray.out	Mon Jun 10 01:04:43 2013 +0100
   124.3 @@ -1,1 +1,1 @@
   124.4 -037
   124.5 +037
   125.1 --- a/tests/basic/passarray.sp	Mon Jun 10 00:46:29 2013 +0100
   125.2 +++ b/tests/basic/passarray.sp	Mon Jun 10 01:04:43 2013 +0100
   125.3 @@ -1,23 +1,23 @@
   125.4 -native PrintNum(num);
   125.5 -
   125.6 -f(a[])
   125.7 -{
   125.8 -    return a[3];
   125.9 -}
  125.10 -
  125.11 -g(a[])
  125.12 -{
  125.13 -    a[3] = 7;
  125.14 -}
  125.15 -
  125.16 -public main()
  125.17 -{
  125.18 -    new b[5];
  125.19 -    b[2] = 3;
  125.20 -    PrintNum(f(b));
  125.21 -    b[3] = 3;
  125.22 -    PrintNum(f(b));
  125.23 -    g(b);
  125.24 -    PrintNum(b[3]);
  125.25 -}
  125.26 -
  125.27 +native PrintNum(num);
  125.28 +
  125.29 +f(a[])
  125.30 +{
  125.31 +    return a[3];
  125.32 +}
  125.33 +
  125.34 +g(a[])
  125.35 +{
  125.36 +    a[3] = 7;
  125.37 +}
  125.38 +
  125.39 +public main()
  125.40 +{
  125.41 +    new b[5];
  125.42 +    b[2] = 3;
  125.43 +    PrintNum(f(b));
  125.44 +    b[3] = 3;
  125.45 +    PrintNum(f(b));
  125.46 +    g(b);
  125.47 +    PrintNum(b[3]);
  125.48 +}
  125.49 +
   126.1 --- a/tests/basic/postinc-array.out	Mon Jun 10 00:46:29 2013 +0100
   126.2 +++ b/tests/basic/postinc-array.out	Mon Jun 10 01:04:43 2013 +0100
   126.3 @@ -1,1 +1,1 @@
   126.4 -01
   126.5 +01
   127.1 --- a/tests/basic/postinc-array.sp	Mon Jun 10 00:46:29 2013 +0100
   127.2 +++ b/tests/basic/postinc-array.sp	Mon Jun 10 01:04:43 2013 +0100
   127.3 @@ -1,8 +1,8 @@
   127.4 -native PrintNum(num);
   127.5 -
   127.6 -public main()
   127.7 -{
   127.8 -    new x[5];
   127.9 -    PrintNum(x[3]++);
  127.10 -    PrintNum(x[3]);
  127.11 -}
  127.12 +native PrintNum(num);
  127.13 +
  127.14 +public main()
  127.15 +{
  127.16 +    new x[5];
  127.17 +    PrintNum(x[3]++);
  127.18 +    PrintNum(x[3]);
  127.19 +}
   128.1 --- a/tests/basic/postinc-local.out	Mon Jun 10 00:46:29 2013 +0100
   128.2 +++ b/tests/basic/postinc-local.out	Mon Jun 10 01:04:43 2013 +0100
   128.3 @@ -1,1 +1,1 @@
   128.4 -01
   128.5 +01
   129.1 --- a/tests/basic/postinc-local.sp	Mon Jun 10 00:46:29 2013 +0100
   129.2 +++ b/tests/basic/postinc-local.sp	Mon Jun 10 01:04:43 2013 +0100
   129.3 @@ -1,8 +1,8 @@
   129.4 -native PrintNum(num);
   129.5 -
   129.6 -public main()
   129.7 -{
   129.8 -    new i = 0;
   129.9 -    PrintNum(i++);
  129.10 -    PrintNum(i);
  129.11 -}
  129.12 +native PrintNum(num);
  129.13 +
  129.14 +public main()
  129.15 +{
  129.16 +    new i = 0;
  129.17 +    PrintNum(i++);
  129.18 +    PrintNum(i);
  129.19 +}
   130.1 --- a/tests/basic/postinc-ref.out	Mon Jun 10 00:46:29 2013 +0100
   130.2 +++ b/tests/basic/postinc-ref.out	Mon Jun 10 01:04:43 2013 +0100
   130.3 @@ -1,1 +1,1 @@
   130.4 -01
   130.5 +01
   131.1 --- a/tests/basic/postinc-ref.sp	Mon Jun 10 00:46:29 2013 +0100
   131.2 +++ b/tests/basic/postinc-ref.sp	Mon Jun 10 01:04:43 2013 +0100
   131.3 @@ -1,13 +1,13 @@
   131.4 -native PrintNum(num);
   131.5 -
   131.6 -f(&a)
   131.7 -{
   131.8 -    return a++;
   131.9 -}
  131.10 -
  131.11 -public main()
  131.12 -{
  131.13 -    new i = 0;
  131.14 -    PrintNum(f(i));
  131.15 -    PrintNum(i);
  131.16 -}
  131.17 +native PrintNum(num);
  131.18 +
  131.19 +f(&a)
  131.20 +{
  131.21 +    return a++;
  131.22 +}
  131.23 +
  131.24 +public main()
  131.25 +{
  131.26 +    new i = 0;
  131.27 +    PrintNum(f(i));
  131.28 +    PrintNum(i);
  131.29 +}
   132.1 --- a/tests/basic/precall-void-used.out	Mon Jun 10 00:46:29 2013 +0100
   132.2 +++ b/tests/basic/precall-void-used.out	Mon Jun 10 01:04:43 2013 +0100
   132.3 @@ -1,1 +1,1 @@
   132.4 -0
   132.5 +0
   133.1 --- a/tests/basic/precall-void-used.sp	Mon Jun 10 00:46:29 2013 +0100
   133.2 +++ b/tests/basic/precall-void-used.sp	Mon Jun 10 01:04:43 2013 +0100
   133.3 @@ -1,17 +1,17 @@
   133.4 -native PrintNum(num);
   133.5 -
   133.6 -g()
   133.7 -{
   133.8 -    PrintNum(f());
   133.9 -}
  133.10 -
  133.11 -f()
  133.12 -{
  133.13 -    return 0;
  133.14 -}
  133.15 -
  133.16 -public main()
  133.17 -{
  133.18 -    g();
  133.19 -}
  133.20 -
  133.21 +native PrintNum(num);
  133.22 +
  133.23 +g()
  133.24 +{
  133.25 +    PrintNum(f());
  133.26 +}
  133.27 +
  133.28 +f()
  133.29 +{
  133.30 +    return 0;
  133.31 +}
  133.32 +
  133.33 +public main()
  133.34 +{
  133.35 +    g();
  133.36 +}
  133.37 +
   134.1 --- a/tests/basic/preinc-array.out	Mon Jun 10 00:46:29 2013 +0100
   134.2 +++ b/tests/basic/preinc-array.out	Mon Jun 10 01:04:43 2013 +0100
   134.3 @@ -1,1 +1,1 @@
   134.4 -1
   134.5 +1
   135.1 --- a/tests/basic/preinc-array.sp	Mon Jun 10 00:46:29 2013 +0100
   135.2 +++ b/tests/basic/preinc-array.sp	Mon Jun 10 01:04:43 2013 +0100
   135.3 @@ -1,7 +1,7 @@
   135.4 -native PrintNum(num);
   135.5 -
   135.6 -public main()
   135.7 -{
   135.8 -    new x[5];
   135.9 -    PrintNum(++x[3]);
  135.10 -}
  135.11 +native PrintNum(num);
  135.12 +
  135.13 +public main()
  135.14 +{
  135.15 +    new x[5];
  135.16 +    PrintNum(++x[3]);
  135.17 +}
   136.1 --- a/tests/basic/preinc-local.out	Mon Jun 10 00:46:29 2013 +0100
   136.2 +++ b/tests/basic/preinc-local.out	Mon Jun 10 01:04:43 2013 +0100
   136.3 @@ -1,1 +1,1 @@
   136.4 -1
   136.5 +1
   137.1 --- a/tests/basic/preinc-local.sp	Mon Jun 10 00:46:29 2013 +0100
   137.2 +++ b/tests/basic/preinc-local.sp	Mon Jun 10 01:04:43 2013 +0100
   137.3 @@ -1,7 +1,7 @@
   137.4 -native PrintNum(num);
   137.5 -
   137.6 -public main()
   137.7 -{
   137.8 -    new i = 0;
   137.9 -    PrintNum(++i);
  137.10 -}
  137.11 +native PrintNum(num);
  137.12 +
  137.13 +public main()
  137.14 +{
  137.15 +    new i = 0;
  137.16 +    PrintNum(++i);
  137.17 +}
   138.1 --- a/tests/basic/preinc-ref.out	Mon Jun 10 00:46:29 2013 +0100
   138.2 +++ b/tests/basic/preinc-ref.out	Mon Jun 10 01:04:43 2013 +0100
   138.3 @@ -1,1 +1,1 @@
   138.4 -11
   138.5 +11
   139.1 --- a/tests/basic/preinc-ref.sp	Mon Jun 10 00:46:29 2013 +0100
   139.2 +++ b/tests/basic/preinc-ref.sp	Mon Jun 10 01:04:43 2013 +0100
   139.3 @@ -1,13 +1,13 @@
   139.4 -native PrintNum(num);
   139.5 -
   139.6 -f(&a)
   139.7 -{
   139.8 -    return ++a;
   139.9 -}
  139.10 -
  139.11 -public main()
  139.12 -{
  139.13 -    new i = 0;
  139.14 -    PrintNum(f(i));
  139.15 -    PrintNum(i);
  139.16 -}
  139.17 +native PrintNum(num);
  139.18 +
  139.19 +f(&a)
  139.20 +{
  139.21 +    return ++a;
  139.22 +}
  139.23 +
  139.24 +public main()
  139.25 +{
  139.26 +    new i = 0;
  139.27 +    PrintNum(f(i));
  139.28 +    PrintNum(i);
  139.29 +}
   140.1 --- a/tests/basic/recursive_import_1_a.out	Mon Jun 10 00:46:29 2013 +0100
   140.2 +++ b/tests/basic/recursive_import_1_a.out	Mon Jun 10 01:04:43 2013 +0100
   140.3 @@ -1,1 +1,1 @@
   140.4 -10
   140.5 +10
   141.1 --- a/tests/basic/recursive_import_1_a.sp	Mon Jun 10 00:46:29 2013 +0100
   141.2 +++ b/tests/basic/recursive_import_1_a.sp	Mon Jun 10 01:04:43 2013 +0100
   141.3 @@ -1,9 +1,9 @@
   141.4 -from recursive_import_1_b import f;
   141.5 -
   141.6 -native PrintNum(num);
   141.7 -
   141.8 -public main()
   141.9 -{
  141.10 -    f();
  141.11 -}
  141.12 -
  141.13 +from recursive_import_1_b import f;
  141.14 +
  141.15 +native PrintNum(num);
  141.16 +
  141.17 +public main()
  141.18 +{
  141.19 +    f();
  141.20 +}
  141.21 +
   142.1 --- a/tests/basic/recursive_import_1_b.sp	Mon Jun 10 00:46:29 2013 +0100
   142.2 +++ b/tests/basic/recursive_import_1_b.sp	Mon Jun 10 01:04:43 2013 +0100
   142.3 @@ -1,6 +1,6 @@
   142.4 -from recursive_import_1_a import PrintNum;
   142.5 -
   142.6 -public f()
   142.7 -{
   142.8 -    PrintNum(10);
   142.9 -}
  142.10 +from recursive_import_1_a import PrintNum;
  142.11 +
  142.12 +public f()
  142.13 +{
  142.14 +    PrintNum(10);
  142.15 +}
   143.1 --- a/tests/basic/ref-arg.out	Mon Jun 10 00:46:29 2013 +0100
   143.2 +++ b/tests/basic/ref-arg.out	Mon Jun 10 01:04:43 2013 +0100
   143.3 @@ -1,1 +1,1 @@
   143.4 -122
   143.5 +122
   144.1 --- a/tests/basic/ref-arg.sp	Mon Jun 10 00:46:29 2013 +0100
   144.2 +++ b/tests/basic/ref-arg.sp	Mon Jun 10 01:04:43 2013 +0100
   144.3 @@ -1,20 +1,20 @@
   144.4 -native PrintNum(b);
   144.5 -
   144.6 -f(&a)
   144.7 -{
   144.8 -    for (new i = 0; i < 10; i = i + 1)
   144.9 -        a = a + i;
  144.10 -    return 0;
  144.11 -}
  144.12 -
  144.13 -g(&b)
  144.14 -{
  144.15 -    return f(b);
  144.16 -}
  144.17 -
  144.18 -public main()
  144.19 -{
  144.20 -    new b = 77;
  144.21 -    g(b);
  144.22 -    PrintNum(b);
  144.23 -}
  144.24 +native PrintNum(b);
  144.25 +
  144.26 +f(&a)
  144.27 +{
  144.28 +    for (new i = 0; i < 10; i = i + 1)
  144.29 +        a = a + i;
  144.30 +    return 0;
  144.31 +}
  144.32 +
  144.33 +g(&b)
  144.34 +{
  144.35 +    return f(b);
  144.36 +}
  144.37 +
  144.38 +public main()
  144.39 +{
  144.40 +    new b = 77;
  144.41 +    g(b);
  144.42 +    PrintNum(b);
  144.43 +}
   145.1 --- a/tests/basic/ref-expr.out	Mon Jun 10 00:46:29 2013 +0100
   145.2 +++ b/tests/basic/ref-expr.out	Mon Jun 10 01:04:43 2013 +0100
   145.3 @@ -1,1 +1,1 @@
   145.4 -122
   145.5 +122
   146.1 --- a/tests/basic/ref-expr.sp	Mon Jun 10 00:46:29 2013 +0100
   146.2 +++ b/tests/basic/ref-expr.sp	Mon Jun 10 01:04:43 2013 +0100
   146.3 @@ -1,13 +1,13 @@
   146.4 -native PrintNum(num);
   146.5 -
   146.6 -f(&a)
   146.7 -{
   146.8 -    for (new i = 0; i < 10; i = i + 1)
   146.9 -        a = a + i;
  146.10 -    return a;
  146.11 -}
  146.12 -
  146.13 -public main()
  146.14 -{
  146.15 -    PrintNum(f(77));
  146.16 -}
  146.17 +native PrintNum(num);
  146.18 +
  146.19 +f(&a)
  146.20 +{
  146.21 +    for (new i = 0; i < 10; i = i + 1)
  146.22 +        a = a + i;
  146.23 +    return a;
  146.24 +}
  146.25 +
  146.26 +public main()
  146.27 +{
  146.28 +    PrintNum(f(77));
  146.29 +}
   147.1 --- a/tests/basic/ref-var.out	Mon Jun 10 00:46:29 2013 +0100
   147.2 +++ b/tests/basic/ref-var.out	Mon Jun 10 01:04:43 2013 +0100
   147.3 @@ -1,1 +1,1 @@
   147.4 -122
   147.5 +122
   148.1 --- a/tests/basic/ref-var.sp	Mon Jun 10 00:46:29 2013 +0100
   148.2 +++ b/tests/basic/ref-var.sp	Mon Jun 10 01:04:43 2013 +0100
   148.3 @@ -1,15 +1,15 @@
   148.4 -native PrintNum(num);
   148.5 -
   148.6 -f(&a)
   148.7 -{
   148.8 -    for (new i = 0; i < 10; i = i + 1)
   148.9 -        a = a + i;
  148.10 -    return 0;
  148.11 -}
  148.12 -
  148.13 -public main()
  148.14 -{
  148.15 -    new b = 77;
  148.16 -    f(b);
  148.17 -    PrintNum(b);
  148.18 -}
  148.19 +native PrintNum(num);
  148.20 +
  148.21 +f(&a)
  148.22 +{
  148.23 +    for (new i = 0; i < 10; i = i + 1)
  148.24 +        a = a + i;
  148.25 +    return 0;
  148.26 +}
  148.27 +
  148.28 +public main()
  148.29 +{
  148.30 +    new b = 77;
  148.31 +    f(b);
  148.32 +    PrintNum(b);
  148.33 +}
   149.1 --- a/tests/basic/return-analyze-for-1.sp	Mon Jun 10 00:46:29 2013 +0100
   149.2 +++ b/tests/basic/return-analyze-for-1.sp	Mon Jun 10 01:04:43 2013 +0100
   149.3 @@ -1,12 +1,12 @@
   149.4 -public f()
   149.5 -{
   149.6 -     for (;;) {
   149.7 -     }
   149.8 -}
   149.9 -
  149.10 -public main()
  149.11 -{
  149.12 -}
  149.13 -
  149.14 -
  149.15 -
  149.16 +public f()
  149.17 +{
  149.18 +     for (;;) {
  149.19 +     }
  149.20 +}
  149.21 +
  149.22 +public main()
  149.23 +{
  149.24 +}
  149.25 +
  149.26 +
  149.27 +
   150.1 --- a/tests/basic/return-analyze-for-2.out	Mon Jun 10 00:46:29 2013 +0100
   150.2 +++ b/tests/basic/return-analyze-for-2.out	Mon Jun 10 01:04:43 2013 +0100
   150.3 @@ -1,1 +1,1 @@
   150.4 -5
   150.5 +5
   151.1 --- a/tests/basic/return-analyze-for-2.sp	Mon Jun 10 00:46:29 2013 +0100
   151.2 +++ b/tests/basic/return-analyze-for-2.sp	Mon Jun 10 01:04:43 2013 +0100
   151.3 @@ -1,16 +1,16 @@
   151.4 -native PrintNum(num);
   151.5 -
   151.6 -f()
   151.7 -{
   151.8 -     for (;;) {
   151.9 -          return 5;
  151.10 -     }
  151.11 -}
  151.12 -
  151.13 -public main()
  151.14 -{
  151.15 -    PrintNum(f());
  151.16 -}
  151.17 -
  151.18 -
  151.19 -
  151.20 +native PrintNum(num);
  151.21 +
  151.22 +f()
  151.23 +{
  151.24 +     for (;;) {
  151.25 +          return 5;
  151.26 +     }
  151.27 +}
  151.28 +
  151.29 +public main()
  151.30 +{
  151.31 +    PrintNum(f());
  151.32 +}
  151.33 +
  151.34 +
  151.35 +
   152.1 --- a/tests/basic/return-analyze-for-3.err	Mon Jun 10 00:46:29 2013 +0100
   152.2 +++ b/tests/basic/return-analyze-for-3.err	Mon Jun 10 01:04:43 2013 +0100
   152.3 @@ -1,1 +1,1 @@
   152.4 -  line 1, col 2: not all paths through function return a value
   152.5 +  line 1, col 2: not all paths through function return a value
   153.1 --- a/tests/basic/return-analyze-for-3.sp	Mon Jun 10 00:46:29 2013 +0100
   153.2 +++ b/tests/basic/return-analyze-for-3.sp	Mon Jun 10 01:04:43 2013 +0100
   153.3 @@ -1,13 +1,13 @@
   153.4 -f(x)
   153.5 -{
   153.6 -    for (;;) {
   153.7 -        if (x)
   153.8 -            return 5;
   153.9 -    }
  153.10 -}
  153.11 -
  153.12 -public main()
  153.13 -{
  153.14 -    f(5);
  153.15 -}
  153.16 -
  153.17 +f(x)
  153.18 +{
  153.19 +    for (;;) {
  153.20 +        if (x)
  153.21 +            return 5;
  153.22 +    }
  153.23 +}
  153.24 +
  153.25 +public main()
  153.26 +{
  153.27 +    f(5);
  153.28 +}
  153.29 +
   154.1 --- a/tests/basic/return-analyze-for-4.err	Mon Jun 10 00:46:29 2013 +0100
   154.2 +++ b/tests/basic/return-analyze-for-4.err	Mon Jun 10 01:04:43 2013 +0100
   154.3 @@ -1,1 +1,1 @@
   154.4 -  line 1, col 8: not all paths through function return a value
   154.5 +  line 1, col 8: not all paths through function return a value
   155.1 --- a/tests/basic/return-analyze-for-4.sp	Mon Jun 10 00:46:29 2013 +0100
   155.2 +++ b/tests/basic/return-analyze-for-4.sp	Mon Jun 10 01:04:43 2013 +0100
   155.3 @@ -1,13 +1,13 @@
   155.4 -public f(x)
   155.5 -{
   155.6 -    for (; x;) {
   155.7 -        return 5;
   155.8 -    }
   155.9 -}
  155.10 -
  155.11 -public main()
  155.12 -{
  155.13 -    return f(5);
  155.14 -}
  155.15 -
  155.16 -
  155.17 +public f(x)
  155.18 +{
  155.19 +    for (; x;) {
  155.20 +        return 5;
  155.21 +    }
  155.22 +}
  155.23 +
  155.24 +public main()
  155.25 +{
  155.26 +    return f(5);
  155.27 +}
  155.28 +
  155.29 +
   156.1 --- a/tests/basic/return-analyze-for-5.out	Mon Jun 10 00:46:29 2013 +0100
   156.2 +++ b/tests/basic/return-analyze-for-5.out	Mon Jun 10 01:04:43 2013 +0100
   156.3 @@ -1,1 +1,1 @@
   156.4 -54
   156.5 +54
   157.1 --- a/tests/basic/return-analyze-for-5.sp	Mon Jun 10 00:46:29 2013 +0100
   157.2 +++ b/tests/basic/return-analyze-for-5.sp	Mon Jun 10 01:04:43 2013 +0100
   157.3 @@ -1,17 +1,17 @@
   157.4 -native PrintNum(num);
   157.5 -
   157.6 -f(x)
   157.7 -{
   157.8 -    for (; x;) {
   157.9 -        return 5;
  157.10 -    }
  157.11 -    return 4;
  157.12 -}
  157.13 -
  157.14 -public main()
  157.15 -{
  157.16 -    PrintNum(f(5));
  157.17 -    PrintNum(f(0));
  157.18 -}
  157.19 -
  157.20 -
  157.21 +native PrintNum(num);
  157.22 +
  157.23 +f(x)
  157.24 +{
  157.25 +    for (; x;) {
  157.26 +        return 5;
  157.27 +    }
  157.28 +    return 4;
  157.29 +}
  157.30 +
  157.31 +public main()
  157.32 +{
  157.33 +    PrintNum(f(5));
  157.34 +    PrintNum(f(0));
  157.35 +}
  157.36 +
  157.37 +
   158.1 --- a/tests/basic/return-analyze-if-1.out	Mon Jun 10 00:46:29 2013 +0100
   158.2 +++ b/tests/basic/return-analyze-if-1.out	Mon Jun 10 01:04:43 2013 +0100
   158.3 @@ -1,1 +1,1 @@
   158.4 -25
   158.5 +25
   159.1 --- a/tests/basic/return-analyze-if-1.sp	Mon Jun 10 00:46:29 2013 +0100
   159.2 +++ b/tests/basic/return-analyze-if-1.sp	Mon Jun 10 01:04:43 2013 +0100
   159.3 @@ -1,16 +1,16 @@
   159.4 -native PrintNum(num);
   159.5 -
   159.6 -f(x)
   159.7 -{
   159.8 -    if (x)
   159.9 -        return 5;
  159.10 -    return 2;
  159.11 -}
  159.12 -
  159.13 -public main()
  159.14 -{
  159.15 -    PrintNum(f(0));
  159.16 -    PrintNum(f(1));
  159.17 -}
  159.18 -
  159.19 -
  159.20 +native PrintNum(num);
  159.21 +
  159.22 +f(x)
  159.23 +{
  159.24 +    if (x)
  159.25 +        return 5;
  159.26 +    return 2;
  159.27 +}
  159.28 +
  159.29 +public main()
  159.30 +{
  159.31 +    PrintNum(f(0));
  159.32 +    PrintNum(f(1));
  159.33 +}
  159.34 +
  159.35 +
   160.1 --- a/tests/basic/return-analyze-if-2.err	Mon Jun 10 00:46:29 2013 +0100
   160.2 +++ b/tests/basic/return-analyze-if-2.err	Mon Jun 10 01:04:43 2013 +0100
   160.3 @@ -1,1 +1,1 @@
   160.4 -  line 3, col 3: not all paths through function return a value
   160.5 +  line 3, col 3: not all paths through function return a value
   161.1 --- a/tests/basic/return-analyze-if-2.sp	Mon Jun 10 00:46:29 2013 +0100
   161.2 +++ b/tests/basic/return-analyze-if-2.sp	Mon Jun 10 01:04:43 2013 +0100
   161.3 @@ -1,14 +1,14 @@
   161.4 -native PrintNum(num);
   161.5 -
   161.6 -f(x)
   161.7 -{
   161.8 -    if (x)
   161.9 -        return 5;
  161.10 -}
  161.11 -
  161.12 -public main()
  161.13 -{
  161.14 -    PrintNum(f(4));
  161.15 -}
  161.16 -
  161.17 -
  161.18 +native PrintNum(num);
  161.19 +
  161.20 +f(x)
  161.21 +{
  161.22 +    if (x)
  161.23 +        return 5;
  161.24 +}
  161.25 +
  161.26 +public main()
  161.27 +{
  161.28 +    PrintNum(f(4));
  161.29 +}
  161.30 +
  161.31 +
   162.1 --- a/tests/basic/return-analyze-if-3.out	Mon Jun 10 00:46:29 2013 +0100
   162.2 +++ b/tests/basic/return-analyze-if-3.out	Mon Jun 10 01:04:43 2013 +0100
   162.3 @@ -1,1 +1,1 @@
   162.4 -65
   162.5 +65
   163.1 --- a/tests/basic/return-analyze-if-3.sp	Mon Jun 10 00:46:29 2013 +0100
   163.2 +++ b/tests/basic/return-analyze-if-3.sp	Mon Jun 10 01:04:43 2013 +0100
   163.3 @@ -1,17 +1,17 @@
   163.4 -native PrintNum(num);
   163.5 -
   163.6 -f(x)
   163.7 -{
   163.8 -    if (x)
   163.9 -        return 5;
  163.10 -    else
  163.11 -        return 6;
  163.12 -}
  163.13 -
  163.14 -public main()
  163.15 -{
  163.16 -    PrintNum(f(0));
  163.17 -    PrintNum(f(1));
  163.18 -}
  163.19 -
  163.20 -
  163.21 +native PrintNum(num);
  163.22 +
  163.23 +f(x)
  163.24 +{
  163.25 +    if (x)
  163.26 +        return 5;
  163.27 +    else
  163.28 +        return 6;
  163.29 +}
  163.30 +
  163.31 +public main()
  163.32 +{
  163.33 +    PrintNum(f(0));
  163.34 +    PrintNum(f(1));
  163.35 +}
  163.36 +
  163.37 +
   164.1 --- a/tests/basic/return-analyze-if-4.err	Mon Jun 10 00:46:29 2013 +0100
   164.2 +++ b/tests/basic/return-analyze-if-4.err	Mon Jun 10 01:04:43 2013 +0100
   164.3 @@ -1,1 +1,1 @@
   164.4 -  line 3, col 3: not all paths through function return a value
   164.5 +  line 3, col 3: not all paths through function return a value
   165.1 --- a/tests/basic/return-analyze-if-4.sp	Mon Jun 10 00:46:29 2013 +0100
   165.2 +++ b/tests/basic/return-analyze-if-4.sp	Mon Jun 10 01:04:43 2013 +0100
   165.3 @@ -1,17 +1,17 @@
   165.4 -native PrintNum(num);
   165.5 -
   165.6 -f(x)
   165.7 -{
   165.8 -    if (x)
   165.9 -        return 5;
  165.10 -    else if (x)
  165.11 -        return 6;
  165.12 -}
  165.13 -
  165.14 -public main()
  165.15 -{
  165.16 -    PrintNum(f(0));
  165.17 -    PrintNum(f(1));
  165.18 -}
  165.19 -
  165.20 -
  165.21 +native PrintNum(num);
  165.22 +
  165.23 +f(x)
  165.24 +{
  165.25 +    if (x)
  165.26 +        return 5;
  165.27 +    else if (x)
  165.28 +        return 6;
  165.29 +}
  165.30 +
  165.31 +public main()
  165.32 +{
  165.33 +    PrintNum(f(0));
  165.34 +    PrintNum(f(1));
  165.35 +}
  165.36 +
  165.37 +
   166.1 --- a/tests/basic/return-analyze-if-5.out	Mon Jun 10 00:46:29 2013 +0100
   166.2 +++ b/tests/basic/return-analyze-if-5.out	Mon Jun 10 01:04:43 2013 +0100
   166.3 @@ -1,1 +1,1 @@
   166.4 -596
   166.5 +596
   167.1 --- a/tests/basic/return-analyze-if-5.sp	Mon Jun 10 00:46:29 2013 +0100
   167.2 +++ b/tests/basic/return-analyze-if-5.sp	Mon Jun 10 01:04:43 2013 +0100
   167.3 @@ -1,20 +1,20 @@
   167.4 -native PrintNum(num);
   167.5 -
   167.6 -f(x)
   167.7 -{
   167.8 -    if (x == 5)
   167.9 -        return 5;
  167.10 -    else if (x == 7)
  167.11 -        return 9;
  167.12 -    else
  167.13 -        return 6;
  167.14 -}
  167.15 -
  167.16 -public main()
  167.17 -{
  167.18 -    PrintNum(f(5));
  167.19 -    PrintNum(f(7));
  167.20 -    PrintNum(f(2));
  167.21 -}
  167.22 -
  167.23 -
  167.24 +native PrintNum(num);
  167.25 +
  167.26 +f(x)
  167.27 +{
  167.28 +    if (x == 5)
  167.29 +        return 5;
  167.30 +    else if (x == 7)
  167.31 +        return 9;
  167.32 +    else
  167.33 +        return 6;
  167.34 +}
  167.35 +
  167.36 +public main()
  167.37 +{
  167.38 +    PrintNum(f(5));
  167.39 +    PrintNum(f(7));
  167.40 +    PrintNum(f(2));
  167.41 +}
  167.42 +
  167.43 +
   168.1 --- a/tests/basic/shell.sp	Mon Jun 10 00:46:29 2013 +0100
   168.2 +++ b/tests/basic/shell.sp	Mon Jun 10 01:04:43 2013 +0100
   168.3 @@ -1,3 +1,3 @@
   168.4 -native PrintNum(num);
   168.5 -native PrintString(const char:text[]);
   168.6 -native PrintFloat(float:f);
   168.7 +native PrintNum(num);
   168.8 +native PrintString(const char:text[]);
   168.9 +native PrintFloat(float:f);
   169.1 --- a/tests/basic/string-lit-1.out	Mon Jun 10 00:46:29 2013 +0100
   169.2 +++ b/tests/basic/string-lit-1.out	Mon Jun 10 01:04:43 2013 +0100
   169.3 @@ -1,1 +1,1 @@
   169.4 -101121
   169.5 +101121
   170.1 --- a/tests/basic/string-lit-1.sp	Mon Jun 10 00:46:29 2013 +0100
   170.2 +++ b/tests/basic/string-lit-1.sp	Mon Jun 10 01:04:43 2013 +0100
   170.3 @@ -1,9 +1,9 @@
   170.4 -native PrintNum(num);
   170.5 -
   170.6 -public main()
   170.7 -{
   170.8 -    new char:str1[] = "hello";
   170.9 -    new char:str2[4] = "bye";
  170.10 -    PrintNum(str1[1]);
  170.11 -    PrintNum(str2[1]);
  170.12 -}
  170.13 +native PrintNum(num);
  170.14 +
  170.15 +public main()
  170.16 +{
  170.17 +    new char:str1[] = "hello";
  170.18 +    new char:str2[4] = "bye";
  170.19 +    PrintNum(str1[1]);
  170.20 +    PrintNum(str2[1]);
  170.21 +}
   171.1 --- a/tests/basic/string-lit-2.out	Mon Jun 10 00:46:29 2013 +0100
   171.2 +++ b/tests/basic/string-lit-2.out	Mon Jun 10 01:04:43 2013 +0100
   171.3 @@ -1,1 +1,1 @@
   171.4 -6568101121
   171.5 +6568101121
   172.1 --- a/tests/basic/string-lit-2.sp	Mon Jun 10 00:46:29 2013 +0100
   172.2 +++ b/tests/basic/string-lit-2.sp	Mon Jun 10 01:04:43 2013 +0100
   172.3 @@ -1,26 +1,26 @@
   172.4 -native PrintNum(num);
   172.5 -
   172.6 -f(x)
   172.7 -{
   172.8 -    new char:str1[];
   172.9 -    new char:str2[4];
  172.10 -
  172.11 -    str1 = "hello";
  172.12 -    str2 = "bye";
  172.13 -
  172.14 -    // Make sure modifying the string doesn't modify the
  172.15 -    // canonical literals.
  172.16 -    if (x) {
  172.17 -        str1[1] = 65;
  172.18 -        str2[1] = 68;
  172.19 -    }
  172.20 -
  172.21 -    PrintNum(str1[1]);
  172.22 -    PrintNum(str2[1]);
  172.23 -}
  172.24 -
  172.25 -public main()
  172.26 -{
  172.27 -    f(1);
  172.28 -    f(0);
  172.29 -}
  172.30 +native PrintNum(num);
  172.31 +
  172.32 +f(x)
  172.33 +{
  172.34 +    new char:str1[];
  172.35 +    new char:str2[4];
  172.36 +
  172.37 +    str1 = "hello";
  172.38 +    str2 = "bye";
  172.39 +
  172.40 +    // Make sure modifying the string doesn't modify the
  172.41 +    // canonical literals.
  172.42 +    if (x) {
  172.43 +        str1[1] = 65;
  172.44 +        str2[1] = 68;
  172.45 +    }
  172.46 +
  172.47 +    PrintNum(str1[1]);
  172.48 +    PrintNum(str2[1]);
  172.49 +}
  172.50 +
  172.51 +public main()
  172.52 +{
  172.53 +    f(1);
  172.54 +    f(0);
  172.55 +}
   173.1 --- a/tests/basic/while.out	Mon Jun 10 00:46:29 2013 +0100
   173.2 +++ b/tests/basic/while.out	Mon Jun 10 01:04:43 2013 +0100
   173.3 @@ -1,1 +1,1 @@
   173.4 -111
   173.5 +111
   174.1 --- a/tests/basic/while.sp	Mon Jun 10 00:46:29 2013 +0100
   174.2 +++ b/tests/basic/while.sp	Mon Jun 10 01:04:43 2013 +0100
   174.3 @@ -1,10 +1,10 @@
   174.4 -native PrintNum(num);
   174.5 -
   174.6 -public main()
   174.7 -{
   174.8 -   new i = 0;
   174.9 -   while (i < 100) {
  174.10 -      i = i + 37;
  174.11 -   }
  174.12 -   PrintNum(i);
  174.13 -}
  174.14 +native PrintNum(num);
  174.15 +
  174.16 +public main()
  174.17 +{
  174.18 +   new i = 0;
  174.19 +   while (i < 100) {
  174.20 +      i = i + 37;
  174.21 +   }
  174.22 +   PrintNum(i);
  174.23 +}
   175.1 --- a/tests/display.py	Mon Jun 10 00:46:29 2013 +0100
   175.2 +++ b/tests/display.py	Mon Jun 10 01:04:43 2013 +0100
   175.3 @@ -1,23 +1,23 @@
   175.4 -# vim: set ts=2 sw=2 tw=99 ft=python et:
   175.5 -
   175.6 -class Interactive:
   175.7 -  def __init__(self):
   175.8 -    self.failures = []
   175.9 -    self.timeouts = []
  175.10 -
  175.11 -  def begin(self, tests):
  175.12 -    return
  175.13 -
  175.14 -  def result(self, test, r):
  175.15 -    if r.ok:
  175.16 -      print('PASS: ' + test.name)
  175.17 -    else:
  175.18 -      if r.timeout:
  175.19 -        print('TIMEOUT: ' + test.name)
  175.20 -      else:
  175.21 -        print('FAIL: ' + test.name)
  175.22 -      print(' -- Error code: ' + str(r.code))
  175.23 -      print(' -- message: \n' + r.message)
  175.24 -      print(' -- stdout: \n' + r.out)
  175.25 -      print(' -- stderr: \n' + r.err)
  175.26 -
  175.27 +# vim: set ts=2 sw=2 tw=99 ft=python et:
  175.28 +
  175.29 +class Interactive:
  175.30 +  def __init__(self):
  175.31 +    self.failures = []
  175.32 +    self.timeouts = []
  175.33 +
  175.34 +  def begin(self, tests):
  175.35 +    return
  175.36 +
  175.37 +  def result(self, test, r):
  175.38 +    if r.ok:
  175.39 +      print('PASS: ' + test.name)
  175.40 +    else:
  175.41 +      if r.timeout:
  175.42 +        print('TIMEOUT: ' + test.name)
  175.43 +      else:
  175.44 +        print('FAIL: ' + test.name)
  175.45 +      print(' -- Error code: ' + str(r.code))
  175.46 +      print(' -- message: \n' + r.message)
  175.47 +      print(' -- stdout: \n' + r.out)
  175.48 +      print(' -- stderr: \n' + r.err)
  175.49 +
   176.1 --- a/tests/harness.py	Mon Jun 10 00:46:29 2013 +0100
   176.2 +++ b/tests/harness.py	Mon Jun 10 01:04:43 2013 +0100
   176.3 @@ -1,116 +1,116 @@
   176.4 -# vim: set ts=2 sw=4 tw=99 ft=python et:
   176.5 -import os
   176.6 -import re
   176.7 -import sys
   176.8 -import time
   176.9 -import os.path
  176.10 -from test import Test
  176.11 -from subprocess import *
  176.12 -from threading import Thread
  176.13 -from display import Interactive
  176.14 -
  176.15 -def FindTests(tests, root, folder):
  176.16 -  folders = []
  176.17 -  for name in os.listdir(os.path.join(root, folder)):
  176.18 -    path = os.path.join(root, folder, name)
  176.19 -    if os.path.isdir(path):
  176.20 -      folders.append(name)
  176.21 -      continue
  176.22 -
  176.23 -    out = re.match("^([^\.]+)\.out$", name)
  176.24 -    err = re.match("^([^\.]+)\.err$", name)
  176.25 -    if out:
  176.26 -        name = os.path.join(folder, out.group(1))
  176.27 -        tests.append(Test(root, name, 'out'))
  176.28 -    elif err:
  176.29 -        name = os.path.join(folder, err.group(1))
  176.30 -        tests.append(Test(root, name, 'err'))
  176.31 -
  176.32 -  for name in folders:
  176.33 -    path = os.path.join(folder, name)
  176.34 -    FindTests(tests, root, path)
  176.35 -
  176.36 -def IsTestRoot(path, name):
  176.37 -  return os.path.isdir(path)
  176.38 -
  176.39 -def RunTest_(argv, options, L):
  176.40 -  if sys.platform != 'win32':
  176.41 -    options['close_fds'] = True
  176.42 -
  176.43 -  p = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options)
  176.44 -
  176.45 -  L[0] = p
  176.46 -  out, err = p.communicate()
  176.47 -  L[1] = (out, err, p.returncode)
  176.48 -
  176.49 -def RunTest(test, options, shell):
  176.50 -  argv = [shell, test.cmd()]
  176.51 -
  176.52 -  L = [None, None]
  176.53 -  timeout = False
  176.54 -  th = Thread(target = RunTest_, args = (argv, options, L))
  176.55 -  th.start()
  176.56 -  th.join(10.0)
  176.57 -  while th.isAlive():
  176.58 -    if L[0] is not None:
  176.59 -      try:
  176.60 -        L[0].kill()
  176.61 -        time.sleep(.1)
  176.62 -        timeout = True
  176.63 -      except e:
  176.64 -        pass
  176.65 -
  176.66 -  th.join()
  176.67 -  (out, err, code) = L[1]
  176.68 -
  176.69 -  return test.check(out, err, code, timeout)
  176.70 -
  176.71 -def RunTests(display, tests, shell):
  176.72 -  display.begin(tests)
  176.73 -  ok = True
  176.74 -  try:
  176.75 -    for test in tests:
  176.76 -      options = { }
  176.77 -      result = RunTest(test, options, shell)
  176.78 -
  176.79 -      ok = ok and result.ok
  176.80 -      
  176.81 -      display.result(test, result)
  176.82 -  except KeyboardInterrupt:
  176.83 -    display.cancel()
  176.84 -    ok = False
  176.85 -
  176.86 -  return ok
  176.87 -
  176.88 -  
  176.89 -def main(argv):
  176.90 -  root = os.path.dirname(os.path.abspath(__file__))
  176.91 -
  176.92 -  from optparse import OptionParser
  176.93 -  op = OptionParser(usage='%prog [options] <shell>')
  176.94 -  (options, args) = op.parse_args(argv)
  176.95 -
  176.96 -  if len(args) != 1:
  176.97 -    op.error('missing <shell> argument')
  176.98 -
  176.99 -  shell = os.path.normpath(args[0])
 176.100 -
 176.101 -  tests = []
 176.102 -  for name in os.listdir(root):
 176.103 -    path = os.path.join(root, name)
 176.104 -    if IsTestRoot(path, name):
 176.105 -      FindTests(tests, root, name)
 176.106 -
 176.107 -  if len(tests) == 0:
 176.108 -    op.error('no test cases found')
 176.109 -
 176.110 -  display = Interactive()
 176.111 -  ok = RunTests(display, tests, shell)
 176.112 -  if ok:
 176.113 -    sys.exit(0)
 176.114 -  else:
 176.115 -    sys.exit(1)
 176.116 -
 176.117 -if __name__ == '__main__':
 176.118 -  main(sys.argv[1:])
 176.119 -
 176.120 +# vim: set ts=2 sw=4 tw=99 ft=python et:
 176.121 +import os
 176.122 +import re
 176.123 +import sys
 176.124 +import time
 176.125 +import os.path
 176.126 +from test import Test
 176.127 +from subprocess import *
 176.128 +from threading import Thread
 176.129 +from display import Interactive
 176.130 +
 176.131 +def FindTests(tests, root, folder):
 176.132 +  folders = []
 176.133 +  for name in os.listdir(os.path.join(root, folder)):
 176.134 +    path = os.path.join(root, folder, name)
 176.135 +    if os.path.isdir(path):
 176.136 +      folders.append(name)
 176.137 +      continue
 176.138 +
 176.139 +    out = re.match("^([^\.]+)\.out$", name)
 176.140 +    err = re.match("^([^\.]+)\.err$", name)
 176.141 +    if out:
 176.142 +        name = os.path.join(folder, out.group(1))
 176.143 +        tests.append(Test(root, name, 'out'))
 176.144 +    elif err:
 176.145 +        name = os.path.join(folder, err.group(1))
 176.146 +        tests.append(Test(root, name, 'err'))
 176.147 +
 176.148 +  for name in folders:
 176.149 +    path = os.path.join(folder, name)
 176.150 +    FindTests(tests, root, path)
 176.151 +
 176.152 +def IsTestRoot(path, name):
 176.153 +  return os.path.isdir(path)
 176.154 +
 176.155 +def RunTest_(argv, options, L):
 176.156 +  if sys.platform != 'win32':
 176.157 +    options['close_fds'] = True
 176.158 +
 176.159 +  p = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options)
 176.160 +
 176.161 +  L[0] = p
 176.162 +  out, err = p.communicate()
 176.163 +  L[1] = (out, err, p.returncode)
 176.164 +
 176.165 +def RunTest(test, options, shell):
 176.166 +  argv = [shell, test.cmd()]
 176.167 +
 176.168 +  L = [None, None]
 176.169 +  timeout = False
 176.170 +  th = Thread(target = RunTest_, args = (argv, options, L))
 176.171 +  th.start()
 176.172 +  th.join(10.0)
 176.173 +  while th.isAlive():
 176.174 +    if L[0] is not None:
 176.175 +      try:
 176.176 +        L[0].kill()
 176.177 +        time.sleep(.1)
 176.178 +        timeout = True
 176.179 +      except e:
 176.180 +        pass
 176.181 +
 176.182 +  th.join()
 176.183 +  (out, err, code) = L[1]
 176.184 +
 176.185 +  return test.check(out, err, code, timeout)
 176.186 +
 176.187 +def RunTests(display, tests, shell):
 176.188 +  display.begin(tests)
 176.189 +  ok = True
 176.190 +  try:
 176.191 +    for test in tests:
 176.192 +      options = { }
 176.193 +      result = RunTest(test, options, shell)
 176.194 +
 176.195 +      ok = ok and result.ok
 176.196 +      
 176.197 +      display.result(test, result)
 176.198 +  except KeyboardInterrupt:
 176.199 +    display.cancel()
 176.200 +    ok = False
 176.201 +
 176.202 +  return ok
 176.203 +
 176.204 +  
 176.205 +def main(argv):
 176.206 +  root = os.path.dirname(os.path.abspath(__file__))
 176.207 +
 176.208 +  from optparse import OptionParser
 176.209 +  op = OptionParser(usage='%prog [options] <shell>')
 176.210 +  (options, args) = op.parse_args(argv)
 176.211 +
 176.212 +  if len(args) != 1:
 176.213 +    op.error('missing <shell> argument')
 176.214 +
 176.215 +  shell = os.path.normpath(args[0])
 176.216 +
 176.217 +  tests = []
 176.218 +  for name in os.listdir(root):
 176.219 +    path = os.path.join(root, name)
 176.220 +    if IsTestRoot(path, name):
 176.221 +      FindTests(tests, root, name)
 176.222 +
 176.223 +  if len(tests) == 0:
 176.224 +    op.error('no test cases found')
 176.225 +
 176.226 +  display = Interactive()
 176.227 +  ok = RunTests(display, tests, shell)
 176.228 +  if ok:
 176.229 +    sys.exit(0)
 176.230 +  else:
 176.231 +    sys.exit(1)
 176.232 +
 176.233 +if __name__ == '__main__':
 176.234 +  main(sys.argv[1:])
 176.235 +
   177.1 --- a/tests/prototype/string-1.sp	Mon Jun 10 00:46:29 2013 +0100
   177.2 +++ b/tests/prototype/string-1.sp	Mon Jun 10 01:04:43 2013 +0100
   177.3 @@ -1,6 +1,6 @@
   177.4 -main()
   177.5 -{
   177.6 -    new String:buffer[100] = "clam";
   177.7 -    buffer = "hedgehog";
   177.8 -    return buffer[3];
   177.9 -}
  177.10 +main()
  177.11 +{
  177.12 +    new String:buffer[100] = "clam";
  177.13 +    buffer = "hedgehog";
  177.14 +    return buffer[3];
  177.15 +}
   178.1 --- a/tests/ref-array.sp	Mon Jun 10 00:46:29 2013 +0100
   178.2 +++ b/tests/ref-array.sp	Mon Jun 10 01:04:43 2013 +0100
   178.3 @@ -1,13 +1,13 @@
   178.4 -f(&a)
   178.5 -{
   178.6 -    for (new i = 0; i < 10; i = i + 1)
   178.7 -        a = a + i;
   178.8 -    return a;
   178.9 -}
  178.10 -
  178.11 -main()
  178.12 -{
  178.13 -    new array[4];
  178.14 -    f(array[3]);
  178.15 -    return array[3];
  178.16 -}
  178.17 +f(&a)
  178.18 +{
  178.19 +    for (new i = 0; i < 10; i = i + 1)
  178.20 +        a = a + i;
  178.21 +    return a;
  178.22 +}
  178.23 +
  178.24 +main()
  178.25 +{
  178.26 +    new array[4];
  178.27 +    f(array[3]);
  178.28 +    return array[3];
  178.29 +}
   179.1 --- a/tests/test.py	Mon Jun 10 00:46:29 2013 +0100
   179.2 +++ b/tests/test.py	Mon Jun 10 01:04:43 2013 +0100
   179.3 @@ -1,64 +1,64 @@
   179.4 -# vim: set ts=2 sw=4 tw=99 ft=python et:
   179.5 -import os
   179.6 -import os.path
   179.7 -
   179.8 -class Result:
   179.9 -  def __init__(self, ok, out, err, code, timeout, message):
  179.10 -    self.ok = ok
  179.11 -    self.out = out
  179.12 -    self.err = err
  179.13 -    self.code = code
  179.14 -    self.timeout = timeout
  179.15 -    self.message = message
  179.16 -
  179.17 -class Test:
  179.18 -  def __init__(self, path, name, type):
  179.19 -    self.path = path
  179.20 -    self.name = name
  179.21 -    self.type = type
  179.22 -
  179.23 -  def cmd(self):
  179.24 -    return os.path.join(self.path, self.name + '.sp')
  179.25 -
  179.26 -  def compare(self, text):
  179.27 -    ok = True
  179.28 -    message = None
  179.29 -    with open(os.path.join(self.path, self.name + '.' + self.type), 'rt') as f:
  179.30 -      text = str.replace(text, '\r', '')
  179.31 -      lines = text.split('\n')
  179.32 -      i = 0
  179.33 -      for line in f:
  179.34 -        line = line.rstrip('\r\n')
  179.35 -        if "Displaying compilation errors for" in lines[i]:
  179.36 -          i += 1
  179.37 -          continue
  179.38 -        if line != lines[i]:
  179.39 -          message = 'Got "' + lines[i] + '", expected "' + line + '"'
  179.40 -          ok = False
  179.41 -          break
  179.42 -        i += 1
  179.43 -    return (ok, message)
  179.44 -
  179.45 -  def check(self, out, err, code, timeout):
  179.46 -    if not out:
  179.47 -      out = ''
  179.48 -    if not err:
  179.49 -      err = ''
  179.50 -    if self.type == 'err':
  179.51 -      if code == 0:
  179.52 -        message = 'Expected failure, got success'
  179.53 -        ok = False
  179.54 -      else:
  179.55 -        (ok, message) = self.compare(err)
  179.56 -    elif self.type == 'out':
  179.57 -      if code != 0:
  179.58 -        message = 'Expected success, got failure (code: ' + str(code) + ')'
  179.59 -        ok = False
  179.60 -      else:
  179.61 -        (ok, message) = self.compare(out)
  179.62 -
  179.63 -    if timeout:
  179.64 -      ok = False
  179.65 -      message = 'timeout'
  179.66 -
  179.67 -    return Result(ok, out, err, code, timeout, message)
  179.68 +# vim: set ts=2 sw=4 tw=99 ft=python et:
  179.69 +import os
  179.70 +import os.path
  179.71 +
  179.72 +class Result:
  179.73 +  def __init__(self, ok, out, err, code, timeout, message):
  179.74 +    self.ok = ok
  179.75 +    self.out = out
  179.76 +    self.err = err
  179.77 +    self.code = code
  179.78 +    self.timeout = timeout
  179.79 +    self.message = message
  179.80 +
  179.81 +class Test:
  179.82 +  def __init__(self, path, name, type):
  179.83 +    self.path = path
  179.84 +    self.name = name
  179.85 +    self.type = type
  179.86 +
  179.87 +  def cmd(self):
  179.88 +    return os.path.join(self.path, self.name + '.sp')
  179.89 +
  179.90 +  def compare(self, text):
  179.91 +    ok = True
  179.92 +    message = None
  179.93 +    with open(os.path.join(self.path, self.name + '.' + self.type), 'rt') as f:
  179.94 +      text = str.replace(text, '\r', '')
  179.95 +      lines = text.split('\n')
  179.96 +      i = 0
  179.97 +      for line in f:
  179.98 +        line = line.rstrip('\r\n')
  179.99 +        if "Displaying compilation errors for" in lines[i]:
 179.100 +          i += 1
 179.101 +          continue
 179.102 +        if line != lines[i]:
 179.103 +          message = 'Got "' + lines[i] + '", expected "' + line + '"'
 179.104 +          ok = False
 179.105 +          break
 179.106 +        i += 1
 179.107 +    return (ok, message)
 179.108 +
 179.109 +  def check(self, out, err, code, timeout):
 179.110 +    if not out:
 179.111 +      out = ''
 179.112 +    if not err:
 179.113 +      err = ''
 179.114 +    if self.type == 'err':
 179.115 +      if code == 0:
 179.116 +        message = 'Expected failure, got success'
 179.117 +        ok = False
 179.118 +      else:
 179.119 +        (ok, message) = self.compare(err)
 179.120 +    elif self.type == 'out':
 179.121 +      if code != 0:
 179.122 +        message = 'Expected success, got failure (code: ' + str(code) + ')'
 179.123 +        ok = False
 179.124 +      else:
 179.125 +        (ok, message) = self.compare(out)
 179.126 +
 179.127 +    if timeout:
 179.128 +      ok = False
 179.129 +      message = 'timeout'
 179.130 +
 179.131 +    return Result(ok, out, err, code, timeout, message)