Massive SemA/BC refactoring to support better type systems. Read on for more.
Massive SemA/BC refactoring to support better type systems. Read on for more.
The previous compiler had a simple pipeline, best outlined as:
(1) Parsing and name binding -> AST
(2) Storage allocation -> AST
(3) Semantic Analysis (SemA) -> AST
(4) Bytecode Compilation (BC) -> Code
This pipeline, unfortunately, had two problems. First, name binding cannot be performed in one pass if we wish to have multi-file support in the form of modules. Name binding must be two-pass.
Second, because SemA was only capable of annotating AST nodes with a single type, most coercion work had to be duplicated in the BC phase, as coercion was not explicit in the SemA output. This made introducing new type rules extremely difficult, and all but precluded concepts like operator overloading (or overloading at all).
This patch rewrites most of Keima's backend. Of interest are the following changes:
(1) CompileContext has been refactored around future multi-file support.
(2) Parsing no longer performs any name binding.
(3) The grammar for type-and-name has been changed from:
(Label | Identifier)? Identifier
to:
Type? Identifier
where:
Type ::= OldType | NewType
OldType ::= Label
NewType ::= Identifier (. NewType)*
Although we do not implement the full production for Type yet, this
distinction is important. A type identifier is now affixed to the AST
as an Expression (right now, always a NameProxy), so it can fully
participate in name binding.
(4) Immediately after parsing, the AST goes through a NamePopulation phase.
This phase creates Scope objects for every scope which declares a name,
and if those names are declaring types or functions, a Symbol is created
and entered into the scope. Symbols entirely replace the old BoundName
classes.
(5) After NamePopulation comes NameBinding. This phase performs three steps:
(a) Links Scope objects together, to form a tree.
(b) Binds any free name to an existing name in the scope chain.
(c) Creates and registers any Symbols for names which have not yet been
added to the scope (for example, local variables).
In accordance, all "allocation" and "binding" concepts have been removed
from Scopes, which are now lightweight container classes.
(6) SemA now generates bytecode for each statement in the AST. Expression
compilation is performed via a separate mechanism called HIR (High-level
Intermediate Representation). To analyze an expression, SemA will walk
the AST, and produce a HIR object for each node. HIR is typed, and SemA
may insert coercion nodes, or even expand an AST node into multiple HIR
nodes. The result of evaluating an expression in SemA is therefore the
the root of a HIR tree, which SemA then sends to the HIRTranslator, which
performs bytecode generation.
As before, SemA still performs full semantic analysis. However, not it
also produces each function's bytecode.
This split allows us to decompose potentially complex semantics into
a more fine-grained, AST-like structure, which can have very simple
code-generation logic. For example, (1.0 + 5) might look like:
HAdd(HFloat(1.0), HConvert(HInteger(5), <Float>))
As part of this decomposition, many opcodes have been removed. Rather than
using typed jumps, we now expand jumps into longer tests. For example:
jge.f <label>
becomes:
ge.f
cvt.f2b
jt <label>
This simplifies the pipeline, and JITs should be able to melt the added
work away.
HIR is not used at a statement level, and HIR does not have any concept
of control-flow.
(7) The old BytecodeCompiler has been removed, as its work is now split
between SemA and HIRTranslator.
In addition, some minor refactorings have taken place:
(1) Opcodes.tbl no longer hardcodes numbers (aaah).
(2) Type has been split into smaller, typed structs.
(3) BytecodeEmitter no longer relies on Pools or RootScopes.
(4) SemA is now responsible for variable/storage allocation.
(5) Native table are now global, rather than per-module. As such, native
declarations now result in a Native object (which still requires a
CALLNATIVE opcode), which is an index into the global table. Natives
must be bound globally. This is in preparation for module support.
(6) Publics are no longer tracked, but rather registered via a global
callback upon module load. This callback can be set by embedders. This
is in preparation for multi-file support.
(7) The BytecodeEmitter now performs Symbol allocations itself, and it
also generates Code objects itself, which removes a good deal of
complexity.
Finally, a test harness has been added. This harness is a python script which finds *.test files, recursively, in the tests folder. For each file it runs the corresponding .sp. The contents of the .test file must match stdout+stderr.
1.1 --- a/include/keima.h Mon Sep 17 00:10:01 2012 -0700
1.2 +++ b/include/keima.h Sat Nov 17 18:41:01 2012 -0800
1.3 @@ -43,6 +43,7 @@
1.4 template <typename T>
1.5 class Handle
1.6 {
1.7 + template <typename S> friend class Root;
1.8 protected:
1.9 template <typename S> void typeCheck() {
1.10 while (false) {
1.11 @@ -111,46 +112,45 @@
1.12 };
1.13
1.14 /*
1.15 - * A non-local variable that outlives HandleScopes. A Root is reference-
1.16 - * counted. When its reference count reaches 0, the Root is removed.
1.17 + * A non-local variable that outlives HandleScopes. Unlike Local, a Root
1.18 + * actually represents a rooted location. Roots must be allocated and
1.19 + * disposed, and assignment to a root changes its contained object, not
1.20 + * the location of the object.
1.21 */
1.22 template <typename T>
1.23 -class Root : public Handle<T>
1.24 +class Root
1.25 {
1.26 public:
1.27 - Root<T>()
1.28 - : Handle<T>()
1.29 + Root()
1.30 + : root_(NULL)
1.31 {
1.32 }
1.33
1.34 - Root<T>(const Root<T> &other)
1.35 - : Handle<T>(reinterpret_cast<T *>(*other))
1.36 + Root(Handle<T> other)
1.37 + : root_(NULL)
1.38 {
1.39 - incref();
1.40 + set(other);
1.41 }
1.42
1.43 - explicit Root(ke::HeapRoot *obj)
1.44 - : Handle<T>(reinterpret_cast<T *>(obj))
1.45 - {
1.46 -incref();
1.47 + inline ~Root();
1.48 +
1.49 + operator const Handle<T>() const {
1.50 + return obj_;
1.51 }
1.52
1.53 - static inline Root<T> New(Handle<T> other);
1.54 -
1.55 - ~Root() {
1.56 - decref();
1.57 + bool operator ==(Handle<T> other) {
1.58 + return Handle<T>(*this) == other;
1.59 }
1.60 -
1.61 - Root<T> &operator =(const Root<T> &other) {
1.62 - decref();
1.63 - this->obj_ = other.obj_;
1.64 - incref();
1.65 + Root<T> &operator =(Handle<T> other) {
1.66 + set(other);
1.67 return *this;
1.68 }
1.69
1.70 private:
1.71 - void incref();
1.72 - void decref();
1.73 + void set(Handle<T> other);
1.74 +
1.75 + ke::HeapRoot *root_;
1.76 + Handle<T> obj_;
1.77 };
1.78
1.79 /*
1.80 @@ -211,7 +211,8 @@
1.81 class IStackFrameIterator
1.82 {
1.83 public:
1.84 - virtual ~IStackFrameIterator() { }
1.85 + virtual ~IStackFrameIterator() {
1.86 + }
1.87
1.88 // Returns true if there are more frames, false otherwise.
1.89 virtual bool done() = 0;
1.90 @@ -232,6 +233,20 @@
1.91 virtual void prev() = 0;
1.92 };
1.93
1.94 +// Listener interface for when public functions are registered or unregisted.
1.95 +class IPublicFunctionListener
1.96 +{
1.97 + public:
1.98 + virtual ~IPublicFunctionListener() {
1.99 + }
1.100 +
1.101 + // Called when a public function becomes available to the runtime.
1.102 + virtual void registerPublic(Handle<Function> fun) = 0;
1.103 +
1.104 + // Called when a public is no longer available to the runtime.
1.105 + virtual void unregisterPublic(Handle<Function> fun) = 0;
1.106 +};
1.107 +
1.108 // A string is an immutable UTF8 buffer.
1.109 class KE_EXPORT String
1.110 {
1.111 @@ -253,21 +268,6 @@
1.112 Local<String> name();
1.113 };
1.114
1.115 -// A native is an ISourcePawnEngine-compatible function provided by C++.
1.116 -class KE_EXPORT Native
1.117 -{
1.118 - public:
1.119 - // Returns the name of a native, which is never NULL. The string is
1.120 - // guaranteed to be interned.
1.121 - Local<String> name();
1.122 -
1.123 - // Returns the function pointer of the native.
1.124 - void *function();
1.125 -
1.126 - // Sets the function pointer of the native.
1.127 - void bind(void *function);
1.128 -};
1.129 -
1.130 // A pubvar is an ISourcePawnEngine-compatible structure that holds information
1.131 // about public variables.
1.132 class KE_EXPORT Pubvar
1.133 @@ -283,21 +283,9 @@
1.134 class KE_EXPORT Module
1.135 {
1.136 public:
1.137 - // Returns publics that are based on forwards.
1.138 - unsigned numPublics();
1.139 - Local<Function> getPublic(unsigned index);
1.140 -
1.141 - // Returns natives.
1.142 - unsigned numNatives();
1.143 - Local<Native> getNative(unsigned index);
1.144 -
1.145 // Sets the native identity pointer, which is passed as the first argument
1.146 // to natives.
1.147 void setNativeIdentity(void *ptr);
1.148 -
1.149 - // Returns the number of public variables.
1.150 - unsigned numPubvars();
1.151 - Local<Pubvar> getPubvar(unsigned index);
1.152 };
1.153
1.154 class Keima
1.155 @@ -346,7 +334,23 @@
1.156 */
1.157 static void InstallMessageReporter(IMessageReporter *reporter);
1.158
1.159 + /* Returns a new stack frame iterator object. */
1.160 static IStackFrameIterator *NewStackFrameIterator();
1.161 +
1.162 + /*
1.163 + * Binds a native, by name, to an address. Natives are an ISPE1 concept
1.164 + * (originally from Pawn/Small's AMX API). In SourceMod 1, natives were
1.165 + * registered globally, but bound to plugins individually. We roughly
1.166 + * preserve that functionality here, by allowing host applications to
1.167 + * give us the name -> address mappings.
1.168 + *
1.169 + * Natives can be rebound or unbound any number of times. This function
1.170 + * fails if there is not enough memory.
1.171 + */
1.172 + static bool BindNative(const char *name, void *address);
1.173 +
1.174 + /* Sets the object that will listen for public functions. */
1.175 + static void SetPublicFunctionListener(IPublicFunctionListener *listener);
1.176 };
1.177
1.178 /*
1.179 @@ -470,38 +474,38 @@
1.180 template <typename T> friend class Root;
1.181
1.182 private:
1.183 - static ke::HeapRoot *NewHeapRoot(ke::Object **objp);
1.184 - static void IncRef(ke::HeapRoot *root);
1.185 - static void DecRef(ke::HeapRoot *root);
1.186 + static ke::HeapRoot *NewHeapRoot();
1.187 + static void Destroy(ke::HeapRoot *root);
1.188 };
1.189
1.190 -template <typename T> Root<T>
1.191 -Root<T>::New(Handle<T> other)
1.192 -{
1.193 - if (!other)
1.194 - return Root<T>();
1.195 - ke::Object **ptr = reinterpret_cast<ke::Object **>(*other);
1.196 - return Root<T>(Internals::NewHeapRoot(ptr));
1.197 -}
1.198 -
1.199 template <typename T> void
1.200 -Root<T>::incref()
1.201 +Root<T>::set(Handle<T> other)
1.202 {
1.203 - if (!*this)
1.204 + if (!other) {
1.205 + obj_ = other;
1.206 return;
1.207 - ke::HeapRoot *ptr = reinterpret_cast<ke::HeapRoot *>(**this);
1.208 - Internals::IncRef(ptr);
1.209 + }
1.210 +
1.211 + ke::Object **ptr = reinterpret_cast<ke::Object **>(*other);
1.212 + if (!root_) {
1.213 + root_ = Internals::NewHeapRoot();
1.214 + if (!root_)
1.215 + return;
1.216 + }
1.217 +
1.218 + *reinterpret_cast<ke::Object **>(root_) = *ptr;
1.219 + obj_.obj_ = reinterpret_cast<T *>(root_);
1.220 }
1.221
1.222 -template <typename T> void
1.223 -Root<T>::decref()
1.224 +template <typename T>
1.225 +Root<T>::~Root()
1.226 {
1.227 - if (!*this)
1.228 + if (!root_)
1.229 return;
1.230 - ke::HeapRoot *ptr = reinterpret_cast<ke::HeapRoot *>(**this);
1.231 - Internals::DecRef(ptr);
1.232 + Internals::Destroy(root_);
1.233 }
1.234
1.235 +
1.236 }
1.237
1.238 #endif // _include_sourcepawn2_api_h_
2.1 --- a/include/keima_util.h Mon Sep 17 00:10:01 2012 -0700
2.2 +++ b/include/keima_util.h Sat Nov 17 18:41:01 2012 -0800
2.3 @@ -1,4 +1,5 @@
2.4 -/*
2.5 +/* vim: set ts=4 sw=4 tw=99 et:
2.6 + *
2.7 * Copyright (C) 2004-2012 David Anderson
2.8 *
2.9 * This file is part of SourcePawn.
2.10 @@ -26,6 +27,23 @@
2.11 # endif
2.12 #endif
2.13
2.14 +// 64-bit detection.
2.15 +#if defined(_M_X64) || defined(__64bit__)
2.16 +# define KE_64BIT
2.17 +#endif
2.18 +
2.19 +// 32-bit detection.
2.20 +#if defined(_M_IX86) || defined(__i386__)
2.21 +# if defined KE_64BIT
2.22 +# error "Detected 32-bit and 64-bit!"
2.23 +# endif
2.24 +# define KE_32BIT
2.25 +#endif
2.26 +
2.27 +#if !defined(KE_32BIT) && !defined(KE_64BIT)
2.28 +# error "Could not detect CPU type"
2.29 +#endif
2.30 +
2.31 #if !defined(KE_EXPORT)
2.32 # define KE_EXPORT
2.33 #endif
3.1 --- a/src/API.cpp Mon Sep 17 00:10:01 2012 -0700
3.2 +++ b/src/API.cpp Sat Nov 17 18:41:01 2012 -0800
3.3 @@ -20,11 +20,7 @@
3.4 #include "../include/keima.h"
3.5 #include "Zone.h"
3.6 #include "RootScopes.h"
3.7 -#include "CompileContext.h"
3.8 -#include "Parser.h"
3.9 -#include "Scopes.h"
3.10 -#include "SemanticAnalysis.h"
3.11 -#include "BytecodeCompiler.h"
3.12 +#include "compiler/CompileContext.h"
3.13 #include "Modules.h"
3.14 #include "GlobalRoots.h"
3.15 #include "Reference.h"
3.16 @@ -32,6 +28,7 @@
3.17 #include "Interpreter.h"
3.18 #include "Stack.h"
3.19 #include "Strings.h"
3.20 +#include "NativeTable.h"
3.21 #include "Spaces-inl.h"
3.22 #include "Heap-inl.h"
3.23
3.24 @@ -94,76 +91,25 @@
3.25 return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
3.26 }
3.27
3.28 -static ke::Module *
3.29 -CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length)
3.30 -{
3.31 - Parser parser(ZONE(), cc, stream, length);
3.32 - ParseTree *tree = parser.parse();
3.33 - if (!tree)
3.34 - return NULL;
3.35 - tree->dump(stdout);
3.36 -
3.37 - if (!Scope::Bind(cc, tree))
3.38 - return NULL;
3.39 -
3.40 - SemanticAnalysis semantics(ZONE(), cc, tree);
3.41 - if (!semantics.analyze())
3.42 - return NULL;
3.43 -
3.44 - Scope::Allocate(tree);
3.45 -
3.46 - BytecodeCompiler compiler(ZONE(), tree, NULL);
3.47 - ke::Local<Module> module(ke::ZONE(), compiler.compile());
3.48 - if (!module)
3.49 - return NULL;
3.50 -
3.51 - ke::InvokeArgs args;
3.52 - if (!ke::ZONE()->stack().pushModuleFrame(module, args))
3.53 - return NULL;
3.54 - if (!ke::Interpret(ke::ZONE(), NULL, NULL))
3.55 - return NULL;
3.56 -
3.57 - return module;
3.58 -}
3.59 -
3.60 ke::Module *
3.61 InternalCompile(const char *path)
3.62 {
3.63 + PoolScope poolScope(ZONE()->pool());
3.64 RootScope roots(ZONE());
3.65 CompileContext cc(ZONE(), path);
3.66
3.67 - char *bytes = NULL;
3.68 - size_t length;
3.69 - {
3.70 - FILE *fp = fopen(path, "rb");
3.71 - if (!fp) {
3.72 - cc.reportError(SourcePosition(), Message_CantOpenFile);
3.73 - return NULL;
3.74 - }
3.75 + TranslationUnit *unit = new (ZONE()->pool()) TranslationUnit();
3.76 + unit->path_ = path;
3.77 +
3.78 + if (!cc.addTranslationUnit(unit))
3.79 + return NULL;
3.80
3.81 - if (fseek(fp, 0, SEEK_END)) {
3.82 - cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
3.83 - fclose(fp);
3.84 - return NULL;
3.85 - }
3.86 - long size = ftell(fp);
3.87 - if (size < 0) {
3.88 - cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
3.89 - fclose(fp);
3.90 - return NULL;
3.91 - }
3.92 - rewind(fp);
3.93 - length = size_t(size);
3.94 - bytes = new char[length + 1];
3.95 - if (fread(bytes, 1, length, fp) != length) {
3.96 - cc.reportError(SourcePosition(), Message_ErrorReadingFile);
3.97 - fclose(fp);
3.98 - delete [] bytes;
3.99 - return NULL;
3.100 - }
3.101 - fclose(fp);
3.102 - }
3.103 + if (!cc.compile())
3.104 + return NULL;
3.105
3.106 + return NULL;
3.107 +
3.108 +#if 0
3.109 ke::Local<ke::Module> module(ZONE(), CompileFromSource(cc, path, bytes, length));
3.110 delete [] bytes;
3.111 if (!module)
3.112 @@ -175,6 +121,8 @@
3.113
3.114 module->setPath(pathstr);
3.115 return module;
3.116 +#endif
3.117 + return NULL;
3.118 }
3.119
3.120 // This is split out from InternalCompile so the RootScope doesn't conflict
3.121 @@ -238,10 +186,9 @@
3.122 }
3.123
3.124 ke::HeapRoot *
3.125 -Ke::Internals::NewHeapRoot(ke::Object **ptr)
3.126 +Ke::Internals::NewHeapRoot()
3.127 {
3.128 - ke::Local<ke::Object> obj(ZONE(), *ptr);
3.129 - ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj);
3.130 + ke::HeapRoot *root = ke::ZONE()->globalRoots()->create();
3.131 if (!root)
3.132 return NULL;
3.133
3.134 @@ -250,15 +197,9 @@
3.135 }
3.136
3.137 void
3.138 -Ke::Internals::IncRef(ke::HeapRoot *root)
3.139 +Ke::Internals::Destroy(ke::HeapRoot *root)
3.140 {
3.141 - ZONE()->globalRoots()->incref(FromAPI(root));
3.142 -}
3.143 -
3.144 -void
3.145 -Ke::Internals::DecRef(ke::HeapRoot *root)
3.146 -{
3.147 - ZONE()->globalRoots()->decref(FromAPI(root));
3.148 + ZONE()->globalRoots()->destroy(FromAPI(root));
3.149 }
3.150
3.151 bool
3.152 @@ -280,40 +221,6 @@
3.153 ke::ZONE()->clearPendingException();
3.154 }
3.155
3.156 -unsigned
3.157 -Ke::Module::numPublics()
3.158 -{
3.159 - ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
3.160 - if (!module->publics())
3.161 - return 0;
3.162 - return module->publics()->length();
3.163 -}
3.164 -
3.165 -Ke::Local<Ke::Function>
3.166 -Ke::Module::getPublic(unsigned index)
3.167 -{
3.168 - ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
3.169 - ke::Local<ke::Function> fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index)));
3.170 - return ToLocal<ke::Function, Ke::Function>(fun);
3.171 -}
3.172 -
3.173 -unsigned
3.174 -Ke::Module::numNatives()
3.175 -{
3.176 - ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
3.177 - if (!module->natives())
3.178 - return 0;
3.179 - return module->natives()->length();
3.180 -}
3.181 -
3.182 -Ke::Local<Ke::Native>
3.183 -Ke::Module::getNative(unsigned index)
3.184 -{
3.185 - ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
3.186 - ke::Local<ke::Native> fun(ke::ZONE(), ke::Native::cast(module->natives()->at(index)));
3.187 - return ToLocal<ke::Native, Ke::Native>(fun);
3.188 -}
3.189 -
3.190 void
3.191 Ke::Module::setNativeIdentity(void *identity)
3.192 {
3.193 @@ -342,20 +249,6 @@
3.194 return ToLocal<ke::String, Ke::String>(fun->name());
3.195 }
3.196
3.197 -Ke::Local<Ke::String>
3.198 -Ke::Native::name()
3.199 -{
3.200 - ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
3.201 - return ToLocal<ke::String, Ke::String>(native->name());
3.202 -}
3.203 -
3.204 -void
3.205 -Ke::Native::bind(void *function)
3.206 -{
3.207 - ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
3.208 - native->bind(function);
3.209 -}
3.210 -
3.211 static inline const char *
3.212 GetInvokeTypeName(Ke::Parameter::Type type)
3.213 {
3.214 @@ -535,3 +428,25 @@
3.215 *retval = result.i32;
3.216 return true;
3.217 }
3.218 +
3.219 +bool
3.220 +Ke::Keima::BindNative(const char *name, void *address)
3.221 +{
3.222 + return ke::ZONE()->nativeTable()->bind(name, address);
3.223 +}
3.224 +
3.225 +void
3.226 +Ke::Keima::SetPublicFunctionListener(IPublicFunctionListener *listener)
3.227 +{
3.228 + ke::ZONE()->setPublicFunctionListener(listener);
3.229 +}
3.230 +
3.231 +void
3.232 +Zone::registerPublic(ke::Handle<Function> fun)
3.233 +{
3.234 + if (!publicFunctionListener_)
3.235 + return;
3.236 +
3.237 + Ke::Local<Ke::Function> local = ToLocal<ke::Function, Ke::Function>(fun);
3.238 + publicFunctionListener_->registerPublic(local);
3.239 +}
4.1 --- a/src/AST.h Mon Sep 17 00:10:01 2012 -0700
4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
4.3 @@ -1,1171 +0,0 @@
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_sourcepawn_ast_h_
4.23 -#define _include_sourcepawn_ast_h_
4.24 -
4.25 -#include "PoolAllocator.h"
4.26 -#include "Token.h"
4.27 -#include "NameBinding.h"
4.28 -#include "Vector.h"
4.29 -
4.30 -namespace ke {
4.31 -
4.32 -#define ASTKINDS(_) \
4.33 - _(VariableDeclaration) \
4.34 - _(ForStatement) \
4.35 - _(ReturnStatement) \
4.36 - _(IntegerLiteral) \
4.37 - _(FloatLiteral) \
4.38 - _(StringLiteral) \
4.39 - _(BinaryExpression) \
4.40 - _(BlockStatement) \
4.41 - _(Assignment) \
4.42 - _(NameProxy) \
4.43 - _(ExpressionStatement) \
4.44 - _(FunctionStatement) \
4.45 - _(CallExpression) \
4.46 - _(IfStatement) \
4.47 - _(IndexExpression) \
4.48 - _(FieldExpression) \
4.49 - _(EnumStatement) \
4.50 - _(WhileStatement) \
4.51 - _(BreakStatement) \
4.52 - _(ContinueStatement) \
4.53 - _(FunctionTypeStatement) \
4.54 - _(IncDecExpression) \
4.55 - _(UnaryExpression) \
4.56 - _(TernaryExpression) \
4.57 - _(BooleanLiteral) \
4.58 - _(StructureStatement) \
4.59 - _(SwitchStatement) \
4.60 - _(ArrayLiteral)
4.61 -
4.62 -// Forward declarations.
4.63 -#define _(name) class name;
4.64 -ASTKINDS(_)
4.65 -#undef _
4.66 -
4.67 -class AstVisitor;
4.68 -
4.69 -// Interface for AST nodes.
4.70 -class AstNode : public PoolObject
4.71 -{
4.72 - SourcePosition pos_;
4.73 -
4.74 - public:
4.75 - enum Kind {
4.76 -# define _(name) k##name,
4.77 - ASTKINDS(_)
4.78 -# undef _
4.79 - AstKind_Invalid
4.80 - };
4.81 -
4.82 - AstNode(const SourcePosition &pos)
4.83 - : pos_(pos)
4.84 - {
4.85 - }
4.86 -
4.87 - virtual Kind kind() const = 0;
4.88 -
4.89 -#define _(name) bool is##name() { return kind() == k##name; } \
4.90 - name *to##name() { assert(is##name()); return (name *)this; } \
4.91 - name *as##name() { if (!is##name()) return NULL; return to##name(); }
4.92 - ASTKINDS(_)
4.93 -#undef _
4.94 -
4.95 - virtual void accept(AstVisitor *visitor) = 0;
4.96 -
4.97 - const SourcePosition &pos() const {
4.98 - return pos_;
4.99 - }
4.100 -};
4.101 -
4.102 -class AstVisitor
4.103 -{
4.104 - public:
4.105 -#define _(name) virtual void visit(name *node) = 0;
4.106 - ASTKINDS(_)
4.107 -#undef _
4.108 -};
4.109 -
4.110 -class Statement : public AstNode
4.111 -{
4.112 - public:
4.113 - Statement(const SourcePosition &pos)
4.114 - : AstNode(pos)
4.115 - {
4.116 - }
4.117 -};
4.118 -
4.119 -class Expression : public AstNode
4.120 -{
4.121 - ScopedRoot<Type> type_;
4.122 -
4.123 - public:
4.124 - Expression(const SourcePosition &pos)
4.125 - : AstNode(pos),
4.126 - type_(NULL)
4.127 - {
4.128 - }
4.129 -
4.130 - void setType(Type *type) {
4.131 - type_ = type;
4.132 - }
4.133 - Type *type() const {
4.134 - return type_;
4.135 - }
4.136 -};
4.137 -
4.138 -typedef PoolList<Statement *> StatementList;
4.139 -typedef PoolList<Expression *> ExpressionList;
4.140 -
4.141 -class VariableDeclaration : public Statement
4.142 -{
4.143 - Variable *variable_;
4.144 - Expression *initialization_;
4.145 - ExpressionList *postDimensions_;
4.146 - BoundName *type_;
4.147 - TokenKind declarator_;
4.148 -
4.149 - public:
4.150 - VariableDeclaration(const SourcePosition &pos, TokenKind declarator, Variable *var,
4.151 - BoundName *type, ExpressionList *postDimensions,
4.152 - Expression *initialization)
4.153 - : Statement(pos),
4.154 - variable_(var),
4.155 - initialization_(initialization),
4.156 - postDimensions_(postDimensions),
4.157 - type_(type),
4.158 - declarator_(declarator)
4.159 - {
4.160 - }
4.161 -
4.162 - BoundName *type() const {
4.163 - return type_;
4.164 - }
4.165 - Kind kind() const {
4.166 - return kVariableDeclaration;
4.167 - }
4.168 - Variable *variable() const {
4.169 - return variable_;
4.170 - }
4.171 - Expression *initialization() const {
4.172 - return initialization_;
4.173 - }
4.174 - ExpressionList *postDimensions() const {
4.175 - return postDimensions_;
4.176 - }
4.177 - void accept(AstVisitor *visitor) {
4.178 - visitor->visit(this);
4.179 - }
4.180 - TokenKind declarator() const {
4.181 - return declarator_;
4.182 - }
4.183 -};
4.184 -
4.185 -class Parameter : public PoolObject
4.186 -{
4.187 - Variable *variable_;
4.188 - BoundName *type_;
4.189 - bool reference_;
4.190 - bool const_;
4.191 - ExpressionList *dimensions_;
4.192 - Expression *initializer_;
4.193 -
4.194 - public:
4.195 - Parameter(Variable *var, BoundName *type, bool reference, bool isConst,
4.196 - ExpressionList *dimensions, Expression *initializer)
4.197 - : variable_(var),
4.198 - type_(type),
4.199 - reference_(reference),
4.200 - const_(isConst),
4.201 - dimensions_(dimensions),
4.202 - initializer_(initializer)
4.203 - {
4.204 - }
4.205 -
4.206 - BoundName *type() const {
4.207 - return type_;
4.208 - }
4.209 - Variable *variable() const {
4.210 - return variable_;
4.211 - }
4.212 - bool reference() const {
4.213 - return reference_;
4.214 - }
4.215 - ExpressionList *dimensions() const {
4.216 - return dimensions_;
4.217 - }
4.218 - bool isConst() const {
4.219 - return const_;
4.220 - }
4.221 - Expression *initializer() const {
4.222 - return initializer_;
4.223 - }
4.224 -};
4.225 -
4.226 -class NameProxy : public Expression
4.227 -{
4.228 - ScopedRoot<String> name_;
4.229 - BoundName *binding_;
4.230 -
4.231 - public:
4.232 - NameProxy(const SourcePosition &pos, Handle<String> name, BoundName *binding)
4.233 - : Expression(pos),
4.234 - name_(name),
4.235 - binding_(binding)
4.236 - {
4.237 - }
4.238 -
4.239 - Kind kind() const {
4.240 - return kNameProxy;
4.241 - }
4.242 - String *name() const {
4.243 - return name_;
4.244 - }
4.245 - void accept(AstVisitor *visitor) {
4.246 - visitor->visit(this);
4.247 - }
4.248 - BoundName *binding() const {
4.249 - return binding_;
4.250 - }
4.251 - void bind(BoundName *name) {
4.252 - assert(!binding());
4.253 - binding_ = name;
4.254 - }
4.255 -};
4.256 -
4.257 -class BooleanLiteral : public Expression
4.258 -{
4.259 - TokenKind token_;
4.260 -
4.261 - public:
4.262 - BooleanLiteral(const SourcePosition &pos, TokenKind token)
4.263 - : Expression(pos),
4.264 - token_(token)
4.265 - {
4.266 - }
4.267 -
4.268 - Kind kind() const {
4.269 - return kBooleanLiteral;
4.270 - }
4.271 - TokenKind token() const {
4.272 - return token_;
4.273 - }
4.274 - void accept(AstVisitor *visitor) {
4.275 - visitor->visit(this);
4.276 - }
4.277 -};
4.278 -
4.279 -class IntegerLiteral : public Expression
4.280 -{
4.281 - int value_;
4.282 -
4.283 - public:
4.284 - IntegerLiteral(const SourcePosition &pos, int value)
4.285 - : Expression(pos),
4.286 - value_(value)
4.287 - {
4.288 - }
4.289 -
4.290 - Kind kind() const {
4.291 - return kIntegerLiteral;
4.292 - }
4.293 - int value() const {
4.294 - return value_;
4.295 - }
4.296 - void accept(AstVisitor *visitor) {
4.297 - visitor->visit(this);
4.298 - }
4.299 -};
4.300 -
4.301 -class FloatLiteral : public Expression
4.302 -{
4.303 - double value_;
4.304 -
4.305 - public:
4.306 - FloatLiteral(const SourcePosition &pos, double value)
4.307 - : Expression(pos),
4.308 - value_(value)
4.309 - {
4.310 - }
4.311 -
4.312 - Kind kind() const {
4.313 - return kFloatLiteral;
4.314 - }
4.315 - double value() const {
4.316 - return value_;
4.317 - }
4.318 - void accept(AstVisitor *visitor) {
4.319 - visitor->visit(this);
4.320 - }
4.321 -};
4.322 -
4.323 -class StringLiteral : public Expression
4.324 -{
4.325 - ScopedRoot<ByteArray> string_;
4.326 -
4.327 - public:
4.328 - StringLiteral(const SourcePosition &pos, ByteArray *array)
4.329 - : Expression(pos),
4.330 - string_(array)
4.331 - {
4.332 - }
4.333 -
4.334 - Kind kind() const {
4.335 - return kStringLiteral;
4.336 - }
4.337 - ByteArray *string() const {
4.338 - return string_;
4.339 - }
4.340 - void accept(AstVisitor *visitor) {
4.341 - visitor->visit(this);
4.342 - }
4.343 -};
4.344 -
4.345 -class ArrayLiteral : public Expression
4.346 -{
4.347 - TokenKind token_;
4.348 - ExpressionList *expressions_;
4.349 -
4.350 - public:
4.351 - ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
4.352 - : Expression(pos),
4.353 - token_(token),
4.354 - expressions_(expressions)
4.355 - {
4.356 - }
4.357 -
4.358 - Kind kind() const {
4.359 - return kArrayLiteral;
4.360 - }
4.361 - TokenKind token() const {
4.362 - return token_;
4.363 - }
4.364 - ExpressionList *expressions() const {
4.365 - return expressions_;
4.366 - }
4.367 - bool isFixed() const {
4.368 - return token_ == TOK_LBRACE;
4.369 - }
4.370 - void accept(AstVisitor *visitor) {
4.371 - visitor->visit(this);
4.372 - }
4.373 -};
4.374 -
4.375 -class UnaryExpression : public Expression
4.376 -{
4.377 - Expression *expression_;
4.378 - TokenKind token_;
4.379 - BoundName *type_;
4.380 -
4.381 - public:
4.382 - UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
4.383 - : Expression(pos),
4.384 - expression_(expr),
4.385 - token_(token)
4.386 - {
4.387 - }
4.388 -
4.389 - UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr,
4.390 - BoundName *type)
4.391 - : Expression(pos),
4.392 - expression_(expr),
4.393 - token_(token),
4.394 - type_(type)
4.395 - {
4.396 - }
4.397 -
4.398 - Kind kind() const {
4.399 - return kUnaryExpression;
4.400 - }
4.401 - Expression *expression() const {
4.402 - return expression_;
4.403 - }
4.404 - TokenKind token() const {
4.405 - return token_;
4.406 - }
4.407 - BoundName *type() const {
4.408 - return type_;
4.409 - }
4.410 - void accept(AstVisitor *visitor) {
4.411 - visitor->visit(this);
4.412 - }
4.413 -};
4.414 -
4.415 -class BinaryExpression : public Expression
4.416 -{
4.417 - Expression *left_;
4.418 - Expression *right_;
4.419 - TokenKind token_;
4.420 -
4.421 - public:
4.422 - BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
4.423 - : Expression(pos),
4.424 - left_(left),
4.425 - right_(right),
4.426 - token_(token)
4.427 - {
4.428 - }
4.429 -
4.430 - Kind kind() const {
4.431 - return kBinaryExpression;
4.432 - }
4.433 - Expression *left() const {
4.434 - return left_;
4.435 - }
4.436 - Expression *right() const {
4.437 - return right_;
4.438 - }
4.439 - TokenKind token() const {
4.440 - return token_;
4.441 - }
4.442 - void accept(AstVisitor *visitor) {
4.443 - visitor->visit(this);
4.444 - }
4.445 -};
4.446 -
4.447 -class TernaryExpression : public Expression
4.448 -{
4.449 - Expression *condition_;
4.450 - Expression *left_;
4.451 - Expression *right_;
4.452 -
4.453 - public:
4.454 - TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
4.455 - : Expression(pos),
4.456 - condition_(condition),
4.457 - left_(left),
4.458 - right_(right)
4.459 - {
4.460 - }
4.461 -
4.462 - Kind kind() const {
4.463 - return kTernaryExpression;
4.464 - }
4.465 - Expression *condition() const {
4.466 - return condition_;
4.467 - }
4.468 - Expression *left() const {
4.469 - return left_;
4.470 - }
4.471 - Expression *right() const {
4.472 - return right_;
4.473 - }
4.474 - void accept(AstVisitor *visitor) {
4.475 - visitor->visit(this);
4.476 - }
4.477 -};
4.478 -
4.479 -class IndexExpression : public Expression
4.480 -{
4.481 - Expression *left_;
4.482 - Expression *right_;
4.483 -
4.484 - public:
4.485 - IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
4.486 - : Expression(pos),
4.487 - left_(left),
4.488 - right_(right)
4.489 - {
4.490 - }
4.491 -
4.492 - Kind kind() const {
4.493 - return kIndexExpression;
4.494 - }
4.495 - Expression *left() const {
4.496 - return left_;
4.497 - }
4.498 - Expression *right() const {
4.499 - return right_;
4.500 - }
4.501 - void accept(AstVisitor *visitor) {
4.502 - visitor->visit(this);
4.503 - }
4.504 -};
4.505 -
4.506 -class FieldExpression : public Expression
4.507 -{
4.508 - Expression *left_;
4.509 - ScopedRoot<String> field_;
4.510 - unsigned fieldIndex_;
4.511 -
4.512 - public:
4.513 - FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
4.514 - : Expression(pos),
4.515 - left_(left),
4.516 - field_(field),
4.517 - fieldIndex_(unsigned(-1))
4.518 - {
4.519 - }
4.520 -
4.521 - Kind kind() const {
4.522 - return kFieldExpression;
4.523 - }
4.524 - Expression *left() const {
4.525 - return left_;
4.526 - }
4.527 - String *field() const {
4.528 - return field_;
4.529 - }
4.530 - void setFieldIndex(unsigned index) {
4.531 - assert(fieldIndex_ == unsigned(-1));
4.532 - fieldIndex_ = index;
4.533 - }
4.534 - unsigned fieldIndex() const {
4.535 - assert(fieldIndex_ != unsigned(-1));
4.536 - return fieldIndex_;
4.537 - }
4.538 - void accept(AstVisitor *visitor) {
4.539 - visitor->visit(this);
4.540 - }
4.541 -};
4.542 -
4.543 -class CallExpression : public Expression
4.544 -{
4.545 - Expression *callee_;
4.546 - ExpressionList *arguments_;
4.547 -
4.548 - public:
4.549 - CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
4.550 - : Expression(pos),
4.551 - callee_(callee),
4.552 - arguments_(arguments)
4.553 - {
4.554 - }
4.555 -
4.556 - Kind kind() const {
4.557 - return kCallExpression;
4.558 - }
4.559 - Expression *callee() const {
4.560 - return callee_;
4.561 - }
4.562 - ExpressionList *arguments() const {
4.563 - return arguments_;
4.564 - }
4.565 - void accept(AstVisitor *visitor) {
4.566 - visitor->visit(this);
4.567 - }
4.568 -};
4.569 -
4.570 -class ForStatement : public Statement
4.571 -{
4.572 - Scope *scope_;
4.573 - Statement *initialization_;
4.574 - Expression *condition_;
4.575 - Statement *update_;
4.576 - Statement *body_;
4.577 -
4.578 - public:
4.579 - ForStatement(const SourcePosition &pos, Scope *scope, Statement *initialization,
4.580 - Expression *condition, Statement *update, Statement *body)
4.581 - : Statement(pos),
4.582 - scope_(scope),
4.583 - initialization_(initialization),
4.584 - condition_(condition),
4.585 - update_(update),
4.586 - body_(body)
4.587 - {
4.588 - }
4.589 -
4.590 - Kind kind() const {
4.591 - return kForStatement;
4.592 - }
4.593 - Statement *initialization() const {
4.594 - return initialization_;
4.595 - }
4.596 - Scope *scope() const {
4.597 - return scope_;
4.598 - }
4.599 - Expression *condition() const {
4.600 - return condition_;
4.601 - }
4.602 - Statement *update() const {
4.603 - return update_;
4.604 - }
4.605 - Statement *body() const {
4.606 - return body_;
4.607 - }
4.608 - void accept(AstVisitor *visitor) {
4.609 - visitor->visit(this);
4.610 - }
4.611 -};
4.612 -
4.613 -class WhileStatement : public Statement
4.614 -{
4.615 - TokenKind token_;
4.616 - Expression *condition_;
4.617 - Statement *body_;
4.618 -
4.619 - public:
4.620 - WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
4.621 - : Statement(pos),
4.622 - token_(kind),
4.623 - condition_(condition),
4.624 - body_(body)
4.625 - {
4.626 - }
4.627 -
4.628 - Kind kind() const {
4.629 - return kWhileStatement;
4.630 - }
4.631 - TokenKind token() const {
4.632 - return token_;
4.633 - }
4.634 - Expression *condition() const {
4.635 - return condition_;
4.636 - }
4.637 - Statement *body() const {
4.638 - return body_;
4.639 - }
4.640 - void accept(AstVisitor *visitor) {
4.641 - visitor->visit(this);
4.642 - }
4.643 -};
4.644 -
4.645 -class ReturnStatement : public Statement
4.646 -{
4.647 - Expression *expression_;
4.648 -
4.649 - public:
4.650 - ReturnStatement(const SourcePosition &pos, Expression *expression)
4.651 - : Statement(pos),
4.652 - expression_(expression)
4.653 - {
4.654 - }
4.655 -
4.656 - Kind kind() const {
4.657 - return kReturnStatement;
4.658 - }
4.659 - Expression *expression() const {
4.660 - return expression_;
4.661 - }
4.662 - void accept(AstVisitor *visitor) {
4.663 - visitor->visit(this);
4.664 - }
4.665 -};
4.666 -
4.667 -class BreakStatement : public Statement
4.668 -{
4.669 - public:
4.670 - BreakStatement(const SourcePosition &pos)
4.671 - : Statement(pos)
4.672 - {
4.673 - }
4.674 -
4.675 - Kind kind() const {
4.676 - return kBreakStatement;
4.677 - }
4.678 - void accept(AstVisitor *visitor) {
4.679 - visitor->visit(this);
4.680 - }
4.681 -};
4.682 -
4.683 -class ContinueStatement : public Statement
4.684 -{
4.685 - public:
4.686 - ContinueStatement(const SourcePosition &pos)
4.687 - : Statement(pos)
4.688 - {
4.689 - }
4.690 -
4.691 - Kind kind() const {
4.692 - return kContinueStatement;
4.693 - }
4.694 - void accept(AstVisitor *visitor) {
4.695 - visitor->visit(this);
4.696 - }
4.697 -};
4.698 -
4.699 -class Assignment : public Expression
4.700 -{
4.701 - TokenKind token_;
4.702 - Expression *lvalue_;
4.703 - Expression *expression_;
4.704 -
4.705 - public:
4.706 - Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
4.707 - : Expression(pos),
4.708 - token_(token),
4.709 - lvalue_(left),
4.710 - expression_(right)
4.711 - {
4.712 - }
4.713 -
4.714 - Kind kind() const {
4.715 - return kAssignment;
4.716 - }
4.717 - TokenKind token() const {
4.718 - return token_;
4.719 - }
4.720 - Expression *lvalue() const {
4.721 - return lvalue_;
4.722 - }
4.723 - Expression *expression() const {
4.724 - return expression_;
4.725 - }
4.726 - void accept(AstVisitor *visitor) {
4.727 - visitor->visit(this);
4.728 - }
4.729 -};
4.730 -
4.731 -class ExpressionStatement : public Statement
4.732 -{
4.733 - Expression *expression_;
4.734 -
4.735 - public:
4.736 - ExpressionStatement(Expression *expression)
4.737 - : Statement(expression->pos()),
4.738 - expression_(expression)
4.739 - {
4.740 - }
4.741 -
4.742 - Kind kind() const {
4.743 - return kExpressionStatement;
4.744 - }
4.745 - Expression *expression() const {
4.746 - return expression_;
4.747 - }
4.748 - void accept(AstVisitor *visitor) {
4.749 - visitor->visit(this);
4.750 - }
4.751 -};
4.752 -
4.753 -class BlockStatement : public Statement
4.754 -{
4.755 - Scope *scope_;
4.756 - StatementList *statements_;
4.757 -
4.758 - public:
4.759 - BlockStatement(const SourcePosition &pos, Scope *scope, StatementList *statements)
4.760 - : Statement(pos),
4.761 - scope_(scope),
4.762 - statements_(statements)
4.763 - {
4.764 - }
4.765 -
4.766 - Kind kind() const {
4.767 - return kBlockStatement;
4.768 - }
4.769 - Scope *scope() const {
4.770 - return scope_;
4.771 - }
4.772 - StatementList *statements() const {
4.773 - return statements_;
4.774 - }
4.775 - void accept(AstVisitor *visitor) {
4.776 - visitor->visit(this);
4.777 - }
4.778 -};
4.779 -
4.780 -typedef PoolList<Parameter *> ParameterList;
4.781 -
4.782 -class FunctionSignature
4.783 -{
4.784 - public:
4.785 - FunctionSignature(BoundName *returnType, ExpressionList *returnDimensions, ParameterList *parameters)
4.786 - : returnType_(returnType),
4.787 - returnDimensions_(returnDimensions),
4.788 - parameters_(parameters)
4.789 - {
4.790 - }
4.791 -
4.792 - BoundName *returnType() const {
4.793 - return returnType_;
4.794 - }
4.795 - ExpressionList *returnDimensions() const {
4.796 - return returnDimensions_;
4.797 - }
4.798 - ParameterList *parameters() const {
4.799 - return parameters_;
4.800 - }
4.801 -
4.802 - private:
4.803 - BoundName *returnType_;
4.804 - ExpressionList *returnDimensions_;
4.805 - ParameterList *parameters_;
4.806 -};
4.807 -
4.808 -class FunctionTypeStatement : public Statement
4.809 -{
4.810 - public:
4.811 - FunctionTypeStatement(const SourcePosition &pos, NamedType *type, const FunctionSignature &signature)
4.812 - : Statement(pos),
4.813 - type_(type),
4.814 - signature_(signature)
4.815 - {
4.816 - }
4.817 -
4.818 - Kind kind() const {
4.819 - return kFunctionTypeStatement;
4.820 - }
4.821 - NamedType *decl() const {
4.822 - return type_;
4.823 - }
4.824 - const FunctionSignature &signature() const {
4.825 - return signature_;
4.826 - }
4.827 - void accept(AstVisitor *visitor) {
4.828 - visitor->visit(this);
4.829 - }
4.830 -
4.831 - private:
4.832 - NamedType *type_;
4.833 - FunctionSignature signature_;
4.834 -};
4.835 -
4.836 -class FunctionStatement : public Statement
4.837 -{
4.838 - Scope *scope_;
4.839 - NamedFunction *fun_;
4.840 - Statement *body_;
4.841 - FunctionSignature signature_;
4.842 - bool explicitReturn_;
4.843 -
4.844 - public:
4.845 - FunctionStatement(const SourcePosition &pos, Scope *scope, NamedFunction *fun, Statement *body,
4.846 - const FunctionSignature &signature, bool explicitReturn)
4.847 - : Statement(pos),
4.848 - scope_(scope),
4.849 - fun_(fun),
4.850 - body_(body),
4.851 - signature_(signature),
4.852 - explicitReturn_(explicitReturn)
4.853 - {
4.854 - }
4.855 -
4.856 - Kind kind() const {
4.857 - return kFunctionStatement;
4.858 - }
4.859 - Scope *scope() const {
4.860 - return scope_;
4.861 - }
4.862 - NamedFunction *fun() const {
4.863 - return fun_;
4.864 - }
4.865 - Statement *body() const {
4.866 - return body_;
4.867 - }
4.868 - const FunctionSignature &signature() {
4.869 - return signature_;
4.870 - }
4.871 - void accept(AstVisitor *visitor) {
4.872 - visitor->visit(this);
4.873 - }
4.874 - bool hasExplicitReturn() const {
4.875 - return explicitReturn_;
4.876 - }
4.877 -};
4.878 -
4.879 -class IfStatement : public Statement
4.880 -{
4.881 - Expression *condition_;
4.882 - Statement *ifTrue_;
4.883 - Statement *ifFalse_;
4.884 -
4.885 - public:
4.886 - IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
4.887 - : Statement(pos),
4.888 - condition_(condition),
4.889 - ifTrue_(ifTrue),
4.890 - ifFalse_(NULL)
4.891 - {
4.892 - }
4.893 -
4.894 - Kind kind() const {
4.895 - return kIfStatement;
4.896 - }
4.897 - Expression *condition() const {
4.898 - return condition_;
4.899 - }
4.900 - Statement *ifTrue() const {
4.901 - return ifTrue_;
4.902 - }
4.903 - Statement *ifFalse() const {
4.904 - return ifFalse_;
4.905 - }
4.906 - void setIfFalse(Statement *ifFalse) {
4.907 - ifFalse_ = ifFalse;
4.908 - }
4.909 - void accept(AstVisitor *visitor) {
4.910 - visitor->visit(this);
4.911 - }
4.912 -};
4.913 -
4.914 -class EnumStatement : public Statement
4.915 -{
4.916 - ScopedRoot<String> name_;
4.917 - NamedType *type_;
4.918 -
4.919 - public:
4.920 - struct Entry {
4.921 - NamedConstant *name;
4.922 - Expression *expr;
4.923 -
4.924 - Entry(NamedConstant *name, Expression *expr)
4.925 - : name(name),
4.926 - expr(expr)
4.927 - {
4.928 - }
4.929 - };
4.930 -
4.931 - typedef PoolList<Entry> EntryList;
4.932 -
4.933 - public:
4.934 - EnumStatement(const SourcePosition &pos, NamedType *type, Handle<String> name, EntryList *entries)
4.935 - : Statement(pos),
4.936 - name_(name),
4.937 - type_(type),
4.938 - entries_(entries)
4.939 - {
4.940 - }
4.941 -
4.942 - Kind kind() const {
4.943 - return kEnumStatement;
4.944 - }
4.945 - String *name() const {
4.946 - return name_;
4.947 - }
4.948 - EntryList *entries() const {
4.949 - return entries_;
4.950 - }
4.951 - NamedType *decl() const {
4.952 - return type_;
4.953 - }
4.954 - void accept(AstVisitor *visitor) {
4.955 - visitor->visit(this);
4.956 - }
4.957 -
4.958 - private:
4.959 - EntryList *entries_;
4.960 -};
4.961 -
4.962 -class IncDecExpression : public Expression
4.963 -{
4.964 - TokenKind token_;
4.965 - Expression *expression_;
4.966 - bool postfix_;
4.967 -
4.968 - public:
4.969 - IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
4.970 - : Expression(pos),
4.971 - token_(token),
4.972 - expression_(expression),
4.973 - postfix_(postfix)
4.974 - {
4.975 - }
4.976 -
4.977 - Kind kind() const {
4.978 - return kIncDecExpression;
4.979 - }
4.980 - TokenKind token() const {
4.981 - return token_;
4.982 - }
4.983 - Expression *expression() const {
4.984 - return expression_;
4.985 - }
4.986 - bool postfix() const {
4.987 - return postfix_;
4.988 - }
4.989 - void accept(AstVisitor *visitor) {
4.990 - visitor->visit(this);
4.991 - }
4.992 -};
4.993 -
4.994 -class Case : public PoolObject
4.995 -{
4.996 - public:
4.997 - Case(Expression *expression, ExpressionList *others, Statement *statement)
4.998 - : expression_(expression),
4.999 - others_(others),
4.1000 - statement_(statement)
4.1001 - {
4.1002 - }
4.1003 -
4.1004 - Expression *expression() const {
4.1005 - return expression_;
4.1006 - }
4.1007 - PoolList<Expression *> *others() const {
4.1008 - return others_;
4.1009 - }
4.1010 - Statement *statement() const {
4.1011 - return statement_;
4.1012 - }
4.1013 -
4.1014 - private:
4.1015 - Expression *expression_;
4.1016 - PoolList <Expression *> *others_;
4.1017 - Statement *statement_;
4.1018 -};
4.1019 -
4.1020 -struct CaseValue
4.1021 -{
4.1022 - BoxedPrimitive box;
4.1023 - size_t statement;
4.1024 -
4.1025 - CaseValue(size_t statement)
4.1026 - : statement(statement)
4.1027 - {
4.1028 - }
4.1029 -};
4.1030 -
4.1031 -typedef PoolList<CaseValue> CaseValueList;
4.1032 -
4.1033 -class SwitchStatement : public Statement
4.1034 -{
4.1035 - public:
4.1036 - SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
4.1037 - Statement *def)
4.1038 - : Statement(pos),
4.1039 - expression_(expression),
4.1040 - cases_(cases),
4.1041 - default_(def),
4.1042 - table_(NULL)
4.1043 - {
4.1044 - }
4.1045 -
4.1046 - Kind kind() const {
4.1047 - return kSwitchStatement;
4.1048 - }
4.1049 - Expression *expression() const {
4.1050 - return expression_;
4.1051 - }
4.1052 - PoolList<Case *> *cases() const {
4.1053 - return cases_;
4.1054 - }
4.1055 - Statement *defaultCase() const {
4.1056 - return default_;
4.1057 - }
4.1058 - void setCaseValueList(CaseValueList *list) {
4.1059 - table_ = list;
4.1060 - }
4.1061 - CaseValueList *caseValueList() const {
4.1062 - return table_;
4.1063 - }
4.1064 - void accept(AstVisitor *visitor) {
4.1065 - visitor->visit(this);
4.1066 - }
4.1067 -
4.1068 - private:
4.1069 - Expression *expression_;
4.1070 - PoolList<Case *> *cases_;
4.1071 - Statement *default_;
4.1072 - CaseValueList *table_;
4.1073 -};
4.1074 -
4.1075 -class StructureStatement : public Statement
4.1076 -{
4.1077 - public:
4.1078 - class Field : public PoolObject
4.1079 - {
4.1080 - SourcePosition pos_;
4.1081 - BoundName *type_;
4.1082 - ScopedRoot<String> name_;
4.1083 - ExpressionList *dimensions_;
4.1084 -
4.1085 - public:
4.1086 - Field(const SourcePosition &pos,
4.1087 - BoundName *type,
4.1088 - Handle<String> name,
4.1089 - ExpressionList *dimensions)
4.1090 - : pos_(pos),
4.1091 - type_(type),
4.1092 - name_(name),
4.1093 - dimensions_(dimensions)
4.1094 - {
4.1095 - }
4.1096 -
4.1097 - const SourcePosition &pos() const {
4.1098 - return pos_;
4.1099 - }
4.1100 - BoundName *type() const {
4.1101 - return type_;
4.1102 - }
4.1103 - String *name() const {
4.1104 - return name_;
4.1105 - }
4.1106 - ExpressionList *dimensions() const {
4.1107 - return dimensions_;
4.1108 - }
4.1109 - };
4.1110 -
4.1111 - typedef PoolList<StructureStatement::Field *> FieldList;
4.1112 -
4.1113 - public:
4.1114 - StructureStatement(const SourcePosition &pos, NamedType *decl, FieldList *fields)
4.1115 - : Statement(pos),
4.1116 - decl_(decl),
4.1117 - fields_(fields)
4.1118 - {
4.1119 - }
4.1120 -
4.1121 - Kind kind() const {
4.1122 - return kStructureStatement;
4.1123 - }
4.1124 - FieldList *fields() const {
4.1125 - return fields_;
4.1126 - }
4.1127 - NamedType *decl() const {
4.1128 - return decl_;
4.1129 - }
4.1130 - void accept(AstVisitor *visitor) {
4.1131 - visitor->visit(this);
4.1132 - }
4.1133 -
4.1134 - private:
4.1135 - NamedType *decl_;
4.1136 - FieldList *fields_;
4.1137 -};
4.1138 -
4.1139 -typedef StructureStatement::FieldList FieldList;
4.1140 -
4.1141 -class Scope;
4.1142 -
4.1143 -typedef PoolList<NameProxy *> NameProxyList;
4.1144 -
4.1145 -class ParseTree : public PoolObject
4.1146 -{
4.1147 - StatementList *statements_;
4.1148 - Scope *scope_;
4.1149 - NameProxyList *unbound_;
4.1150 -
4.1151 - public:
4.1152 - ParseTree(Scope *scope, StatementList *statements, NameProxyList *unbound)
4.1153 - : statements_(statements),
4.1154 - scope_(scope),
4.1155 - unbound_(unbound)
4.1156 - {
4.1157 - }
4.1158 -
4.1159 - void dump(FILE *fp);
4.1160 -
4.1161 - StatementList *statements() const {
4.1162 - return statements_;
4.1163 - }
4.1164 - Scope *scope() const {
4.1165 - return scope_;
4.1166 - }
4.1167 - NameProxyList *unbound() const {
4.1168 - return unbound_;
4.1169 - }
4.1170 -};
4.1171 -
4.1172 -}
4.1173 -
4.1174 -#endif // _include_sourcepawn_ast_h_
5.1 --- a/src/BytecodeCompiler.cpp Mon Sep 17 00:10:01 2012 -0700
5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
5.3 @@ -1,1576 +0,0 @@
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 -#include <string.h>
5.23 -#include "BytecodeCompiler.h"
5.24 -#include "Scopes.h"
5.25 -#include "Modules.h"
5.26 -#include "Types.h"
5.27 -#include "Array.h"
5.28 -#include "Strings.h"
5.29 -#include "Zone.h"
5.30 -#include "Environments.h"
5.31 -#include "Box.h"
5.32 -#include "Heap-inl.h"
5.33 -
5.34 -using namespace ke;
5.35 -
5.36 -typedef BytecodeEmitter::Label Label;
5.37 -
5.38 -#define __ emitter_.
5.39 -
5.40 -BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
5.41 - : zone_(zone),
5.42 - tree_(tree),
5.43 - emitter_(zone->pool()),
5.44 - locals_(NULL),
5.45 - scope_(NULL),
5.46 - moduleData_(module),
5.47 - loop_(NULL)
5.48 -{
5.49 -}
5.50 -
5.51 -static inline TokenKind
5.52 -ToCompare(Expression *expr)
5.53 -{
5.54 - if (expr->isBinaryExpression()) {
5.55 - BinaryExpression *b = expr->toBinaryExpression();
5.56 - if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
5.57 - return b->token();
5.58 - } else if (expr->isUnaryExpression()) {
5.59 - UnaryExpression *u = expr->toUnaryExpression();
5.60 - if (u->token() == TOK_NOT)
5.61 - return TOK_NOT;
5.62 - }
5.63 - return TOK_EOF;
5.64 -}
5.65 -
5.66 -static inline Opcode
5.67 -CompareTokenToJump(TokenKind kind)
5.68 -{
5.69 - switch (kind) {
5.70 - case TOK_EQUALS:
5.71 - return OP_JEQ;
5.72 - case TOK_NOTEQUALS:
5.73 - return OP_JNE;
5.74 - case TOK_GT:
5.75 - return OP_JG;
5.76 - case TOK_GE:
5.77 - return OP_JGE;
5.78 - case TOK_LT:
5.79 - return OP_JL;
5.80 - default:
5.81 - assert(kind == TOK_LE);
5.82 - return OP_JLE;
5.83 - }
5.84 -}
5.85 -
5.86 -static inline Opcode
5.87 -TokenToOpcode(TokenKind kind)
5.88 -{
5.89 - switch (kind) {
5.90 - case TOK_PLUS:
5.91 - return OP_ADD;
5.92 - case TOK_MINUS:
5.93 - return OP_SUB;
5.94 - case TOK_STAR:
5.95 - return OP_MUL;
5.96 - case TOK_SLASH:
5.97 - return OP_DIV;
5.98 - case TOK_PERCENT:
5.99 - return OP_MOD;
5.100 - case TOK_SHR:
5.101 - return OP_SHR;
5.102 - case TOK_USHR:
5.103 - return OP_USHR;
5.104 - case TOK_SHL:
5.105 - return OP_SHL;
5.106 - case TOK_BITAND:
5.107 - return OP_BITAND;
5.108 - case TOK_BITOR:
5.109 - return OP_BITOR;
5.110 - case TOK_GT:
5.111 - return OP_GT;
5.112 - case TOK_GE:
5.113 - return OP_GE;
5.114 - case TOK_LT:
5.115 - return OP_LT;
5.116 - case TOK_LE:
5.117 - return OP_LE;
5.118 - case TOK_EQUALS:
5.119 - return OP_EQ;
5.120 - case TOK_NOTEQUALS:
5.121 - return OP_NE;
5.122 - default:
5.123 - assert(kind == TOK_BITXOR);
5.124 - return OP_BITXOR;
5.125 - }
5.126 -}
5.127 -
5.128 -void
5.129 -BytecodeCompiler::recordLifoSlot(Scope *scope)
5.130 -{
5.131 - if (!scope)
5.132 - return;
5.133 -
5.134 - if (Variable *var = scope->lifoSlot()) {
5.135 - locals_->set(zone_, var->slot(), var->type());
5.136 - __ savelifo(var->slot());
5.137 - }
5.138 -}
5.139 -
5.140 -void
5.141 -BytecodeCompiler::unwindTo(Scope *scope)
5.142 -{
5.143 - // Note: we only need to unwind to the outermost scope's LIFO slot.
5.144 - Variable *var = NULL;
5.145 - for (Scope *current = scope_; current != scope; current = current->enclosing()) {
5.146 - if (Variable *slot = current->lifoSlot())
5.147 - var = slot;
5.148 - }
5.149 -
5.150 - if (var)
5.151 - __ unwindlifo(var->slot());
5.152 -}
5.153 -
5.154 -void
5.155 -BytecodeCompiler::visit(NameProxy *name)
5.156 -{
5.157 - switch (name->binding()->kind()) {
5.158 - case BoundName::VARIABLE:
5.159 - {
5.160 - Variable *var = name->binding()->toVariable();
5.161 -
5.162 - if (var->location() == Variable::STACK) {
5.163 - __ getlocal(var);
5.164 - assert(!name->type()->isReference());
5.165 - } else if (var->location() == Variable::ENVIRONMENT) {
5.166 - getEnvSlot(var);
5.167 - } else {
5.168 - assert(var->location() == Variable::PARAMETER);
5.169 - __ getarg(var);
5.170 -
5.171 - // If this argument is actually a reference, dereference it now.
5.172 - if (var->type()->isReference())
5.173 - __ getref(var->type()->contained());
5.174 - }
5.175 - break;
5.176 - }
5.177 -
5.178 - case BoundName::FUNCTION:
5.179 - {
5.180 - NamedFunction *fun = name->binding()->toNamedFunction();
5.181 - __ module();
5.182 - __ getmodule_fn(fun->slot());
5.183 - break;
5.184 - }
5.185 -
5.186 - default:
5.187 - {
5.188 - NamedConstant *constant = name->binding()->toNamedConstant();
5.189 - __ int_(constant->value().toInt());
5.190 - break;
5.191 - }
5.192 - }
5.193 -}
5.194 -
5.195 -void
5.196 -BytecodeCompiler::visit(ExpressionStatement *node)
5.197 -{
5.198 - // Expressions leave their value on the top of the stack, so we make sure
5.199 - // to balance the stack if they're used as a statement.
5.200 - node->expression()->accept(this);
5.201 - if (!node->expression()->type()->isVoid())
5.202 - __ pop();
5.203 -}
5.204 -
5.205 -static inline bool
5.206 -IsCompositeValueType(Type *type)
5.207 -{
5.208 - return type->isStruct() ||
5.209 - (type->isArray() && type->isFixedLength());
5.210 -}
5.211 -
5.212 -static inline Array *
5.213 -StringLiteralToArray(Zone *zone, StringLiteral *node)
5.214 -{
5.215 - Local<Type> type(zone, node->type());
5.216 - Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
5.217 - if (!map)
5.218 - return NULL;
5.219 -
5.220 - return Array::NewString(zone,
5.221 - map,
5.222 - node->string()->raw(),
5.223 - node->string()->length(),
5.224 - Heap::Tenure_Old);
5.225 -}
5.226 -
5.227 -void
5.228 -BytecodeCompiler::visit(Assignment *node)
5.229 -{
5.230 - Local<Type> left(zone_, node->type());
5.231 - Local<Type> right(zone_, node->expression()->type());
5.232 -
5.233 - // The first step is three sub-steps:
5.234 - //
5.235 - // (1) Bind the left-hand side.
5.236 - // -- If a cumulative operation (+=, etc):
5.237 - // (2) Save a copy of the binding on the stack.
5.238 - // (3) Dereference the binding to get a value.
5.239 - //
5.240 - if (node->lvalue()->isNameProxy()) {
5.241 - NameProxy *proxy = node->lvalue()->toNameProxy();
5.242 - Variable *var = proxy->binding()->toVariable();
5.243 -
5.244 - // We need to fetch the variable under the following circumstances:
5.245 - // (1) The variable is a reference, since we'll store into the ref.
5.246 - // (2) The variable is a fixed array, since we need to copy into it.
5.247 - // (3) The variable is a struct, since we need to copy into it.
5.248 - if (var->type()->isReference() || IsCompositeValueType(var->type()))
5.249 - __ get(var);
5.250 -
5.251 - // Get the value if needed.
5.252 - if (node->token() != TOK_ASSIGN) {
5.253 - // += etc is not allowed on arrays.
5.254 - assert(!var->type()->isArray());
5.255 -
5.256 - if (var->location() == Variable::ENVIRONMENT)
5.257 - getEnvSlot(var);
5.258 -
5.259 - if (var->type()->isReference()) {
5.260 - __ dup();
5.261 - __ getref(var->type()->contained());
5.262 - } else if (var->location() != Variable::ENVIRONMENT) {
5.263 - __ get(var);
5.264 - }
5.265 - }
5.266 - } else if (node->lvalue()->isFieldExpression()) {
5.267 - FieldExpression *expr = node->lvalue()->toFieldExpression();
5.268 - __ note_position(expr->pos());
5.269 -
5.270 - expr->left()->accept(this);
5.271 -
5.272 - if (node->token() != TOK_ASSIGN)
5.273 - __ dup();
5.274 -
5.275 - if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
5.276 - __ getfield(expr->fieldIndex(), left);
5.277 - } else {
5.278 - IndexExpression *index = node->lvalue()->toIndexExpression();
5.279 - __ note_position(index->pos());
5.280 -
5.281 - index->left()->accept(this);
5.282 - index->right()->accept(this);
5.283 -
5.284 - if (node->token() != TOK_ASSIGN)
5.285 - __ dup2();
5.286 -
5.287 - if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
5.288 - __ getelem(left);
5.289 - }
5.290 -
5.291 - if (node->token() == TOK_ASSIGN) {
5.292 - // Special case: if the left-hand side is a string literal, we must
5.293 - // spawn a new copy (:TODO: something about const?)
5.294 - if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
5.295 - Local<Array> string(zone_,
5.296 - StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
5.297 - if (!string)
5.298 - return;
5.299 -
5.300 - Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
5.301 - __ note_position(node->expression()->pos());
5.302 - __ int_(string->length());
5.303 - __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
5.304 - __ object(string);
5.305 - __ copyarray();
5.306 - } else {
5.307 - node->expression()->accept(this);
5.308 - }
5.309 - } else {
5.310 - visitForALU(left, node->expression());
5.311 -
5.312 - TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
5.313 - __ note_position(node->pos());
5.314 - __ binary(TokenToOpcode(alu));
5.315 - }
5.316 -
5.317 - // Emit the store.
5.318 - if (left->isArray() && left->isFixedLength()) {
5.319 - // (x = y) returns the left-hand side; if |x| is a fixed-length array,
5.320 - // then |y| is as well, and we perform a deep copy.
5.321 - assert(right->isFixedLength());
5.322 - __ note_position(node->pos());
5.323 - __ copyarray();
5.324 - } else if (left->isStruct()) {
5.325 - // Structs have value semantics, so emit a full copy. We don't break
5.326 - // this down into u-ops, to avoid unnecessary bytecode explosion.
5.327 - assert(right->isStruct());
5.328 - __ note_position(node->pos());
5.329 - __ copystruct();
5.330 - } else if (node->lvalue()->isNameProxy()) {
5.331 - NameProxy *proxy = node->lvalue()->toNameProxy();
5.332 - Variable *var = proxy->binding()->toVariable();
5.333 -
5.334 - if (var->type()->isReference())
5.335 - __ setref(var->type()->contained());
5.336 - else if (var->location() == Variable::ENVIRONMENT)
5.337 - setEnvSlot(var);
5.338 - else
5.339 - __ set(var);
5.340 - } else if (node->lvalue()->isFieldExpression()) {
5.341 - FieldExpression *expr = node->lvalue()->toFieldExpression();
5.342 - __ setfield(expr->fieldIndex(), left);
5.343 - } else {
5.344 - __ setelem(left);
5.345 - }
5.346 -}
5.347 -
5.348 -void
5.349 -BytecodeCompiler::visit(IncDecExpression *node)
5.350 -{
5.351 - // In the postfix case, the logic looks like:
5.352 - // (1) Bind -> REF
5.353 - // (2) Dup -> REF REF
5.354 - // (3) Fetch -> REF VAL
5.355 - // (4) Swap -> VAL REF
5.356 - // (5) Pick -> VAL REF VAL
5.357 - // (6) Add -> VAL REF VAL+1
5.358 - // (7) Store -> VAL VAL+1
5.359 - // (8) Drop -> VAL
5.360 - //
5.361 - // In the prefix case, the logic looks like:
5.362 - // (1) Bind -> REF
5.363 - // (2) Dup -> REF REF
5.364 - // (3) Fetch -> REF VAL
5.365 - // --
5.366 - // --
5.367 - // (6) Add -> REF VAL+1
5.368 - // (7) Store -> VAL+1
5.369 - // --
5.370 - //
5.371 - // This is squirrely enough such that we don't bother sharing too much
5.372 - // with the above.
5.373 - //
5.374 - // Note: We simulate a "Pick" operation with a dup2+pop.
5.375 -
5.376 - // This is steps (1) to (5).
5.377 - Expression *expr = node->expression();
5.378 - if (expr->isNameProxy()) {
5.379 - NameProxy *proxy = expr->toNameProxy();
5.380 - Variable *var = proxy->binding()->toVariable();
5.381 -
5.382 - // Bind.
5.383 - if (var->location() == Variable::ENVIRONMENT)
5.384 - getEnvSlot(var);
5.385 - else if (var->type()->isReference() || var->type()->isArray())
5.386 - __ get(var);
5.387 -
5.388 - // Dup and fetch.
5.389 - if (var->type()->isReference()) {
5.390 - __ dup();
5.391 - __ getref(node->type());
5.392 - if (node->postfix()) {
5.393 - __ swap();
5.394 - __ pick2();
5.395 - }
5.396 - } else {
5.397 - assert(!var->type()->isArray());
5.398 - if (var->location() != Variable::ENVIRONMENT)
5.399 - __ get(var);
5.400 - if (node->postfix())
5.401 - __ dup();
5.402 - }
5.403 - } else if (expr->isFieldExpression()) {
5.404 - FieldExpression *field = expr->toFieldExpression();
5.405 -
5.406 - field->left()->accept(this);
5.407 - __ dup();
5.408 - __ getfield(field->fieldIndex(), field->type());
5.409 -
5.410 - if (node->postfix()) {
5.411 - // The stack looks like this now:
5.412 - // OBJECT VALUE
5.413 - __ swap(); // VALUE OBJECT
5.414 - __ pick2(); // VALUE OBJECT VALUE
5.415 - }
5.416 - } else {
5.417 - IndexExpression *index = expr->toIndexExpression();
5.418 - __ note_position(index->pos());
5.419 -
5.420 - index->left()->accept(this);
5.421 - index->right()->accept(this);
5.422 -
5.423 - assert(!node->type()->isArray());
5.424 - __ dup2();
5.425 - __ getelem(node->type());
5.426 -
5.427 - if (node->postfix()) {
5.428 - // The stack looks like this now:
5.429 - // ARRAY INDEX VALUE
5.430 - //
5.431 - // So we must use a PICK operation to rotate the stack into position.
5.432 - __ roll3(); // INDEX VALUE ARRAY
5.433 - __ roll3(); // VALUE ARRAY INDEX
5.434 - __ pick3(); // VALUE ARRAY INDEX VALUE
5.435 - }
5.436 - }
5.437 -
5.438 - // Perform step (6).
5.439 - if (node->type()->isFloat()) {
5.440 - __ float_(1.0);
5.441 - } else {
5.442 - assert(node->type()->isInt32());
5.443 - __ int_(1);
5.444 - }
5.445 -
5.446 - __ note_position(node->pos());
5.447 - if (node->token() == TOK_INCREMENT)
5.448 - __ binary(OP_ADD);
5.449 - else
5.450 - __ binary(OP_SUB);
5.451 -
5.452 - // Perform step (7).
5.453 - if (expr->isNameProxy()) {
5.454 - NameProxy *proxy = expr->toNameProxy();
5.455 - Variable *var = proxy->binding()->toVariable();
5.456 -
5.457 - if (var->type()->isReference())
5.458 - __ setref(node->type());
5.459 - else if (var->location() == Variable::ENVIRONMENT)
5.460 - setEnvSlot(var);
5.461 - else
5.462 - __ set(var);
5.463 - } else if (expr->isFieldExpression()) {
5.464 - FieldExpression *field = expr->toFieldExpression();
5.465 - __ setfield(field->fieldIndex(), field->type());
5.466 - } else {
5.467 - assert(expr->isIndexExpression());
5.468 - __ setelem(node->type());
5.469 - }
5.470 -
5.471 - // Perform step (8).
5.472 - if (node->postfix())
5.473 - __ pop();
5.474 -}
5.475 -
5.476 -void
5.477 -BytecodeCompiler::visitForALU(Type *needed, Expression *node)
5.478 -{
5.479 - node->accept(this);
5.480 - if (needed->isFloat() && !node->type()->isFloat())
5.481 - __ cvt_i2f();
5.482 - else
5.483 - assert(needed->primitive() == node->type()->primitive());
5.484 -}
5.485 -
5.486 -static inline Type *
5.487 -GetCoercionType(TokenKind tok, Type *left, Type *right)
5.488 -{
5.489 - if (left->isFloat())
5.490 - return left;
5.491 - return right;
5.492 -}
5.493 -
5.494 -void
5.495 -BytecodeCompiler::visit(UnaryExpression *node)
5.496 -{
5.497 - Local<Type> out(zone_, ((Expression *)node)->type());
5.498 -
5.499 - switch (node->token()) {
5.500 - case TOK_MINUS:
5.501 - {
5.502 - Local<Type> type(zone_, node->expression()->type());
5.503 - node->expression()->accept(this);
5.504 -
5.505 - if (out->isFloat())
5.506 - __ neg_f();
5.507 - else
5.508 - __ neg();
5.509 - break;
5.510 - }
5.511 -
5.512 - case TOK_NOT:
5.513 - {
5.514 - Local<Type> type(zone_, node->expression()->type());
5.515 - node->expression()->accept(this);
5.516 -
5.517 - if (out->isFloat())
5.518 - __ not_f();
5.519 - else
5.520 - __ not_();
5.521 - break;
5.522 - }
5.523 -
5.524 - case TOK_LABEL:
5.525 - {
5.526 - Local<Type> from(zone_, node->expression()->type());
5.527 -
5.528 - node->expression()->accept(this);
5.529 - if (!from->isFloat() && out->isFloat())
5.530 - __ bits_f2i();
5.531 - else if (from->isFloat() && !out->isFloat())
5.532 - __ bits_i2f();
5.533 - break;
5.534 - }
5.535 -
5.536 - case TOK_SIZEOF:
5.537 - {
5.538 - Local<Type> type(zone_, node->expression()->type());
5.539 - if (type->isFixedLength()) {
5.540 - __ int_(type->fixedLength());
5.541 - } else {
5.542 - node->expression()->accept(this);
5.543 - __ sizeof_();
5.544 - }
5.545 - break;
5.546 - }
5.547 -
5.548 - default:
5.549 - assert(node->token() == TOK_TILDE);
5.550 - node->expression()->accept(this);
5.551 - __ bitnot();
5.552 - break;
5.553 - }
5.554 -}
5.555 -
5.556 -void
5.557 -BytecodeCompiler::visit(BinaryExpression *node)
5.558 -{
5.559 - if (node->token() == TOK_AND || node->token() == TOK_OR) {
5.560 - Label success, failure, done;
5.561 - visitForTest(node, &success, &failure, &success);
5.562 - __ bind(&success);
5.563 - __ int_(1);
5.564 - __ drop(1); // Otherwise, the stack depth will be +1 too much.
5.565 - __ jump(&done);
5.566 - __ bind(&failure);
5.567 - __ int_(0);
5.568 - __ bind(&done);
5.569 - return;
5.570 - }
5.571 -
5.572 - Local<Type> leftType(zone_, node->left()->type());
5.573 - Local<Type> rightType(zone_, node->right()->type());
5.574 - Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
5.575 -
5.576 - visitForALU(coerce, node->left());
5.577 - visitForALU(coerce, node->right());
5.578 -
5.579 - Opcode op = TokenToOpcode(node->token());
5.580 - if (node->type()->isFloat())
5.581 - op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
5.582 -
5.583 - __ note_position(node->pos());
5.584 - __ binary(op);
5.585 -}
5.586 -
5.587 -void
5.588 -BytecodeCompiler::visit(IndexExpression *node)
5.589 -{
5.590 - node->left()->accept(this);
5.591 - node->right()->accept(this);
5.592 - __ note_position(node->pos());
5.593 - __ getelem(node->type());
5.594 -}
5.595 -
5.596 -void
5.597 -BytecodeCompiler::visit(FieldExpression *node)
5.598 -{
5.599 - node->left()->accept(this);
5.600 - __ getfield(node->fieldIndex(), node->type());
5.601 -}
5.602 -
5.603 -void
5.604 -BytecodeCompiler::visit(ReturnStatement *node)
5.605 -{
5.606 - if (node->expression()) {
5.607 - node->expression()->accept(this);
5.608 - __ return_();
5.609 - } else {
5.610 - __ returnvoid();
5.611 - }
5.612 -}
5.613 -
5.614 -void
5.615 -BytecodeCompiler::visitForTest(Expression *expression,
5.616 - Label *trueBranch,
5.617 - Label *falseBranch,
5.618 - Label *fallthrough)
5.619 -{
5.620 - TokenKind token = ToCompare(expression);
5.621 - if (token == TOK_EOF || token == TOK_NOT) {
5.622 - if (token == TOK_EOF)
5.623 - expression->accept(this);
5.624 - else
5.625 - expression->toUnaryExpression()->expression()->accept(this);
5.626 -
5.627 - bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
5.628 -
5.629 - Opcode op = jumpOnTrue ? OP_JT : OP_JF;
5.630 - if (expression->type()->isFloat())
5.631 - op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
5.632 -
5.633 - if (fallthrough == falseBranch)
5.634 - __ j(op, trueBranch);
5.635 - else
5.636 - __ j(op, falseBranch);
5.637 - return;
5.638 - }
5.639 -
5.640 - BinaryExpression *binary = expression->toBinaryExpression();
5.641 -
5.642 - if (token == TOK_AND || token == TOK_OR) {
5.643 - Label next;
5.644 - if (token == TOK_AND)
5.645 - visitForTest(binary->left(), &next, falseBranch, &next);
5.646 - else
5.647 - visitForTest(binary->left(), trueBranch, &next, &next);
5.648 - __ bind(&next);
5.649 - visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
5.650 - return;
5.651 - }
5.652 -
5.653 - Opcode op = CompareTokenToJump(token);
5.654 - if (fallthrough == trueBranch)
5.655 - op = Invert(op);
5.656 -
5.657 - Local<Type> leftType(zone_, binary->left()->type());
5.658 - Local<Type> rightType(zone_, binary->right()->type());
5.659 - Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
5.660 -
5.661 - visitForALU(coerce, binary->left());
5.662 - visitForALU(coerce, binary->right());
5.663 - if (coerce->isFloat())
5.664 - op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
5.665 -
5.666 - if (fallthrough == trueBranch)
5.667 - __ j(op, falseBranch);
5.668 - else
5.669 - __ j(op, trueBranch);
5.670 -}
5.671 -
5.672 -void
5.673 -BytecodeCompiler::visit(ForStatement *node)
5.674 -{
5.675 - AutoEnterScope forScope(this, node->scope());
5.676 -
5.677 - recordLifoSlot(node->scope());
5.678 -
5.679 - Label join, update;
5.680 - LoopScope loop(scope_, &join, &update, &loop_);
5.681 -
5.682 - if (node->initialization())
5.683 - node->initialization()->accept(this);
5.684 -
5.685 - Label header, test;
5.686 - if (node->condition())
5.687 - __ jump(&test);
5.688 -
5.689 - __ bind(&header);
5.690 - node->body()->accept(this);
5.691 -
5.692 - __ bind(&update);
5.693 - if (node->update())
5.694 - node->update()->accept(this);
5.695 -
5.696 - if (node->condition()) {
5.697 - __ bind(&test);
5.698 - visitForTest(node->condition(), &header, &join, &join);
5.699 - } else {
5.700 - __ jump(&header);
5.701 - }
5.702 -
5.703 - __ bind(&join);
5.704 -
5.705 - if (node->scope())
5.706 - unwindTo(node->scope()->enclosing());
5.707 - assert(__ stackDepth() == 0);
5.708 -}
5.709 -
5.710 -void
5.711 -BytecodeCompiler::visit(WhileStatement *node)
5.712 -{
5.713 - Label header, join;
5.714 -
5.715 - __ bind(&header);
5.716 -
5.717 - LoopScope loop(scope_, &join, &header, &loop_);
5.718 -
5.719 - if (node->token() == TOK_WHILE) {
5.720 - Label body;
5.721 -
5.722 - visitForTest(node->condition(), &body, &join, &body);
5.723 - __ bind(&body);
5.724 - node->body()->accept(this);
5.725 - __ jump(&header);
5.726 - } else {
5.727 - node->body()->accept(this);
5.728 - visitForTest(node->condition(), &header, &join, &join);
5.729 - }
5.730 -
5.731 - __ bind(&join);
5.732 -}
5.733 -
5.734 -void
5.735 -BytecodeCompiler::visit(BreakStatement *node)
5.736 -{
5.737 - unwindTo(loop_->scope());
5.738 - __ jump(loop_->break_());
5.739 -}
5.740 -
5.741 -void
5.742 -BytecodeCompiler::visit(ContinueStatement *node)
5.743 -{
5.744 - unwindTo(loop_->scope());
5.745 - __ jump(loop_->continue_());
5.746 -}
5.747 -
5.748 -void
5.749 -BytecodeCompiler::visit(BlockStatement *node)
5.750 -{
5.751 - AutoEnterScope blockScope(this, node->scope());
5.752 -
5.753 - recordLifoSlot(node->scope());
5.754 -
5.755 - for (size_t i = 0; i < node->statements()->length(); i++) {
5.756 - Statement *statement = node->statements()->at(i);
5.757 - statement->accept(this);
5.758 - assert(__ stackDepth() == 0);
5.759 - }
5.760 -
5.761 - // We don't bother emitting an "unwind" instruction for function scopes,
5.762 - // since this is taken care of by the calling convention.
5.763 - if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
5.764 - unwindTo(node->scope()->enclosing());
5.765 -}
5.766 -
5.767 -void
5.768 -BytecodeCompiler::visit(IntegerLiteral *node)
5.769 -{
5.770 - __ int_(node->value());
5.771 -}
5.772 -
5.773 -void
5.774 -BytecodeCompiler::visit(BooleanLiteral *node)
5.775 -{
5.776 - if (node->token() == TOK_TRUE)
5.777 - __ true_();
5.778 - else
5.779 - __ false_();
5.780 -}
5.781 -
5.782 -void
5.783 -BytecodeCompiler::visit(FloatLiteral *node)
5.784 -{
5.785 - __ float_((float)node->value());
5.786 -}
5.787 -
5.788 -void
5.789 -BytecodeCompiler::visit(StringLiteral *node)
5.790 -{
5.791 - Local<Array> array(zone_, StringLiteralToArray(zone_, node));
5.792 - if (!array)
5.793 - return;
5.794 -
5.795 - __ note_position(node->pos());
5.796 - __ object(array);
5.797 -}
5.798 -
5.799 -void
5.800 -BytecodeCompiler::getEnvSlot(Variable *var)
5.801 -{
5.802 - assert(var->scope()->kind() == Scope::GLOBAL);
5.803 - __ getglobal(var);
5.804 -}
5.805 -
5.806 -void
5.807 -BytecodeCompiler::setEnvSlot(Variable *var)
5.808 -{
5.809 - assert(var->scope()->kind() == Scope::GLOBAL);
5.810 - __ setglobal(var);
5.811 -}
5.812 -
5.813 -static bool
5.814 -FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
5.815 -{
5.816 - Local<Array> string(zone);
5.817 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
5.818 - Expression *expr = literal->expressions()->at(i);
5.819 - StringLiteral *lit = expr->toStringLiteral();
5.820 - if ((string = StringLiteralToArray(zone, lit)) == NULL)
5.821 - return false;
5.822 -
5.823 - array->writeObject(zone, i, string);
5.824 -
5.825 - if (string->length() > *maxsize)
5.826 - *maxsize = string->length();
5.827 -
5.828 - assert(!array->type()->contained()->isFixedLength() ||
5.829 - array->type()->contained()->fixedLength() >= string->length());
5.830 - }
5.831 -
5.832 - return true;
5.833 -}
5.834 -
5.835 -static bool
5.836 -FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
5.837 -{
5.838 - assert(array->type()->fixedLength() == literal->expressions()->length());
5.839 -
5.840 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
5.841 - Expression *expr = literal->expressions()->at(i);
5.842 - if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
5.843 - array->writeInt32(i, lit->value());
5.844 - continue;
5.845 - }
5.846 - if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
5.847 - if (lit->token() == TOK_TRUE)
5.848 - array->writeInt32(i, 1);
5.849 - else
5.850 - array->writeInt32(i, 0);
5.851 - continue;
5.852 - }
5.853 - if (FloatLiteral *lit = expr->asFloatLiteral()) {
5.854 - array->writeFloat(i, lit->value());
5.855 - continue;
5.856 - }
5.857 -
5.858 - // Unrecognized literal type.
5.859 - assert(false);
5.860 - }
5.861 -
5.862 - return true;
5.863 -}
5.864 -
5.865 -static bool
5.866 -TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
5.867 - unsigned *maxsize)
5.868 -{
5.869 - assert(type->fixedLength() == literal->expressions()->length());
5.870 -
5.871 - Local<Type> contained(zone, type->contained());
5.872 - if (contained->isCharArray())
5.873 - return FillArrayLiteral_String(zone, array, literal, maxsize);
5.874 -
5.875 - if (!contained->isArray())
5.876 - return FillArrayLiteral_Primitive(zone, array, literal);
5.877 -
5.878 - Local<Array> subarray(zone);
5.879 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
5.880 - Expression *expr = literal->expressions()->at(i);
5.881 - subarray = Array::cast(array->readObject(i));
5.882 - if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
5.883 - return false;
5.884 - }
5.885 -
5.886 - return true;
5.887 -}
5.888 -
5.889 -static Array *
5.890 -BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
5.891 -{
5.892 - Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
5.893 - if (!root)
5.894 - return NULL;
5.895 -
5.896 - // This should have allocated everything in the array, so all we need to
5.897 - // do is traverse down to the lowest levels and copy things.
5.898 - Local<Type> type(zone, map->type());
5.899 - if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
5.900 - return NULL;
5.901 -
5.902 - return root;
5.903 -}
5.904 -
5.905 -static inline bool
5.906 -ArrayContainsCharBuffers(Type *type)
5.907 -{
5.908 - if (type->contained()->isArray())
5.909 - return ArrayContainsCharBuffers(type->contained());
5.910 - return type->isCharArray();
5.911 -}
5.912 -
5.913 -void
5.914 -BytecodeCompiler::visit(VariableDeclaration *node)
5.915 -{
5.916 - Variable *var = node->variable();
5.917 -
5.918 - Local<Type> type(zone_, var->type());
5.919 - if (type->isArray()) {
5.920 - Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
5.921 - __ note_position(node->pos());
5.922 -
5.923 - Local<Type> right(zone_);
5.924 - if (node->initialization())
5.925 - right = node->initialization()->type();
5.926 -
5.927 - // There are a few methods for allocating, here:
5.928 - // (1) If the array is fixed,
5.929 - // (a) Initializer not present,
5.930 - // NEWFIXED
5.931 - // (b) Left is const non-string:
5.932 - // <nothing>
5.933 - // (b) Otherwise:
5.934 - // NEWFIXED
5.935 - // COPYARRAY
5.936 - // (2) If the array is not fixed,
5.937 - // (a) Initializer is not present,
5.938 - // NEWEMPTY
5.939 - // (b) Initializer is not a string literal,
5.940 - // or left is const:
5.941 - // <nothing>
5.942 - // (c) Initializer is a string literal,
5.943 - // NEWSIZED
5.944 - // COPYARRAY
5.945 - //
5.946 -
5.947 - Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
5.948 - ? Heap::Tenure_Old
5.949 - : Heap::Tenure_Default;
5.950 -
5.951 - if (Expression *init = node->initialization()) {
5.952 - if (init->isArrayLiteral()) {
5.953 - unsigned maxsize = 0;
5.954 - Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
5.955 - if (!array)
5.956 - return;
5.957 -
5.958 - assert(type->isFixedLength());
5.959 -
5.960 - if (type->isConst()) {
5.961 - __ object(array);
5.962 - } else if (ArrayContainsCharBuffers(type)) {
5.963 - // This array contains mutable char buffers, so
5.964 - // unfortunately this gets a little more complicated. We
5.965 - // compute the maximum size needed for the innermost
5.966 - // string, which is similar to SP1. This means we can use
5.967 - // CopyArray rather than individually emit opcodes to clone
5.968 - // every string.
5.969 - Local<Type> child(zone_, type);
5.970 - for (size_t i = 0; i < type->levels() - 1; i++) {
5.971 - __ int_(child->fixedLength());
5.972 - child = child->contained();
5.973 - }
5.974 - __ int_(maxsize);
5.975 - __ newarray(OP_NEWSIZED, map, tenure);
5.976 - __ object(array);
5.977 - __ copyarray();
5.978 - } else {
5.979 - __ newarray(OP_NEWFIXED, map, tenure);
5.980 - __ object(array);
5.981 - __ copyarray();
5.982 - }
5.983 - } else if (type->isFixedLength()) {
5.984 - // Note in the case of:
5.985 - // const String:buffer[50] = "hello";
5.986 - //
5.987 - // We want to preserve sizeof(buffer) == 50.
5.988 - if (type->isConst() && !type->isCharArray()) {
5.989 - init->accept(this);
5.990 - } else {
5.991 - __ newarray(OP_NEWFIXED, map, tenure);
5.992 - init->accept(this);
5.993 - __ copyarray();
5.994 - }
5.995 - } else if (!type->isConst() && init->isStringLiteral()) {
5.996 - // This is a degenerate case of ArrayLiteral.
5.997 - __ int_(right->fixedLength());
5.998 - __ newarray(OP_NEWSIZED, map, tenure);
5.999 - init->accept(this);
5.1000 - __ copyarray();
5.1001 - } else if (type->isConst()) {
5.1002 - init->accept(this);
5.1003 - }
5.1004 - } else if (type->isFixedLength()) {
5.1005 - __ newarray(OP_NEWFIXED, map, tenure);
5.1006 - } else {
5.1007 - if (node->postDimensions()) {
5.1008 - for (size_t i = 0; i < node->postDimensions()->length(); i++) {
5.1009 - Expression *expr = node->postDimensions()->at(i);
5.1010 - if (expr)
5.1011 - expr->accept(this);
5.1012 - else
5.1013 - __ int_(0);
5.1014 - }
5.1015 - __ newarray(OP_NEWSIZED, map, tenure);
5.1016 - } else {
5.1017 - __ newarray(OP_NEWEMPTY, map, tenure);
5.1018 - }
5.1019 - }
5.1020 - } else if (type->isStruct()) {
5.1021 - Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
5.1022 -
5.1023 - // Because structs can contain arrays, any sort of composition
5.1024 - // triggers non-LIFO allocation. This is just for correctness.
5.1025 - // We could do better by:
5.1026 - // (1) Limiting to structs that just (recursively) contain arrays,
5.1027 - // (2) Swap Stack for Default tenure in Struct::New
5.1028 - // (3) JIT analysis
5.1029 - if (var->scope()->kind() == Scope::GLOBAL)
5.1030 - __ newstruct(map, Heap::Tenure_Old);
5.1031 - else if (var->needsHeapAllocation() || map->composed())
5.1032 - __ newstruct(map, Heap::Tenure_Default);
5.1033 - else
5.1034 - __ newstruct(map, Heap::Tenure_Stack);
5.1035 - } else {
5.1036 - if (node->initialization()) {
5.1037 - node->initialization()->accept(this);
5.1038 - } else {
5.1039 - if (type->isInt32OrEnum() || type->isBool()) {
5.1040 - __ int_(0);
5.1041 - } else {
5.1042 - assert(type->isFloat());
5.1043 - __ float_(0);
5.1044 - }
5.1045 - }
5.1046 - }
5.1047 -
5.1048 - if (var->location() == Variable::STACK) {
5.1049 - __ setlocal(var);
5.1050 - locals_->set(zone_, var->slot(), var->type());
5.1051 - } else {
5.1052 - assert(var->location() == Variable::ENVIRONMENT);
5.1053 - setEnvSlot(var);
5.1054 - }
5.1055 -
5.1056 - __ pop();
5.1057 -}
5.1058 -
5.1059 -void
5.1060 -BytecodeCompiler::visit(CallExpression *node)
5.1061 -{
5.1062 - Local<Type> funType(zone_, node->callee()->type());
5.1063 -
5.1064 - // Sniff out natives, which have a specific opcode and are guaranteed to
5.1065 - // be called via name proxy.
5.1066 - NamedFunction *native = NULL;
5.1067 - if (funType->isNative())
5.1068 - native = node->callee()->toNameProxy()->binding()->toNamedFunction();
5.1069 -
5.1070 - Local<Type> given(zone_);
5.1071 - for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
5.1072 - Expression *arg = node->arguments()->at(i);
5.1073 -
5.1074 - given = arg->type();
5.1075 -
5.1076 - // We need to compute a reference if the parameter was in the form:
5.1077 - // f(&a)
5.1078 - // Note this form does not allow: f({})
5.1079 - //
5.1080 - // We also need to compute references for all variadic native
5.1081 - // arguments, but arrays and references are already in the
5.1082 - // appropriate form.
5.1083 - bool mustPushReference = false;
5.1084 - if (i >= funType->parameters()->length()) {
5.1085 - assert(funType->isNative() && funType->isNativeVariadic());
5.1086 - mustPushReference = !given->isArray() && !given->isReference();
5.1087 - } else if (funType->parameterAt(i)->isReference()) {
5.1088 - mustPushReference = !given->isReference();
5.1089 - }
5.1090 -
5.1091 - // If a native is passed to a native, it must only be one level deep.
5.1092 - assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
5.1093 -
5.1094 - if (mustPushReference) {
5.1095 - if (arg->isNameProxy()) {
5.1096 - // :TODO: test with functions and globals
5.1097 - // Compute a reference to the name.
5.1098 - Variable *var = arg->toNameProxy()->binding()->toVariable();
5.1099 - __ note_position(node->pos());
5.1100 - __ newref(var);
5.1101 - } else if (arg->isFieldExpression()) {
5.1102 - FieldExpression *expr = arg->toFieldExpression();
5.1103 - expr->left()->accept(this);
5.1104 - __ note_position(expr->pos());
5.1105 - __ fieldref_lifo(expr->fieldIndex());
5.1106 - } else {
5.1107 - // We don't know how to, or can't, build a direct reference to
5.1108 - // this type. Make an indirect one, by taking the top of the
5.1109 - // stack and boxing it up.
5.1110 - arg->accept(this);
5.1111 - __ note_position(node->pos());
5.1112 - __ slotref_lifo();
5.1113 - }
5.1114 - } else {
5.1115 - arg->accept(this);
5.1116 - }
5.1117 - }
5.1118 -
5.1119 - unsigned argc = node->arguments()->length();
5.1120 -
5.1121 - // If there are missing arguments, then we're not done and have to push
5.1122 - // default parameters.
5.1123 - Local<Box> box(zone_);
5.1124 - Local<Array> array(zone_);
5.1125 - Local<ArrayMap> map(zone_);
5.1126 - for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
5.1127 - box = Box::cast(funType->defaults()->at(i));
5.1128 -
5.1129 - if (box->type()->isPod()) {
5.1130 - if (box->type()->pod() == PrimitiveType_Int32)
5.1131 - __ int_(box->toInt32());
5.1132 - else if (box->type()->pod() == PrimitiveType_Float)
5.1133 - __ float_(box->toFloat());
5.1134 - else
5.1135 - assert(false);
5.1136 -
5.1137 - if (funType->parameterAt(i)->isReference()) {
5.1138 - __ note_position(node->pos());
5.1139 - __ slotref_lifo();
5.1140 - }
5.1141 - } else {
5.1142 - assert(box->type()->isArray());
5.1143 -
5.1144 - array = Array::cast(box->toObject());
5.1145 - if (funType->parameterAt(i)->isConst()) {
5.1146 - __ object(array);
5.1147 - } else {
5.1148 - // We need to copy the array since it's mutable. Note that
5.1149 - // although COPYARRAY returns its left-hand side, this may
5.1150 - // change in the future, we do the same thing and dupe the
5.1151 - // newly allocated array.
5.1152 - map = ArrayMap::cast(array->map());
5.1153 -
5.1154 - // Natives cannot escape array references, so we can allocate
5.1155 - // them on the LIFO stack.
5.1156 - if (funType->isNative())
5.1157 - __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
5.1158 - else
5.1159 - __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
5.1160 - __ dup();
5.1161 - __ object(array);
5.1162 - __ copyarray();
5.1163 - __ pop();
5.1164 - }
5.1165 - }
5.1166 -
5.1167 - argc++;
5.1168 - }
5.1169 -
5.1170 - __ note_position(node->pos());
5.1171 - if (native) {
5.1172 - __ callnative(native->slot(), argc);
5.1173 - __ drop(argc);
5.1174 - } else {
5.1175 - node->callee()->accept(this);
5.1176 - __ call(funType);
5.1177 - __ drop(argc + 1);
5.1178 - }
5.1179 -}
5.1180 -
5.1181 -void
5.1182 -BytecodeCompiler::visit(TernaryExpression *node)
5.1183 -{
5.1184 - Label success, failure, join;
5.1185 -
5.1186 - visitForTest(node->condition(), &success, &failure, &success);
5.1187 - __ bind(&success);
5.1188 - node->left()->accept(this);
5.1189 - __ drop(1);
5.1190 - __ jump(&join);
5.1191 - __ bind(&failure);
5.1192 - node->right()->accept(this);
5.1193 - __ bind(&join);
5.1194 -}
5.1195 -
5.1196 -void
5.1197 -BytecodeCompiler::visit(IfStatement *node)
5.1198 -{
5.1199 - Label join;
5.1200 - if (!node->ifFalse()) {
5.1201 - Label success;
5.1202 -
5.1203 - visitForTest(node->condition(), &success, &join, &success);
5.1204 - __ bind(&success);
5.1205 - node->ifTrue()->accept(this);
5.1206 - } else {
5.1207 - Label success, next;
5.1208 -
5.1209 - visitForTest(node->condition(), &success, &next, &success);
5.1210 - __ bind(&success);
5.1211 - node->ifTrue()->accept(this);
5.1212 - __ jump(&join);
5.1213 - __ bind(&next);
5.1214 - node->ifFalse()->accept(this);
5.1215 - }
5.1216 -
5.1217 - __ bind(&join);
5.1218 -}
5.1219 -
5.1220 -bool
5.1221 -BytecodeCompiler::tableswitch(SwitchStatement *node)
5.1222 -{
5.1223 - CaseValueList *values = node->caseValueList();
5.1224 -
5.1225 - if (values->length() < 3)
5.1226 - return false;
5.1227 -
5.1228 - // Find the delta between the largest and smallest value.
5.1229 - int hi = values->at(values->length() - 1).box.toInt();
5.1230 - int lo = values->at(0).box.toInt();
5.1231 - assert(hi > lo);
5.1232 -
5.1233 - unsigned tablesize = TableSwitchEntries(lo, hi);
5.1234 - if (tablesize > MAX_TABLESWITCH_ENTRIES)
5.1235 - return false;
5.1236 -
5.1237 - Label def, join;
5.1238 -
5.1239 - // Create the list of labels that each statement will bind to.
5.1240 - Label *labels = new Label[node->cases()->length()];
5.1241 -
5.1242 - // Create the table of labels we'll use for each case.
5.1243 - Label **table = new Label *[tablesize];
5.1244 -
5.1245 - // Link all cases, by default, to the default label.
5.1246 - for (size_t i = 0; i < tablesize; i++)
5.1247 - table[i] = &def;
5.1248 -
5.1249 - // Now patch actual cases to their correct labels.
5.1250 - for (size_t i = 0; i < values->length(); i++) {
5.1251 - CaseValue &v = values->at(i);
5.1252 - assert(v.statement < node->cases()->length());
5.1253 -
5.1254 - unsigned index = unsigned(v.box.toInt() - lo);
5.1255 - assert(index < tablesize);
5.1256 -
5.1257 - table[index] = &labels[v.statement];
5.1258 - }
5.1259 -
5.1260 - // Emit the tableswitch opcode and the jump table.
5.1261 - __ tableswitch(lo, hi, &def, table);
5.1262 -
5.1263 - // We're done with the jump table now.
5.1264 - delete [] table;
5.1265 -
5.1266 - // Emit each statement.
5.1267 - for (size_t i = 0; i < node->cases()->length(); i++) {
5.1268 - Statement *stmt = node->cases()->at(i)->statement();
5.1269 -
5.1270 - __ bind(&labels[i]);
5.1271 - stmt->accept(this);
5.1272 - __ jump(&join);
5.1273 - }
5.1274 -
5.1275 - // We're done with the statement labels.
5.1276 - delete [] labels;
5.1277 -
5.1278 - // Emit the default case.
5.1279 - __ bind(&def);
5.1280 - if (node->defaultCase())
5.1281 - node->defaultCase()->accept(this);
5.1282 -
5.1283 - __ bind(&join);
5.1284 -
5.1285 - return true;
5.1286 -}
5.1287 -
5.1288 -void
5.1289 -BytecodeCompiler::visit(SwitchStatement *node)
5.1290 -{
5.1291 - node->expression()->accept(this);
5.1292 -
5.1293 - if (tableswitch(node))
5.1294 - return;
5.1295 -
5.1296 - Label join;
5.1297 -
5.1298 - for (size_t i = 0; i < node->cases()->length(); i++) {
5.1299 - Case *c = node->cases()->at(i);
5.1300 -
5.1301 - Label success, fail;
5.1302 - if (c->others()) {
5.1303 - for (size_t j = 0; j < c->others()->length(); j++) {
5.1304 - Expression *expr = c->others()->at(j);
5.1305 -
5.1306 - __ dup();
5.1307 - expr->accept(this);
5.1308 - __ j(OP_JEQ, &success);
5.1309 - }
5.1310 - }
5.1311 -
5.1312 - // The final test.
5.1313 - __ dup();
5.1314 - c->expression()->accept(this);
5.1315 - __ j(OP_JNE, &fail);
5.1316 - __ bind(&success);
5.1317 - c->statement()->accept(this);
5.1318 - __ jump(&join);
5.1319 - __ bind(&fail);
5.1320 - }
5.1321 -
5.1322 - if (node->defaultCase())
5.1323 - node->defaultCase()->accept(this);
5.1324 -
5.1325 - __ pop();
5.1326 - __ bind(&join);
5.1327 -}
5.1328 -
5.1329 -void
5.1330 -BytecodeCompiler::visit(FunctionStatement *node)
5.1331 -{
5.1332 - if (!node->fun()->used())
5.1333 - return;
5.1334 -
5.1335 - if (node->fun()->isNative()) {
5.1336 - assert(!moduleData_->natives->at(node->fun()->slot()));
5.1337 -
5.1338 - Local<Type> type(zone_, node->fun()->type());
5.1339 - Local<String> name(zone_, node->fun()->name());
5.1340 - Local<Native> native(zone_, Native::New(zone_, type, name));
5.1341 - if (!native)
5.1342 - return;
5.1343 -
5.1344 - moduleData_->natives->set(zone_, node->fun()->slot(), native);
5.1345 - return;
5.1346 - }
5.1347 -
5.1348 - // If the function has no body, then it's just a declaration.
5.1349 - if (!node->body()) {
5.1350 - assert(node->fun()->isForward() || node->fun()->isPublic());
5.1351 - return;
5.1352 - }
5.1353 -
5.1354 - BytecodeCompiler child(zone_, tree_, moduleData_);
5.1355 - Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
5.1356 - if (!fun)
5.1357 - return;
5.1358 -
5.1359 - assert(!moduleData_->module->getFunction(node->fun()->slot()));
5.1360 - moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
5.1361 -}
5.1362 -
5.1363 -void
5.1364 -BytecodeCompiler::visit(FunctionTypeStatement *node)
5.1365 -{
5.1366 -}
5.1367 -
5.1368 -void
5.1369 -BytecodeCompiler::visit(EnumStatement *node)
5.1370 -{
5.1371 -}
5.1372 -
5.1373 -void
5.1374 -BytecodeCompiler::visit(StructureStatement *node)
5.1375 -{
5.1376 -}
5.1377 -
5.1378 -void
5.1379 -BytecodeCompiler::visit(ArrayLiteral *node)
5.1380 -{
5.1381 - // We shouldn't reach these; they're handled manually when initializing
5.1382 - // declared arrays.
5.1383 - assert(false);
5.1384 -}
5.1385 -
5.1386 -Code *
5.1387 -BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
5.1388 -{
5.1389 - // STOP doubles as RETURNVOID.
5.1390 - __ stop();
5.1391 -
5.1392 - if (__ oom() || zone_->hasPendingException())
5.1393 - return NULL;
5.1394 -
5.1395 - Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
5.1396 - if (!bytes)
5.1397 - return NULL;
5.1398 - memcpy(bytes->raw(), __ buffer(), __ length());
5.1399 -
5.1400 - for (size_t i = 0; i < scope->maxContainedLocals(); i++)
5.1401 - assert(locals_->at(i));
5.1402 -
5.1403 - Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
5.1404 - if (!objects)
5.1405 - return NULL;
5.1406 -
5.1407 - for (size_t i = 0; i < __ objects()->length(); i++)
5.1408 - objects->set(zone_, i, *(__ objects()->at(i)));
5.1409 -
5.1410 - Local<ByteArray> safepoints(zone_);
5.1411 -
5.1412 - // If any stack slots hold gc pointers at potential failure points in the
5.1413 - // bytecode, record them now. We do this by building a list of tuples;
5.1414 - // each tuple contains the pc offset, and a bitset containing which stack
5.1415 - // slots must be scanned by the gc.
5.1416 - if (__ oopRecords()->length()) {
5.1417 - size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
5.1418 - size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
5.1419 - safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
5.1420 - if (!safepoints)
5.1421 - return NULL;
5.1422 -
5.1423 - Address cursor = safepoints->raw();
5.1424 - for (size_t i = 0; i < __ oopRecords()->length(); i++) {
5.1425 - OopRecord *record = __ oopRecords()->at(i);
5.1426 - assert(record->depth <= __ maxStackDepth());
5.1427 -
5.1428 - *reinterpret_cast<unsigned *>(cursor) = record->offset;
5.1429 -
5.1430 - unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
5.1431 - for (unsigned i = 0; i < record->depth; i++)
5.1432 - bits[i / 8] |= (1 << (i % 8));
5.1433 -
5.1434 - cursor += bytesPerSafepoint;
5.1435 - }
5.1436 -
5.1437 - assert(cursor == safepoints->raw() + gcmapSize);
5.1438 - }
5.1439 -
5.1440 - Local<ByteArray> sourcemap(zone_);
5.1441 - if (__ sourcemapLength()) {
5.1442 - sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
5.1443 - if (!sourcemap)
5.1444 - return NULL;
5.1445 -
5.1446 - memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
5.1447 - }
5.1448 -
5.1449 - Local<Code> code(zone_);
5.1450 -
5.1451 - code = Code::New(zone_,
5.1452 - bytes,
5.1453 - locals_,
5.1454 - objects,
5.1455 - __ maxStackDepth(),
5.1456 - moduleData_->module,
5.1457 - safepoints,
5.1458 - sourcemap,
5.1459 - lineno);
5.1460 - return code;
5.1461 -}
5.1462 -
5.1463 -Function *
5.1464 -BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
5.1465 -{
5.1466 - // Note: No need to record a life slot here, since it's part of the Frame.
5.1467 - AutoEnterScope functionScope(this, node->scope());
5.1468 -
5.1469 - // Set the initial line, because line mappings are deltas.
5.1470 - __ setFirstLine(node->pos().line);
5.1471 - locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
5.1472 -
5.1473 - node->body()->accept(this);
5.1474 -
5.1475 - unsigned nargs = node->scope()->numArguments();
5.1476 - Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
5.1477 - if (!args)
5.1478 - return NULL;
5.1479 -
5.1480 - for (size_t i = 0; i < node->scope()->numArguments(); i++)
5.1481 - args->set(zone_, i, node->scope()->getArgument(i)->type());
5.1482 -
5.1483 -
5.1484 - Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
5.1485 - if (!code)
5.1486 - return NULL;
5.1487 -
5.1488 - Local<Type> type(zone_, node->fun()->type());
5.1489 - Local<String> name(zone_, node->fun()->name());
5.1490 - Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
5.1491 - if (!fun)
5.1492 - return NULL;
5.1493 -
5.1494 - // If this function had a forward, export it as a named public.
5.1495 - if (node->fun()->isPublic()) {
5.1496 - assert(node->fun()->isPublic());
5.1497 - ScopedRoot<Function> root(fun);
5.1498 - if (!root)
5.1499 - return NULL;
5.1500 - if (!moduleData_->publics.append(root))
5.1501 - return NULL;
5.1502 - }
5.1503 -
5.1504 -#ifndef NDEBUG
5.1505 - Disassemble(code, stdout);
5.1506 -#endif
5.1507 -
5.1508 - return fun;
5.1509 -}
5.1510 -
5.1511 -Module *
5.1512 -BytecodeCompiler::compile()
5.1513 -{
5.1514 - AutoEnterScope scope(this, tree_->scope());
5.1515 -
5.1516 - ModuleData moduleData;
5.1517 -
5.1518 - moduleData_ = &moduleData;
5.1519 - moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
5.1520 -
5.1521 - if (!moduleData_)
5.1522 - return NULL;
5.1523 -
5.1524 - moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
5.1525 - if (!moduleData_->natives)
5.1526 - return NULL;
5.1527 -
5.1528 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
5.1529 - Statement *statement = tree_->statements()->at(i);
5.1530 - statement->accept(this);
5.1531 - }
5.1532 -
5.1533 - if (zone_->hasPendingException())
5.1534 - return NULL;
5.1535 -
5.1536 -#ifndef NDEBUG
5.1537 - for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
5.1538 - assert(moduleData_->module->getFunction(i));
5.1539 - for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
5.1540 - assert(moduleData_->natives->at(i));
5.1541 -#endif
5.1542 -
5.1543 - if (moduleData_->publics.length()) {
5.1544 - Local<Function> fun(zone_);
5.1545 - Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
5.1546 - Heap::Tenure_Old));
5.1547 - if (!list)
5.1548 - return NULL;
5.1549 -
5.1550 - for (size_t i = 0; i < moduleData_->publics.length(); i++)
5.1551 - list->set(zone_, i, moduleData_->publics[i]);
5.1552 -
5.1553 - moduleData_->module->setPublics(list);
5.1554 - }
5.1555 -
5.1556 - moduleData_->module->setNatives(moduleData_->natives);
5.1557 -
5.1558 - if (scope_->numEnvironmentVars()) {
5.1559 - Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
5.1560 - if (!globalMap)
5.1561 - return NULL;
5.1562 -
5.1563 - Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
5.1564 - if (!environment)
5.1565 - return NULL;
5.1566 -
5.1567 - moduleData_->module->setEnvironment(environment);
5.1568 - }
5.1569 -
5.1570 - Local<Code> code(zone_, compileCode(tree_->scope(), 1));
5.1571 - if (!code)
5.1572 - return NULL;
5.1573 -
5.1574 - Disassemble(code, stdout);
5.1575 -
5.1576 - moduleData_->module->setCode(code);
5.1577 -
5.1578 - return moduleData_->module;
5.1579 -}
6.1 --- a/src/BytecodeCompiler.h Mon Sep 17 00:10:01 2012 -0700
6.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
6.3 @@ -1,159 +0,0 @@
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_bytecode_compiler_h_
6.23 -#define _include_bytecode_compiler_h_
6.24 -
6.25 -#include "AST.h"
6.26 -#include "BytecodeEmitter.h"
6.27 -#include "Functions.h"
6.28 -
6.29 -namespace ke {
6.30 -
6.31 -class Module;
6.32 -class Array;
6.33 -class ArrayMap;
6.34 -
6.35 -struct ModuleData
6.36 -{
6.37 - ScopedRoot<Module> module;
6.38 - PoolList<ScopedRoot<Function> > publics;
6.39 - ScopedRoot<FixedArray> natives;
6.40 -};
6.41 -
6.42 -class BytecodeCompiler : public AstVisitor
6.43 -{
6.44 - Zone *zone_;
6.45 - ParseTree *tree_;
6.46 - BytecodeEmitter emitter_;
6.47 - ScopedRoot<FixedArray> locals_;
6.48 - Scope *scope_;
6.49 - ModuleData *moduleData_;
6.50 -
6.51 - class LoopScope
6.52 - {
6.53 - Scope *scope_;
6.54 - BytecodeEmitter::Label *bk_;
6.55 - BytecodeEmitter::Label *ct_;
6.56 - LoopScope **prevp_;
6.57 - LoopScope *prev_;
6.58 -
6.59 - public:
6.60 - LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
6.61 - LoopScope **prevp)
6.62 - : scope_(scope),
6.63 - bk_(bk),
6.64 - ct_(ct),
6.65 - prevp_(prevp),
6.66 - prev_(*prevp)
6.67 - {
6.68 - *prevp_ = this;
6.69 - }
6.70 -
6.71 - ~LoopScope()
6.72 - {
6.73 - *prevp_ = prev_;
6.74 - }
6.75 -
6.76 - BytecodeEmitter::Label *break_() {
6.77 - return bk_;
6.78 - }
6.79 - BytecodeEmitter::Label *continue_() {
6.80 - return ct_;
6.81 - }
6.82 - Scope *scope() {
6.83 - return scope_;
6.84 - }
6.85 - };
6.86 -
6.87 - LoopScope *loop_;
6.88 -
6.89 - public:
6.90 - class AutoEnterScope
6.91 - {
6.92 - BytecodeCompiler *bc_;
6.93 - Scope *saved_;
6.94 -
6.95 - public:
6.96 - AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
6.97 - : bc_(bc),
6.98 - saved_(bc->scope_)
6.99 - {
6.100 - if (scope)
6.101 - bc->scope_ = scope;
6.102 - }
6.103 - ~AutoEnterScope() {
6.104 - bc_->scope_ = saved_;
6.105 - }
6.106 - };
6.107 -
6.108 - private:
6.109 - void recordLifoSlot(Scope *scope);
6.110 - void unwindTo(Scope *scope);
6.111 - void visitForTest(Expression *expression,
6.112 - BytecodeEmitter::Label *trueBranch,
6.113 - BytecodeEmitter::Label *falseBranch,
6.114 - BytecodeEmitter::Label *fallthrough);
6.115 - Code *compileCode(Scope *scope, unsigned lineno);
6.116 - Function *compileFunction(ModuleData *module, FunctionStatement *fun);
6.117 - void visitForALU(Type *needed, Expression *node);
6.118 -
6.119 - void getEnvSlot(Variable *var);
6.120 - void setEnvSlot(Variable *var);
6.121 -
6.122 - bool tableswitch(SwitchStatement *node);
6.123 -
6.124 - public:
6.125 - BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
6.126 -
6.127 - Module *compile();
6.128 -
6.129 - public:
6.130 - void visit(NameProxy *name);
6.131 - void visit(Assignment *node);
6.132 - void visit(BinaryExpression *node);
6.133 - void visit(ReturnStatement *node);
6.134 - void visit(ForStatement *node);
6.135 - void visit(BlockStatement *node);
6.136 - void visit(VariableDeclaration *node);
6.137 - void visit(IntegerLiteral *node);
6.138 - void visit(BooleanLiteral *node);
6.139 - void visit(FloatLiteral *node);
6.140 - void visit(StringLiteral *node);
6.141 - void visit(ExpressionStatement *node);
6.142 - void visit(FunctionStatement *node);
6.143 - void visit(CallExpression *node);
6.144 - void visit(IfStatement *node);
6.145 - void visit(IndexExpression *node);
6.146 - void visit(EnumStatement *node);
6.147 - void visit(WhileStatement *node);
6.148 - void visit(BreakStatement *node);
6.149 - void visit(ContinueStatement *node);
6.150 - void visit(IncDecExpression *node);
6.151 - void visit(UnaryExpression *node);
6.152 - void visit(TernaryExpression *node);
6.153 - void visit(StructureStatement *node);
6.154 - void visit(FieldExpression *node);
6.155 - void visit(SwitchStatement *node);
6.156 - void visit(FunctionTypeStatement *node);
6.157 - void visit(ArrayLiteral *node);
6.158 -};
6.159 -
6.160 -}
6.161 -
6.162 -#endif // _include_bytecode_generator_h_
7.1 --- a/src/BytecodeEmitter.cpp Mon Sep 17 00:10:01 2012 -0700
7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
7.3 @@ -1,122 +0,0 @@
7.4 -/* vim: set ts=4 sw=4 tw=99 et:
7.5 - *
7.6 - * Copyright (C) 2012 David Anderson
7.7 - *
7.8 - * This file is part of JITCraft.
7.9 - *
7.10 - * JITCraft is free software: you can redistribute it and/or modify it under
7.11 - * the terms of the GNU General Public License as published by the Free
7.12 - * Software Foundation, either version 3 of the License, or (at your option)
7.13 - * any later version.
7.14 - *
7.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
7.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
7.18 - *
7.19 - * You should have received a copy of the GNU General Public License along with
7.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
7.21 - */
7.22 -#include <stdlib.h>
7.23 -#include <string.h>
7.24 -#include "BytecodeEmitter.h"
7.25 -#include "Utility.h"
7.26 -#include "Types.h"
7.27 -#include "Zone.h"
7.28 -#include "Spaces-inl.h"
7.29 -#include "Heap-inl.h"
7.30 -
7.31 -using namespace ke;
7.32 -
7.33 -BytecodeEmitter::BytecodeEmitter(PoolAllocator &pool)
7.34 - : pool_(pool),
7.35 - buffer_(inline_buffer_),
7.36 - buffer_pos_(buffer_),
7.37 - buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
7.38 - oom_(false),
7.39 - maxStackDepth_(0)
7.40 -{
7.41 - lastCodePosition_ = 0;
7.42 - firstLine_ = 1;
7.43 -}
7.44 -
7.45 -bool
7.46 -BytecodeEmitter::growBuffer(size_t nbytes)
7.47 -{
7.48 - if (oom_) {
7.49 - buffer_pos_ = buffer_;
7.50 - return false;
7.51 - }
7.52 -
7.53 - size_t newSize = size_t((buffer_end_ - buffer_) * 2);
7.54 - if (newSize >= MAX_LENGTH) {
7.55 - oom_ = true;
7.56 - buffer_pos_ = buffer_;
7.57 - ZONE()->reportOutOfMemory();
7.58 - return false;
7.59 - }
7.60 -
7.61 - bytecode *newBuffer;
7.62 - if (buffer_ == inline_buffer_)
7.63 - newBuffer = (bytecode *)malloc(newSize);
7.64 - else
7.65 - newBuffer = (bytecode *)realloc(buffer_, newSize);
7.66 -
7.67 - // If we can't allocate a buffer, reset the buffer to the start and set
7.68 - // a flag to indicate out-of-memory.
7.69 - if (!newBuffer) {
7.70 - oom_ = true;
7.71 - buffer_pos_ = buffer_;
7.72 - ZONE()->reportOutOfMemory();
7.73 - return false;
7.74 - }
7.75 -
7.76 - if (buffer_ == inline_buffer_)
7.77 - memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
7.78 -
7.79 - buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
7.80 - buffer_ = newBuffer;
7.81 - buffer_end_ = buffer_ + newSize;
7.82 - assert(buffer_pos_ + nbytes < buffer_end_);
7.83 -
7.84 - return true;
7.85 -}
7.86 -
7.87 -void
7.88 -BytecodeEmitter::recordOops()
7.89 -{
7.90 - OopRecord *record = new (pool_) OopRecord(oopMap_.length(), position());
7.91 -
7.92 - record->slots = (bool *)pool_.allocate(record->depth);
7.93 - if (!record->slots) {
7.94 - oom_ = true;
7.95 - return;
7.96 - }
7.97 -
7.98 - bool hadOops = false;
7.99 - for (size_t i = 0; i < oopMap_.length(); i++) {
7.100 - bool bit = oopMap_[i];
7.101 - record->slots[i] = bit;
7.102 - hadOops |= bit;
7.103 - }
7.104 -
7.105 - if (!hadOops)
7.106 - return;
7.107 -
7.108 - oom_ &= oopRecords_.append(record);
7.109 -}
7.110 -
7.111 -void
7.112 -BytecodeEmitter::note_position(const SourcePosition &pos)
7.113 -{
7.114 - assert(pos.line > 0);
7.115 - assert(unsigned(pos.line) >= firstLine_);
7.116 -
7.117 - unsigned lineDelta = unsigned(pos.line) - firstLine_;
7.118 - unsigned pcDelta = unsigned(position()) - lastCodePosition_;
7.119 -
7.120 - sourcemap_.writeUint32(pcDelta);
7.121 - sourcemap_.writeUint32(lineDelta);
7.122 - sourcemap_.writeUint32(pos.col);
7.123 -
7.124 - lastCodePosition_ = unsigned(position());
7.125 -}
8.1 --- a/src/BytecodeEmitter.h Mon Sep 17 00:10:01 2012 -0700
8.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
8.3 @@ -1,672 +0,0 @@
8.4 -/* vim: set ts=4 sw=4 tw=99 et:
8.5 - *
8.6 - * Copyright (C) 2012 David Anderson
8.7 - *
8.8 - * This file is part of JITCraft.
8.9 - *
8.10 - * JITCraft is free software: you can redistribute it and/or modify it under
8.11 - * the terms of the GNU General Public License as published by the Free
8.12 - * Software Foundation, either version 3 of the License, or (at your option)
8.13 - * any later version.
8.14 - *
8.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
8.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8.18 - *
8.19 - * You should have received a copy of the GNU General Public License along with
8.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
8.21 - */
8.22 -#ifndef _include_bytecode_emitter_h_
8.23 -#define _include_bytecode_emitter_h_
8.24 -
8.25 -#include <assert.h>
8.26 -#include <limits.h>
8.27 -#include "Opcodes.h"
8.28 -#include "NameBinding.h"
8.29 -#include "Handles.h"
8.30 -#include "CompactBuffer.h"
8.31 -#include "Array.h"
8.32 -
8.33 -namespace ke {
8.34 -
8.35 -class Type;
8.36 -class Map;
8.37 -class ArrayMap;
8.38 -
8.39 -typedef PoolList<ScopedRoot<Object> > ObjectList;
8.40 -
8.41 -struct OopRecord : public PoolObject
8.42 -{
8.43 - unsigned depth;
8.44 - unsigned offset;
8.45 - bool *slots;
8.46 -
8.47 - OopRecord(unsigned length, unsigned offset)
8.48 - : depth(length),
8.49 - offset(offset),
8.50 - slots(NULL)
8.51 - {
8.52 - }
8.53 -};
8.54 -
8.55 -class BytecodeEmitter
8.56 -{
8.57 - private:
8.58 - PoolAllocator &pool_;
8.59 -
8.60 - bytecode *buffer_;
8.61 - bytecode *buffer_pos_;
8.62 - bytecode *buffer_end_;
8.63 - bytecode inline_buffer_[512];
8.64 - bool oom_;
8.65 - unsigned maxStackDepth_;
8.66 - ObjectList objects_;
8.67 - PoolList<bool> oopMap_;
8.68 - PoolList<OopRecord *> oopRecords_;
8.69 - CompactBufferWriter sourcemap_;
8.70 - unsigned lastCodePosition_;
8.71 - unsigned firstLine_;
8.72 -
8.73 - private:
8.74 - // The maximum size of a code object must be such that the distance between
8.75 - // two instructions fits into a signed, 31-bit integer. This ensures that
8.76 - // all code-bounded buffers (like the number of object literals or
8.77 - // safepoints) does not need to be bounds checked. It also means we can add
8.78 - // any two offsets and be guaranteed that they don't overflow.
8.79 - static const size_t MAX_LENGTH = INT_MAX / 2;
8.80 -
8.81 - private:
8.82 - bool growBuffer(size_t bytes);
8.83 -
8.84 - // Checking the return value is not necessary, since the inline buffer is
8.85 - // used as a ballast.
8.86 - bool ensure(size_t bytes) {
8.87 - if (buffer_pos_ + bytes > buffer_end_)
8.88 - return growBuffer(bytes);
8.89 - return true;
8.90 - }
8.91 -
8.92 - void writeUint8(unsigned value) {
8.93 - assert(value <= UCHAR_MAX);
8.94 - *buffer_pos_++ = value;
8.95 - }
8.96 - void writeFloat(float value) {
8.97 - *(float *)buffer_pos_ = value;
8.98 - buffer_pos_ += sizeof(float);
8.99 - }
8.100 - void writeInt32(int value) {
8.101 - *(int *)buffer_pos_ = value;
8.102 - buffer_pos_ += sizeof(int);
8.103 - }
8.104 - void writeUint32(unsigned value) {
8.105 - *(unsigned *)buffer_pos_ = value;
8.106 - buffer_pos_ += sizeof(unsigned);
8.107 - }
8.108 - void writeOp(Opcode op) {
8.109 - if (oom_)
8.110 - return;
8.111 -
8.112 - writeUint8(op);
8.113 - for (int i = 0; i < OpcodeInfo[op].nuses; i++)
8.114 - oopMap_.pop();
8.115 - for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
8.116 - oopMap_.append(false);
8.117 - if (oopMap_.length() > maxStackDepth_)
8.118 - maxStackDepth_ = oopMap_.length();
8.119 - }
8.120 - void writeObject(Object *obj) {
8.121 - writeUint32(objects_.length());
8.122 - ScopedRoot<Object> root(obj);
8.123 - if (!objects_.append(root))
8.124 - oom_ = true;
8.125 - }
8.126 -
8.127 - int position() const {
8.128 - assert(buffer_pos_ - buffer_ < INT_MAX / 2);
8.129 - return int(buffer_pos_ - buffer_);
8.130 - }
8.131 -
8.132 - public:
8.133 - BytecodeEmitter(PoolAllocator &pool);
8.134 -
8.135 - bytecode *buffer() const {
8.136 - return buffer_;
8.137 - }
8.138 - unsigned length() const {
8.139 - return unsigned(buffer_pos_ - buffer_);
8.140 - }
8.141 - bool oom() const {
8.142 - return oom_ || sourcemap_.oom();
8.143 - }
8.144 - unsigned stackDepth() const {
8.145 - return oopMap_.length();
8.146 - }
8.147 - unsigned maxStackDepth() const {
8.148 - return maxStackDepth_;
8.149 - }
8.150 - const ObjectList *objects() const {
8.151 - return &objects_;
8.152 - }
8.153 - PoolList<OopRecord *> *oopRecords() {
8.154 - return &oopRecords_;
8.155 - }
8.156 -
8.157 - void drop(unsigned amt) {
8.158 - assert(amt <= stackDepth());
8.159 - for (unsigned i = 0; i < amt; i++)
8.160 - oopMap_.pop();
8.161 - }
8.162 -
8.163 - void note_position(const SourcePosition &pos);
8.164 - uint8 *sourcemap() const {
8.165 - return sourcemap_.buffer();
8.166 - }
8.167 - size_t sourcemapLength() const {
8.168 - return sourcemap_.length();
8.169 - }
8.170 - void setFirstLine(unsigned line) {
8.171 - assert(!sourcemap_.length());
8.172 - firstLine_ = line;
8.173 - }
8.174 -
8.175 - public:
8.176 - // A label represents a local control-flow target in the bytecode. A label
8.177 - // may be in three states:
8.178 - //
8.179 - // (1) Empty - the label is not used yet.
8.180 - // (2) Pending - the label has incoming jumps, but the actual location of
8.181 - // is not yet known. The list of jumps is threaded through
8.182 - // the four bytes reserved for each emitted jump target. In
8.183 - // this case, the offset field is the location of the most
8.184 - // recently emitted incoming jump.
8.185 - // (3) Bound - the label's position has been pinned.
8.186 - //
8.187 - // A jump can be emitted to a label in any state. Binding a label
8.188 - // immediately backpatches all pending incoming jumps. A label must be
8.189 - // bound if it is used.
8.190 - class Label
8.191 - {
8.192 - int offset_ : 31;
8.193 - bool bound_ : 1;
8.194 -
8.195 - void setOffset(int offset) {
8.196 - offset_ = offset;
8.197 - assert(offset_ == offset);
8.198 - }
8.199 -
8.200 - public:
8.201 - static const int INVALID_OFFSET = -1;
8.202 -
8.203 - public:
8.204 - Label()
8.205 - : offset_(INVALID_OFFSET),
8.206 - bound_(false)
8.207 - {
8.208 - }
8.209 - ~Label()
8.210 - {
8.211 - assert(bound_ || offset_ == INVALID_OFFSET);
8.212 - }
8.213 -
8.214 - bool bound() const {
8.215 - return bound_;
8.216 - }
8.217 - int offset() const {
8.218 - return offset_;
8.219 - }
8.220 - void bind(int offset) {
8.221 - assert(!bound_);
8.222 - setOffset(offset);
8.223 - bound_ = true;
8.224 - }
8.225 - int link(int offset) {
8.226 - assert(!bound_);
8.227 - int old = offset_;
8.228 - setOffset(offset);
8.229 - return old;
8.230 - }
8.231 - };
8.232 -
8.233 - private:
8.234 - int patchJumpAt(int at, int to) {
8.235 - assert(at >= 0 && at < position());
8.236 - int old = *(int *)(buffer_ + at + 1);
8.237 - *(int *)(buffer_ + at + 1) = (to - at);
8.238 - return old;
8.239 - }
8.240 -
8.241 - void singleByteOp(Opcode op) {
8.242 - assert(OpcodeInfo[op].length == 1);
8.243 - ensure(OpcodeInfo[op].length);
8.244 - writeOp(op);
8.245 - }
8.246 -
8.247 - // Mark a stack slot as having an object pointer.
8.248 - void markOop(unsigned depth, bool oop = true) {
8.249 - if (oom_)
8.250 - return;
8.251 - oopMap_[oopMap_.length() - depth] = oop;
8.252 - }
8.253 - bool getOop(unsigned depth) {
8.254 - if (oom_)
8.255 - return false;
8.256 - return oopMap_[oopMap_.length() - depth];
8.257 - }
8.258 -
8.259 - // Mark the current bytecode position as either re-entrant (meaning, it
8.260 - // can leave the interpreter or call to another function), or causing GC.
8.261 - // This will record which stack slots have objects and associate that
8.262 - // information with the current pc.
8.263 - void recordOops();
8.264 -
8.265 - public:
8.266 - void int_(int value) {
8.267 - ensure(OP_INT);
8.268 - writeOp(OP_INT);
8.269 - writeInt32(value);
8.270 - }
8.271 - void return_() {
8.272 - ensure(OP_RETURN);
8.273 - writeOp(OP_RETURN);
8.274 - }
8.275 - void getlocal(Variable *var) {
8.276 - ensure(OP_GETLOCAL_LENGTH);
8.277 - writeOp(OP_GETLOCAL);
8.278 - writeUint32(var->slot());
8.279 -
8.280 - if (var->type()->isTraceable())
8.281 - markOop(1);
8.282 - }
8.283 - void setlocal(Variable *var) {
8.284 - ensure(OP_SETLOCAL_LENGTH);
8.285 - writeOp(OP_SETLOCAL);
8.286 - writeUint32(var->slot());
8.287 -
8.288 - if (var->type()->isTraceable())
8.289 - markOop(1);
8.290 - }
8.291 - void getarg(Variable *var) {
8.292 - ensure(OP_GETARG_LENGTH);
8.293 - writeOp(OP_GETARG);
8.294 - writeUint32(var->slot());
8.295 -
8.296 - if (var->type()->isTraceable())
8.297 - markOop(1);
8.298 - }
8.299 - void setarg(Variable *var) {
8.300 - ensure(OP_SETARG_LENGTH);
8.301 - writeOp(OP_SETARG);
8.302 - writeUint32(var->slot());
8.303 -
8.304 - if (var->type()->isTraceable())
8.305 - markOop(1);
8.306 - }
8.307 -
8.308 - void j(Opcode op, Label *label) {
8.309 - // Since jumps can skip around the stream, do not try to do anything
8.310 - // in a potentially truncated state.
8.311 - if (oom())
8.312 - return;
8.313 -
8.314 - assert(op >= OP_JL && op <= OP_JUMP);
8.315 - ensure(OP_JUMP_LENGTH);
8.316 -
8.317 - if (label->bound()) {
8.318 - // We can immediately emit this jump.
8.319 - int distance = label->offset() - position();
8.320 - writeOp(op);
8.321 - writeInt32(distance);
8.322 - } else {
8.323 - // We can't emit this jump yet. Add a placeholder.
8.324 - int old = label->link(position());
8.325 - writeOp(op);
8.326 - writeInt32(old);
8.327 - }
8.328 - }
8.329 - void bind(Label *label) {
8.330 - if (oom())
8.331 - return;
8.332 -
8.333 - assert(!label->bound());
8.334 -
8.335 - int offset = label->offset();
8.336 - while (offset != Label::INVALID_OFFSET)
8.337 - offset = patchJumpAt(offset, position());
8.338 -
8.339 - label->bind(position());
8.340 - }
8.341 - void jump(Label *label) {
8.342 - j(OP_JUMP, label);
8.343 - }
8.344 -
8.345 - void binary(Opcode op) {
8.346 - singleByteOp(op);
8.347 - }
8.348 -
8.349 - void pop() {
8.350 - singleByteOp(OP_POP);
8.351 - }
8.352 - void stop() {
8.353 - singleByteOp(OP_STOP);
8.354 - }
8.355 - void call(Handle<Type> fun) {
8.356 - recordOops();
8.357 - ensure(OP_CALL_LENGTH);
8.358 - writeOp(OP_CALL);
8.359 -
8.360 - if (fun->returnType()->isVoid())
8.361 - drop(1);
8.362 - else if (fun->returnType()->isTraceable())
8.363 - markOop(1);
8.364 - }
8.365 - void callnative(unsigned index, unsigned argc) {
8.366 - recordOops();
8.367 - ensure(OP_CALLNATIVE_LENGTH);
8.368 - writeOp(OP_CALLNATIVE);
8.369 - writeUint32(index);
8.370 - writeUint32(argc);
8.371 - }
8.372 -
8.373 - void getelem(Type *type) {
8.374 - singleByteOp(OP_GETELEM);
8.375 -
8.376 - if (type->isTraceable())
8.377 - markOop(1);
8.378 - }
8.379 - void setelem(Type *type) {
8.380 - singleByteOp(OP_SETELEM);
8.381 - }
8.382 -
8.383 - void getfield(unsigned index, Type *type) {
8.384 - ensure(OP_GETFIELD_LENGTH);
8.385 - writeOp(OP_GETFIELD);
8.386 - writeUint32(index);
8.387 -
8.388 - if (type->isTraceable())
8.389 - markOop(1);
8.390 - }
8.391 - void setfield(unsigned index, Type *type) {
8.392 - ensure(OP_SETFIELD_LENGTH);
8.393 - writeOp(OP_SETFIELD);
8.394 - writeUint32(index);
8.395 -
8.396 - if (type->isTraceable())
8.397 - markOop(1);
8.398 - }
8.399 -
8.400 - void getglobal(Variable *var) {
8.401 - ensure(OP_GETGLOBAL_F_LENGTH);
8.402 - if (var->type()->isPrimitive()) {
8.403 - switch (var->type()->primitive()) {
8.404 - case PrimitiveType_Float:
8.405 - writeOp(OP_GETGLOBAL_F);
8.406 - break;
8.407 - default:
8.408 - assert(var->type()->primitive() == PrimitiveType_Int32);
8.409 - writeOp(OP_GETGLOBAL_I);
8.410 - break;
8.411 - }
8.412 - } else {
8.413 - writeOp(OP_GETGLOBAL_O);
8.414 - markOop(1);
8.415 - }
8.416 - writeUint32(var->slot());
8.417 - }
8.418 - void setglobal(Variable *var) {
8.419 - ensure(OP_SETGLOBAL_F_LENGTH);
8.420 - if (var->type()->isPrimitive()) {
8.421 - switch (var->type()->primitive()) {
8.422 - case PrimitiveType_Float:
8.423 - writeOp(OP_SETGLOBAL_F);
8.424 - break;
8.425 - default:
8.426 - assert(var->type()->primitive() == PrimitiveType_Int32);
8.427 - writeOp(OP_SETGLOBAL_I);
8.428 - break;
8.429 - }
8.430 - } else {
8.431 - writeOp(OP_SETGLOBAL_O);
8.432 - }
8.433 - writeUint32(var->slot());
8.434 - }
8.435 -
8.436 - void float_(float value) {
8.437 - ensure(OP_FLOAT_LENGTH);
8.438 - writeOp(OP_FLOAT);
8.439 - writeFloat(value);
8.440 - }
8.441 - void cvt_i2f() {
8.442 - singleByteOp(OP_CVT_I2F);
8.443 - }
8.444 - void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
8.445 - assert(op == OP_NEWFIXED ||
8.446 - op == OP_NEWEMPTY ||
8.447 - op == OP_NEWSIZED);
8.448 -
8.449 - recordOops();
8.450 - ensure(OpcodeInfo[op].length);
8.451 - writeOp(op);
8.452 - writeUint8(tenure);
8.453 - writeObject(map);
8.454 -
8.455 - if (op == OP_NEWSIZED)
8.456 - drop(map->type()->levels());
8.457 -
8.458 - markOop(1);
8.459 - }
8.460 - void newstruct(Handle<Map> map, Heap::Tenure tenure) {
8.461 - recordOops();
8.462 - ensure(OP_NEWSTRUCT_LENGTH);
8.463 - writeOp(OP_NEWSTRUCT);
8.464 - writeUint8(tenure);
8.465 - writeObject(map);
8.466 - markOop(1);
8.467 - }
8.468 - void savelifo(unsigned slot) {
8.469 - ensure(OP_SAVELIFO_LENGTH);
8.470 - writeOp(OP_SAVELIFO);
8.471 - writeUint32(slot);
8.472 - }
8.473 - void unwindlifo(unsigned slot) {
8.474 - ensure(OP_UNWINDLIFO_LENGTH);
8.475 - writeOp(OP_UNWINDLIFO);
8.476 - writeUint32(slot);
8.477 - }
8.478 - void newref(Variable *var) {
8.479 - recordOops();
8.480 - if (var->location() == Variable::STACK) {
8.481 - ensure(OP_VARREF_LIFO_LENGTH);
8.482 - writeOp(OP_VARREF_LIFO);
8.483 - } else {
8.484 - assert(var->location() == Variable::PARAMETER);
8.485 - ensure(OP_ARGREF_LIFO_LENGTH);
8.486 - writeOp(OP_ARGREF_LIFO);
8.487 - }
8.488 - writeUint32(var->slot());
8.489 - markOop(1);
8.490 - }
8.491 -
8.492 - void slotref_lifo() {
8.493 - recordOops();
8.494 - singleByteOp(OP_SLOTREF_LIFO);
8.495 - markOop(1);
8.496 - }
8.497 - void fieldref_lifo(unsigned index) {
8.498 - recordOops();
8.499 - ensure(OP_FIELDREF_LIFO_LENGTH);
8.500 - writeOp(OP_FIELDREF_LIFO);
8.501 - writeUint32(index);
8.502 - markOop(1);
8.503 - }
8.504 - void getref(Type *type) {
8.505 - if (type->pod() == PrimitiveType_Int32) {
8.506 - singleByteOp(OP_GETREF_I);
8.507 - } else {
8.508 - assert(type->pod() == PrimitiveType_Float);
8.509 - singleByteOp(OP_GETREF_F);
8.510 - }
8.511 - }
8.512 - void setref(Type *type) {
8.513 - if (type->pod() == PrimitiveType_Int32) {
8.514 - singleByteOp(OP_SETREF_I);
8.515 - } else {
8.516 - assert(type->pod() == PrimitiveType_Float);
8.517 - singleByteOp(OP_SETREF_F);
8.518 - }
8.519 - }
8.520 - void object(Handle<Object> obj) {
8.521 - ensure(OP_OBJECT_LENGTH);
8.522 - writeOp(OP_OBJECT);
8.523 - writeObject(obj);
8.524 - markOop(1);
8.525 - }
8.526 - void copyarray() {
8.527 - singleByteOp(OP_COPYARRAY);
8.528 - markOop(1);
8.529 - }
8.530 - void copystruct() {
8.531 - singleByteOp(OP_COPYSTRUCT);
8.532 - markOop(1);
8.533 - }
8.534 - void sizeof_() {
8.535 - singleByteOp(OP_SIZEOF);
8.536 - }
8.537 -
8.538 - void dup() {
8.539 - bool oop = getOop(1);
8.540 - singleByteOp(OP_DUP);
8.541 - markOop(1, oop);
8.542 - }
8.543 - void dup2() {
8.544 - bool oop2 = getOop(2);
8.545 - bool oop1 = getOop(1);
8.546 -
8.547 - singleByteOp(OP_DUP2);
8.548 -
8.549 - markOop(2, oop2);
8.550 - markOop(1, oop1);
8.551 - }
8.552 - void swap() {
8.553 - bool oop2 = getOop(2);
8.554 - bool oop1 = getOop(1);
8.555 -
8.556 - singleByteOp(OP_SWAP);
8.557 -
8.558 - markOop(2, oop1);
8.559 - markOop(1, oop2);
8.560 - }
8.561 - void roll3() {
8.562 - bool oop3 = getOop(3);
8.563 - bool oop2 = getOop(2);
8.564 - bool oop1 = getOop(1);
8.565 -
8.566 - singleByteOp(OP_ROLL3);
8.567 -
8.568 - markOop(3, oop2);
8.569 - markOop(2, oop1);
8.570 - markOop(1, oop3);
8.571 - }
8.572 - void pick2() {
8.573 - bool oop2 = getOop(2);
8.574 - bool oop1 = getOop(1);
8.575 -
8.576 - singleByteOp(OP_PICK2);
8.577 -
8.578 - markOop(3, oop2);
8.579 - markOop(2, oop1);
8.580 - markOop(1, oop2);
8.581 - }
8.582 - void pick3() {
8.583 - bool oop3 = getOop(3);
8.584 - bool oop2 = getOop(2);
8.585 - bool oop1 = getOop(1);
8.586 -
8.587 - singleByteOp(OP_PICK3);
8.588 -
8.589 - markOop(4, oop3);
8.590 - markOop(3, oop2);
8.591 - markOop(2, oop1);
8.592 - markOop(1, oop3);
8.593 - }
8.594 -
8.595 - void returnvoid() {
8.596 - singleByteOp(OP_RETURNVOID);
8.597 - }
8.598 - void module() {
8.599 - singleByteOp(OP_MODULE);
8.600 - markOop(1);
8.601 - }
8.602 - void getmodule_fn(unsigned index) {
8.603 - ensure(OP_GETMODULE_FN_LENGTH);
8.604 - writeOp(OP_GETMODULE_FN);
8.605 - writeUint32(index);
8.606 - markOop(1);
8.607 - }
8.608 - void bitnot() {
8.609 - singleByteOp(OP_BITNOT);
8.610 - }
8.611 - void not_() {
8.612 - singleByteOp(OP_NOT);
8.613 - }
8.614 - void not_f() {
8.615 - singleByteOp(OP_NOT_F);
8.616 - }
8.617 - void neg() {
8.618 - singleByteOp(OP_NEG);
8.619 - }
8.620 - void neg_f() {
8.621 - singleByteOp(OP_NEG_F);
8.622 - }
8.623 - void bits_i2f() {
8.624 - singleByteOp(OP_BITS_I2F);
8.625 - }
8.626 - void bits_f2i() {
8.627 - singleByteOp(OP_BITS_F2I);
8.628 - }
8.629 - void true_() {
8.630 - singleByteOp(OP_TRUE);
8.631 - }
8.632 - void false_() {
8.633 - singleByteOp(OP_FALSE);
8.634 - }
8.635 -
8.636 - void tableswitch(int low, int high, Label *def, Label **labels) {
8.637 - unsigned tablesize = TableSwitchEntries(low, high);
8.638 - assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
8.639 -
8.640 - ensure(OP_TABLESWITCH_LENGTH);
8.641 - writeOp(OP_TABLESWITCH);
8.642 - writeInt32(low);
8.643 - writeInt32(high);
8.644 - jump(def);
8.645 -
8.646 - // When labels are patched, we assume each position is a jump. Rather
8.647 - // than hack position offsets to make labels work without actual
8.648 - // incoming jumps, we emit a jump inline.
8.649 - for (unsigned i = 0; i < tablesize; i++)
8.650 - jump(labels[i]);
8.651 - }
8.652 -
8.653 - // Helpers.
8.654 - void get(Variable *var) {
8.655 - if (var->location() == Variable::STACK) {
8.656 - getlocal(var);
8.657 - } else {
8.658 - assert(var->location() == Variable::PARAMETER);
8.659 - getarg(var);
8.660 - }
8.661 - }
8.662 - void set(Variable *var) {
8.663 - assert(!var->type()->isReference());
8.664 - if (var->location() == Variable::STACK) {
8.665 - setlocal(var);
8.666 - } else {
8.667 - assert(var->location() == Variable::PARAMETER);
8.668 - setarg(var);
8.669 - }
8.670 - }
8.671 -};
8.672 -
8.673 -}
8.674 -
8.675 -#endif // _include_bytecode_emitter_h_
9.1 --- a/src/Code.h Mon Sep 17 00:10:01 2012 -0700
9.2 +++ b/src/Code.h Sat Nov 17 18:41:01 2012 -0800
9.3 @@ -24,7 +24,6 @@
9.4 #include "Heap.h"
9.5 #include "Types.h"
9.6 #include "FixedArray.h"
9.7 -#include "Token.h"
9.8
9.9 namespace ke {
9.10
9.11 @@ -40,6 +39,7 @@
9.12 Barriered<ByteArray> bytecode_;
9.13 Barriered<FixedArray> locals_;
9.14 Barriered<FixedArray> objects_;
9.15 + Barriered<FixedArray> strings_;
9.16 Barriered<ByteArray> safepoints_;
9.17 Barriered<ByteArray> sourcemap_;
9.18 unsigned maxStackDepth_;
9.19 @@ -52,9 +52,8 @@
9.20
9.21 public:
9.22 static Code *New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
9.23 - Handle<FixedArray> objects, unsigned maxStackDepth, Handle<Module> module,
9.24 - Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap,
9.25 - unsigned lineNumber);
9.26 + Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
9.27 + Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap);
9.28
9.29 Module *module() {
9.30 return module_;
9.31 @@ -83,8 +82,15 @@
9.32 ByteArray *safepoints() {
9.33 return safepoints_;
9.34 }
9.35 + FixedArray *strings() {
9.36 + return strings_;
9.37 + }
9.38 uint8 *safepointAt(unsigned pcOffset);
9.39
9.40 + void setModule(Handle<Module> module) {
9.41 + module_ = module;
9.42 + }
9.43 +
9.44 unsigned pcToOffset(bytecode *pc) {
9.45 assert(pc >= start() && pc < start() + length());
9.46 return unsigned(pc - start());
9.47 @@ -108,6 +114,9 @@
9.48 static inline size_t offsetOfObjects() {
9.49 return OFFSETOF(Code, objects_);
9.50 }
9.51 + static inline size_t offsetOfStrings() {
9.52 + return OFFSETOF(Code, strings_);
9.53 + }
9.54 static inline size_t offsetOfSafepoints() {
9.55 return OFFSETOF(Code, safepoints_);
9.56 }
10.1 --- a/src/CompileContext.cpp Mon Sep 17 00:10:01 2012 -0700
10.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
10.3 @@ -1,58 +0,0 @@
10.4 -/*
10.5 - * Copyright (C) 2012 David Anderson
10.6 - *
10.7 - * This file is part of JITCraft.
10.8 - *
10.9 - * JITCraft 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 - * Foobar 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 - * JITCraft. If not, see http://www.gnu.org/licenses/.
10.20 - */
10.21 -#include <stdio.h>
10.22 -#include "Scanner.h"
10.23 -#include "CompileContext.h"
10.24 -#include "Zone.h"
10.25 -#include "Spaces-inl.h"
10.26 -#include "Heap-inl.h"
10.27 -
10.28 -using namespace ke;
10.29 -
10.30 -CompileContext::CompileContext(Zone *zone, const char *file)
10.31 - : zone_(zone),
10.32 - failures_(0),
10.33 - file_(file)
10.34 -{
10.35 -}
10.36 -
10.37 -CompileContext::~CompileContext()
10.38 -{
10.39 - if (failures_)
10.40 - zone_->endCompilationErrors();
10.41 -}
10.42 -
10.43 -void
10.44 -CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
10.45 -{
10.46 - if (!failures_)
10.47 - zone_->beginCompilationErrors(file_);
10.48 -
10.49 - zone_->reportCompilationError(msg, pos.line, pos.col, ap);
10.50 -
10.51 - failures_++;
10.52 -}
10.53 -
10.54 -void
10.55 -CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
10.56 -{
10.57 - va_list ap;
10.58 - va_start(ap, msg);
10.59 - reportErrorVa(pos, msg, ap);
10.60 - va_end(ap);
10.61 -}
11.1 --- a/src/CompileContext.h Mon Sep 17 00:10:01 2012 -0700
11.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
11.3 @@ -1,49 +0,0 @@
11.4 -/*
11.5 - * Copyright (C) 2012 David Anderson
11.6 - *
11.7 - * This file is part of JITCraft.
11.8 - *
11.9 - * JITCraft is free software: you can redistribute it and/or modify it under
11.10 - * the terms of the GNU General Public License as published by the Free
11.11 - * Software Foundation, either version 3 of the License, or (at your option)
11.12 - * any later version.
11.13 - *
11.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
11.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11.17 - *
11.18 - * You should have received a copy of the GNU General Public License along with
11.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
11.20 - */
11.21 -#ifndef _include_jitcraft_compile_context_h_
11.22 -#define _include_jitcraft_compile_context_h_
11.23 -
11.24 -#include <stdarg.h>
11.25 -#include "Messages.h"
11.26 -
11.27 -namespace ke {
11.28 -
11.29 -class Zone;
11.30 -struct SourcePosition;
11.31 -
11.32 -class CompileContext
11.33 -{
11.34 - Zone *zone_;
11.35 - unsigned failures_;
11.36 - const char *file_;
11.37 -
11.38 - public:
11.39 - CompileContext(Zone *zone, const char *file);
11.40 - ~CompileContext();
11.41 -
11.42 - void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
11.43 - void reportError(const SourcePosition &pos, Message msg, ...);
11.44 -
11.45 - unsigned failures() const {
11.46 - return failures_;
11.47 - }
11.48 -};
11.49 -
11.50 -}
11.51 -
11.52 -#endif // _include_jitcraft_compile_context_h_
12.1 --- a/src/Environments.cpp Mon Sep 17 00:10:01 2012 -0700
12.2 +++ b/src/Environments.cpp Sat Nov 17 18:41:01 2012 -0800
12.3 @@ -1,19 +1,19 @@
12.4 /*
12.5 * Copyright (C) 2012 David Anderson
12.6 *
12.7 - * This file is part of JITCraft.
12.8 + * This file is part of SourcePawn.
12.9 *
12.10 - * JITCraft is free software: you can redistribute it and/or modify it under
12.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
12.12 * the terms of the GNU General Public License as published by the Free
12.13 * Software Foundation, either version 3 of the License, or (at your option)
12.14 * any later version.
12.15 *
12.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
12.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
12.18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12.19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12.20 *
12.21 * You should have received a copy of the GNU General Public License along with
12.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
12.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
12.24 */
12.25 #include <string.h>
12.26 #include "Utility.h"
12.27 @@ -21,7 +21,7 @@
12.28 #include "Structures.h"
12.29 #include "FixedArray.h"
12.30 #include "Zone.h"
12.31 -#include "NameBinding.h"
12.32 +#include "compiler/NameBinding.h"
12.33 #include "Spaces-inl.h"
12.34 #include "Heap-inl.h"
12.35
12.36 @@ -59,6 +59,7 @@
12.37 return env;
12.38 }
12.39
12.40 +#if 0
12.41 EnvironmentMap *
12.42 EnvironmentMap::New(Zone *zone, unsigned nvars, Variable **vars)
12.43 {
12.44 @@ -98,3 +99,4 @@
12.45
12.46 return map;
12.47 }
12.48 +#endif
12.49 \ No newline at end of file
13.1 --- a/src/Functions.cpp Mon Sep 17 00:10:01 2012 -0700
13.2 +++ b/src/Functions.cpp Sat Nov 17 18:41:01 2012 -0800
13.3 @@ -23,7 +23,7 @@
13.4 using namespace ke;
13.5
13.6 Function *
13.7 -Function::New(Zone *zone, Handle<Code> code, Handle<Type> type, Handle<String> name,
13.8 +Function::New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
13.9 const SourcePosition &pos)
13.10 {
13.11 Function *fun = Function::cast(zone->allocate(MapKind_Function, sizeof(Function), Heap::Tenure_Old));
13.12 @@ -38,14 +38,13 @@
13.13 }
13.14
13.15 Native *
13.16 -Native::New(Zone *zone, Handle<Type> type, Handle<String> name)
13.17 +Native::New(Zone *zone, Handle<FunctionType> type, size_t index)
13.18 {
13.19 Native *fun = Native::cast(zone->allocate(MapKind_Native, sizeof(Native), Heap::Tenure_Old));
13.20 if (!fun)
13.21 return NULL;
13.22
13.23 fun->type_ = type;
13.24 - fun->name_ = name;
13.25 - fun->function_ = NULL;
13.26 + fun->index_ = index;
13.27 return fun;
13.28 }
14.1 --- a/src/Functions.h Mon Sep 17 00:10:01 2012 -0700
14.2 +++ b/src/Functions.h Sat Nov 17 18:41:01 2012 -0800
14.3 @@ -20,31 +20,30 @@
14.4
14.5 #include "Heap.h"
14.6 #include "Barriers.h"
14.7 -#include "Token.h"
14.8 #include "Types.h"
14.9 +#include "Opcodes.h"
14.10
14.11 namespace ke {
14.12
14.13 class Code;
14.14 class Module;
14.15 -class Type;
14.16 class String;
14.17
14.18 class Function : public Object
14.19 {
14.20 Barriered<Code> code_;
14.21 - Barriered<Type> type_;
14.22 + Barriered<FunctionType> type_;
14.23 Barriered<String> name_;
14.24 SourcePosition pos_;
14.25
14.26 public:
14.27 - static Function *New(Zone *zone, Handle<Code> code, Handle<Type> type, Handle<String> name,
14.28 + static Function *New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
14.29 const SourcePosition &pos);
14.30
14.31 Code *code() const {
14.32 return code_;
14.33 }
14.34 - Type *type() const {
14.35 + FunctionType *type() const {
14.36 return type_;
14.37 }
14.38 String *name() const {
14.39 @@ -82,33 +81,25 @@
14.40 // for earlier ISourcePawnEngine API compatibility.
14.41 class Native : public Object
14.42 {
14.43 - Barriered<Type> type_;
14.44 - Barriered<String> name_;
14.45 - void *function_;
14.46 + Barriered<FunctionType> type_;
14.47 +
14.48 + // Index into the Zone's native table.
14.49 + size_t index_;
14.50
14.51 public:
14.52 - static Native *New(Zone *zone, Handle<Type> type, Handle<String> name);
14.53 + static Native *New(Zone *zone, Handle<FunctionType> type, size_t index);
14.54
14.55 - void *function() {
14.56 - return function_;
14.57 - }
14.58 - Type *type() {
14.59 + FunctionType *type() {
14.60 return type_;
14.61 }
14.62 - String *name() {
14.63 - return name_;
14.64 - }
14.65 - void bind(void *function) {
14.66 - function_ = function;
14.67 + size_t index() const {
14.68 + return index_;
14.69 }
14.70
14.71 // Begin GC Descriptor.
14.72 static inline size_t offsetOfType() {
14.73 return OFFSETOF(Native, type_);
14.74 }
14.75 - static inline size_t offsetOfName() {
14.76 - return OFFSETOF(Native, name_);
14.77 - }
14.78 // End GC Descriptor.
14.79
14.80 static inline Native *cast(Object *obj) {
15.1 --- a/src/GlobalRoots.cpp Mon Sep 17 00:10:01 2012 -0700
15.2 +++ b/src/GlobalRoots.cpp Sat Nov 17 18:41:01 2012 -0800
15.3 @@ -52,7 +52,7 @@
15.4 }
15.5
15.6 HeapRoot *
15.7 -GlobalRoots::create(Handle<Object> obj)
15.8 +GlobalRoots::create()
15.9 {
15.10 HeapRoot *root = new HeapRoot();
15.11 if (!root) {
15.12 @@ -60,25 +60,15 @@
15.13 return NULL;
15.14 }
15.15
15.16 - root->obj = obj;
15.17 - root->refcount = 1;
15.18 + root->obj = NULL;
15.19
15.20 roots_.append(root);
15.21 return root;
15.22 }
15.23
15.24 void
15.25 -GlobalRoots::incref(HeapRoot *root)
15.26 +GlobalRoots::destroy(HeapRoot *root)
15.27 {
15.28 - root->refcount++;
15.29 + roots_.remove(root);
15.30 + delete root;
15.31 }
15.32 -
15.33 -void
15.34 -GlobalRoots::decref(HeapRoot *root)
15.35 -{
15.36 - assert(root->refcount > 0);
15.37 - if (--root->refcount == 0) {
15.38 - roots_.remove(root);
15.39 - delete root;
15.40 - }
15.41 -}
16.1 --- a/src/GlobalRoots.h Mon Sep 17 00:10:01 2012 -0700
16.2 +++ b/src/GlobalRoots.h Sat Nov 17 18:41:01 2012 -0800
16.3 @@ -33,7 +33,6 @@
16.4 {
16.5 public:
16.6 Object *obj;
16.7 - intptr_t refcount;
16.8 };
16.9
16.10 class GlobalRoots
16.11 @@ -46,11 +45,8 @@
16.12
16.13 bool initialize();
16.14
16.15 - // The caller must immediately incref this.
16.16 - HeapRoot *create(Handle<Object> ptr);
16.17 -
16.18 - void incref(HeapRoot *root);
16.19 - void decref(HeapRoot *root);
16.20 + HeapRoot *create();
16.21 + void destroy(HeapRoot *root);
16.22
16.23 void accept(VirtualObjectVisitor *visitor);
16.24
17.1 --- a/src/Handles.h Mon Sep 17 00:10:01 2012 -0700
17.2 +++ b/src/Handles.h Sat Nov 17 18:41:01 2012 -0800
17.3 @@ -29,6 +29,11 @@
17.4 template <typename T> class Local;
17.5 template <typename T> class ScopedRoot;
17.6
17.7 +struct NullAddress
17.8 +{
17.9 + static void * const Sentinel;
17.10 +};
17.11 +
17.12 /*
17.13 * Internal handles work differently from API handles. An API handle is a
17.14 * root, whereas as an internal handle points to a rooted location. This
17.15 @@ -40,6 +45,12 @@
17.16 {
17.17 T * const *thingp_;
17.18
17.19 + private:
17.20 + Handle()
17.21 + : thingp_(reinterpret_cast<T * const *>(&NullAddress::Sentinel))
17.22 + {
17.23 + }
17.24 +
17.25 public:
17.26 Handle(const Handle &other) {
17.27 thingp_ = other.address();
17.28 @@ -51,6 +62,10 @@
17.29 template <typename S> inline Handle(const Local<S> &local);
17.30 template <typename S> inline Handle(const ScopedRoot<S> &root);
17.31
17.32 + static inline Handle Null() {
17.33 + return Handle();
17.34 + }
17.35 +
17.36 public:
17.37 T *operator ->() {
17.38 return *thingp_;
18.1 --- a/src/HashTable.h Mon Sep 17 00:10:01 2012 -0700
18.2 +++ b/src/HashTable.h Sat Nov 17 18:41:01 2012 -0800
18.3 @@ -127,7 +127,7 @@
18.4 { }
18.5
18.6 Payload * operator ->() {
18.7 - return entry_->payload();
18.8 + return &entry_->payload();
18.9 }
18.10 Payload & operator *() {
18.11 return entry_->payload();
18.12 @@ -421,6 +421,8 @@
18.13 };
18.14 };
18.15
18.16 +
18.17 +
18.18 }
18.19
18.20 #endif // _INCLUDE_KEIMA_HASHTABLE_H_
19.1 --- a/src/Interpreter.cpp Mon Sep 17 00:10:01 2012 -0700
19.2 +++ b/src/Interpreter.cpp Sat Nov 17 18:41:01 2012 -0800
19.3 @@ -26,6 +26,7 @@
19.4 #include "Strings.h"
19.5 #include "Environments.h"
19.6 #include "Structures.h"
19.7 +#include "NativeTable.h"
19.8 #include "Heap-inl.h"
19.9
19.10 using namespace ke;
19.11 @@ -218,7 +219,16 @@
19.12 static void
19.13 GetField(Struct *obj, unsigned index, LocalSlot *vp)
19.14 {
19.15 - Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
19.16 + StructType *type = StructType::cast(obj->map()->type());
19.17 + Descriptor *desc = Descriptor::cast(type->fields()->at(index));
19.18 + GetField(obj, desc, vp);
19.19 +}
19.20 +
19.21 +static void
19.22 +GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
19.23 +{
19.24 + Local<StructType> type(zone, StructType::cast(obj->map()->type()));
19.25 + Local<Descriptor> desc(zone, type->lookupField(name, NULL));
19.26 GetField(obj, desc, vp);
19.27 }
19.28
19.29 @@ -246,7 +256,16 @@
19.30 static void
19.31 SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
19.32 {
19.33 - Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
19.34 + StructType *type = StructType::cast(obj->map()->type());
19.35 + Descriptor *desc = Descriptor::cast(type->fields()->at(index));
19.36 + SetField(zone, obj, desc, v);
19.37 +}
19.38 +
19.39 +static void
19.40 +SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
19.41 +{
19.42 + Local<StructType> type(zone, StructType::cast(obj->map()->type()));
19.43 + Local<Descriptor> desc(zone, type->lookupField(name, NULL));
19.44 SetField(zone, obj, desc, v);
19.45 }
19.46
19.47 @@ -257,7 +276,7 @@
19.48 {
19.49 assert(left->map()->type() == right->map()->type());
19.50
19.51 - Local<Type> type(zone, left->map()->type());
19.52 + Local<StructType> type(zone, StructType::cast(left->map()->type()));
19.53 Local<Struct> leftStruct(zone);
19.54 Local<Struct> rightStruct(zone);
19.55 Local<Array> leftArray(zone);
19.56 @@ -299,6 +318,13 @@
19.57 {
19.58 NativeArgs guard;
19.59
19.60 + void *address = zone->nativeTable()->address(native->index());
19.61 + if (!address) {
19.62 + Local<String> name(zone, zone->nativeTable()->name(native->index()));
19.63 + zone->reportError(Message_NativeNotBound, name->chars());
19.64 + return false;
19.65 + }
19.66 +
19.67 if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
19.68 return false;
19.69
19.70 @@ -308,7 +334,7 @@
19.71 cells[0] = argc;
19.72
19.73 // Pass the formal arguments.
19.74 - Local<Type> type(zone, native->type());
19.75 + Local<FunctionType> type(zone, native->type());
19.76 Local<Type> param(zone);
19.77 for (unsigned i = 0; i < type->parameters()->length(); i++) {
19.78 param = type->parameterAt(i);
19.79 @@ -338,7 +364,7 @@
19.80 }
19.81
19.82 typedef intptr_t (*INVOKE)(void *, intptr_t *);
19.83 - INVOKE invoke = (INVOKE)native->function();
19.84 + INVOKE invoke = (INVOKE)address;
19.85 *result = invoke(identity, cells);
19.86
19.87 return !zone->hasPendingException();
19.88 @@ -399,42 +425,6 @@
19.89 break;
19.90 }
19.91
19.92 -#define RELATIONAL_JUMP(op) \
19.93 - { \
19.94 - int right = POP_I32(top); \
19.95 - int left = POP_I32(top); \
19.96 - if (left op right) { \
19.97 - top.pc += READ_INT32(top.pc); \
19.98 - continue; \
19.99 - } \
19.100 - }
19.101 -
19.102 -case OP_JL:
19.103 - RELATIONAL_JUMP(<);
19.104 - break;
19.105 -
19.106 -case OP_JLE:
19.107 - RELATIONAL_JUMP(<=);
19.108 - break;
19.109 -
19.110 -case OP_JG:
19.111 - RELATIONAL_JUMP(>);
19.112 - break;
19.113 -
19.114 -case OP_JGE:
19.115 - RELATIONAL_JUMP(>=);
19.116 - break;
19.117 -
19.118 -case OP_JEQ:
19.119 - RELATIONAL_JUMP(==);
19.120 - break;
19.121 -
19.122 -case OP_JNE:
19.123 - RELATIONAL_JUMP(!=);
19.124 - break;
19.125 -
19.126 -#undef RELATIONAL_JUMP
19.127 -
19.128 case OP_JT:
19.129 {
19.130 int value = POP_I32(top);
19.131 @@ -455,74 +445,22 @@
19.132 break;
19.133 }
19.134
19.135 -#define RELATIONAL_JUMP_F(op) \
19.136 - { \
19.137 - float right = POP_F(top); \
19.138 - float left = POP_F(top); \
19.139 - if (left op right) { \
19.140 - top.pc += READ_INT32(top.pc); \
19.141 - continue; \
19.142 - } \
19.143 - }
19.144 -
19.145 -case OP_JL_F:
19.146 - RELATIONAL_JUMP_F(<);
19.147 - break;
19.148 -
19.149 -case OP_JLE_F:
19.150 - RELATIONAL_JUMP_F(<=);
19.151 - break;
19.152 -
19.153 -case OP_JG_F:
19.154 - RELATIONAL_JUMP_F(>);
19.155 - break;
19.156 -
19.157 -case OP_JGE_F:
19.158 - RELATIONAL_JUMP_F(>=);
19.159 - break;
19.160 -
19.161 -case OP_JEQ_F:
19.162 - RELATIONAL_JUMP_F(==);
19.163 - break;
19.164 -
19.165 -case OP_JNE_F:
19.166 - RELATIONAL_JUMP_F(!=);
19.167 - break;
19.168 -
19.169 -case OP_JT_F:
19.170 -{
19.171 - float value = POP_F(top);
19.172 - if (value) {
19.173 - top.pc += READ_INT32(top.pc);
19.174 - continue;
19.175 - }
19.176 - break;
19.177 -}
19.178 -
19.179 -case OP_JF_F:
19.180 -{
19.181 - float value = POP_F(top);
19.182 - if (!value) {
19.183 - top.pc += READ_INT32(top.pc);
19.184 - continue;
19.185 - }
19.186 - break;
19.187 -}
19.188 -
19.189 case OP_JUMP:
19.190 top.pc += READ_INT32(top.pc);
19.191 continue;
19.192
19.193 case OP_GETLOCAL:
19.194 {
19.195 - int slot = READ_INT32(top.pc);
19.196 + unsigned slot = READ_UINT32(top.pc);
19.197 + assert(slot < top.fp->code()->nlocals());
19.198 *top.sp++ = locals[slot];
19.199 break;
19.200 }
19.201
19.202 case OP_SETLOCAL:
19.203 {
19.204 - int slot = READ_INT32(top.pc);
19.205 + unsigned slot = READ_UINT32(top.pc);
19.206 + assert(slot < top.fp->code()->nlocals());
19.207 locals[slot] = top.sp[-1];
19.208 break;
19.209 }
19.210 @@ -756,7 +694,7 @@
19.211
19.212 case OP_CALL:
19.213 {
19.214 - Local<Function> newFun(zone, top.sp[-1].fun);
19.215 + Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
19.216 top.sp--;
19.217
19.218 if (!zone->stack().pushInlineFrame(newFun))
19.219 @@ -911,15 +849,6 @@
19.220 break;
19.221 }
19.222
19.223 -case OP_FIELDREF_LIFO:
19.224 -{
19.225 - Local<Struct> obj(zone, Struct::cast(top.sp[-1].obj));
19.226 - top.sp[-1].obj = Reference::NewField(zone, obj, READ_UINT32(top.pc), Heap::Tenure_Stack);
19.227 - if (!top.sp[-1].obj)
19.228 - goto error;
19.229 - break;
19.230 -}
19.231 -
19.232 case OP_GETREF_I:
19.233 {
19.234 top.sp[-1].i32 = top.sp[-1].ref->getInt();
19.235 @@ -1014,14 +943,10 @@
19.236
19.237 case OP_CALLNATIVE:
19.238 {
19.239 - unsigned index = READ_UINT32(top.pc);
19.240 - unsigned argc = READ_UINT32(top.pc + 4);
19.241 + unsigned argc = READ_UINT32(top.pc);
19.242
19.243 - Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
19.244 - if (!native->function()) {
19.245 - zone->reportError(Message_NativeNotBound, native->name()->chars());
19.246 - goto error;
19.247 - }
19.248 + Local<Native> native(zone, Native::cast(top.sp[-1].obj));
19.249 + top.sp--;
19.250
19.251 int result;
19.252 void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
19.253 @@ -1033,64 +958,6 @@
19.254 break;
19.255 }
19.256
19.257 -case OP_MODULE:
19.258 -{
19.259 - top.sp++;
19.260 - top.sp[-1].module = top.fp->code()->module();
19.261 - break;
19.262 -}
19.263 -
19.264 -case OP_GETMODULE_FN:
19.265 -{
19.266 - top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
19.267 - break;
19.268 -}
19.269 -
19.270 -case OP_GETGLOBAL_I:
19.271 -{
19.272 - unsigned slot = READ_UINT32(top.pc);
19.273 - top.sp++;
19.274 - top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot);
19.275 - break;
19.276 -}
19.277 -
19.278 -case OP_GETGLOBAL_F:
19.279 -{
19.280 - unsigned slot = READ_UINT32(top.pc);
19.281 - top.sp++;
19.282 - top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot);
19.283 - break;
19.284 -}
19.285 -
19.286 -case OP_GETGLOBAL_O:
19.287 -{
19.288 - unsigned slot = READ_UINT32(top.pc);
19.289 - top.sp++;
19.290 - top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot);
19.291 - break;
19.292 -}
19.293 -
19.294 -case OP_SETGLOBAL_I:
19.295 -{
19.296 - unsigned slot = READ_UINT32(top.pc);
19.297 - top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32);
19.298 - break;
19.299 -}
19.300 -
19.301 -case OP_SETGLOBAL_F:
19.302 -{
19.303 - unsigned slot = READ_UINT32(top.pc);
19.304 - top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f);
19.305 - break;
19.306 -}
19.307 -
19.308 -case OP_SETGLOBAL_O:
19.309 -{
19.310 - unsigned slot = READ_UINT32(top.pc);
19.311 - top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj);
19.312 - break;
19.313 -}
19.314 -
19.315 case OP_BITS_I2F:
19.316 case OP_BITS_F2I:
19.317 {
19.318 @@ -1165,6 +1032,33 @@
19.319 break;
19.320 }
19.321
19.322 +case OP_PUBLIC:
19.323 +{
19.324 + Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
19.325 + zone->registerPublic(fun);
19.326 + top.sp--;
19.327 + break;
19.328 +}
19.329 +
19.330 +case OP_SETGLOBAL:
19.331 +{
19.332 + Local<Code> code(zone, top.fp->code());
19.333 + Local<Struct> obj(zone, code->module()->globals());
19.334 + Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
19.335 + SetGlobal(zone, obj, name, top.sp[-1]);
19.336 + break;
19.337 +}
19.338 +
19.339 +case OP_GETGLOBAL:
19.340 +{
19.341 + Local<Code> code(zone, top.fp->code());
19.342 + Local<Struct> obj(zone, code->module()->globals());
19.343 + Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
19.344 + GetGlobal(zone, obj, name, top.sp);
19.345 + top.sp++;
19.346 + break;
19.347 +}
19.348 +
19.349 default:
19.350 assert(false);
19.351 return false;
20.1 --- a/src/Messages.tbl Mon Sep 17 00:10:01 2012 -0700
20.2 +++ b/src/Messages.tbl Sat Nov 17 18:41:01 2012 -0800
20.3 @@ -61,7 +61,6 @@
20.4 MSG(IdentifierNotFound, SyntaxError, "identifier '%s' could not be found")
20.5 MSG(TypeMismatchDuringInvoke, TypeError, "incoming type '%s' does not match signature type '%s'")
20.6 MSG(CannotInvokeReturnType, SyntaxError, "cannot invoke function with return type '%s'")
20.7 -MSG(TypeNotFound, SyntaxError, "type '%s' could not be found")
20.8 MSG(IdentifierIsNotAType, SyntaxError, "identifier '%s' cannot be used as a type")
20.9 MSG(TypeMismatch, TypeError, "type mismatch (expected '%s', got '%s')")
20.10 MSG(PropertyNotFound, TypeError, "property '%s' not found on type '%s'")
20.11 @@ -80,4 +79,6 @@
20.12 MSG(CannotComputeIndexRef, SyntaxError, "cannot use an array index as a reference")
20.13 MSG(BadDynamicInitializer, SyntaxError, "dynamic length specified, but preceding array is empty")
20.14 MSG(SizeofNeedsArray, TypeError, "sizeof requires an array")
20.15 -
20.16 +MSG(ImportsMustBeFirst, SyntaxError, "import statements must come before other statements")
20.17 +MSG(ImportedNameAlreadyBound, TypeError, "imported name has already been bound")
20.18 +MSG(CannotResolveImport, TypeError, "cannot resolve import %s")
20.19 \ No newline at end of file
21.1 --- a/src/Modules.cpp Mon Sep 17 00:10:01 2012 -0700
21.2 +++ b/src/Modules.cpp Sat Nov 17 18:41:01 2012 -0800
21.3 @@ -23,21 +23,15 @@
21.4 using namespace ke;
21.5
21.6 Module *
21.7 -Module::New(Zone *zone, unsigned nfunctions)
21.8 +Module::New(Zone *zone)
21.9 {
21.10 Local<Module> module(zone, Module::cast(zone->allocate(MapKind_Module, sizeof(Module), Heap::Tenure_Old)));
21.11 if (!module)
21.12 return NULL;
21.13
21.14 - Local<FixedArray> functions(zone, FixedArray::New(zone, nfunctions, Heap::Tenure_Old));
21.15 - if (!functions)
21.16 - return NULL;
21.17 -
21.18 - module->functions_ = functions;
21.19 module->file_ = NULL;
21.20 - module->publics_ = NULL;
21.21 - module->natives_ = NULL;
21.22 - module->environment_ = NULL;
21.23 + module->globals_ = NULL;
21.24 module->nativeIdentity_ = NULL;
21.25 + module->globals_ = NULL;
21.26 return module;
21.27 }
22.1 --- a/src/Modules.h Mon Sep 17 00:10:01 2012 -0700
22.2 +++ b/src/Modules.h Sat Nov 17 18:41:01 2012 -0800
22.3 @@ -25,60 +25,37 @@
22.4 namespace ke {
22.5
22.6 class Environment;
22.7 +class Struct;
22.8
22.9 class Module : public Object
22.10 {
22.11 - Barriered<FixedArray> functions_;
22.12 - Barriered<FixedArray> publics_;
22.13 - Barriered<FixedArray> natives_;
22.14 Barriered<String> file_;
22.15 - Barriered<Environment> environment_;
22.16 Barriered<Code> code_;
22.17 + Barriered<Struct> globals_;
22.18 void *nativeIdentity_;
22.19
22.20 public:
22.21 - static Module *New(Zone *zone, unsigned nfunctions);
22.22 -
22.23 - Function *getFunction(size_t i) {
22.24 - return Function::cast(functions_->at(i));
22.25 - }
22.26 - void setFunction(Zone *zone, size_t i, Function *fun) {
22.27 - assert(!functions_->at(i));
22.28 - assert(fun);
22.29 - functions_->set(zone, i, fun);
22.30 - }
22.31 -
22.32 - FixedArray *publics() {
22.33 - return publics_;
22.34 - }
22.35 - FixedArray *natives() {
22.36 - return natives_;
22.37 - }
22.38 + static Module *New(Zone *zone);
22.39 +
22.40 String *file() {
22.41 return file_;
22.42 }
22.43 - Environment *environment() {
22.44 - return environment_;
22.45 - }
22.46 Code *code() {
22.47 return code_;
22.48 }
22.49 -
22.50 - void setPublics(Handle<FixedArray> publics) {
22.51 - publics_ = publics;
22.52 + Struct *globals() {
22.53 + return globals_;
22.54 }
22.55 - void setNatives(Handle<FixedArray> natives) {
22.56 - natives_ = natives;
22.57 - }
22.58 +
22.59 void setPath(Handle<String> path) {
22.60 file_ = path;
22.61 }
22.62 - void setEnvironment(Handle<Environment> environment) {
22.63 - environment_ = environment;
22.64 - }
22.65 void setCode(Handle<Code> code) {
22.66 code_ = code;
22.67 }
22.68 + void setGlobals(Handle<Struct> globals) {
22.69 + globals_ = globals;
22.70 + }
22.71
22.72 void *nativeIdentity() {
22.73 return nativeIdentity_;
22.74 @@ -88,24 +65,15 @@
22.75 }
22.76
22.77 // Begin GC Descriptor.
22.78 - static inline size_t offsetOfFunctions() {
22.79 - return OFFSETOF(Module, functions_);
22.80 - }
22.81 - static inline size_t offsetOfPublics() {
22.82 - return OFFSETOF(Module, publics_);
22.83 - }
22.84 - static inline size_t offsetOfNatives() {
22.85 - return OFFSETOF(Module, natives_);
22.86 - }
22.87 static inline size_t offsetOfFile() {
22.88 return OFFSETOF(Module, file_);
22.89 }
22.90 - static inline size_t offsetOfEnvironment() {
22.91 - return OFFSETOF(Module, environment_);
22.92 - }
22.93 static inline size_t offsetOfCode() {
22.94 return OFFSETOF(Module, code_);
22.95 }
22.96 + static inline size_t offsetOfGlobals() {
22.97 + return OFFSETOF(Module, globals_);
22.98 + }
22.99 // End GC Descriptor.
22.100
22.101 static inline Module *cast(Object *obj) {
23.1 --- a/src/NameBinding.cpp Mon Sep 17 00:10:01 2012 -0700
23.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
23.3 @@ -1,57 +0,0 @@
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 SourcePawn.
23.9 - *
23.10 - * SourcePawn 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 - * SourcePawn 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 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
23.21 - */
23.22 -#include "NameBinding.h"
23.23 -#include "Strings.h"
23.24 -#include "Zone.h"
23.25 -#include "Scopes.h"
23.26 -#include "Spaces-inl.h"
23.27 -#include "Heap-inl.h"
23.28 -
23.29 -using namespace ke;
23.30 -
23.31 -BoundName::BoundName(Scope *scope, Handle<String> name, const SourcePosition &pos)
23.32 - : scope_(scope),
23.33 - name_(name),
23.34 - type_(NULL),
23.35 - used_(false),
23.36 - pos_(pos)
23.37 -{
23.38 -}
23.39 -
23.40 -NamedFunction::NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos,
23.41 - TokenKind token)
23.42 - : BoundName(scope, name, pos),
23.43 - token_(token),
23.44 - isVariadicNative_(false)
23.45 -{
23.46 -}
23.47 -
23.48 -Variable::Variable(Scope *scope, Handle<String> name, const SourcePosition &pos)
23.49 - : BoundName(scope, name, pos),
23.50 - location_(UNALLOCATED),
23.51 - public_(false)
23.52 -{
23.53 -}
23.54 -
23.55 -bool
23.56 -Variable::needsHeapAllocation()
23.57 -{
23.58 - return scope()->kind() == Scope::GLOBAL;
23.59 -}
23.60 -
24.1 --- a/src/NameBinding.h Mon Sep 17 00:10:01 2012 -0700
24.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
24.3 @@ -1,257 +0,0 @@
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 SourcePawn.
24.9 - *
24.10 - * SourcePawn 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 - * SourcePawn 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 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
24.21 - */
24.22 -#ifndef _include_name_binding_h_
24.23 -#define _include_name_binding_h_
24.24 -
24.25 -#include "PoolAllocator.h"
24.26 -#include "Types.h"
24.27 -#include "Scanner.h"
24.28 -
24.29 -namespace ke {
24.30 -
24.31 -class Variable;
24.32 -class NamedFunction;
24.33 -class Scope;
24.34 -class Type;
24.35 -class NamedConstant;
24.36 -class NamedType;
24.37 -class UnboundName;
24.38 -class String;
24.39 -
24.40 -class BoundName : public PoolObject
24.41 -{
24.42 - Scope *scope_;
24.43 - ScopedRoot<String> name_;
24.44 - ScopedRoot<Type> type_;
24.45 - bool used_;
24.46 -
24.47 - protected:
24.48 - SourcePosition pos_;
24.49 -
24.50 - public:
24.51 - enum Kind {
24.52 - VARIABLE,
24.53 - FUNCTION,
24.54 - CONSTANT,
24.55 - TYPE,
24.56 - UNBOUND
24.57 - };
24.58 -
24.59 - BoundName(Scope *scope, Handle<String> name, const SourcePosition &pos);
24.60 -
24.61 - virtual Kind kind() const = 0;
24.62 -
24.63 - String *name() const {
24.64 - return name_;
24.65 - }
24.66 - Scope *scope() const {
24.67 - return scope_;
24.68 - }
24.69 - Variable *toVariable() {
24.70 - assert(kind() == VARIABLE);
24.71 - return reinterpret_cast<Variable *>(this);
24.72 - }
24.73 - NamedFunction *toNamedFunction() {
24.74 - assert(kind() == FUNCTION);
24.75 - return reinterpret_cast<NamedFunction *>(this);
24.76 - }
24.77 - NamedConstant *toNamedConstant() {
24.78 - assert(kind() == CONSTANT);
24.79 - return reinterpret_cast<NamedConstant *>(this);
24.80 - }
24.81 - NamedType *toNamedType() {
24.82 - assert(kind() == TYPE);
24.83 - return reinterpret_cast<NamedType *>(this);
24.84 - }
24.85 - Type *type() const {
24.86 - return type_;
24.87 - }
24.88 - void setType(Handle<Type> type) {
24.89 - type_ = type;
24.90 - }
24.91 - void setUsed() {
24.92 - used_ = true;
24.93 - }
24.94 - bool used() const {
24.95 - return used_;
24.96 - }
24.97 - const SourcePosition &pos() {
24.98 - return pos_;
24.99 - }
24.100 -};
24.101 -
24.102 -class NamedFunction : public BoundName
24.103 -{
24.104 - unsigned slot_;
24.105 - TokenKind token_;
24.106 - ScopedRoot<Type> forwardType_;
24.107 - bool isVariadicNative_;
24.108 - Vector<BoundName *, PoolAllocationPolicy> globals_;
24.109 -
24.110 - public:
24.111 - NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos, TokenKind token);
24.112 -
24.113 - Kind kind() const {
24.114 - return FUNCTION;
24.115 - }
24.116 - void allocate(unsigned slot) {
24.117 - slot_ = slot;
24.118 - }
24.119 - bool isForward() const {
24.120 - return token_ == TOK_FORWARD;
24.121 - }
24.122 - bool isPublic() const {
24.123 - return token_ == TOK_PUBLIC;
24.124 - }
24.125 - bool isNative() const {
24.126 - return token_ == TOK_NATIVE;
24.127 - }
24.128 - TokenKind token() const {
24.129 - return token_;
24.130 - }
24.131 - void setForwardType(Handle<Type> type) {
24.132 - forwardType_ = type;
24.133 - }
24.134 - Type *forwardType() {
24.135 - return forwardType_;
24.136 - }
24.137 - void setImplemented(const SourcePosition &at) {
24.138 - token_ = TOK_PUBLIC;
24.139 - pos_ = at;
24.140 - }
24.141 - void markNativeVariadic() {
24.142 - assert(token_ == TOK_NATIVE);
24.143 - isVariadicNative_ = true;
24.144 - }
24.145 - bool isNativeVariadic() {
24.146 - assert(token_ == TOK_NATIVE);
24.147 - return isVariadicNative_;
24.148 - }
24.149 - unsigned slot() const {
24.150 - return slot_;
24.151 - }
24.152 - bool addUsedGlobal(BoundName *name) {
24.153 - return globals_.append(name);
24.154 - }
24.155 - Vector<BoundName *, PoolAllocationPolicy> *usedGlobals() {
24.156 - return &globals_;
24.157 - }
24.158 -};
24.159 -
24.160 -class NamedConstant : public BoundName
24.161 -{
24.162 - BoxedPrimitive value_;
24.163 -
24.164 - public:
24.165 - NamedConstant(Scope *scope, Handle<String> name, const SourcePosition &pos)
24.166 - : BoundName(scope, name, pos)
24.167 - {
24.168 - }
24.169 -
24.170 - Kind kind() const {
24.171 - return CONSTANT;
24.172 - }
24.173 - void set(Handle<Type> type, const BoxedPrimitive &value) {
24.174 - value_ = value;
24.175 - setType(type);
24.176 - }
24.177 - BoxedPrimitive value() const {
24.178 - return value_;
24.179 - }
24.180 -};
24.181 -
24.182 -class NamedType : public BoundName
24.183 -{
24.184 - public:
24.185 - NamedType(Scope *scope, Handle<String> name, Handle<Type> type)
24.186 - : BoundName(scope, name, SourcePosition())
24.187 - {
24.188 - setType(type);
24.189 - }
24.190 -
24.191 - NamedType(Scope *scope, Handle<String> name, const SourcePosition &pos)
24.192 - : BoundName(scope, name, pos)
24.193 - {
24.194 - }
24.195 -
24.196 - Kind kind() const {
24.197 - return TYPE;
24.198 - }
24.199 -};
24.200 -
24.201 -class UnboundName : public BoundName
24.202 -{
24.203 - public:
24.204 - UnboundName(Scope *scope, Handle<String> name)
24.205 - : BoundName(scope, name, SourcePosition())
24.206 - {
24.207 - }
24.208 -
24.209 - Kind kind() const {
24.210 - return UNBOUND;
24.211 - }
24.212 -};
24.213 -
24.214 -class Variable : public BoundName
24.215 -{
24.216 - public:
24.217 - enum Location {
24.218 - UNALLOCATED,
24.219 - STACK,
24.220 - PARAMETER,
24.221 - ENVIRONMENT
24.222 - };
24.223 -
24.224 - Variable(Scope *scope, Handle<String> name, const SourcePosition &pos);
24.225 -
24.226 - Kind kind() const {
24.227 - return VARIABLE;
24.228 - }
24.229 - bool unallocated() const {
24.230 - return location() == UNALLOCATED;
24.231 - }
24.232 - void allocate(Location location, unsigned slot) {
24.233 - location_ = location;
24.234 - slot_ = slot;
24.235 - }
24.236 - Location location() const {
24.237 - return location_;
24.238 - }
24.239 - unsigned slot() const {
24.240 - assert(!unallocated());
24.241 - return slot_;
24.242 - }
24.243 - void setPublic() {
24.244 - assert(!public_);
24.245 - public_ = true;
24.246 - }
24.247 - bool isPublic() const {
24.248 - return public_;
24.249 - }
24.250 - bool needsHeapAllocation();
24.251 -
24.252 - private:
24.253 - Location location_;
24.254 - unsigned slot_;
24.255 - bool public_;
24.256 -};
24.257 -
24.258 -}
24.259 -
24.260 -#endif // _include_name_binding_h_
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/src/NativeTable.cpp Sat Nov 17 18:41:01 2012 -0800
25.3 @@ -0,0 +1,96 @@
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 SourcePawn.
25.9 + *
25.10 + * SourcePawn 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 + * SourcePawn 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 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
25.21 + */
25.22 +#include "Zone.h"
25.23 +#include "NativeTable.h"
25.24 +#include "StringPool.h"
25.25 +
25.26 +using namespace ke;
25.27 +
25.28 +NativeTable::NativeTable(Zone *zone)
25.29 + : zone_(zone),
25.30 + nativeMap_(ZoneAllocatorPolicy())
25.31 +{
25.32 +}
25.33 +
25.34 +NativeTable::~NativeTable()
25.35 +{
25.36 + for (size_t i = 0; i < natives_.length(); i++)
25.37 + delete natives_[i];
25.38 +}
25.39 +
25.40 +bool
25.41 +NativeTable::initialize()
25.42 +{
25.43 + return nativeMap_.init(16);
25.44 +}
25.45 +
25.46 +bool
25.47 +NativeTable::add(Handle<String> name, size_t *indexp)
25.48 +{
25.49 + // :TODO: assert no GC
25.50 + CharsAndLength key(name->chars(), name->length());
25.51 + NativeMap::Insert p = nativeMap_.findForAdd(key);
25.52 + if (p.found()) {
25.53 + *indexp = (*p)->index;
25.54 + return true;
25.55 + }
25.56 +
25.57 + NativeInfo *info = new NativeInfo(name, NULL, natives_.length());
25.58 + if (!info || !natives_.append(info))
25.59 + return false;
25.60 +
25.61 + if (!nativeMap_.add(p, info))
25.62 + return false;
25.63 +
25.64 + *indexp = info->index;
25.65 +
25.66 + return true;
25.67 +}
25.68 +
25.69 +bool
25.70 +NativeTable::bind(const char *name, void *address)
25.71 +{
25.72 + CharsAndLength key(name, strlen(name));
25.73 + NativeMap::Insert p = nativeMap_.findForAdd(key);
25.74 + if (p.found()) {
25.75 + (*p)->address = address;
25.76 + return true;
25.77 + }
25.78 +
25.79 + Local<String> str(zone_, zone_->symbols()->add(key.str(), key.length()));
25.80 + if (!str)
25.81 + return false;
25.82 +
25.83 + // :TODO: assert no GC
25.84 + NativeInfo *info = new NativeInfo(str, address, natives_.length());
25.85 + if (!info || !natives_.append(info))
25.86 + return false;
25.87 +
25.88 + if (!nativeMap_.add(p, info))
25.89 + return false;
25.90 +
25.91 + return true;
25.92 +}
25.93 +
25.94 +void
25.95 +NativeTable::accept(VirtualObjectVisitor *visitor)
25.96 +{
25.97 + for (size_t i = 0; i < natives_.length(); i++)
25.98 + visitor->visit(natives_[i]->name.address());
25.99 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/src/NativeTable.h Sat Nov 17 18:41:01 2012 -0800
26.3 @@ -0,0 +1,89 @@
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_sp2_native_table_h_
26.23 +#define _include_sp2_native_table_h_
26.24 +
26.25 +#include "AllocatorPolicies.h"
26.26 +#include "Strings.h"
26.27 +#include "HashTable.h"
26.28 +#include "Vector.h"
26.29 +#include "VirtualObjectVisitor.h"
26.30 +
26.31 +namespace ke {
26.32 +
26.33 +class NativeTable
26.34 +{
26.35 + public:
26.36 + NativeTable(Zone *zone);
26.37 + ~NativeTable();
26.38 +
26.39 + private:
26.40 + struct NativeInfo {
26.41 + Unbarriered<String> name;
26.42 + void *address;
26.43 + size_t index;
26.44 +
26.45 + NativeInfo(String *name, void *address, size_t index)
26.46 + : address(address),
26.47 + index(index)
26.48 + {
26.49 + this->name = name;
26.50 + }
26.51 + };
26.52 +
26.53 + struct Policy
26.54 + {
26.55 + typedef NativeInfo * Payload;
26.56 +
26.57 + static uint32 hash(const CharsAndLength &key) {
26.58 + return HashCharSequence(key.str(), key.length());
26.59 + }
26.60 +
26.61 + static bool matches(const CharsAndLength &key, NativeInfo *info) {
26.62 + if (info->name->length() != key.length())
26.63 + return false;
26.64 + return memcmp(info->name->chars(), key.str(), key.length() * sizeof(char)) == 0;
26.65 + }
26.66 + };
26.67 +
26.68 + typedef HashTable<Policy, ZoneAllocatorPolicy> NativeMap;
26.69 +
26.70 + public:
26.71 + bool initialize();
26.72 +
26.73 + bool bind(const char *name, void *address);
26.74 + bool add(Handle<String> name, size_t *indexp);
26.75 + String *name(size_t index) const {
26.76 + return natives_[index]->name;
26.77 + }
26.78 + void *address(size_t index) const {
26.79 + return natives_[index]->address;
26.80 + }
26.81 +
26.82 + void accept(VirtualObjectVisitor *visitor);
26.83 +
26.84 + private:
26.85 + Zone *zone_;
26.86 + NativeMap nativeMap_;
26.87 + Vector<NativeInfo *> natives_;
26.88 +};
26.89 +
26.90 +}
26.91 +
26.92 +#endif // _include_sp2_native_table_h_
27.1 --- a/src/ObjectVisitor.h Mon Sep 17 00:10:01 2012 -0700
27.2 +++ b/src/ObjectVisitor.h Sat Nov 17 18:41:01 2012 -0800
27.3 @@ -47,13 +47,25 @@
27.4
27.5 size_t iterateType(Object *obj) {
27.6 visitField(obj, Type::offsetOfContained());
27.7 - visitField(obj, Type::offsetOfReturnType());
27.8 - visitField(obj, Type::offsetOfParameters());
27.9 + visitField(obj, Type::offsetOfName());
27.10 + return sizeof(Type);
27.11 + }
27.12 +
27.13 + size_t iterateStructType(Object *obj) {
27.14 + visitField(obj, Type::offsetOfContained());
27.15 visitField(obj, Type::offsetOfName());
27.16 - visitField(obj, Type::offsetOfFields());
27.17 - visitField(obj, Type::offsetOfDefaults());
27.18 - visitField(obj, Type::offsetOfNewMap());
27.19 - return sizeof(Type);
27.20 + visitField(obj, StructType::offsetOfFields());
27.21 + visitField(obj, StructType::offsetOfNewMap());
27.22 + return sizeof(StructType);
27.23 + }
27.24 +
27.25 + size_t iterateFunctionType(Object *obj) {
27.26 + visitField(obj, Type::offsetOfContained());
27.27 + visitField(obj, Type::offsetOfName());
27.28 + visitField(obj, FunctionType::offsetOfReturnType());
27.29 + visitField(obj, FunctionType::offsetOfParameters());
27.30 + visitField(obj, FunctionType::offsetOfDefaults());
27.31 + return sizeof(FunctionType);
27.32 }
27.33
27.34 size_t iterateFixedArray(FixedArray *array) {
27.35 @@ -75,6 +87,7 @@
27.36 visitField(obj, Code::offsetOfObjects());
27.37 visitField(obj, Code::offsetOfSafepoints());
27.38 visitField(obj, Code::offsetOfSourceMap());
27.39 + visitField(obj, Code::offsetOfStrings());
27.40 return sizeof(Code);
27.41 }
27.42
27.43 @@ -84,11 +97,8 @@
27.44 }
27.45
27.46 size_t iterateModule(Object *obj) {
27.47 - visitField(obj, Module::offsetOfFunctions());
27.48 - visitField(obj, Module::offsetOfPublics());
27.49 - visitField(obj, Module::offsetOfNatives());
27.50 visitField(obj, Module::offsetOfFile());
27.51 - visitField(obj, Module::offsetOfEnvironment());
27.52 + visitField(obj, Module::offsetOfGlobals());
27.53 visitField(obj, Module::offsetOfCode());
27.54 return sizeof(Module);
27.55 }
27.56 @@ -108,7 +118,6 @@
27.57
27.58 size_t iterateNative(Object *obj) {
27.59 visitField(obj, Native::offsetOfType());
27.60 - visitField(obj, Native::offsetOfName());
27.61 return sizeof(Native);
27.62 }
27.63
27.64 @@ -182,6 +191,12 @@
27.65 case MapKind_Type:
27.66 return iterateType(obj);
27.67
27.68 + case MapKind_FunctionType:
27.69 + return iterateFunctionType(obj);
27.70 +
27.71 + case MapKind_StructType:
27.72 + return iterateStructType(obj);
27.73 +
27.74 case MapKind_FixedArray:
27.75 return iterateFixedArray(FixedArray::cast(obj));
27.76
27.77 @@ -256,6 +271,12 @@
27.78 case MapKind_Type:
27.79 return sizeof(Type);
27.80
27.81 + case MapKind_FunctionType:
27.82 + return sizeof(FunctionType);
27.83 +
27.84 + case MapKind_StructType:
27.85 + return sizeof(StructType);
27.86 +
27.87 case MapKind_FixedArray:
27.88 return FixedArray::cast(obj)->objSize();
27.89
28.1 --- a/src/Objects.h Mon Sep 17 00:10:01 2012 -0700
28.2 +++ b/src/Objects.h Sat Nov 17 18:41:01 2012 -0800
28.3 @@ -35,6 +35,8 @@
28.4 {
28.5 // Represents Type objects.
28.6 MapKind_Type,
28.7 + MapKind_FunctionType,
28.8 + MapKind_StructType,
28.9
28.10 // Represents basic data structures. When adding to this, don't forget
28.11 // to update Zone::initialize(), or you'll get a NULL crash trying to
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/src/OldByCo.cpp Sat Nov 17 18:41:01 2012 -0800
29.3 @@ -0,0 +1,1585 @@
29.4 +/* vim: set ts=4 sw=4 tw=99 et:
29.5 + *
29.6 + * Copyright (C) 2012 David Anderson
29.7 + *
29.8 + * This file is part of JITCraft.
29.9 + *
29.10 + * JITCraft is free software: you can redistribute it and/or modify it under
29.11 + * the terms of the GNU General Public License as published by the Free
29.12 + * Software Foundation, either version 3 of the License, or (at your option)
29.13 + * any later version.
29.14 + *
29.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
29.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
29.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
29.18 + *
29.19 + * You should have received a copy of the GNU General Public License along with
29.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
29.21 + */
29.22 +#include <string.h>
29.23 +#include "../Modules.h"
29.24 +#include "../Types.h"
29.25 +#include "../Array.h"
29.26 +#include "../Strings.h"
29.27 +#include "../Zone.h"
29.28 +#include "../Environments.h"
29.29 +#include "../Box.h"
29.30 +#include "../Heap-inl.h"
29.31 +#include "BytecodeCompiler.h"
29.32 +#include "Scopes.h"
29.33 +
29.34 +using namespace ke;
29.35 +
29.36 +typedef BytecodeEmitter::Label Label;
29.37 +
29.38 +#define __ emitter_.
29.39 +
29.40 +BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
29.41 + : zone_(zone),
29.42 + tree_(tree),
29.43 + emitter_(zone->pool()),
29.44 + locals_(NULL),
29.45 + scope_(NULL),
29.46 + moduleData_(module),
29.47 + loop_(NULL)
29.48 +{
29.49 +}
29.50 +
29.51 +static inline TokenKind
29.52 +ToCompare(Expression *expr)
29.53 +{
29.54 + if (expr->isBinaryExpression()) {
29.55 + BinaryExpression *b = expr->toBinaryExpression();
29.56 + if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
29.57 + return b->token();
29.58 + } else if (expr->isUnaryExpression()) {
29.59 + UnaryExpression *u = expr->toUnaryExpression();
29.60 + if (u->token() == TOK_NOT)
29.61 + return TOK_NOT;
29.62 + }
29.63 + return TOK_EOF;
29.64 +}
29.65 +
29.66 +static inline Opcode
29.67 +CompareTokenToJump(TokenKind kind)
29.68 +{
29.69 + switch (kind) {
29.70 + case TOK_EQUALS:
29.71 + return OP_JEQ;
29.72 + case TOK_NOTEQUALS:
29.73 + return OP_JNE;
29.74 + case TOK_GT:
29.75 + return OP_JG;
29.76 + case TOK_GE:
29.77 + return OP_JGE;
29.78 + case TOK_LT:
29.79 + return OP_JL;
29.80 + default:
29.81 + assert(kind == TOK_LE);
29.82 + return OP_JLE;
29.83 + }
29.84 +}
29.85 +
29.86 +static inline Opcode
29.87 +TokenToOpcode(TokenKind kind)
29.88 +{
29.89 + switch (kind) {
29.90 + case TOK_PLUS:
29.91 + return OP_ADD;
29.92 + case TOK_MINUS:
29.93 + return OP_SUB;
29.94 + case TOK_STAR:
29.95 + return OP_MUL;
29.96 + case TOK_SLASH:
29.97 + return OP_DIV;
29.98 + case TOK_PERCENT:
29.99 + return OP_MOD;
29.100 + case TOK_SHR:
29.101 + return OP_SHR;
29.102 + case TOK_USHR:
29.103 + return OP_USHR;
29.104 + case TOK_SHL:
29.105 + return OP_SHL;
29.106 + case TOK_BITAND:
29.107 + return OP_BITAND;
29.108 + case TOK_BITOR:
29.109 + return OP_BITOR;
29.110 + case TOK_GT:
29.111 + return OP_GT;
29.112 + case TOK_GE:
29.113 + return OP_GE;
29.114 + case TOK_LT:
29.115 + return OP_LT;
29.116 + case TOK_LE:
29.117 + return OP_LE;
29.118 + case TOK_EQUALS:
29.119 + return OP_EQ;
29.120 + case TOK_NOTEQUALS:
29.121 + return OP_NE;
29.122 + default:
29.123 + assert(kind == TOK_BITXOR);
29.124 + return OP_BITXOR;
29.125 + }
29.126 +}
29.127 +
29.128 +void
29.129 +BytecodeCompiler::recordLifoSlot(Scope *scope)
29.130 +{
29.131 + if (!scope)
29.132 + return;
29.133 +
29.134 + if (Variable *var = scope->lifoSlot()) {
29.135 + locals_->set(zone_, var->slot(), var->type());
29.136 + __ savelifo(var->slot());
29.137 + }
29.138 +}
29.139 +
29.140 +void
29.141 +BytecodeCompiler::unwindTo(Scope *scope)
29.142 +{
29.143 + // Note: we only need to unwind to the outermost scope's LIFO slot.
29.144 + Variable *var = NULL;
29.145 + for (Scope *current = scope_; current != scope; current = current->enclosing()) {
29.146 + if (Variable *slot = current->lifoSlot())
29.147 + var = slot;
29.148 + }
29.149 +
29.150 + if (var)
29.151 + __ unwindlifo(var->slot());
29.152 +}
29.153 +
29.154 +void
29.155 +BytecodeCompiler::visit(NameProxy *name)
29.156 +{
29.157 + switch (name->binding()->kind()) {
29.158 + case BoundName::VARIABLE:
29.159 + {
29.160 + Variable *var = name->binding()->toVariable();
29.161 +
29.162 + if (var->location() == Variable::STACK) {
29.163 + __ getlocal(var);
29.164 + assert(!name->type()->isReference());
29.165 + } else if (var->location() == Variable::ENVIRONMENT) {
29.166 + getEnvSlot(var);
29.167 + } else {
29.168 + assert(var->location() == Variable::PARAMETER);
29.169 + __ getarg(var);
29.170 +
29.171 + // If this argument is actually a reference, dereference it now.
29.172 + if (var->type()->isReference())
29.173 + __ getref(var->type()->contained());
29.174 + }
29.175 + break;
29.176 + }
29.177 +
29.178 + case BoundName::FUNCTION:
29.179 + {
29.180 + NamedFunction *fun = name->binding()->toNamedFunction();
29.181 + __ module();
29.182 + __ getmodule_fn(fun->slot());
29.183 + break;
29.184 + }
29.185 +
29.186 + default:
29.187 + {
29.188 + NamedConstant *constant = name->binding()->toNamedConstant();
29.189 + __ int_(constant->value().toInt());
29.190 + break;
29.191 + }
29.192 + }
29.193 +}
29.194 +
29.195 +void
29.196 +BytecodeCompiler::visit(ExpressionStatement *node)
29.197 +{
29.198 + // Expressions leave their value on the top of the stack, so we make sure
29.199 + // to balance the stack if they're used as a statement.
29.200 + node->expression()->accept(this);
29.201 + if (!node->expression()->type()->isVoid())
29.202 + __ pop();
29.203 +}
29.204 +
29.205 +static inline bool
29.206 +IsCompositeValueType(Type *type)
29.207 +{
29.208 + return type->isStruct() ||
29.209 + (type->isArray() && type->isFixedLength());
29.210 +}
29.211 +
29.212 +static inline Array *
29.213 +StringLiteralToArray(Zone *zone, StringLiteral *node)
29.214 +{
29.215 + Local<Type> type(zone, node->type());
29.216 + Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
29.217 + if (!map)
29.218 + return NULL;
29.219 +
29.220 + return Array::NewString(zone,
29.221 + map,
29.222 + node->string()->raw(),
29.223 + node->string()->length(),
29.224 + Heap::Tenure_Old);
29.225 +}
29.226 +
29.227 +void
29.228 +BytecodeCompiler::visit(Assignment *node)
29.229 +{
29.230 + Local<Type> left(zone_, node->type());
29.231 + Local<Type> right(zone_, node->expression()->type());
29.232 +
29.233 + // The first step is three sub-steps:
29.234 + //
29.235 + // (1) Bind the left-hand side.
29.236 + // -- If a cumulative operation (+=, etc):
29.237 + // (2) Save a copy of the binding on the stack.
29.238 + // (3) Dereference the binding to get a value.
29.239 + //
29.240 + if (node->lvalue()->isNameProxy()) {
29.241 + NameProxy *proxy = node->lvalue()->toNameProxy();
29.242 + Variable *var = proxy->binding()->toVariable();
29.243 +
29.244 + // We need to fetch the variable under the following circumstances:
29.245 + // (1) The variable is a reference, since we'll store into the ref.
29.246 + // (2) The variable is a fixed array, since we need to copy into it.
29.247 + // (3) The variable is a struct, since we need to copy into it.
29.248 + if (var->type()->isReference() || IsCompositeValueType(var->type()))
29.249 + __ get(var);
29.250 +
29.251 + // Get the value if needed.
29.252 + if (node->token() != TOK_ASSIGN) {
29.253 + // += etc is not allowed on arrays.
29.254 + assert(!var->type()->isArray());
29.255 +
29.256 + if (var->location() == Variable::ENVIRONMENT)
29.257 + getEnvSlot(var);
29.258 +
29.259 + if (var->type()->isReference()) {
29.260 + __ dup();
29.261 + __ getref(var->type()->contained());
29.262 + } else if (var->location() != Variable::ENVIRONMENT) {
29.263 + __ get(var);
29.264 + }
29.265 + }
29.266 + } else if (node->lvalue()->isFieldExpression()) {
29.267 + FieldExpression *expr = node->lvalue()->toFieldExpression();
29.268 + __ note_position(expr->pos());
29.269 +
29.270 + expr->left()->accept(this);
29.271 +
29.272 + if (node->token() != TOK_ASSIGN)
29.273 + __ dup();
29.274 +
29.275 + if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
29.276 + __ getfield(expr->fieldIndex(), left);
29.277 + } else {
29.278 + IndexExpression *index = node->lvalue()->toIndexExpression();
29.279 + __ note_position(index->pos());
29.280 +
29.281 + index->left()->accept(this);
29.282 + index->right()->accept(this);
29.283 +
29.284 + if (node->token() != TOK_ASSIGN)
29.285 + __ dup2();
29.286 +
29.287 + if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
29.288 + __ getelem(left);
29.289 + }
29.290 +
29.291 + if (node->token() == TOK_ASSIGN) {
29.292 + // Special case: if the left-hand side is a string literal, we must
29.293 + // spawn a new copy (:TODO: something about const?)
29.294 + if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
29.295 + Local<Array> string(zone_,
29.296 + StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
29.297 + if (!string)
29.298 + return;
29.299 +
29.300 + Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
29.301 + __ note_position(node->expression()->pos());
29.302 + __ int_(string->length());
29.303 + __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
29.304 + __ object(string);
29.305 + __ copyarray();
29.306 + } else {
29.307 + node->expression()->accept(this);
29.308 + }
29.309 + } else {
29.310 + visitForALU(left, node->expression());
29.311 +
29.312 + TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
29.313 + __ note_position(node->pos());
29.314 + __ binary(TokenToOpcode(alu));
29.315 + }
29.316 +
29.317 + // Emit the store.
29.318 + if (left->isArray() && left->isFixedLength()) {
29.319 + // (x = y) returns the left-hand side; if |x| is a fixed-length array,
29.320 + // then |y| is as well, and we perform a deep copy.
29.321 + assert(right->isFixedLength());
29.322 + __ note_position(node->pos());
29.323 + __ copyarray();
29.324 + } else if (left->isStruct()) {
29.325 + // Structs have value semantics, so emit a full copy. We don't break
29.326 + // this down into u-ops, to avoid unnecessary bytecode explosion.
29.327 + assert(right->isStruct());
29.328 + __ note_position(node->pos());
29.329 + __ copystruct();
29.330 + } else if (node->lvalue()->isNameProxy()) {
29.331 + NameProxy *proxy = node->lvalue()->toNameProxy();
29.332 + Variable *var = proxy->binding()->toVariable();
29.333 +
29.334 + if (var->type()->isReference())
29.335 + __ setref(var->type()->contained());
29.336 + else if (var->location() == Variable::ENVIRONMENT)
29.337 + setEnvSlot(var);
29.338 + else
29.339 + __ set(var);
29.340 + } else if (node->lvalue()->isFieldExpression()) {
29.341 + FieldExpression *expr = node->lvalue()->toFieldExpression();
29.342 + __ setfield(expr->fieldIndex(), left);
29.343 + } else {
29.344 + __ setelem(left);
29.345 + }
29.346 +}
29.347 +
29.348 +void
29.349 +BytecodeCompiler::visit(IncDecExpression *node)
29.350 +{
29.351 + // In the postfix case, the logic looks like:
29.352 + // (1) Bind -> REF
29.353 + // (2) Dup -> REF REF
29.354 + // (3) Fetch -> REF VAL
29.355 + // (4) Swap -> VAL REF
29.356 + // (5) Pick -> VAL REF VAL
29.357 + // (6) Add -> VAL REF VAL+1
29.358 + // (7) Store -> VAL VAL+1
29.359 + // (8) Drop -> VAL
29.360 + //
29.361 + // In the prefix case, the logic looks like:
29.362 + // (1) Bind -> REF
29.363 + // (2) Dup -> REF REF
29.364 + // (3) Fetch -> REF VAL
29.365 + // --
29.366 + // --
29.367 + // (6) Add -> REF VAL+1
29.368 + // (7) Store -> VAL+1
29.369 + // --
29.370 + //
29.371 + // This is squirrely enough such that we don't bother sharing too much
29.372 + // with the above.
29.373 + //
29.374 + // Note: We simulate a "Pick" operation with a dup2+pop.
29.375 +
29.376 + // This is steps (1) to (5).
29.377 + Expression *expr = node->expression();
29.378 + if (expr->isNameProxy()) {
29.379 + NameProxy *proxy = expr->toNameProxy();
29.380 + Variable *var = proxy->binding()->toVariable();
29.381 +
29.382 + // Bind.
29.383 + if (var->location() == Variable::ENVIRONMENT)
29.384 + getEnvSlot(var);
29.385 + else if (var->type()->isReference() || var->type()->isArray())
29.386 + __ get(var);
29.387 +
29.388 + // Dup and fetch.
29.389 + if (var->type()->isReference()) {
29.390 + __ dup();
29.391 + __ getref(node->type());
29.392 + if (node->postfix()) {
29.393 + __ swap();
29.394 + __ pick2();
29.395 + }
29.396 + } else {
29.397 + assert(!var->type()->isArray());
29.398 + if (var->location() != Variable::ENVIRONMENT)
29.399 + __ get(var);
29.400 + if (node->postfix())
29.401 + __ dup();
29.402 + }
29.403 + } else if (expr->isFieldExpression()) {
29.404 + FieldExpression *field = expr->toFieldExpression();
29.405 +
29.406 + field->left()->accept(this);
29.407 + __ dup();
29.408 + __ getfield(field->fieldIndex(), field->type());
29.409 +
29.410 + if (node->postfix()) {
29.411 + // The stack looks like this now:
29.412 + // OBJECT VALUE
29.413 + __ swap(); // VALUE OBJECT
29.414 + __ pick2(); // VALUE OBJECT VALUE
29.415 + }
29.416 + } else {
29.417 + IndexExpression *index = expr->toIndexExpression();
29.418 + __ note_position(index->pos());
29.419 +
29.420 + index->left()->accept(this);
29.421 + index->right()->accept(this);
29.422 +
29.423 + assert(!node->type()->isArray());
29.424 + __ dup2();
29.425 + __ getelem(node->type());
29.426 +
29.427 + if (node->postfix()) {
29.428 + // The stack looks like this now:
29.429 + // ARRAY INDEX VALUE
29.430 + //
29.431 + // So we must use a PICK operation to rotate the stack into position.
29.432 + __ roll3(); // INDEX VALUE ARRAY
29.433 + __ roll3(); // VALUE ARRAY INDEX
29.434 + __ pick3(); // VALUE ARRAY INDEX VALUE
29.435 + }
29.436 + }
29.437 +
29.438 + // Perform step (6).
29.439 + if (node->type()->isFloat()) {
29.440 + __ float_(1.0);
29.441 + } else {
29.442 + assert(node->type()->isInt32());
29.443 + __ int_(1);
29.444 + }
29.445 +
29.446 + __ note_position(node->pos());
29.447 + if (node->token() == TOK_INCREMENT)
29.448 + __ binary(OP_ADD);
29.449 + else
29.450 + __ binary(OP_SUB);
29.451 +
29.452 + // Perform step (7).
29.453 + if (expr->isNameProxy()) {
29.454 + NameProxy *proxy = expr->toNameProxy();
29.455 + Variable *var = proxy->binding()->toVariable();
29.456 +
29.457 + if (var->type()->isReference())
29.458 + __ setref(node->type());
29.459 + else if (var->location() == Variable::ENVIRONMENT)
29.460 + setEnvSlot(var);
29.461 + else
29.462 + __ set(var);
29.463 + } else if (expr->isFieldExpression()) {
29.464 + FieldExpression *field = expr->toFieldExpression();
29.465 + __ setfield(field->fieldIndex(), field->type());
29.466 + } else {
29.467 + assert(expr->isIndexExpression());
29.468 + __ setelem(node->type());
29.469 + }
29.470 +
29.471 + // Perform step (8).
29.472 + if (node->postfix())
29.473 + __ pop();
29.474 +}
29.475 +
29.476 +void
29.477 +BytecodeCompiler::visitForALU(Type *needed, Expression *node)
29.478 +{
29.479 + node->accept(this);
29.480 + if (needed->isFloat() && !node->type()->isFloat())
29.481 + __ cvt_i2f();
29.482 + else
29.483 + assert(needed->primitive() == node->type()->primitive());
29.484 +}
29.485 +
29.486 +static inline Type *
29.487 +GetCoercionType(TokenKind tok, Type *left, Type *right)
29.488 +{
29.489 + if (left->isFloat())
29.490 + return left;
29.491 + return right;
29.492 +}
29.493 +
29.494 +void
29.495 +BytecodeCompiler::visit(UnaryExpression *node)
29.496 +{
29.497 + Local<Type> out(zone_, ((Expression *)node)->type());
29.498 +
29.499 + switch (node->token()) {
29.500 + case TOK_MINUS:
29.501 + {
29.502 + Local<Type> type(zone_, node->expression()->type());
29.503 + node->expression()->accept(this);
29.504 +
29.505 + if (out->isFloat())
29.506 + __ neg_f();
29.507 + else
29.508 + __ neg();
29.509 + break;
29.510 + }
29.511 +
29.512 + case TOK_NOT:
29.513 + {
29.514 + Local<Type> type(zone_, node->expression()->type());
29.515 + node->expression()->accept(this);
29.516 +
29.517 + if (out->isFloat())
29.518 + __ not_f();
29.519 + else
29.520 + __ not_();
29.521 + break;
29.522 + }
29.523 +
29.524 + case TOK_LABEL:
29.525 + {
29.526 + Local<Type> from(zone_, node->expression()->type());
29.527 +
29.528 + node->expression()->accept(this);
29.529 + if (!from->isFloat() && out->isFloat())
29.530 + __ bits_f2i();
29.531 + else if (from->isFloat() && !out->isFloat())
29.532 + __ bits_i2f();
29.533 + break;
29.534 + }
29.535 +
29.536 + case TOK_SIZEOF:
29.537 + {
29.538 + Local<Type> type(zone_, node->expression()->type());
29.539 + if (type->isFixedLength()) {
29.540 + __ int_(type->fixedLength());
29.541 + } else {
29.542 + node->expression()->accept(this);
29.543 + __ sizeof_();
29.544 + }
29.545 + break;
29.546 + }
29.547 +
29.548 + default:
29.549 + assert(node->token() == TOK_TILDE);
29.550 + node->expression()->accept(this);
29.551 + __ bitnot();
29.552 + break;
29.553 + }
29.554 +}
29.555 +
29.556 +void
29.557 +BytecodeCompiler::visit(BinaryExpression *node)
29.558 +{
29.559 + if (node->token() == TOK_AND || node->token() == TOK_OR) {
29.560 + Label success, failure, done;
29.561 + visitForTest(node, &success, &failure, &success);
29.562 + __ bind(&success);
29.563 + __ int_(1);
29.564 + __ drop(1); // Otherwise, the stack depth will be +1 too much.
29.565 + __ jump(&done);
29.566 + __ bind(&failure);
29.567 + __ int_(0);
29.568 + __ bind(&done);
29.569 + return;
29.570 + }
29.571 +
29.572 + Local<Type> leftType(zone_, node->left()->type());
29.573 + Local<Type> rightType(zone_, node->right()->type());
29.574 + Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
29.575 +
29.576 + visitForALU(coerce, node->left());
29.577 + visitForALU(coerce, node->right());
29.578 +
29.579 + Opcode op = TokenToOpcode(node->token());
29.580 + if (node->type()->isFloat())
29.581 + op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
29.582 +
29.583 + __ note_position(node->pos());
29.584 + __ binary(op);
29.585 +}
29.586 +
29.587 +void
29.588 +BytecodeCompiler::visit(IndexExpression *node)
29.589 +{
29.590 + node->left()->accept(this);
29.591 + node->right()->accept(this);
29.592 + __ note_position(node->pos());
29.593 + __ getelem(node->type());
29.594 +}
29.595 +
29.596 +void
29.597 +BytecodeCompiler::visit(FieldExpression *node)
29.598 +{
29.599 + node->left()->accept(this);
29.600 + __ getfield(node->fieldIndex(), node->type());
29.601 +}
29.602 +
29.603 +void
29.604 +BytecodeCompiler::visit(ReturnStatement *node)
29.605 +{
29.606 + if (node->expression()) {
29.607 + node->expression()->accept(this);
29.608 + __ return_();
29.609 + } else {
29.610 + __ returnvoid();
29.611 + }
29.612 +}
29.613 +
29.614 +void
29.615 +BytecodeCompiler::visitForTest(Expression *expression,
29.616 + Label *trueBranch,
29.617 + Label *falseBranch,
29.618 + Label *fallthrough)
29.619 +{
29.620 + TokenKind token = ToCompare(expression);
29.621 + if (token == TOK_EOF || token == TOK_NOT) {
29.622 + if (token == TOK_EOF)
29.623 + expression->accept(this);
29.624 + else
29.625 + expression->toUnaryExpression()->expression()->accept(this);
29.626 +
29.627 + bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
29.628 +
29.629 + Opcode op = jumpOnTrue ? OP_JT : OP_JF;
29.630 + if (expression->type()->isFloat())
29.631 + op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
29.632 +
29.633 + if (fallthrough == falseBranch)
29.634 + __ j(op, trueBranch);
29.635 + else
29.636 + __ j(op, falseBranch);
29.637 + return;
29.638 + }
29.639 +
29.640 + BinaryExpression *binary = expression->toBinaryExpression();
29.641 +
29.642 + if (token == TOK_AND || token == TOK_OR) {
29.643 + Label next;
29.644 + if (token == TOK_AND)
29.645 + visitForTest(binary->left(), &next, falseBranch, &next);
29.646 + else
29.647 + visitForTest(binary->left(), trueBranch, &next, &next);
29.648 + __ bind(&next);
29.649 + visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
29.650 + return;
29.651 + }
29.652 +
29.653 + Opcode op = CompareTokenToJump(token);
29.654 + if (fallthrough == trueBranch)
29.655 + op = Invert(op);
29.656 +
29.657 + Local<Type> leftType(zone_, binary->left()->type());
29.658 + Local<Type> rightType(zone_, binary->right()->type());
29.659 + Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
29.660 +
29.661 + visitForALU(coerce, binary->left());
29.662 + visitForALU(coerce, binary->right());
29.663 + if (coerce->isFloat())
29.664 + op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
29.665 +
29.666 + if (fallthrough == trueBranch)
29.667 + __ j(op, falseBranch);
29.668 + else
29.669 + __ j(op, trueBranch);
29.670 +}
29.671 +
29.672 +void
29.673 +BytecodeCompiler::visit(ForStatement *node)
29.674 +{
29.675 + AutoEnterScope forScope(this, node->scope());
29.676 +
29.677 + recordLifoSlot(node->scope());
29.678 +
29.679 + Label join, update;
29.680 + LoopScope loop(scope_, &join, &update, &loop_);
29.681 +
29.682 + if (node->initialization())
29.683 + node->initialization()->accept(this);
29.684 +
29.685 + Label header, test;
29.686 + if (node->condition())
29.687 + __ jump(&test);
29.688 +
29.689 + __ bind(&header);
29.690 + node->body()->accept(this);
29.691 +
29.692 + __ bind(&update);
29.693 + if (node->update())
29.694 + node->update()->accept(this);
29.695 +
29.696 + if (node->condition()) {
29.697 + __ bind(&test);
29.698 + visitForTest(node->condition(), &header, &join, &join);
29.699 + } else {
29.700 + __ jump(&header);
29.701 + }
29.702 +
29.703 + __ bind(&join);
29.704 +
29.705 + if (node->scope())
29.706 + unwindTo(node->scope()->enclosing());
29.707 + assert(__ stackDepth() == 0);
29.708 +}
29.709 +
29.710 +void
29.711 +BytecodeCompiler::visit(WhileStatement *node)
29.712 +{
29.713 + Label header, join;
29.714 +
29.715 + __ bind(&header);
29.716 +
29.717 + LoopScope loop(scope_, &join, &header, &loop_);
29.718 +
29.719 + if (node->token() == TOK_WHILE) {
29.720 + Label body;
29.721 +
29.722 + visitForTest(node->condition(), &body, &join, &body);
29.723 + __ bind(&body);
29.724 + node->body()->accept(this);
29.725 + __ jump(&header);
29.726 + } else {
29.727 + node->body()->accept(this);
29.728 + visitForTest(node->condition(), &header, &join, &join);
29.729 + }
29.730 +
29.731 + __ bind(&join);
29.732 +}
29.733 +
29.734 +void
29.735 +BytecodeCompiler::visit(BreakStatement *node)
29.736 +{
29.737 + unwindTo(loop_->scope());
29.738 + __ jump(loop_->break_());
29.739 +}
29.740 +
29.741 +void
29.742 +BytecodeCompiler::visit(ContinueStatement *node)
29.743 +{
29.744 + unwindTo(loop_->scope());
29.745 + __ jump(loop_->continue_());
29.746 +}
29.747 +
29.748 +void
29.749 +BytecodeCompiler::visit(BlockStatement *node)
29.750 +{
29.751 + AutoEnterScope blockScope(this, node->scope());
29.752 +
29.753 + recordLifoSlot(node->scope());
29.754 +
29.755 + for (size_t i = 0; i < node->statements()->length(); i++) {
29.756 + Statement *statement = node->statements()->at(i);
29.757 + statement->accept(this);
29.758 + assert(__ stackDepth() == 0);
29.759 + }
29.760 +
29.761 + // We don't bother emitting an "unwind" instruction for function scopes,
29.762 + // since this is taken care of by the calling convention.
29.763 + if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
29.764 + unwindTo(node->scope()->enclosing());
29.765 +}
29.766 +
29.767 +void
29.768 +BytecodeCompiler::visit(IntegerLiteral *node)
29.769 +{
29.770 + __ int_(node->value());
29.771 +}
29.772 +
29.773 +void
29.774 +BytecodeCompiler::visit(BooleanLiteral *node)
29.775 +{
29.776 + if (node->token() == TOK_TRUE)
29.777 + __ true_();
29.778 + else
29.779 + __ false_();
29.780 +}
29.781 +
29.782 +void
29.783 +BytecodeCompiler::visit(FloatLiteral *node)
29.784 +{
29.785 + __ float_((float)node->value());
29.786 +}
29.787 +
29.788 +void
29.789 +BytecodeCompiler::visit(StringLiteral *node)
29.790 +{
29.791 + Local<Array> array(zone_, StringLiteralToArray(zone_, node));
29.792 + if (!array)
29.793 + return;
29.794 +
29.795 + __ note_position(node->pos());
29.796 + __ object(array);
29.797 +}
29.798 +
29.799 +void
29.800 +BytecodeCompiler::getEnvSlot(Variable *var)
29.801 +{
29.802 + assert(var->scope()->kind() == Scope::GLOBAL);
29.803 + __ getglobal(var);
29.804 +}
29.805 +
29.806 +void
29.807 +BytecodeCompiler::setEnvSlot(Variable *var)
29.808 +{
29.809 + assert(var->scope()->kind() == Scope::GLOBAL);
29.810 + __ setglobal(var);
29.811 +}
29.812 +
29.813 +static bool
29.814 +FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
29.815 +{
29.816 + Local<Array> string(zone);
29.817 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
29.818 + Expression *expr = literal->expressions()->at(i);
29.819 + StringLiteral *lit = expr->toStringLiteral();
29.820 + if ((string = StringLiteralToArray(zone, lit)) == NULL)
29.821 + return false;
29.822 +
29.823 + array->writeObject(zone, i, string);
29.824 +
29.825 + if (string->length() > *maxsize)
29.826 + *maxsize = string->length();
29.827 +
29.828 + assert(!array->type()->contained()->isFixedLength() ||
29.829 + array->type()->contained()->fixedLength() >= string->length());
29.830 + }
29.831 +
29.832 + return true;
29.833 +}
29.834 +
29.835 +static bool
29.836 +FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
29.837 +{
29.838 + assert(array->type()->fixedLength() == literal->expressions()->length());
29.839 +
29.840 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
29.841 + Expression *expr = literal->expressions()->at(i);
29.842 + if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
29.843 + array->writeInt32(i, lit->value());
29.844 + continue;
29.845 + }
29.846 + if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
29.847 + if (lit->token() == TOK_TRUE)
29.848 + array->writeInt32(i, 1);
29.849 + else
29.850 + array->writeInt32(i, 0);
29.851 + continue;
29.852 + }
29.853 + if (FloatLiteral *lit = expr->asFloatLiteral()) {
29.854 + array->writeFloat(i, (float)lit->value());
29.855 + continue;
29.856 + }
29.857 +
29.858 + // Unrecognized literal type.
29.859 + assert(false);
29.860 + }
29.861 +
29.862 + return true;
29.863 +}
29.864 +
29.865 +static bool
29.866 +TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
29.867 + unsigned *maxsize)
29.868 +{
29.869 + assert(type->fixedLength() == literal->expressions()->length());
29.870 +
29.871 + Local<Type> contained(zone, type->contained());
29.872 + if (contained->isCharArray())
29.873 + return FillArrayLiteral_String(zone, array, literal, maxsize);
29.874 +
29.875 + if (!contained->isArray())
29.876 + return FillArrayLiteral_Primitive(zone, array, literal);
29.877 +
29.878 + Local<Array> subarray(zone);
29.879 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
29.880 + Expression *expr = literal->expressions()->at(i);
29.881 + subarray = Array::cast(array->readObject(i));
29.882 + if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
29.883 + return false;
29.884 + }
29.885 +
29.886 + return true;
29.887 +}
29.888 +
29.889 +static Array *
29.890 +BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
29.891 +{
29.892 + Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
29.893 + if (!root)
29.894 + return NULL;
29.895 +
29.896 + // This should have allocated everything in the array, so all we need to
29.897 + // do is traverse down to the lowest levels and copy things.
29.898 + Local<Type> type(zone, map->type());
29.899 + if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
29.900 + return NULL;
29.901 +
29.902 + return root;
29.903 +}
29.904 +
29.905 +static inline bool
29.906 +ArrayContainsCharBuffers(Type *type)
29.907 +{
29.908 + if (type->contained()->isArray())
29.909 + return ArrayContainsCharBuffers(type->contained());
29.910 + return type->isCharArray();
29.911 +}
29.912 +
29.913 +void
29.914 +BytecodeCompiler::visit(VariableDeclaration *node)
29.915 +{
29.916 + Variable *var = node->variable();
29.917 +
29.918 + Local<Type> type(zone_, var->type());
29.919 + if (type->isArray()) {
29.920 + Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
29.921 + __ note_position(node->pos());
29.922 +
29.923 + Local<Type> right(zone_);
29.924 + if (node->initialization())
29.925 + right = node->initialization()->type();
29.926 +
29.927 + // There are a few methods for allocating, here:
29.928 + // (1) If the array is fixed,
29.929 + // (a) Initializer not present,
29.930 + // NEWFIXED
29.931 + // (b) Left is const non-string:
29.932 + // <nothing>
29.933 + // (b) Otherwise:
29.934 + // NEWFIXED
29.935 + // COPYARRAY
29.936 + // (2) If the array is not fixed,
29.937 + // (a) Initializer is not present,
29.938 + // NEWEMPTY
29.939 + // (b) Initializer is not a string literal,
29.940 + // or left is const:
29.941 + // <nothing>
29.942 + // (c) Initializer is a string literal,
29.943 + // NEWSIZED
29.944 + // COPYARRAY
29.945 + //
29.946 +
29.947 + Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
29.948 + ? Heap::Tenure_Old
29.949 + : Heap::Tenure_Default;
29.950 +
29.951 + if (Expression *init = node->initialization()) {
29.952 + if (init->isArrayLiteral()) {
29.953 + unsigned maxsize = 0;
29.954 + Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
29.955 + if (!array)
29.956 + return;
29.957 +
29.958 + assert(type->isFixedLength());
29.959 +
29.960 + if (type->isConst()) {
29.961 + __ object(array);
29.962 + } else if (ArrayContainsCharBuffers(type)) {
29.963 + // This array contains mutable char buffers, so
29.964 + // unfortunately this gets a little more complicated. We
29.965 + // compute the maximum size needed for the innermost
29.966 + // string, which is similar to SP1. This means we can use
29.967 + // CopyArray rather than individually emit opcodes to clone
29.968 + // every string.
29.969 + Local<Type> child(zone_, type);
29.970 + for (size_t i = 0; i < type->levels() - 1; i++) {
29.971 + __ int_(child->fixedLength());
29.972 + child = child->contained();
29.973 + }
29.974 + __ int_(maxsize);
29.975 + __ newarray(OP_NEWSIZED, map, tenure);
29.976 + __ object(array);
29.977 + __ copyarray();
29.978 + } else {
29.979 + __ newarray(OP_NEWFIXED, map, tenure);
29.980 + __ object(array);
29.981 + __ copyarray();
29.982 + }
29.983 + } else if (type->isFixedLength()) {
29.984 + // Note in the case of:
29.985 + // const String:buffer[50] = "hello";
29.986 + //
29.987 + // We want to preserve sizeof(buffer) == 50.
29.988 + if (type->isConst() && !type->isCharArray()) {
29.989 + init->accept(this);
29.990 + } else {
29.991 + __ newarray(OP_NEWFIXED, map, tenure);
29.992 + init->accept(this);
29.993 + __ copyarray();
29.994 + }
29.995 + } else if (!type->isConst() && init->isStringLiteral()) {
29.996 + // This is a degenerate case of ArrayLiteral.
29.997 + __ int_(right->fixedLength());
29.998 + __ newarray(OP_NEWSIZED, map, tenure);
29.999 + init->accept(this);
29.1000 + __ copyarray();
29.1001 + } else if (type->isConst()) {
29.1002 + init->accept(this);
29.1003 + }
29.1004 + } else if (type->isFixedLength()) {
29.1005 + __ newarray(OP_NEWFIXED, map, tenure);
29.1006 + } else {
29.1007 +#if 0
29.1008 + if (node->postDimensions()) {
29.1009 + for (size_t i = 0; i < node->postDimensions()->length(); i++) {
29.1010 + Expression *expr = node->postDimensions()->at(i);
29.1011 + if (expr)
29.1012 + expr->accept(this);
29.1013 + else
29.1014 + __ int_(0);
29.1015 + }
29.1016 + __ newarray(OP_NEWSIZED, map, tenure);
29.1017 + } else {
29.1018 + __ newarray(OP_NEWEMPTY, map, tenure);
29.1019 + }
29.1020 +#endif
29.1021 + }
29.1022 + } else if (type->isStruct()) {
29.1023 + Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
29.1024 +
29.1025 + // Because structs can contain arrays, any sort of composition
29.1026 + // triggers non-LIFO allocation. This is just for correctness.
29.1027 + // We could do better by:
29.1028 + // (1) Limiting to structs that just (recursively) contain arrays,
29.1029 + // (2) Swap Stack for Default tenure in Struct::New
29.1030 + // (3) JIT analysis
29.1031 + if (var->scope()->kind() == Scope::GLOBAL)
29.1032 + __ newstruct(map, Heap::Tenure_Old);
29.1033 + else if (var->needsHeapAllocation() || map->composed())
29.1034 + __ newstruct(map, Heap::Tenure_Default);
29.1035 + else
29.1036 + __ newstruct(map, Heap::Tenure_Stack);
29.1037 + } else {
29.1038 + if (node->initialization()) {
29.1039 + node->initialization()->accept(this);
29.1040 + } else {
29.1041 + if (type->isInt32OrEnum() || type->isBool()) {
29.1042 + __ int_(0);
29.1043 + } else {
29.1044 + assert(type->isFloat());
29.1045 + __ float_(0);
29.1046 + }
29.1047 + }
29.1048 + }
29.1049 +
29.1050 + if (var->location() == Variable::STACK) {
29.1051 + __ setlocal(var);
29.1052 + locals_->set(zone_, var->slot(), var->type());
29.1053 + } else {
29.1054 + assert(var->location() == Variable::ENVIRONMENT);
29.1055 + setEnvSlot(var);
29.1056 + }
29.1057 +
29.1058 + __ pop();
29.1059 +}
29.1060 +
29.1061 +void
29.1062 +BytecodeCompiler::visit(CallExpression *node)
29.1063 +{
29.1064 +#if 0
29.1065 + Local<Type> funType(zone_, node->callee()->type());
29.1066 +
29.1067 + // Sniff out natives, which have a specific opcode and are guaranteed to
29.1068 + // be called via name proxy.
29.1069 + NamedFunction *native = NULL;
29.1070 + if (funType->isNative())
29.1071 + native = node->callee()->toNameProxy()->binding()->toNamedFunction();
29.1072 +
29.1073 + Local<Type> given(zone_);
29.1074 + for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
29.1075 + Expression *arg = node->arguments()->at(i);
29.1076 +
29.1077 + given = arg->type();
29.1078 +
29.1079 + // We need to compute a reference if the parameter was in the form:
29.1080 + // f(&a)
29.1081 + // Note this form does not allow: f({})
29.1082 + //
29.1083 + // We also need to compute references for all variadic native
29.1084 + // arguments, but arrays and references are already in the
29.1085 + // appropriate form.
29.1086 + bool mustPushReference = false;
29.1087 + if (i >= funType->parameters()->length()) {
29.1088 + assert(funType->isNative() && funType->isNativeVariadic());
29.1089 + mustPushReference = !given->isArray() && !given->isReference();
29.1090 + } else if (funType->parameterAt(i)->isReference()) {
29.1091 + mustPushReference = !given->isReference();
29.1092 + }
29.1093 +
29.1094 + // If a native is passed to a native, it must only be one level deep.
29.1095 + assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
29.1096 +
29.1097 + if (mustPushReference) {
29.1098 + if (arg->isNameProxy()) {
29.1099 + // :TODO: test with functions and globals
29.1100 + // Compute a reference to the name.
29.1101 + Variable *var = arg->toNameProxy()->binding()->toVariable();
29.1102 + __ note_position(node->pos());
29.1103 + __ newref(var);
29.1104 + } else if (arg->isFieldExpression()) {
29.1105 + FieldExpression *expr = arg->toFieldExpression();
29.1106 + expr->left()->accept(this);
29.1107 + __ note_position(expr->pos());
29.1108 + __ fieldref_lifo(expr->fieldIndex());
29.1109 + } else {
29.1110 + // We don't know how to, or can't, build a direct reference to
29.1111 + // this type. Make an indirect one, by taking the top of the
29.1112 + // stack and boxing it up.
29.1113 + arg->accept(this);
29.1114 + __ note_position(node->pos());
29.1115 + __ slotref_lifo();
29.1116 + }
29.1117 + } else {
29.1118 + arg->accept(this);
29.1119 + }
29.1120 + }
29.1121 +
29.1122 + unsigned argc = node->arguments()->length();
29.1123 +
29.1124 + // If there are missing arguments, then we're not done and have to push
29.1125 + // default parameters.
29.1126 + Local<Box> box(zone_);
29.1127 + Local<Array> array(zone_);
29.1128 + Local<ArrayMap> map(zone_);
29.1129 + for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
29.1130 + box = Box::cast(funType->defaults()->at(i));
29.1131 +
29.1132 + if (box->type()->isPod()) {
29.1133 + if (box->type()->pod() == PrimitiveType_Int32)
29.1134 + __ int_(box->toInt32());
29.1135 + else if (box->type()->pod() == PrimitiveType_Float)
29.1136 + __ float_(box->toFloat());
29.1137 + else
29.1138 + assert(false);
29.1139 +
29.1140 + if (funType->parameterAt(i)->isReference()) {
29.1141 + __ note_position(node->pos());
29.1142 + __ slotref_lifo();
29.1143 + }
29.1144 + } else {
29.1145 + assert(box->type()->isArray());
29.1146 +
29.1147 + array = Array::cast(box->toObject());
29.1148 + if (funType->parameterAt(i)->isConst()) {
29.1149 + __ object(array);
29.1150 + } else {
29.1151 + // We need to copy the array since it's mutable. Note that
29.1152 + // although COPYARRAY returns its left-hand side, this may
29.1153 + // change in the future, we do the same thing and dupe the
29.1154 + // newly allocated array.
29.1155 + map = ArrayMap::cast(array->map());
29.1156 +
29.1157 + // Natives cannot escape array references, so we can allocate
29.1158 + // them on the LIFO stack.
29.1159 + if (funType->isNative())
29.1160 + __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
29.1161 + else
29.1162 + __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
29.1163 + __ dup();
29.1164 + __ object(array);
29.1165 + __ copyarray();
29.1166 + __ pop();
29.1167 + }
29.1168 + }
29.1169 +
29.1170 + argc++;
29.1171 + }
29.1172 +
29.1173 + __ note_position(node->pos());
29.1174 + if (native) {
29.1175 + __ callnative(native->slot(), argc);
29.1176 + __ drop(argc);
29.1177 + } else {
29.1178 + node->callee()->accept(this);
29.1179 + __ call(funType);
29.1180 + __ drop(argc + 1);
29.1181 + }
29.1182 +#endif
29.1183 +}
29.1184 +
29.1185 +void
29.1186 +BytecodeCompiler::visit(TernaryExpression *node)
29.1187 +{
29.1188 + Label success, failure, join;
29.1189 +
29.1190 + visitForTest(node->condition(), &success, &failure, &success);
29.1191 + __ bind(&success);
29.1192 + node->left()->accept(this);
29.1193 + __ drop(1);
29.1194 + __ jump(&join);
29.1195 + __ bind(&failure);
29.1196 + node->right()->accept(this);
29.1197 + __ bind(&join);
29.1198 +}
29.1199 +
29.1200 +void
29.1201 +BytecodeCompiler::visit(IfStatement *node)
29.1202 +{
29.1203 + Label join;
29.1204 + if (!node->ifFalse()) {
29.1205 + Label success;
29.1206 +
29.1207 + visitForTest(node->condition(), &success, &join, &success);
29.1208 + __ bind(&success);
29.1209 + node->ifTrue()->accept(this);
29.1210 + } else {
29.1211 + Label success, next;
29.1212 +
29.1213 + visitForTest(node->condition(), &success, &next, &success);
29.1214 + __ bind(&success);
29.1215 + node->ifTrue()->accept(this);
29.1216 + __ jump(&join);
29.1217 + __ bind(&next);
29.1218 + node->ifFalse()->accept(this);
29.1219 + }
29.1220 +
29.1221 + __ bind(&join);
29.1222 +}
29.1223 +
29.1224 +bool
29.1225 +BytecodeCompiler::tableswitch(SwitchStatement *node)
29.1226 +{
29.1227 + CaseValueList *values = node->caseValueList();
29.1228 +
29.1229 + if (values->length() < 3)
29.1230 + return false;
29.1231 +
29.1232 + // Find the delta between the largest and smallest value.
29.1233 + int hi = values->at(values->length() - 1).box.toInt();
29.1234 + int lo = values->at(0).box.toInt();
29.1235 + assert(hi > lo);
29.1236 +
29.1237 + unsigned tablesize = TableSwitchEntries(lo, hi);
29.1238 + if (tablesize > MAX_TABLESWITCH_ENTRIES)
29.1239 + return false;
29.1240 +
29.1241 + Label def, join;
29.1242 +
29.1243 + // Create the list of labels that each statement will bind to.
29.1244 + Label *labels = new Label[node->cases()->length()];
29.1245 +
29.1246 + // Create the table of labels we'll use for each case.
29.1247 + Label **table = new Label *[tablesize];
29.1248 +
29.1249 + // Link all cases, by default, to the default label.
29.1250 + for (size_t i = 0; i < tablesize; i++)
29.1251 + table[i] = &def;
29.1252 +
29.1253 + // Now patch actual cases to their correct labels.
29.1254 + for (size_t i = 0; i < values->length(); i++) {
29.1255 + CaseValue &v = values->at(i);
29.1256 + assert(v.statement < node->cases()->length());
29.1257 +
29.1258 + unsigned index = unsigned(v.box.toInt() - lo);
29.1259 + assert(index < tablesize);
29.1260 +
29.1261 + table[index] = &labels[v.statement];
29.1262 + }
29.1263 +
29.1264 + // Emit the tableswitch opcode and the jump table.
29.1265 + __ tableswitch(lo, hi, &def, table);
29.1266 +
29.1267 + // We're done with the jump table now.
29.1268 + delete [] table;
29.1269 +
29.1270 + // Emit each statement.
29.1271 + for (size_t i = 0; i < node->cases()->length(); i++) {
29.1272 + Statement *stmt = node->cases()->at(i)->statement();
29.1273 +
29.1274 + __ bind(&labels[i]);
29.1275 + stmt->accept(this);
29.1276 + __ jump(&join);
29.1277 + }
29.1278 +
29.1279 + // We're done with the statement labels.
29.1280 + delete [] labels;
29.1281 +
29.1282 + // Emit the default case.
29.1283 + __ bind(&def);
29.1284 + if (node->defaultCase())
29.1285 + node->defaultCase()->accept(this);
29.1286 +
29.1287 + __ bind(&join);
29.1288 +
29.1289 + return true;
29.1290 +}
29.1291 +
29.1292 +void
29.1293 +BytecodeCompiler::visit(SwitchStatement *node)
29.1294 +{
29.1295 + node->expression()->accept(this);
29.1296 +
29.1297 + if (tableswitch(node))
29.1298 + return;
29.1299 +
29.1300 + Label join;
29.1301 +
29.1302 + for (size_t i = 0; i < node->cases()->length(); i++) {
29.1303 + Case *c = node->cases()->at(i);
29.1304 +
29.1305 + Label success, fail;
29.1306 + if (c->others()) {
29.1307 + for (size_t j = 0; j < c->others()->length(); j++) {
29.1308 + Expression *expr = c->others()->at(j);
29.1309 +
29.1310 + __ dup();
29.1311 + expr->accept(this);
29.1312 + __ j(OP_JEQ, &success);
29.1313 + }
29.1314 + }
29.1315 +
29.1316 + // The final test.
29.1317 + __ dup();
29.1318 + c->expression()->accept(this);
29.1319 + __ j(OP_JNE, &fail);
29.1320 + __ bind(&success);
29.1321 + c->statement()->accept(this);
29.1322 + __ jump(&join);
29.1323 + __ bind(&fail);
29.1324 + }
29.1325 +
29.1326 + if (node->defaultCase())
29.1327 + node->defaultCase()->accept(this);
29.1328 +
29.1329 + __ pop();
29.1330 + __ bind(&join);
29.1331 +}
29.1332 +
29.1333 +void
29.1334 +BytecodeCompiler::visit(FunctionStatement *node)
29.1335 +{
29.1336 + if (!node->fun()->used())
29.1337 + return;
29.1338 +
29.1339 + if (node->fun()->isNative()) {
29.1340 + assert(!moduleData_->natives->at(node->fun()->slot()));
29.1341 +
29.1342 + Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
29.1343 + Local<String> name(zone_, node->fun()->name());
29.1344 + Local<Native> native(zone_, Native::New(zone_, type, name));
29.1345 + if (!native)
29.1346 + return;
29.1347 +
29.1348 + moduleData_->natives->set(zone_, node->fun()->slot(), native);
29.1349 + return;
29.1350 + }
29.1351 +
29.1352 + // If the function has no body, then it's just a declaration.
29.1353 + if (!node->body()) {
29.1354 + assert(node->fun()->isForward() || node->fun()->isPublic());
29.1355 + return;
29.1356 + }
29.1357 +
29.1358 + BytecodeCompiler child(zone_, tree_, moduleData_);
29.1359 + Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
29.1360 + if (!fun)
29.1361 + return;
29.1362 +
29.1363 + assert(!moduleData_->module->getFunction(node->fun()->slot()));
29.1364 + moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
29.1365 +}
29.1366 +
29.1367 +void
29.1368 +BytecodeCompiler::visit(FunctionTypeStatement *node)
29.1369 +{
29.1370 +}
29.1371 +
29.1372 +void
29.1373 +BytecodeCompiler::visit(EnumStatement *node)
29.1374 +{
29.1375 +}
29.1376 +
29.1377 +void
29.1378 +BytecodeCompiler::visit(StructureStatement *node)
29.1379 +{
29.1380 +}
29.1381 +
29.1382 +void
29.1383 +BytecodeCompiler::visit(ArrayLiteral *node)
29.1384 +{
29.1385 + // We shouldn't reach these; they're handled manually when initializing
29.1386 + // declared arrays.
29.1387 + assert(false);
29.1388 +}
29.1389 +
29.1390 +void
29.1391 +BytecodeCompiler::visit(ImportStatement *node)
29.1392 +{
29.1393 +}
29.1394 +
29.1395 +Code *
29.1396 +BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
29.1397 +{
29.1398 + // STOP doubles as RETURNVOID.
29.1399 + __ stop();
29.1400 +
29.1401 + if (__ oom() || zone_->hasPendingException())
29.1402 + return NULL;
29.1403 +
29.1404 + Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
29.1405 + if (!bytes)
29.1406 + return NULL;
29.1407 + memcpy(bytes->raw(), __ buffer(), __ length());
29.1408 +
29.1409 + for (size_t i = 0; i < scope->maxContainedLocals(); i++)
29.1410 + assert(locals_->at(i));
29.1411 +
29.1412 + Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
29.1413 + if (!objects)
29.1414 + return NULL;
29.1415 +
29.1416 + for (size_t i = 0; i < __ objects()->length(); i++)
29.1417 + objects->set(zone_, i, *(__ objects()->at(i)));
29.1418 +
29.1419 + Local<ByteArray> safepoints(zone_);
29.1420 +
29.1421 + // If any stack slots hold gc pointers at potential failure points in the
29.1422 + // bytecode, record them now. We do this by building a list of tuples;
29.1423 + // each tuple contains the pc offset, and a bitset containing which stack
29.1424 + // slots must be scanned by the gc.
29.1425 + if (__ oopRecords()->length()) {
29.1426 + size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
29.1427 + size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
29.1428 + safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
29.1429 + if (!safepoints)
29.1430 + return NULL;
29.1431 +
29.1432 + Address cursor = safepoints->raw();
29.1433 + for (size_t i = 0; i < __ oopRecords()->length(); i++) {
29.1434 + OopRecord *record = __ oopRecords()->at(i);
29.1435 + assert(record->depth <= __ maxStackDepth());
29.1436 +
29.1437 + *reinterpret_cast<unsigned *>(cursor) = record->offset;
29.1438 +
29.1439 + unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
29.1440 + for (unsigned i = 0; i < record->depth; i++)
29.1441 + bits[i / 8] |= (1 << (i % 8));
29.1442 +
29.1443 + cursor += bytesPerSafepoint;
29.1444 + }
29.1445 +
29.1446 + assert(cursor == safepoints->raw() + gcmapSize);
29.1447 + }
29.1448 +
29.1449 + Local<ByteArray> sourcemap(zone_);
29.1450 + if (__ sourcemapLength()) {
29.1451 + sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
29.1452 + if (!sourcemap)
29.1453 + return NULL;
29.1454 +
29.1455 + memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
29.1456 + }
29.1457 +
29.1458 + Local<Code> code(zone_);
29.1459 +
29.1460 + code = Code::New(zone_,
29.1461 + bytes,
29.1462 + locals_,
29.1463 + objects,
29.1464 + __ maxStackDepth(),
29.1465 + moduleData_->module,
29.1466 + safepoints,
29.1467 + sourcemap,
29.1468 + lineno);
29.1469 + return code;
29.1470 +}
29.1471 +
29.1472 +Function *
29.1473 +BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
29.1474 +{
29.1475 + // Note: No need to record a life slot here, since it's part of the Frame.
29.1476 + AutoEnterScope functionScope(this, node->scope());
29.1477 +
29.1478 + // Set the initial line, because line mappings are deltas.
29.1479 + __ setFirstLine(node->pos().line);
29.1480 + locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
29.1481 +
29.1482 + node->body()->accept(this);
29.1483 +
29.1484 + unsigned nargs = node->scope()->numArguments();
29.1485 + Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
29.1486 + if (!args)
29.1487 + return NULL;
29.1488 +
29.1489 + for (size_t i = 0; i < node->scope()->numArguments(); i++)
29.1490 + args->set(zone_, i, node->scope()->getArgument(i)->type());
29.1491 +
29.1492 +
29.1493 + Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
29.1494 + if (!code)
29.1495 + return NULL;
29.1496 +
29.1497 + Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
29.1498 + Local<String> name(zone_, node->fun()->name());
29.1499 + Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
29.1500 + if (!fun)
29.1501 + return NULL;
29.1502 +
29.1503 + // If this function had a forward, export it as a named public.
29.1504 + if (node->fun()->isPublic()) {
29.1505 + assert(node->fun()->isPublic());
29.1506 + ScopedRoot<Function> root(fun);
29.1507 + if (!root)
29.1508 + return NULL;
29.1509 + if (!moduleData_->publics.append(root))
29.1510 + return NULL;
29.1511 + }
29.1512 +
29.1513 +#ifndef NDEBUG
29.1514 + Disassemble(code, stdout);
29.1515 +#endif
29.1516 +
29.1517 + return fun;
29.1518 +}
29.1519 +
29.1520 +Module *
29.1521 +BytecodeCompiler::compile()
29.1522 +{
29.1523 + AutoEnterScope scope(this, tree_->globalScope());
29.1524 +
29.1525 + ModuleData moduleData;
29.1526 +
29.1527 + moduleData_ = &moduleData;
29.1528 + moduleData_->module = Module::New(zone_, tree_->globalScope()->numFunctions());
29.1529 +
29.1530 + if (!moduleData_)
29.1531 + return NULL;
29.1532 +
29.1533 + moduleData_->natives = FixedArray::New(zone_, tree_->globalScope()->numNatives(), Heap::Tenure_Old);
29.1534 + if (!moduleData_->natives)
29.1535 + return NULL;
29.1536 +
29.1537 + for (size_t i = 0; i < tree_->statements()->length(); i++) {
29.1538 + Statement *statement = tree_->statements()->at(i);
29.1539 + statement->accept(this);
29.1540 + }
29.1541 +
29.1542 + if (zone_->hasPendingException())
29.1543 + return NULL;
29.1544 +
29.1545 +#ifndef NDEBUG
29.1546 + for (size_t i = 0; i < tree_->globalScope()->numFunctions(); i++)
29.1547 + assert(moduleData_->module->getFunction(i));
29.1548 + for (size_t i = 0; i < tree_->globalScope()->numNatives(); i++)
29.1549 + assert(moduleData_->natives->at(i));
29.1550 +#endif
29.1551 +
29.1552 + if (moduleData_->publics.length()) {
29.1553 + Local<Function> fun(zone_);
29.1554 + Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
29.1555 + Heap::Tenure_Old));
29.1556 + if (!list)
29.1557 + return NULL;
29.1558 +
29.1559 + for (size_t i = 0; i < moduleData_->publics.length(); i++)
29.1560 + list->set(zone_, i, moduleData_->publics[i]);
29.1561 +
29.1562 + moduleData_->module->setPublics(list);
29.1563 + }
29.1564 +
29.1565 + moduleData_->module->setNatives(moduleData_->natives);
29.1566 +
29.1567 + if (scope_->numEnvironmentVars()) {
29.1568 + Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
29.1569 + if (!globalMap)
29.1570 + return NULL;
29.1571 +
29.1572 + Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
29.1573 + if (!environment)
29.1574 + return NULL;
29.1575 +
29.1576 + moduleData_->module->setEnvironment(environment);
29.1577 + }
29.1578 +
29.1579 + Local<Code> code(zone_, compileCode(tree_->globalScope(), 1));
29.1580 + if (!code)
29.1581 + return NULL;
29.1582 +
29.1583 + Disassemble(code, stdout);
29.1584 +
29.1585 + moduleData_->module->setCode(code);
29.1586 +
29.1587 + return moduleData_->module;
29.1588 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/src/OldByCo.h Sat Nov 17 18:41:01 2012 -0800
30.3 @@ -0,0 +1,160 @@
30.4 +/* vim: set ts=4 sw=4 tw=99 et:
30.5 + *
30.6 + * Copyright (C) 2012 David Anderson
30.7 + *
30.8 + * This file is part of JITCraft.
30.9 + *
30.10 + * JITCraft is free software: you can redistribute it and/or modify it under
30.11 + * the terms of the GNU General Public License as published by the Free
30.12 + * Software Foundation, either version 3 of the License, or (at your option)
30.13 + * any later version.
30.14 + *
30.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
30.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
30.18 + *
30.19 + * You should have received a copy of the GNU General Public License along with
30.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
30.21 + */
30.22 +#ifndef _include_bytecode_compiler_h_
30.23 +#define _include_bytecode_compiler_h_
30.24 +
30.25 +#include "../Functions.h"
30.26 +#include "AST.h"
30.27 +#include "BytecodeEmitter.h"
30.28 +
30.29 +namespace ke {
30.30 +
30.31 +class Module;
30.32 +class Array;
30.33 +class ArrayMap;
30.34 +
30.35 +struct ModuleData
30.36 +{
30.37 + ScopedRoot<Module> module;
30.38 + PoolList<ScopedRoot<Function> > publics;
30.39 + ScopedRoot<FixedArray> natives;
30.40 +};
30.41 +
30.42 +class BytecodeCompiler : public AstVisitor
30.43 +{
30.44 + Zone *zone_;
30.45 + ParseTree *tree_;
30.46 + BytecodeEmitter emitter_;
30.47 + ScopedRoot<FixedArray> locals_;
30.48 + Scope *scope_;
30.49 + ModuleData *moduleData_;
30.50 +
30.51 + class LoopScope
30.52 + {
30.53 + Scope *scope_;
30.54 + BytecodeEmitter::Label *bk_;
30.55 + BytecodeEmitter::Label *ct_;
30.56 + LoopScope **prevp_;
30.57 + LoopScope *prev_;
30.58 +
30.59 + public:
30.60 + LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
30.61 + LoopScope **prevp)
30.62 + : scope_(scope),
30.63 + bk_(bk),
30.64 + ct_(ct),
30.65 + prevp_(prevp),
30.66 + prev_(*prevp)
30.67 + {
30.68 + *prevp_ = this;
30.69 + }
30.70 +
30.71 + ~LoopScope()
30.72 + {
30.73 + *prevp_ = prev_;
30.74 + }
30.75 +
30.76 + BytecodeEmitter::Label *break_() {
30.77 + return bk_;
30.78 + }
30.79 + BytecodeEmitter::Label *continue_() {
30.80 + return ct_;
30.81 + }
30.82 + Scope *scope() {
30.83 + return scope_;
30.84 + }
30.85 + };
30.86 +
30.87 + LoopScope *loop_;
30.88 +
30.89 + public:
30.90 + class AutoEnterScope
30.91 + {
30.92 + BytecodeCompiler *bc_;
30.93 + Scope *saved_;
30.94 +
30.95 + public:
30.96 + AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
30.97 + : bc_(bc),
30.98 + saved_(bc->scope_)
30.99 + {
30.100 + if (scope)
30.101 + bc->scope_ = scope;
30.102 + }
30.103 + ~AutoEnterScope() {
30.104 + bc_->scope_ = saved_;
30.105 + }
30.106 + };
30.107 +
30.108 + private:
30.109 + void recordLifoSlot(Scope *scope);
30.110 + void unwindTo(Scope *scope);
30.111 + void visitForTest(Expression *expression,
30.112 + BytecodeEmitter::Label *trueBranch,
30.113 + BytecodeEmitter::Label *falseBranch,
30.114 + BytecodeEmitter::Label *fallthrough);
30.115 + Code *compileCode(Scope *scope, unsigned lineno);
30.116 + Function *compileFunction(ModuleData *module, FunctionStatement *fun);
30.117 + void visitForALU(Type *needed, Expression *node);
30.118 +
30.119 + void getEnvSlot(Variable *var);
30.120 + void setEnvSlot(Variable *var);
30.121 +
30.122 + bool tableswitch(SwitchStatement *node);
30.123 +
30.124 + public:
30.125 + BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
30.126 +
30.127 + Module *compile();
30.128 +
30.129 + public:
30.130 + void visit(NameProxy *name);
30.131 + void visit(Assignment *node);
30.132 + void visit(BinaryExpression *node);
30.133 + void visit(ReturnStatement *node);
30.134 + void visit(ForStatement *node);
30.135 + void visit(BlockStatement *node);
30.136 + void visit(VariableDeclaration *node);
30.137 + void visit(IntegerLiteral *node);
30.138 + void visit(BooleanLiteral *node);
30.139 + void visit(FloatLiteral *node);
30.140 + void visit(StringLiteral *node);
30.141 + void visit(ExpressionStatement *node);
30.142 + void visit(FunctionStatement *node);
30.143 + void visit(CallExpression *node);
30.144 + void visit(IfStatement *node);
30.145 + void visit(IndexExpression *node);
30.146 + void visit(EnumStatement *node);
30.147 + void visit(WhileStatement *node);
30.148 + void visit(BreakStatement *node);
30.149 + void visit(ContinueStatement *node);
30.150 + void visit(IncDecExpression *node);
30.151 + void visit(UnaryExpression *node);
30.152 + void visit(TernaryExpression *node);
30.153 + void visit(StructureStatement *node);
30.154 + void visit(FieldExpression *node);
30.155 + void visit(SwitchStatement *node);
30.156 + void visit(FunctionTypeStatement *node);
30.157 + void visit(ArrayLiteral *node);
30.158 + void visit(ImportStatement *node);
30.159 +};
30.160 +
30.161 +}
30.162 +
30.163 +#endif // _include_bytecode_generator_h_
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/src/OldSema.cpp Sat Nov 17 18:41:01 2012 -0800
31.3 @@ -0,0 +1,1899 @@
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 JITCraft.
31.9 + *
31.10 + * JITCraft 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 + * Foobar 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 + * JITCraft. If not, see http://www.gnu.org/licenses/.
31.21 + */
31.22 +#include <string.h>
31.23 +#include "SemanticAnalysis.h"
31.24 +#include "../Types.h"
31.25 +#include "../Zone.h"
31.26 +#include "../TypeManager.h"
31.27 +#include "../Strings.h"
31.28 +#include "../Box.h"
31.29 +#include "../Array.h"
31.30 +#include "../Heap-inl.h"
31.31 +#include "Scopes.h"
31.32 +#include "NameBinding.h"
31.33 +
31.34 +using namespace ke;
31.35 +
31.36 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
31.37 + : zone_(zone),
31.38 + cc_(cc),
31.39 + tree_(tree),
31.40 + scope_(NULL),
31.41 + loop_(NULL)
31.42 +{
31.43 +}
31.44 +
31.45 +bool
31.46 +SemanticAnalysis::analyze()
31.47 +{
31.48 + assert(false);
31.49 + return false;
31.50 +}
31.51 +
31.52 +
31.53 +#if 0
31.54 +
31.55 +static inline bool
31.56 +IsPrimitiveType(Type *type, PrimitiveType primitive)
31.57 +{
31.58 + if (!type)
31.59 + return false;
31.60 +
31.61 + if (!type->isPrimitive())
31.62 + return false;
31.63 +
31.64 + return primitive == type->primitive();
31.65 +}
31.66 +
31.67 +static inline bool
31.68 +EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
31.69 + BoxedPrimitive *out)
31.70 +{
31.71 + switch (kind) {
31.72 + case TOK_PLUS:
31.73 + *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
31.74 + return true;
31.75 +
31.76 + case TOK_SHL:
31.77 + *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
31.78 + return true;
31.79 +
31.80 + default:
31.81 + return false;
31.82 + }
31.83 +}
31.84 +
31.85 +static inline bool
31.86 +EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
31.87 +{
31.88 + switch (kind) {
31.89 + case TOK_MINUS:
31.90 + *out = BoxedPrimitive::Int(-inner.toInt());
31.91 + return true;
31.92 +
31.93 + default:
31.94 + return false;
31.95 + }
31.96 +}
31.97 +
31.98 +static bool
31.99 +EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
31.100 +{
31.101 + switch (expression->kind()) {
31.102 + case AstNode::kBinaryExpression:
31.103 + {
31.104 + BoxedPrimitive left;
31.105 + BoxedPrimitive right;
31.106 + BinaryExpression *b = expression->toBinaryExpression();
31.107 + if (!EvaluateForConstant(b->left(), &left) ||
31.108 + !EvaluateForConstant(b->right(), &right))
31.109 + {
31.110 + return false;
31.111 + }
31.112 + return EvaluateBinaryOperation(b->token(), left, right, out);
31.113 + }
31.114 +
31.115 + case AstNode::kUnaryExpression:
31.116 + {
31.117 + BoxedPrimitive inner;
31.118 + UnaryExpression *u = expression->toUnaryExpression();
31.119 + if (!EvaluateForConstant(u->expression(), &inner))
31.120 + return false;
31.121 + return EvaluateUnaryOperation(u->token(), inner, out);
31.122 + }
31.123 +
31.124 + case AstNode::kNameProxy:
31.125 + {
31.126 + NameProxy *proxy = expression->toNameProxy();
31.127 + if (proxy->binding()->kind() != BoundName::CONSTANT)
31.128 + return false;
31.129 +
31.130 + NamedConstant *c = proxy->binding()->toNamedConstant();
31.131 + if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
31.132 + return false;
31.133 +
31.134 + *out = c->value();
31.135 + return true;
31.136 + }
31.137 +
31.138 + case AstNode::kBooleanLiteral:
31.139 + *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
31.140 + return true;
31.141 +
31.142 + case AstNode::kIntegerLiteral:
31.143 + *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
31.144 + return true;
31.145 +
31.146 + default:
31.147 + return false;
31.148 + }
31.149 +}
31.150 +
31.151 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
31.152 + : zone_(zone),
31.153 + cc_(cc),
31.154 + tree_(tree),
31.155 + scope_(NULL),
31.156 + loop_(NULL)
31.157 +{
31.158 +}
31.159 +
31.160 +bool
31.161 +SemanticAnalysis::analyze()
31.162 +{
31.163 + if (cc_.failures())
31.164 + return false;
31.165 +
31.166 + scope_ = tree_->globalScope();
31.167 + assert(scope_->kind() == Scope::GLOBAL);
31.168 +
31.169 + for (size_t i = 0; i < tree_->statements()->length(); i++) {
31.170 + Statement *statement = tree_->statements()->at(i);
31.171 + if (statement->isFunctionStatement()) {
31.172 + FunctionStatement *funstmt = statement->toFunctionStatement();
31.173 + if (!preanalyze(funstmt))
31.174 + return false;
31.175 + } else if (statement->isEnumStatement()) {
31.176 + EnumStatement *enumstmt = statement->toEnumStatement();
31.177 +
31.178 + // We pre-fill global enum types, since they may occur in function
31.179 + // signatures. This should probably be somewhere else...
31.180 + enumstmt->accept(this);
31.181 + } else if (statement->isStructureStatement()) {
31.182 + StructureStatement *node = statement->toStructureStatement();
31.183 + node->accept(this);
31.184 + if (!node->decl()->type())
31.185 + return false;
31.186 + } else if (statement->isFunctionTypeStatement()) {
31.187 + FunctionTypeStatement *node = statement->toFunctionTypeStatement();
31.188 + node->accept(this);
31.189 + if (!node->decl()->type())
31.190 + return false;
31.191 + }
31.192 + }
31.193 +
31.194 + for (size_t i = 0; i < tree_->statements()->length(); i++) {
31.195 + Statement *statement = tree_->statements()->at(i);
31.196 +
31.197 + // We can't double-process these. Maybe put this check somewhere else.
31.198 + if (statement->isEnumStatement())
31.199 + continue;
31.200 +
31.201 + statement->accept(this);
31.202 + }
31.203 +
31.204 + if (!determineLiveFunctions())
31.205 + return false;
31.206 +
31.207 + return !cc_.failures();
31.208 +}
31.209 +
31.210 +bool
31.211 +SemanticAnalysis::determineLiveFunctions()
31.212 +{
31.213 + Vector<NamedFunction *> worklist;
31.214 +
31.215 + // Add the root set.
31.216 + for (size_t i = 0; i < tree_->statements()->length(); i++) {
31.217 + Statement *statement = tree_->statements()->at(i);
31.218 + if (!statement->isFunctionStatement())
31.219 + continue;
31.220 +
31.221 + FunctionStatement *stmt = statement->toFunctionStatement();
31.222 + NamedFunction *fun = stmt->fun();
31.223 + if (!fun->used())
31.224 + continue;
31.225 +
31.226 + for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
31.227 + NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
31.228 +
31.229 + // Names in these lists are always unused, however, we mark them
31.230 + // as used while inserting into the work queue, to avoid double-
31.231 + // insertion.
31.232 + if (name->used())
31.233 + continue;
31.234 +
31.235 + if (!worklist.append(name))
31.236 + return false;
31.237 +
31.238 + name->setUsed();
31.239 + }
31.240 + }
31.241 +
31.242 + while (!worklist.empty()) {
31.243 + NamedFunction *fun = worklist.popCopy();
31.244 +
31.245 + for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
31.246 + NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
31.247 + if (name->used())
31.248 + continue;
31.249 + if (!worklist.append(name))
31.250 + return false;
31.251 + name->setUsed();
31.252 + }
31.253 + }
31.254 +
31.255 + return true;
31.256 +}
31.257 +
31.258 +Type *
31.259 +SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
31.260 +{
31.261 + if (!name)
31.262 + return zone_->types()->getPrimitive(PrimitiveType_Int32);
31.263 +
31.264 + if (name->kind() == BoundName::UNBOUND) {
31.265 + cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
31.266 + return NULL;
31.267 + }
31.268 +
31.269 + if (name->kind() != BoundName::TYPE) {
31.270 + cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
31.271 + return NULL;
31.272 + }
31.273 +
31.274 + if (!name->type())
31.275 + return NULL;
31.276 +
31.277 + return name->type();
31.278 +}
31.279 +
31.280 +Type *
31.281 +SemanticAnalysis::visitAndApplyType(Expression *expression)
31.282 +{
31.283 + expression->accept(this);
31.284 + return expression->type();
31.285 +}
31.286 +
31.287 +Type *
31.288 +SemanticAnalysis::visitForLoad(Expression *expression)
31.289 +{
31.290 + Local<Type> type(zone_, visitAndApplyType(expression));
31.291 + if (!type)
31.292 + return NULL;
31.293 +
31.294 + if (type->isReference()) {
31.295 + expression->setType(type->contained());
31.296 + } else if (expression->isCallExpression()) {
31.297 + if (type->isVoid()) {
31.298 + CallExpression *call = expression->toCallExpression();
31.299 + cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
31.300 + return NULL;
31.301 + }
31.302 + }
31.303 +
31.304 + return expression->type();
31.305 +}
31.306 +
31.307 +void
31.308 +SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
31.309 +{
31.310 + const char *op = TokenNames[token];
31.311 + const char *name = GetTypeName(type);
31.312 +
31.313 + cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
31.314 +}
31.315 +
31.316 +void
31.317 +SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
31.318 +{
31.319 + const char *op = TokenNames[token];
31.320 + const char *leftName = GetTypeName(left);
31.321 + const char *rightName = GetTypeName(right);
31.322 +
31.323 + cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
31.324 +}
31.325 +
31.326 +Type *
31.327 +SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
31.328 +{
31.329 + if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
31.330 + (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
31.331 + {
31.332 + // If either side is a float, the other side must be a float or int.
31.333 + if (left->isFloat() || right->isFloat()) {
31.334 + Type *floatType = left->isFloat() ? left : right;
31.335 + Type *other = left->isFloat() ? right : left;
31.336 + if (other->isFloat() || other->isInt32())
31.337 + return floatType;
31.338 + }
31.339 + }
31.340 +
31.341 + if (token == TOK_OR || token == TOK_AND) {
31.342 + if (!canTest(node, left) || !canTest(node, right))
31.343 + return NULL;
31.344 + return zone_->types()->getPrimitive(PrimitiveType_Bool);
31.345 + }
31.346 +
31.347 + if (token >= TOK_EQUALS && token <= TOK_GE) {
31.348 + if ((left->isFloat() || left->isInt32()) &&
31.349 + (right->isFloat() || right->isInt32()))
31.350 + {
31.351 + return zone_->types()->getPrimitive(PrimitiveType_Bool);
31.352 + }
31.353 + binaryTypeError(node, token, left, right);
31.354 + return NULL;
31.355 + }
31.356 +
31.357 + if (!left->isInt32() || !right->isInt32()) {
31.358 + binaryTypeError(node, token, left, right);
31.359 + return NULL;
31.360 + }
31.361 +
31.362 + return left;
31.363 +}
31.364 +
31.365 +bool
31.366 +SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
31.367 +{
31.368 + if (!type->isPrimitive() && !type->isEnum()) {
31.369 + cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
31.370 + return false;
31.371 + }
31.372 + return true;
31.373 +}
31.374 +
31.375 +Type *
31.376 +SemanticAnalysis::visitForLValue(Expression *expression)
31.377 +{
31.378 + if (expression->isIndexExpression()) {
31.379 + Type *type = visitAndApplyType(expression);
31.380 + if (!type)
31.381 + return NULL;
31.382 +
31.383 + // if (type->isConst()) {
31.384 + // cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
31.385 + // return NULL;
31.386 + // }
31.387 +
31.388 + return type;
31.389 + }
31.390 +
31.391 + if (expression->isFieldExpression()) {
31.392 + Type *type = visitAndApplyType(expression);
31.393 + if (!type)
31.394 + return NULL;
31.395 +
31.396 + // if (expression->toFieldExpression()->left()->type()->isConst()) {
31.397 + // cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
31.398 + // return NULL;
31.399 + // }
31.400 +
31.401 + return type;
31.402 + }
31.403 +
31.404 + if (!expression->isNameProxy()) {
31.405 + cc_.reportError(expression->pos(), Message_ExpectedLValue);
31.406 + return NULL;
31.407 + }
31.408 +
31.409 + NameProxy *proxy = expression->toNameProxy();
31.410 + if (!proxy->binding()->kind() == BoundName::VARIABLE) {
31.411 + cc_.reportError(expression->pos(), Message_ExpectedLValue);
31.412 + return NULL;
31.413 + }
31.414 +
31.415 + Variable *var = proxy->binding()->toVariable();
31.416 + if (!var->type())
31.417 + return NULL;
31.418 +
31.419 + if (var->type()->isReference()) {
31.420 + if (var->type()->isConst()) {
31.421 + cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
31.422 + return NULL;
31.423 + }
31.424 + return var->type()->contained();
31.425 + }
31.426 + return var->type();
31.427 +}
31.428 +
31.429 +SemanticAnalysis::ControlStatus
31.430 +SemanticAnalysis::visitForControl(Statement *statement)
31.431 +{
31.432 + ControlScope scope(&control_);
31.433 + statement->accept(this);
31.434 + return scope.status();
31.435 +}
31.436 +
31.437 +void
31.438 +SemanticAnalysis::visit(NameProxy *name)
31.439 +{
31.440 + BoundName *binding = name->binding();
31.441 +
31.442 + if (binding->scope()->kind() == Scope::GLOBAL) {
31.443 + if (!function_ || function_->isPublic()) {
31.444 + // Whatever we're referencing must be kept alive no matter what.
31.445 + // As such, we simply mark it used, and don't do anything special.
31.446 + binding->setUsed();
31.447 + } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
31.448 + // Otherwise, we're inside a normal stock or function. Since we
31.449 + // don't really know if we've been used yet, we shouldn't
31.450 + // prematurely references as alive. Instead, we keep a list of
31.451 + // which names have been used, so we can mark them later if needed.
31.452 + //
31.453 + // Note that we skip this step if the binding is already in the
31.454 + // root set.
31.455 + if (!function_->addUsedGlobal(binding))
31.456 + return;
31.457 + }
31.458 + }
31.459 +
31.460 + name->setType(binding->type());
31.461 +}
31.462 +
31.463 +void
31.464 +SemanticAnalysis::visit(Assignment *node)
31.465 +{
31.466 + Local<Type> exprType(zone_, visitForLoad(node->expression()));
31.467 + if (!exprType)
31.468 + return ;
31.469 +
31.470 + Local<Type> type(zone_, visitForLValue(node->lvalue()));
31.471 + if (!type)
31.472 + return;
31.473 +
31.474 + if (node->token() != TOK_ASSIGN) {
31.475 + if (!typeCheckBinary(node, node->token(), type, exprType))
31.476 + return;
31.477 + }
31.478 +
31.479 + if (!typeCheckAssignment(node->pos(), exprType, type, true))
31.480 + return;
31.481 +
31.482 + node->setType(type);
31.483 +}
31.484 +
31.485 +void
31.486 +SemanticAnalysis::visit(IncDecExpression *node)
31.487 +{
31.488 + Local<Type> type(zone_, visitForLValue(node->expression()));
31.489 + if (!type)
31.490 + return;
31.491 +
31.492 + assert(!type->isReference());
31.493 +
31.494 + if (!type->isInt32() && !type->isFloat()) {
31.495 + unaryTypeError(node, node->token(), type);
31.496 + return;
31.497 + }
31.498 +
31.499 + node->setType(type);
31.500 +}
31.501 +
31.502 +void
31.503 +SemanticAnalysis::visit(UnaryExpression *node)
31.504 +{
31.505 + Local<Type> type(zone_, visitForLoad(node->expression()));
31.506 + if (!type)
31.507 + return;
31.508 +
31.509 + switch (node->token())
31.510 + {
31.511 + case TOK_NOT:
31.512 + if (!canTest(node->expression(), type))
31.513 + return;
31.514 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
31.515 + if (!type)
31.516 + return;
31.517 + node->setType(type);
31.518 + break;
31.519 +
31.520 + case TOK_MINUS:
31.521 + if (!type->isFloat() && !type->isInt32()) {
31.522 + unaryTypeError(node, node->token(), type);
31.523 + return;
31.524 + }
31.525 + node->setType(type);
31.526 + break;
31.527 +
31.528 + case TOK_LABEL:
31.529 + {
31.530 + Local<Type> to(zone_, bindType(node->pos(), node->type()));
31.531 + if (!to)
31.532 + return;
31.533 +
31.534 + if ((!type->isFloat() && !type->isInt32OrEnum()) ||
31.535 + (!to->isFloat() && !to->isInt32OrEnum()))
31.536 + {
31.537 + unaryTypeError(node, node->token(), type);
31.538 + return;
31.539 + }
31.540 +
31.541 + node->setType(to);
31.542 + break;
31.543 + }
31.544 +
31.545 + case TOK_SIZEOF:
31.546 + {
31.547 + if (!type->isArray()) {
31.548 + cc_.reportError(node->pos(), Message_SizeofNeedsArray);
31.549 + return;
31.550 + }
31.551 + node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
31.552 + break;
31.553 + }
31.554 +
31.555 + default:
31.556 + assert(node->token() == TOK_TILDE);
31.557 + if (!type->isInt32()) {
31.558 + unaryTypeError(node, node->token(), type);
31.559 + return;
31.560 + }
31.561 + node->setType(type);
31.562 + break;
31.563 + }
31.564 +}
31.565 +
31.566 +void
31.567 +SemanticAnalysis::visit(TernaryExpression *node)
31.568 +{
31.569 + Local<Type> type(zone_, visitForLoad(node->condition()));
31.570 + if (!type)
31.571 + return;
31.572 +
31.573 + if (!canTest(node->condition(), type))
31.574 + return;
31.575 +
31.576 + Local<Type> left(zone_, visitForLoad(node->left()));
31.577 + Local<Type> right(zone_, visitForLoad(node->right()));
31.578 + if (!left || !right)
31.579 + return;
31.580 +
31.581 + if (left != right) {
31.582 + binaryTypeError(node, TOK_QMARK, left, right);
31.583 + return;
31.584 + }
31.585 +}
31.586 +
31.587 +void
31.588 +SemanticAnalysis::visit(BinaryExpression *node)
31.589 +{
31.590 + Local<Type> left(zone_, visitForLoad(node->left()));
31.591 + Local<Type> right(zone_, visitForLoad(node->right()));
31.592 + if (!left || !right)
31.593 + return;
31.594 +
31.595 + Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
31.596 + if (!result)
31.597 + return;
31.598 +
31.599 + node->setType(result);
31.600 +}
31.601 +
31.602 +void
31.603 +SemanticAnalysis::visit(ReturnStatement *node)
31.604 +{
31.605 + // Set this early, so if we error we don't get more errors.
31.606 + control_->returns(Returns_Always);
31.607 +
31.608 + if (!node->expression()) {
31.609 + if (!function_->type()->returnType()->isVoid())
31.610 + cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
31.611 + return;
31.612 + }
31.613 +
31.614 + Local<Type> type(zone_, visitForLoad(node->expression()));
31.615 + if (!type)
31.616 + return;
31.617 +
31.618 + Local<Type> returnType(zone_, function_->type()->returnType());
31.619 + if (!typeCheckAssignment(node->pos(), type, returnType, true))
31.620 + return;
31.621 +}
31.622 +
31.623 +void
31.624 +SemanticAnalysis::visit(ForStatement *node)
31.625 +{
31.626 + LoopScope loop(&loop_);
31.627 +
31.628 + if (node->scope())
31.629 + scope_ = node->scope();
31.630 +
31.631 + if (node->initialization())
31.632 + node->initialization()->accept(this);
31.633 +
31.634 + if (node->condition()) {
31.635 + Local<Type> type(zone_, visitForLoad(node->condition()));
31.636 + if (!type || !canTest(node->condition(), type)) {
31.637 + return;
31.638 + }
31.639 + }
31.640 +
31.641 + if (node->update())
31.642 + node->update()->accept(this);
31.643 +
31.644 + ControlStatus status = visitForControl(node->body());
31.645 +
31.646 + // If there is a condition, we treat this like a while loop. Otherwise,
31.647 + // join point is only reachable if the loop contains a break. The
31.648 + // termination status doesn't tell us anything yet.
31.649 + if (node->condition() || loop.breaks())
31.650 + control_->merge(status, ControlStatus(false, Returns_Never));
31.651 + else
31.652 + control_->terminate(status.returns());
31.653 +
31.654 + if (node->scope())
31.655 + scope_ = scope_->enclosing();
31.656 +}
31.657 +
31.658 +void
31.659 +SemanticAnalysis::visit(WhileStatement *node)
31.660 +{
31.661 + LoopScope loop(&loop_);
31.662 +
31.663 + Local<Type> type(zone_, visitForLoad(node->condition()));
31.664 + if (!type || !canTest(node->condition(), type)) {
31.665 + return;
31.666 + }
31.667 +
31.668 + ControlStatus status = visitForControl(node->body());
31.669 +
31.670 + // Detect loops that will always have a fork in the control-flow graph.
31.671 + // This will be a |while| loop, or a |do-while| loop whose body does
31.672 + // not terminate.
31.673 + //
31.674 + // For now, we treat these as an |if| regardless of the direction the
31.675 + // branch can take. That means the control-flow is always conditional.
31.676 + if (node->token() == TOK_WHILE ||
31.677 + !status.terminates() ||
31.678 + loop.breaks())
31.679 + {
31.680 + control_->merge(status, ControlStatus(false, Returns_Never));
31.681 + } else {
31.682 + // At this point, we've got a do-while loop with a |return| or
31.683 + // |continue|, meaning that the rest of the block is unreachable.
31.684 + control_->terminate(status.returns());
31.685 + }
31.686 +}
31.687 +
31.688 +void
31.689 +SemanticAnalysis::visit(BlockStatement *node)
31.690 +{
31.691 + if (node->scope())
31.692 + scope_ = node->scope();
31.693 + for (size_t i = 0; i < node->statements()->length(); i++) {
31.694 + Statement *statement = node->statements()->at(i);
31.695 + statement->accept(this);
31.696 + }
31.697 + if (node->scope())
31.698 + scope_ = scope_->enclosing();
31.699 +}
31.700 +
31.701 +static inline bool
31.702 +IsScalarString(Type *type)
31.703 +{
31.704 + if (type->isPrimitive() && type->primitive() == PrimitiveType_Char)
31.705 + return true;
31.706 + if (type->isReference())
31.707 + return IsScalarString(type->contained());
31.708 + return false;
31.709 +}
31.710 +
31.711 +static const int INFER_ARRAY_SIZE = 0;
31.712 +static const int EVAL_ARRAY_SIZE = -1;
31.713 +static const int DYNAMIC_ARRAY_SIZE = -2;
31.714 +
31.715 +bool
31.716 +SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
31.717 +{
31.718 + bool hadEmptySize = false;
31.719 +
31.720 + for (size_t i = 0; i < exprs->length(); i++) {
31.721 + Expression *expr = exprs->at(i);
31.722 + if (!expr) {
31.723 + dims[i] = INFER_ARRAY_SIZE;
31.724 + hadEmptySize = true;
31.725 + continue;
31.726 + }
31.727 +
31.728 + BoxedPrimitive box;
31.729 + if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
31.730 + int size = box.toInt();
31.731 + if (size <= 0) {
31.732 + cc_.reportError(expr->pos(), Message_BadArraySize);
31.733 + return false;
31.734 + }
31.735 +
31.736 + dims[i] = size;
31.737 + continue;
31.738 + }
31.739 +
31.740 + Local<Type> exprType(zone_, visitForLoad(expr));
31.741 + if (!exprType)
31.742 + return false;
31.743 +
31.744 + if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
31.745 + cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
31.746 + return false;
31.747 + }
31.748 +
31.749 + if (hadEmptySize) {
31.750 + cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
31.751 + return false;
31.752 + }
31.753 +
31.754 + dims[i] = EVAL_ARRAY_SIZE;
31.755 + }
31.756 +
31.757 + return true;
31.758 +}
31.759 +
31.760 +bool
31.761 +SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
31.762 + int dims[MAX_ARRAY_DEPTH],
31.763 + unsigned dimcount, unsigned level)
31.764 +{
31.765 + if (dims[level] == EVAL_ARRAY_SIZE) {
31.766 + cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
31.767 + return false;
31.768 + }
31.769 +
31.770 + if (dims[level] == INFER_ARRAY_SIZE) {
31.771 + // Strings always become dynamic arrays.
31.772 + if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
31.773 + dims[level] = literal->expressions()->length();
31.774 + } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
31.775 + cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
31.776 + return false;
31.777 + } else {
31.778 + if (literal->expressions()->length() != unsigned(dims[level])) {
31.779 + cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
31.780 + return false;
31.781 + }
31.782 + }
31.783 +
31.784 + if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
31.785 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
31.786 + Expression *expr = literal->expressions()->at(i);
31.787 + if (!expr->isStringLiteral()) {
31.788 + cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
31.789 + return false;
31.790 + }
31.791 +
31.792 + StringLiteral *lit = expr->toStringLiteral();
31.793 + if (dims[level + 1] > 0 &&
31.794 + unsigned(dims[level]) < lit->string()->length())
31.795 + {
31.796 + cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
31.797 + return false;
31.798 + }
31.799 + if (!visitAndApplyType(lit))
31.800 + return false;
31.801 + }
31.802 + } else if (level == dimcount - 1) {
31.803 + Local<Type> type(zone_);
31.804 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
31.805 + Expression *expr = literal->expressions()->at(i);
31.806 + if (expr->isArrayLiteral()) {
31.807 + cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
31.808 + return false;
31.809 + }
31.810 +
31.811 + if ((type = visitAndApplyType(expr)) == NULL)
31.812 + return false;
31.813 +
31.814 + if (!typeCheckAssignment(expr->pos(), type, contained, true))
31.815 + return false;
31.816 + }
31.817 + } else {
31.818 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
31.819 + Expression *expr = literal->expressions()->at(i);
31.820 + if (!expr->isArrayLiteral()) {
31.821 + cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
31.822 + return false;
31.823 + }
31.824 +
31.825 + assert(expr->toArrayLiteral()->isFixed());
31.826 +
31.827 + if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
31.828 + contained,
31.829 + dims,
31.830 + dimcount,
31.831 + level + 1))
31.832 + {
31.833 + return false;
31.834 + }
31.835 + }
31.836 + }
31.837 +
31.838 + return true;
31.839 +}
31.840 +
31.841 +void
31.842 +SemanticAnalysis::visit(VariableDeclaration *node)
31.843 +{
31.844 + Local<Type> type(zone_, bindType(node->pos(), node->type()));
31.845 + if (!type)
31.846 + return;
31.847 +
31.848 +#if 0
31.849 + if (node->postDimensions() || type->isArray()) {
31.850 + // The type could be an array type, so sum the type and postDimensions
31.851 + // together.
31.852 + unsigned dimcount = node->postDimensions()->length();
31.853 + if (type->isArray())
31.854 + dimcount += type->levels();
31.855 + if (dimcount > MAX_ARRAY_DEPTH) {
31.856 + cc_.reportError(node->pos(), Message_MaximumArrayDepth);
31.857 + return;
31.858 + }
31.859 +
31.860 + // Take an initial guess at the array dimension sizes.
31.861 + int dims[MAX_ARRAY_DEPTH];
31.862 + if (!evaluateDimensions(node->postDimensions(), dims))
31.863 + return;
31.864 +
31.865 + // Now add in the type's array dimensions.
31.866 + Local<Type> contained(zone_, type);
31.867 + for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
31.868 + if (type->isFixedLength())
31.869 + dims[i] = type->fixedLength();
31.870 + else
31.871 + dims[i] = DYNAMIC_ARRAY_SIZE;
31.872 + contained = contained->contained();
31.873 + }
31.874 +
31.875 + Expression *initializer = node->initialization();
31.876 + if (initializer &&
31.877 + initializer->isArrayLiteral() &&
31.878 + initializer->toArrayLiteral()->isFixed())
31.879 + {
31.880 + // Fixed array initializers are special; we use them to infer any
31.881 + // missing information in the original array. We do not evaluate
31.882 + // the array initializer as an expression.
31.883 + if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
31.884 + contained,
31.885 + dims,
31.886 + dimcount,
31.887 + 0))
31.888 + {
31.889 + return;
31.890 + }
31.891 + initializer = NULL;
31.892 + }
31.893 +
31.894 + // We now have enough information to build the actual array type.
31.895 + // Start from the original dimcount, not the one computed for
31.896 + // initializers.
31.897 + for (size_t i = node->postDimensions()->length() - 1;
31.898 + i < node->postDimensions()->length();
31.899 + i--)
31.900 + {
31.901 + int size = dims[i] > 0
31.902 + ? dims[i]
31.903 + : Type::DYNAMIC_ARRAY_SIZE;
31.904 +
31.905 + type = zone_->types()->newArray(type, size, false);
31.906 + if (!type)
31.907 + return;
31.908 + }
31.909 +
31.910 + // Finally, if we had a non-fixed initializer, make sure it type
31.911 + // checks.
31.912 + if (initializer) {
31.913 + Local<Type> right(zone_, visitForLoad(initializer));
31.914 + if (!right)
31.915 + return;
31.916 +
31.917 + if (!typeCheckAssignment(node->pos(), right, type, true))
31.918 + return;
31.919 + }
31.920 + } else {
31.921 + if (node->initialization()) {
31.922 + Local<Type> right(zone_, visitForLoad(node->initialization()));
31.923 + if (!right)
31.924 + return;
31.925 + if (!typeCheckAssignment(node->pos(), right, type, true))
31.926 + return;
31.927 + }
31.928 +
31.929 + if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) {
31.930 + cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
31.931 + return;
31.932 + }
31.933 + }
31.934 +#endif
31.935 +
31.936 +#if 0
31.937 + // If this variable is stack allocated, we could use the LIFO heap
31.938 + // to allocate it. If that's the case, make sure to reserve a slot
31.939 + // so we can unwind the LIFO heap at the end of this scope.
31.940 + if (!node->variable()->needsHeapAllocation()) {
31.941 + if (type->isArray() || type->isStruct())
31.942 + scope_->setUsesLifoHeap();
31.943 + }
31.944 +
31.945 + node->variable()->setType(type);
31.946 +#endif
31.947 +}
31.948 +
31.949 +void
31.950 +SemanticAnalysis::visit(IntegerLiteral *node)
31.951 +{
31.952 + node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
31.953 +}
31.954 +
31.955 +void
31.956 +SemanticAnalysis::visit(BooleanLiteral *node)
31.957 +{
31.958 + node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool));
31.959 +}
31.960 +
31.961 +void
31.962 +SemanticAnalysis::visit(ExpressionStatement *node)
31.963 +{
31.964 + visitAndApplyType(node->expression());
31.965 +}
31.966 +
31.967 +Box *
31.968 +SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
31.969 +{
31.970 + Local<Type> given(zone_, visitForLoad(parameter->initializer()));
31.971 +
31.972 + BoxedPrimitive prim;
31.973 + if (EvaluateForConstant(parameter->initializer(), &prim)) {
31.974 + if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
31.975 + return NULL;
31.976 +
31.977 + if (prim.type() == PrimitiveType_Int32)
31.978 + return Box::New(zone_, given, prim.toInt());
31.979 + return Box::New(zone_, given, prim.toFloat());
31.980 + } else if (parameter->initializer()->isStringLiteral()) {
31.981 + StringLiteral *literal = parameter->initializer()->toStringLiteral();
31.982 +
31.983 + if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
31.984 + return NULL;
31.985 +
31.986 + Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, given));
31.987 + if (!map)
31.988 + return NULL;
31.989 +
31.990 + Local<Array> array(zone_,
31.991 + Array::NewString(zone_,
31.992 + map,
31.993 + literal->string()->raw(),
31.994 + literal->string()->length(),
31.995 + Heap::Tenure_Old));
31.996 + if (!array)
31.997 + return NULL;
31.998 +
31.999 + return Box::NewObj(zone_, given, array, Heap::Tenure_Old);
31.1000 + }
31.1001 +
31.1002 + cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant);
31.1003 + return NULL;
31.1004 +}
31.1005 +
31.1006 +bool
31.1007 +SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
31.1008 + FixedArray **argsp, FixedArray **defaultsp)
31.1009 +{
31.1010 + Local<FixedArray> args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
31.1011 + if (!args)
31.1012 + return false;
31.1013 +
31.1014 + Local<FixedArray> defaults(zone_);
31.1015 +
31.1016 + // Apply types to arguments.
31.1017 + for (size_t i = 0; i < sig.parameters()->length(); i++) {
31.1018 + Parameter *parameter = sig.parameters()->at(i);
31.1019 +
31.1020 +#if 0
31.1021 + Local<Type> type(zone_, bindType(parameter->variable()->pos(), parameter->type()));
31.1022 + if (!type)
31.1023 + return false;
31.1024 +
31.1025 + if (parameter->reference()) {
31.1026 + if (parameter->dimensions()) {
31.1027 + cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
31.1028 + return false;
31.1029 + }
31.1030 +
31.1031 + if (type->isStruct()) {
31.1032 + cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference);
31.1033 + return false;
31.1034 + }
31.1035 +
31.1036 + type = zone_->types()->getReference(type, parameter->isConst());
31.1037 + if (!type)
31.1038 + return false;
31.1039 + } else if (parameter->dimensions()) {
31.1040 + type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
31.1041 + if (!type)
31.1042 + return false;
31.1043 +
31.1044 + if (kind == TOK_NATIVE && type->levels() > 1) {
31.1045 + cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
31.1046 + return false;
31.1047 + }
31.1048 + }
31.1049 +
31.1050 + if (IsScalarString(type)) {
31.1051 + cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
31.1052 + return false;
31.1053 + }
31.1054 +
31.1055 + args->set(zone_, i, type);
31.1056 + parameter->variable()->setType(type);
31.1057 +
31.1058 + if (parameter->initializer()) {
31.1059 + if (!defaults) {
31.1060 + defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old);
31.1061 + if (!defaults)
31.1062 + return false;
31.1063 + }
31.1064 +
31.1065 + Local<Box> box(zone_, evaluateDefaultParameter(type, parameter));
31.1066 + if (!box)
31.1067 + return false;
31.1068 +
31.1069 + defaults->set(zone_, i, box);
31.1070 + }
31.1071 +#endif
31.1072 + }
31.1073 +
31.1074 + *argsp = args;
31.1075 + *defaultsp = defaults;
31.1076 +
31.1077 + return true;
31.1078 +}
31.1079 +
31.1080 +void
31.1081 +SemanticAnalysis::visit(FunctionTypeStatement *node)
31.1082 +{
31.1083 + if (node->decl()->type())
31.1084 + return;
31.1085 +
31.1086 + Local<FixedArray> args(zone_);
31.1087 + Local<FixedArray> defaults(zone_);
31.1088 +
31.1089 + const FunctionSignature &sig= node->signature();
31.1090 + if (!buildFunctionArgs(node,
31.1091 + TOK_STOCK,
31.1092 + sig,
31.1093 + args.address(),
31.1094 + defaults.address()))
31.1095 + {
31.1096 + return;
31.1097 + }
31.1098 +
31.1099 +#if 0
31.1100 + Local<Type> returnType(zone_);
31.1101 + if (sig.returnType())
31.1102 + returnType = bindType(node->pos(), sig.returnType());
31.1103 + else
31.1104 + returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
31.1105 +
31.1106 + if (!returnType)
31.1107 + return;
31.1108 +
31.1109 + Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args, defaults));
31.1110 + if (!funtype)
31.1111 + return;
31.1112 +
31.1113 + node->decl()->setType(funtype);
31.1114 +#endif
31.1115 +}
31.1116 +
31.1117 +Type *
31.1118 +SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
31.1119 +{
31.1120 + Local<Type> arrayType(zone_, type);
31.1121 +
31.1122 + unsigned dimcount = dimensions->length();
31.1123 + if (type->isArray())
31.1124 + dimcount += type->levels();
31.1125 +
31.1126 + if (dimcount > MAX_ARRAY_DEPTH) {
31.1127 + cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
31.1128 + Message_MaximumArrayDepth);
31.1129 + return false;
31.1130 + }
31.1131 +
31.1132 + // Note: constness is sort of bogus. Fix this sometime.
31.1133 + for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
31.1134 + Expression *expr = dimensions->at(i);
31.1135 + if (!expr) {
31.1136 + arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
31.1137 + if (!arrayType)
31.1138 + return NULL;
31.1139 +
31.1140 + continue;
31.1141 + }
31.1142 +
31.1143 + BoxedPrimitive box;
31.1144 + if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
31.1145 + cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
31.1146 + return NULL;
31.1147 + }
31.1148 +
31.1149 + if (box.toInt() <= 0) {
31.1150 + cc_.reportError(expr->pos(), Message_BadArraySize);
31.1151 + return NULL;
31.1152 + }
31.1153 +
31.1154 + arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
31.1155 + if (!arrayType)
31.1156 + return NULL;
31.1157 + }
31.1158 +
31.1159 + return arrayType;
31.1160 +}
31.1161 +
31.1162 +bool
31.1163 +SemanticAnalysis::preanalyze(FunctionStatement *node)
31.1164 +{
31.1165 + Local<FixedArray> args(zone_);
31.1166 + Local<FixedArray> defaults(zone_);
31.1167 +
31.1168 + const FunctionSignature &sig = node->signature();
31.1169 + if (!buildFunctionArgs(node,
31.1170 + node->fun()->token(),
31.1171 + sig,
31.1172 + args.address(),
31.1173 + defaults.address()))
31.1174 + {
31.1175 + return false;
31.1176 + }
31.1177 +
31.1178 +#if 0
31.1179 + Local<Type> returnType(zone_);
31.1180 + if (sig.returnType() ||
31.1181 + node->hasExplicitReturn() ||
31.1182 + node->fun()->isNative())
31.1183 + {
31.1184 + returnType = bindType(node->pos(), sig.returnType());
31.1185 + } else {
31.1186 + returnType = zone_->types()->getVoid();
31.1187 + }
31.1188 + if (!returnType)
31.1189 + return false;
31.1190 +
31.1191 + if (sig.returnDimensions()) {
31.1192 + returnType = buildArrayType(returnType, sig.returnDimensions(), false);
31.1193 + if (!returnType)
31.1194 + return false;
31.1195 + }
31.1196 +
31.1197 + if (IsScalarString(returnType)) {
31.1198 + cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
31.1199 + return false;
31.1200 + }
31.1201 +
31.1202 + Local<Type> funtype(zone_);
31.1203 + if (node->fun()->isNative())
31.1204 + funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
31.1205 + else
31.1206 + funtype = zone_->types()->newFunction(returnType, args, defaults);
31.1207 + if (!funtype)
31.1208 + return false;
31.1209 +
31.1210 + // If the function already has a type, it was forward declared before, and
31.1211 + // now this is our chance to type check the second declaration.
31.1212 + if (node->fun()->type()) {
31.1213 + Local<Type> forward(zone_, node->fun()->type());
31.1214 + if (!Type::Compare(funtype, forward)) {
31.1215 + cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
31.1216 + return false;
31.1217 + }
31.1218 + node->fun()->setForwardType(forward);
31.1219 + }
31.1220 +
31.1221 + node->fun()->setType(funtype);
31.1222 +#endif
31.1223 +
31.1224 + return true;
31.1225 +}
31.1226 +
31.1227 +void
31.1228 +SemanticAnalysis::visit(FunctionStatement *node)
31.1229 +{
31.1230 + function_ = node->fun();
31.1231 + scope_ = node->scope();
31.1232 +
31.1233 + ControlScope control(&control_);
31.1234 + if (node->body()) {
31.1235 + node->body()->accept(this);
31.1236 +
31.1237 + ControlStatus status = control.status();
31.1238 + if (status.returns() == Returns_Sometimes) {
31.1239 + cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
31.1240 + } else if (status.returns() == Returns_Never) {
31.1241 + if (!function_->type()->returnType()->isVoid())
31.1242 + cc_.reportError(node->pos(), Message_MissingReturnValue);
31.1243 + }
31.1244 + }
31.1245 +
31.1246 + scope_ = NULL;
31.1247 + function_ = NULL;
31.1248 +}
31.1249 +
31.1250 +void
31.1251 +SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given)
31.1252 +{
31.1253 + cc_.reportError(pos, Message_TypeMismatch,
31.1254 + GetTypeName(actual),
31.1255 + GetTypeName(given));
31.1256 +}
31.1257 +
31.1258 +bool
31.1259 +SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> argGiven,
31.1260 + Handle<Type> argActual, bool forAssign)
31.1261 +{
31.1262 + Local<Type> actual(zone_, argActual);
31.1263 + Local<Type> given(zone_, argGiven);
31.1264 +
31.1265 + if (!given->isArray()) {
31.1266 + cc_.reportError(pos, Message_ExpectedArray);
31.1267 + return false;
31.1268 + }
31.1269 + if (given->levels() != actual->levels()) {
31.1270 + cc_.reportError(pos, Message_ArrayDimensionsMismatch);
31.1271 + return false;
31.1272 + }
31.1273 +
31.1274 + unsigned level = 1;
31.1275 + while (given->isArray()) {
31.1276 + if (actual->isFixedLength()) {
31.1277 + if (forAssign) {
31.1278 + if (!given->isFixedLength()) {
31.1279 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
31.1280 + return false;
31.1281 + }
31.1282 +
31.1283 + if (actual->isCharArray()) {
31.1284 + // String assignment can have a truncated |given|.
31.1285 + if (given->fixedLength() > actual->fixedLength()) {
31.1286 + cc_.reportError(pos, Message_ArrayAssignmentTooBig);
31.1287 + return false;
31.1288 + }
31.1289 + } else {
31.1290 + if (given->fixedLength() != actual->fixedLength()) {
31.1291 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
31.1292 + return false;
31.1293 + }
31.1294 + }
31.1295 + }
31.1296 + } else if (given->isFixedLength()) {
31.1297 + // We do not allow assignments in the form:
31.1298 + // [][] = [][Y]
31.1299 + //
31.1300 + // Otherwise, the following code could break the size guarantees
31.1301 + // of the right-hand side:
31.1302 + //
31.1303 + // new x[][5];
31.1304 + // new y[][];
31.1305 + // new z[3];
31.1306 + //
31.1307 + // y = x;
31.1308 + // y[0] = z;
31.1309 + //
31.1310 + // Now |x[0]| contains a 4-length array.
31.1311 + if (level > 1) {
31.1312 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
31.1313 + return false;
31.1314 + }
31.1315 + }
31.1316 + given = given->contained();
31.1317 + actual = actual->contained();
31.1318 + level++;
31.1319 + }
31.1320 +
31.1321 + return typeCheckAssignment(pos, given, actual, forAssign);
31.1322 +}
31.1323 +
31.1324 +bool
31.1325 +SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle<Type> argGiven,
31.1326 + Handle<Type> argActual, bool forAssign)
31.1327 +{
31.1328 + Local<Type> actual(zone_, argActual);
31.1329 + Local<Type> given(zone_, argGiven);
31.1330 +
31.1331 + if (actual->isArray())
31.1332 + return typeCheckArrayAssignment(pos, given, actual, forAssign);
31.1333 +
31.1334 + if (given->isArray()) {
31.1335 + cc_.reportError(pos, Message_CannotAssignArrayToScalar);
31.1336 + return false;
31.1337 + }
31.1338 +
31.1339 + // The given type may not have been dereferenced.
31.1340 + if (given->isReference())
31.1341 + given = given->contained();
31.1342 + if (actual->isReference())
31.1343 + actual = actual->contained();
31.1344 +
31.1345 + // We coerce unchecked to a few things.
31.1346 + if (actual->isUnchecked() || given->isUnchecked()) {
31.1347 + Type *check = actual->isUnchecked() ? given : actual;
31.1348 + if (check->isUnchecked() ||
31.1349 + check->isEnum() ||
31.1350 + check->isInt32() ||
31.1351 + check->isBool() ||
31.1352 + check->isFloat())
31.1353 + {
31.1354 + return true;
31.1355 + }
31.1356 + typeMismatch(pos, actual, given);
31.1357 + return false;
31.1358 + }
31.1359 +
31.1360 + if (given->isFunction() && actual->isFunction()) {
31.1361 + if (!Type::Compare(given, actual)) {
31.1362 + typeMismatch(pos, actual, given);
31.1363 + return false;
31.1364 + }
31.1365 + return true;
31.1366 + }
31.1367 +
31.1368 + if (actual->isEnum()) {
31.1369 + if (!given->isEnum() || actual != given) {
31.1370 + typeMismatch(pos, actual, given);
31.1371 + return false;
31.1372 + }
31.1373 + return true;
31.1374 + }
31.1375 +
31.1376 + if (actual->isStruct()) {
31.1377 + if (!given->isStruct() || actual != given) {
31.1378 + typeMismatch(pos, actual, given);
31.1379 + return false;
31.1380 + }
31.1381 + return true;
31.1382 + }
31.1383 +
31.1384 + if (given->isEnum() || given->isFunction() || given->isStruct()) {
31.1385 + typeMismatch(pos, actual, given);
31.1386 + return false;
31.1387 + }
31.1388 +
31.1389 + // This coercion is trivial.
31.1390 + if (given->isBool() && actual->isInt32())
31.1391 + return true;
31.1392 +
31.1393 + if (given->primitive() != actual->primitive()) {
31.1394 + typeMismatch(pos, actual, given);
31.1395 + return false;
31.1396 + }
31.1397 +
31.1398 + return true;
31.1399 +}
31.1400 +
31.1401 +bool
31.1402 +SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
31.1403 +{
31.1404 + return typeCheckAssignment(node->pos(), given, actual, false);
31.1405 +}
31.1406 +
31.1407 +bool
31.1408 +SemanticAnalysis::checkArgumentCount(Handle<Type> type, unsigned actual)
31.1409 +{
31.1410 + if (type->parameters()->length() == actual)
31.1411 + return true;
31.1412 +
31.1413 + if (actual > type->parameters()->length()) {
31.1414 + if (!type->isNative() || !type->isNativeVariadic())
31.1415 + return false;
31.1416 + return true;
31.1417 + }
31.1418 +
31.1419 + if (!type->defaults())
31.1420 + return false;
31.1421 +
31.1422 + // Missing arguments. See if there's a default argument for each missing
31.1423 + // actual.
31.1424 + for (unsigned i = actual; i < type->parameters()->length(); i++) {
31.1425 + if (!type->defaults()->at(i))
31.1426 + return false;
31.1427 + }
31.1428 +
31.1429 + return true;
31.1430 +}
31.1431 +
31.1432 +void
31.1433 +SemanticAnalysis::visit(CallExpression *node)
31.1434 +{
31.1435 + Local<Type> type(zone_, visitForLoad(node->callee()));
31.1436 + if (!type)
31.1437 + return;
31.1438 +
31.1439 + if (!type->isFunction()) {
31.1440 + cc_.reportError(node->pos(), Message_CalleeNotFunction);
31.1441 + return;
31.1442 + }
31.1443 +
31.1444 + if (!checkArgumentCount(type, node->arguments()->length())) {
31.1445 + cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
31.1446 + return;
31.1447 + }
31.1448 +
31.1449 + // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
31.1450 + // if (fun->isForward()) {
31.1451 + // cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
31.1452 + // return;
31.1453 + // }
31.1454 +
31.1455 + for (unsigned i = 0; i < node->arguments()->length(); i++) {
31.1456 + // Note: we don't compute references unless the callee needs a
31.1457 + // reference type.
31.1458 + Expression *expression = node->arguments()->at(i);
31.1459 + Local<Type> given(zone_, visitAndApplyType(expression));
31.1460 + if (!given)
31.1461 + return;
31.1462 +
31.1463 + // Since we skip a load, check for a call expression that returns void.
31.1464 + if (given->isVoid()) {
31.1465 + assert(expression->isCallExpression());
31.1466 + CallExpression *call = expression->toCallExpression();
31.1467 + cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
31.1468 + return;
31.1469 + }
31.1470 +
31.1471 + bool mustComputeReference;
31.1472 + if (i >= type->parameters()->length()) {
31.1473 + // Special handling for natives. Arguments past the formal must
31.1474 + // always have references computed. However, arrays are already
31.1475 + // references for natives.
31.1476 + assert(type->isNative() && type->isNativeVariadic());
31.1477 + mustComputeReference = !given->isReference() && !given->isArray();
31.1478 + } else {
31.1479 + Local<Type> actual(zone_, type->parameterAt(i));
31.1480 +
31.1481 + if (expression->isIndexExpression()) {
31.1482 + // Disabled until we can make it work.
31.1483 +#if 0
31.1484 + if (actual->isArray()) {
31.1485 + // We special case the ability to pass x[y] into x[], which
31.1486 + // creates an array slice. We only do this if we know the
31.1487 + // assignment would otherwise not type-check.
31.1488 + IndexExpression *index = expression->toIndexExpression();
31.1489 + if (index->left()->type()->levels() == actual->levels())
31.1490 + given = index->left()->type();
31.1491 + } else
31.1492 +#endif
31.1493 + if (actual->isReference()) {
31.1494 + cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
31.1495 + return;
31.1496 + }
31.1497 + }
31.1498 +
31.1499 + if (!typeCheckParameter(expression, given, actual))
31.1500 + return;
31.1501 + mustComputeReference = actual->isReference() && !given->isReference();
31.1502 + }
31.1503 +
31.1504 + // If the actual is a reference, and the given is not, we'll need to
31.1505 + // compute a reference, which may be allocated on the stack.
31.1506 + if (mustComputeReference)
31.1507 + scope_->setUsesLifoHeap();
31.1508 + }
31.1509 +
31.1510 + node->setType(type->returnType());
31.1511 +}
31.1512 +
31.1513 +void
31.1514 +SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
31.1515 +{
31.1516 + if (other.returns() < status().returns())
31.1517 + return;
31.1518 +
31.1519 + if (other.terminates())
31.1520 + terminate(other.returns());
31.1521 + else
31.1522 + returns(other.returns());
31.1523 +}
31.1524 +
31.1525 +void
31.1526 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
31.1527 +{
31.1528 + // If both sides terminate in a return, we consider this a return as well.
31.1529 + if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
31.1530 + terminate(Returns_Always);
31.1531 + return;
31.1532 + }
31.1533 +
31.1534 + ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
31.1535 + ? Returns_Never
31.1536 + : Returns_Sometimes;
31.1537 +
31.1538 + if (left.terminates() && right.terminates())
31.1539 + terminate(status);
31.1540 + else
31.1541 + returns(status);
31.1542 +}
31.1543 +
31.1544 +void
31.1545 +SemanticAnalysis::visit(IfStatement *node)
31.1546 +{
31.1547 + Local<Type> type(zone_, visitForLoad(node->condition()));
31.1548 + if (!type)
31.1549 + return;
31.1550 +
31.1551 + if (!canTest(node, type))
31.1552 + return;
31.1553 +
31.1554 + ControlStatus trueBranch = visitForControl(node->ifTrue());
31.1555 + ControlStatus falseBranch = ControlStatus(false, Returns_Never);
31.1556 +
31.1557 + if (node->ifFalse())
31.1558 + falseBranch = visitForControl(node->ifFalse());
31.1559 +
31.1560 + control_->merge(trueBranch, falseBranch);
31.1561 +}
31.1562 +
31.1563 +void
31.1564 +SemanticAnalysis::visit(IndexExpression *node)
31.1565 +{
31.1566 + Local<Type> left(zone_, visitForLoad(node->left()));
31.1567 + Local<Type> right(zone_, visitForLoad(node->right()));
31.1568 +
31.1569 + if (!left || !right)
31.1570 + return;
31.1571 +
31.1572 + if (!right->isInt32() && !right->isEnum()) {
31.1573 + cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
31.1574 + return;
31.1575 + }
31.1576 + if (!left->isArray()) {
31.1577 + cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
31.1578 + return;
31.1579 + }
31.1580 +
31.1581 + // Note: char arrays are automatically up-casted to return an int32.
31.1582 + if (left->isCharArray())
31.1583 + node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
31.1584 + else
31.1585 + node->setType(left->contained());
31.1586 +}
31.1587 +
31.1588 +void
31.1589 +SemanticAnalysis::visit(FieldExpression *node)
31.1590 +{
31.1591 + Local<Type> left(zone_, visitForLoad(node->left()));
31.1592 + if (!left)
31.1593 + return;
31.1594 +
31.1595 + if (!left->isStruct()) {
31.1596 + cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
31.1597 + GetTypeName(left));
31.1598 + return;
31.1599 + }
31.1600 +
31.1601 + Local<String> field(zone_, node->field());
31.1602 +
31.1603 + unsigned offset;
31.1604 + Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
31.1605 + if (!desc) {
31.1606 + cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
31.1607 + GetTypeName(left));
31.1608 + return;
31.1609 + }
31.1610 +
31.1611 + node->setFieldIndex(offset);
31.1612 + node->setType(desc->type());
31.1613 +}
31.1614 +
31.1615 +void
31.1616 +SemanticAnalysis::visit(EnumStatement *node)
31.1617 +{
31.1618 + Local<String> name(zone_, node->name());
31.1619 + Local<Type> type(zone_);
31.1620 + if (name)
31.1621 + type = zone_->types()->newEnum(name);
31.1622 + else
31.1623 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
31.1624 +
31.1625 + if (!type)
31.1626 + return;
31.1627 +
31.1628 + if (node->decl())
31.1629 + node->decl()->setType(type);
31.1630 +
31.1631 + int value = 0;
31.1632 + for (size_t i = 0; i < node->entries()->length(); i++) {
31.1633 + EnumStatement::Entry &entry = node->entries()->at(i);
31.1634 +
31.1635 + BoxedPrimitive box = BoxedPrimitive::Int(value);
31.1636 + if (entry.expr) {
31.1637 + entry.expr->accept(this);
31.1638 + if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
31.1639 + cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
31.1640 + return;
31.1641 + }
31.1642 +
31.1643 + assert(box.type() == PrimitiveType_Int32);
31.1644 + value = box.toInt();
31.1645 + }
31.1646 +
31.1647 +#if 0
31.1648 + entry.name->set(type, box);
31.1649 +#endif
31.1650 + value++;
31.1651 + }
31.1652 +}
31.1653 +
31.1654 +static int
31.1655 +SortCaseIntValues(const void *p1, const void *p2)
31.1656 +{
31.1657 + CaseValue *v1 = (CaseValue *)p1;
31.1658 + CaseValue *v2 = (CaseValue *)p2;
31.1659 +
31.1660 + return v1->box.toInt() - v2->box.toInt();
31.1661 +}
31.1662 +
31.1663 +void
31.1664 +SemanticAnalysis::visit(SwitchStatement *node)
31.1665 +{
31.1666 + Local<Type> caseType(zone_, visitForLoad(node->expression()));
31.1667 + if (!caseType)
31.1668 + return;
31.1669 +
31.1670 + if (!caseType->isEnum() && !caseType->isInt32()) {
31.1671 + cc_.reportError(node->pos(), Message_CaseMustBeInteger);
31.1672 + return;
31.1673 + }
31.1674 +
31.1675 + PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
31.1676 + ControlStatus status = ControlStatus(false, Returns_Never);
31.1677 +
31.1678 + Local<Type> check(zone_);
31.1679 + for (size_t i = 0; i < node->cases()->length(); i++) {
31.1680 + Case *c = node->cases()->at(i);
31.1681 +
31.1682 + check = visitForLoad(c->expression());
31.1683 + if (!check)
31.1684 + return;
31.1685 +
31.1686 + if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
31.1687 + return;
31.1688 +
31.1689 + CaseValue v(i);
31.1690 + if (!EvaluateForConstant(c->expression(), &v.box)) {
31.1691 + cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
31.1692 + return;
31.1693 + }
31.1694 + if (!values->append(v))
31.1695 + return;
31.1696 +
31.1697 + if (c->others()) {
31.1698 + for (size_t j = 0; j < c->others()->length(); j++) {
31.1699 + Expression *expr = c->others()->at(j);
31.1700 + check = visitForLoad(expr);
31.1701 + if (!check)
31.1702 + return;
31.1703 +
31.1704 + if (!typeCheckAssignment(expr->pos(), check, caseType, false))
31.1705 + return;
31.1706 +
31.1707 + CaseValue v(i);
31.1708 + if (!EvaluateForConstant(expr, &v.box)) {
31.1709 + cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
31.1710 + return;
31.1711 + }
31.1712 + if (!values->append(v))
31.1713 + return;
31.1714 + }
31.1715 + }
31.1716 +
31.1717 + ControlStatus latest = visitForControl(c->statement());
31.1718 +
31.1719 + if (i != 0)
31.1720 + control_->merge(status, latest);
31.1721 +
31.1722 + status = latest;
31.1723 + }
31.1724 +
31.1725 + if (node->defaultCase()) {
31.1726 + ControlStatus latest = visitForControl(node->defaultCase());
31.1727 +
31.1728 + if (node->cases()->length()) {
31.1729 + // If we had any other cases, we must merge.
31.1730 + control_->merge(status, latest);
31.1731 + } else {
31.1732 + // Otherwise, control-flow always flows through here.
31.1733 + control_->inherit(latest);
31.1734 + }
31.1735 + } else if (node->cases()->length()) {
31.1736 + control_->merge(status, ControlStatus(false, Returns_Never));
31.1737 + }
31.1738 +
31.1739 + if (values->length() > 1) {
31.1740 + qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
31.1741 +
31.1742 + for (size_t i = 1; i < values->length(); i++) {
31.1743 + CaseValue &prev = values->at(i - 1);
31.1744 + CaseValue &cur = values->at(i);
31.1745 + if (prev.box.toInt() == cur.box.toInt()) {
31.1746 + cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
31.1747 + return;
31.1748 + }
31.1749 + }
31.1750 + }
31.1751 +
31.1752 + node->setCaseValueList(values);
31.1753 +}
31.1754 +
31.1755 +void
31.1756 +SemanticAnalysis::visit(StructureStatement *node)
31.1757 +{
31.1758 +#if 0
31.1759 + // If this node already has a type, it was pre-analyzed, so skip it.
31.1760 + if (node->decl()->type())
31.1761 + return;
31.1762 +
31.1763 + FieldList *fields = node->fields();
31.1764 + Local<FixedArray> desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old));
31.1765 + if (!desctable)
31.1766 + return;
31.1767 +
31.1768 + Vector<unsigned> composedList;
31.1769 + StructureBufferBuilder builder;
31.1770 +
31.1771 + Local<Type> type(zone_);
31.1772 + Local<String> name(zone_);
31.1773 + Local<Descriptor> desc(zone_);
31.1774 + for (size_t i = 0; i < fields->length(); i++) {
31.1775 + StructureStatement::Field *field = fields->at(i);
31.1776 +
31.1777 + type = bindType(field->pos(), field->type());
31.1778 + if (!type)
31.1779 + return;
31.1780 +
31.1781 + if (field->dimensions()) {
31.1782 + type = buildArrayType(type, field->dimensions(), false);
31.1783 + if (!type)
31.1784 + return;
31.1785 +
31.1786 + if (!ArrayMap::Attach(zone_, type))
31.1787 + return;
31.1788 + }
31.1789 +
31.1790 + if (IsScalarString(type)) {
31.1791 + cc_.reportError(field->pos(), Message_CannotDeclareStringCell);
31.1792 + return;
31.1793 + }
31.1794 +
31.1795 + unsigned offset;
31.1796 + if (!builder.add(type, &offset))
31.1797 + return;
31.1798 +
31.1799 + name = field->name();
31.1800 + desc = Descriptor::New(zone_, name, type, offset);
31.1801 + if (!desc)
31.1802 + return;
31.1803 +
31.1804 + desctable->set(zone_, i, desc);
31.1805 +
31.1806 + if (type->isStruct() || type->isArray()) {
31.1807 + if (!composedList.append(i))
31.1808 + return;
31.1809 + }
31.1810 + }
31.1811 +
31.1812 + Local<FixedArray> composed(zone_);
31.1813 + if (composedList.length()) {
31.1814 + composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old);
31.1815 + if (!composed)
31.1816 + return;
31.1817 +
31.1818 + for (unsigned i = 0; i < composedList.length(); i++)
31.1819 + composed->set(zone_, i, desctable->at(i));
31.1820 + }
31.1821 +
31.1822 + Local<StructMap> map(zone_, StructMap::New(zone_, builder, composed));
31.1823 + if (!map)
31.1824 + return;
31.1825 +
31.1826 + name = node->decl()->name();
31.1827 + type = zone_->types()->newStruct(name, desctable, map);
31.1828 + if (!type)
31.1829 + return;
31.1830 +
31.1831 + map->setType(type);
31.1832 + node->decl()->setType(type);
31.1833 +#endif
31.1834 +}
31.1835 +
31.1836 +void
31.1837 +SemanticAnalysis::visit(StringLiteral *node)
31.1838 +{
31.1839 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
31.1840 + if (!type)
31.1841 + return;
31.1842 +
31.1843 + type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
31.1844 + if (!type)
31.1845 + return;
31.1846 +
31.1847 + node->setType(type);
31.1848 +}
31.1849 +
31.1850 +void
31.1851 +SemanticAnalysis::visit(FloatLiteral *node)
31.1852 +{
31.1853 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
31.1854 + if (!type)
31.1855 + return;
31.1856 +
31.1857 + node->setType(type);
31.1858 +}
31.1859 +
31.1860 +void
31.1861 +SemanticAnalysis::visit(BreakStatement *node)
31.1862 +{
31.1863 + if (!loop_) {
31.1864 + cc_.reportError(node->pos(), Message_BreakOutsideLoop);
31.1865 + return;
31.1866 + }
31.1867 +
31.1868 + // Note: ignore breaks that occur in unreachable control-flow.
31.1869 + if (!control_->status().terminates())
31.1870 + loop_->addBreak();
31.1871 +
31.1872 + control_->terminate(Returns_Never);
31.1873 +}
31.1874 +
31.1875 +void
31.1876 +SemanticAnalysis::visit(ContinueStatement *node)
31.1877 +{
31.1878 + if (!loop_) {
31.1879 + cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
31.1880 + return;
31.1881 + }
31.1882 +
31.1883 + // Note: ignore continues that occur in unreachable control-flow.
31.1884 + if (!control_->status().terminates())
31.1885 + loop_->addContinue();
31.1886 +
31.1887 + control_->terminate(Returns_Never);
31.1888 +}
31.1889 +
31.1890 +void
31.1891 +SemanticAnalysis::visit(ArrayLiteral *node)
31.1892 +{
31.1893 + // We should never visit this.
31.1894 + cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
31.1895 +}
31.1896 +
31.1897 +void
31.1898 +SemanticAnalysis::visit(ImportStatement *node)
31.1899 +{
31.1900 +}
31.1901 +
31.1902 +#endif
31.1903 \ No newline at end of file
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/src/OldSema.h Sat Nov 17 18:41:01 2012 -0800
32.3 @@ -0,0 +1,237 @@
32.4 +/* vim: set ts=4 sw=4 tw=99 et:
32.5 + *
32.6 + * Copyright (C) 2012 David Anderson
32.7 + *
32.8 + * This file is part of JITCraft.
32.9 + *
32.10 + * JITCraft is free software: you can redistribute it and/or modify it under
32.11 + * the terms of the GNU General Public License as published by the Free
32.12 + * Software Foundation, either version 3 of the License, or (at your option)
32.13 + * any later version.
32.14 + *
32.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
32.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
32.18 + *
32.19 + * You should have received a copy of the GNU General Public License along with
32.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
32.21 + */
32.22 +#ifndef _include_semantic_analysis_h_
32.23 +#define _include_semantic_analysis_h_
32.24 +
32.25 +#include <assert.h>
32.26 +#include "AST.h"
32.27 +#include "../Types.h"
32.28 +
32.29 +namespace ke {
32.30 +
32.31 +class Box;
32.32 +
32.33 +class SemanticAnalysis : public AstVisitor
32.34 +{
32.35 + Zone *zone_;
32.36 + CompileContext &cc_;
32.37 + ParseTree *tree_;
32.38 + Scope *scope_;
32.39 + NamedFunction *function_;
32.40 +
32.41 + enum ReturnStatus
32.42 + {
32.43 + Returns_Never,
32.44 + Returns_Sometimes,
32.45 + Returns_Always
32.46 + };
32.47 +
32.48 + // Tuple that describes whether a path terminates control flow, and
32.49 + // if it is guaranteed to end in a return.
32.50 + class ControlStatus
32.51 + {
32.52 + bool terminates_;
32.53 + ReturnStatus returns_;
32.54 +
32.55 + public:
32.56 + ControlStatus(bool terminates, ReturnStatus returns)
32.57 + : terminates_(terminates),
32.58 + returns_(returns)
32.59 + {
32.60 + }
32.61 +
32.62 + bool terminates() const {
32.63 + return terminates_;
32.64 + }
32.65 + ReturnStatus returns() const {
32.66 + return returns_;
32.67 + }
32.68 + };
32.69 +
32.70 + // Used to keep track of terminating control flow and return statements
32.71 + // inside control structures.
32.72 + class ControlScope
32.73 + {
32.74 + ReturnStatus returns_;
32.75 + ControlScope **prevp_;
32.76 + ControlScope *prev_;
32.77 + bool terminates_;
32.78 +
32.79 + public:
32.80 + ControlScope(ControlScope **prev)
32.81 + : returns_(Returns_Never),
32.82 + prevp_(prev),
32.83 + prev_(*prev),
32.84 + terminates_(false)
32.85 + {
32.86 + *prevp_ = this;
32.87 + }
32.88 +
32.89 + ControlStatus status() const {
32.90 + return ControlStatus(terminates_, returns_);
32.91 + }
32.92 +
32.93 + // We allow multiple terminators, but only the first one takes effect.
32.94 + // For example, |break; continue;| is legal but the continue is
32.95 + // unreachable.
32.96 + void returns(ReturnStatus status) {
32.97 + if (terminates_)
32.98 + return;
32.99 + if (status > returns_)
32.100 + returns_ = status;
32.101 + }
32.102 + void terminate(ReturnStatus status) {
32.103 + if (terminates_)
32.104 + return;
32.105 + terminates_ = true;
32.106 + returns_ = status;
32.107 + }
32.108 + void merge(const ControlStatus &left, const ControlStatus &right);
32.109 + void inherit(const ControlStatus &other);
32.110 +
32.111 + ~ControlScope()
32.112 + {
32.113 + *prevp_ = prev_;
32.114 + }
32.115 + };
32.116 +
32.117 + class LoopScope
32.118 + {
32.119 + LoopScope **prevp_;
32.120 + LoopScope *prev_;
32.121 + unsigned breaks_;
32.122 + unsigned continues_;
32.123 +
32.124 + public:
32.125 + LoopScope(LoopScope **prev)
32.126 + : prevp_(prev),
32.127 + prev_(*prev),
32.128 + breaks_(0),
32.129 + continues_(0)
32.130 + {
32.131 + *prevp_ = this;
32.132 + }
32.133 +
32.134 + ~LoopScope()
32.135 + {
32.136 + *prevp_ = prev_;
32.137 + }
32.138 +
32.139 + void addBreak() {
32.140 + breaks_++;
32.141 + }
32.142 + void addContinue() {
32.143 + continues_++;
32.144 + }
32.145 + unsigned breaks() const {
32.146 + return breaks_;
32.147 + }
32.148 + unsigned continues() const {
32.149 + return continues_;
32.150 + }
32.151 + };
32.152 +
32.153 + ControlScope *control_;
32.154 + LoopScope *loop_;
32.155 +
32.156 + private:
32.157 + bool canTest(AstNode *node, Handle<Type> type);
32.158 + void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
32.159 + void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
32.160 + void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
32.161 + Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
32.162 +
32.163 + Type *bindType(const SourcePosition &pos, BoundName *name);
32.164 +
32.165 + // These check if one type is compatible with another type, for various
32.166 + // purposes, like:
32.167 + // return (expr) matches function return type
32.168 + // call(a, b) matches expected arg type
32.169 + // a = b matches declared type
32.170 + //
32.171 + bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
32.172 + bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
32.173 + bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
32.174 +
32.175 + Type *visitForLoad(Expression *expression);
32.176 + bool preanalyze(FunctionStatement *node);
32.177 + Type *visitForLValue(Expression *expression);
32.178 + Type *visitAndApplyType(Expression *expression);
32.179 + ControlStatus visitForControl(Statement *statement);
32.180 +
32.181 + bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
32.182 + bool inferFixedArrayLiteral(ArrayLiteral *literal,
32.183 + Handle<Type> type,
32.184 + int dims[MAX_ARRAY_DEPTH],
32.185 + unsigned dimcount,
32.186 + unsigned level);
32.187 +
32.188 + // Builds an array type used for parameters, returns, or field entries.
32.189 + Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
32.190 +
32.191 + Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
32.192 + bool checkArgumentCount(Handle<Type> type, unsigned actual);
32.193 + bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
32.194 + FixedArray **args, FixedArray **defaults);
32.195 +
32.196 + void markCallResultUsed(CallExpression *call);
32.197 +
32.198 + bool determineLiveFunctions();
32.199 +
32.200 + public:
32.201 + SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
32.202 + bool analyze();
32.203 +
32.204 + public:
32.205 + void visit(NameProxy *name);
32.206 + void visit(Assignment *node);
32.207 + void visit(BinaryExpression *node);
32.208 + void visit(ReturnStatement *node);
32.209 + void visit(ForStatement *node);
32.210 + void visit(BlockStatement *node);
32.211 + void visit(VariableDeclaration *node);
32.212 + void visit(IntegerLiteral *node);
32.213 + void visit(ExpressionStatement *node);
32.214 + void visit(FunctionStatement *node);
32.215 + void visit(CallExpression *node);
32.216 + void visit(IfStatement *node);
32.217 + void visit(IndexExpression *node);
32.218 + void visit(EnumStatement *node);
32.219 + void visit(FloatLiteral *node);
32.220 + void visit(WhileStatement *node);
32.221 + void visit(BreakStatement *node);
32.222 + void visit(ContinueStatement *node);
32.223 + void visit(StringLiteral *node);
32.224 + void visit(IncDecExpression *node);
32.225 + void visit(UnaryExpression *node);
32.226 + void visit(TernaryExpression *node);
32.227 + void visit(BooleanLiteral *node);
32.228 + void visit(StructureStatement *node);
32.229 + void visit(FieldExpression *node);
32.230 + void visit(SwitchStatement *node);
32.231 + void visit(FunctionTypeStatement *node);
32.232 + void visit(ArrayLiteral *node);
32.233 + void visit(ImportStatement *node);
32.234 +};
32.235 +
32.236 +const char *GetTypeName(Type *type);
32.237 +
32.238 +} // namespace ke
32.239 +
32.240 +#endif // _include_semantic_analysis_h_
33.1 --- a/src/Opcodes.cpp Mon Sep 17 00:10:01 2012 -0700
33.2 +++ b/src/Opcodes.cpp Sat Nov 17 18:41:01 2012 -0800
33.3 @@ -31,7 +31,7 @@
33.4
33.5 OpInfo ke::OpcodeInfo[] =
33.6 {
33.7 -#define OPDEF(name, number, text, length, uses, defs) \
33.8 +#define OPDEF(name, text, length, uses, defs) \
33.9 {text, length, uses, defs},
33.10 #include "Opcodes.tbl"
33.11 #undef OPDEF
33.12 @@ -39,9 +39,8 @@
33.13
33.14 Code *
33.15 Code::New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
33.16 - Handle<FixedArray> objects, unsigned maxStackDepth, Handle<Module> module,
33.17 - Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap,
33.18 - unsigned lineNumber)
33.19 + Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
33.20 + Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap)
33.21 {
33.22 Local<Code> code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old)));
33.23 if (!code)
33.24 @@ -51,10 +50,11 @@
33.25 code->locals_ = locals;
33.26 code->objects_ = objects;
33.27 code->maxStackDepth_ = maxStackDepth;
33.28 - code->module_ = module;
33.29 + code->module_ = NULL;
33.30 code->safepoints_ = safepoints;
33.31 code->sourcemap_ = sourcemap;
33.32 - code->lineNumber_ = lineNumber;
33.33 + code->lineNumber_ = 0;
33.34 + code->strings_ = strings;
33.35 return code;
33.36 }
33.37
33.38 @@ -85,7 +85,9 @@
33.39 op == OP_VARREF_LIFO ||
33.40 op == OP_ARGREF_LIFO ||
33.41 op == OP_SLOTREF_LIFO ||
33.42 - op == OP_COPYARRAY);
33.43 + op == OP_COPYARRAY ||
33.44 + op == OP_CALLNATIVE ||
33.45 + op == OP_PUBLIC);
33.46 #endif
33.47
33.48 if (!safepoints_)
33.49 @@ -133,12 +135,6 @@
33.50 }
33.51
33.52 // All jumps must be the same length.
33.53 -STATIC_ASSERT(OP_JL_LENGTH == OP_JUMP_LENGTH);
33.54 -STATIC_ASSERT(OP_JLE_LENGTH == OP_JUMP_LENGTH);
33.55 -STATIC_ASSERT(OP_JG_LENGTH == OP_JUMP_LENGTH);
33.56 -STATIC_ASSERT(OP_JGE_LENGTH == OP_JUMP_LENGTH);
33.57 -STATIC_ASSERT(OP_JEQ_LENGTH == OP_JUMP_LENGTH);
33.58 -STATIC_ASSERT(OP_JNE_LENGTH == OP_JUMP_LENGTH);
33.59 STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH);
33.60 STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH);
33.61
33.62 @@ -187,7 +183,6 @@
33.63 case OP_PICK2:
33.64 case OP_PICK3:
33.65 case OP_CALL:
33.66 - case OP_MODULE:
33.67 case OP_LT:
33.68 case OP_LE:
33.69 case OP_GE:
33.70 @@ -211,6 +206,7 @@
33.71 case OP_TRUE:
33.72 case OP_FALSE:
33.73 case OP_SIZEOF:
33.74 + case OP_PUBLIC:
33.75 break;
33.76
33.77 case OP_STOP:
33.78 @@ -225,22 +221,8 @@
33.79 fprintf(fp, "%f", READ_FLOAT(pc));
33.80 break;
33.81
33.82 - case OP_JL:
33.83 - case OP_JLE:
33.84 - case OP_JG:
33.85 - case OP_JGE:
33.86 - case OP_JEQ:
33.87 - case OP_JNE:
33.88 case OP_JT:
33.89 case OP_JF:
33.90 - case OP_JL_F:
33.91 - case OP_JLE_F:
33.92 - case OP_JG_F:
33.93 - case OP_JGE_F:
33.94 - case OP_JEQ_F:
33.95 - case OP_JNE_F:
33.96 - case OP_JT_F:
33.97 - case OP_JF_F:
33.98 case OP_JUMP:
33.99 fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc));
33.100 break;
33.101 @@ -283,22 +265,17 @@
33.102 case OP_VARREF_LIFO:
33.103 case OP_ARGREF_LIFO:
33.104 case OP_OBJECT:
33.105 - case OP_GETMODULE_FN:
33.106 - case OP_GETGLOBAL_I:
33.107 - case OP_GETGLOBAL_F:
33.108 - case OP_GETGLOBAL_O:
33.109 - case OP_SETGLOBAL_I:
33.110 - case OP_SETGLOBAL_F:
33.111 - case OP_SETGLOBAL_O:
33.112 case OP_GETFIELD:
33.113 case OP_SETFIELD:
33.114 - case OP_FIELDREF_LIFO:
33.115 fprintf(fp, "%u", READ_UINT32(pc));
33.116 break;
33.117
33.118 case OP_CALLNATIVE:
33.119 - fprintf(fp, "%u %u", READ_UINT32(pc), READ_UINT32(pc + 4));
33.120 + {
33.121 + unsigned argc = READ_UINT32(pc);
33.122 + fprintf(fp, " ; %u args", argc);
33.123 break;
33.124 + }
33.125
33.126 case OP_TABLESWITCH:
33.127 {
33.128 @@ -308,6 +285,14 @@
33.129 break;
33.130 }
33.131
33.132 + case OP_GETGLOBAL:
33.133 + case OP_SETGLOBAL:
33.134 + {
33.135 + unsigned index = READ_UINT32(pc);
33.136 + fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars());
33.137 + break;
33.138 + }
33.139 +
33.140 default:
33.141 // Unknown opcode!
33.142 assert(false);
34.1 --- a/src/Opcodes.h Mon Sep 17 00:10:01 2012 -0700
34.2 +++ b/src/Opcodes.h Sat Nov 17 18:41:01 2012 -0800
34.3 @@ -23,17 +23,35 @@
34.4 #include <stdio.h>
34.5
34.6 namespace ke {
34.7 +
34.8 +struct SourcePosition
34.9 +{
34.10 + int line;
34.11 + int col;
34.12 +
34.13 + SourcePosition()
34.14 + : line(-1),
34.15 + col(-1)
34.16 + {
34.17 + }
34.18 +
34.19 + SourcePosition(unsigned line, unsigned col)
34.20 + : line(line),
34.21 + col(col)
34.22 + {
34.23 + }
34.24 +};
34.25
34.26 enum Opcode
34.27 {
34.28 -#define OPDEF(name, number, text, length, uses, defs) \
34.29 - name = number,
34.30 +#define OPDEF(name, text, length, uses, defs) \
34.31 + name,
34.32 #include "Opcodes.tbl"
34.33 #undef OPDEF
34.34 OPCODES_TOTAL
34.35 };
34.36
34.37 -#define OPDEF(name, number, text, length, uses, defs) \
34.38 +#define OPDEF(name, text, length, uses, defs) \
34.39 static const unsigned name##_LENGTH = length;
34.40 #include "Opcodes.tbl"
34.41 #undef OPDEF
34.42 @@ -50,26 +68,6 @@
34.43
34.44 extern OpInfo OpcodeInfo[];
34.45
34.46 -static inline Opcode
34.47 -Invert(Opcode op)
34.48 -{
34.49 - switch (op) {
34.50 - case OP_JEQ:
34.51 - return OP_JNE;
34.52 - case OP_JNE:
34.53 - return OP_JEQ;
34.54 - case OP_JG:
34.55 - return OP_JLE;
34.56 - case OP_JGE:
34.57 - return OP_JL;
34.58 - case OP_JL:
34.59 - return OP_JGE;
34.60 - default:
34.61 - assert(op == OP_JLE);
34.62 - return OP_JG;
34.63 - }
34.64 -}
34.65 -
34.66 static const unsigned MAX_TABLESWITCH_ENTRIES = 256;
34.67
34.68 static inline unsigned
35.1 --- a/src/Opcodes.tbl Mon Sep 17 00:10:01 2012 -0700
35.2 +++ b/src/Opcodes.tbl Sat Nov 17 18:41:01 2012 -0800
35.3 @@ -17,7 +17,7 @@
35.4 * JITCraft. If not, see http://www.gnu.org/licenses/.
35.5 */
35.6 // Opcode macros:
35.7 -// NAME NUMBER TEXT LENGTH USES DEFS
35.8 +// NAME TEXT LENGTH USES DEFS
35.9 //
35.10 // Type suffixes:
35.11 // I = 32-bit integer
35.12 @@ -25,83 +25,62 @@
35.13 // O = object reference
35.14
35.15 // No operation.
35.16 -OPDEF(OP_NOP, 0, "nop", 1, 0, 0)
35.17 +OPDEF(OP_NOP, "nop", 1, 0, 0)
35.18
35.19 // Pushes a signed integer immediate onto the stack.
35.20 -OPDEF(OP_INT, 1, "int", 5, 0, 1)
35.21 +OPDEF(OP_INT, "int", 5, 0, 1)
35.22
35.23 // Returns from the current routine, propagating the value at the top of the
35.24 // stack to the caller.
35.25 -OPDEF(OP_RETURN, 2, "return", 1, 1, 0)
35.26 -
35.27 -// Stack transitions for these comparison ops:
35.28 -// rhs = pop()
35.29 -// lhs = pop()
35.30 -// if (lhs COMPARE rhs)
35.31 -// goto target (immediate, relative to the beginning of the jump instruction)
35.32 -OPDEF(OP_JL, 3, "jl", 5, 2, 0)
35.33 -OPDEF(OP_JLE, 4, "jle", 5, 2, 0)
35.34 -OPDEF(OP_JG, 5, "jg", 5, 2, 0)
35.35 -OPDEF(OP_JGE, 6, "jge", 5, 2, 0)
35.36 -OPDEF(OP_JEQ, 7, "jeq", 5, 2, 0)
35.37 -OPDEF(OP_JNE, 8, "jne", 5, 2, 0)
35.38 +OPDEF(OP_RETURN, "return", 1, 1, 0)
35.39
35.40 // value = pop()
35.41 // if (value == [true, false])
35.42 // goto target
35.43 -OPDEF(OP_JT, 9, "jt", 5, 1, 0)
35.44 -OPDEF(OP_JF, 10, "jf", 5, 1, 0)
35.45 -
35.46 -OPDEF(OP_JL_F, 11, "jl.f", 5, 2, 0)
35.47 -OPDEF(OP_JLE_F, 12, "jle.f", 5, 2, 0)
35.48 -OPDEF(OP_JG_F, 13, "jg.f", 5, 2, 0)
35.49 -OPDEF(OP_JGE_F, 14, "jge.f", 5, 2, 0)
35.50 -OPDEF(OP_JEQ_F, 15, "jeq.f", 5, 2, 0)
35.51 -OPDEF(OP_JNE_F, 16, "jne.f", 5, 2, 0)
35.52 -OPDEF(OP_JT_F, 17, "jt.f", 5, 1, 0)
35.53 -OPDEF(OP_JF_F, 18, "jf.f", 5, 1, 0)
35.54 +OPDEF(OP_JT, "jt", 5, 1, 0)
35.55 +OPDEF(OP_JF, "jf", 5, 1, 0)
35.56
35.57 // Unconditional jump.
35.58 -OPDEF(OP_JUMP, 19, "jump", 5, 0, 0)
35.59 +OPDEF(OP_JUMP, "jump", 5, 0, 0)
35.60
35.61 // Gets or sets the value of a local variable onto the stack. The local
35.62 // variable is given by an immediate index.
35.63 -OPDEF(OP_GETLOCAL, 20, "getlocal", 5, 0, 1)
35.64 -OPDEF(OP_SETLOCAL, 21, "setlocal", 5, 1, 1)
35.65 +OPDEF(OP_GETLOCAL, "getlocal", 5, 0, 1)
35.66 +OPDEF(OP_SETLOCAL, "setlocal", 5, 1, 1)
35.67
35.68 // Stack transitions for these binary operators:
35.69 // rhs = pop()
35.70 // lhs = pop()
35.71 // push(lhs OP rhs)
35.72 -OPDEF(OP_ADD, 22, "add", 1, 2, 1)
35.73 -OPDEF(OP_SUB, 23, "sub", 1, 2, 1)
35.74 -OPDEF(OP_MUL, 24, "mul", 1, 2, 1)
35.75 -OPDEF(OP_DIV, 25, "div", 1, 2, 1)
35.76 -OPDEF(OP_MOD, 26, "mod", 1, 2, 1)
35.77 +OPDEF(OP_ADD, "add", 1, 2, 1)
35.78 +OPDEF(OP_SUB, "sub", 1, 2, 1)
35.79 +OPDEF(OP_MUL, "mul", 1, 2, 1)
35.80 +OPDEF(OP_DIV, "div", 1, 2, 1)
35.81 +OPDEF(OP_MOD, "mod", 1, 2, 1)
35.82
35.83 -OPDEF(OP_LT, 27, "lt", 1, 2, 1)
35.84 -OPDEF(OP_LE, 28, "le", 1, 2, 1)
35.85 -OPDEF(OP_GE, 29, "ge", 1, 2, 1)
35.86 -OPDEF(OP_GT, 30, "gt", 1, 2, 1)
35.87 -OPDEF(OP_EQ, 31, "eq", 1, 2, 1)
35.88 -OPDEF(OP_NE, 32, "ne", 1, 2, 1)
35.89 +OPDEF(OP_LT, "lt", 1, 2, 1)
35.90 +OPDEF(OP_LE, "le", 1, 2, 1)
35.91 +OPDEF(OP_GE, "ge", 1, 2, 1)
35.92 +OPDEF(OP_GT, "gt", 1, 2, 1)
35.93 +OPDEF(OP_EQ, "eq", 1, 2, 1)
35.94 +OPDEF(OP_NE, "ne", 1, 2, 1)
35.95
35.96 -OPDEF(OP_NOT, 33, "not", 1, 1, 1)
35.97 -OPDEF(OP_NEG, 34, "neg", 1, 1, 1)
35.98 +OPDEF(OP_NOT, "not", 1, 1, 1)
35.99 +OPDEF(OP_NEG, "neg", 1, 1, 1)
35.100
35.101 -OPDEF(OP_POP, 35, "pop", 1, 1, 0)
35.102 +OPDEF(OP_POP, "pop", 1, 1, 0)
35.103
35.104 // Unconditional terminator placed at the end of code. If a function returns
35.105 // void, this acts as a RETURNVOID. Otherwise, it must be unreachable.
35.106 -OPDEF(OP_STOP, 36, "stop", 1, 0, 0)
35.107 +OPDEF(OP_STOP, "stop", 1, 0, 0)
35.108
35.109 // Call a function with N arguments. The target function must be the last item
35.110 // on the stack.
35.111 -OPDEF(OP_CALL, 37, "call", 1, -1, 1)
35.112 +OPDEF(OP_CALL, "call", 1, -1, 1)
35.113
35.114 // Similar to GET/LOCAL, except for arguments.
35.115 -OPDEF(OP_GETARG, 38, "getarg", 5, 0, 1)
35.116 -OPDEF(OP_SETARG, 39, "setarg", 5, 1, 1)
35.117 +OPDEF(OP_GETARG, "getarg", 5, 0, 1)
35.118 +OPDEF(OP_SETARG, "setarg", 5, 1, 1)
35.119
35.120 // Allocates either:
35.121 // A fixed array,
35.122 @@ -113,83 +92,83 @@
35.123 //
35.124 // Format:
35.125 // [u8 op] [u8 tenure] [u32 index]
35.126 -OPDEF(OP_NEWFIXED, 40, "newfixed", 6, 0, 1)
35.127 -OPDEF(OP_NEWEMPTY, 41, "newempty", 6, 0, 1)
35.128 -OPDEF(OP_NEWSIZED, 42, "newsized", 6, -1, 1)
35.129 +OPDEF(OP_NEWFIXED, "newfixed", 6, 0, 1)
35.130 +OPDEF(OP_NEWEMPTY, "newempty", 6, 0, 1)
35.131 +OPDEF(OP_NEWSIZED, "newsized", 6, -1, 1)
35.132
35.133 // Performs an array-to-array assignment.
35.134 // Left = pop()
35.135 // Right = pop()
35.136 // copy(Left, Right)
35.137 // push(Left)
35.138 -OPDEF(OP_COPYARRAY, 43, "arraycopy", 1, 2, 1)
35.139 +OPDEF(OP_COPYARRAY, "arraycopy", 1, 2, 1)
35.140
35.141 // Reads or writes an integer element to an unsafe array.
35.142 // index = pop()
35.143 // ref = pop()
35.144 // ref[index]
35.145 //
35.146 -OPDEF(OP_GETELEM, 44, "getelem", 1, 2, 1)
35.147 -OPDEF(OP_SETELEM, 45, "setelem", 1, 3, 1)
35.148 +OPDEF(OP_GETELEM, "getelem", 1, 2, 1)
35.149 +OPDEF(OP_SETELEM, "setelem", 1, 3, 1)
35.150
35.151 // Pushes a 32-bit IEEE-754 floating point immediate onto the stack.
35.152 -OPDEF(OP_FLOAT, 46, "float", 5, 0, 1)
35.153 +OPDEF(OP_FLOAT, "float", 5, 0, 1)
35.154
35.155 // Converts an integer to a 32-bit IEEE-754 floating point immediate.
35.156 -OPDEF(OP_CVT_I2F, 47, "cvt.i2f", 1, 1, 1)
35.157 +OPDEF(OP_CVT_I2F, "cvt.i2f", 1, 1, 1)
35.158
35.159 // Stack transitions for these binary operators:
35.160 // rhs = pop()
35.161 // lhs = pop()
35.162 // push(lhs OP rhs)
35.163 -OPDEF(OP_ADD_F, 48, "add.f", 1, 2, 1)
35.164 -OPDEF(OP_SUB_F, 49, "sub.f", 1, 2, 1)
35.165 -OPDEF(OP_MUL_F, 50, "mul.f", 1, 2, 1)
35.166 -OPDEF(OP_DIV_F, 51, "div.f", 1, 2, 1)
35.167 +OPDEF(OP_ADD_F, "add.f", 1, 2, 1)
35.168 +OPDEF(OP_SUB_F, "sub.f", 1, 2, 1)
35.169 +OPDEF(OP_MUL_F, "mul.f", 1, 2, 1)
35.170 +OPDEF(OP_DIV_F, "div.f", 1, 2, 1)
35.171
35.172 -OPDEF(OP_LT_F, 52, "lt.f", 1, 2, 1)
35.173 -OPDEF(OP_LE_F, 53, "le.f", 1, 2, 1)
35.174 -OPDEF(OP_GE_F, 54, "ge.f", 1, 2, 1)
35.175 -OPDEF(OP_GT_F, 55, "gt.f", 1, 2, 1)
35.176 -OPDEF(OP_EQ_F, 56, "eq.f", 1, 2, 1)
35.177 -OPDEF(OP_NE_F, 57, "ne.f", 1, 2, 1)
35.178 +OPDEF(OP_LT_F, "lt.f", 1, 2, 1)
35.179 +OPDEF(OP_LE_F, "le.f", 1, 2, 1)
35.180 +OPDEF(OP_GE_F, "ge.f", 1, 2, 1)
35.181 +OPDEF(OP_GT_F, "gt.f", 1, 2, 1)
35.182 +OPDEF(OP_EQ_F, "eq.f", 1, 2, 1)
35.183 +OPDEF(OP_NE_F, "ne.f", 1, 2, 1)
35.184
35.185 -OPDEF(OP_NOT_F, 58, "not.f", 1, 1, 1)
35.186 -OPDEF(OP_NEG_F, 59, "neg.f", 1, 1, 1)
35.187 +OPDEF(OP_NOT_F, "not.f", 1, 1, 1)
35.188 +OPDEF(OP_NEG_F, "neg.f", 1, 1, 1)
35.189
35.190 // Bitwise operators.
35.191 -OPDEF(OP_SHL, 60, "shl", 1, 2, 1)
35.192 -OPDEF(OP_SHR, 61, "shr", 1, 2, 1)
35.193 -OPDEF(OP_USHR, 62, "ushr", 1, 2, 1)
35.194 -OPDEF(OP_BITAND, 63, "bitand", 1, 2, 1)
35.195 -OPDEF(OP_BITOR, 64, "bitor", 1, 2, 1)
35.196 -OPDEF(OP_BITXOR, 65, "bitxor", 1, 2, 1)
35.197 -OPDEF(OP_BITNOT, 66, "bitnot", 1, 1, 1)
35.198 +OPDEF(OP_SHL, "shl", 1, 2, 1)
35.199 +OPDEF(OP_SHR, "shr", 1, 2, 1)
35.200 +OPDEF(OP_USHR, "ushr", 1, 2, 1)
35.201 +OPDEF(OP_BITAND, "bitand", 1, 2, 1)
35.202 +OPDEF(OP_BITOR, "bitor", 1, 2, 1)
35.203 +OPDEF(OP_BITXOR, "bitxor", 1, 2, 1)
35.204 +OPDEF(OP_BITNOT, "bitnot", 1, 1, 1)
35.205
35.206 // Saves or restores the position of the LIFO heap to/from a local slot.
35.207 -OPDEF(OP_SAVELIFO, 67, "savelifo", 5, 0, 0)
35.208 -OPDEF(OP_UNWINDLIFO, 68, "unwindlifo", 5, 0, 0)
35.209 +OPDEF(OP_SAVELIFO, "savelifo", 5, 0, 0)
35.210 +OPDEF(OP_UNWINDLIFO, "unwindlifo", 5, 0, 0)
35.211
35.212 // Composes a variable reference to a stack slot or argument.
35.213 -OPDEF(OP_VARREF_LIFO, 69, "varref.lifo", 5, 0, 1)
35.214 -OPDEF(OP_ARGREF_LIFO, 70, "argref.lifo", 5, 0, 1)
35.215 -OPDEF(OP_SLOTREF_LIFO, 71, "slotref.lifo", 1, 1, 1)
35.216 -OPDEF(OP_GETREF_I, 72, "getref.i", 1, 1, 1)
35.217 -OPDEF(OP_SETREF_I, 73, "setref.i", 1, 2, 1)
35.218 -OPDEF(OP_GETREF_F, 74, "getref.f", 1, 1, 1)
35.219 -OPDEF(OP_SETREF_F, 75, "setref.f", 1, 2, 1)
35.220 +OPDEF(OP_VARREF_LIFO, "varref.lifo", 5, 0, 1)
35.221 +OPDEF(OP_ARGREF_LIFO, "argref.lifo", 5, 0, 1)
35.222 +OPDEF(OP_SLOTREF_LIFO, "slotref.lifo", 1, 1, 1)
35.223 +OPDEF(OP_GETREF_I, "getref.i", 1, 1, 1)
35.224 +OPDEF(OP_SETREF_I, "setref.i", 1, 2, 1)
35.225 +OPDEF(OP_GETREF_F, "getref.f", 1, 1, 1)
35.226 +OPDEF(OP_SETREF_F, "setref.f", 1, 2, 1)
35.227
35.228 // Pushes an object reference onto the stack.
35.229 -OPDEF(OP_OBJECT, 76, "object", 5, 0, 1)
35.230 +OPDEF(OP_OBJECT, "object", 5, 0, 1)
35.231
35.232 // Duplicates the top item on the stack.
35.233 -OPDEF(OP_DUP, 77, "dup", 1, 1, 2)
35.234 +OPDEF(OP_DUP, "dup", 1, 1, 2)
35.235
35.236 // Duplicates the top two items on the stack.
35.237 -OPDEF(OP_DUP2, 78, "dup2", 1, 2, 4)
35.238 +OPDEF(OP_DUP2, "dup2", 1, 2, 4)
35.239
35.240 // Swaps the two items at the top of the stack.
35.241 -OPDEF(OP_SWAP, 79, "swap", 1, 2, 2)
35.242 +OPDEF(OP_SWAP, "swap", 1, 2, 2)
35.243
35.244 // Roll operation is the same as Forth. It steals a value on the stack,
35.245 // shifting all stack values down, and then places the stolen value back at
35.246 @@ -199,77 +178,68 @@
35.247 // sp[-3] = sp[-2]
35.248 // sp[-2] = sp[-1]
35.249 // sp[-1] = p
35.250 -OPDEF(OP_ROLL3, 80, "roll3", 1, 3, 3)
35.251 +OPDEF(OP_ROLL3, "roll3", 1, 3, 3)
35.252
35.253 // Pick operation is the same as Forth. It pushes a copy of a slot at a
35.254 // specific depth.
35.255 //
35.256 // push(sp[-n])
35.257 -OPDEF(OP_PICK2, 81, "pick2", 1, 2, 3)
35.258 -OPDEF(OP_PICK3, 82, "pick3", 1, 3, 4)
35.259 +OPDEF(OP_PICK2, "pick2", 1, 2, 3)
35.260 +OPDEF(OP_PICK3, "pick3", 1, 3, 4)
35.261
35.262 // Calls a native function. During the course of calling a native, arguments
35.263 // on the stack are re-pushed to match the cell-based native calling
35.264 // convention expected by ISourcePawnEngine.
35.265 //
35.266 // Unlike the normal CALL instruction, natives take truly variadic arguments
35.267 -// and so we must specify the number of arguments. The format is:
35.268 +// and so we must specify the number of arguments.
35.269 //
35.270 -// [u8 Opcode] [u32 Index] [u32 ArgCount]
35.271 +// [u8 Opcode] [u32 ArgCount]
35.272 //
35.273 -OPDEF(OP_CALLNATIVE, 83, "callnative", 9, -1, 1)
35.274 +OPDEF(OP_CALLNATIVE, "callnative", 5, -1, 1)
35.275
35.276 // Returns from a function that does return a value.
35.277 -OPDEF(OP_RETURNVOID, 84, "returnvoid", 1, 0, 0)
35.278 -
35.279 -// Loads the module of the running function.
35.280 -OPDEF(OP_MODULE, 85, "module", 1, 0, 1)
35.281 +OPDEF(OP_RETURNVOID, "returnvoid", 1, 0, 0)
35.282
35.283 -// Loads a function from a module object. The operand is the slot number
35.284 -// in the module.
35.285 -OPDEF(OP_GETMODULE_FN, 86, "getmodule.fn", 5, 1, 1)
35.286 -
35.287 -// Opcodes for accessing an environment slot in the global scope.
35.288 -OPDEF(OP_SETGLOBAL_I, 87, "setglobal.i", 5, 1, 1)
35.289 -OPDEF(OP_SETGLOBAL_F, 88, "setglobal.f", 5, 1, 1)
35.290 -OPDEF(OP_SETGLOBAL_O, 89, "setglobal.o", 5, 1, 1)
35.291 -OPDEF(OP_GETGLOBAL_I, 90, "getglobal.i", 5, 0, 1)
35.292 -OPDEF(OP_GETGLOBAL_F, 91, "getglobal.f", 5, 0, 1)
35.293 -OPDEF(OP_GETGLOBAL_O, 92, "getglobal.o", 5, 0, 1)
35.294 +// Opcodes for accessing an environment slot in the global scope. The index
35.295 +// maps into the code object's string table, and represents the name of the
35.296 +// global variable.
35.297 +OPDEF(OP_SETGLOBAL, "setglobal", 5, 1, 1)
35.298 +OPDEF(OP_GETGLOBAL, "getglobal", 5, 0, 1)
35.299
35.300 // Reinterprets a 32-bit integer as a float, or vice-versa.
35.301 -OPDEF(OP_BITS_I2F, 93, "bits.i2f", 1, 1, 1)
35.302 -OPDEF(OP_BITS_F2I, 94, "bits.f2i", 1, 1, 1)
35.303 +OPDEF(OP_BITS_I2F, "bits.i2f", 1, 1, 1)
35.304 +OPDEF(OP_BITS_F2I, "bits.f2i", 1, 1, 1)
35.305
35.306 // Pushes a boolean value.
35.307 -OPDEF(OP_TRUE, 95, "true", 1, 0, 1)
35.308 -OPDEF(OP_FALSE, 96, "false", 1, 0, 1)
35.309 +OPDEF(OP_TRUE, "true", 1, 0, 1)
35.310 +OPDEF(OP_FALSE, "false", 1, 0, 1)
35.311
35.312 // Allocate a struct. The HeapTenure is stored as a byte following pc. The
35.313 // StructMap to use is specified as an index into the script's Map table.
35.314 //
35.315 // Format:
35.316 // [u8 op] [u8 tenure] [u32 index]
35.317 -OPDEF(OP_NEWSTRUCT, 97, "newstruct", 6, 0, 1)
35.318 +OPDEF(OP_NEWSTRUCT, "newstruct", 6, 0, 1)
35.319
35.320 // Performs a struct-to-struct assignment.
35.321 // Left = pop()
35.322 // Right = pop()
35.323 // copy(Left, Right)
35.324 // push(Left)
35.325 -OPDEF(OP_COPYSTRUCT, 98, "structcopy", 1, 2, 1)
35.326 +OPDEF(OP_COPYSTRUCT, "structcopy", 1, 2, 1)
35.327
35.328 // Sets or gets a property in a struct. The index of the field is specified as
35.329 // a 32-bit integer. Note that these opcodes follow a new style of deriving
35.330 // their types at runtime.
35.331 -OPDEF(OP_GETFIELD, 99, "getfield", 5, 1, 1)
35.332 -OPDEF(OP_SETFIELD, 100, "setfield", 5, 2, 1)
35.333 -
35.334 -OPDEF(OP_FIELDREF_LIFO, 101, "fieldref.lifo", 5, 1, 1)
35.335 +OPDEF(OP_GETFIELD, "getfield", 5, 1, 1)
35.336 +OPDEF(OP_SETFIELD, "setfield", 5, 2, 1)
35.337
35.338 // Table-based jump.
35.339 // [u8 op] [i32 low] [i32 high] [u32 jump] [u32 jumps...]
35.340 -OPDEF(OP_TABLESWITCH, 102, "tableswitch", 9, 1, 0)
35.341 +OPDEF(OP_TABLESWITCH, "tableswitch", 9, 1, 0)
35.342
35.343 -OPDEF(OP_SIZEOF, 103, "sizeof", 1, 1, 1)
35.344 +OPDEF(OP_SIZEOF, "sizeof", 1, 1, 1)
35.345
35.346 +// Registers a function as a publicly exported name.
35.347 +OPDEF(OP_PUBLIC, "public", 1, 1, 0)
35.348 \ No newline at end of file
36.1 --- a/src/Parser.cpp Mon Sep 17 00:10:01 2012 -0700
36.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
36.3 @@ -1,1846 +0,0 @@
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 -#include <string.h>
36.23 -#include "Zone.h"
36.24 -#include "Parser.h"
36.25 -#include "FixedArray.h"
36.26 -#include "Heap.h"
36.27 -#include "Strings.h"
36.28 -#include "TypeManager.h"
36.29 -#include "Heap-inl.h"
36.30 -
36.31 -using namespace ke;
36.32 -
36.33 -Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length)
36.34 - : zone_(zone),
36.35 - cc_(cc),
36.36 - pool_(zone_->pool()),
36.37 - scanner_(cc, stream, length),
36.38 - scope_(NULL),
36.39 - unbound_(NULL)
36.40 -{
36.41 - unbound_ = new (pool_) PoolList<NameProxy *>();
36.42 -}
36.43 -
36.44 -bool
36.45 -Parser::peek(TokenKind kind)
36.46 -{
36.47 - return scanner_.peek() == kind;
36.48 -}
36.49 -
36.50 -bool
36.51 -Parser::match(TokenKind kind)
36.52 -{
36.53 - if (!peek(kind))
36.54 - return false;
36.55 - scanner_.scan();
36.56 - return true;
36.57 -}
36.58 -
36.59 -bool
36.60 -Parser::matchSemicolon()
36.61 -{
36.62 - return expect(TOK_SEMICOLON);
36.63 -}
36.64 -
36.65 -bool
36.66 -Parser::expect(TokenKind kind)
36.67 -{
36.68 - TokenKind got = scanner_.scan();
36.69 - if (got == kind)
36.70 - return true;
36.71 - cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]);
36.72 - return false;
36.73 -}
36.74 -
36.75 -Scope *
36.76 -Parser::enterScope(Scope::Kind kind)
36.77 -{
36.78 - scope_ = new (pool_) Scope(pool_, kind, scope_);
36.79 - if (!scope_->initialize())
36.80 - return NULL;
36.81 - return scope_;
36.82 -}
36.83 -
36.84 -NameProxy *
36.85 -Parser::bind(Handle<String> name)
36.86 -{
36.87 - BoundName *bound = scope_->lookup(name);
36.88 - NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), name, bound);
36.89 - if (!bound && !unbound_->append(proxy))
36.90 - return NULL;
36.91 - return proxy;
36.92 -}
36.93 -
36.94 -BoundName *
36.95 -Parser::bindType(Handle<String> name)
36.96 -{
36.97 - if (BoundName *binding = scope_->lookup(name))
36.98 - return binding;
36.99 -
36.100 - return new (pool_) UnboundName(scope_, name);
36.101 -}
36.102 -
36.103 -bool
36.104 -Parser::matchName(String **name, TokenKind kind)
36.105 -{
36.106 - assert(kind == TOK_NAME || kind == TOK_LABEL);
36.107 - *name = NULL;
36.108 - if (!match(kind))
36.109 - return false;
36.110 - *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
36.111 - return true;
36.112 -}
36.113 -
36.114 -String *
36.115 -Parser::expectName()
36.116 -{
36.117 - if (!expect(TOK_NAME))
36.118 - return NULL;
36.119 - return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
36.120 -}
36.121 -
36.122 -void
36.123 -Parser::redeclarationError(BoundName *other)
36.124 -{
36.125 - cc_.reportError(scanner_.begin(), Message_RedeclaredName, other->name()->chars(),
36.126 - other->pos().line, other->pos().col);
36.127 -}
36.128 -
36.129 -Expression *
36.130 -Parser::primitive()
36.131 -{
36.132 - TokenKind kind = scanner_.peek();
36.133 - switch (kind) {
36.134 - case TOK_FLOAT_LITERAL:
36.135 - {
36.136 - scanner_.scan();
36.137 - double value = Scanner::ParseDouble(scanner_.literal());
36.138 - return new (pool_) FloatLiteral(scanner_.begin(), value);
36.139 - }
36.140 -
36.141 - case TOK_HEX_LITERAL:
36.142 - {
36.143 - scanner_.scan();
36.144 - int value = strtol(scanner_.literal(), NULL, 16);
36.145 - return new (pool_) IntegerLiteral(scanner_.begin(), value);
36.146 - }
36.147 -
36.148 - case TOK_INTEGER_LITERAL:
36.149 - {
36.150 - scanner_.scan();
36.151 - int value = atoi(scanner_.literal());
36.152 - return new (pool_) IntegerLiteral(scanner_.begin(), value);
36.153 - }
36.154 -
36.155 - case TOK_TRUE:
36.156 - case TOK_FALSE:
36.157 - scanner_.scan();
36.158 - return new (pool_) BooleanLiteral(scanner_.begin(), kind);
36.159 -
36.160 - case TOK_STRING_LITERAL:
36.161 - {
36.162 - scanner_.scan();
36.163 - Local<ByteArray> array(zone_, ByteArray::New(zone_, scanner_.literal_length() + 1));
36.164 - if (!array)
36.165 - return NULL;
36.166 - memcpy(array->raw(), scanner_.literal(), scanner_.literal_length() + 1);
36.167 - return new (pool_) StringLiteral(scanner_.begin(), array);
36.168 - }
36.169 -
36.170 - default:
36.171 - {
36.172 - if (kind != TOK_ERROR)
36.173 - cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]);
36.174 - return NULL;
36.175 - }
36.176 - }
36.177 -}
36.178 -
36.179 -Expression *
36.180 -Parser::arrayLiteral(TokenKind kind)
36.181 -{
36.182 - assert(kind == TOK_LBRACE || kind == TOK_LBRACKET);
36.183 -
36.184 - TokenKind close = (kind == TOK_LBRACE)
36.185 - ? TOK_RBRACE
36.186 - : TOK_RBRACKET;
36.187 -
36.188 - SourcePosition pos = scanner_.begin();
36.189 -
36.190 - ExpressionList *list = new (pool_) ExpressionList();
36.191 - do {
36.192 - if (match(close))
36.193 - break;
36.194 -
36.195 - Expression *expr = NULL;
36.196 - if (kind == TOK_LBRACE) {
36.197 - if (peek(TOK_LBRACE))
36.198 - expr = arrayLiteral(TOK_LBRACE);
36.199 - else
36.200 - expr = primitive();
36.201 - } else {
36.202 - expr = expression();
36.203 - }
36.204 - if (!expr)
36.205 - return NULL;
36.206 -
36.207 - if (!list->append(expr))
36.208 - return NULL;
36.209 -
36.210 - if (!match(TOK_COMMA)) {
36.211 - if (!expect(close))
36.212 - return NULL;
36.213 - break;
36.214 - }
36.215 - } while (true);
36.216 -
36.217 - return new (pool_) ArrayLiteral(pos, kind, list);
36.218 -}
36.219 -
36.220 -Expression *
36.221 -Parser::prefix()
36.222 -{
36.223 - switch (scanner_.peek()) {
36.224 - case TOK_LPAREN:
36.225 - {
36.226 - scanner_.scan();
36.227 - Expression *expr = expression();
36.228 - if (!expr)
36.229 - return NULL;
36.230 - if (!expect(TOK_RPAREN))
36.231 - return NULL;
36.232 - return expr;
36.233 - }
36.234 -
36.235 - case TOK_NAME:
36.236 - {
36.237 - Local<String> name(zone_, expectName());
36.238 - if (!name)
36.239 - return NULL;
36.240 - return bind(name);
36.241 - }
36.242 -
36.243 - default:
36.244 - return primitive();
36.245 - }
36.246 -}
36.247 -
36.248 -Expression *
36.249 -Parser::call(Expression *callee)
36.250 -{
36.251 - ExpressionList *arguments = new (pool_) ExpressionList();
36.252 -
36.253 - SourcePosition pos = scanner_.begin();
36.254 - expect(TOK_LPAREN);
36.255 -
36.256 - if (!match(TOK_RPAREN)) {
36.257 - while (true) {
36.258 - Expression *expr = expression();
36.259 - if (!expr)
36.260 - return NULL;
36.261 -
36.262 - if (!arguments->append(expr))
36.263 - return NULL;
36.264 -
36.265 - if (!match(TOK_COMMA))
36.266 - break;
36.267 - }
36.268 -
36.269 - if (!expect(TOK_RPAREN))
36.270 - return NULL;
36.271 - }
36.272 -
36.273 - return new (pool_) CallExpression(pos, callee, arguments);
36.274 -}
36.275 -
36.276 -Expression *
36.277 -Parser::index(Expression *left)
36.278 -{
36.279 - expect(TOK_LBRACKET);
36.280 -
36.281 - SourcePosition pos = scanner_.begin();
36.282 - Expression *expr = expression();
36.283 - if (!expr)
36.284 - return NULL;
36.285 -
36.286 - if (!expect(TOK_RBRACKET))
36.287 - return NULL;
36.288 -
36.289 - return new (pool_) IndexExpression(pos, left, expr);
36.290 -}
36.291 -
36.292 -Expression *
36.293 -Parser::field(Expression *left)
36.294 -{
36.295 - expect(TOK_DOT);
36.296 -
36.297 - SourcePosition pos = scanner_.begin();
36.298 - Local<String> name(zone_, expectName());
36.299 - if (!name)
36.300 - return NULL;
36.301 -
36.302 - return new (pool_) FieldExpression(pos, left, name);
36.303 -}
36.304 -
36.305 -Expression *
36.306 -Parser::primary()
36.307 -{
36.308 - Expression *expr = prefix();
36.309 - if (!expr)
36.310 - return NULL;
36.311 -
36.312 - for (;;) {
36.313 - switch (scanner_.peek()) {
36.314 - case TOK_LPAREN:
36.315 - if ((expr = call(expr)) == NULL)
36.316 - return NULL;
36.317 - break;
36.318 -
36.319 - case TOK_LBRACKET:
36.320 - if ((expr = index(expr)) == NULL)
36.321 - return NULL;
36.322 - break;
36.323 -
36.324 - case TOK_DOT:
36.325 - if ((expr = field(expr)) == NULL)
36.326 - return NULL;
36.327 - break;
36.328 -
36.329 - default:
36.330 - return expr;
36.331 - }
36.332 - }
36.333 -}
36.334 -
36.335 -Expression *
36.336 -Parser::unary()
36.337 -{
36.338 - TokenKind token = scanner_.peek();
36.339 -
36.340 - SourcePosition pos = scanner_.begin();
36.341 - switch (token) {
36.342 - case TOK_INCREMENT:
36.343 - case TOK_DECREMENT:
36.344 - {
36.345 - scanner_.scan();
36.346 - Expression *expr = unary();
36.347 - if (!expr)
36.348 - return NULL;
36.349 - return new (pool_) IncDecExpression(pos, token, expr, false);
36.350 - }
36.351 -
36.352 - case TOK_MINUS:
36.353 - case TOK_NOT:
36.354 - case TOK_TILDE:
36.355 - {
36.356 - scanner_.scan();
36.357 - Expression *expr = unary();
36.358 - if (!expr)
36.359 - return NULL;
36.360 - return new (pool_) UnaryExpression(pos, token, expr);
36.361 - }
36.362 -
36.363 - case TOK_SIZEOF:
36.364 - {
36.365 - scanner_.scan();
36.366 - if (!expect(TOK_LPAREN))
36.367 - return NULL;
36.368 - Expression *expr = unary();
36.369 - if (!expr)
36.370 - return NULL;
36.371 - if (!expect(TOK_RPAREN))
36.372 - return NULL;
36.373 - return new (pool_) UnaryExpression(pos, token, expr);
36.374 - }
36.375 -
36.376 - case TOK_LABEL:
36.377 - {
36.378 - scanner_.scan();
36.379 - Local<String> tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
36.380 - if (!tag)
36.381 - return NULL;
36.382 -
36.383 - BoundName *type = NULL;
36.384 - if (tag)
36.385 - type = bindType(tag);
36.386 -
36.387 - Expression *expr = unary();
36.388 - if (!expr)
36.389 - return NULL;
36.390 -
36.391 - return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, type);
36.392 - }
36.393 -
36.394 - default:
36.395 - break;
36.396 - }
36.397 -
36.398 - Expression *expr = primary();
36.399 -
36.400 - token = scanner_.peek();
36.401 - if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
36.402 - scanner_.scan();
36.403 - return new (pool_) IncDecExpression(pos, token, expr, true);
36.404 - }
36.405 -
36.406 - return expr;
36.407 -}
36.408 -
36.409 -Expression *
36.410 -Parser::multiplication()
36.411 -{
36.412 - Expression *left = unary();
36.413 - do {
36.414 - if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT))
36.415 - break;
36.416 - SourcePosition pos = scanner_.begin();
36.417 - TokenKind kind = scanner_.last();
36.418 - Expression *right = unary();
36.419 - if (!right)
36.420 - return NULL;
36.421 - left = new (pool_) BinaryExpression(pos, kind, left, right);
36.422 - } while (left);
36.423 - return left;
36.424 -}
36.425 -
36.426 -Expression *
36.427 -Parser::addition()
36.428 -{
36.429 - Expression *left = multiplication();
36.430 - while (left) {
36.431 - if (!match(TOK_PLUS) && !match(TOK_MINUS))
36.432 - break;
36.433 - SourcePosition pos = scanner_.begin();
36.434 - TokenKind kind = scanner_.last();
36.435 - Expression *right = multiplication();
36.436 - if (!right)
36.437 - return NULL;
36.438 - left = new (pool_) BinaryExpression(pos, kind, left, right);
36.439 - }
36.440 - return left;
36.441 -}
36.442 -
36.443 -Expression *
36.444 -Parser::shift()
36.445 -{
36.446 - Expression *left = addition();
36.447 - while (left) {
36.448 - if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR))
36.449 - break;
36.450 - SourcePosition pos = scanner_.begin();
36.451 - TokenKind kind = scanner_.last();
36.452 - Expression *right = addition();
36.453 - if (!right)
36.454 - return NULL;
36.455 - left = new (pool_) BinaryExpression(pos, kind, left, right);
36.456 - }
36.457 - return left;
36.458 -}
36.459 -
36.460 -Expression *
36.461 -Parser::bitand_()
36.462 -{
36.463 - Expression *left = shift();
36.464 - while (left) {
36.465 - if (!match(TOK_BITAND))
36.466 - break;
36.467 - SourcePosition pos = scanner_.begin();
36.468 - Expression *right = shift();
36.469 - if (!right)
36.470 - return NULL;
36.471 - left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right);
36.472 - }
36.473 - return left;
36.474 -}
36.475 -
36.476 -Expression *
36.477 -Parser::bitxor()
36.478 -{
36.479 - Expression *left = bitand_();
36.480 - while (left) {
36.481 - if (!match(TOK_BITXOR))
36.482 - break;
36.483 - SourcePosition pos = scanner_.begin();
36.484 - Expression *right = shift();
36.485 - if (!right)
36.486 - return NULL;
36.487 - left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right);
36.488 - }
36.489 - return left;
36.490 -}
36.491 -
36.492 -Expression *
36.493 -Parser::bitor_()
36.494 -{
36.495 - Expression *left = bitxor();
36.496 - while (left) {
36.497 - if (!match(TOK_BITOR))
36.498 - break;
36.499 - SourcePosition pos = scanner_.begin();
36.500 - Expression *right = bitxor();
36.501 - if (!right)
36.502 - return NULL;
36.503 - left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right);
36.504 - }
36.505 - return left;
36.506 -}
36.507 -
36.508 -Expression *
36.509 -Parser::relational()
36.510 -{
36.511 - Expression *left = bitor_();
36.512 - while (left) {
36.513 - TokenKind kind = scanner_.peek();
36.514 - if (kind < TOK_LT || kind > TOK_GE)
36.515 - break;
36.516 - scanner_.scan();
36.517 - SourcePosition pos = scanner_.begin();
36.518 - Expression *right = shift();
36.519 - if (!right)
36.520 - return NULL;
36.521 - left = new (pool_) BinaryExpression(pos, kind, left, right);
36.522 - }
36.523 - return left;
36.524 -}
36.525 -
36.526 -Expression *
36.527 -Parser::equals()
36.528 -{
36.529 - Expression *left = relational();
36.530 - while (left) {
36.531 - if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS))
36.532 - break;
36.533 - TokenKind kind = scanner_.last();
36.534 - SourcePosition pos = scanner_.begin();
36.535 - Expression *right = relational();
36.536 - if (!right)
36.537 - return NULL;
36.538 - left = new (pool_) BinaryExpression(pos, kind, left, right);
36.539 - }
36.540 - return left;
36.541 -}
36.542 -
36.543 -Expression *
36.544 -Parser::and_()
36.545 -{
36.546 - Expression *left = equals();
36.547 - while (left) {
36.548 - if (!match(TOK_AND))
36.549 - break;
36.550 - SourcePosition pos = scanner_.begin();
36.551 - Expression *right = equals();
36.552 - if (!right)
36.553 - return NULL;
36.554 - left = new (pool_) BinaryExpression(pos, TOK_AND, left, right);
36.555 - }
36.556 - return left;
36.557 -}
36.558 -
36.559 -Expression *
36.560 -Parser::or_()
36.561 -{
36.562 - Expression *left = and_();
36.563 - while (left) {
36.564 - if (!match(TOK_OR))
36.565 - break;
36.566 - SourcePosition pos = scanner_.begin();
36.567 - Expression *right = and_();
36.568 - if (!right)
36.569 - return NULL;
36.570 - left = new (pool_) BinaryExpression(pos, TOK_OR, left, right);
36.571 - }
36.572 - return left;
36.573 -}
36.574 -
36.575 -Expression *
36.576 -Parser::ternary()
36.577 -{
36.578 - Expression *cond = or_();
36.579 - if (!cond)
36.580 - return NULL;
36.581 -
36.582 - if (!match(TOK_QMARK))
36.583 - return cond;
36.584 -
36.585 - Expression *left;
36.586 - SourcePosition pos = scanner_.begin();
36.587 - AutoAllowTags<false> disableTags(scanner_);
36.588 - {
36.589 - if ((left = expression()) == NULL)
36.590 - return NULL;
36.591 - }
36.592 -
36.593 - if (!expect(TOK_COLON))
36.594 - return NULL;
36.595 -
36.596 - Expression *right = expression();
36.597 - if (!right)
36.598 - return NULL;
36.599 -
36.600 - return new (pool_) TernaryExpression(pos, cond, left, right);
36.601 -}
36.602 -
36.603 -Expression *
36.604 -Parser::assignment()
36.605 -{
36.606 - Expression *left = ternary();
36.607 - while (left) {
36.608 - TokenKind token = scanner_.peek();
36.609 - if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
36.610 - break;
36.611 - scanner_.scan();
36.612 - SourcePosition pos = scanner_.begin();
36.613 - Expression *expr = ternary();
36.614 - if (!expr)
36.615 - return NULL;
36.616 -
36.617 - left = new (pool_) Assignment(pos, token, left, expr);
36.618 - }
36.619 - return left;
36.620 -}
36.621 -
36.622 -Expression *
36.623 -Parser::expression()
36.624 -{
36.625 - return assignment();
36.626 -}
36.627 -
36.628 -Statement *
36.629 -Parser::while_()
36.630 -{
36.631 - SourcePosition pos = scanner_.begin();
36.632 - scanner_.scan();
36.633 -
36.634 - if (!expect(TOK_LPAREN))
36.635 - return NULL;
36.636 -
36.637 - Expression *condition = expression();
36.638 - if (!condition)
36.639 - return NULL;
36.640 -
36.641 - if (!expect(TOK_RPAREN))
36.642 - return NULL;
36.643 -
36.644 - // Inside a loop, we force the creation of a scope object. Normally, we
36.645 - // will cull scopes if they have no variables. However inside a loop,
36.646 - // function calls that take references may compute a LIFO object, and to
36.647 - // avoid temporarily leaking many such objects, we ensure that a scope
36.648 - // is present so a LIFO slot can be allocated.
36.649 - if (!enterScope(Scope::BLOCK))
36.650 - return NULL;
36.651 -
36.652 - Statement *body;
36.653 - if (scanner_.peek() == TOK_LBRACE)
36.654 - body = block(scope_);
36.655 - else
36.656 - body = localStatement();
36.657 - if (!body)
36.658 - return NULL;
36.659 -
36.660 - scope_ = scope_->enclosing();
36.661 - return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body);
36.662 -}
36.663 -
36.664 -Statement *
36.665 -Parser::do_()
36.666 -{
36.667 - SourcePosition pos = scanner_.begin();
36.668 - scanner_.scan();
36.669 -
36.670 - // See the comment in ::while_() as to why we force a scope.
36.671 - if (!enterScope(Scope::BLOCK))
36.672 - return NULL;
36.673 -
36.674 - Statement *body;
36.675 - if (scanner_.peek() == TOK_LBRACE)
36.676 - body = block(scope_);
36.677 - else
36.678 - body = localStatement();
36.679 - if (!body)
36.680 - return NULL;
36.681 -
36.682 - scope_ = scope_->enclosing();
36.683 -
36.684 - if (!expect(TOK_WHILE))
36.685 - return NULL;
36.686 -
36.687 - if (!expect(TOK_LPAREN))
36.688 - return NULL;
36.689 - Expression *condition = expression();
36.690 - if (!condition)
36.691 - return NULL;
36.692 - if (!expect(TOK_RPAREN))
36.693 - return NULL;
36.694 -
36.695 - return new (pool_) WhileStatement(pos, TOK_DO, condition, body);
36.696 -}
36.697 -
36.698 -Statement *
36.699 -Parser::switch_()
36.700 -{
36.701 - expect(TOK_SWITCH);
36.702 -
36.703 - SourcePosition pos = scanner_.begin();
36.704 -
36.705 - if (!expect(TOK_LPAREN))
36.706 - return NULL;
36.707 - Expression *expr = expression();
36.708 - if (!expr)
36.709 - return NULL;
36.710 - if (!expect(TOK_RPAREN))
36.711 - return NULL;
36.712 -
36.713 - if (!expect(TOK_LBRACE))
36.714 - return NULL;
36.715 -
36.716 - SourcePosition defaultPos;
36.717 - PoolList<Case *> *cases = new (pool_) PoolList<Case *>();
36.718 -
36.719 - Statement *defaultCase = NULL;
36.720 -
36.721 - while (!peek(TOK_RBRACE)) {
36.722 - Expression *expr = NULL;
36.723 - ExpressionList *others = NULL;
36.724 - if (match(TOK_DEFAULT)) {
36.725 - if (defaultCase) {
36.726 - cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch);
36.727 - return NULL;
36.728 - }
36.729 -
36.730 - defaultPos = scanner_.begin();
36.731 - } else {
36.732 - if (defaultCase) {
36.733 - cc_.reportError(defaultPos, Message_DefaultMustBeLastCase);
36.734 - return NULL;
36.735 - }
36.736 -
36.737 - if (!expect(TOK_CASE))
36.738 - return NULL;
36.739 -
36.740 - // A limitation in the grammar is that |case <NAME>:| will be
36.741 - // detected as a label.
36.742 - AutoAllowTags<false> disableTags(scanner_);
36.743 -
36.744 - if ((expr = expression()) == NULL)
36.745 - return NULL;
36.746 -
36.747 - if (peek(TOK_COMMA)) {
36.748 - others = new (pool_) ExpressionList();
36.749 - while (match(TOK_COMMA)) {
36.750 - Expression *other = expression();
36.751 - if (!other)
36.752 - return NULL;
36.753 - if (!others->append(other))
36.754 - return NULL;
36.755 - }
36.756 - }
36.757 - }
36.758 -
36.759 - if (!expect(TOK_COLON))
36.760 - return NULL;
36.761 -
36.762 - Statement *statement = localStatement();
36.763 - if (!statement)
36.764 - return NULL;
36.765 -
36.766 - if (!peek(TOK_CASE) &&
36.767 - !peek(TOK_DEFAULT) &&
36.768 - !peek(TOK_RBRACE))
36.769 - {
36.770 - cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase);
36.771 - return NULL;
36.772 - }
36.773 -
36.774 - if (expr) {
36.775 - Case *caze = new (pool_) Case(expr, others, statement);
36.776 - if (!cases->append(caze))
36.777 - return NULL;
36.778 - } else {
36.779 - defaultCase = statement;
36.780 - }
36.781 - }
36.782 -
36.783 - if (!expect(TOK_RBRACE))
36.784 - return NULL;
36.785 -
36.786 - return new (pool_) SwitchStatement(pos, expr, cases, defaultCase);
36.787 -}
36.788 -
36.789 -Statement *
36.790 -Parser::forStatement()
36.791 -{
36.792 - SourcePosition pos = scanner_.begin();
36.793 - scanner_.scan();
36.794 - if (!expect(TOK_LPAREN))
36.795 - return NULL;
36.796 -
36.797 - Statement *decl = NULL;
36.798 - if (!match(TOK_SEMICOLON)) {
36.799 - if (match(TOK_NEW)) {
36.800 - if (!enterScope(Scope::BLOCK))
36.801 - return NULL;
36.802 - if ((decl = vars(TOK_STOCK, TOK_NEW)) == NULL)
36.803 - return NULL;
36.804 - } else {
36.805 - if ((decl = expressionStatement()) == NULL)
36.806 - return NULL;
36.807 - }
36.808 - if (!expect(TOK_SEMICOLON))
36.809 - return NULL;
36.810 - }
36.811 -
36.812 - Expression *condition = NULL;
36.813 - if (!match(TOK_SEMICOLON)) {
36.814 - if ((condition = expression()) == NULL)
36.815 - return NULL;
36.816 - if (!expect(TOK_SEMICOLON))
36.817 - return NULL;
36.818 - }
36.819 -
36.820 - Statement *update = NULL;
36.821 - if (!match(TOK_RPAREN)) {
36.822 - if ((update = expressionStatement()) == NULL)
36.823 - return NULL;
36.824 - if (!expect(TOK_RPAREN))
36.825 - return NULL;
36.826 - }
36.827 -
36.828 - // See the comment in ::while_() as to why we force a scope.
36.829 - if (!enterScope(Scope::BLOCK))
36.830 - return NULL;
36.831 -
36.832 - Statement *body;
36.833 - if (scanner_.peek() == TOK_LBRACE)
36.834 - body = block(scope_);
36.835 - else
36.836 - body = localStatement();
36.837 - if (!body)
36.838 - return NULL;
36.839 -
36.840 - scope_ = scope_->enclosing();
36.841 -
36.842 - Scope *declScope = NULL;
36.843 - if (decl && (decl->isVariableDeclaration() || decl->isBlockStatement())) {
36.844 - declScope = scope_->unlinkIfEmpty();
36.845 - scope_ = scope_->enclosing();
36.846 - }
36.847 - return new (pool_) ForStatement(pos, declScope, decl, condition, update, body);
36.848 -}
36.849 -
36.850 -ExpressionList *
36.851 -Parser::dimensions()
36.852 -{
36.853 - ExpressionList *postDimensions = new (pool_) ExpressionList();
36.854 - while (match(TOK_LBRACKET)) {
36.855 - Expression *dim = NULL;
36.856 - if (!match(TOK_RBRACKET)) {
36.857 - if ((dim = expression()) == NULL)
36.858 - return NULL;
36.859 - if (!expect(TOK_RBRACKET))
36.860 - return NULL;
36.861 - }
36.862 -
36.863 - if (!postDimensions->append(dim))
36.864 - return NULL;
36.865 - }
36.866 - return postDimensions;
36.867 -}
36.868 -
36.869 -VariableDeclaration *
36.870 -Parser::var(TokenKind scope, TokenKind kind)
36.871 -{
36.872 - Local<String> tag(zone_);
36.873 - if (matchName(tag.ref(), TOK_LABEL) && !tag)
36.874 - return NULL;
36.875 -
36.876 - BoundName *type = NULL;
36.877 - if (tag)
36.878 - type = bindType(tag);
36.879 -
36.880 - Local<String> name(zone_, expectName());
36.881 - if (!name)
36.882 - return NULL;
36.883 -
36.884 - SourcePosition pos = scanner_.begin();
36.885 -
36.886 - if (BoundName *other = scope_->localLookup(name)) {
36.887 - redeclarationError(other);
36.888 - return NULL;
36.889 - }
36.890 -
36.891 - ExpressionList *postDimensions = NULL;
36.892 - if (peek(TOK_LBRACKET)) {
36.893 - if ((postDimensions = dimensions()) == NULL)
36.894 - return NULL;
36.895 - }
36.896 -
36.897 - Expression *expr = NULL;
36.898 - if (match(TOK_ASSIGN)) {
36.899 - switch (scanner_.peek()) {
36.900 - // Note: we don't support [] literals yet.
36.901 - case TOK_LBRACE:
36.902 - if ((expr = arrayLiteral(scanner_.scan())) == NULL)
36.903 - return NULL;
36.904 - break;
36.905 -
36.906 - default:
36.907 - if ((expr = expression()) == NULL)
36.908 - return NULL;
36.909 - break;
36.910 - }
36.911 - }
36.912 -
36.913 - Variable *var = scope_->declareVariable(name, pos);
36.914 - if (!var)
36.915 - return NULL;
36.916 -
36.917 - if (scope == TOK_PUBLIC)
36.918 - var->setPublic();
36.919 -
36.920 - return new (pool_) VariableDeclaration(var->pos(), kind, var, type, postDimensions, expr);
36.921 -}
36.922 -
36.923 -Statement *
36.924 -Parser::vars(TokenKind scope, TokenKind kind)
36.925 -{
36.926 - VariableDeclaration *decl = var(scope, kind);
36.927 - if (!decl)
36.928 - return NULL;
36.929 -
36.930 - if (!peek(TOK_COMMA))
36.931 - return decl;
36.932 -
36.933 - StatementList *statements = new (pool_) StatementList();
36.934 - if (!statements->append(decl))
36.935 - return NULL;
36.936 -
36.937 - while (match(TOK_COMMA)) {
36.938 - Statement *decl = var(scope, kind);
36.939 - if (!decl)
36.940 - return NULL;
36.941 - if (!statements->append(decl))
36.942 - return NULL;
36.943 - }
36.944 -
36.945 - // Create a fake-o block with no scope to create a statement list.
36.946 - return new (pool_) BlockStatement(decl->pos(), NULL, statements);
36.947 -}
36.948 -
36.949 -Statement *
36.950 -Parser::returnStatement()
36.951 -{
36.952 - SourcePosition pos = scanner_.begin();
36.953 - if (!expect(TOK_RETURN))
36.954 - return NULL;
36.955 -
36.956 - Expression *expr = NULL;
36.957 - if (scanner_.peek() != TOK_SEMICOLON) {
36.958 - if ((expr = expression()) == NULL)
36.959 - return NULL;
36.960 -
36.961 - // We only care about non-void returns when determining whether a
36.962 - // tagless function is non-void.
36.963 - encounteredReturn_ = true;
36.964 - }
36.965 -
36.966 - return new (pool_) ReturnStatement(pos, expr);
36.967 -}
36.968 -
36.969 -Statement *
36.970 -Parser::expressionStatement()
36.971 -{
36.972 - Expression *left = assignment();
36.973 - if (!left)
36.974 - return NULL;
36.975 -
36.976 - return new (pool_) ExpressionStatement(left);
36.977 -}
36.978 -
36.979 -Statement *
36.980 -Parser::block(Scope *scope)
36.981 -{
36.982 - if (!expect(TOK_LBRACE))
36.983 - return NULL;
36.984 -
36.985 - SourcePosition pos = scanner_.begin();
36.986 - if (!scope && !enterScope(Scope::BLOCK))
36.987 - return NULL;
36.988 -
36.989 - StatementList *statements = new (pool_) StatementList();
36.990 - while (!match(TOK_RBRACE)) {
36.991 - Statement *statement = localStatement();
36.992 - if (statement == NULL)
36.993 - return NULL;
36.994 - if (!statements->append(statement))
36.995 - return NULL;
36.996 - }
36.997 -
36.998 - if (!scope) {
36.999 - scope = scope_->unlinkIfEmpty();
36.1000 - scope_ = scope_->enclosing();
36.1001 - }
36.1002 - BlockStatement *block = new (pool_) BlockStatement(pos, scope, statements);
36.1003 - return block;
36.1004 -}
36.1005 -
36.1006 -Statement *
36.1007 -Parser::if_()
36.1008 -{
36.1009 - expect(TOK_IF);
36.1010 -
36.1011 - SourcePosition pos = scanner_.begin();
36.1012 - if (!expect(TOK_LPAREN))
36.1013 - return NULL;
36.1014 -
36.1015 - Expression *cond = expression();
36.1016 - if (!cond)
36.1017 - return NULL;
36.1018 -
36.1019 - if (!expect(TOK_RPAREN))
36.1020 - return NULL;
36.1021 -
36.1022 - Statement *ifTrue = localStatement();
36.1023 - if (!ifTrue)
36.1024 - return NULL;
36.1025 -
36.1026 - IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue);
36.1027 -
36.1028 - IfStatement *last = outer;
36.1029 - while (match(TOK_ELSE)) {
36.1030 - if (!match(TOK_IF)) {
36.1031 - Statement *ifFalse = localStatement();
36.1032 - if (!ifFalse)
36.1033 - return NULL;
36.1034 -
36.1035 - last->setIfFalse(ifFalse);
36.1036 - break;
36.1037 - }
36.1038 -
36.1039 - SourcePosition pos = scanner_.begin();
36.1040 - if (!expect(TOK_LPAREN))
36.1041 - return NULL;
36.1042 -
36.1043 - Expression *otherCond = expression();
36.1044 - if (!otherCond)
36.1045 - return NULL;
36.1046 -
36.1047 - if (!expect(TOK_RPAREN))
36.1048 - return NULL;
36.1049 -
36.1050 - Statement *otherIfTrue = localStatement();
36.1051 - if (!otherIfTrue)
36.1052 - return NULL;
36.1053 -
36.1054 - IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue);
36.1055 - last->setIfFalse(inner);
36.1056 - last = inner;
36.1057 - }
36.1058 -
36.1059 - return outer;
36.1060 -}
36.1061 -
36.1062 -Statement *
36.1063 -Parser::localStatement()
36.1064 -{
36.1065 - Statement *statement = NULL;
36.1066 -
36.1067 - // Statements which must be followed by a semicolon will break out of the
36.1068 - // switch. If they may end in BlockStatements, they'll immediately return.
36.1069 -
36.1070 - TokenKind kind = scanner_.peek();
36.1071 - switch (kind) {
36.1072 - case TOK_CONST:
36.1073 - case TOK_NEW:
36.1074 - scanner_.scan();
36.1075 - if ((statement = vars(TOK_STOCK, kind)) == NULL)
36.1076 - return NULL;
36.1077 - break;
36.1078 -
36.1079 - case TOK_FOR:
36.1080 - return forStatement();
36.1081 -
36.1082 - case TOK_WHILE:
36.1083 - return while_();
36.1084 -
36.1085 - case TOK_BREAK:
36.1086 - scanner_.scan();
36.1087 - statement = new (pool_) BreakStatement(scanner_.begin());
36.1088 - break;
36.1089 -
36.1090 - case TOK_CONTINUE:
36.1091 - scanner_.scan();
36.1092 - statement = new (pool_) ContinueStatement(scanner_.begin());
36.1093 - break;
36.1094 -
36.1095 - case TOK_DO:
36.1096 - if ((statement = do_()) == NULL)
36.1097 - return NULL;
36.1098 - break;
36.1099 -
36.1100 - case TOK_RETURN:
36.1101 - if ((statement = returnStatement()) == NULL)
36.1102 - return NULL;
36.1103 - break;
36.1104 -
36.1105 - case TOK_ENUM:
36.1106 - if ((statement = enum_()) == NULL)
36.1107 - return NULL;
36.1108 - break;
36.1109 -
36.1110 - case TOK_STRUCT:
36.1111 - if ((statement = struct_()) == NULL)
36.1112 - return NULL;
36.1113 - break;
36.1114 -
36.1115 - case TOK_SWITCH:
36.1116 - return switch_();
36.1117 -
36.1118 - case TOK_IF:
36.1119 - return if_();
36.1120 -
36.1121 - case TOK_LBRACE:
36.1122 - return block();
36.1123 -
36.1124 - default:
36.1125 - break;
36.1126 - }
36.1127 -
36.1128 - if (!statement) {
36.1129 - if ((statement = expressionStatement()) == NULL)
36.1130 - return NULL;
36.1131 - }
36.1132 -
36.1133 - if (!expect(TOK_SEMICOLON))
36.1134 - return NULL;
36.1135 -
36.1136 - return statement;
36.1137 -}
36.1138 -
36.1139 -Statement *
36.1140 -Parser::struct_()
36.1141 -{
36.1142 - expect(TOK_STRUCT);
36.1143 -
36.1144 - Local<String> name(zone_, expectName());
36.1145 - if (!name)
36.1146 - return NULL;
36.1147 -
36.1148 - SourcePosition pos = scanner_.begin();
36.1149 -
36.1150 - if (BoundName *other = scope_->localLookup(name)) {
36.1151 - redeclarationError(other);
36.1152 - return NULL;
36.1153 - }
36.1154 -
36.1155 - NamedType *type;
36.1156 - if ((type = scope_->declareType(name, scanner_.begin())) == NULL)
36.1157 - return NULL;
36.1158 -
36.1159 - if (!expect(TOK_LBRACE))
36.1160 - return NULL;
36.1161 -
36.1162 - FieldList *fields = new (pool_) FieldList();
36.1163 -
36.1164 - while (!peek(TOK_RBRACE)) {
36.1165 - if (matchName(name.ref(), TOK_LABEL) && !name)
36.1166 - return NULL;
36.1167 -
36.1168 - BoundName *type = NULL;
36.1169 - if (name) {
36.1170 - if ((type = bindType(name)) == NULL)
36.1171 - return NULL;
36.1172 - }
36.1173 -
36.1174 - name = expectName();
36.1175 - if (!name)
36.1176 - return NULL;
36.1177 -
36.1178 - SourcePosition pos = scanner_.begin();
36.1179 -
36.1180 - ExpressionList *postDimensions = NULL;
36.1181 - if (peek(TOK_LBRACKET)) {
36.1182 - if ((postDimensions = dimensions()) == NULL)
36.1183 - return NULL;
36.1184 - }
36.1185 -
36.1186 - if (!matchSemicolon())
36.1187 - return NULL;
36.1188 -
36.1189 - StructureStatement::Field *field =
36.1190 - new (pool_) StructureStatement::Field(pos, type, name, postDimensions);
36.1191 - if (!field || !fields->append(field))
36.1192 - return NULL;
36.1193 - }
36.1194 -
36.1195 - if (!expect(TOK_RBRACE))
36.1196 - return NULL;
36.1197 -
36.1198 - if (fields->empty()) {
36.1199 - cc_.reportError(pos, Message_StructCantBeEmpty);
36.1200 - return NULL;
36.1201 - }
36.1202 -
36.1203 - return new (pool_) StructureStatement(pos, type, fields);
36.1204 -}
36.1205 -
36.1206 -Statement *
36.1207 -Parser::enum_()
36.1208 -{
36.1209 - expect(TOK_ENUM);
36.1210 -
36.1211 - NamedType *type = NULL;
36.1212 - SourcePosition pos = scanner_.begin();
36.1213 -
36.1214 - Local<String> name(zone_);
36.1215 - if (matchName(name.ref())) {
36.1216 - if (!name)
36.1217 - return NULL;
36.1218 -
36.1219 - if (BoundName *other = scope_->localLookup(name)) {
36.1220 - redeclarationError(other);
36.1221 - return NULL;
36.1222 - }
36.1223 -
36.1224 - if ((type = scope_->declareType(name, scanner_.begin())) == NULL)
36.1225 - return NULL;
36.1226 - }
36.1227 -
36.1228 - EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList();
36.1229 -
36.1230 - if (!expect(TOK_LBRACE))
36.1231 - return NULL;
36.1232 -
36.1233 - do {
36.1234 - if (scanner_.peek() == TOK_RBRACE)
36.1235 - break;
36.1236 -
36.1237 - Local<String> name(zone_, expectName());
36.1238 - if (!name)
36.1239 - return NULL;
36.1240 -
36.1241 - if (BoundName *other = scope_->localLookup(name)) {
36.1242 - redeclarationError(other);
36.1243 - return NULL;
36.1244 - }
36.1245 -
36.1246 - NamedConstant *constant = scope_->declareConstant(name, scanner_.begin());
36.1247 - if (!constant)
36.1248 - return NULL;
36.1249 -
36.1250 - Expression *expr = NULL;
36.1251 - if (match(TOK_ASSIGN)) {
36.1252 - if ((expr = expression()) == NULL)
36.1253 - return NULL;
36.1254 - }
36.1255 -
36.1256 - if (!entries->append(EnumStatement::Entry(constant, expr)))
36.1257 - return NULL;
36.1258 - } while (match(TOK_COMMA));
36.1259 - if (!expect(TOK_RBRACE))
36.1260 - return NULL;
36.1261 -
36.1262 - return new (pool_) EnumStatement(pos, type, name, entries);
36.1263 -}
36.1264 -
36.1265 -Statement *
36.1266 -Parser::function(TokenKind token)
36.1267 -{
36.1268 - Local<String> returnTag(zone_);
36.1269 - if (token == TOK_LABEL) {
36.1270 - returnTag = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
36.1271 - if (!returnTag)
36.1272 - return NULL;
36.1273 -
36.1274 - token = TOK_STOCK;
36.1275 - } else {
36.1276 - if (peek(TOK_LABEL)) {
36.1277 - if (matchName(returnTag.ref(), TOK_LABEL) && !returnTag)
36.1278 - return NULL;
36.1279 - } else if (peek(TOK_NAME)) {
36.1280 - // Peek for a type that has no :
36.1281 - returnTag = expectName();
36.1282 - if (!returnTag)
36.1283 - return NULL;
36.1284 - }
36.1285 - }
36.1286 -
36.1287 - Local<String> name(zone_);
36.1288 - ExpressionList *returnDimensions = NULL;
36.1289 -
36.1290 - bool allowArrayReturns = token != TOK_NATIVE &&
36.1291 - token != TOK_PUBLIC &&
36.1292 - token != TOK_FORWARD;
36.1293 -
36.1294 - if (allowArrayReturns && peek(TOK_LBRACKET)) {
36.1295 - if ((returnDimensions = dimensions()) == NULL)
36.1296 - return NULL;
36.1297 - if ((name = expectName()) == NULL)
36.1298 - return NULL;
36.1299 - } else if (peek(TOK_NAME)) {
36.1300 - if ((name = expectName()) == NULL)
36.1301 - return NULL;
36.1302 - } else {
36.1303 - // We predicted |type name|, but just got |name| instead.
36.1304 - name = returnTag;
36.1305 - returnTag = NULL;
36.1306 - }
36.1307 -
36.1308 - BoundName *returnType = NULL;
36.1309 - if (returnTag)
36.1310 - returnType = bindType(returnTag);
36.1311 -
36.1312 - SourcePosition pos = scanner_.begin();
36.1313 -
36.1314 - // The function name goes into the outer (global) scope.
36.1315 - assert(!scope_->enclosing());
36.1316 -
36.1317 - NamedType *type = NULL;
36.1318 - NamedFunction *fun = NULL;
36.1319 - if (BoundName *other = scope_->localLookup(name)) {
36.1320 - // We allow a redeclaration if the new type is a public, and the old
36.1321 - // type was a forward. However, the forward must come first.
36.1322 - if (token == TOK_TYPEDEF || other->kind() != BoundName::FUNCTION) {
36.1323 - redeclarationError(other);
36.1324 - return NULL;
36.1325 - }
36.1326 -
36.1327 - fun = other->toNamedFunction();
36.1328 - if (!fun->isForward() || token != TOK_PUBLIC) {
36.1329 - redeclarationError(other);
36.1330 - return NULL;
36.1331 - }
36.1332 -
36.1333 - // We've got the same name, but the original is a forward, so let it
36.1334 - // slide and re-use the original declaration.
36.1335 - fun->setImplemented(scanner_.begin());
36.1336 - } else if (token == TOK_TYPEDEF) {
36.1337 - type = scope_->declareType(name, scanner_.begin());
36.1338 - if (!type)
36.1339 - return NULL;
36.1340 - } else {
36.1341 - fun = scope_->declareFunction(name, scanner_.begin(), token);
36.1342 - if (!fun)
36.1343 - return NULL;
36.1344 - }
36.1345 -
36.1346 - if (fun && fun->isPublic())
36.1347 - fun->setUsed();
36.1348 -
36.1349 - Scope *scope = enterScope(Scope::FUNCTION);
36.1350 - if (!scope)
36.1351 - return NULL;
36.1352 -
36.1353 - ParameterList *parameters = new (pool_) ParameterList();
36.1354 -
36.1355 - if (!expect(TOK_LPAREN))
36.1356 - return NULL;
36.1357 -
36.1358 - if (!match(TOK_RPAREN)) {
36.1359 - while (true) {
36.1360 - bool isConst = match(TOK_CONST);
36.1361 - bool ref = match(TOK_AMPERSAND);
36.1362 -
36.1363 - SourcePosition begin = scanner_.begin();
36.1364 - Local<String> tag(zone_);
36.1365 - if (matchName(tag.ref(), TOK_LABEL) && !tag)
36.1366 - return NULL;
36.1367 -
36.1368 - BoundName *type = NULL;
36.1369 - if (tag)
36.1370 - type = bindType(tag);
36.1371 -
36.1372 - if (match(TOK_ELLIPSES)) {
36.1373 - if (isConst || ref) {
36.1374 - cc_.reportError(begin, Message_InvalidVarArgs);
36.1375 - return NULL;
36.1376 - }
36.1377 -
36.1378 - if (token != TOK_NATIVE) {
36.1379 - cc_.reportError(begin, Message_VarArgsOutsideNative);
36.1380 - return NULL;
36.1381 - }
36.1382 -
36.1383 - fun->markNativeVariadic();
36.1384 - break;
36.1385 - }
36.1386 -
36.1387 - Local<String> name(zone_, expectName());
36.1388 - if (!name)
36.1389 - return NULL;
36.1390 -
36.1391 - if (BoundName *other = scope_->localLookup(name)) {
36.1392 - redeclarationError(other);
36.1393 - return NULL;
36.1394 - }
36.1395 - Variable *arg = scope_->declareArgument(name, scanner_.begin());
36.1396 - if (!arg)
36.1397 - return NULL;
36.1398 -
36.1399 - // Look for dimensions.
36.1400 - ExpressionList *postDimensions = NULL;
36.1401 - if (peek(TOK_LBRACKET)) {
36.1402 - if ((postDimensions = dimensions()) == NULL)
36.1403 - return NULL;
36.1404 - }
36.1405 -
36.1406 - Expression *expr = NULL;
36.1407 - if (match(TOK_ASSIGN)) {
36.1408 - if ((expr = expression()) == NULL)
36.1409 - return NULL;
36.1410 - }
36.1411 -
36.1412 - Parameter *parameter = new (pool_) Parameter(arg, type, ref, isConst, postDimensions,
36.1413 - expr);
36.1414 - if (!parameters->append(parameter))
36.1415 - return NULL;
36.1416 -
36.1417 - if (!match(TOK_COMMA))
36.1418 - break;
36.1419 - }
36.1420 - if (!expect(TOK_RPAREN))
36.1421 - return NULL;
36.1422 - }
36.1423 -
36.1424 - encounteredReturn_ = false;
36.1425 -
36.1426 - Statement *body = NULL;
36.1427 - if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) {
36.1428 - body = block();
36.1429 - if (!body)
36.1430 - return NULL;
36.1431 - }
36.1432 -
36.1433 - scope_ = scope_->enclosing();
36.1434 -
36.1435 - FunctionSignature signature(returnType, returnDimensions, parameters);
36.1436 - if (token == TOK_TYPEDEF)
36.1437 - return new (pool_) FunctionTypeStatement(pos, type, signature);
36.1438 -
36.1439 - return new (pool_) FunctionStatement(pos, scope, fun, body, signature, encounteredReturn_);
36.1440 -}
36.1441 -
36.1442 -static inline bool
36.1443 -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle<Type> type)
36.1444 -{
36.1445 - Local<String> tag(zone, zone->makeSymbol(name));
36.1446 - if (!tag)
36.1447 - return false;
36.1448 -
36.1449 - return !!scope->declareType(tag, type);
36.1450 -}
36.1451 -
36.1452 -static inline bool
36.1453 -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type)
36.1454 -{
36.1455 - Local<Type> primitive(zone, zone->types()->getPrimitive(type));
36.1456 - assert(primitive);
36.1457 - return DeclareIntrinsicType(zone, scope, name, primitive);
36.1458 -}
36.1459 -
36.1460 -bool
36.1461 -Parser::setupIntrinsics()
36.1462 -{
36.1463 - if (!DeclareIntrinsicType(zone_, scope_, "Float", PrimitiveType_Float))
36.1464 - return false;
36.1465 - if (!DeclareIntrinsicType(zone_, scope_, "_", PrimitiveType_Int32))
36.1466 - return false;
36.1467 - if (!DeclareIntrinsicType(zone_, scope_, "bool", PrimitiveType_Bool))
36.1468 - return false;
36.1469 - if (!DeclareIntrinsicType(zone_, scope_, "String", PrimitiveType_Char))
36.1470 - return false;
36.1471 -
36.1472 - Local<Type> unchecked(zone_, zone_->types()->getUnchecked());
36.1473 - if (!DeclareIntrinsicType(zone_, scope_, "unchecked", unchecked))
36.1474 - return false;
36.1475 -
36.1476 - Local<Type> voidType(zone_, zone_->types()->getVoid());
36.1477 - if (!DeclareIntrinsicType(zone_, scope_, "void", voidType))
36.1478 - return false;
36.1479 -
36.1480 - Local<Type> intType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
36.1481 - if (!DeclareIntrinsicType(zone_, scope_, "int", intType))
36.1482 - return false;
36.1483 -
36.1484 - return true;
36.1485 -}
36.1486 -
36.1487 -ParseTree *
36.1488 -Parser::parse()
36.1489 -{
36.1490 - StatementList *statements = new (pool_) StatementList();
36.1491 -
36.1492 - if (!enterScope(Scope::GLOBAL))
36.1493 - return NULL;
36.1494 -
36.1495 - if (!setupIntrinsics())
36.1496 - return NULL;
36.1497 -
36.1498 - for (;;) {
36.1499 - Statement *statement = NULL;
36.1500 -
36.1501 - TokenKind kind = scanner_.peek();
36.1502 - switch (kind) {
36.1503 - case TOK_ERROR:
36.1504 - return NULL;
36.1505 -
36.1506 - case TOK_EOF:
36.1507 - break;
36.1508 -
36.1509 - case TOK_NAME:
36.1510 - if ((statement = function(TOK_NAME)) == NULL)
36.1511 - return NULL;
36.1512 - break;
36.1513 -
36.1514 - case TOK_FORWARD:
36.1515 - case TOK_PUBLIC:
36.1516 - case TOK_NATIVE:
36.1517 - case TOK_STOCK:
36.1518 - case TOK_LABEL:
36.1519 - case TOK_TYPEDEF:
36.1520 - {
36.1521 - scanner_.scan();
36.1522 - if (kind == TOK_PUBLIC && peek(TOK_CONST)) {
36.1523 - if ((statement = var(TOK_PUBLIC, scanner_.scan())) == NULL)
36.1524 - return NULL;
36.1525 - if (!matchSemicolon())
36.1526 - return NULL;
36.1527 - } else {
36.1528 - if ((statement = function(kind)) == NULL)
36.1529 - return NULL;
36.1530 - if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon())
36.1531 - return NULL;
36.1532 - }
36.1533 - break;
36.1534 - }
36.1535 -
36.1536 - case TOK_CONST:
36.1537 - case TOK_NEW:
36.1538 - {
36.1539 - // Note: at global scope, we don't accept comma-delimited
36.1540 - // declarations yet, to see if we can get away with forcing
36.1541 - // a nicer top-level style.
36.1542 - scanner_.scan();
36.1543 - if ((statement = var(TOK_STOCK, kind)) == NULL)
36.1544 - return NULL;
36.1545 - if (!matchSemicolon())
36.1546 - return NULL;
36.1547 - break;
36.1548 - }
36.1549 -
36.1550 - case TOK_ENUM:
36.1551 - if ((statement = enum_()) == NULL)
36.1552 - return NULL;
36.1553 - if (!matchSemicolon())
36.1554 - return NULL;
36.1555 - break;
36.1556 -
36.1557 - case TOK_STRUCT:
36.1558 - if ((statement = struct_()) == NULL)
36.1559 - return NULL;
36.1560 - if (!matchSemicolon())
36.1561 - return NULL;
36.1562 - break;
36.1563 -
36.1564 - default:
36.1565 - cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
36.1566 - return NULL;
36.1567 - }
36.1568 -
36.1569 - if (!statement)
36.1570 - break;
36.1571 -
36.1572 - if (!statements->append(statement))
36.1573 - return NULL;
36.1574 - }
36.1575 -
36.1576 - return new (pool_) ParseTree(scope_, statements, unbound_);
36.1577 -}
36.1578 -
36.1579 -class AstPrinter : public AstVisitor
36.1580 -{
36.1581 - FILE *fp_;
36.1582 - size_t level_;
36.1583 -
36.1584 - private:
36.1585 - void prefix() {
36.1586 - for (size_t i = 0; i < level_; i++)
36.1587 - fprintf(fp_, " ");
36.1588 - }
36.1589 - void indent() {
36.1590 - level_++;
36.1591 - }
36.1592 - void unindent() {
36.1593 - level_--;
36.1594 - }
36.1595 -
36.1596 - public:
36.1597 - AstPrinter(FILE *fp)
36.1598 - : fp_(fp),
36.1599 - level_(0)
36.1600 - {
36.1601 - }
36.1602 -
36.1603 - void dump(const FunctionSignature &sig) {
36.1604 - prefix();
36.1605 - fprintf(fp_, "%s", sig.returnType()
36.1606 - ? sig.returnType()->name()->chars()
36.1607 - : "_");
36.1608 - if (sig.returnDimensions()) {
36.1609 - for (size_t i = 0; i < sig.returnDimensions()->length(); i++)
36.1610 - fprintf(fp_, "[]");
36.1611 - }
36.1612 - fprintf(fp_, "()\n");
36.1613 - }
36.1614 - void visit(NameProxy *name) {
36.1615 - prefix();
36.1616 - fprintf(fp_, "[ NameProxy (%s)%s\n", name->name()->chars(),
36.1617 - (name->binding() ? "" : " unbound"));
36.1618 - }
36.1619 - void visit(CallExpression *node) {
36.1620 - prefix();
36.1621 - fprintf(fp_, "[ CallExpression\n");
36.1622 - indent();
36.1623 - node->callee()->accept(this);
36.1624 - for (size_t i = 0; i < node->arguments()->length(); i++)
36.1625 - node->arguments()->at(i)->accept(this);
36.1626 - unindent();
36.1627 - }
36.1628 - void visit(FunctionTypeStatement *node) {
36.1629 - prefix();
36.1630 - fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->decl()->name()->chars());
36.1631 - indent();
36.1632 - dump(node->signature());
36.1633 - unindent();
36.1634 - }
36.1635 - void visit(FunctionStatement *node) {
36.1636 - prefix();
36.1637 - fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars());
36.1638 - indent();
36.1639 - dump(node->signature());
36.1640 - if (node->body())
36.1641 - node->body()->accept(this);
36.1642 - unindent();
36.1643 - }
36.1644 - void visit(ExpressionStatement *node) {
36.1645 - prefix();
36.1646 - fprintf(fp_, "[ ExpressionStatement\n");
36.1647 - indent();
36.1648 - node->expression()->accept(this);
36.1649 - unindent();
36.1650 - }
36.1651 - void visit(Assignment *node) {
36.1652 - prefix();
36.1653 - fprintf(fp_, "[ Assignment\n");
36.1654 - indent();
36.1655 - node->lvalue()->accept(this);
36.1656 - node->expression()->accept(this);
36.1657 - unindent();
36.1658 - }
36.1659 - void visit(TernaryExpression *node) {
36.1660 - prefix();
36.1661 - fprintf(fp_, "[ TernaryExpression\n");
36.1662 - indent();
36.1663 - node->condition()->accept(this);
36.1664 - node->left()->accept(this);
36.1665 - node->right()->accept(this);
36.1666 - unindent();
36.1667 - }
36.1668 - void visit(BinaryExpression *node) {
36.1669 - prefix();
36.1670 - fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]);
36.1671 - indent();
36.1672 - node->left()->accept(this);
36.1673 - node->right()->accept(this);
36.1674 - unindent();
36.1675 - }
36.1676 - void visit(UnaryExpression *node) {
36.1677 - prefix();
36.1678 - fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]);
36.1679 - indent();
36.1680 - node->expression()->accept(this);
36.1681 - unindent();
36.1682 - }
36.1683 - void visit(ReturnStatement *node) {
36.1684 - prefix();
36.1685 - fprintf(fp_, "[ ReturnStatement\n");
36.1686 - indent();
36.1687 - if (node->expression())
36.1688 - node->expression()->accept(this);
36.1689 - unindent();
36.1690 - }
36.1691 - void visit(ForStatement *node) {
36.1692 - prefix();
36.1693 - fprintf(fp_, "[ ForStatement\n");
36.1694 - indent();
36.1695 - if (node->initialization())
36.1696 - node->initialization()->accept(this);
36.1697 - if (node->condition())
36.1698 - node->condition()->accept(this);
36.1699 - if (node->update())
36.1700 - node->update()->accept(this);
36.1701 - node->body()->accept(this);
36.1702 - unindent();
36.1703 - }
36.1704 - void visit(BlockStatement *node) {
36.1705 - prefix();
36.1706 - fprintf(fp_, "[ BlockStatement\n");
36.1707 - indent();
36.1708 - for (size_t i = 0; i < node->statements()->length(); i++)
36.1709 - node->statements()->at(i)->accept(this);
36.1710 - unindent();
36.1711 - }
36.1712 - void visit(VariableDeclaration *node) {
36.1713 - prefix();
36.1714 - fprintf(fp_, "[ VariableDeclaration (%s)\n", node->variable()->name()->chars());
36.1715 - indent();
36.1716 - if (node->initialization())
36.1717 - node->initialization()->accept(this);
36.1718 - unindent();
36.1719 - }
36.1720 - void visit(IntegerLiteral *node) {
36.1721 - prefix();
36.1722 - fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
36.1723 - }
36.1724 - void visit(BooleanLiteral *node) {
36.1725 - prefix();
36.1726 - fprintf(fp_, "[ BooleanLiteral (%s)\n",
36.1727 - (node->token() == TOK_TRUE) ? "true" : "false");
36.1728 - }
36.1729 - void visit(FloatLiteral *node) {
36.1730 - prefix();
36.1731 - fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
36.1732 - }
36.1733 - void visit(IfStatement *node) {
36.1734 - prefix();
36.1735 - fprintf(fp_, "[ IfStatement\n");
36.1736 - indent();
36.1737 - node->ifTrue()->accept(this);
36.1738 - if (node->ifFalse())
36.1739 - node->ifFalse()->accept(this);
36.1740 - unindent();
36.1741 - }
36.1742 - void visit(IndexExpression *node) {
36.1743 - prefix();
36.1744 - fprintf(fp_, "[ IndexExpression\n");
36.1745 - indent();
36.1746 - node->left()->accept(this);
36.1747 - node->right()->accept(this);
36.1748 - unindent();
36.1749 - }
36.1750 - void visit(EnumStatement *node) {
36.1751 - prefix();
36.1752 - fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : "<anonymous>");
36.1753 - indent();
36.1754 - for (size_t i = 0; i < node->entries()->length(); i++) {
36.1755 - prefix();
36.1756 - fprintf(fp_, "%s =\n", node->entries()->at(i).name->name()->chars());
36.1757 - if (node->entries()->at(i).expr) {
36.1758 - indent();
36.1759 - node->entries()->at(i).expr->accept(this);
36.1760 - unindent();
36.1761 - }
36.1762 - }
36.1763 - unindent();
36.1764 - }
36.1765 - void visit(WhileStatement *node) {
36.1766 - prefix();
36.1767 - fprintf(fp_, "[ WhileStatement (%s)\n",
36.1768 - (node->token() == TOK_DO) ? "do" : "while");
36.1769 - indent();
36.1770 - if (node->token() == TOK_DO) {
36.1771 - node->condition()->accept(this);
36.1772 - node->body()->accept(this);
36.1773 - } else {
36.1774 - node->condition()->accept(this);
36.1775 - node->body()->accept(this);
36.1776 - }
36.1777 - unindent();
36.1778 - }
36.1779 - void visit(BreakStatement *node) {
36.1780 - prefix();
36.1781 - fprintf(fp_, "[ BreakStatement\n");
36.1782 - }
36.1783 - void visit(ContinueStatement *node) {
36.1784 - prefix();
36.1785 - fprintf(fp_, "[ ContinueStatement\n");
36.1786 - }
36.1787 - void visit(StringLiteral *node) {
36.1788 - prefix();
36.1789 - fprintf(fp_, "[ StringLiteral\n");
36.1790 - }
36.1791 - void visit(IncDecExpression *node) {
36.1792 - prefix();
36.1793 - fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
36.1794 - indent();
36.1795 - node->expression()->accept(this);
36.1796 - unindent();
36.1797 - }
36.1798 - void visit(StructureStatement *node) {
36.1799 - prefix();
36.1800 - fprintf(fp_, "[ StructureStatement %s\n", node->decl()->name()->chars());
36.1801 - }
36.1802 - void visit(FieldExpression *node) {
36.1803 - prefix();
36.1804 - fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars());
36.1805 - indent();
36.1806 - node->left()->accept(this);
36.1807 - unindent();
36.1808 - }
36.1809 - void visit(SwitchStatement *node) {
36.1810 - prefix();
36.1811 - fprintf(fp_, "[ SwitchStatement\n");
36.1812 - indent();
36.1813 - node->expression()->accept(this);
36.1814 - for (size_t i = 0; i < node->cases()->length(); i++) {
36.1815 - Case *c = node->cases()->at(i);
36.1816 - c->expression()->accept(this);
36.1817 - if (c->others()) {
36.1818 - for (size_t j = 0; j < c->others()->length(); j++)
36.1819 - c->others()->at(j)->accept(this);
36.1820 - }
36.1821 - indent();
36.1822 - c->statement()->accept(this);
36.1823 - unindent();
36.1824 - }
36.1825 - if (node->defaultCase())
36.1826 - node->defaultCase()->accept(this);
36.1827 - unindent();
36.1828 - }
36.1829 - void visit(ArrayLiteral *node) {
36.1830 - prefix();
36.1831 - fprintf(fp_, "[ ArrayLiteral\n");
36.1832 - indent();
36.1833 - for (size_t i = 0; i < node->expressions()->length(); i++) {
36.1834 - Expression *expr = node->expressions()->at(i);
36.1835 - indent();
36.1836 - expr->accept(this);
36.1837 - unindent();
36.1838 - }
36.1839 - }
36.1840 -};
36.1841 -
36.1842 -void
36.1843 -ParseTree::dump(FILE *fp)
36.1844 -{
36.1845 - AstPrinter printer(fp);
36.1846 -
36.1847 - for (size_t i = 0; i < statements_->length(); i++)
36.1848 - statements_->at(i)->accept(&printer);
36.1849 -}
37.1 --- a/src/Parser.h Mon Sep 17 00:10:01 2012 -0700
37.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
37.3 @@ -1,106 +0,0 @@
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 SourcePawn.
37.9 - *
37.10 - * SourcePawn 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 - * SourcePawn 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 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
37.21 - */
37.22 -#ifndef _include_jitcraft_parser_h_
37.23 -#define _include_jitcraft_parser_h_
37.24 -
37.25 -#include <stdio.h>
37.26 -#include "AST.h"
37.27 -#include "Scanner.h"
37.28 -#include "Scopes.h"
37.29 -#include "Strings.h"
37.30 -
37.31 -namespace ke {
37.32 -
37.33 -class Parser
37.34 -{
37.35 - Zone *zone_;
37.36 - CompileContext &cc_;
37.37 - PoolAllocator &pool_;
37.38 - Scanner scanner_;
37.39 - Scope *scope_;
37.40 - PoolList<NameProxy *> *unbound_;
37.41 - bool encounteredReturn_;
37.42 -
37.43 - private:
37.44 - void redeclarationError(BoundName *name);
37.45 - bool peek(TokenKind kind);
37.46 - bool match(TokenKind kind);
37.47 - bool expect(TokenKind kind);
37.48 - bool matchSemicolon();
37.49 -
37.50 - Scope *enterScope(Scope::Kind kind);
37.51 -
37.52 -
37.53 - VariableDeclaration *var(TokenKind scope, TokenKind kind);
37.54 - Statement *vars(TokenKind scope, TokenKind kind);
37.55 - bool matchName(String **name, TokenKind kind = TOK_NAME);
37.56 -
37.57 - NameProxy *bind(Handle<String> name);
37.58 - BoundName *bindType(Handle<String> string);
37.59 -
37.60 - ExpressionList *dimensions();
37.61 - String *expectName();
37.62 -
37.63 - Expression *primitive();
37.64 - Expression *arrayLiteral(TokenKind kind);
37.65 - Expression *call(Expression *callee);
37.66 - Expression *field(Expression *left);
37.67 - Expression *index(Expression *left);
37.68 - Expression *prefix();
37.69 - Expression *primary();
37.70 - Expression *unary();
37.71 - Expression *multiplication();
37.72 - Expression *addition();
37.73 - Expression *shift();
37.74 - Expression *bitand_();
37.75 - Expression *bitxor();
37.76 - Expression *bitor_();
37.77 - Expression *relational();
37.78 - Expression *equals();
37.79 - Expression *and_();
37.80 - Expression *or_();
37.81 - Expression *ternary();
37.82 - Expression *assignment();
37.83 - Expression *expression();
37.84 -
37.85 - Statement *switch_();
37.86 - Statement *struct_();
37.87 - Statement *enum_();
37.88 - Statement *if_();
37.89 - Statement *block(Scope *scope = NULL);
37.90 - Statement *function(TokenKind tok);
37.91 - Statement *expressionStatement();
37.92 - Statement *while_();
37.93 - Statement *do_();
37.94 - Statement *forStatement();
37.95 - Statement *localStatement();
37.96 - Statement *globalStatement();
37.97 - Statement *returnStatement();
37.98 -
37.99 - bool setupIntrinsics();
37.100 -
37.101 - public:
37.102 - Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
37.103 -
37.104 - ParseTree *parse();
37.105 -};
37.106 -
37.107 -}
37.108 -
37.109 -#endif // _include_jitcraft_parser_h_
38.1 --- a/src/PoolAllocator.cpp Mon Sep 17 00:10:01 2012 -0700
38.2 +++ b/src/PoolAllocator.cpp Sat Nov 17 18:41:01 2012 -0800
38.3 @@ -122,7 +122,7 @@
38.4 void *
38.5 PoolAllocationPolicy::malloc(size_t bytes)
38.6 {
38.7 - return ZONE()->pool().allocate(bytes);
38.8 + return ZONE()->pool().rawAllocate(bytes);
38.9 }
38.10
38.11 void
39.1 --- a/src/PoolAllocator.h Mon Sep 17 00:10:01 2012 -0700
39.2 +++ b/src/PoolAllocator.h Sat Nov 17 18:41:01 2012 -0800
39.3 @@ -58,7 +58,7 @@
39.4 PoolAllocator();
39.5 ~PoolAllocator();
39.6
39.7 - void *allocate(size_t bytes) {
39.8 + void *rawAllocate(size_t bytes) {
39.9 // Guarantee malloc alignment.
39.10 size_t actualBytes = Align(bytes, kMallocAlignment);
39.11 if (!last_ || (size_t(last_->end - last_->ptr) < actualBytes))
39.12 @@ -68,6 +68,15 @@
39.13 return ptr;
39.14 }
39.15
39.16 + template <typename T>
39.17 + T *alloc(size_t count = 1) {
39.18 + void *ptr = rawAllocate(count * sizeof(T));
39.19 + if (!ptr)
39.20 + return NULL;
39.21 +
39.22 + return reinterpret_cast<T *>(ptr);
39.23 + }
39.24 +
39.25 char *enter();
39.26 void leave(char *position);
39.27 };
39.28 @@ -93,10 +102,10 @@
39.29 {
39.30 public:
39.31 void *operator new(size_t size, PoolAllocator &pool) {
39.32 - return pool.allocate(size);
39.33 + return pool.rawAllocate(size);
39.34 }
39.35 void *operator new [](size_t size, PoolAllocator &pool) {
39.36 - return pool.allocate(size);
39.37 + return pool.rawAllocate(size);
39.38 }
39.39
39.40 // Using delete on pool-allocated objects is illegal.
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/src/QualType.h Sat Nov 17 18:41:01 2012 -0800
40.3 @@ -0,0 +1,51 @@
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_sp2_qualtype_h_
40.23 +#define _include_sp2_qualtype_h_
40.24 +
40.25 +#include "Objects.h"
40.26 +
40.27 +namespace ke {
40.28 +
40.29 +class Type;
40.30 +
40.31 +enum TypeQualifiers
40.32 +{
40.33 + Qual_None = 0,
40.34 + Qual_Const = (1 << 0),
40.35 + Qual_Public = (1 << 1),
40.36 + Total_Qualifiers
40.37 +};
40.38 +
40.39 +// A QualType is a fully-qualified type in the SP2 type system.
40.40 +class QualType : public Object
40.41 +{
40.42 + public:
40.43 +
40.44 +
40.45 + private:
40.46 + union {
40.47 + Type *type_;
40.48 + uintptr_t flags_;
40.49 + };
40.50 +};
40.51 +
40.52 +}
40.53 +
40.54 +#endif // _include_sp2_qualtype_h_
41.1 --- a/src/Reference.cpp Mon Sep 17 00:10:01 2012 -0700
41.2 +++ b/src/Reference.cpp Sat Nov 17 18:41:01 2012 -0800
41.3 @@ -49,16 +49,3 @@
41.4 return ref;
41.5 }
41.6
41.7 -Reference *
41.8 -Reference::NewField(Zone *zone, Handle<Struct> obj, size_t index, Heap::Tenure tenure)
41.9 -{
41.10 - Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
41.11 - if (!ref)
41.12 - return NULL;
41.13 -
41.14 - Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
41.15 - ref->location_ = obj->ref(desc);
41.16 - ref->base_ = obj;
41.17 - return ref;
41.18 -}
41.19 -
42.1 --- a/src/Reference.h Mon Sep 17 00:10:01 2012 -0700
42.2 +++ b/src/Reference.h Sat Nov 17 18:41:01 2012 -0800
42.3 @@ -40,7 +40,6 @@
42.4 public:
42.5 static Reference *NewStack(Zone *zone, void *location, Heap::Tenure tenure = Heap::Tenure_Default);
42.6 static Reference *NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure = Heap::Tenure_Default);
42.7 - static Reference *NewField(Zone *zone, Handle<Struct> obj, size_t index, Heap::Tenure tenure = Heap::Tenure_Default);
42.8
42.9 int getInt() {
42.10 return *reinterpret_cast<int *>(location_);
43.1 --- a/src/Scanner.cpp Mon Sep 17 00:10:01 2012 -0700
43.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
43.3 @@ -1,679 +0,0 @@
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 JITCraft.
43.9 - *
43.10 - * JITCraft 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 - * Foobar 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 - * JITCraft. If not, see http://www.gnu.org/licenses/.
43.21 - */
43.22 -#include <assert.h>
43.23 -#include <ctype.h>
43.24 -#include <math.h>
43.25 -#include <limits.h>
43.26 -#include <string.h>
43.27 -#include "Scanner.h"
43.28 -#include "Utility.h"
43.29 -
43.30 -using namespace ke;
43.31 -
43.32 -const char *ke::TokenNames[] =
43.33 -{
43.34 -#define _(name, str) str,
43.35 - TOKENMAP(_)
43.36 -#undef _
43.37 - NULL
43.38 -};
43.39 -
43.40 -Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
43.41 - : cc_(cc),
43.42 - stream_(stream),
43.43 - length_(length),
43.44 - pushed_(false),
43.45 - allowTags_(true),
43.46 - saved_('\0'),
43.47 - pos_(stream_)
43.48 -{
43.49 - cur_.line = 1;
43.50 - cur_.col = 1;
43.51 - last_ = cur_;
43.52 -}
43.53 -
43.54 -char
43.55 -Scanner::getChar()
43.56 -{
43.57 - if (saved_ != '\0') {
43.58 - char temp = saved_;
43.59 - saved_ = '\0';
43.60 - return temp;
43.61 - }
43.62 - if (pos_ >= stream_ + length_)
43.63 - return '\0';
43.64 - last_.col = cur_.col++;
43.65 - return *pos_++;
43.66 -}
43.67 -
43.68 -void
43.69 -Scanner::putChar(char c)
43.70 -{
43.71 - assert(saved_ == '\0');
43.72 - saved_ = c;
43.73 - cur_.col = last_.col;
43.74 -}
43.75 -
43.76 -void
43.77 -Scanner::calcNewLine(char c)
43.78 -{
43.79 - cur_.line++;
43.80 - cur_.col = 1;
43.81 - last_ = cur_;
43.82 -
43.83 - char o;
43.84 - if (c == '\r' && ((o = getChar()) != '\n'))
43.85 - putChar(o);
43.86 -}
43.87 -
43.88 -void
43.89 -Scanner::eatSingleLine()
43.90 -{
43.91 - char c;
43.92 - while ((c = getChar()) != '\0') {
43.93 - if (c == '\n' || c == '\r') {
43.94 - calcNewLine(c);
43.95 - break;
43.96 - }
43.97 - }
43.98 -}
43.99 -
43.100 -bool
43.101 -Scanner::eatComment()
43.102 -{
43.103 - char c;
43.104 -
43.105 - while ((c = getChar()) != '\0') {
43.106 - while (c == '*') {
43.107 - c = getChar();
43.108 - if (c == '\0')
43.109 - return false;
43.110 - if (c == '/')
43.111 - return true;
43.112 - }
43.113 - if (c == '\r' || c == '\n')
43.114 - calcNewLine(c);
43.115 - }
43.116 -
43.117 - return false;
43.118 -}
43.119 -
43.120 -static inline bool
43.121 -IsDigit(char c)
43.122 -{
43.123 - return c >= '0' && c <= '9';
43.124 -}
43.125 -
43.126 -// Based off the logic in sc2.c's ftoi()...
43.127 -double
43.128 -Scanner::ParseDouble(const char *string)
43.129 -{
43.130 - const char *ptr = string;
43.131 -
43.132 - double number = 0.0;
43.133 - while (IsDigit(*ptr)) {
43.134 - number = (number * 10) + (*ptr - '0');
43.135 - ptr++;
43.136 - }
43.137 -
43.138 - assert(*ptr == '.');
43.139 - ptr++;
43.140 -
43.141 - double fraction = 0.0;
43.142 - double multiplier = 1.0;
43.143 - while (IsDigit(*ptr)) {
43.144 - fraction = (fraction * 10) + (*ptr - '0');
43.145 - multiplier = multiplier / 10.0;
43.146 - ptr++;
43.147 - }
43.148 -
43.149 - number += fraction * multiplier;
43.150 -
43.151 - if (*ptr++ == 'e') {
43.152 - int sign = 1;
43.153 - if (*ptr == '-') {
43.154 - sign = -1;
43.155 - ptr++;
43.156 - }
43.157 -
43.158 - int exponent = 0;
43.159 - while (IsDigit(*ptr)) {
43.160 - exponent = (exponent * 10) + (*ptr - '0');
43.161 - ptr++;
43.162 - }
43.163 -
43.164 - multiplier = pow(10.0, exponent * sign);
43.165 - number *= multiplier;
43.166 - }
43.167 -
43.168 - return number;
43.169 -}
43.170 -
43.171 -static inline bool
43.172 -IsHexDigit(char c)
43.173 -{
43.174 - return IsDigit(c) ||
43.175 - (c >= 'a' && c <= 'f') ||
43.176 - (c >= 'A' && c <= 'F');
43.177 -}
43.178 -
43.179 -// Based on the logic for litchar() in sc2.c.
43.180 -int
43.181 -Scanner::readEscapeCode()
43.182 -{
43.183 - char c = getChar();
43.184 - if (c == '\\')
43.185 - return c;
43.186 -
43.187 - switch (c) {
43.188 - case 'a':
43.189 - return '\a';
43.190 - case 'b':
43.191 - return '\b';
43.192 - case 'e':
43.193 - return 27; // Apparently \e is non-standard.
43.194 - case 'f':
43.195 - return '\f';
43.196 - case 'n':
43.197 - return '\n';
43.198 - case 'r':
43.199 - return '\r';
43.200 - case 't':
43.201 - return '\t';
43.202 - case '\v':
43.203 - return '\v';
43.204 -
43.205 - case 'x':
43.206 - {
43.207 - unsigned digits = 0;
43.208 - char r = 0;
43.209 -
43.210 - c = getChar();
43.211 - while (IsHexDigit(c) && digits < 2) {
43.212 - if (IsDigit(c))
43.213 - c = (c << 4) + (c - '0');
43.214 - else
43.215 - c = (c << 4) + (tolower(c) - 'a' + 10);
43.216 - digits++;
43.217 - c = getChar();
43.218 - }
43.219 -
43.220 - // Swallow a trailing ';'
43.221 - if (c != ';')
43.222 - putChar(c);
43.223 -
43.224 - return r;
43.225 - }
43.226 -
43.227 - case '\'':
43.228 - case '\"':
43.229 - case '%':
43.230 - return c;
43.231 -
43.232 - default:
43.233 - {
43.234 - if (IsDigit(c)) {
43.235 - // \ddd
43.236 - char r = 0;
43.237 - while (IsDigit(c)) {
43.238 - r = r * 10 + (c - '0');
43.239 - c = getChar();
43.240 - }
43.241 -
43.242 - // Swallow a trailing ;
43.243 - if (c != ';')
43.244 - putChar(c);
43.245 -
43.246 - return r;
43.247 - }
43.248 - cc_.reportError(begin(), Message_UnknownEscapeCode, c);
43.249 - return INT_MAX;
43.250 - }
43.251 - }
43.252 -}
43.253 -
43.254 -TokenKind
43.255 -Scanner::stringLiteral()
43.256 -{
43.257 - literal_.clear();
43.258 -
43.259 - for (;;) {
43.260 - char c = getChar();
43.261 - if (c == '\"')
43.262 - break;
43.263 - if (c == '\r' || c == '\n' || c == '\0') {
43.264 - cc_.reportError(begin(), Message_UnterminatedString);
43.265 - return TOK_ERROR;
43.266 - }
43.267 - if (c == '\\') {
43.268 - int code = readEscapeCode();
43.269 - if (code == INT_MAX)
43.270 - return TOK_ERROR;
43.271 - c = char(code);
43.272 - }
43.273 - if (!literal_.append(c))
43.274 - return TOK_ERROR;
43.275 - }
43.276 -
43.277 - if (!literal_.append('\0'))
43.278 - return TOK_ERROR;
43.279 -
43.280 - return TOK_STRING_LITERAL;
43.281 -}
43.282 -
43.283 -TokenKind
43.284 -Scanner::hexLiteral()
43.285 -{
43.286 - literal_.clear();
43.287 -
43.288 - char c;
43.289 - for (;;) {
43.290 - c = getChar();
43.291 - if (!IsHexDigit(c))
43.292 - break;
43.293 - if (!literal_.append(c))
43.294 - return TOK_ERROR;
43.295 - }
43.296 -
43.297 - putChar(c);
43.298 -
43.299 - if (!literal_.append('\0'))
43.300 - return TOK_ERROR;
43.301 - return TOK_HEX_LITERAL;
43.302 -}
43.303 -
43.304 -TokenKind
43.305 -Scanner::numberLiteral(char first)
43.306 -{
43.307 - literal_.clear();
43.308 - if (!literal_.append(first))
43.309 - return TOK_ERROR;
43.310 -
43.311 - char c;
43.312 - for (;;) {
43.313 - c = getChar();
43.314 - if (!IsDigit(c))
43.315 - break;
43.316 - if (!literal_.append(c))
43.317 - return TOK_ERROR;
43.318 - }
43.319 -
43.320 - // Detect a hexadecimal string.
43.321 - if (literal_.length() == 1 &&
43.322 - literal_[0] == '0' &&
43.323 - (c == 'x' || c == 'X'))
43.324 - {
43.325 - return hexLiteral();
43.326 - }
43.327 -
43.328 - if (c != '.') {
43.329 - putChar(c);
43.330 - if (!literal_.append('\0'))
43.331 - return TOK_ERROR;
43.332 - return TOK_INTEGER_LITERAL;
43.333 - }
43.334 - if (!literal_.append(c))
43.335 - return TOK_ERROR;
43.336 -
43.337 - c = getChar();
43.338 - if (!IsDigit(c)) {
43.339 - cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
43.340 - return TOK_ERROR;
43.341 - }
43.342 - if (!literal_.append(c))
43.343 - return TOK_ERROR;
43.344 -
43.345 - for (;;) {
43.346 - c = getChar();
43.347 - if (!IsDigit(c))
43.348 - break;
43.349 - if (!literal_.append(c))
43.350 - return TOK_ERROR;
43.351 - }
43.352 -
43.353 - if (c != 'e') {
43.354 - putChar(c);
43.355 - } else {
43.356 - if (!literal_.append(c))
43.357 - return TOK_ERROR;
43.358 - c = getChar();
43.359 - if (c == '-') {
43.360 - if (!literal_.append(c))
43.361 - return TOK_ERROR;
43.362 - c = getChar();
43.363 - }
43.364 - if (!IsDigit(c)) {
43.365 - cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
43.366 - return TOK_ERROR;
43.367 - }
43.368 - if (!literal_.append(c))
43.369 - return TOK_ERROR;
43.370 - for (;;) {
43.371 - c = getChar();
43.372 - if (!IsDigit(c)) {
43.373 - putChar(c);
43.374 - break;
43.375 - }
43.376 - if (!literal_.append(c))
43.377 - return TOK_ERROR;
43.378 - }
43.379 - }
43.380 -
43.381 - if (!literal_.append('\0'))
43.382 - return TOK_ERROR;
43.383 -
43.384 - return TOK_FLOAT_LITERAL;
43.385 -}
43.386 -
43.387 -static inline TokenKind
43.388 -FindIdentifier(const char *str)
43.389 -{
43.390 - if (!strcmp(str, "new"))
43.391 - return TOK_NEW;
43.392 - if (!strcmp(str, "for"))
43.393 - return TOK_FOR;
43.394 - if (!strcmp(str, "return"))
43.395 - return TOK_RETURN;
43.396 - if (!strcmp(str, "if"))
43.397 - return TOK_IF;
43.398 - if (!strcmp(str, "else"))
43.399 - return TOK_ELSE;
43.400 - if (!strcmp(str, "enum"))
43.401 - return TOK_ENUM;
43.402 - if (!strcmp(str, "while"))
43.403 - return TOK_WHILE;
43.404 - if (!strcmp(str, "do"))
43.405 - return TOK_DO;
43.406 - if (!strcmp(str, "break"))
43.407 - return TOK_BREAK;
43.408 - if (!strcmp(str, "continue"))
43.409 - return TOK_CONTINUE;
43.410 - if (!strcmp(str, "forward"))
43.411 - return TOK_FORWARD;
43.412 - if (!strcmp(str, "public"))
43.413 - return TOK_PUBLIC;
43.414 - if (!strcmp(str, "const"))
43.415 - return TOK_CONST;
43.416 - if (!strcmp(str, "native"))
43.417 - return TOK_NATIVE;
43.418 - if (!strcmp(str, "stock"))
43.419 - return TOK_STOCK;
43.420 - if (!strcmp(str, "true"))
43.421 - return TOK_TRUE;
43.422 - if (!strcmp(str, "false"))
43.423 - return TOK_FALSE;
43.424 - if (!strcmp(str, "struct"))
43.425 - return TOK_STRUCT;
43.426 - if (!strcmp(str, "switch"))
43.427 - return TOK_SWITCH;
43.428 - if (!strcmp(str, "case"))
43.429 - return TOK_CASE;
43.430 - if (!strcmp(str, "default"))
43.431 - return TOK_DEFAULT;
43.432 - if (!strcmp(str, "typedef"))
43.433 - return TOK_TYPEDEF;
43.434 - if (!strcmp(str, "void"))
43.435 - return TOK_VOID;
43.436 - if (!strcmp(str, "int"))
43.437 - return TOK_INT;
43.438 - if (!strcmp(str, "sizeof"))
43.439 - return TOK_SIZEOF;
43.440 - return TOK_NONE;
43.441 -}
43.442 -
43.443 -TokenKind
43.444 -Scanner::identifier(char first)
43.445 -{
43.446 - literal_.clear();
43.447 - if (!literal_.append(first))
43.448 - return TOK_ERROR;
43.449 -
43.450 - char c;
43.451 - for (;;) {
43.452 - c = getChar();
43.453 - if (!isascii(c) || (!isalnum(c) && c != '_'))
43.454 - break;
43.455 - if (!literal_.append(c))
43.456 - return TOK_ERROR;
43.457 - }
43.458 -
43.459 - if (!literal_.append('\0'))
43.460 - return TOK_ERROR;
43.461 -
43.462 - // Most keywords do not act as labels.
43.463 - TokenKind kind = FindIdentifier(literal());
43.464 - if (kind != TOK_NONE) {
43.465 - putChar(c);
43.466 - return kind;
43.467 - }
43.468 -
43.469 - if (c == ':' && allowTags_)
43.470 - return TOK_LABEL;
43.471 -
43.472 - putChar(c);
43.473 -
43.474 - // _ is a special case which acts as a tag and a keyword.
43.475 - if (!strcmp(literal(), "_"))
43.476 - return TOK_UNDERSCORE;
43.477 -
43.478 - return TOK_NAME;
43.479 -}
43.480 -
43.481 -TokenKind
43.482 -Scanner::next()
43.483 -{
43.484 - assert(!pushed_);
43.485 -
43.486 - for (;;) {
43.487 - begin_ = cur_;
43.488 -
43.489 - char c = getChar();
43.490 - switch (c) {
43.491 - case '/':
43.492 - {
43.493 - c = getChar();
43.494 - if (c == '/') {
43.495 - eatSingleLine();
43.496 - break;
43.497 - }
43.498 - if (c == '*') {
43.499 - if (!eatComment()) {
43.500 - cc_.reportError(begin(), Message_UnterminatedComment);
43.501 - return TOK_ERROR;
43.502 - }
43.503 - break;
43.504 - }
43.505 - putChar(c);
43.506 - return TOK_SLASH;
43.507 - }
43.508 -
43.509 - case '\n':
43.510 - case '\r':
43.511 - calcNewLine(c);
43.512 - break;
43.513 -
43.514 - case ';': return TOK_SEMICOLON;
43.515 - case '{': return TOK_LBRACE;
43.516 - case '}': return TOK_RBRACE;
43.517 - case '(': return TOK_LPAREN;
43.518 - case ')': return TOK_RPAREN;
43.519 - case '[': return TOK_LBRACKET;
43.520 - case ']': return TOK_RBRACKET;
43.521 - case '~': return TOK_TILDE;
43.522 - case '?': return TOK_QMARK;
43.523 - case ':': return TOK_COLON;
43.524 -
43.525 - case '.':
43.526 - c = getChar();
43.527 - if (c == '.') {
43.528 - c = getChar();
43.529 - if (c == '.')
43.530 - return TOK_ELLIPSES;
43.531 - cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
43.532 - return TOK_ERROR;
43.533 - }
43.534 - putChar(c);
43.535 - return TOK_DOT;
43.536 -
43.537 - case '*':
43.538 - c = getChar();
43.539 - if (c == '=')
43.540 - return TOK_ASSIGN_MUL;
43.541 - putChar(c);
43.542 - return TOK_STAR;
43.543 -
43.544 - case '+':
43.545 - c = getChar();
43.546 - if (c == '=')
43.547 - return TOK_ASSIGN_ADD;
43.548 - if (c == '+')
43.549 - return TOK_INCREMENT;
43.550 - putChar(c);
43.551 - return TOK_PLUS;
43.552 -
43.553 - case '&':
43.554 - c = getChar();
43.555 - if (c == '=')
43.556 - return TOK_ASSIGN_BITAND;
43.557 - if (c == '&')
43.558 - return TOK_AND;
43.559 - putChar(c);
43.560 - return TOK_BITAND;
43.561 -
43.562 - case '|':
43.563 - c = getChar();
43.564 - if (c == '=')
43.565 - return TOK_ASSIGN_BITOR;
43.566 - if (c == '|')
43.567 - return TOK_OR;
43.568 - putChar(c);
43.569 - return TOK_BITOR;
43.570 -
43.571 - case '^':
43.572 - c = getChar();
43.573 - if (c == '=')
43.574 - return TOK_ASSIGN_BITXOR;
43.575 - putChar(c);
43.576 - return TOK_BITXOR;
43.577 -
43.578 - case '%':
43.579 - c = getChar();
43.580 - if (c == '=')
43.581 - return TOK_ASSIGN_MOD;
43.582 - putChar(c);
43.583 - return TOK_PERCENT;
43.584 -
43.585 - case '-':
43.586 - c = getChar();
43.587 - if (c == '=')
43.588 - return TOK_ASSIGN_SUB;
43.589 - if (c == '-')
43.590 - return TOK_DECREMENT;
43.591 - putChar(c);
43.592 - return TOK_MINUS;
43.593 -
43.594 - case ',': return TOK_COMMA;
43.595 - case '\0': return TOK_EOF;
43.596 -
43.597 - case '!':
43.598 - c = getChar();
43.599 - if (c == '=')
43.600 - return TOK_NOTEQUALS;
43.601 - putChar(c);
43.602 - return TOK_NOT;
43.603 -
43.604 - case '=':
43.605 - c = getChar();
43.606 - if (c == '=')
43.607 - return TOK_EQUALS;
43.608 - putChar(c);
43.609 - return TOK_ASSIGN;
43.610 -
43.611 -
43.612 - case '<':
43.613 - c = getChar();
43.614 - if (c == '=')
43.615 - return TOK_LE;
43.616 - if (c == '<') {
43.617 - c = getChar();
43.618 - if (c == '=')
43.619 - return TOK_ASSIGN_SHL;
43.620 - putChar(c);
43.621 - return TOK_SHL;
43.622 - }
43.623 - putChar(c);
43.624 - return TOK_LT;
43.625 -
43.626 - case '>':
43.627 - c = getChar();
43.628 - if (c == '=')
43.629 - return TOK_GE;
43.630 - if (c == '>') {
43.631 - c = getChar();
43.632 - if (c == '>') {
43.633 - c = getChar();
43.634 - if (c == '=')
43.635 - return TOK_ASSIGN_USHR;
43.636 - putChar(c);
43.637 - return TOK_USHR;
43.638 - }
43.639 - return TOK_SHR;
43.640 - }
43.641 - putChar(c);
43.642 - return TOK_GT;
43.643 -
43.644 - case ' ':
43.645 - case '\t':
43.646 - case '\f':
43.647 - break;
43.648 -
43.649 - case '"':
43.650 - return stringLiteral();
43.651 -
43.652 - default:
43.653 - if (c >= '0' && c <= '9')
43.654 - return numberLiteral(c);
43.655 - if (c == '_' || (isascii(c) && isalpha(c)))
43.656 - return identifier(c);
43.657 - cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
43.658 - return TOK_ERROR;
43.659 - }
43.660 - }
43.661 -}
43.662 -
43.663 -TokenKind
43.664 -Scanner::scan()
43.665 -{
43.666 - if (pushed_) {
43.667 - pushed_ = false;
43.668 - return lastToken_;
43.669 - }
43.670 - lastToken_ = next();
43.671 - return lastToken_;
43.672 -}
43.673 -
43.674 -TokenKind
43.675 -Scanner::peek()
43.676 -{
43.677 - if (pushed_)
43.678 - return lastToken_;
43.679 - scan();
43.680 - pushed_ = true;
43.681 - return lastToken_;
43.682 -}
44.1 --- a/src/Scanner.h Mon Sep 17 00:10:01 2012 -0700
44.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
44.3 @@ -1,114 +0,0 @@
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 SourcePawn.
44.9 - *
44.10 - * SourcePawn 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 - * SourcePawn 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 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
44.21 - */
44.22 -#ifndef _include_jitcraft_scanner_h_
44.23 -#define _include_jitcraft_scanner_h_
44.24 -
44.25 -#include <string>
44.26 -#include "Token.h"
44.27 -#include "CompileContext.h"
44.28 -#include "Vector.h"
44.29 -
44.30 -namespace ke {
44.31 -
44.32 -class Scanner
44.33 -{
44.34 - template <bool Enabled>
44.35 - friend class AutoAllowTags;
44.36 -
44.37 - CompileContext &cc_;
44.38 - const char *stream_;
44.39 - size_t length_;
44.40 - bool pushed_;
44.41 - bool allowTags_;
44.42 - char saved_;
44.43 - const char *pos_;
44.44 - Vector<char> literal_;
44.45 - TokenKind lastToken_;
44.46 - SourcePosition last_;
44.47 - SourcePosition cur_;
44.48 - SourcePosition begin_;
44.49 -
44.50 - private:
44.51 - char getChar();
44.52 - void putChar(char c);
44.53 - void eatSingleLine();
44.54 - bool eatComment();
44.55 - void calcNewLine(char c);
44.56 - int readEscapeCode();
44.57 - TokenKind stringLiteral();
44.58 - TokenKind hexLiteral();
44.59 - TokenKind numberLiteral(char first);
44.60 - TokenKind identifier(char first);
44.61 -
44.62 - TokenKind next();
44.63 -
44.64 - public:
44.65 - Scanner(CompileContext &cc, const char *stream, size_t length);
44.66 -
44.67 - static double ParseDouble(const char *string);
44.68 -
44.69 - TokenKind scan();
44.70 - TokenKind peek();
44.71 - TokenKind last() const {
44.72 - return lastToken_;
44.73 - }
44.74 -
44.75 - bool tagsEnabled() const {
44.76 - return allowTags_;
44.77 - }
44.78 - void setTagsEnabled(bool enabled) {
44.79 - allowTags_ = enabled;
44.80 - }
44.81 -
44.82 - // Beginning source position of the last instruction.
44.83 - SourcePosition begin() const {
44.84 - return begin_;
44.85 - }
44.86 -
44.87 - // Note: the literal may have embedded NUL characters.
44.88 - const char *literal() const {
44.89 - return literal_.buffer();
44.90 - }
44.91 - size_t literal_length() const {
44.92 - return literal_.length() - 1;
44.93 - }
44.94 -};
44.95 -
44.96 -template <bool Enabled>
44.97 -class AutoAllowTags
44.98 -{
44.99 - Scanner &scanner_;
44.100 - bool prev_;
44.101 -
44.102 - public:
44.103 - AutoAllowTags(Scanner &scanner)
44.104 - : scanner_(scanner),
44.105 - prev_(scanner_.tagsEnabled())
44.106 - {
44.107 - scanner_.setTagsEnabled(Enabled);
44.108 - }
44.109 - ~AutoAllowTags()
44.110 - {
44.111 - scanner_.setTagsEnabled(prev_);
44.112 - }
44.113 -};
44.114 -
44.115 -} // namespace ke
44.116 -
44.117 -#endif // _include_jitcraft_scanner_h_
45.1 --- a/src/Scopes.cpp Mon Sep 17 00:10:01 2012 -0700
45.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
45.3 @@ -1,289 +0,0 @@
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 JITCraft.
45.9 - *
45.10 - * JITCraft 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 - * Foobar 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 - * JITCraft. If not, see http://www.gnu.org/licenses/.
45.21 - */
45.22 -#include "Scopes.h"
45.23 -#include "Zone.h"
45.24 -#include "Types.h"
45.25 -#include "TypeManager.h"
45.26 -#include "Strings.h"
45.27 -#include "CompileContext.h"
45.28 -#include "Environments.h"
45.29 -#include "Spaces-inl.h"
45.30 -#include "Heap-inl.h"
45.31 -
45.32 -using namespace ke;
45.33 -
45.34 -Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
45.35 - : pool_(pool),
45.36 - locals_(0),
45.37 - maxContainedLocals_(0),
45.38 - numFunctions_(0),
45.39 - numNatives_(0),
45.40 - lifoSlot_(NULL),
45.41 - kind_(kind),
45.42 - enclosing_(enclosing)
45.43 -{
45.44 -}
45.45 -
45.46 -bool
45.47 -Scope::initialize()
45.48 -{
45.49 - if (enclosing_ && !enclosing_->children_.append(this))
45.50 - return false;
45.51 - return true;
45.52 -}
45.53 -
45.54 -void
45.55 -Scope::unlink()
45.56 -{
45.57 - assert(empty());
45.58 -
45.59 - assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
45.60 - enclosing_->children_.pop();
45.61 -
45.62 - // OOM here is swallowed and checked after compilation.
45.63 - // :TODO: make the above true.
45.64 - for (size_t i = 0; i < children_.length(); i++)
45.65 - enclosing_->children_.append(children_[i]);
45.66 -}
45.67 -
45.68 -Scope *
45.69 -Scope::unlinkIfEmpty()
45.70 -{
45.71 - if (empty()) {
45.72 - unlink();
45.73 - return NULL;
45.74 - }
45.75 - return this;
45.76 -}
45.77 -
45.78 -BoundName *
45.79 -Scope::localLookup(Handle<String> name)
45.80 -{
45.81 - for (size_t i = 0; i < names_.length(); i++) {
45.82 - if (names_[i]->name() == name)
45.83 - return names_[i];
45.84 - }
45.85 - return NULL;
45.86 -}
45.87 -
45.88 -BoundName *
45.89 -Scope::lookup(Handle<String> name)
45.90 -{
45.91 - for (Scope *scope = this; scope; scope = scope->enclosing()) {
45.92 - if (BoundName *bound = scope->localLookup(name))
45.93 - return bound;
45.94 - }
45.95 - return NULL;
45.96 -}
45.97 -
45.98 -Variable *
45.99 -Scope::declareVariable(Handle<String> name, const SourcePosition &pos)
45.100 -{
45.101 - assert(!localLookup(name));
45.102 -
45.103 - Variable *var = new (pool_) Variable(this, name, pos);
45.104 - if (!names_.append(var))
45.105 - return NULL;
45.106 - return var;
45.107 -}
45.108 -
45.109 -Variable *
45.110 -Scope::declareArgument(Handle<String> name, const SourcePosition &pos)
45.111 -{
45.112 - assert(kind() == FUNCTION);
45.113 - Variable *var = declareVariable(name, pos);
45.114 - if (!names_.append(var))
45.115 - return NULL;
45.116 - if (!parameters_.append(var))
45.117 - return NULL;
45.118 - return var;
45.119 -}
45.120 -
45.121 -NamedFunction *
45.122 -Scope::declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token)
45.123 -{
45.124 - assert(!localLookup(name));
45.125 - assert(kind() == GLOBAL);
45.126 -
45.127 - NamedFunction *fun = new (pool_) NamedFunction(this, name, pos, token);
45.128 - if (!names_.append(fun))
45.129 - return NULL;
45.130 - return fun;
45.131 -}
45.132 -
45.133 -NamedConstant *
45.134 -Scope::declareConstant(Handle<String> name, const SourcePosition &pos)
45.135 -{
45.136 - NamedConstant *constant = new (pool_) NamedConstant(this, name, pos);
45.137 - if (!names_.append(constant))
45.138 - return NULL;
45.139 - return constant;
45.140 -}
45.141 -
45.142 -NamedType *
45.143 -Scope::declareType(Handle<String> name, const SourcePosition &pos)
45.144 -{
45.145 - NamedType *decl = new (pool_) NamedType(this, name, pos);
45.146 - if (!names_.append(decl))
45.147 - return NULL;
45.148 - return decl;
45.149 -}
45.150 -
45.151 -NamedType *
45.152 -Scope::declareType(Handle<String> name, Handle<Type> type)
45.153 -{
45.154 - NamedType *decl = new (pool_) NamedType(this, name, type);
45.155 - if (!names_.append(decl))
45.156 - return NULL;
45.157 - return decl;
45.158 -}
45.159 -
45.160 -void
45.161 -Scope::allocateGlobals()
45.162 -{
45.163 - assert(kind() == GLOBAL);
45.164 -
45.165 - for (size_t i = 0; i < children_.length(); i++) {
45.166 - assert(children_[i]->kind() == FUNCTION);
45.167 - children_[i]->allocate();
45.168 - }
45.169 -
45.170 - Local<Type> type(ZONE());
45.171 - for (size_t i = 0; i < names_.length(); i++) {
45.172 - BoundName *name = names_[i];
45.173 -
45.174 - if (name->kind() == BoundName::FUNCTION) {
45.175 - NamedFunction *fun = name->toNamedFunction();
45.176 - if (!fun->used())
45.177 - continue;
45.178 -
45.179 - if (fun->isNative())
45.180 - fun->allocate(numNatives_++);
45.181 - else
45.182 - fun->allocate(numFunctions_++);
45.183 - } else if (name->kind() == BoundName::VARIABLE) {
45.184 - allocate(name->toVariable());
45.185 - }
45.186 - }
45.187 -}
45.188 -
45.189 -void
45.190 -Scope::allocate(Variable *var)
45.191 -{
45.192 - if (!var->unallocated())
45.193 - return;
45.194 -
45.195 - if (kind() == GLOBAL) {
45.196 - var->allocate(Variable::ENVIRONMENT, envVars_.length());
45.197 - envVars_.append(var);
45.198 - } else {
45.199 - var->allocate(Variable::STACK, maxContainedLocals_ + locals_);
45.200 - locals_++;
45.201 - }
45.202 -}
45.203 -
45.204 -void
45.205 -Scope::allocate()
45.206 -{
45.207 - maxContainedLocals_ = 0;
45.208 - for (size_t i = 0; i < children_.length(); i++) {
45.209 - Scope *scope = children_[i];
45.210 - scope->allocate();
45.211 - if (scope->maxContainedLocals() > maxContainedLocals_)
45.212 - maxContainedLocals_ = scope->maxContainedLocals();
45.213 - }
45.214 -
45.215 - for (size_t i = 0; i < parameters_.length(); i++)
45.216 - parameters_[i]->allocate(Variable::PARAMETER, i);
45.217 -
45.218 - if (lifoSlot_)
45.219 - allocate(lifoSlot_);
45.220 - for (size_t i = 0; i < names_.length(); i++) {
45.221 - if (names_[i]->kind() != BoundName::VARIABLE)
45.222 - continue;
45.223 -
45.224 - allocate(names_[i]->toVariable());
45.225 - }
45.226 -
45.227 - maxContainedLocals_ += locals_;
45.228 -}
45.229 -
45.230 -bool
45.231 -Scope::Bind(CompileContext &cc, ParseTree *tree)
45.232 -{
45.233 - Local<String> name(ZONE());
45.234 - for (size_t i = 0; i < tree->unbound()->length(); i++) {
45.235 - NameProxy *proxy = tree->unbound()->at(i);
45.236 - name = proxy->name();
45.237 - BoundName *binding = tree->scope()->lookup(name);
45.238 -
45.239 - if (!binding) {
45.240 - cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
45.241 - return false;
45.242 - }
45.243 -
45.244 - // We only allow global functions to be late-bound.
45.245 - if (binding->kind() != BoundName::FUNCTION ||
45.246 - binding->scope()->kind() != Scope::GLOBAL)
45.247 - {
45.248 - cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
45.249 - return false;
45.250 - }
45.251 -
45.252 - proxy->bind(binding);
45.253 -
45.254 - // Find the function the proxy is defined in.
45.255 - }
45.256 - return true;
45.257 -}
45.258 -
45.259 -void
45.260 -Scope::Allocate(ParseTree *tree)
45.261 -{
45.262 - tree->scope()->allocateGlobals();
45.263 -}
45.264 -
45.265 -void
45.266 -Scope::setUsesLifoHeap()
45.267 -{
45.268 - // Only one lifo slot is needed per scope.
45.269 - if (lifoSlot_)
45.270 - return;
45.271 -
45.272 - // If the parent of this scope is the function scope, then this is the
45.273 - // function's block scope, and the lifo slot is part of the Frame instead.
45.274 - // Note we can get a function scope here if we're making a temporary in a
45.275 - // function with no local variables.
45.276 - if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
45.277 - return;
45.278 -
45.279 - Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
45.280 - if (!type)
45.281 - return;
45.282 -
45.283 - Local<String> name(ZONE());
45.284 - lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
45.285 - lifoSlot_->setType(type);
45.286 -}
45.287 -
45.288 -EnvironmentMap *
45.289 -Scope::createEnvironmentMap(Zone *zone)
45.290 -{
45.291 - return EnvironmentMap::New(zone, envVars_.length(), envVars_.buffer());
45.292 -}
46.1 --- a/src/Scopes.h Mon Sep 17 00:10:01 2012 -0700
46.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
46.3 @@ -1,120 +0,0 @@
46.4 -/*
46.5 - * Copyright (C) 2012 David Anderson
46.6 - *
46.7 - * This file is part of JITCraft.
46.8 - *
46.9 - * JITCraft is free software: you can redistribute it and/or modify it under
46.10 - * the terms of the GNU General Public License as published by the Free
46.11 - * Software Foundation, either version 3 of the License, or (at your option)
46.12 - * any later version.
46.13 - *
46.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
46.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
46.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
46.17 - *
46.18 - * You should have received a copy of the GNU General Public License along with
46.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
46.20 - */
46.21 -#ifndef _include_jitcraft_scopes_h_
46.22 -#define _include_jitcraft_scopes_h_
46.23 -
46.24 -#include "PoolAllocator.h"
46.25 -#include "AST.h"
46.26 -#include "NameBinding.h"
46.27 -#include "Structures.h"
46.28 -
46.29 -namespace ke {
46.30 -
46.31 -class CompileContext;
46.32 -class EnvironmentMap;
46.33 -
46.34 -class Scope : public PoolObject
46.35 -{
46.36 - PoolAllocator &pool_;
46.37 - PoolList<BoundName *> names_;
46.38 - PoolList<Scope *> children_;
46.39 - PoolList<Variable *> parameters_;
46.40 - unsigned locals_;
46.41 - unsigned maxContainedLocals_;
46.42 - unsigned numFunctions_;
46.43 - unsigned numNatives_;
46.44 - PoolList<Variable *> envVars_;
46.45 - Variable *lifoSlot_;
46.46 -
46.47 - bool empty() const {
46.48 - return names_.length() == 0;
46.49 - }
46.50 - void unlink();
46.51 -
46.52 - public:
46.53 - enum Kind {
46.54 - GLOBAL,
46.55 - FUNCTION,
46.56 - BLOCK
46.57 - };
46.58 -
46.59 - public:
46.60 - Scope(PoolAllocator &pool, Kind kind, Scope *enclosing);
46.61 - bool initialize();
46.62 -
46.63 - Kind kind() const {
46.64 - return kind_;
46.65 - }
46.66 - Scope *enclosing() const {
46.67 - return enclosing_;
46.68 - }
46.69 - unsigned locals() const {
46.70 - return locals_;
46.71 - }
46.72 - unsigned maxContainedLocals() const {
46.73 - return maxContainedLocals_;
46.74 - }
46.75 - unsigned numFunctions() const {
46.76 - return numFunctions_;
46.77 - }
46.78 - unsigned numNatives() const {
46.79 - return numNatives_;
46.80 - }
46.81 - unsigned numArguments() const {
46.82 - return parameters_.length();
46.83 - }
46.84 - unsigned numEnvironmentVars() const {
46.85 - return envVars_.length();
46.86 - }
46.87 - Variable *getArgument(size_t index) {
46.88 - return parameters_[index];
46.89 - }
46.90 - Variable *lifoSlot() {
46.91 - return lifoSlot_;
46.92 - }
46.93 - void setUsesLifoHeap();
46.94 -
46.95 - Scope *unlinkIfEmpty();
46.96 - BoundName *localLookup(Handle<String> name);
46.97 - BoundName *lookup(Handle<String> name);
46.98 -
46.99 - NamedFunction *declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token);
46.100 - Variable *declareVariable(Handle<String> name, const SourcePosition &pos);
46.101 - Variable *declareArgument(Handle<String> name, const SourcePosition &pos);
46.102 - NamedConstant *declareConstant(Handle<String> name, const SourcePosition &pos);
46.103 - NamedType *declareType(Handle<String> name, const SourcePosition &pos);
46.104 - NamedType *declareType(Handle<String> name, Handle<Type> type);
46.105 -
46.106 - EnvironmentMap *createEnvironmentMap(Zone *zone);
46.107 -
46.108 - void allocate(Variable *var);
46.109 - void allocate();
46.110 - void allocateGlobals();
46.111 -
46.112 - public:
46.113 - static bool Bind(CompileContext &cc, ParseTree *tree);
46.114 - static void Allocate(ParseTree *tree);
46.115 -
46.116 - private:
46.117 - Kind kind_;
46.118 - Scope *enclosing_;
46.119 -};
46.120 -
46.121 -}
46.122 -
46.123 -#endif // _include_jitcraft_scopes_h_
47.1 --- a/src/SemanticAnalysis.cpp Mon Sep 17 00:10:01 2012 -0700
47.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
47.3 @@ -1,1887 +0,0 @@
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 <string.h>
47.23 -#include "SemanticAnalysis.h"
47.24 -#include "Types.h"
47.25 -#include "Zone.h"
47.26 -#include "TypeManager.h"
47.27 -#include "Scopes.h"
47.28 -#include "NameBinding.h"
47.29 -#include "Strings.h"
47.30 -#include "Box.h"
47.31 -#include "Array.h"
47.32 -#include "Heap-inl.h"
47.33 -
47.34 -using namespace ke;
47.35 -
47.36 -static inline bool
47.37 -IsPrimitiveType(Type *type, PrimitiveType primitive)
47.38 -{
47.39 - if (!type)
47.40 - return false;
47.41 -
47.42 - if (!type->isPrimitive())
47.43 - return false;
47.44 -
47.45 - return primitive == type->primitive();
47.46 -}
47.47 -
47.48 -static inline bool
47.49 -EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
47.50 - BoxedPrimitive *out)
47.51 -{
47.52 - switch (kind) {
47.53 - case TOK_PLUS:
47.54 - *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
47.55 - return true;
47.56 -
47.57 - case TOK_SHL:
47.58 - *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
47.59 - return true;
47.60 -
47.61 - default:
47.62 - return false;
47.63 - }
47.64 -}
47.65 -
47.66 -static inline bool
47.67 -EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
47.68 -{
47.69 - switch (kind) {
47.70 - case TOK_MINUS:
47.71 - *out = BoxedPrimitive::Int(-inner.toInt());
47.72 - return true;
47.73 -
47.74 - default:
47.75 - return false;
47.76 - }
47.77 -}
47.78 -
47.79 -static bool
47.80 -EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
47.81 -{
47.82 - switch (expression->kind()) {
47.83 - case AstNode::kBinaryExpression:
47.84 - {
47.85 - BoxedPrimitive left;
47.86 - BoxedPrimitive right;
47.87 - BinaryExpression *b = expression->toBinaryExpression();
47.88 - if (!EvaluateForConstant(b->left(), &left) ||
47.89 - !EvaluateForConstant(b->right(), &right))
47.90 - {
47.91 - return false;
47.92 - }
47.93 - return EvaluateBinaryOperation(b->token(), left, right, out);
47.94 - }
47.95 -
47.96 - case AstNode::kUnaryExpression:
47.97 - {
47.98 - BoxedPrimitive inner;
47.99 - UnaryExpression *u = expression->toUnaryExpression();
47.100 - if (!EvaluateForConstant(u->expression(), &inner))
47.101 - return false;
47.102 - return EvaluateUnaryOperation(u->token(), inner, out);
47.103 - }
47.104 -
47.105 - case AstNode::kNameProxy:
47.106 - {
47.107 - NameProxy *proxy = expression->toNameProxy();
47.108 - if (proxy->binding()->kind() != BoundName::CONSTANT)
47.109 - return false;
47.110 -
47.111 - NamedConstant *c = proxy->binding()->toNamedConstant();
47.112 - if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
47.113 - return false;
47.114 -
47.115 - *out = c->value();
47.116 - return true;
47.117 - }
47.118 -
47.119 - case AstNode::kBooleanLiteral:
47.120 - *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
47.121 - return true;
47.122 -
47.123 - case AstNode::kIntegerLiteral:
47.124 - *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
47.125 - return true;
47.126 -
47.127 - default:
47.128 - return false;
47.129 - }
47.130 -}
47.131 -
47.132 -SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
47.133 - : zone_(zone),
47.134 - cc_(cc),
47.135 - tree_(tree),
47.136 - scope_(NULL),
47.137 - loop_(NULL)
47.138 -{
47.139 -}
47.140 -
47.141 -bool
47.142 -SemanticAnalysis::analyze()
47.143 -{
47.144 - if (cc_.failures())
47.145 - return false;
47.146 -
47.147 - scope_ = tree_->scope();
47.148 -
47.149 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
47.150 - Statement *statement = tree_->statements()->at(i);
47.151 - if (statement->isFunctionStatement()) {
47.152 - FunctionStatement *funstmt = statement->toFunctionStatement();
47.153 - if (!preanalyze(funstmt))
47.154 - return false;
47.155 - } else if (statement->isEnumStatement()) {
47.156 - EnumStatement *enumstmt = statement->toEnumStatement();
47.157 -
47.158 - // We pre-fill global enum types, since they may occur in function
47.159 - // signatures. This should probably be somewhere else...
47.160 - enumstmt->accept(this);
47.161 - } else if (statement->isStructureStatement()) {
47.162 - StructureStatement *node = statement->toStructureStatement();
47.163 - node->accept(this);
47.164 - if (!node->decl()->type())
47.165 - return false;
47.166 - } else if (statement->isFunctionTypeStatement()) {
47.167 - FunctionTypeStatement *node = statement->toFunctionTypeStatement();
47.168 - node->accept(this);
47.169 - if (!node->decl()->type())
47.170 - return false;
47.171 - }
47.172 - }
47.173 -
47.174 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
47.175 - Statement *statement = tree_->statements()->at(i);
47.176 -
47.177 - // We can't double-process these. Maybe put this check somewhere else.
47.178 - if (statement->isEnumStatement())
47.179 - continue;
47.180 -
47.181 - statement->accept(this);
47.182 - }
47.183 -
47.184 - if (!determineLiveFunctions())
47.185 - return false;
47.186 -
47.187 - return !cc_.failures();
47.188 -}
47.189 -
47.190 -bool
47.191 -SemanticAnalysis::determineLiveFunctions()
47.192 -{
47.193 - Vector<NamedFunction *> worklist;
47.194 -
47.195 - // Add the root set.
47.196 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
47.197 - Statement *statement = tree_->statements()->at(i);
47.198 - if (!statement->isFunctionStatement())
47.199 - continue;
47.200 -
47.201 - FunctionStatement *stmt = statement->toFunctionStatement();
47.202 - NamedFunction *fun = stmt->fun();
47.203 - if (!fun->used())
47.204 - continue;
47.205 -
47.206 - for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
47.207 - NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
47.208 -
47.209 - // Names in these lists are always unused, however, we mark them
47.210 - // as used while inserting into the work queue, to avoid double-
47.211 - // insertion.
47.212 - if (name->used())
47.213 - continue;
47.214 -
47.215 - if (!worklist.append(name))
47.216 - return false;
47.217 -
47.218 - name->setUsed();
47.219 - }
47.220 - }
47.221 -
47.222 - while (!worklist.empty()) {
47.223 - NamedFunction *fun = worklist.popCopy();
47.224 -
47.225 - for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
47.226 - NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
47.227 - if (name->used())
47.228 - continue;
47.229 - if (!worklist.append(name))
47.230 - return false;
47.231 - name->setUsed();
47.232 - }
47.233 - }
47.234 -
47.235 - return true;
47.236 -}
47.237 -
47.238 -Type *
47.239 -SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
47.240 -{
47.241 - if (!name)
47.242 - return zone_->types()->getPrimitive(PrimitiveType_Int32);
47.243 -
47.244 - if (name->kind() == BoundName::UNBOUND) {
47.245 - cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
47.246 - return NULL;
47.247 - }
47.248 -
47.249 - if (name->kind() != BoundName::TYPE) {
47.250 - cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
47.251 - return NULL;
47.252 - }
47.253 -
47.254 - if (!name->type())
47.255 - return NULL;
47.256 -
47.257 - return name->type();
47.258 -}
47.259 -
47.260 -Type *
47.261 -SemanticAnalysis::visitAndApplyType(Expression *expression)
47.262 -{
47.263 - expression->accept(this);
47.264 - return expression->type();
47.265 -}
47.266 -
47.267 -Type *
47.268 -SemanticAnalysis::visitForLoad(Expression *expression)
47.269 -{
47.270 - Local<Type> type(zone_, visitAndApplyType(expression));
47.271 - if (!type)
47.272 - return NULL;
47.273 -
47.274 - if (type->isReference()) {
47.275 - expression->setType(type->contained());
47.276 - } else if (expression->isCallExpression()) {
47.277 - if (type->isVoid()) {
47.278 - CallExpression *call = expression->toCallExpression();
47.279 - cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
47.280 - return NULL;
47.281 - }
47.282 - }
47.283 -
47.284 - return expression->type();
47.285 -}
47.286 -
47.287 -// :TODO: this leaks an interior pointer.
47.288 -const char *
47.289 -ke::GetTypeName(Type *type)
47.290 -{
47.291 - if (type->isArray())
47.292 - return "array";
47.293 - if (type->isFunction())
47.294 - return "function";
47.295 - if (type->isVoid())
47.296 - return "void";
47.297 - if (type->isEnum() || type->isStruct())
47.298 - return type->name()->chars();
47.299 - if (type->isReference())
47.300 - type = type->contained();
47.301 - switch (type->primitive()) {
47.302 - case PrimitiveType_Bool:
47.303 - return "bool";
47.304 - case PrimitiveType_Char:
47.305 - return "String";
47.306 - case PrimitiveType_Int32:
47.307 - return "int";
47.308 - case PrimitiveType_Float:
47.309 - return "Float";
47.310 - default:
47.311 - return "<unknown>";
47.312 - }
47.313 -}
47.314 -
47.315 -void
47.316 -SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
47.317 -{
47.318 - const char *op = TokenNames[token];
47.319 - const char *name = GetTypeName(type);
47.320 -
47.321 - cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
47.322 -}
47.323 -
47.324 -void
47.325 -SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
47.326 -{
47.327 - const char *op = TokenNames[token];
47.328 - const char *leftName = GetTypeName(left);
47.329 - const char *rightName = GetTypeName(right);
47.330 -
47.331 - cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
47.332 -}
47.333 -
47.334 -Type *
47.335 -SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
47.336 -{
47.337 - if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
47.338 - (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
47.339 - {
47.340 - // If either side is a float, the other side must be a float or int.
47.341 - if (left->isFloat() || right->isFloat()) {
47.342 - Type *floatType = left->isFloat() ? left : right;
47.343 - Type *other = left->isFloat() ? right : left;
47.344 - if (other->isFloat() || other->isInt32())
47.345 - return floatType;
47.346 - }
47.347 - }
47.348 -
47.349 - if (token == TOK_OR || token == TOK_AND) {
47.350 - if (!canTest(node, left) || !canTest(node, right))
47.351 - return NULL;
47.352 - return zone_->types()->getPrimitive(PrimitiveType_Bool);
47.353 - }
47.354 -
47.355 - if (token >= TOK_EQUALS && token <= TOK_GE) {
47.356 - if ((left->isFloat() || left->isInt32()) &&
47.357 - (right->isFloat() || right->isInt32()))
47.358 - {
47.359 - return zone_->types()->getPrimitive(PrimitiveType_Bool);
47.360 - }
47.361 - binaryTypeError(node, token, left, right);
47.362 - return NULL;
47.363 - }
47.364 -
47.365 - if (!left->isInt32() || !right->isInt32()) {
47.366 - binaryTypeError(node, token, left, right);
47.367 - return NULL;
47.368 - }
47.369 -
47.370 - return left;
47.371 -}
47.372 -
47.373 -bool
47.374 -SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
47.375 -{
47.376 - if (!type->isPrimitive() && !type->isEnum()) {
47.377 - cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
47.378 - return false;
47.379 - }
47.380 - return true;
47.381 -}
47.382 -
47.383 -Type *
47.384 -SemanticAnalysis::visitForLValue(Expression *expression)
47.385 -{
47.386 - if (expression->isIndexExpression()) {
47.387 - Type *type = visitAndApplyType(expression);
47.388 - if (!type)
47.389 - return NULL;
47.390 -
47.391 - // if (type->isConst()) {
47.392 - // cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
47.393 - // return NULL;
47.394 - // }
47.395 -
47.396 - return type;
47.397 - }
47.398 -
47.399 - if (expression->isFieldExpression()) {
47.400 - Type *type = visitAndApplyType(expression);
47.401 - if (!type)
47.402 - return NULL;
47.403 -
47.404 - // if (expression->toFieldExpression()->left()->type()->isConst()) {
47.405 - // cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
47.406 - // return NULL;
47.407 - // }
47.408 -
47.409 - return type;
47.410 - }
47.411 -
47.412 - if (!expression->isNameProxy()) {
47.413 - cc_.reportError(expression->pos(), Message_ExpectedLValue);
47.414 - return NULL;
47.415 - }
47.416 -
47.417 - NameProxy *proxy = expression->toNameProxy();
47.418 - if (!proxy->binding()->kind() == BoundName::VARIABLE) {
47.419 - cc_.reportError(expression->pos(), Message_ExpectedLValue);
47.420 - return NULL;
47.421 - }
47.422 -
47.423 - Variable *var = proxy->binding()->toVariable();
47.424 - if (!var->type())
47.425 - return NULL;
47.426 -
47.427 - if (var->type()->isReference()) {
47.428 - if (var->type()->isConst()) {
47.429 - cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
47.430 - return NULL;
47.431 - }
47.432 - return var->type()->contained();
47.433 - }
47.434 - return var->type();
47.435 -}
47.436 -
47.437 -SemanticAnalysis::ControlStatus
47.438 -SemanticAnalysis::visitForControl(Statement *statement)
47.439 -{
47.440 - ControlScope scope(&control_);
47.441 - statement->accept(this);
47.442 - return scope.status();
47.443 -}
47.444 -
47.445 -void
47.446 -SemanticAnalysis::visit(NameProxy *name)
47.447 -{
47.448 - BoundName *binding = name->binding();
47.449 -
47.450 - if (binding->scope()->kind() == Scope::GLOBAL) {
47.451 - if (!function_ || function_->isPublic()) {
47.452 - // Whatever we're referencing must be kept alive no matter what.
47.453 - // As such, we simply mark it used, and don't do anything special.
47.454 - binding->setUsed();
47.455 - } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
47.456 - // Otherwise, we're inside a normal stock or function. Since we
47.457 - // don't really know if we've been used yet, we shouldn't
47.458 - // prematurely references as alive. Instead, we keep a list of
47.459 - // which names have been used, so we can mark them later if needed.
47.460 - //
47.461 - // Note that we skip this step if the binding is already in the
47.462 - // root set.
47.463 - if (!function_->addUsedGlobal(binding))
47.464 - return;
47.465 - }
47.466 - }
47.467 -
47.468 - name->setType(binding->type());
47.469 -}
47.470 -
47.471 -void
47.472 -SemanticAnalysis::visit(Assignment *node)
47.473 -{
47.474 - Local<Type> exprType(zone_, visitForLoad(node->expression()));
47.475 - if (!exprType)
47.476 - return ;
47.477 -
47.478 - Local<Type> type(zone_, visitForLValue(node->lvalue()));
47.479 - if (!type)
47.480 - return;
47.481 -
47.482 - if (node->token() != TOK_ASSIGN) {
47.483 - if (!typeCheckBinary(node, node->token(), type, exprType))
47.484 - return;
47.485 - }
47.486 -
47.487 - if (!typeCheckAssignment(node->pos(), exprType, type, true))
47.488 - return;
47.489 -
47.490 - node->setType(type);
47.491 -}
47.492 -
47.493 -void
47.494 -SemanticAnalysis::visit(IncDecExpression *node)
47.495 -{
47.496 - Local<Type> type(zone_, visitForLValue(node->expression()));
47.497 - if (!type)
47.498 - return;
47.499 -
47.500 - assert(!type->isReference());
47.501 -
47.502 - if (!type->isInt32() && !type->isFloat()) {
47.503 - unaryTypeError(node, node->token(), type);
47.504 - return;
47.505 - }
47.506 -
47.507 - node->setType(type);
47.508 -}
47.509 -
47.510 -void
47.511 -SemanticAnalysis::visit(UnaryExpression *node)
47.512 -{
47.513 - Local<Type> type(zone_, visitForLoad(node->expression()));
47.514 - if (!type)
47.515 - return;
47.516 -
47.517 - switch (node->token())
47.518 - {
47.519 - case TOK_NOT:
47.520 - if (!canTest(node->expression(), type))
47.521 - return;
47.522 - type = zone_->types()->getPrimitive(PrimitiveType_Int32);
47.523 - if (!type)
47.524 - return;
47.525 - node->setType(type);
47.526 - break;
47.527 -
47.528 - case TOK_MINUS:
47.529 - if (!type->isFloat() && !type->isInt32()) {
47.530 - unaryTypeError(node, node->token(), type);
47.531 - return;
47.532 - }
47.533 - node->setType(type);
47.534 - break;
47.535 -
47.536 - case TOK_LABEL:
47.537 - {
47.538 - Local<Type> to(zone_, bindType(node->pos(), node->type()));
47.539 - if (!to)
47.540 - return;
47.541 -
47.542 - if ((!type->isFloat() && !type->isInt32OrEnum()) ||
47.543 - (!to->isFloat() && !to->isInt32OrEnum()))
47.544 - {
47.545 - unaryTypeError(node, node->token(), type);
47.546 - return;
47.547 - }
47.548 -
47.549 - node->setType(to);
47.550 - break;
47.551 - }
47.552 -
47.553 - case TOK_SIZEOF:
47.554 - {
47.555 - if (!type->isArray()) {
47.556 - cc_.reportError(node->pos(), Message_SizeofNeedsArray);
47.557 - return;
47.558 - }
47.559 - node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
47.560 - break;
47.561 - }
47.562 -
47.563 - default:
47.564 - assert(node->token() == TOK_TILDE);
47.565 - if (!type->isInt32()) {
47.566 - unaryTypeError(node, node->token(), type);
47.567 - return;
47.568 - }
47.569 - node->setType(type);
47.570 - break;
47.571 - }
47.572 -}
47.573 -
47.574 -void
47.575 -SemanticAnalysis::visit(TernaryExpression *node)
47.576 -{
47.577 - Local<Type> type(zone_, visitForLoad(node->condition()));
47.578 - if (!type)
47.579 - return;
47.580 -
47.581 - if (!canTest(node->condition(), type))
47.582 - return;
47.583 -
47.584 - Local<Type> left(zone_, visitForLoad(node->left()));
47.585 - Local<Type> right(zone_, visitForLoad(node->right()));
47.586 - if (!left || !right)
47.587 - return;
47.588 -
47.589 - if (left != right) {
47.590 - binaryTypeError(node, TOK_QMARK, left, right);
47.591 - return;
47.592 - }
47.593 -}
47.594 -
47.595 -void
47.596 -SemanticAnalysis::visit(BinaryExpression *node)
47.597 -{
47.598 - Local<Type> left(zone_, visitForLoad(node->left()));
47.599 - Local<Type> right(zone_, visitForLoad(node->right()));
47.600 - if (!left || !right)
47.601 - return;
47.602 -
47.603 - Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
47.604 - if (!result)
47.605 - return;
47.606 -
47.607 - node->setType(result);
47.608 -}
47.609 -
47.610 -void
47.611 -SemanticAnalysis::visit(ReturnStatement *node)
47.612 -{
47.613 - // Set this early, so if we error we don't get more errors.
47.614 - control_->returns(Returns_Always);
47.615 -
47.616 - if (!node->expression()) {
47.617 - if (!function_->type()->returnType()->isVoid())
47.618 - cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
47.619 - return;
47.620 - }
47.621 -
47.622 - Local<Type> type(zone_, visitForLoad(node->expression()));
47.623 - if (!type)
47.624 - return;
47.625 -
47.626 - Local<Type> returnType(zone_, function_->type()->returnType());
47.627 - if (!typeCheckAssignment(node->pos(), type, returnType, true))
47.628 - return;
47.629 -}
47.630 -
47.631 -void
47.632 -SemanticAnalysis::visit(ForStatement *node)
47.633 -{
47.634 - LoopScope loop(&loop_);
47.635 -
47.636 - if (node->scope())
47.637 - scope_ = node->scope();
47.638 -
47.639 - if (node->initialization())
47.640 - node->initialization()->accept(this);
47.641 -
47.642 - if (node->condition()) {
47.643 - Local<Type> type(zone_, visitForLoad(node->condition()));
47.644 - if (!type || !canTest(node->condition(), type)) {
47.645 - return;
47.646 - }
47.647 - }
47.648 -
47.649 - if (node->update())
47.650 - node->update()->accept(this);
47.651 -
47.652 - ControlStatus status = visitForControl(node->body());
47.653 -
47.654 - // If there is a condition, we treat this like a while loop. Otherwise,
47.655 - // join point is only reachable if the loop contains a break. The
47.656 - // termination status doesn't tell us anything yet.
47.657 - if (node->condition() || loop.breaks())
47.658 - control_->merge(status, ControlStatus(false, Returns_Never));
47.659 - else
47.660 - control_->terminate(status.returns());
47.661 -
47.662 - if (node->scope())
47.663 - scope_ = scope_->enclosing();
47.664 -}
47.665 -
47.666 -void
47.667 -SemanticAnalysis::visit(WhileStatement *node)
47.668 -{
47.669 - LoopScope loop(&loop_);
47.670 -
47.671 - Local<Type> type(zone_, visitForLoad(node->condition()));
47.672 - if (!type || !canTest(node->condition(), type)) {
47.673 - return;
47.674 - }
47.675 -
47.676 - ControlStatus status = visitForControl(node->body());
47.677 -
47.678 - // Detect loops that will always have a fork in the control-flow graph.
47.679 - // This will be a |while| loop, or a |do-while| loop whose body does
47.680 - // not terminate.
47.681 - //
47.682 - // For now, we treat these as an |if| regardless of the direction the
47.683 - // branch can take. That means the control-flow is always conditional.
47.684 - if (node->token() == TOK_WHILE ||
47.685 - !status.terminates() ||
47.686 - loop.breaks())
47.687 - {
47.688 - control_->merge(status, ControlStatus(false, Returns_Never));
47.689 - } else {
47.690 - // At this point, we've got a do-while loop with a |return| or
47.691 - // |continue|, meaning that the rest of the block is unreachable.
47.692 - control_->terminate(status.returns());
47.693 - }
47.694 -}
47.695 -
47.696 -void
47.697 -SemanticAnalysis::visit(BlockStatement *node)
47.698 -{
47.699 - if (node->scope())
47.700 - scope_ = node->scope();
47.701 - for (size_t i = 0; i < node->statements()->length(); i++) {
47.702 - Statement *statement = node->statements()->at(i);
47.703 - statement->accept(this);
47.704 - }
47.705 - if (node->scope())
47.706 - scope_ = scope_->enclosing();
47.707 -}
47.708 -
47.709 -static inline bool
47.710 -IsScalarString(Type *type)
47.711 -{
47.712 - if (type->isPrimitive() && type->primitive() == PrimitiveType_Char)
47.713 - return true;
47.714 - if (type->isReference())
47.715 - return IsScalarString(type->contained());
47.716 - return false;
47.717 -}
47.718 -
47.719 -static const int INFER_ARRAY_SIZE = 0;
47.720 -static const int EVAL_ARRAY_SIZE = -1;
47.721 -static const int DYNAMIC_ARRAY_SIZE = -2;
47.722 -
47.723 -bool
47.724 -SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
47.725 -{
47.726 - bool hadEmptySize = false;
47.727 -
47.728 - for (size_t i = 0; i < exprs->length(); i++) {
47.729 - Expression *expr = exprs->at(i);
47.730 - if (!expr) {
47.731 - dims[i] = INFER_ARRAY_SIZE;
47.732 - hadEmptySize = true;
47.733 - continue;
47.734 - }
47.735 -
47.736 - BoxedPrimitive box;
47.737 - if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
47.738 - int size = box.toInt();
47.739 - if (size <= 0) {
47.740 - cc_.reportError(expr->pos(), Message_BadArraySize);
47.741 - return false;
47.742 - }
47.743 -
47.744 - dims[i] = size;
47.745 - continue;
47.746 - }
47.747 -
47.748 - Local<Type> exprType(zone_, visitForLoad(expr));
47.749 - if (!exprType)
47.750 - return false;
47.751 -
47.752 - if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
47.753 - cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
47.754 - return false;
47.755 - }
47.756 -
47.757 - if (hadEmptySize) {
47.758 - cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
47.759 - return false;
47.760 - }
47.761 -
47.762 - dims[i] = EVAL_ARRAY_SIZE;
47.763 - }
47.764 -
47.765 - return true;
47.766 -}
47.767 -
47.768 -bool
47.769 -SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
47.770 - int dims[MAX_ARRAY_DEPTH],
47.771 - unsigned dimcount, unsigned level)
47.772 -{
47.773 - if (dims[level] == EVAL_ARRAY_SIZE) {
47.774 - cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
47.775 - return false;
47.776 - }
47.777 -
47.778 - if (dims[level] == INFER_ARRAY_SIZE) {
47.779 - // Strings always become dynamic arrays.
47.780 - if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
47.781 - dims[level] = literal->expressions()->length();
47.782 - } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
47.783 - cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
47.784 - return false;
47.785 - } else {
47.786 - if (literal->expressions()->length() != unsigned(dims[level])) {
47.787 - cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
47.788 - return false;
47.789 - }
47.790 - }
47.791 -
47.792 - if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
47.793 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
47.794 - Expression *expr = literal->expressions()->at(i);
47.795 - if (!expr->isStringLiteral()) {
47.796 - cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
47.797 - return false;
47.798 - }
47.799 -
47.800 - StringLiteral *lit = expr->toStringLiteral();
47.801 - if (dims[level + 1] > 0 &&
47.802 - unsigned(dims[level]) < lit->string()->length())
47.803 - {
47.804 - cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
47.805 - return false;
47.806 - }
47.807 - if (!visitAndApplyType(lit))
47.808 - return false;
47.809 - }
47.810 - } else if (level == dimcount - 1) {
47.811 - Local<Type> type(zone_);
47.812 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
47.813 - Expression *expr = literal->expressions()->at(i);
47.814 - if (expr->isArrayLiteral()) {
47.815 - cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
47.816 - return false;
47.817 - }
47.818 -
47.819 - if ((type = visitAndApplyType(expr)) == NULL)
47.820 - return false;
47.821 -
47.822 - if (!typeCheckAssignment(expr->pos(), type, contained, true))
47.823 - return false;
47.824 - }
47.825 - } else {
47.826 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
47.827 - Expression *expr = literal->expressions()->at(i);
47.828 - if (!expr->isArrayLiteral()) {
47.829 - cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
47.830 - return false;
47.831 - }
47.832 -
47.833 - assert(expr->toArrayLiteral()->isFixed());
47.834 -
47.835 - if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
47.836 - contained,
47.837 - dims,
47.838 - dimcount,
47.839 - level + 1))
47.840 - {
47.841 - return false;
47.842 - }
47.843 - }
47.844 - }
47.845 -
47.846 - return true;
47.847 -}
47.848 -
47.849 -void
47.850 -SemanticAnalysis::visit(VariableDeclaration *node)
47.851 -{
47.852 - Local<Type> type(zone_, bindType(node->pos(), node->type()));
47.853 - if (!type)
47.854 - return;
47.855 -
47.856 - if (node->postDimensions() || type->isArray()) {
47.857 - // The type could be an array type, so sum the type and postDimensions
47.858 - // together.
47.859 - unsigned dimcount = node->postDimensions()->length();
47.860 - if (type->isArray())
47.861 - dimcount += type->levels();
47.862 - if (dimcount > MAX_ARRAY_DEPTH) {
47.863 - cc_.reportError(node->pos(), Message_MaximumArrayDepth);
47.864 - return;
47.865 - }
47.866 -
47.867 - // Take an initial guess at the array dimension sizes.
47.868 - int dims[MAX_ARRAY_DEPTH];
47.869 - if (!evaluateDimensions(node->postDimensions(), dims))
47.870 - return;
47.871 -
47.872 - // Now add in the type's array dimensions.
47.873 - Local<Type> contained(zone_, type);
47.874 - for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
47.875 - if (type->isFixedLength())
47.876 - dims[i] = type->fixedLength();
47.877 - else
47.878 - dims[i] = DYNAMIC_ARRAY_SIZE;
47.879 - contained = contained->contained();
47.880 - }
47.881 -
47.882 - Expression *initializer = node->initialization();
47.883 - if (initializer &&
47.884 - initializer->isArrayLiteral() &&
47.885 - initializer->toArrayLiteral()->isFixed())
47.886 - {
47.887 - // Fixed array initializers are special; we use them to infer any
47.888 - // missing information in the original array. We do not evaluate
47.889 - // the array initializer as an expression.
47.890 - if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
47.891 - contained,
47.892 - dims,
47.893 - dimcount,
47.894 - 0))
47.895 - {
47.896 - return;
47.897 - }
47.898 - initializer = NULL;
47.899 - }
47.900 -
47.901 - // We now have enough information to build the actual array type.
47.902 - // Start from the original dimcount, not the one computed for
47.903 - // initializers.
47.904 - for (size_t i = node->postDimensions()->length() - 1;
47.905 - i < node->postDimensions()->length();
47.906 - i--)
47.907 - {
47.908 - int size = dims[i] > 0
47.909 - ? dims[i]
47.910 - : Type::DYNAMIC_ARRAY_SIZE;
47.911 -
47.912 - type = zone_->types()->newArray(type, size, false);
47.913 - if (!type)
47.914 - return;
47.915 - }
47.916 -
47.917 - // Finally, if we had a non-fixed initializer, make sure it type
47.918 - // checks.
47.919 - if (initializer) {
47.920 - Local<Type> right(zone_, visitForLoad(initializer));
47.921 - if (!right)
47.922 - return;
47.923 -
47.924 - if (!typeCheckAssignment(node->pos(), right, type, true))
47.925 - return;
47.926 - }
47.927 - } else {
47.928 - if (node->initialization()) {
47.929 - Local<Type> right(zone_, visitForLoad(node->initialization()));
47.930 - if (!right)
47.931 - return;
47.932 - if (!typeCheckAssignment(node->pos(), right, type, true))
47.933 - return;
47.934 - }
47.935 -
47.936 - if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) {
47.937 - cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
47.938 - return;
47.939 - }
47.940 - }
47.941 -
47.942 - // If this variable is stack allocated, we could use the LIFO heap
47.943 - // to allocate it. If that's the case, make sure to reserve a slot
47.944 - // so we can unwind the LIFO heap at the end of this scope.
47.945 - if (!node->variable()->needsHeapAllocation()) {
47.946 - if (type->isArray() || type->isStruct())
47.947 - scope_->setUsesLifoHeap();
47.948 - }
47.949 -
47.950 - node->variable()->setType(type);
47.951 -}
47.952 -
47.953 -void
47.954 -SemanticAnalysis::visit(IntegerLiteral *node)
47.955 -{
47.956 - node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
47.957 -}
47.958 -
47.959 -void
47.960 -SemanticAnalysis::visit(BooleanLiteral *node)
47.961 -{
47.962 - node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool));
47.963 -}
47.964 -
47.965 -void
47.966 -SemanticAnalysis::visit(ExpressionStatement *node)
47.967 -{
47.968 - visitAndApplyType(node->expression());
47.969 -}
47.970 -
47.971 -Box *
47.972 -SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
47.973 -{
47.974 - Local<Type> given(zone_, visitForLoad(parameter->initializer()));
47.975 -
47.976 - BoxedPrimitive prim;
47.977 - if (EvaluateForConstant(parameter->initializer(), &prim)) {
47.978 - if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
47.979 - return NULL;
47.980 -
47.981 - if (prim.type() == PrimitiveType_Int32)
47.982 - return Box::New(zone_, given, prim.toInt());
47.983 - return Box::New(zone_, given, prim.toFloat());
47.984 - } else if (parameter->initializer()->isStringLiteral()) {
47.985 - StringLiteral *literal = parameter->initializer()->toStringLiteral();
47.986 -
47.987 - if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
47.988 - return NULL;
47.989 -
47.990 - Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, given));
47.991 - if (!map)
47.992 - return NULL;
47.993 -
47.994 - Local<Array> array(zone_,
47.995 - Array::NewString(zone_,
47.996 - map,
47.997 - literal->string()->raw(),
47.998 - literal->string()->length(),
47.999 - Heap::Tenure_Old));
47.1000 - if (!array)
47.1001 - return NULL;
47.1002 -
47.1003 - return Box::NewObj(zone_, given, array, Heap::Tenure_Old);
47.1004 - }
47.1005 -
47.1006 - cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant);
47.1007 - return NULL;
47.1008 -}
47.1009 -
47.1010 -bool
47.1011 -SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
47.1012 - FixedArray **argsp, FixedArray **defaultsp)
47.1013 -{
47.1014 - Local<FixedArray> args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
47.1015 - if (!args)
47.1016 - return false;
47.1017 -
47.1018 - Local<FixedArray> defaults(zone_);
47.1019 -
47.1020 - // Apply types to arguments.
47.1021 - for (size_t i = 0; i < sig.parameters()->length(); i++) {
47.1022 - Parameter *parameter = sig.parameters()->at(i);
47.1023 -
47.1024 - Local<Type> type(zone_, bindType(parameter->variable()->pos(), parameter->type()));
47.1025 - if (!type)
47.1026 - return false;
47.1027 -
47.1028 - if (parameter->reference()) {
47.1029 - if (parameter->dimensions()) {
47.1030 - cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
47.1031 - return false;
47.1032 - }
47.1033 -
47.1034 - if (type->isStruct()) {
47.1035 - cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference);
47.1036 - return false;
47.1037 - }
47.1038 -
47.1039 - type = zone_->types()->getReference(type, parameter->isConst());
47.1040 - if (!type)
47.1041 - return false;
47.1042 - } else if (parameter->dimensions()) {
47.1043 - type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
47.1044 - if (!type)
47.1045 - return false;
47.1046 -
47.1047 - if (kind == TOK_NATIVE && type->levels() > 1) {
47.1048 - cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
47.1049 - return false;
47.1050 - }
47.1051 - }
47.1052 -
47.1053 - if (IsScalarString(type)) {
47.1054 - cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
47.1055 - return false;
47.1056 - }
47.1057 -
47.1058 - args->set(zone_, i, type);
47.1059 - parameter->variable()->setType(type);
47.1060 -
47.1061 - if (parameter->initializer()) {
47.1062 - if (!defaults) {
47.1063 - defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old);
47.1064 - if (!defaults)
47.1065 - return false;
47.1066 - }
47.1067 -
47.1068 - Local<Box> box(zone_, evaluateDefaultParameter(type, parameter));
47.1069 - if (!box)
47.1070 - return false;
47.1071 -
47.1072 - defaults->set(zone_, i, box);
47.1073 - }
47.1074 - }
47.1075 -
47.1076 - *argsp = args;
47.1077 - *defaultsp = defaults;
47.1078 -
47.1079 - return true;
47.1080 -}
47.1081 -
47.1082 -void
47.1083 -SemanticAnalysis::visit(FunctionTypeStatement *node)
47.1084 -{
47.1085 - if (node->decl()->type())
47.1086 - return;
47.1087 -
47.1088 - Local<FixedArray> args(zone_);
47.1089 - Local<FixedArray> defaults(zone_);
47.1090 -
47.1091 - const FunctionSignature &sig= node->signature();
47.1092 - if (!buildFunctionArgs(node,
47.1093 - TOK_STOCK,
47.1094 - sig,
47.1095 - args.address(),
47.1096 - defaults.address()))
47.1097 - {
47.1098 - return;
47.1099 - }
47.1100 -
47.1101 - Local<Type> returnType(zone_);
47.1102 - if (sig.returnType())
47.1103 - returnType = bindType(node->pos(), sig.returnType());
47.1104 - else
47.1105 - returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
47.1106 -
47.1107 - if (!returnType)
47.1108 - return;
47.1109 -
47.1110 - Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args, defaults));
47.1111 - if (!funtype)
47.1112 - return;
47.1113 -
47.1114 - node->decl()->setType(funtype);
47.1115 -}
47.1116 -
47.1117 -Type *
47.1118 -SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
47.1119 -{
47.1120 - Local<Type> arrayType(zone_, type);
47.1121 -
47.1122 - unsigned dimcount = dimensions->length();
47.1123 - if (type->isArray())
47.1124 - dimcount += type->levels();
47.1125 -
47.1126 - if (dimcount > MAX_ARRAY_DEPTH) {
47.1127 - cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
47.1128 - Message_MaximumArrayDepth);
47.1129 - return false;
47.1130 - }
47.1131 -
47.1132 - // Note: constness is sort of bogus. Fix this sometime.
47.1133 - for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
47.1134 - Expression *expr = dimensions->at(i);
47.1135 - if (!expr) {
47.1136 - arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
47.1137 - if (!arrayType)
47.1138 - return NULL;
47.1139 -
47.1140 - continue;
47.1141 - }
47.1142 -
47.1143 - BoxedPrimitive box;
47.1144 - if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
47.1145 - cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
47.1146 - return NULL;
47.1147 - }
47.1148 -
47.1149 - if (box.toInt() <= 0) {
47.1150 - cc_.reportError(expr->pos(), Message_BadArraySize);
47.1151 - return NULL;
47.1152 - }
47.1153 -
47.1154 - arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
47.1155 - if (!arrayType)
47.1156 - return NULL;
47.1157 - }
47.1158 -
47.1159 - return arrayType;
47.1160 -}
47.1161 -
47.1162 -bool
47.1163 -SemanticAnalysis::preanalyze(FunctionStatement *node)
47.1164 -{
47.1165 - Local<FixedArray> args(zone_);
47.1166 - Local<FixedArray> defaults(zone_);
47.1167 -
47.1168 - const FunctionSignature &sig = node->signature();
47.1169 - if (!buildFunctionArgs(node,
47.1170 - node->fun()->token(),
47.1171 - sig,
47.1172 - args.address(),
47.1173 - defaults.address()))
47.1174 - {
47.1175 - return false;
47.1176 - }
47.1177 -
47.1178 - Local<Type> returnType(zone_);
47.1179 - if (sig.returnType() ||
47.1180 - node->hasExplicitReturn() ||
47.1181 - node->fun()->isNative())
47.1182 - {
47.1183 - returnType = bindType(node->pos(), sig.returnType());
47.1184 - } else {
47.1185 - returnType = zone_->types()->getVoid();
47.1186 - }
47.1187 - if (!returnType)
47.1188 - return false;
47.1189 -
47.1190 - if (sig.returnDimensions()) {
47.1191 - returnType = buildArrayType(returnType, sig.returnDimensions(), false);
47.1192 - if (!returnType)
47.1193 - return false;
47.1194 - }
47.1195 -
47.1196 - if (IsScalarString(returnType)) {
47.1197 - cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
47.1198 - return false;
47.1199 - }
47.1200 -
47.1201 - Local<Type> funtype(zone_);
47.1202 - if (node->fun()->isNative())
47.1203 - funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
47.1204 - else
47.1205 - funtype = zone_->types()->newFunction(returnType, args, defaults);
47.1206 - if (!funtype)
47.1207 - return false;
47.1208 -
47.1209 - // If the function already has a type, it was forward declared before, and
47.1210 - // now this is our chance to type check the second declaration.
47.1211 - if (node->fun()->type()) {
47.1212 - Local<Type> forward(zone_, node->fun()->type());
47.1213 - if (!Type::Compare(funtype, forward)) {
47.1214 - cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
47.1215 - return false;
47.1216 - }
47.1217 - node->fun()->setForwardType(forward);
47.1218 - }
47.1219 -
47.1220 - node->fun()->setType(funtype);
47.1221 -
47.1222 - return true;
47.1223 -}
47.1224 -
47.1225 -void
47.1226 -SemanticAnalysis::visit(FunctionStatement *node)
47.1227 -{
47.1228 - function_ = node->fun();
47.1229 - scope_ = node->scope();
47.1230 -
47.1231 - ControlScope control(&control_);
47.1232 - if (node->body()) {
47.1233 - node->body()->accept(this);
47.1234 -
47.1235 - ControlStatus status = control.status();
47.1236 - if (status.returns() == Returns_Sometimes) {
47.1237 - cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
47.1238 - } else if (status.returns() == Returns_Never) {
47.1239 - if (!function_->type()->returnType()->isVoid())
47.1240 - cc_.reportError(node->pos(), Message_MissingReturnValue);
47.1241 - }
47.1242 - }
47.1243 -
47.1244 - scope_ = NULL;
47.1245 - function_ = NULL;
47.1246 -}
47.1247 -
47.1248 -void
47.1249 -SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given)
47.1250 -{
47.1251 - cc_.reportError(pos, Message_TypeMismatch,
47.1252 - GetTypeName(actual),
47.1253 - GetTypeName(given));
47.1254 -}
47.1255 -
47.1256 -bool
47.1257 -SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> argGiven,
47.1258 - Handle<Type> argActual, bool forAssign)
47.1259 -{
47.1260 - Local<Type> actual(zone_, argActual);
47.1261 - Local<Type> given(zone_, argGiven);
47.1262 -
47.1263 - if (!given->isArray()) {
47.1264 - cc_.reportError(pos, Message_ExpectedArray);
47.1265 - return false;
47.1266 - }
47.1267 - if (given->levels() != actual->levels()) {
47.1268 - cc_.reportError(pos, Message_ArrayDimensionsMismatch);
47.1269 - return false;
47.1270 - }
47.1271 -
47.1272 - unsigned level = 1;
47.1273 - while (given->isArray()) {
47.1274 - if (actual->isFixedLength()) {
47.1275 - if (forAssign) {
47.1276 - if (!given->isFixedLength()) {
47.1277 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
47.1278 - return false;
47.1279 - }
47.1280 -
47.1281 - if (actual->isCharArray()) {
47.1282 - // String assignment can have a truncated |given|.
47.1283 - if (given->fixedLength() > actual->fixedLength()) {
47.1284 - cc_.reportError(pos, Message_ArrayAssignmentTooBig);
47.1285 - return false;
47.1286 - }
47.1287 - } else {
47.1288 - if (given->fixedLength() != actual->fixedLength()) {
47.1289 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
47.1290 - return false;
47.1291 - }
47.1292 - }
47.1293 - }
47.1294 - } else if (given->isFixedLength()) {
47.1295 - // We do not allow assignments in the form:
47.1296 - // [][] = [][Y]
47.1297 - //
47.1298 - // Otherwise, the following code could break the size guarantees
47.1299 - // of the right-hand side:
47.1300 - //
47.1301 - // new x[][5];
47.1302 - // new y[][];
47.1303 - // new z[3];
47.1304 - //
47.1305 - // y = x;
47.1306 - // y[0] = z;
47.1307 - //
47.1308 - // Now |x[0]| contains a 4-length array.
47.1309 - if (level > 1) {
47.1310 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
47.1311 - return false;
47.1312 - }
47.1313 - }
47.1314 - given = given->contained();
47.1315 - actual = actual->contained();
47.1316 - level++;
47.1317 - }
47.1318 -
47.1319 - return typeCheckAssignment(pos, given, actual, forAssign);
47.1320 -}
47.1321 -
47.1322 -bool
47.1323 -SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle<Type> argGiven,
47.1324 - Handle<Type> argActual, bool forAssign)
47.1325 -{
47.1326 - Local<Type> actual(zone_, argActual);
47.1327 - Local<Type> given(zone_, argGiven);
47.1328 -
47.1329 - if (actual->isArray())
47.1330 - return typeCheckArrayAssignment(pos, given, actual, forAssign);
47.1331 -
47.1332 - if (given->isArray()) {
47.1333 - cc_.reportError(pos, Message_CannotAssignArrayToScalar);
47.1334 - return false;
47.1335 - }
47.1336 -
47.1337 - // The given type may not have been dereferenced.
47.1338 - if (given->isReference())
47.1339 - given = given->contained();
47.1340 - if (actual->isReference())
47.1341 - actual = actual->contained();
47.1342 -
47.1343 - // We coerce unchecked to a few things.
47.1344 - if (actual->isUnchecked() || given->isUnchecked()) {
47.1345 - Type *check = actual->isUnchecked() ? given : actual;
47.1346 - if (check->isUnchecked() ||
47.1347 - check->isEnum() ||
47.1348 - check->isInt32() ||
47.1349 - check->isBool() ||
47.1350 - check->isFloat())
47.1351 - {
47.1352 - return true;
47.1353 - }
47.1354 - typeMismatch(pos, actual, given);
47.1355 - return false;
47.1356 - }
47.1357 -
47.1358 - if (given->isFunction() && actual->isFunction()) {
47.1359 - if (!Type::Compare(given, actual)) {
47.1360 - typeMismatch(pos, actual, given);
47.1361 - return false;
47.1362 - }
47.1363 - return true;
47.1364 - }
47.1365 -
47.1366 - if (actual->isEnum()) {
47.1367 - if (!given->isEnum() || actual != given) {
47.1368 - typeMismatch(pos, actual, given);
47.1369 - return false;
47.1370 - }
47.1371 - return true;
47.1372 - }
47.1373 -
47.1374 - if (actual->isStruct()) {
47.1375 - if (!given->isStruct() || actual != given) {
47.1376 - typeMismatch(pos, actual, given);
47.1377 - return false;
47.1378 - }
47.1379 - return true;
47.1380 - }
47.1381 -
47.1382 - if (given->isEnum() || given->isFunction() || given->isStruct()) {
47.1383 - typeMismatch(pos, actual, given);
47.1384 - return false;
47.1385 - }
47.1386 -
47.1387 - // This coercion is trivial.
47.1388 - if (given->isBool() && actual->isInt32())
47.1389 - return true;
47.1390 -
47.1391 - if (given->primitive() != actual->primitive()) {
47.1392 - typeMismatch(pos, actual, given);
47.1393 - return false;
47.1394 - }
47.1395 -
47.1396 - return true;
47.1397 -}
47.1398 -
47.1399 -bool
47.1400 -SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
47.1401 -{
47.1402 - return typeCheckAssignment(node->pos(), given, actual, false);
47.1403 -}
47.1404 -
47.1405 -bool
47.1406 -SemanticAnalysis::checkArgumentCount(Handle<Type> type, unsigned actual)
47.1407 -{
47.1408 - if (type->parameters()->length() == actual)
47.1409 - return true;
47.1410 -
47.1411 - if (actual > type->parameters()->length()) {
47.1412 - if (!type->isNative() || !type->isNativeVariadic())
47.1413 - return false;
47.1414 - return true;
47.1415 - }
47.1416 -
47.1417 - if (!type->defaults())
47.1418 - return false;
47.1419 -
47.1420 - // Missing arguments. See if there's a default argument for each missing
47.1421 - // actual.
47.1422 - for (unsigned i = actual; i < type->parameters()->length(); i++) {
47.1423 - if (!type->defaults()->at(i))
47.1424 - return false;
47.1425 - }
47.1426 -
47.1427 - return true;
47.1428 -}
47.1429 -
47.1430 -void
47.1431 -SemanticAnalysis::visit(CallExpression *node)
47.1432 -{
47.1433 - Local<Type> type(zone_, visitForLoad(node->callee()));
47.1434 - if (!type)
47.1435 - return;
47.1436 -
47.1437 - if (!type->isFunction()) {
47.1438 - cc_.reportError(node->pos(), Message_CalleeNotFunction);
47.1439 - return;
47.1440 - }
47.1441 -
47.1442 - if (!checkArgumentCount(type, node->arguments()->length())) {
47.1443 - cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
47.1444 - return;
47.1445 - }
47.1446 -
47.1447 - // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
47.1448 - // if (fun->isForward()) {
47.1449 - // cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
47.1450 - // return;
47.1451 - // }
47.1452 -
47.1453 - for (unsigned i = 0; i < node->arguments()->length(); i++) {
47.1454 - // Note: we don't compute references unless the callee needs a
47.1455 - // reference type.
47.1456 - Expression *expression = node->arguments()->at(i);
47.1457 - Local<Type> given(zone_, visitAndApplyType(expression));
47.1458 - if (!given)
47.1459 - return;
47.1460 -
47.1461 - // Since we skip a load, check for a call expression that returns void.
47.1462 - if (given->isVoid()) {
47.1463 - assert(expression->isCallExpression());
47.1464 - CallExpression *call = expression->toCallExpression();
47.1465 - cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
47.1466 - return;
47.1467 - }
47.1468 -
47.1469 - bool mustComputeReference;
47.1470 - if (i >= type->parameters()->length()) {
47.1471 - // Special handling for natives. Arguments past the formal must
47.1472 - // always have references computed. However, arrays are already
47.1473 - // references for natives.
47.1474 - assert(type->isNative() && type->isNativeVariadic());
47.1475 - mustComputeReference = !given->isReference() && !given->isArray();
47.1476 - } else {
47.1477 - Local<Type> actual(zone_, type->parameterAt(i));
47.1478 -
47.1479 - if (expression->isIndexExpression()) {
47.1480 - // Disabled until we can make it work.
47.1481 -#if 0
47.1482 - if (actual->isArray()) {
47.1483 - // We special case the ability to pass x[y] into x[], which
47.1484 - // creates an array slice. We only do this if we know the
47.1485 - // assignment would otherwise not type-check.
47.1486 - IndexExpression *index = expression->toIndexExpression();
47.1487 - if (index->left()->type()->levels() == actual->levels())
47.1488 - given = index->left()->type();
47.1489 - } else
47.1490 -#endif
47.1491 - if (actual->isReference()) {
47.1492 - cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
47.1493 - return;
47.1494 - }
47.1495 - }
47.1496 -
47.1497 - if (!typeCheckParameter(expression, given, actual))
47.1498 - return;
47.1499 - mustComputeReference = actual->isReference() && !given->isReference();
47.1500 - }
47.1501 -
47.1502 - // If the actual is a reference, and the given is not, we'll need to
47.1503 - // compute a reference, which may be allocated on the stack.
47.1504 - if (mustComputeReference)
47.1505 - scope_->setUsesLifoHeap();
47.1506 - }
47.1507 -
47.1508 - node->setType(type->returnType());
47.1509 -}
47.1510 -
47.1511 -void
47.1512 -SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
47.1513 -{
47.1514 - if (other.returns() < status().returns())
47.1515 - return;
47.1516 -
47.1517 - if (other.terminates())
47.1518 - terminate(other.returns());
47.1519 - else
47.1520 - returns(other.returns());
47.1521 -}
47.1522 -
47.1523 -void
47.1524 -SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
47.1525 -{
47.1526 - // If both sides terminate in a return, we consider this a return as well.
47.1527 - if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
47.1528 - terminate(Returns_Always);
47.1529 - return;
47.1530 - }
47.1531 -
47.1532 - ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
47.1533 - ? Returns_Never
47.1534 - : Returns_Sometimes;
47.1535 -
47.1536 - if (left.terminates() && right.terminates())
47.1537 - terminate(status);
47.1538 - else
47.1539 - returns(status);
47.1540 -}
47.1541 -
47.1542 -void
47.1543 -SemanticAnalysis::visit(IfStatement *node)
47.1544 -{
47.1545 - Local<Type> type(zone_, visitForLoad(node->condition()));
47.1546 - if (!type)
47.1547 - return;
47.1548 -
47.1549 - if (!canTest(node, type))
47.1550 - return;
47.1551 -
47.1552 - ControlStatus trueBranch = visitForControl(node->ifTrue());
47.1553 - ControlStatus falseBranch = ControlStatus(false, Returns_Never);
47.1554 -
47.1555 - if (node->ifFalse())
47.1556 - falseBranch = visitForControl(node->ifFalse());
47.1557 -
47.1558 - control_->merge(trueBranch, falseBranch);
47.1559 -}
47.1560 -
47.1561 -void
47.1562 -SemanticAnalysis::visit(IndexExpression *node)
47.1563 -{
47.1564 - Local<Type> left(zone_, visitForLoad(node->left()));
47.1565 - Local<Type> right(zone_, visitForLoad(node->right()));
47.1566 -
47.1567 - if (!left || !right)
47.1568 - return;
47.1569 -
47.1570 - if (!right->isInt32() && !right->isEnum()) {
47.1571 - cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
47.1572 - return;
47.1573 - }
47.1574 - if (!left->isArray()) {
47.1575 - cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
47.1576 - return;
47.1577 - }
47.1578 -
47.1579 - // Note: char arrays are automatically up-casted to return an int32.
47.1580 - if (left->isCharArray())
47.1581 - node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
47.1582 - else
47.1583 - node->setType(left->contained());
47.1584 -}
47.1585 -
47.1586 -void
47.1587 -SemanticAnalysis::visit(FieldExpression *node)
47.1588 -{
47.1589 - Local<Type> left(zone_, visitForLoad(node->left()));
47.1590 - if (!left)
47.1591 - return;
47.1592 -
47.1593 - if (!left->isStruct()) {
47.1594 - cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
47.1595 - GetTypeName(left));
47.1596 - return;
47.1597 - }
47.1598 -
47.1599 - Local<String> field(zone_, node->field());
47.1600 -
47.1601 - unsigned offset;
47.1602 - Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
47.1603 - if (!desc) {
47.1604 - cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
47.1605 - GetTypeName(left));
47.1606 - return;
47.1607 - }
47.1608 -
47.1609 - node->setFieldIndex(offset);
47.1610 - node->setType(desc->type());
47.1611 -}
47.1612 -
47.1613 -void
47.1614 -SemanticAnalysis::visit(EnumStatement *node)
47.1615 -{
47.1616 - Local<String> name(zone_, node->name());
47.1617 - Local<Type> type(zone_);
47.1618 - if (name)
47.1619 - type = zone_->types()->newEnum(name);
47.1620 - else
47.1621 - type = zone_->types()->getPrimitive(PrimitiveType_Int32);
47.1622 -
47.1623 - if (!type)
47.1624 - return;
47.1625 -
47.1626 - if (node->decl())
47.1627 - node->decl()->setType(type);
47.1628 -
47.1629 - int value = 0;
47.1630 - for (size_t i = 0; i < node->entries()->length(); i++) {
47.1631 - EnumStatement::Entry &entry = node->entries()->at(i);
47.1632 -
47.1633 - BoxedPrimitive box = BoxedPrimitive::Int(value);
47.1634 - if (entry.expr) {
47.1635 - entry.expr->accept(this);
47.1636 - if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
47.1637 - cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
47.1638 - return;
47.1639 - }
47.1640 -
47.1641 - assert(box.type() == PrimitiveType_Int32);
47.1642 - value = box.toInt();
47.1643 - }
47.1644 -
47.1645 - entry.name->set(type, box);
47.1646 - value++;
47.1647 - }
47.1648 -}
47.1649 -
47.1650 -static int
47.1651 -SortCaseIntValues(const void *p1, const void *p2)
47.1652 -{
47.1653 - CaseValue *v1 = (CaseValue *)p1;
47.1654 - CaseValue *v2 = (CaseValue *)p2;
47.1655 -
47.1656 - return v1->box.toInt() - v2->box.toInt();
47.1657 -}
47.1658 -
47.1659 -void
47.1660 -SemanticAnalysis::visit(SwitchStatement *node)
47.1661 -{
47.1662 - Local<Type> caseType(zone_, visitForLoad(node->expression()));
47.1663 - if (!caseType)
47.1664 - return;
47.1665 -
47.1666 - if (!caseType->isEnum() && !caseType->isInt32()) {
47.1667 - cc_.reportError(node->pos(), Message_CaseMustBeInteger);
47.1668 - return;
47.1669 - }
47.1670 -
47.1671 - PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
47.1672 - ControlStatus status = ControlStatus(false, Returns_Never);
47.1673 -
47.1674 - Local<Type> check(zone_);
47.1675 - for (size_t i = 0; i < node->cases()->length(); i++) {
47.1676 - Case *c = node->cases()->at(i);
47.1677 -
47.1678 - check = visitForLoad(c->expression());
47.1679 - if (!check)
47.1680 - return;
47.1681 -
47.1682 - if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
47.1683 - return;
47.1684 -
47.1685 - CaseValue v(i);
47.1686 - if (!EvaluateForConstant(c->expression(), &v.box)) {
47.1687 - cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
47.1688 - return;
47.1689 - }
47.1690 - if (!values->append(v))
47.1691 - return;
47.1692 -
47.1693 - if (c->others()) {
47.1694 - for (size_t j = 0; j < c->others()->length(); j++) {
47.1695 - Expression *expr = c->others()->at(j);
47.1696 - check = visitForLoad(expr);
47.1697 - if (!check)
47.1698 - return;
47.1699 -
47.1700 - if (!typeCheckAssignment(expr->pos(), check, caseType, false))
47.1701 - return;
47.1702 -
47.1703 - CaseValue v(i);
47.1704 - if (!EvaluateForConstant(expr, &v.box)) {
47.1705 - cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
47.1706 - return;
47.1707 - }
47.1708 - if (!values->append(v))
47.1709 - return;
47.1710 - }
47.1711 - }
47.1712 -
47.1713 - ControlStatus latest = visitForControl(c->statement());
47.1714 -
47.1715 - if (i != 0)
47.1716 - control_->merge(status, latest);
47.1717 -
47.1718 - status = latest;
47.1719 - }
47.1720 -
47.1721 - if (node->defaultCase()) {
47.1722 - ControlStatus latest = visitForControl(node->defaultCase());
47.1723 -
47.1724 - if (node->cases()->length()) {
47.1725 - // If we had any other cases, we must merge.
47.1726 - control_->merge(status, latest);
47.1727 - } else {
47.1728 - // Otherwise, control-flow always flows through here.
47.1729 - control_->inherit(latest);
47.1730 - }
47.1731 - } else if (node->cases()->length()) {
47.1732 - control_->merge(status, ControlStatus(false, Returns_Never));
47.1733 - }
47.1734 -
47.1735 - if (values->length() > 1) {
47.1736 - qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
47.1737 -
47.1738 - for (size_t i = 1; i < values->length(); i++) {
47.1739 - CaseValue &prev = values->at(i - 1);
47.1740 - CaseValue &cur = values->at(i);
47.1741 - if (prev.box.toInt() == cur.box.toInt()) {
47.1742 - cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
47.1743 - return;
47.1744 - }
47.1745 - }
47.1746 - }
47.1747 -
47.1748 - node->setCaseValueList(values);
47.1749 -}
47.1750 -
47.1751 -void
47.1752 -SemanticAnalysis::visit(StructureStatement *node)
47.1753 -{
47.1754 - // If this node already has a type, it was pre-analyzed, so skip it.
47.1755 - if (node->decl()->type())
47.1756 - return;
47.1757 -
47.1758 - FieldList *fields = node->fields();
47.1759 - Local<FixedArray> desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old));
47.1760 - if (!desctable)
47.1761 - return;
47.1762 -
47.1763 - Vector<unsigned> composedList;
47.1764 - StructureBufferBuilder builder;
47.1765 -
47.1766 - Local<Type> type(zone_);
47.1767 - Local<String> name(zone_);
47.1768 - Local<Descriptor> desc(zone_);
47.1769 - for (size_t i = 0; i < fields->length(); i++) {
47.1770 - StructureStatement::Field *field = fields->at(i);
47.1771 -
47.1772 - type = bindType(field->pos(), field->type());
47.1773 - if (!type)
47.1774 - return;
47.1775 -
47.1776 - if (field->dimensions()) {
47.1777 - type = buildArrayType(type, field->dimensions(), false);
47.1778 - if (!type)
47.1779 - return;
47.1780 -
47.1781 - if (!ArrayMap::Attach(zone_, type))
47.1782 - return;
47.1783 - }
47.1784 -
47.1785 - if (IsScalarString(type)) {
47.1786 - cc_.reportError(field->pos(), Message_CannotDeclareStringCell);
47.1787 - return;
47.1788 - }
47.1789 -
47.1790 - unsigned offset;
47.1791 - if (!builder.add(type, &offset))
47.1792 - return;
47.1793 -
47.1794 - name = field->name();
47.1795 - desc = Descriptor::New(zone_, name, type, offset);
47.1796 - if (!desc)
47.1797 - return;
47.1798 -
47.1799 - desctable->set(zone_, i, desc);
47.1800 -
47.1801 - if (type->isStruct() || type->isArray()) {
47.1802 - if (!composedList.append(i))
47.1803 - return;
47.1804 - }
47.1805 - }
47.1806 -
47.1807 - Local<FixedArray> composed(zone_);
47.1808 - if (composedList.length()) {
47.1809 - composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old);
47.1810 - if (!composed)
47.1811 - return;
47.1812 -
47.1813 - for (unsigned i = 0; i < composedList.length(); i++)
47.1814 - composed->set(zone_, i, desctable->at(i));
47.1815 - }
47.1816 -
47.1817 - Local<StructMap> map(zone_, StructMap::New(zone_, builder, composed));
47.1818 - if (!map)
47.1819 - return;
47.1820 -
47.1821 - name = node->decl()->name();
47.1822 - type = zone_->types()->newStruct(name, desctable, map);
47.1823 - if (!type)
47.1824 - return;
47.1825 -
47.1826 - map->setType(type);
47.1827 - node->decl()->setType(type);
47.1828 -}
47.1829 -
47.1830 -void
47.1831 -SemanticAnalysis::visit(StringLiteral *node)
47.1832 -{
47.1833 - Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
47.1834 - if (!type)
47.1835 - return;
47.1836 -
47.1837 - type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
47.1838 - if (!type)
47.1839 - return;
47.1840 -
47.1841 - node->setType(type);
47.1842 -}
47.1843 -
47.1844 -void
47.1845 -SemanticAnalysis::visit(FloatLiteral *node)
47.1846 -{
47.1847 - Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
47.1848 - if (!type)
47.1849 - return;
47.1850 -
47.1851 - node->setType(type);
47.1852 -}
47.1853 -
47.1854 -void
47.1855 -SemanticAnalysis::visit(BreakStatement *node)
47.1856 -{
47.1857 - if (!loop_) {
47.1858 - cc_.reportError(node->pos(), Message_BreakOutsideLoop);
47.1859 - return;
47.1860 - }
47.1861 -
47.1862 - // Note: ignore breaks that occur in unreachable control-flow.
47.1863 - if (!control_->status().terminates())
47.1864 - loop_->addBreak();
47.1865 -
47.1866 - control_->terminate(Returns_Never);
47.1867 -}
47.1868 -
47.1869 -void
47.1870 -SemanticAnalysis::visit(ContinueStatement *node)
47.1871 -{
47.1872 - if (!loop_) {
47.1873 - cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
47.1874 - return;
47.1875 - }
47.1876 -
47.1877 - // Note: ignore continues that occur in unreachable control-flow.
47.1878 - if (!control_->status().terminates())
47.1879 - loop_->addContinue();
47.1880 -
47.1881 - control_->terminate(Returns_Never);
47.1882 -}
47.1883 -
47.1884 -void
47.1885 -SemanticAnalysis::visit(ArrayLiteral *node)
47.1886 -{
47.1887 - // We should never visit this.
47.1888 - cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
47.1889 -}
47.1890 -
48.1 --- a/src/SemanticAnalysis.h Mon Sep 17 00:10:01 2012 -0700
48.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
48.3 @@ -1,236 +0,0 @@
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_semantic_analysis_h_
48.23 -#define _include_semantic_analysis_h_
48.24 -
48.25 -#include <assert.h>
48.26 -#include "AST.h"
48.27 -#include "Types.h"
48.28 -
48.29 -namespace ke {
48.30 -
48.31 -class Box;
48.32 -
48.33 -class SemanticAnalysis : public AstVisitor
48.34 -{
48.35 - Zone *zone_;
48.36 - CompileContext &cc_;
48.37 - ParseTree *tree_;
48.38 - Scope *scope_;
48.39 - NamedFunction *function_;
48.40 -
48.41 - enum ReturnStatus
48.42 - {
48.43 - Returns_Never,
48.44 - Returns_Sometimes,
48.45 - Returns_Always
48.46 - };
48.47 -
48.48 - // Tuple that describes whether a path terminates control flow, and
48.49 - // if it is guaranteed to end in a return.
48.50 - class ControlStatus
48.51 - {
48.52 - bool terminates_;
48.53 - ReturnStatus returns_;
48.54 -
48.55 - public:
48.56 - ControlStatus(bool terminates, ReturnStatus returns)
48.57 - : terminates_(terminates),
48.58 - returns_(returns)
48.59 - {
48.60 - }
48.61 -
48.62 - bool terminates() const {
48.63 - return terminates_;
48.64 - }
48.65 - ReturnStatus returns() const {
48.66 - return returns_;
48.67 - }
48.68 - };
48.69 -
48.70 - // Used to keep track of terminating control flow and return statements
48.71 - // inside control structures.
48.72 - class ControlScope
48.73 - {
48.74 - ReturnStatus returns_;
48.75 - ControlScope **prevp_;
48.76 - ControlScope *prev_;
48.77 - bool terminates_;
48.78 -
48.79 - public:
48.80 - ControlScope(ControlScope **prev)
48.81 - : returns_(Returns_Never),
48.82 - prevp_(prev),
48.83 - prev_(*prev),
48.84 - terminates_(false)
48.85 - {
48.86 - *prevp_ = this;
48.87 - }
48.88 -
48.89 - ControlStatus status() const {
48.90 - return ControlStatus(terminates_, returns_);
48.91 - }
48.92 -
48.93 - // We allow multiple terminators, but only the first one takes effect.
48.94 - // For example, |break; continue;| is legal but the continue is
48.95 - // unreachable.
48.96 - void returns(ReturnStatus status) {
48.97 - if (terminates_)
48.98 - return;
48.99 - if (status > returns_)
48.100 - returns_ = status;
48.101 - }
48.102 - void terminate(ReturnStatus status) {
48.103 - if (terminates_)
48.104 - return;
48.105 - terminates_ = true;
48.106 - returns_ = status;
48.107 - }
48.108 - void merge(const ControlStatus &left, const ControlStatus &right);
48.109 - void inherit(const ControlStatus &other);
48.110 -
48.111 - ~ControlScope()
48.112 - {
48.113 - *prevp_ = prev_;
48.114 - }
48.115 - };
48.116 -
48.117 - class LoopScope
48.118 - {
48.119 - LoopScope **prevp_;
48.120 - LoopScope *prev_;
48.121 - unsigned breaks_;
48.122 - unsigned continues_;
48.123 -
48.124 - public:
48.125 - LoopScope(LoopScope **prev)
48.126 - : prevp_(prev),
48.127 - prev_(*prev),
48.128 - breaks_(0),
48.129 - continues_(0)
48.130 - {
48.131 - *prevp_ = this;
48.132 - }
48.133 -
48.134 - ~LoopScope()
48.135 - {
48.136 - *prevp_ = prev_;
48.137 - }
48.138 -
48.139 - void addBreak() {
48.140 - breaks_++;
48.141 - }
48.142 - void addContinue() {
48.143 - continues_++;
48.144 - }
48.145 - unsigned breaks() const {
48.146 - return breaks_;
48.147 - }
48.148 - unsigned continues() const {
48.149 - return continues_;
48.150 - }
48.151 - };
48.152 -
48.153 - ControlScope *control_;
48.154 - LoopScope *loop_;
48.155 -
48.156 - private:
48.157 - bool canTest(AstNode *node, Handle<Type> type);
48.158 - void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
48.159 - void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
48.160 - void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
48.161 - Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
48.162 -
48.163 - Type *bindType(const SourcePosition &pos, BoundName *name);
48.164 -
48.165 - // These check if one type is compatible with another type, for various
48.166 - // purposes, like:
48.167 - // return (expr) matches function return type
48.168 - // call(a, b) matches expected arg type
48.169 - // a = b matches declared type
48.170 - //
48.171 - bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
48.172 - bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
48.173 - bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
48.174 -
48.175 - Type *visitForLoad(Expression *expression);
48.176 - bool preanalyze(FunctionStatement *node);
48.177 - Type *visitForLValue(Expression *expression);
48.178 - Type *visitAndApplyType(Expression *expression);
48.179 - ControlStatus visitForControl(Statement *statement);
48.180 -
48.181 - bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
48.182 - bool inferFixedArrayLiteral(ArrayLiteral *literal,
48.183 - Handle<Type> type,
48.184 - int dims[MAX_ARRAY_DEPTH],
48.185 - unsigned dimcount,
48.186 - unsigned level);
48.187 -
48.188 - // Builds an array type used for parameters, returns, or field entries.
48.189 - Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
48.190 -
48.191 - Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
48.192 - bool checkArgumentCount(Handle<Type> type, unsigned actual);
48.193 - bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
48.194 - FixedArray **args, FixedArray **defaults);
48.195 -
48.196 - void markCallResultUsed(CallExpression *call);
48.197 -
48.198 - bool determineLiveFunctions();
48.199 -
48.200 - public:
48.201 - SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
48.202 - bool analyze();
48.203 -
48.204 - public:
48.205 - void visit(NameProxy *name);
48.206 - void visit(Assignment *node);
48.207 - void visit(BinaryExpression *node);
48.208 - void visit(ReturnStatement *node);
48.209 - void visit(ForStatement *node);
48.210 - void visit(BlockStatement *node);
48.211 - void visit(VariableDeclaration *node);
48.212 - void visit(IntegerLiteral *node);
48.213 - void visit(ExpressionStatement *node);
48.214 - void visit(FunctionStatement *node);
48.215 - void visit(CallExpression *node);
48.216 - void visit(IfStatement *node);
48.217 - void visit(IndexExpression *node);
48.218 - void visit(EnumStatement *node);
48.219 - void visit(FloatLiteral *node);
48.220 - void visit(WhileStatement *node);
48.221 - void visit(BreakStatement *node);
48.222 - void visit(ContinueStatement *node);
48.223 - void visit(StringLiteral *node);
48.224 - void visit(IncDecExpression *node);
48.225 - void visit(UnaryExpression *node);
48.226 - void visit(TernaryExpression *node);
48.227 - void visit(BooleanLiteral *node);
48.228 - void visit(StructureStatement *node);
48.229 - void visit(FieldExpression *node);
48.230 - void visit(SwitchStatement *node);
48.231 - void visit(FunctionTypeStatement *node);
48.232 - void visit(ArrayLiteral *node);
48.233 -};
48.234 -
48.235 -const char *GetTypeName(Type *type);
48.236 -
48.237 -} // namespace ke
48.238 -
48.239 -#endif // _include_semantic_analysis_h_
49.1 --- a/src/Stack.cpp Mon Sep 17 00:10:01 2012 -0700
49.2 +++ b/src/Stack.cpp Sat Nov 17 18:41:01 2012 -0800
49.3 @@ -23,6 +23,7 @@
49.4 #include "Zone.h"
49.5 #include "Strings.h"
49.6 #include "Modules.h"
49.7 +#include "NativeTable.h"
49.8 #include "Heap-inl.h"
49.9
49.10 using namespace ke;
49.11 @@ -286,7 +287,7 @@
49.12 StackIter::function() const
49.13 {
49.14 if (fp_->isNative())
49.15 - return fp_->native()->name()->chars();
49.16 + return ZONE()->nativeTable()->name(fp_->native()->index())->chars();
49.17 if (Function *fun = fp_->maybeFun())
49.18 return fun->name()->chars();
49.19 return "<toplevel>";
50.1 --- a/src/StringPool.h Mon Sep 17 00:10:01 2012 -0700
50.2 +++ b/src/StringPool.h Sat Nov 17 18:41:01 2012 -0800
50.3 @@ -1,19 +1,20 @@
50.4 -/*
50.5 +/* vim: set ts=4 sw=4 tw=99 et:
50.6 + *
50.7 * Copyright (C) 2012 David Anderson
50.8 *
50.9 - * This file is part of JITCraft.
50.10 + * This file is part of SourcePawn.
50.11 *
50.12 - * JITCraft is free software: you can redistribute it and/or modify it under
50.13 + * SourcePawn is free software: you can redistribute it and/or modify it under
50.14 * the terms of the GNU General Public License as published by the Free
50.15 * Software Foundation, either version 3 of the License, or (at your option)
50.16 * any later version.
50.17 *
50.18 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
50.19 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
50.20 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
50.21 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
50.22 *
50.23 * You should have received a copy of the GNU General Public License along with
50.24 - * JITCraft. If not, see http://www.gnu.org/licenses/.
50.25 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
50.26 */
50.27 #ifndef _include_jitcraft_string_pool_h_
50.28 #define _include_jitcraft_string_pool_h_
50.29 @@ -31,25 +32,6 @@
50.30 // Guarantee that strings with the same contents will map to one pointer.
50.31 class StringPool
50.32 {
50.33 - class CharsAndLength {
50.34 - const char *str_;
50.35 - size_t length_;
50.36 -
50.37 - public:
50.38 - CharsAndLength(const char *str, size_t length)
50.39 - : str_(str),
50.40 - length_(length)
50.41 - {
50.42 - }
50.43 -
50.44 - const char *str() const {
50.45 - return str_;
50.46 - }
50.47 - size_t length() const {
50.48 - return length_;
50.49 - }
50.50 - };
50.51 -
50.52 struct Policy
50.53 {
50.54 typedef String * Payload;
51.1 --- a/src/Strings.h Mon Sep 17 00:10:01 2012 -0700
51.2 +++ b/src/Strings.h Sat Nov 17 18:41:01 2012 -0800
51.3 @@ -52,6 +52,26 @@
51.4 }
51.5 };
51.6
51.7 +class CharsAndLength
51.8 +{
51.9 + const char *str_;
51.10 + size_t length_;
51.11 +
51.12 + public:
51.13 + CharsAndLength(const char *str, size_t length)
51.14 + : str_(str),
51.15 + length_(length)
51.16 + {
51.17 + }
51.18 +
51.19 + const char *str() const {
51.20 + return str_;
51.21 + }
51.22 + size_t length() const {
51.23 + return length_;
51.24 + }
51.25 +};
51.26 +
51.27 }
51.28
51.29 #endif // _include_jitcraft_string_h_
52.1 --- a/src/Structures.cpp Mon Sep 17 00:10:01 2012 -0700
52.2 +++ b/src/Structures.cpp Sat Nov 17 18:41:01 2012 -0800
52.3 @@ -51,7 +51,7 @@
52.4 }
52.5
52.6 Descriptor *
52.7 -Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type, unsigned offset)
52.8 +Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type)
52.9 {
52.10 Local<Descriptor> desc(zone,
52.11 Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old)));
52.12 @@ -60,13 +60,31 @@
52.13
52.14 desc->name_ = name;
52.15 desc->type_ = type;
52.16 - desc->offset_ = offset;
52.17 + desc->offset_ = unsigned(-1);
52.18 return desc;
52.19 }
52.20
52.21 StructMap *
52.22 -StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<FixedArray> composed)
52.23 +StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
52.24 {
52.25 + Vector<unsigned> composedIndexes;
52.26 + for (size_t i = 0; i < type->fields()->length(); i++) {
52.27 + Descriptor *desc = Descriptor::cast(type->fields()->at(i));
52.28 + if (desc->type()->isArray() || desc->type()->isStruct()) {
52.29 + if (!composedIndexes.append(i))
52.30 + return NULL;
52.31 + }
52.32 + }
52.33 +
52.34 + Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
52.35 + if (!composed)
52.36 + return NULL;
52.37 +
52.38 + for (size_t i = 0; i < composedIndexes.length(); i++) {
52.39 + Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
52.40 + composed->set(zone, i, desc);
52.41 + }
52.42 +
52.43 size_t bytesNeeded = sizeof(StructMap) +
52.44 (builder.traceableOffsetCount() * sizeof(unsigned));
52.45
52.46 @@ -77,7 +95,7 @@
52.47
52.48 map->structureSize_ = builder.structureSize();
52.49 map->traceOffsetCount_ = builder.traceableOffsetCount();
52.50 - map->type_ = NULL;
52.51 + map->type_ = type;
52.52 map->composed_ = composed;
52.53 memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
52.54 sizeof(unsigned) * builder.traceableOffsetCount());
52.55 @@ -107,14 +125,17 @@
52.56 desc = Descriptor::cast(map->composed()->at(i));
52.57
52.58 if (desc->type()->isStruct()) {
52.59 - childStructMap = StructMap::cast(desc->type()->newMap());
52.60 + childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
52.61 child = Struct::New(zone, childStructMap, tenure);
52.62 } else if (desc->type()->isArray()) {
52.63 + assert(false);
52.64 +#if 0
52.65 childArrayMap = ArrayMap::cast(desc->type()->newMap());
52.66 if (desc->type()->isFixedLength())
52.67 child = Array::NewFixed(zone, childArrayMap, tenure);
52.68 else
52.69 child = Array::NewEmpty(zone, childArrayMap, tenure);
52.70 +#endif
52.71 }
52.72 if (!child)
52.73 return NULL;
53.1 --- a/src/Structures.h Mon Sep 17 00:10:01 2012 -0700
53.2 +++ b/src/Structures.h Sat Nov 17 18:41:01 2012 -0800
53.3 @@ -29,6 +29,7 @@
53.4 class Type;
53.5 class String;
53.6 class FixedArray;
53.7 +class StructType;
53.8
53.9 // When describing composite structures, the GC must be able to trace interior
53.10 // references to Objects. To make this possible, maps that describe composite
53.11 @@ -69,8 +70,7 @@
53.12 unsigned offset_;
53.13
53.14 public:
53.15 - static Descriptor *New(Zone *zone, Handle<String> name, Handle<Type> type,
53.16 - unsigned offset);
53.17 + static Descriptor *New(Zone *zone, Handle<String> name, Handle<Type> type);
53.18
53.19 String *name() {
53.20 return name_;
53.21 @@ -79,8 +79,13 @@
53.22 return type_;
53.23 }
53.24 unsigned offset() {
53.25 + assert(offset_ != unsigned(-1));
53.26 return offset_;
53.27 }
53.28 + void setOffset(unsigned offset) {
53.29 + assert(offset_ == unsigned(-1));
53.30 + offset_ = offset;
53.31 + }
53.32
53.33 // Begin GC descriptor.
53.34 static inline size_t offsetOfName() {
53.35 @@ -101,13 +106,13 @@
53.36 {
53.37 unsigned structureSize_;
53.38 unsigned traceOffsetCount_;
53.39 - Barriered<Type> type_;
53.40 + Barriered<StructType> type_;
53.41
53.42 // List of descriptors which must be allocated upon initialization.
53.43 Barriered<FixedArray> composed_;
53.44
53.45 public:
53.46 - static StructMap *New(Zone *zone, const StructureBufferBuilder &builder, Handle<FixedArray> composed);
53.47 + static StructMap *New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type);
53.48
53.49 unsigned structureSize() {
53.50 return structureSize_;
53.51 @@ -121,14 +126,14 @@
53.52 size_t objSize() {
53.53 return sizeof(StructMap) + sizeof(unsigned) * traceOffsetCount();
53.54 }
53.55 - Type *type() {
53.56 + StructType *type() {
53.57 return type_;
53.58 }
53.59 FixedArray *composed() {
53.60 return composed_;
53.61 }
53.62
53.63 - void setType(Type *type) {
53.64 + void setType(StructType *type) {
53.65 assert(!type_);
53.66 type_ = type;
53.67 }
54.1 --- a/src/Token.h Mon Sep 17 00:10:01 2012 -0700
54.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
54.3 @@ -1,144 +0,0 @@
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 -#ifndef _include_jitcraft_token_h_
54.23 -#define _include_jitcraft_token_h_
54.24 -
54.25 -namespace ke {
54.26 -
54.27 -struct SourcePosition
54.28 -{
54.29 - int line;
54.30 - int col;
54.31 -
54.32 - SourcePosition()
54.33 - : line(-1),
54.34 - col(-1)
54.35 - {
54.36 - }
54.37 -
54.38 - SourcePosition(unsigned line, unsigned col)
54.39 - : line(line),
54.40 - col(col)
54.41 - {
54.42 - }
54.43 -};
54.44 -
54.45 -// List of tokens the scanner can recognize.
54.46 -//
54.47 -// Some restrictions:
54.48 -// * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
54.49 -// op-and-assign equivalent.
54.50 -#define TOKENMAP(_) \
54.51 - _(NONE, "<none>") \
54.52 - _(ERROR, "<error>") \
54.53 - _(NEW, "'new'") \
54.54 - _(FOR, "'for'") \
54.55 - _(RETURN, "'return'") \
54.56 - _(NAME, "<name>") \
54.57 - _(INTEGER_LITERAL, "<integer>") \
54.58 - _(HEX_LITERAL, "<hex>") \
54.59 - _(FLOAT_LITERAL, "<float>") \
54.60 - _(STRING_LITERAL, "<string>") \
54.61 - _(IF, "<if>") \
54.62 - _(ELSE, "<else>") \
54.63 - _(ENUM, "<enum>") \
54.64 - _(LABEL, "<label>") \
54.65 - _(WHILE, "<while>") \
54.66 - _(DO, "<do>") \
54.67 - _(BREAK, "<break>") \
54.68 - _(CONTINUE, "<continue>") \
54.69 - _(FORWARD, "<forward>") \
54.70 - _(PUBLIC, "<public>") \
54.71 - _(CONST, "<const>") \
54.72 - _(NATIVE, "<native>") \
54.73 - _(STOCK, "<stock>") \
54.74 - _(TRUE, "<true>") \
54.75 - _(FALSE, "<false>") \
54.76 - _(STRUCT, "<struct>") \
54.77 - _(SWITCH, "<switch>") \
54.78 - _(CASE, "<case>") \
54.79 - _(DEFAULT, "<default>") \
54.80 - _(TYPEDEF, "<typedef>") \
54.81 - _(VOID, "<void>") \
54.82 - _(INT, "<int>") \
54.83 - _(SIZEOF, "<sizeof>") \
54.84 - _(ELLIPSES, "...") \
54.85 - _(PLUS, "+") \
54.86 - _(MINUS, "-") \
54.87 - _(STAR, "*") \
54.88 - _(SLASH, "/") \
54.89 - _(PERCENT, "%") \
54.90 - _(AMPERSAND, "&") \
54.91 - _(BITOR, "|") \
54.92 - _(BITXOR, "^") \
54.93 - _(SHR, ">>") \
54.94 - _(USHR, ">>>") \
54.95 - _(SHL, "<<") \
54.96 - _(ASSIGN, "=") \
54.97 - _(SEMICOLON, ";") \
54.98 - _(LBRACE, "{") \
54.99 - _(RBRACE, "}") \
54.100 - _(LPAREN, "(") \
54.101 - _(RPAREN, ")") \
54.102 - _(LBRACKET, "[") \
54.103 - _(RBRACKET, "]") \
54.104 - _(ASSIGN_ADD, "+=") \
54.105 - _(ASSIGN_SUB, "-=") \
54.106 - _(ASSIGN_MUL, "*=") \
54.107 - _(ASSIGN_DIV, "/=") \
54.108 - _(ASSIGN_MOD, "%=") \
54.109 - _(ASSIGN_BITAND, "&=") \
54.110 - _(ASSIGN_BITOR, "|=") \
54.111 - _(ASSIGN_BITXOR, "^=") \
54.112 - _(ASSIGN_SHR, ">>=") \
54.113 - _(ASSIGN_USHR, ">>>=") \
54.114 - _(ASSIGN_SHL, "<<=") \
54.115 - _(INCREMENT, "++") \
54.116 - _(DECREMENT, "--") \
54.117 - _(EQUALS, "==") \
54.118 - _(NOTEQUALS, "!=") \
54.119 - _(LT, "<") \
54.120 - _(LE, "<=") \
54.121 - _(GT, ">") \
54.122 - _(GE, ">=") \
54.123 - _(AND, "&&") \
54.124 - _(OR, "||") \
54.125 - _(COMMA, ",") \
54.126 - _(NOT, "!") \
54.127 - _(TILDE, "~") \
54.128 - _(QMARK, "?") \
54.129 - _(COLON, ":") \
54.130 - _(UNDERSCORE, "_") \
54.131 - _(DOT, ".") \
54.132 - _(EOF, "<end-of-file>")
54.133 -
54.134 -enum TokenKind
54.135 -{
54.136 -# define _(name, str) TOK_##name,
54.137 - TOKENMAP(_)
54.138 -# undef _
54.139 - TOK_BITAND = TOK_AMPERSAND,
54.140 - TOKENS_TOTAL
54.141 -};
54.142 -
54.143 -extern const char *TokenNames[];
54.144 -
54.145 -} // namespace ke
54.146 -
54.147 -#endif //_include_jitcraft_token_h_
55.1 --- a/src/TypeManager.cpp Mon Sep 17 00:10:01 2012 -0700
55.2 +++ b/src/TypeManager.cpp Sat Nov 17 18:41:01 2012 -0800
55.3 @@ -88,33 +88,11 @@
55.4 }
55.5
55.6 Type *
55.7 -TypeManager::newFunction(Handle<Type> returnType, Handle<FixedArray> args,
55.8 - Handle<FixedArray> defaults)
55.9 -{
55.10 - // :TODO: cache this.
55.11 - return Type::NewFunction(zone_, returnType, args, defaults);
55.12 -}
55.13 -
55.14 -Type *
55.15 -TypeManager::newNative(Handle<Type> returnType, Handle<FixedArray> args,
55.16 - Handle<FixedArray> defaults, bool variadic)
55.17 -{
55.18 - // :TODO: cache this.
55.19 - return Type::NewNative(zone_, returnType, args, defaults, variadic);
55.20 -}
55.21 -
55.22 -Type *
55.23 TypeManager::newEnum(Handle<String> name)
55.24 {
55.25 return Type::NewEnum(zone_, name);
55.26 }
55.27
55.28 -Type *
55.29 -TypeManager::newStruct(Handle<String> name, Handle<FixedArray> fields, Handle<Map> newMap)
55.30 -{
55.31 - return Type::NewStruct(zone_, name, fields, newMap);
55.32 -}
55.33 -
55.34 void
55.35 TypeManager::accept(VirtualObjectVisitor *visitor)
55.36 {
56.1 --- a/src/TypeManager.h Mon Sep 17 00:10:01 2012 -0700
56.2 +++ b/src/TypeManager.h Sat Nov 17 18:41:01 2012 -0800
56.3 @@ -56,11 +56,6 @@
56.4 Type *newArray(Handle<Type> contained, int elements, bool isConst);
56.5 Type *newExternalArray(Handle<Type> contained);
56.6 Type *newEnum(Handle<String> name);
56.7 - Type *newFunction(Handle<Type> returnType, Handle<FixedArray> args,
56.8 - Handle<FixedArray> deafults);
56.9 - Type *newNative(Handle<Type> returnType, Handle<FixedArray> args,
56.10 - Handle<FixedArray> defaults, bool variadic);
56.11 - Type *newStruct(Handle<String> name, Handle<FixedArray> fields, Handle<Map> newMap);
56.12
56.13 void accept(VirtualObjectVisitor *visitor);
56.14 };
57.1 --- a/src/Types.cpp Mon Sep 17 00:10:01 2012 -0700
57.2 +++ b/src/Types.cpp Sat Nov 17 18:41:01 2012 -0800
57.3 @@ -34,11 +34,6 @@
57.4
57.5 type->kind_ = VOID;
57.6 type->contained_ = NULL;
57.7 - type->returnType_ = NULL;
57.8 - type->parameters_ = NULL;
57.9 - type->defaults_ = NULL;
57.10 - type->fields_ = NULL;
57.11 - type->newMap_ = NULL;
57.12 return type;
57.13 }
57.14
57.15 @@ -51,11 +46,6 @@
57.16
57.17 type->kind_ = UNCHECKED;
57.18 type->contained_ = NULL;
57.19 - type->returnType_ = NULL;
57.20 - type->parameters_ = NULL;
57.21 - type->defaults_ = NULL;
57.22 - type->fields_ = NULL;
57.23 - type->newMap_ = NULL;
57.24 return type;
57.25 }
57.26
57.27 @@ -69,12 +59,6 @@
57.28 type->kind_ = PRIMITIVE;
57.29 type->name_ = NULL;
57.30 type->contained_ = NULL;
57.31 - type->returnType_ = NULL;
57.32 - type->parameters_ = NULL;
57.33 - type->defaults_ = NULL;
57.34 - type->fields_ = NULL;
57.35 - type->newMap_ = NULL;
57.36 - type->newMap_ = NULL;
57.37 type->primitive_ = prim;
57.38 return type;
57.39 }
57.40 @@ -89,11 +73,6 @@
57.41 type->kind_ = ARRAY;
57.42 type->name_ = NULL;
57.43 type->contained_ = contained;
57.44 - type->returnType_ = NULL;
57.45 - type->parameters_ = NULL;
57.46 - type->defaults_ = NULL;
57.47 - type->fields_ = NULL;
57.48 - type->newMap_ = NULL;
57.49 type->elements_ = elements;
57.50 if (!contained->isArray())
57.51 type->levels_ = 1;
57.52 @@ -115,11 +94,6 @@
57.53 type->kind_ = EXTERNAL_ARRAY;
57.54 type->name_ = NULL;
57.55 type->contained_ = contained;
57.56 - type->returnType_ = NULL;
57.57 - type->parameters_ = NULL;
57.58 - type->defaults_ = NULL;
57.59 - type->fields_ = NULL;
57.60 - type->newMap_ = NULL;
57.61 type->elements_ = DYNAMIC_ARRAY_SIZE;
57.62 type->levels_ = 1;
57.63 type->const_ = false;
57.64 @@ -136,35 +110,11 @@
57.65 type->kind_ = REFERENCE;
57.66 type->name_ = NULL;
57.67 type->contained_ = contained;
57.68 - type->returnType_ = NULL;
57.69 - type->parameters_ = NULL;
57.70 - type->defaults_ = NULL;
57.71 - type->fields_ = NULL;
57.72 - type->newMap_ = NULL;
57.73 type->const_ = isConst;
57.74 return type;
57.75 }
57.76
57.77 Type *
57.78 -Type::NewFunction(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
57.79 - Handle<FixedArray> defaults)
57.80 -{
57.81 - Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
57.82 - if (!type)
57.83 - return NULL;
57.84 -
57.85 - type->kind_ = FUNCTION;
57.86 - type->name_ = NULL;
57.87 - type->contained_ = NULL;
57.88 - type->fields_ = NULL;
57.89 - type->newMap_ = NULL;
57.90 - type->returnType_ = returnType;
57.91 - type->parameters_ = parameters;
57.92 - type->defaults_ = defaults;
57.93 - return type;
57.94 -}
57.95 -
57.96 -Type *
57.97 Type::NewEnum(Zone *zone, Handle<String> name)
57.98 {
57.99 Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
57.100 @@ -174,32 +124,10 @@
57.101 type->kind_ = ENUM;
57.102 type->name_ = name;
57.103 type->contained_ = NULL;
57.104 - type->returnType_ = NULL;
57.105 - type->parameters_ = NULL;
57.106 - type->defaults_ = NULL;
57.107 - type->fields_ = NULL;
57.108 - type->newMap_ = NULL;
57.109 return type;
57.110 }
57.111
57.112 -Type *
57.113 -Type::NewStruct(Zone *zone, Handle<String> name, Handle<FixedArray> fields, Handle<Map> newMap)
57.114 -{
57.115 - Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
57.116 - if (!type)
57.117 - return NULL;
57.118 -
57.119 - type->kind_ = STRUCT;
57.120 - type->name_ = name;
57.121 - type->contained_ = NULL;
57.122 - type->returnType_ = NULL;
57.123 - type->parameters_ = NULL;
57.124 - type->defaults_ = NULL;
57.125 - type->newMap_ = newMap;
57.126 - type->fields_ = fields;
57.127 - return type;
57.128 -}
57.129 -
57.130 +#if 0
57.131 Type *
57.132 Type::NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
57.133 Handle<FixedArray> defaults, bool variadic)
57.134 @@ -219,6 +147,7 @@
57.135 type->variadicNative_ = variadic;
57.136 return type;
57.137 }
57.138 +#endif
57.139
57.140 bool
57.141 Type::Compare(Type *left, Type *right)
57.142 @@ -244,17 +173,19 @@
57.143
57.144 case Type::FUNCTION:
57.145 {
57.146 - if (!Compare(left->returnType(), right->returnType()))
57.147 + FunctionType *fleft = FunctionType::cast(left);
57.148 + FunctionType *fright = FunctionType::cast(right);
57.149 + if (!Compare(fleft->returnType(), fright->returnType()))
57.150 return false;
57.151 - if (left->parameters()->length() != right->parameters()->length())
57.152 - return false;
57.153 - if (left->isNative() != right->isNative())
57.154 + if (fleft->parameters()->length() != fright->parameters()->length())
57.155 return false;
57.156 - if (left->isNative() && (left->isNativeVariadic() != right->isNativeVariadic()))
57.157 + if (fleft->isNative() != fright->isNative())
57.158 + return false;
57.159 + if (fleft->isNative() && (fleft->isNativeVariadic() != fright->isNativeVariadic()))
57.160 return false;
57.161 - for (unsigned i = 0; i < left->parameters()->length(); i++) {
57.162 - Type *leftparam = left->parameterAt(i);
57.163 - Type *rightparam = right->parameterAt(i);
57.164 + for (unsigned i = 0; i < fleft->parameters()->length(); i++) {
57.165 + Type *leftparam = fleft->parameterAt(i);
57.166 + Type *rightparam = fright->parameterAt(i);
57.167 if (!Compare(leftparam, rightparam))
57.168 return false;
57.169 }
57.170 @@ -273,15 +204,50 @@
57.171 }
57.172 }
57.173
57.174 -Descriptor *
57.175 -Type::lookupField(Handle<String> name, unsigned *index)
57.176 +
57.177 +StructType *
57.178 +StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
57.179 {
57.180 - assert(isStruct());
57.181 + Local<StructType> type(zone, StructType::cast(zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old)));
57.182 + if (!type)
57.183 + return NULL;
57.184 +
57.185 + type->kind_ = STRUCT;
57.186 + type->name_ = name;
57.187 + type->contained_ = NULL;
57.188 + type->newMap_ = NULL;
57.189 + type->fields_ = fields;
57.190 +
57.191 + // Fill in field offsets.
57.192 + StructureBufferBuilder builder;
57.193 + Local<Type> fieldType(zone);
57.194 + for (size_t i = 0; i < fields->length(); i++) {
57.195 + Descriptor *desc = Descriptor::cast(fields->at(i));
57.196 + fieldType = desc->type();
57.197
57.198 + unsigned offset;
57.199 + if (!builder.add(fieldType, &offset))
57.200 + return NULL;
57.201 + desc->setOffset(offset);
57.202 + }
57.203 +
57.204 + Local<StructMap> map(zone, StructMap::New(zone, builder, type));
57.205 + if (!map)
57.206 + return NULL;
57.207 +
57.208 + type->newMap_ = map;
57.209 +
57.210 + return type;
57.211 +}
57.212 +
57.213 +Descriptor *
57.214 +StructType::lookupField(Handle<String> name, unsigned *index)
57.215 +{
57.216 for (unsigned i = 0; i < fields_->length(); i++) {
57.217 Descriptor *desc = Descriptor::cast(fields_->at(i));
57.218 if (desc->name() == name) {
57.219 - *index = i;
57.220 + if (index)
57.221 + *index = i;
57.222 return desc;
57.223 }
57.224 }
57.225 @@ -289,3 +255,48 @@
57.226 return NULL;
57.227 }
57.228
57.229 +FunctionType *
57.230 +FunctionType::New(Zone *zone, TokenKind token)
57.231 +{
57.232 + Local<FunctionType> type(zone, FunctionType::cast(zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old)));
57.233 + if (!type)
57.234 + return NULL;
57.235 +
57.236 + type->kind_ = FUNCTION;
57.237 + type->name_ = NULL;
57.238 + type->contained_ = NULL;
57.239 + type->parameters_ = NULL;
57.240 + type->defaults_ = NULL;
57.241 + type->returnType_ = NULL;
57.242 + type->token_ = token;
57.243 + return type;
57.244 +}
57.245 +
57.246 +// :TODO: this leaks an interior pointer.
57.247 +const char *
57.248 +ke::GetTypeName(Type *type)
57.249 +{
57.250 + if (type->isArray())
57.251 + return "array";
57.252 + if (type->isFunction())
57.253 + return "function";
57.254 + if (type->isVoid())
57.255 + return "void";
57.256 + if (type->isEnum() || type->isStruct())
57.257 + return type->name()->chars();
57.258 + if (type->isReference())
57.259 + type = type->contained();
57.260 + switch (type->primitive()) {
57.261 + case PrimitiveType_Bool:
57.262 + return "bool";
57.263 + case PrimitiveType_Char:
57.264 + return "String";
57.265 + case PrimitiveType_Int32:
57.266 + return "int";
57.267 + case PrimitiveType_Float:
57.268 + return "Float";
57.269 + default:
57.270 + return "<unknown>";
57.271 + }
57.272 +}
57.273 +
58.1 --- a/src/Types.h Mon Sep 17 00:10:01 2012 -0700
58.2 +++ b/src/Types.h Sat Nov 17 18:41:01 2012 -0800
58.3 @@ -22,11 +22,13 @@
58.4 #include "Heap.h"
58.5 #include "Barriers.h"
58.6 #include "FixedArray.h"
58.7 +#include "compiler/Token.h"
58.8
58.9 namespace ke {
58.10
58.11 class String;
58.12 class Descriptor;
58.13 +class StructMap;
58.14
58.15 #define MAX_ARRAY_DEPTH 5
58.16
58.17 @@ -59,6 +61,7 @@
58.18
58.19 class Type : public Object
58.20 {
58.21 + protected:
58.22 enum Kind {
58.23 // A primitive is a plain-old-data type.
58.24 PRIMITIVE,
58.25 @@ -74,9 +77,6 @@
58.26 // A function type encapsulates a function signature.
58.27 FUNCTION,
58.28
58.29 - // A native is a limited type of function used for system calls.
58.30 - NATIVE,
58.31 -
58.32 // Void is an internal type used to specify that a function returns no
58.33 // value.
58.34 VOID,
58.35 @@ -108,17 +108,15 @@
58.36 static Type *NewArray(Zone *zone, Handle<Type> contained, int elements, bool isConst);
58.37 static Type *NewExternalArray(Zone *zone, Handle<Type> contained);
58.38 static Type *NewReference(Zone *zone, Handle<Type> contained, bool isConst);
58.39 - static Type *NewFunction(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
58.40 - Handle<FixedArray> defaults);
58.41 - static Type *NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
58.42 - Handle<FixedArray> defaults, bool isVariadic);
58.43 static Type *NewEnum(Zone *zone, Handle<String> name);
58.44 - static Type *NewStruct(Zone *zone, Handle<String> name, Handle<FixedArray> fields, Handle<Map> newMap);
58.45
58.46 static bool Compare(Type *left, Type *right);
58.47
58.48 static Type *cast(Object *obj) {
58.49 - assert(!obj || obj->is(MapKind_Type));
58.50 + assert(!obj ||
58.51 + obj->is(MapKind_Type) ||
58.52 + obj->is(MapKind_FunctionType) ||
58.53 + obj->is(MapKind_StructType));
58.54 return (Type *)obj;
58.55 }
58.56
58.57 @@ -132,10 +130,7 @@
58.58 return kind() == REFERENCE;
58.59 }
58.60 bool isFunction() {
58.61 - return kind() == FUNCTION || kind() == NATIVE;
58.62 - }
58.63 - bool isNative() {
58.64 - return kind() == NATIVE;
58.65 + return kind() == FUNCTION;
58.66 }
58.67 bool isVoid() {
58.68 return kind() == VOID;
58.69 @@ -146,10 +141,6 @@
58.70 bool isStruct() {
58.71 return kind() == STRUCT;
58.72 }
58.73 - bool isNativeVariadic() {
58.74 - assert(isNative());
58.75 - return variadicNative_;
58.76 - }
58.77 PrimitiveType primitive() {
58.78 assert(isPrimitive());
58.79 return primitive_;
58.80 @@ -216,21 +207,6 @@
58.81 bool isExternalArray() {
58.82 return kind() == EXTERNAL_ARRAY;
58.83 }
58.84 - Type *returnType() {
58.85 - assert(isFunction());
58.86 - return returnType_;
58.87 - }
58.88 - FixedArray *parameters() {
58.89 - assert(isFunction());
58.90 - return parameters_;
58.91 - }
58.92 - FixedArray *defaults() {
58.93 - assert(isFunction());
58.94 - return defaults_;
58.95 - }
58.96 - Type *parameterAt(size_t i) {
58.97 - return Type::cast(parameters()->at(i));
58.98 - }
58.99 bool isTraceable() {
58.100 return !isPrimitive();
58.101 }
58.102 @@ -248,47 +224,25 @@
58.103 assert(isEnum() || isStruct());
58.104 return name_;
58.105 }
58.106 - FixedArray *fields() {
58.107 - assert(isStruct());
58.108 - return fields_;
58.109 +
58.110 + Map *newMap() {
58.111 + assert(false);
58.112 + return NULL;
58.113 }
58.114 - Descriptor *lookupField(Handle<String> name, unsigned *index);
58.115 -
58.116 - // Objects of this type can be created with this cached map.
58.117 - Map *newMap() {
58.118 - assert(isStruct() || isArray());
58.119 - return newMap_;
58.120 - }
58.121 - void setNewMap(Map *map) {
58.122 - assert(!newMap());
58.123 - newMap_ = map;
58.124 + void setNewMap(void *p) {
58.125 + assert(false);
58.126 }
58.127
58.128 // GC Descriptor.
58.129 static inline size_t offsetOfContained() {
58.130 return OFFSETOF(Type, contained_);
58.131 }
58.132 - static inline size_t offsetOfReturnType() {
58.133 - return OFFSETOF(Type, returnType_);
58.134 - }
58.135 - static inline size_t offsetOfParameters() {
58.136 - return OFFSETOF(Type, parameters_);
58.137 - }
58.138 static inline size_t offsetOfName() {
58.139 return OFFSETOF(Type, name_);
58.140 }
58.141 - static inline size_t offsetOfFields() {
58.142 - return OFFSETOF(Type, fields_);
58.143 - }
58.144 - static inline size_t offsetOfNewMap() {
58.145 - return OFFSETOF(Type, newMap_);
58.146 - }
58.147 - static inline size_t offsetOfDefaults() {
58.148 - return OFFSETOF(Type, defaults_);
58.149 - }
58.150 // End GC Descriptor.
58.151
58.152 - private:
58.153 + protected:
58.154 Kind kind_;
58.155 PrimitiveType primitive_;
58.156
58.157 @@ -302,18 +256,116 @@
58.158 // Arrays and references only.
58.159 Barriered<Type> contained_;
58.160
58.161 + // Enums and structs only.
58.162 + Barriered<String> name_;
58.163 +};
58.164 +
58.165 +class StructType : public Type
58.166 +{
58.167 + public:
58.168 + static StructType *New(Zone *zone, Handle<String> name, Handle<FixedArray> fields);
58.169 +
58.170 + FixedArray *fields() {
58.171 + assert(isStruct());
58.172 + return fields_;
58.173 + }
58.174 + Descriptor *lookupField(Handle<String> name, unsigned *index = NULL);
58.175 +
58.176 + // Objects of this type can be created with this cached map.
58.177 + StructMap *newMap() {
58.178 + return newMap_;
58.179 + }
58.180 + void setNewMap(StructMap *map) {
58.181 + assert(!newMap());
58.182 + newMap_ = map;
58.183 + }
58.184 +
58.185 + // GC Descriptor.
58.186 + static inline size_t offsetOfFields() {
58.187 + return OFFSETOF(StructType, fields_);
58.188 + }
58.189 + static inline size_t offsetOfNewMap() {
58.190 + return OFFSETOF(StructType, newMap_);
58.191 + }
58.192 + // End GC Descriptor.
58.193 +
58.194 + static StructType *cast(Object *obj) {
58.195 + assert(!obj || obj->is(MapKind_StructType));
58.196 + return (StructType *)obj;
58.197 + }
58.198 +
58.199 + private:
58.200 + // Structs only.
58.201 + Barriered<FixedArray> fields_;
58.202 + Barriered<StructMap> newMap_;
58.203 +};
58.204 +
58.205 +class FunctionType : public Type
58.206 +{
58.207 + public:
58.208 + static FunctionType *New(Zone *zone, TokenKind kind);
58.209 +
58.210 + Type *parameterAt(size_t i) {
58.211 + return Type::cast(parameters()->at(i));
58.212 + }
58.213 + Type *returnType() {
58.214 + assert(isFunction());
58.215 + return returnType_;
58.216 + }
58.217 + FixedArray *parameters() {
58.218 + assert(isFunction());
58.219 + return parameters_;
58.220 + }
58.221 + FixedArray *defaults() {
58.222 + assert(isFunction());
58.223 + return defaults_;
58.224 + }
58.225 + bool isNative() {
58.226 + return token_ == TOK_NATIVE;
58.227 + }
58.228 + bool isForward() {
58.229 + return token_ == TOK_FORWARD;
58.230 + }
58.231 + bool isNativeVariadic() {
58.232 + assert(isNative());
58.233 + return variadicNative_;
58.234 + }
58.235 + void setReturnType(Handle<Type> returnType) {
58.236 + assert(!returnType_);
58.237 + returnType_ = returnType;
58.238 + }
58.239 + void setParameterTypes(Handle<FixedArray> types) {
58.240 + assert(!parameters_);
58.241 + parameters_ = types;
58.242 + }
58.243 + TokenKind token() {
58.244 + return token_;
58.245 + }
58.246 +
58.247 + // GC Descriptor.
58.248 + static inline size_t offsetOfReturnType() {
58.249 + return OFFSETOF(FunctionType, returnType_);
58.250 + }
58.251 + static inline size_t offsetOfParameters() {
58.252 + return OFFSETOF(FunctionType, parameters_);
58.253 + }
58.254 + static inline size_t offsetOfDefaults() {
58.255 + return OFFSETOF(FunctionType, defaults_);
58.256 + }
58.257 + // End GC Descriptor.
58.258 +
58.259 + static FunctionType *cast(Object *obj) {
58.260 + assert(!obj || obj->is(MapKind_FunctionType));
58.261 + return (FunctionType *)obj;
58.262 + }
58.263 +
58.264 + private:
58.265 // Functions only.
58.266 Barriered<Type> returnType_;
58.267 Barriered<FixedArray> parameters_;
58.268 Barriered<FixedArray> defaults_;
58.269 + TokenKind token_;
58.270 bool variadicNative_;
58.271 -
58.272 - // Enums and structs only.
58.273 - Barriered<String> name_;
58.274 -
58.275 - // Structs only.
58.276 - Barriered<FixedArray> fields_;
58.277 - Barriered<Map> newMap_;
58.278 };
58.279
58.280 class BoxedPrimitive
58.281 @@ -351,6 +403,8 @@
58.282 }
58.283 };
58.284
58.285 +const char *GetTypeName(Type *type);
58.286 +
58.287 }
58.288
58.289 #endif // _include_jc_types_h_
59.1 --- a/src/Utility.h Mon Sep 17 00:10:01 2012 -0700
59.2 +++ b/src/Utility.h Sat Nov 17 18:41:01 2012 -0800
59.3 @@ -37,6 +37,8 @@
59.4 typedef uint8_t uint8;
59.5 typedef int32_t int32;
59.6 typedef uint32_t uint32;
59.7 +typedef int64_t int64;
59.8 +typedef uint64_t uint64;
59.9
59.10 typedef uint8 * Address;
59.11
59.12 @@ -110,6 +112,41 @@
59.13 return hasher.result();
59.14 }
59.15
59.16 +// From http://burtleburtle.net/bob/hash/integer.html
59.17 +static inline uint32
59.18 +HashInt32(int32 a)
59.19 +{
59.20 + a = (a ^ 61) ^ (a >> 16);
59.21 + a = a + (a << 3);
59.22 + a = a ^ (a >> 4);
59.23 + a = a * 0x27d4eb2d;
59.24 + a = a ^ (a >> 15);
59.25 + return a;
59.26 +}
59.27 +
59.28 +// From http://www.cris.com/~Ttwang/tech/inthash.htm
59.29 +static inline uint32
59.30 +HashInt64(int64 key)
59.31 +{
59.32 + key = (~key) + (key << 18); // key = (key << 18) - key - 1;
59.33 + key = key ^ (uint64(key) >> 31);
59.34 + key = key * 21; // key = (key + (key << 2)) + (key << 4);
59.35 + key = key ^ (uint64(key) >> 11);
59.36 + key = key + (key << 6);
59.37 + key = key ^ (uint64(key) >> 22);
59.38 + return uint32(key);
59.39 +}
59.40 +
59.41 +static inline uint32
59.42 +HashPointer(void *p)
59.43 +{
59.44 +#if defined(KE_32BIT)
59.45 + return HashInt32(reinterpret_cast<int32>(p));
59.46 +#elif defined(KE_64BIT)
59.47 + return HashInt64(reinterpret_cast<int64>(p));
59.48 +#endif
59.49 +}
59.50 +
59.51 static inline size_t
59.52 Log2(size_t number)
59.53 {
60.1 --- a/src/Vector.h Mon Sep 17 00:10:01 2012 -0700
60.2 +++ b/src/Vector.h Sat Nov 17 18:41:01 2012 -0800
60.3 @@ -47,6 +47,11 @@
60.4 nitems++;
60.5 return true;
60.6 }
60.7 + void infallibleAppend(const T &item) {
60.8 + assert(GrowIfNeeded(1));
60.9 + new (&data[nitems]) T(item);
60.10 + nitems++;
60.11 + }
60.12 T popCopy() {
60.13 T t = at(length() - 1);
60.14 pop();
60.15 @@ -85,6 +90,13 @@
60.16 return data;
60.17 }
60.18
60.19 + bool ensure(size_t desired) {
60.20 + if (desired <= length())
60.21 + return true;
60.22 +
60.23 + return GrowIfNeeded(desired - length());
60.24 + }
60.25 +
60.26 private:
60.27 bool GrowIfNeeded(size_t needed)
60.28 {
61.1 --- a/src/VirtualObjectVisitor.h Mon Sep 17 00:10:01 2012 -0700
61.2 +++ b/src/VirtualObjectVisitor.h Sat Nov 17 18:41:01 2012 -0800
61.3 @@ -2,25 +2,26 @@
61.4 *
61.5 * Copyright (C) 2012 David Anderson
61.6 *
61.7 - * This file is part of JITCraft.
61.8 + * This file is part of SourcePawn.
61.9 *
61.10 - * JITCraft is free software: you can redistribute it and/or modify it under
61.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
61.12 * the terms of the GNU General Public License as published by the Free
61.13 * Software Foundation, either version 3 of the License, or (at your option)
61.14 * any later version.
61.15 *
61.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
61.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
61.18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
61.19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
61.20 *
61.21 * You should have received a copy of the GNU General Public License along with
61.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
61.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
61.24 */
61.25 #ifndef _include_jc_virtual_object_visitor_h_
61.26 #define _include_jc_virtual_object_visitor_h_
61.27
61.28 namespace ke {
61.29
61.30 +class Zone;
61.31 class Object;
61.32
61.33 class VirtualObjectVisitor
61.34 @@ -29,6 +30,21 @@
61.35 virtual void visit(Object **ptr) = 0;
61.36 };
61.37
61.38 +// This is a helper class for automatically rooting C++ objects that need
61.39 +// special tracing. It is implemented in Zone.
61.40 +class AutoRooted
61.41 +{
61.42 + public:
61.43 + AutoRooted(Zone *zone);
61.44 + ~AutoRooted();
61.45 +
61.46 + virtual void accept(VirtualObjectVisitor *visitor) = 0;
61.47 +
61.48 + private:
61.49 + Zone *zone_;
61.50 + AutoRooted *prev_;
61.51 +};
61.52 +
61.53 }
61.54
61.55 #endif // _include_jc_virtual_object_visitor_h_
62.1 --- a/src/Zone.cpp Mon Sep 17 00:10:01 2012 -0700
62.2 +++ b/src/Zone.cpp Sat Nov 17 18:41:01 2012 -0800
62.3 @@ -23,6 +23,7 @@
62.4 #include "GlobalRoots.h"
62.5 #include "AllocatorPolicies.h"
62.6 #include "Array.h"
62.7 +#include "NativeTable.h"
62.8 #include "Spaces-inl.h"
62.9 #include "Heap-inl.h"
62.10
62.11 @@ -30,6 +31,8 @@
62.12
62.13 Zone *ke::SingleThreadedZone;
62.14
62.15 +void * const NullAddress::Sentinel = NULL;
62.16 +
62.17 Zone::Zone()
62.18 : stack_(thisFromCtor()),
62.19 heap_(thisFromCtor()),
62.20 @@ -37,6 +40,7 @@
62.21 symbols_(NULL),
62.22 globalRoots_(NULL),
62.23 lastLocalRoot_(NULL),
62.24 + specialRoots_(NULL),
62.25 hasPendingException_(false),
62.26 reporter_(NULL)
62.27 {
62.28 @@ -45,8 +49,9 @@
62.29 Zone::~Zone()
62.30 {
62.31 delete types_;
62.32 + delete nativeTable_;
62.33 + delete globalRoots_;
62.34 delete symbols_;
62.35 - delete globalRoots_;
62.36 }
62.37
62.38 bool
62.39 @@ -65,9 +70,17 @@
62.40 if (!globalRoots_ || !globalRoots_->initialize())
62.41 return false;
62.42
62.43 + nativeTable_ = new NativeTable(this);
62.44 + if (!nativeTable_ || !nativeTable_->initialize())
62.45 + return false;
62.46 +
62.47 maps_[MapKind_Meta] = heap_.metaMap();
62.48 if ((maps_[MapKind_Type] = allocateMap(MapKind_Type, sizeof(Map))) == NULL)
62.49 return false;
62.50 + if ((maps_[MapKind_FunctionType] = allocateMap(MapKind_FunctionType, sizeof(Map))) == NULL)
62.51 + return false;
62.52 + if ((maps_[MapKind_StructType] = allocateMap(MapKind_StructType, sizeof(Map))) == NULL)
62.53 + return false;
62.54 if ((maps_[MapKind_FixedArray] = allocateMap(MapKind_FixedArray, sizeof(Map))) == NULL)
62.55 return false;
62.56 if ((maps_[MapKind_ByteArray] = allocateMap(MapKind_ByteArray, sizeof(Map))) == NULL)
62.57 @@ -118,9 +131,12 @@
62.58 if (!type)
62.59 return false;
62.60
62.61 + // :TODO:
62.62 +#if 0
62.63 externalGenericArrayMap_ = ArrayMap::Attach(this, type);
62.64 if (!externalGenericArrayMap_)
62.65 return false;
62.66 +#endif
62.67
62.68 type = types_->getPrimitive(PrimitiveType_Char);
62.69 if (!type)
62.70 @@ -130,9 +146,12 @@
62.71 if (!type)
62.72 return false;
62.73
62.74 + // :TODO:
62.75 +#if 0
62.76 externalCharArrayMap_ = ArrayMap::Attach(this, type);
62.77 if (!externalCharArrayMap_)
62.78 return false;
62.79 +#endif
62.80 }
62.81
62.82 return true;
62.83 @@ -166,6 +185,7 @@
62.84
62.85 globalRoots_->accept(visitor);
62.86 rootScopes_.accept(visitor);
62.87 + nativeTable_->accept(visitor);
62.88
62.89 stack_.accept(visitor);
62.90 }
62.91 @@ -315,7 +335,13 @@
62.92 void
62.93 ZoneAllocatorPolicy::reportAllocationOverflow()
62.94 {
62.95 - ZONE()->reportError(Message_AllocationOverflow);
62.96 + ZONE()->reportAllocationOverflow();
62.97 +}
62.98 +
62.99 +void
62.100 +Zone::reportAllocationOverflow()
62.101 +{
62.102 + reportError(Message_AllocationOverflow);
62.103 }
62.104
62.105 void
62.106 @@ -324,3 +350,20 @@
62.107 hasPendingException_ = false;
62.108 }
62.109
62.110 +void
62.111 +Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener)
62.112 +{
62.113 + publicFunctionListener_ = listener;
62.114 +}
62.115 +
62.116 +AutoRooted::AutoRooted(Zone *zone)
62.117 + : zone_(zone),
62.118 + prev_(*zone->lastSpecialRoot())
62.119 +{
62.120 + *zone->lastSpecialRoot() = this;
62.121 +}
62.122 +
62.123 +AutoRooted::~AutoRooted()
62.124 +{
62.125 + *zone_->lastSpecialRoot() = prev_;
62.126 +}
63.1 --- a/src/Zone.h Mon Sep 17 00:10:01 2012 -0700
63.2 +++ b/src/Zone.h Sat Nov 17 18:41:01 2012 -0800
63.3 @@ -37,6 +37,7 @@
63.4 class GlobalRoots;
63.5 class ArrayMap;
63.6 class Exception;
63.7 +class NativeTable;
63.8
63.9 class Zone
63.10 {
63.11 @@ -52,15 +53,19 @@
63.12 TypeManager *types_;
63.13 StringPool *symbols_;
63.14 GlobalRoots *globalRoots_;
63.15 + NativeTable *nativeTable_;
63.16
63.17 // Root list.
63.18 Local<Object> *lastLocalRoot_;
63.19 RootScopeManager rootScopes_;
63.20 + AutoRooted *specialRoots_;
63.21
63.22 // Exception stuff.
63.23 bool hasPendingException_;
63.24 Ke::IMessageReporter *reporter_;
63.25
63.26 + Ke::IPublicFunctionListener *publicFunctionListener_;
63.27 +
63.28 private:
63.29 Zone *thisFromCtor() {
63.30 return this;
63.31 @@ -103,6 +108,9 @@
63.32 TypeManager *types() const {
63.33 return types_;
63.34 }
63.35 + AutoRooted **lastSpecialRoot() {
63.36 + return &specialRoots_;
63.37 + }
63.38 Local<Object> **lastLocalRoot() {
63.39 return &lastLocalRoot_;
63.40 }
63.41 @@ -118,11 +126,15 @@
63.42 GlobalRoots *globalRoots() {
63.43 return globalRoots_;
63.44 }
63.45 + NativeTable *nativeTable() {
63.46 + return nativeTable_;
63.47 + }
63.48
63.49 String *makeSymbol(const char *string, size_t length);
63.50 String *makeSymbol(const char *string);
63.51
63.52 void reportOutOfMemory();
63.53 + void reportAllocationOverflow();
63.54 void reportError(Message message, ...);
63.55 void reportErrorVA(Message message, va_list ap);
63.56 bool hasPendingException();
63.57 @@ -133,6 +145,10 @@
63.58 void endCompilationErrors();
63.59
63.60 void accept(VirtualObjectVisitor *visitor);
63.61 +
63.62 + void setPublicFunctionListener(Ke::IPublicFunctionListener *listener);
63.63 + void registerPublic(Handle<Function> fun);
63.64 + void unregisterPublic(Handle<Function> fun);
63.65 };
63.66
63.67 // In a multi-threaded system, this would be a TLS variable.
64.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
64.2 +++ b/src/comment Sat Nov 17 18:41:01 2012 -0800
64.3 @@ -0,0 +1,101 @@
64.4 +Massive refactoring to support better type systems. Read on for more.
64.5 +
64.6 +The previous compiler had a simple pipeline, best outlined as:
64.7 + (1) Parsing and name binding -> AST
64.8 + (2) Storage allocation -> AST
64.9 + (3) Semantic Analysis (SemA) -> AST
64.10 + (4) Bytecode Compilation (BC) -> Code
64.11 +
64.12 +This pipeline, unfortunately, had two problems. First, name binding cannot be performed in one pass if we wish to have multi-file support in the form of modules. Name binding must be two-pass.
64.13 +
64.14 +Second, because SemA was only capable of annotating AST nodes with a single type, most coercion work had to be duplicated in the BC phase, as coercion was not explicit in the SemA output. This made introducing new type rules extremely difficult, and all but precluded concepts like operator overloading (or overloading at all).
64.15 +
64.16 +This patch rewrites most of Keima's backend. Of interest are the following changes:
64.17 + (1) CompileContext has been refactored around future multi-file support.
64.18 + (2) Parsing no longer performs any name binding.
64.19 + (3) The grammar for type-and-name has been changed from:
64.20 + (Label | Identifier)? Identifier
64.21 + to:
64.22 + Type? Identifier
64.23 + where:
64.24 + Type ::= OldType | NewType
64.25 + OldType ::= Label
64.26 + NewType ::= Identifier (. NewType)*
64.27 +
64.28 +
64.29 + Although we do not implement the full production for Type yet, this
64.30 + distinction is important. A type identifier is now affixed to the AST
64.31 + as an Expression (right now, always a NameProxy), so it can fully
64.32 + participate in name binding.
64.33 +
64.34 + (4) Immediately after parsing, the AST goes through a NamePopulation phase.
64.35 + This phase creates Scope objects for every scope which declares a name,
64.36 + and if those names are declaring types or functions, a Symbol is created
64.37 + and entered into the scope. Symbols entirely replace the old BoundName
64.38 + classes.
64.39 +
64.40 + (5) After NamePopulation comes NameBinding. This phase performs three steps:
64.41 + (a) Links Scope objects together, to form a tree.
64.42 + (b) Binds any free name to an existing name in the scope chain.
64.43 + (c) Creates and registers any Symbols for names which have not yet been
64.44 + added to the scope (for example, local variables).
64.45 +
64.46 + In accordance, all "allocation" and "binding" concepts have been removed
64.47 + from Scopes, which are now lightweight container classes.
64.48 +
64.49 + (6) SemA now generates bytecode for each statement in the AST. Expression
64.50 + compilation is performed via a separate mechanism called HIR (High-level
64.51 + Intermediate Representation). To analyze an expression, SemA will walk
64.52 + the AST, and produce a HIR object for each node. HIR is typed, and SemA
64.53 + may insert coercion nodes, or even expand an AST node into multiple HIR
64.54 + nodes. The result of evaluating an expression in SemA is therefore the
64.55 + the root of a HIR tree, which SemA then sends to the HIRTranslator, which
64.56 + performs bytecode generation.
64.57 +
64.58 + As before, SemA still performs full semantic analysis. However, not it
64.59 + also produces each function's bytecode.
64.60 +
64.61 + This split allows us to decompose potentially complex semantics into
64.62 + a more fine-grained, AST-like structure, which can have very simple
64.63 + code-generation logic. For example, (1.0 + 5) might look like:
64.64 +
64.65 + HAdd(HFloat(1.0), HConvert(HInteger(5), <Float>))
64.66 +
64.67 + As part of this decomposition, many opcodes have been removed. Rather than
64.68 + using typed jumps, we now expand jumps into longer tests. For example:
64.69 + jge.f <label>
64.70 + becomes:
64.71 + ge.f
64.72 + cvt.f2b
64.73 + jt <label>
64.74 +
64.75 + This simplifies the pipeline, and JITs should be able to melt the added
64.76 + work away.
64.77 +
64.78 + HIR is not used at a statement level, and HIR does not have any concept
64.79 + of control-flow.
64.80 +
64.81 + (7) The old BytecodeCompiler has been removed, as its work is now split
64.82 + between SemA and HIRTranslator.
64.83 +
64.84 +
64.85 +In addition, some minor refactorings have taken place:
64.86 +
64.87 + (1) Opcodes.tbl no longer hardcodes numbers (aaah).
64.88 + (2) Type has been split into smaller, typed structs.
64.89 + (3) BytecodeEmitter no longer relies on Pools or RootScopes.
64.90 + (4) SemA is now responsible for variable/storage allocation.
64.91 + (5) Native table are now global, rather than per-module. As such, native
64.92 + declarations now result in a Native object (which still requires a
64.93 + CALLNATIVE opcode), which is an index into the global table. Natives
64.94 + must be bound globally. This is in preparation for module support.
64.95 + (6) Publics are no longer tracked, but rather registered via a global
64.96 + callback upon module load. This callback can be set by embedders. This
64.97 + is in preparation for multi-file support.
64.98 + (7) The BytecodeEmitter now performs Symbol allocations itself, and it
64.99 + also generates Code objects itself, which removes a good deal of
64.100 + complexity.
64.101 +
64.102 +Finally, a test harness has been added. This harness is a python script which finds *.test files, recursively, in the tests folder. For each file it runs the corresponding .sp. The contents of the .test file must match stdout+stderr.
64.103 +
64.104 +
65.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
65.2 +++ b/src/compiler/AST.h Sat Nov 17 18:41:01 2012 -0800
65.3 @@ -0,0 +1,1155 @@
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_sourcepawn_ast_h_
65.23 +#define _include_sourcepawn_ast_h_
65.24 +
65.25 +#include "../PoolAllocator.h"
65.26 +#include "../Vector.h"
65.27 +#include "Token.h"
65.28 +#include "NameBinding.h"
65.29 +#include "Symbols.h"
65.30 +#include "../QualType.h"
65.31 +
65.32 +namespace ke {
65.33 +
65.34 +class Scope;
65.35 +
65.36 +#define ASTKINDS(_) \
65.37 + _(VariableDeclaration) \
65.38 + _(ForStatement) \
65.39 + _(ReturnStatement) \
65.40 + _(IntegerLiteral) \
65.41 + _(FloatLiteral) \
65.42 + _(StringLiteral) \
65.43 + _(BinaryExpression) \
65.44 + _(BlockStatement) \
65.45 + _(Assignment) \
65.46 + _(NameProxy) \
65.47 + _(ExpressionStatement) \
65.48 + _(FunctionStatement) \
65.49 + _(CallExpression) \
65.50 + _(IfStatement) \
65.51 + _(IndexExpression) \
65.52 + _(FieldExpression) \
65.53 + _(EnumStatement) \
65.54 + _(WhileStatement) \
65.55 + _(BreakStatement) \
65.56 + _(ContinueStatement) \
65.57 + _(FunctionTypeStatement) \
65.58 + _(IncDecExpression) \
65.59 + _(UnaryExpression) \
65.60 + _(TernaryExpression) \
65.61 + _(BooleanLiteral) \
65.62 + _(StructureStatement) \
65.63 + _(SwitchStatement) \
65.64 + _(ArrayLiteral) \
65.65 + _(ImportStatement)
65.66 +
65.67 +// Forward declarations.
65.68 +#define _(name) class name;
65.69 +ASTKINDS(_)
65.70 +#undef _
65.71 +
65.72 +class AstVisitor;
65.73 +
65.74 +// Interface for AST nodes.
65.75 +class AstNode : public PoolObject
65.76 +{
65.77 + SourcePosition pos_;
65.78 +
65.79 + public:
65.80 + enum Kind {
65.81 +# define _(name) k##name,
65.82 + ASTKINDS(_)
65.83 +# undef _
65.84 + AstKind_Invalid
65.85 + };
65.86 +
65.87 + AstNode(const SourcePosition &pos)
65.88 + : pos_(pos)
65.89 + {
65.90 + }
65.91 +
65.92 + virtual Kind kind() const = 0;
65.93 +
65.94 +#define _(name) bool is##name() { return kind() == k##name; } \
65.95 + name *to##name() { assert(is##name()); return (name *)this; } \
65.96 + name *as##name() { if (!is##name()) return NULL; return to##name(); }
65.97 + ASTKINDS(_)
65.98 +#undef _
65.99 +
65.100 + virtual void accept(AstVisitor *visitor) = 0;
65.101 +
65.102 + const SourcePosition &pos() const {
65.103 + return pos_;
65.104 + }
65.105 +};
65.106 +
65.107 +#define DECLARE_NODE(type) \
65.108 + Kind kind() const { \
65.109 + return k##type; \
65.110 + } \
65.111 + void accept(AstVisitor *visitor) { \
65.112 + visitor->visit##type(this); \
65.113 + }
65.114 +
65.115 +class AstVisitor
65.116 +{
65.117 + public:
65.118 +#define _(name) virtual void visit##name(name *node) { assert(false); }
65.119 + ASTKINDS(_)
65.120 +#undef _
65.121 +};
65.122 +
65.123 +class Statement : public AstNode
65.124 +{
65.125 + public:
65.126 + Statement(const SourcePosition &pos)
65.127 + : AstNode(pos)
65.128 + {
65.129 + }
65.130 +};
65.131 +
65.132 +class Expression : public AstNode
65.133 +{
65.134 + ScopedRoot<Type> type_;
65.135 +
65.136 + public:
65.137 + Expression(const SourcePosition &pos)
65.138 + : AstNode(pos),
65.139 + type_(NULL)
65.140 + {
65.141 + }
65.142 +
65.143 + void setType(Type *type) {
65.144 + type_ = type;
65.145 + }
65.146 + Type *type() const {
65.147 + return type_;
65.148 + }
65.149 +};
65.150 +
65.151 +typedef PoolList<Statement *> StatementList;
65.152 +typedef PoolList<Expression *> ExpressionList;
65.153 +
65.154 +class VariableDeclaration : public Statement
65.155 +{
65.156 + TypeQualifiers qual_;
65.157 + ScopedRoot<String> name_;
65.158 + Expression *initialization_;
65.159 + Expression *type_;
65.160 + VariableSymbol *sym_;
65.161 +
65.162 + public:
65.163 + VariableDeclaration(const SourcePosition &pos, TypeQualifiers qual, Handle<String> name,
65.164 + Expression *type, Expression *initialization)
65.165 + : Statement(pos),
65.166 + qual_(qual),
65.167 + name_(name),
65.168 + initialization_(initialization),
65.169 + type_(type),
65.170 + sym_(NULL)
65.171 + {
65.172 + }
65.173 +
65.174 + DECLARE_NODE(VariableDeclaration);
65.175 +
65.176 + Expression *initialization() const {
65.177 + return initialization_;
65.178 + }
65.179 + Handle<String> name() {
65.180 + return name_;
65.181 + }
65.182 + Expression *declType() const {
65.183 + return type_;
65.184 + }
65.185 + void setSymbol(VariableSymbol *sym) {
65.186 + assert(!sym_);
65.187 + sym_ = sym;
65.188 + }
65.189 + VariableSymbol *sym() const {
65.190 + return sym_;
65.191 + }
65.192 + Expression *type() const {
65.193 + return type_;
65.194 + }
65.195 +};
65.196 +
65.197 +class Parameter : public PoolObject
65.198 +{
65.199 + ScopedRoot<String> name_;
65.200 + Expression *type_;
65.201 + bool reference_;
65.202 + bool const_;
65.203 + Expression *initializer_;
65.204 + VariableSymbol *sym_;
65.205 + SourcePosition pos_;
65.206 +
65.207 + public:
65.208 + Parameter(Handle<String> name, Expression *type, bool reference, bool isConst,
65.209 + Expression *initializer, const SourcePosition &pos)
65.210 + : name_(name),
65.211 + type_(type),
65.212 + reference_(reference),
65.213 + const_(isConst),
65.214 + initializer_(initializer),
65.215 + sym_(NULL),
65.216 + pos_(pos)
65.217 + {
65.218 + }
65.219 +
65.220 + Expression *type() const {
65.221 + return type_;
65.222 + }
65.223 + Handle<String> name() const {
65.224 + return name_;
65.225 + }
65.226 + bool reference() const {
65.227 + return reference_;
65.228 + }
65.229 + bool isConst() const {
65.230 + return const_;
65.231 + }
65.232 + Expression *initializer() const {
65.233 + return initializer_;
65.234 + }
65.235 + void setSymbol(VariableSymbol *sym) {
65.236 + assert(!sym_);
65.237 + sym_ = sym;
65.238 + }
65.239 + VariableSymbol *sym() const {
65.240 + return sym_;
65.241 + }
65.242 + const SourcePosition &pos() const {
65.243 + return pos_;
65.244 + }
65.245 +};
65.246 +
65.247 +class NameProxy : public Expression
65.248 +{
65.249 + ScopedRoot<String> name_;
65.250 + Symbol *binding_;
65.251 +
65.252 + public:
65.253 + NameProxy(const SourcePosition &pos, Handle<String> name)
65.254 + : Expression(pos),
65.255 + name_(name),
65.256 + binding_(NULL)
65.257 + {
65.258 + }
65.259 +
65.260 + DECLARE_NODE(NameProxy);
65.261 +
65.262 + Handle<String> name() const {
65.263 + return name_;
65.264 + }
65.265 + Symbol *sym() const {
65.266 + return binding_;
65.267 + }
65.268 + void bind(Symbol *sym) {
65.269 + binding_ = sym;
65.270 + }
65.271 +};
65.272 +
65.273 +class BooleanLiteral : public Expression
65.274 +{
65.275 + TokenKind token_;
65.276 +
65.277 + public:
65.278 + BooleanLiteral(const SourcePosition &pos, TokenKind token)
65.279 + : Expression(pos),
65.280 + token_(token)
65.281 + {
65.282 + }
65.283 +
65.284 + DECLARE_NODE(BooleanLiteral);
65.285 + TokenKind token() const {
65.286 + return token_;
65.287 + }
65.288 +};
65.289 +
65.290 +class IntegerLiteral : public Expression
65.291 +{
65.292 + int value_;
65.293 +
65.294 + public:
65.295 + IntegerLiteral(const SourcePosition &pos, int value)
65.296 + : Expression(pos),
65.297 + value_(value)
65.298 + {
65.299 + }
65.300 +
65.301 + DECLARE_NODE(IntegerLiteral);
65.302 +
65.303 + int value() const {
65.304 + return value_;
65.305 + }
65.306 +};
65.307 +
65.308 +class FloatLiteral : public Expression
65.309 +{
65.310 + double value_;
65.311 +
65.312 + public:
65.313 + FloatLiteral(const SourcePosition &pos, double value)
65.314 + : Expression(pos),
65.315 + value_(value)
65.316 + {
65.317 + }
65.318 +
65.319 + DECLARE_NODE(FloatLiteral);
65.320 +
65.321 + double value() const {
65.322 + return value_;
65.323 + }
65.324 +};
65.325 +
65.326 +class StringLiteral : public Expression
65.327 +{
65.328 + ScopedRoot<ByteArray> string_;
65.329 +
65.330 + public:
65.331 + StringLiteral(const SourcePosition &pos, ByteArray *array)
65.332 + : Expression(pos),
65.333 + string_(array)
65.334 + {
65.335 + }
65.336 +
65.337 + DECLARE_NODE(StringLiteral);
65.338 +
65.339 + ByteArray *string() const {
65.340 + return string_;
65.341 + }
65.342 +};
65.343 +
65.344 +class ArrayLiteral : public Expression
65.345 +{
65.346 + TokenKind token_;
65.347 + ExpressionList *expressions_;
65.348 +
65.349 + public:
65.350 + ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
65.351 + : Expression(pos),
65.352 + token_(token),
65.353 + expressions_(expressions)
65.354 + {
65.355 + }
65.356 +
65.357 + DECLARE_NODE(ArrayLiteral);
65.358 +
65.359 + TokenKind token() const {
65.360 + return token_;
65.361 + }
65.362 + ExpressionList *expressions() const {
65.363 + return expressions_;
65.364 + }
65.365 + bool isFixed() const {
65.366 + return token_ == TOK_LBRACE;
65.367 + }
65.368 +};
65.369 +
65.370 +class UnaryExpression : public Expression
65.371 +{
65.372 + Expression *expression_;
65.373 + TokenKind token_;
65.374 + NameProxy *tag_;
65.375 +
65.376 + public:
65.377 + UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
65.378 + : Expression(pos),
65.379 + expression_(expr),
65.380 + token_(token),
65.381 + tag_(NULL)
65.382 + {
65.383 + }
65.384 +
65.385 + UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr,
65.386 + NameProxy *tag)
65.387 + : Expression(pos),
65.388 + expression_(expr),
65.389 + token_(token),
65.390 + tag_(tag)
65.391 + {
65.392 + }
65.393 +
65.394 + DECLARE_NODE(UnaryExpression);
65.395 +
65.396 + Expression *expression() const {
65.397 + return expression_;
65.398 + }
65.399 + TokenKind token() const {
65.400 + return token_;
65.401 + }
65.402 + NameProxy *tag() const {
65.403 + return tag_;
65.404 + }
65.405 +};
65.406 +
65.407 +class BinaryExpression : public Expression
65.408 +{
65.409 + Expression *left_;
65.410 + Expression *right_;
65.411 + TokenKind token_;
65.412 +
65.413 + public:
65.414 + BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
65.415 + : Expression(pos),
65.416 + left_(left),
65.417 + right_(right),
65.418 + token_(token)
65.419 + {
65.420 + }
65.421 +
65.422 + DECLARE_NODE(BinaryExpression);
65.423 +
65.424 + Expression *left() const {
65.425 + return left_;
65.426 + }
65.427 + Expression *right() const {
65.428 + return right_;
65.429 + }
65.430 + TokenKind token() const {
65.431 + return token_;
65.432 + }
65.433 +};
65.434 +
65.435 +class TernaryExpression : public Expression
65.436 +{
65.437 + Expression *condition_;
65.438 + Expression *left_;
65.439 + Expression *right_;
65.440 +
65.441 + public:
65.442 + TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
65.443 + : Expression(pos),
65.444 + condition_(condition),
65.445 + left_(left),
65.446 + right_(right)
65.447 + {
65.448 + }
65.449 +
65.450 + DECLARE_NODE(TernaryExpression);
65.451 +
65.452 + Expression *condition() const {
65.453 + return condition_;
65.454 + }
65.455 + Expression *left() const {
65.456 + return left_;
65.457 + }
65.458 + Expression *right() const {
65.459 + return right_;
65.460 + }
65.461 +};
65.462 +
65.463 +class IndexExpression : public Expression
65.464 +{
65.465 + Expression *left_;
65.466 + Expression *right_;
65.467 +
65.468 + public:
65.469 + IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
65.470 + : Expression(pos),
65.471 + left_(left),
65.472 + right_(right)
65.473 + {
65.474 + }
65.475 +
65.476 + DECLARE_NODE(IndexExpression);
65.477 +
65.478 + Expression *left() const {
65.479 + return left_;
65.480 + }
65.481 + Expression *right() const {
65.482 + return right_;
65.483 + }
65.484 +};
65.485 +
65.486 +class FieldExpression : public Expression
65.487 +{
65.488 + Expression *left_;
65.489 + ScopedRoot<String> field_;
65.490 + unsigned fieldIndex_;
65.491 +
65.492 + public:
65.493 + FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
65.494 + : Expression(pos),
65.495 + left_(left),
65.496 + field_(field),
65.497 + fieldIndex_(unsigned(-1))
65.498 + {
65.499 + }
65.500 +
65.501 + DECLARE_NODE(FieldExpression);
65.502 +
65.503 + Expression *left() const {
65.504 + return left_;
65.505 + }
65.506 + String *field() const {
65.507 + return field_;
65.508 + }
65.509 + void setFieldIndex(unsigned index) {
65.510 + assert(fieldIndex_ == unsigned(-1));
65.511 + fieldIndex_ = index;
65.512 + }
65.513 + unsigned fieldIndex() const {
65.514 + assert(fieldIndex_ != unsigned(-1));
65.515 + return fieldIndex_;
65.516 + }
65.517 +};
65.518 +
65.519 +class CallExpression : public Expression
65.520 +{
65.521 + Expression *callee_;
65.522 + ExpressionList *arguments_;
65.523 +
65.524 + public:
65.525 + CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
65.526 + : Expression(pos),
65.527 + callee_(callee),
65.528 + arguments_(arguments)
65.529 + {
65.530 + }
65.531 +
65.532 + DECLARE_NODE(CallExpression);
65.533 +
65.534 + Expression *callee() const {
65.535 + return callee_;
65.536 + }
65.537 + ExpressionList *arguments() const {
65.538 + return arguments_;
65.539 + }
65.540 +};
65.541 +
65.542 +class ForStatement : public Statement
65.543 +{
65.544 + Statement *initialization_;
65.545 + Expression *condition_;
65.546 + Statement *update_;
65.547 + Statement *body_;
65.548 + Scope *scope_;
65.549 +
65.550 + public:
65.551 + ForStatement(const SourcePosition &pos, Statement *initialization,
65.552 + Expression *condition, Statement *update, Statement *body)
65.553 + : Statement(pos),
65.554 + initialization_(initialization),
65.555 + condition_(condition),
65.556 + update_(update),
65.557 + body_(body),
65.558 + scope_(NULL)
65.559 + {
65.560 + }
65.561 +
65.562 + DECLARE_NODE(ForStatement);
65.563 +
65.564 + Statement *initialization() const {
65.565 + return initialization_;
65.566 + }
65.567 + Expression *condition() const {
65.568 + return condition_;
65.569 + }
65.570 + Statement *update() const {
65.571 + return update_;
65.572 + }
65.573 + Statement *body() const {
65.574 + return body_;
65.575 + }
65.576 + Scope *scope() const {
65.577 + return scope_;
65.578 + }
65.579 + void setScope(Scope *scope) {
65.580 + scope_ = scope;
65.581 + }
65.582 +};
65.583 +
65.584 +class WhileStatement : public Statement
65.585 +{
65.586 + TokenKind token_;
65.587 + Expression *condition_;
65.588 + Statement *body_;
65.589 +
65.590 + public:
65.591 + WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
65.592 + : Statement(pos),
65.593 + token_(kind),
65.594 + condition_(condition),
65.595 + body_(body)
65.596 + {
65.597 + }
65.598 +
65.599 + DECLARE_NODE(WhileStatement);
65.600 +
65.601 + TokenKind token() const {
65.602 + return token_;
65.603 + }
65.604 + Expression *condition() const {
65.605 + return condition_;
65.606 + }
65.607 + Statement *body() const {
65.608 + return body_;
65.609 + }
65.610 +};
65.611 +
65.612 +class ReturnStatement : public Statement
65.613 +{
65.614 + Expression *expression_;
65.615 +
65.616 + public:
65.617 + ReturnStatement(const SourcePosition &pos, Expression *expression)
65.618 + : Statement(pos),
65.619 + expression_(expression)
65.620 + {
65.621 + }
65.622 +
65.623 + DECLARE_NODE(ReturnStatement);
65.624 +
65.625 + Expression *expression() const {
65.626 + return expression_;
65.627 + }
65.628 +};
65.629 +
65.630 +class BreakStatement : public Statement
65.631 +{
65.632 + public:
65.633 + BreakStatement(const SourcePosition &pos)
65.634 + : Statement(pos)
65.635 + {
65.636 + }
65.637 +
65.638 + DECLARE_NODE(BreakStatement);
65.639 +};
65.640 +
65.641 +class ContinueStatement : public Statement
65.642 +{
65.643 + public:
65.644 + ContinueStatement(const SourcePosition &pos)
65.645 + : Statement(pos)
65.646 + {
65.647 + }
65.648 +
65.649 + DECLARE_NODE(ContinueStatement);
65.650 +};
65.651 +
65.652 +class Assignment : public Expression
65.653 +{
65.654 + TokenKind token_;
65.655 + Expression *lvalue_;
65.656 + Expression *expression_;
65.657 +
65.658 + public:
65.659 + Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
65.660 + : Expression(pos),
65.661 + token_(token),
65.662 + lvalue_(left),
65.663 + expression_(right)
65.664 + {
65.665 + }
65.666 +
65.667 + DECLARE_NODE(Assignment);
65.668 +
65.669 + TokenKind token() const {
65.670 + return token_;
65.671 + }
65.672 + Expression *lvalue() const {
65.673 + return lvalue_;
65.674 + }
65.675 + Expression *expression() const {
65.676 + return expression_;
65.677 + }
65.678 +};
65.679 +
65.680 +class ExpressionStatement : public Statement
65.681 +{
65.682 + Expression *expression_;
65.683 +
65.684 + public:
65.685 + ExpressionStatement(Expression *expression)
65.686 + : Statement(expression->pos()),
65.687 + expression_(expression)
65.688 + {
65.689 + }
65.690 +
65.691 + DECLARE_NODE(ExpressionStatement);
65.692 +
65.693 + Expression *expression() const {
65.694 + return expression_;
65.695 + }
65.696 +};
65.697 +
65.698 +class BlockStatement : public Statement
65.699 +{
65.700 + StatementList *statements_;
65.701 + Scope *scope_;
65.702 +
65.703 + public:
65.704 + BlockStatement(const SourcePosition &pos, StatementList *statements)
65.705 + : Statement(pos),
65.706 + statements_(statements),
65.707 + scope_(NULL)
65.708 + {
65.709 + }
65.710 +
65.711 + DECLARE_NODE(BlockStatement);
65.712 +
65.713 + StatementList *statements() const {
65.714 + return statements_;
65.715 + }
65.716 + Scope *scope() const {
65.717 + return scope_;
65.718 + }
65.719 + void setScope(Scope *scope) {
65.720 + scope_ = scope;
65.721 + }
65.722 +};
65.723 +
65.724 +typedef PoolList<Parameter *> ParameterList;
65.725 +
65.726 +class FunctionSignature
65.727 +{
65.728 + public:
65.729 + FunctionSignature(Expression *returnType, ParameterList *parameters, bool variadic)
65.730 + : returnType_(returnType),
65.731 + parameters_(parameters),
65.732 + variadic_(variadic)
65.733 + {
65.734 + }
65.735 +
65.736 + Expression *returnType() const {
65.737 + return returnType_;
65.738 + }
65.739 + ParameterList *parameters() const {
65.740 + return parameters_;
65.741 + }
65.742 + bool variadic() const {
65.743 + return variadic_;
65.744 + }
65.745 +
65.746 + private:
65.747 + Expression *returnType_;
65.748 + ParameterList *parameters_;
65.749 + bool variadic_;
65.750 +};
65.751 +
65.752 +class FunctionTypeStatement : public Statement
65.753 +{
65.754 + public:
65.755 + FunctionTypeStatement(const SourcePosition &pos, Handle<String> name, const FunctionSignature &signature)
65.756 + : Statement(pos),
65.757 + name_(name),
65.758 + signature_(signature)
65.759 + {
65.760 + }
65.761 +
65.762 + DECLARE_NODE(FunctionTypeStatement);
65.763 +
65.764 + Handle<String> name() const {
65.765 + return name_;
65.766 + }
65.767 + const FunctionSignature &signature() const {
65.768 + return signature_;
65.769 + }
65.770 +
65.771 + private:
65.772 + ScopedRoot<String> name_;
65.773 + FunctionSignature signature_;
65.774 +
65.775 +};
65.776 +
65.777 +class FunctionStatement : public Statement
65.778 +{
65.779 + ScopedRoot<String> name_;
65.780 + TokenKind kind_;
65.781 + Statement *body_;
65.782 + FunctionSignature signature_;
65.783 + bool explicitReturn_;
65.784 + FunctionSymbol *sym_;
65.785 + Scope *argScope_;
65.786 + Scope *varScope_;
65.787 +
65.788 + public:
65.789 + FunctionStatement(const SourcePosition &pos, Handle<String> name, TokenKind kind,
65.790 + Statement *body, const FunctionSignature &signature, bool explicitReturn)
65.791 + : Statement(pos),
65.792 + name_(name),
65.793 + kind_(kind),
65.794 + body_(body),
65.795 + signature_(signature),
65.796 + explicitReturn_(explicitReturn),
65.797 + sym_(NULL),
65.798 + argScope_(NULL),
65.799 + varScope_(NULL)
65.800 + {
65.801 + }
65.802 +
65.803 + DECLARE_NODE(FunctionStatement);
65.804 +
65.805 + Handle<String> name() const {
65.806 + return name_;
65.807 + }
65.808 + Statement *body() const {
65.809 + return body_;
65.810 + }
65.811 + const FunctionSignature &signature() {
65.812 + return signature_;
65.813 + }
65.814 + bool hasExplicitReturn() const {
65.815 + return explicitReturn_;
65.816 + }
65.817 + TokenKind token() const {
65.818 + return kind_;
65.819 + }
65.820 + void setSymbol(FunctionSymbol *sym) {
65.821 + assert(!sym_);
65.822 + sym_ = sym;
65.823 + }
65.824 + FunctionSymbol *sym() const {
65.825 + return sym_;
65.826 + }
65.827 + void setScopes(Scope *argScope, Scope *varScope) {
65.828 + argScope_ = argScope;
65.829 + varScope_ = varScope;
65.830 + }
65.831 + Scope *argScope() const {
65.832 + return argScope_;
65.833 + }
65.834 + Scope *varScope() const {
65.835 + return varScope_;
65.836 + }
65.837 +};
65.838 +
65.839 +class IfStatement : public Statement
65.840 +{
65.841 + Expression *condition_;
65.842 + Statement *ifTrue_;
65.843 + Statement *ifFalse_;
65.844 +
65.845 + public:
65.846 + IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
65.847 + : Statement(pos),
65.848 + condition_(condition),
65.849 + ifTrue_(ifTrue),
65.850 + ifFalse_(NULL)
65.851 + {
65.852 + }
65.853 +
65.854 + DECLARE_NODE(IfStatement);
65.855 +
65.856 + Expression *condition() const {
65.857 + return condition_;
65.858 + }
65.859 + Statement *ifTrue() const {
65.860 + return ifTrue_;
65.861 + }
65.862 + Statement *ifFalse() const {
65.863 + return ifFalse_;
65.864 + }
65.865 + void setIfFalse(Statement *ifFalse) {
65.866 + ifFalse_ = ifFalse;
65.867 + }
65.868 +};
65.869 +
65.870 +class EnumStatement : public Statement
65.871 +{
65.872 + ScopedRoot<String> name_;
65.873 + TypeSymbol *sym_;
65.874 +
65.875 + public:
65.876 + struct Entry {
65.877 + ScopedRoot<String> name;
65.878 + Expression *expr;
65.879 +
65.880 + Entry(Handle<String> name, Expression *expr)
65.881 + : name(name),
65.882 + expr(expr)
65.883 + {
65.884 + }
65.885 + };
65.886 +
65.887 + typedef PoolList<Entry> EntryList;
65.888 +
65.889 + public:
65.890 + EnumStatement(const SourcePosition &pos, Handle<String> name, EntryList *entries)
65.891 + : Statement(pos),
65.892 + name_(name),
65.893 + entries_(entries),
65.894 + sym_(NULL)
65.895 + {
65.896 + }
65.897 +
65.898 + DECLARE_NODE(EnumStatement);
65.899 +
65.900 + String *name() const {
65.901 + return name_;
65.902 + }
65.903 + EntryList *entries() const {
65.904 + return entries_;
65.905 + }
65.906 + void setSymbol(TypeSymbol *sym) {
65.907 + assert(!sym_);
65.908 + sym_ = sym;
65.909 + }
65.910 + TypeSymbol *sym() const {
65.911 + return sym_;
65.912 + }
65.913 +
65.914 + private:
65.915 + EntryList *entries_;
65.916 +};
65.917 +
65.918 +class IncDecExpression : public Expression
65.919 +{
65.920 + TokenKind token_;
65.921 + Expression *expression_;
65.922 + bool postfix_;
65.923 +
65.924 + public:
65.925 + IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
65.926 + : Expression(pos),
65.927 + token_(token),
65.928 + expression_(expression),
65.929 + postfix_(postfix)
65.930 + {
65.931 + }
65.932 +
65.933 + DECLARE_NODE(IncDecExpression);
65.934 +
65.935 + TokenKind token() const {
65.936 + return token_;
65.937 + }
65.938 + Expression *expression() const {
65.939 + return expression_;
65.940 + }
65.941 + bool postfix() const {
65.942 + return postfix_;
65.943 + }
65.944 +};
65.945 +
65.946 +class Case : public PoolObject
65.947 +{
65.948 + public:
65.949 + Case(Expression *expression, ExpressionList *others, Statement *statement)
65.950 + : expression_(expression),
65.951 + others_(others),
65.952 + statement_(statement)
65.953 + {
65.954 + }
65.955 +
65.956 + Expression *expression() const {
65.957 + return expression_;
65.958 + }
65.959 + PoolList<Expression *> *others() const {
65.960 + return others_;
65.961 + }
65.962 + Statement *statement() const {
65.963 + return statement_;
65.964 + }
65.965 +
65.966 + private:
65.967 + Expression *expression_;
65.968 + PoolList <Expression *> *others_;
65.969 + Statement *statement_;
65.970 +};
65.971 +
65.972 +struct CaseValue
65.973 +{
65.974 + BoxedPrimitive box;
65.975 + size_t statement;
65.976 +
65.977 + CaseValue(size_t statement)
65.978 + : statement(statement)
65.979 + {
65.980 + }
65.981 +};
65.982 +
65.983 +typedef PoolList<CaseValue> CaseValueList;
65.984 +
65.985 +class SwitchStatement : public Statement
65.986 +{
65.987 + public:
65.988 + SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
65.989 + Statement *def)
65.990 + : Statement(pos),
65.991 + expression_(expression),
65.992 + cases_(cases),
65.993 + default_(def),
65.994 + table_(NULL)
65.995 + {
65.996 + }
65.997 +
65.998 + DECLARE_NODE(SwitchStatement);
65.999 +
65.1000 + Expression *expression() const {
65.1001 + return expression_;
65.1002 + }
65.1003 + PoolList<Case *> *cases() const {
65.1004 + return cases_;
65.1005 + }
65.1006 + Statement *defaultCase() const {
65.1007 + return default_;
65.1008 + }
65.1009 + void setCaseValueList(CaseValueList *list) {
65.1010 + table_ = list;
65.1011 + }
65.1012 + CaseValueList *caseValueList() const {
65.1013 + return table_;
65.1014 + }
65.1015 +
65.1016 + private:
65.1017 + Expression *expression_;
65.1018 + PoolList<Case *> *cases_;
65.1019 + Statement *default_;
65.1020 + CaseValueList *table_;
65.1021 +};
65.1022 +
65.1023 +class StructureStatement : public Statement
65.1024 +{
65.1025 + public:
65.1026 + class Field : public PoolObject
65.1027 + {
65.1028 + SourcePosition pos_;
65.1029 + Expression *type_;
65.1030 + ScopedRoot<String> name_;
65.1031 +
65.1032 + public:
65.1033 + Field(const SourcePosition &pos,
65.1034 + Expression *type,
65.1035 + Handle<String> name)
65.1036 + : pos_(pos),
65.1037 + type_(type),
65.1038 + name_(name)
65.1039 + {
65.1040 + }
65.1041 +
65.1042 + const SourcePosition &pos() const {
65.1043 + return pos_;
65.1044 + }
65.1045 + Handle<String> name() const {
65.1046 + return name_;
65.1047 + }
65.1048 + Expression *type() const {
65.1049 + return type_;
65.1050 + }
65.1051 + };
65.1052 +
65.1053 + typedef PoolList<StructureStatement::Field *> FieldList;
65.1054 +
65.1055 + public:
65.1056 + StructureStatement(const SourcePosition &pos, Handle<String> name, FieldList *fields)
65.1057 + : Statement(pos),
65.1058 + name_(name),
65.1059 + fields_(fields),
65.1060 + sym_(NULL)
65.1061 + {
65.1062 + }
65.1063 +
65.1064 + DECLARE_NODE(StructureStatement);
65.1065 +
65.1066 + FieldList *fields() const {
65.1067 + return fields_;
65.1068 + }
65.1069 + Handle<String> name() const {
65.1070 + return name_;
65.1071 + }
65.1072 + void setSymbol(TypeSymbol *sym) {
65.1073 + assert(!sym_);
65.1074 + sym_ = sym;
65.1075 + }
65.1076 + TypeSymbol *sym() const {
65.1077 + return sym_;
65.1078 + }
65.1079 +
65.1080 + private:
65.1081 + ScopedRoot<String> name_;
65.1082 + FieldList *fields_;
65.1083 + TypeSymbol *sym_;
65.1084 +};
65.1085 +
65.1086 +typedef PoolList<ScopedRoot<String> *> NameList;
65.1087 +
65.1088 +class ImportStatement : public Statement
65.1089 +{
65.1090 + public:
65.1091 + ImportStatement(const SourcePosition &pos, NameList *names, TokenKind suffix)
65.1092 + : Statement(pos),
65.1093 + names_(names),
65.1094 + suffix_(suffix),
65.1095 + source_(NULL)
65.1096 + {
65.1097 + }
65.1098 +
65.1099 + DECLARE_NODE(ImportStatement);
65.1100 +
65.1101 + NameList *path() const {
65.1102 + return names_;
65.1103 + }
65.1104 + void setImportSource(TranslationUnit *unit) {
65.1105 + source_ = unit;
65.1106 + }
65.1107 + TranslationUnit *source() const {
65.1108 + return source_;
65.1109 + }
65.1110 + TokenKind suffix() const {
65.1111 + return suffix_;
65.1112 + }
65.1113 + Handle<String> name() const {
65.1114 + assert(suffix() != TOK_STAR);
65.1115 + return *names_->at(names_->length() - 1);
65.1116 + }
65.1117 +
65.1118 + private:
65.1119 + NameList *names_;
65.1120 + TokenKind suffix_;
65.1121 + TranslationUnit *source_;
65.1122 +};
65.1123 +
65.1124 +typedef StructureStatement::FieldList FieldList;
65.1125 +typedef PoolList<NameProxy *> NameProxyList;
65.1126 +
65.1127 +#undef DECLARE_NODE
65.1128 +
65.1129 +class ParseTree : public PoolObject
65.1130 +{
65.1131 + StatementList *statements_;
65.1132 + NameProxyList *unbound_;
65.1133 + PoolList<ImportStatement *> *imports_;
65.1134 +
65.1135 + public:
65.1136 + ParseTree(StatementList *statements, NameProxyList *unbound, PoolList<ImportStatement *> *imports)
65.1137 + : statements_(statements),
65.1138 + unbound_(unbound),
65.1139 + imports_(imports)
65.1140 + {
65.1141 + }
65.1142 +
65.1143 + void dump(FILE *fp);
65.1144 +
65.1145 + StatementList *statements() const {
65.1146 + return statements_;
65.1147 + }
65.1148 + NameProxyList *unbound() const {
65.1149 + return unbound_;
65.1150 + }
65.1151 + PoolList<ImportStatement *> *imports() const {
65.1152 + return imports_;
65.1153 + }
65.1154 +};
65.1155 +
65.1156 +}
65.1157 +
65.1158 +#endif // _include_sourcepawn_ast_h_
66.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
66.2 +++ b/src/compiler/BytecodeEmitter.cpp Sat Nov 17 18:41:01 2012 -0800
66.3 @@ -0,0 +1,344 @@
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 JITCraft.
66.9 + *
66.10 + * JITCraft 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 + * Foobar 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 + * JITCraft. If not, see http://www.gnu.org/licenses/.
66.21 + */
66.22 +#include <stdlib.h>
66.23 +#include <string.h>
66.24 +#include "../Utility.h"
66.25 +#include "../Types.h"
66.26 +#include "../Zone.h"
66.27 +#include "../Strings.h"
66.28 +#include "../Zone.h"
66.29 +#include "BytecodeEmitter.h"
66.30 +#include "Symbols.h"
66.31 +#include "Scopes.h"
66.32 +#include "../Spaces-inl.h"
66.33 +#include "../Heap-inl.h"
66.34 +
66.35 +using namespace ke;
66.36 +
66.37 +StringTable::StringTable()
66.38 + : set_(ZoneAllocatorPolicy()),
66.39 + initialized_(false)
66.40 +{
66.41 +}
66.42 +
66.43 +bool
66.44 +StringTable::initialize()
66.45 +{
66.46 + assert(!initialized_);
66.47 + initialized_ = true;
66.48 + if (!set_.init(16))
66.49 + return false;
66.50 + return true;
66.51 +}
66.52 +
66.53 +bool
66.54 +StringTable::add(Handle<String> name, unsigned *indexp)
66.55 +{
66.56 + if (!initialized_ && !initialize())
66.57 + return false;
66.58 +
66.59 + Set::Insert p = set_.findForAdd(*name);
66.60 + if (p.found()) {
66.61 + *indexp = p->index;
66.62 + return true;
66.63 + }
66.64 +
66.65 + if (strings_.length() > INT_MAX) {
66.66 + ZONE()->reportAllocationOverflow();
66.67 + return false;
66.68 + }
66.69 +
66.70 + Entry e(name, strings_.length());
66.71 + if (!strings_.append(e))
66.72 + return false;
66.73 +
66.74 + if (!set_.add(p, e))
66.75 + return false;
66.76 +
66.77 + *indexp = e.index;
66.78 +
66.79 + return true;
66.80 +}
66.81 +
66.82 +void
66.83 +StringTable::accept(VirtualObjectVisitor *visitor)
66.84 +{
66.85 + for (size_t i = 0; i < strings_.length(); i++)
66.86 + visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
66.87 +}
66.88 +
66.89 +BytecodeEmitter::BytecodeEmitter(PoolAllocator &pool)
66.90 + : AutoRooted(ZONE()),
66.91 + pool_(pool),
66.92 + buffer_(inline_buffer_),
66.93 + buffer_pos_(buffer_),
66.94 + buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
66.95 + oom_(false),
66.96 + maxStackDepth_(0)
66.97 +{
66.98 + lastCodePosition_ = 0;
66.99 + firstLine_ = 1;
66.100 +}
66.101 +
66.102 +BytecodeEmitter::~BytecodeEmitter()
66.103 +{
66.104 + for (size_t i = 0; i < oopRecords_.length(); i++)
66.105 + delete oopRecords_[i];
66.106 +}
66.107 +
66.108 +void
66.109 +BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
66.110 +{
66.111 + for (size_t i = 0; i < objects_.length(); i++)
66.112 + visitor->visit(&objects_[i]);
66.113 +
66.114 + strings_.accept(visitor);
66.115 +}
66.116 +
66.117 +bool
66.118 +BytecodeEmitter::growBuffer(size_t nbytes)
66.119 +{
66.120 + if (oom_) {
66.121 + buffer_pos_ = buffer_;
66.122 + return false;
66.123 + }
66.124 +
66.125 + size_t newSize = size_t((buffer_end_ - buffer_) * 2);
66.126 + if (newSize >= MAX_LENGTH) {
66.127 + oom_ = true;
66.128 + buffer_pos_ = buffer_;
66.129 + ZONE()->reportOutOfMemory();
66.130 + return false;
66.131 + }
66.132 +
66.133 + bytecode *newBuffer;
66.134 + if (buffer_ == inline_buffer_)
66.135 + newBuffer = (bytecode *)malloc(newSize);
66.136 + else
66.137 + newBuffer = (bytecode *)realloc(buffer_, newSize);
66.138 +
66.139 + // If we can't allocate a buffer, reset the buffer to the start and set
66.140 + // a flag to indicate out-of-memory.
66.141 + if (!newBuffer) {
66.142 + oom_ = true;
66.143 + buffer_pos_ = buffer_;
66.144 + ZONE()->reportOutOfMemory();
66.145 + return false;
66.146 + }
66.147 +
66.148 + if (buffer_ == inline_buffer_)
66.149 + memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
66.150 +
66.151 + buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
66.152 + buffer_ = newBuffer;
66.153 + buffer_end_ = buffer_ + newSize;
66.154 + assert(buffer_pos_ + nbytes < buffer_end_);
66.155 +
66.156 + return true;
66.157 +}
66.158 +
66.159 +void
66.160 +BytecodeEmitter::recordOops()
66.161 +{
66.162 + OopRecord *record = new OopRecord(oopMap_.length(), position());
66.163 +
66.164 + if (!record->slots.ensure(record->depth)) {
66.165 + oom_ = true;
66.166 + return;
66.167 + }
66.168 +
66.169 + bool hadOops = false;
66.170 + for (size_t i = 0; i < oopMap_.length(); i++) {
66.171 + bool bit = oopMap_[i];
66.172 + record->slots.infallibleAppend(bit);
66.173 + hadOops |= bit;
66.174 + }
66.175 +
66.176 + if (!hadOops) {
66.177 + delete record;
66.178 + return;
66.179 + }
66.180 +
66.181 + oom_ &= oopRecords_.append(record);
66.182 +}
66.183 +
66.184 +void
66.185 +BytecodeEmitter::note_position(const SourcePosition &pos)
66.186 +{
66.187 + assert(pos.line > 0);
66.188 + assert(unsigned(pos.line) >= firstLine_);
66.189 +
66.190 + unsigned lineDelta = unsigned(pos.line) - firstLine_;
66.191 + unsigned pcDelta = unsigned(position()) - lastCodePosition_;
66.192 +
66.193 + sourcemap_.writeUint32(pcDelta);
66.194 + sourcemap_.writeUint32(lineDelta);
66.195 + sourcemap_.writeUint32(pos.col);
66.196 +
66.197 + lastCodePosition_ = unsigned(position());
66.198 +}
66.199 +
66.200 +void
66.201 +BytecodeEmitter::getglobal(Symbol *sym)
66.202 +{
66.203 + ensure(OP_GETGLOBAL_LENGTH);
66.204 + writeOp(OP_GETGLOBAL);
66.205 + writeUint32(addString(sym->name()));
66.206 + if (sym->type()->isTraceable())
66.207 + markOop(1);
66.208 +}
66.209 +void
66.210 +BytecodeEmitter::setglobal(Symbol *sym)
66.211 +{
66.212 + ensure(OP_SETGLOBAL_LENGTH);
66.213 + writeOp(OP_SETGLOBAL);
66.214 + writeUint32(addString(sym->name()));
66.215 + if (sym->type()->isTraceable())
66.216 + markOop(1);
66.217 +}
66.218 +
66.219 +void
66.220 +BytecodeEmitter::getlocal(VariableSymbol *var)
66.221 +{
66.222 + ensure(OP_GETLOCAL_LENGTH);
66.223 + writeOp(OP_GETLOCAL);
66.224 + writeUint32(var->slot());
66.225 + if (var->type()->isTraceable())
66.226 + markOop(1);
66.227 +}
66.228 +
66.229 +void
66.230 +BytecodeEmitter::setlocal(VariableSymbol *var)
66.231 +{
66.232 + ensure(OP_SETLOCAL_LENGTH);
66.233 + writeOp(OP_SETLOCAL);
66.234 + writeUint32(var->slot());
66.235 + if (var->type()->isTraceable())
66.236 + markOop(1);
66.237 +}
66.238 +
66.239 +bool
66.240 +BytecodeEmitter::allocate(VariableSymbol *sym)
66.241 +{
66.242 + assert(sym->isVariable());
66.243 + assert(sym->scope()->kind() == Scope::BLOCK);
66.244 +
66.245 + switch (sym->scope()->kind()) {
66.246 + case Scope::BLOCK:
66.247 + {
66.248 + // See overall comment on overflows.
66.249 + assert(locals_.length() < UINT_MAX);
66.250 + sym->allocate(VariableSymbol::Local, locals_.length());
66.251 + if (!locals_.append(sym))
66.252 + return false;
66.253 + break;
66.254 + }
66.255 +
66.256 + default:
66.257 + assert(false);
66.258 + return false;
66.259 + }
66.260 +
66.261 + return true;
66.262 +}
66.263 +
66.264 +Code *
66.265 +BytecodeEmitter::finish()
66.266 +{
66.267 + stop();
66.268 +
66.269 + Zone *zone = ZONE();
66.270 + if (oom() || zone->hasPendingException())
66.271 + return NULL;
66.272 +
66.273 + Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
66.274 + if (!bytes)
66.275 + return NULL;
66.276 + memcpy(bytes->raw(), buffer(), length());
66.277 +
66.278 + Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
66.279 + if (!objects)
66.280 + return NULL;
66.281 +
66.282 + for (size_t i = 0; i < objects_.length(); i++)
66.283 + objects->set(zone, i, objects_[i]);
66.284 +
66.285 + // If any stack slots hold gc pointers at potential failure points in the
66.286 + // bytecode, record them now. We do this by building a list of tuples;
66.287 + // each tuple contains the pc offset, and a bitset containing which stack
66.288 + // slots must be scanned by the gc.
66.289 + Local<ByteArray> safepoints(zone);
66.290 + if (oopRecords_.length()) {
66.291 + size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
66.292 + size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
66.293 + safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
66.294 + if (!safepoints)
66.295 + return NULL;
66.296 +
66.297 + Address cursor = safepoints->raw();
66.298 + for (size_t i = 0; i < oopRecords_.length(); i++) {
66.299 + OopRecord *record = oopRecords_[i];
66.300 + assert(record->depth <= maxStackDepth());
66.301 +
66.302 + *reinterpret_cast<unsigned *>(cursor) = record->offset;
66.303 +
66.304 + unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
66.305 + for (unsigned i = 0; i < record->depth; i++)
66.306 + bits[i / 8] |= (1 << (i % 8));
66.307 +
66.308 + cursor += bytesPerSafepoint;
66.309 + }
66.310 +
66.311 + assert(cursor == safepoints->raw() + gcmapSize);
66.312 + }
66.313 +
66.314 + Local<ByteArray> sourcemap(zone);
66.315 + if (sourcemap_.length()) {
66.316 + sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
66.317 + if (!sourcemap)
66.318 + return NULL;
66.319 +
66.320 + memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
66.321 + }
66.322 +
66.323 + Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
66.324 + if (!strings)
66.325 + return NULL;
66.326 + for (size_t i = 0; i < strings_.stringCount(); i++)
66.327 + strings->set(zone, i, strings_.stringAt(i));
66.328 +
66.329 + Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
66.330 + if (!locals)
66.331 + return NULL;
66.332 + for (size_t i = 0; i < locals_.length(); i++)
66.333 + locals->set(zone, i, locals_[i]->type());
66.334 +
66.335 + Local<Code> code(zone);
66.336 +
66.337 + code = Code::New(zone,
66.338 + bytes,
66.339 + locals,
66.340 + objects,
66.341 + strings,
66.342 + maxStackDepth(),
66.343 + safepoints,
66.344 + sourcemap);
66.345 +
66.346 + return code;
66.347 +}
67.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
67.2 +++ b/src/compiler/BytecodeEmitter.h Sat Nov 17 18:41:01 2012 -0800
67.3 @@ -0,0 +1,737 @@
67.4 +/* vim: set ts=4 sw=4 tw=99 et:
67.5 + *
67.6 + * Copyright (C) 2012 David Anderson
67.7 + *
67.8 + * This file is part of JITCraft.
67.9 + *
67.10 + * JITCraft is free software: you can redistribute it and/or modify it under
67.11 + * the terms of the GNU General Public License as published by the Free
67.12 + * Software Foundation, either version 3 of the License, or (at your option)
67.13 + * any later version.
67.14 + *
67.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
67.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
67.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
67.18 + *
67.19 + * You should have received a copy of the GNU General Public License along with
67.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
67.21 + */
67.22 +#ifndef _include_bytecode_emitter_h_
67.23 +#define _include_bytecode_emitter_h_
67.24 +
67.25 +#include <assert.h>
67.26 +#include <limits.h>
67.27 +#include "../Opcodes.h"
67.28 +#include "../Handles.h"
67.29 +#include "../CompactBuffer.h"
67.30 +#include "../Array.h"
67.31 +#include "../HashTable.h"
67.32 +#include "../VirtualObjectVisitor.h"
67.33 +
67.34 +namespace ke {
67.35 +
67.36 +// An overarching note on overflows: Though we should use CheckedInt, we rely
67.37 +// on a source-length cap covering all possible overflow checks. As long as
67.38 +// the source length is capped to INT_MAX, the number of AST nodes will be
67.39 +// strictly beneath that cap, and so to will most things generated by the
67.40 +// AST. For example, local and argument counts, number of functions, fields
67.41 +// in a struct, et cetera. Not everything can be covered by this cap: the
67.42 +// stack depth, number of bytecodes for example. In these cases we explicitly
67.43 +// test for overflow of INT_MAX and in other cases we assert.
67.44 +//
67.45 +// In the future, we should of course use a checked int wrapper.
67.46 +
67.47 +class Type;
67.48 +class Map;
67.49 +class ArrayMap;
67.50 +class Symbol;
67.51 +class VariableSymbol;
67.52 +
67.53 +struct OopRecord
67.54 +{
67.55 + unsigned depth;
67.56 + unsigned offset;
67.57 + Vector<bool> slots;
67.58 +
67.59 + OopRecord(unsigned length, unsigned offset)
67.60 + : depth(length),
67.61 + offset(offset)
67.62 + {
67.63 + }
67.64 +};
67.65 +
67.66 +class StringTable
67.67 +{
67.68 + struct Entry
67.69 + {
67.70 + String *string;
67.71 + unsigned index;
67.72 +
67.73 + Entry()
67.74 + : string(NULL),
67.75 + index(0)
67.76 + {
67.77 + }
67.78 +
67.79 + Entry(String *string, unsigned index)
67.80 + : string(string),
67.81 + index(index)
67.82 + {
67.83 + }
67.84 + };
67.85 +
67.86 + struct Policy
67.87 + {
67.88 + typedef Entry Payload;
67.89 +
67.90 + static uint32 hash(String *string) {
67.91 + return HashPointer(string);
67.92 + }
67.93 +
67.94 + static bool matches(String *key, Entry &e) {
67.95 + return key == e.string;
67.96 + }
67.97 + };
67.98 +
67.99 + typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
67.100 +
67.101 + public:
67.102 + StringTable();
67.103 + bool initialize();
67.104 + void accept(VirtualObjectVisitor *visitor);
67.105 +
67.106 + bool add(Handle<String> name, unsigned *indexp);
67.107 + size_t stringCount() const {
67.108 + return strings_.length();
67.109 + }
67.110 + String *stringAt(size_t i) const {
67.111 + return strings_[i].string;
67.112 + }
67.113 +
67.114 + private:
67.115 + Set set_;
67.116 + Vector<Entry> strings_;
67.117 + bool initialized_;
67.118 +};
67.119 +
67.120 +// The bytecode emitter assists in building Code objects, by emitting opcodes
67.121 +// and tracking stack information. Since the SemA creates temporary pool/root
67.122 +// scopes, we cannot use ScopedRoot or PoolObjects. Instead, BCE gets a
67.123 +// special marking function.
67.124 +class BytecodeEmitter : public AutoRooted
67.125 +{
67.126 + private:
67.127 + PoolAllocator &pool_;
67.128 +
67.129 + bytecode *buffer_;
67.130 + bytecode *buffer_pos_;
67.131 + bytecode *buffer_end_;
67.132 + bytecode inline_buffer_[512];
67.133 + bool oom_;
67.134 + unsigned maxStackDepth_;
67.135 + Vector<bool> oopMap_;
67.136 + Vector<OopRecord *> oopRecords_;
67.137 + CompactBufferWriter sourcemap_;
67.138 + unsigned lastCodePosition_;
67.139 + unsigned firstLine_;
67.140 + StringTable strings_;
67.141 + Vector<Symbol *> locals_;
67.142 + Vector<Object *> objects_;
67.143 +
67.144 + private:
67.145 + // The maximum size of a code object must be such that the distance between
67.146 + // two instructions fits into a signed, 31-bit integer. This ensures that
67.147 + // all code-bounded buffers (like the number of object literals or
67.148 + // safepoints) does not need to be bounds checked. It also means we can add
67.149 + // any two offsets and be guaranteed that they don't overflow.
67.150 + static const size_t MAX_LENGTH = INT_MAX / 2;
67.151 +
67.152 + private:
67.153 + bool growBuffer(size_t bytes);
67.154 +
67.155 + // Checking the return value is not necessary, since the inline buffer is
67.156 + // used as a ballast.
67.157 + bool ensure(size_t bytes) {
67.158 + if (buffer_pos_ + bytes > buffer_end_)
67.159 + return growBuffer(bytes);
67.160 + return true;
67.161 + }
67.162 +
67.163 + void writeUint8(unsigned value) {
67.164 + assert(value <= UCHAR_MAX);
67.165 + *buffer_pos_++ = value;
67.166 + }
67.167 + void writeFloat(float value) {
67.168 + *(float *)buffer_pos_ = value;
67.169 + buffer_pos_ += sizeof(float);
67.170 + }
67.171 + void writeInt32(int value) {
67.172 + *(int *)buffer_pos_ = value;
67.173 + buffer_pos_ += sizeof(int);
67.174 + }
67.175 + void writeUint32(unsigned value) {
67.176 + *(unsigned *)buffer_pos_ = value;
67.177 + buffer_pos_ += sizeof(unsigned);
67.178 + }
67.179 + void writeOp(Opcode op) {
67.180 + if (oom_)
67.181 + return;
67.182 +
67.183 + writeUint8(op);
67.184 + for (int i = 0; i < OpcodeInfo[op].nuses; i++)
67.185 + oopMap_.pop();
67.186 + for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
67.187 + oopMap_.append(false);
67.188 + if (oopMap_.length() > maxStackDepth_)
67.189 + maxStackDepth_ = oopMap_.length();
67.190 + }
67.191 + void writeObject(Object *obj) {
67.192 + writeUint32(objects_.length());
67.193 + ScopedRoot<Object> root(obj);
67.194 + if (!objects_.append(root))
67.195 + oom_ = true;
67.196 + }
67.197 +
67.198 + int position() const {
67.199 + assert(buffer_pos_ - buffer_ < INT_MAX / 2);
67.200 + return int(buffer_pos_ - buffer_);
67.201 + }
67.202 +
67.203 + public:
67.204 + BytecodeEmitter(PoolAllocator &pool);
67.205 + ~BytecodeEmitter();
67.206 +
67.207 + void accept(VirtualObjectVisitor *visitor);
67.208 +
67.209 + bytecode *buffer() const {
67.210 + return buffer_;
67.211 + }
67.212 + unsigned length() const {
67.213 + return unsigned(buffer_pos_ - buffer_);
67.214 + }
67.215 + bool oom() const {
67.216 + return oom_ || sourcemap_.oom();
67.217 + }
67.218 + unsigned stackDepth() const {
67.219 + return oopMap_.length();
67.220 + }
67.221 + unsigned maxStackDepth() const {
67.222 + return maxStackDepth_;
67.223 + }
67.224 +
67.225 + void drop(unsigned amt) {
67.226 + assert(amt <= stackDepth());
67.227 + for (unsigned i = 0; i < amt; i++)
67.228 + oopMap_.pop();
67.229 + }
67.230 +
67.231 + void note_position(const SourcePosition &pos);
67.232 + void setFirstLine(unsigned line) {
67.233 + assert(!sourcemap_.length());
67.234 + firstLine_ = line;
67.235 + }
67.236 +
67.237 + public:
67.238 + // A label represents a local control-flow target in the bytecode. A label
67.239 + // may be in three states:
67.240 + //
67.241 + // (1) Empty - the label is not used yet.
67.242 + // (2) Pending - the label has incoming jumps, but the actual location of
67.243 + // is not yet known. The list of jumps is threaded through
67.244 + // the four bytes reserved for each emitted jump target. In
67.245 + // this case, the offset field is the location of the most
67.246 + // recently emitted incoming jump.
67.247 + // (3) Bound - the label's position has been pinned.
67.248 + //
67.249 + // A jump can be emitted to a label in any state. Binding a label
67.250 + // immediately backpatches all pending incoming jumps. A label must be
67.251 + // bound if it is used.
67.252 + class Label
67.253 + {
67.254 + int offset_ : 31;
67.255 + bool bound_ : 1;
67.256 +
67.257 + void setOffset(int offset) {
67.258 + offset_ = offset;
67.259 + assert(offset_ == offset);
67.260 + }
67.261 +
67.262 + public:
67.263 + static const int INVALID_OFFSET = -1;
67.264 +
67.265 + public:
67.266 + Label()
67.267 + : offset_(INVALID_OFFSET),
67.268 + bound_(false)
67.269 + {
67.270 + }
67.271 + ~Label()
67.272 + {
67.273 + assert(bound_ || offset_ == INVALID_OFFSET);
67.274 + }
67.275 +
67.276 + bool bound() const {
67.277 + return bound_;
67.278 + }
67.279 + int offset() const {
67.280 + return offset_;
67.281 + }
67.282 + void bind(int offset) {
67.283 + assert(!bound_);
67.284 + setOffset(offset);
67.285 + bound_ = true;
67.286 + }
67.287 + int link(int offset) {
67.288 + assert(!bound_);
67.289 + int old = offset_;
67.290 + setOffset(offset);
67.291 + return old;
67.292 + }
67.293 + };
67.294 +
67.295 + private:
67.296 + int patchJumpAt(int at, int to) {
67.297 + assert(at >= 0 && at < position());
67.298 + int old = *(int *)(buffer_ + at + 1);
67.299 + *(int *)(buffer_ + at + 1) = (to - at);
67.300 + return old;
67.301 + }
67.302 +
67.303 + void singleByteOp(Opcode op) {
67.304 + assert(OpcodeInfo[op].length == 1);
67.305 + ensure(OpcodeInfo[op].length);
67.306 + writeOp(op);
67.307 + }
67.308 +
67.309 + // Mark a stack slot as having an object pointer.
67.310 + void markOop(unsigned depth, bool oop = true) {
67.311 + if (oom_)
67.312 + return;
67.313 + oopMap_[oopMap_.length() - depth] = oop;
67.314 + }
67.315 + bool getOop(unsigned depth) {
67.316 + if (oom_)
67.317 + return false;
67.318 + return oopMap_[oopMap_.length() - depth];
67.319 + }
67.320 +
67.321 + // Mark the current bytecode position as either re-entrant (meaning, it
67.322 + // can leave the interpreter or call to another function), or causing GC.
67.323 + // This will record which stack slots have objects and associate that
67.324 + // information with the current pc.
67.325 + void recordOops();
67.326 +
67.327 + public:
67.328 + void int_(int value) {
67.329 + ensure(OP_INT);
67.330 + writeOp(OP_INT);
67.331 + writeInt32(value);
67.332 + }
67.333 + void return_() {
67.334 + ensure(OP_RETURN);
67.335 + writeOp(OP_RETURN);
67.336 + }
67.337 + void getlocal(VariableSymbol *var);
67.338 + void setlocal(VariableSymbol *var);
67.339 +#if 0
67.340 + void getarg(Variable *var) {
67.341 + ensure(OP_GETARG_LENGTH);
67.342 + writeOp(OP_GETARG);
67.343 + writeUint32(var->slot());
67.344 +
67.345 + if (var->type()->isTraceable())
67.346 + markOop(1);
67.347 + }
67.348 + void setarg(Variable *var) {
67.349 + ensure(OP_SETARG_LENGTH);
67.350 + writeOp(OP_SETARG);
67.351 + writeUint32(var->slot());
67.352 +
67.353 + if (var->type()->isTraceable())
67.354 + markOop(1);
67.355 + }
67.356 +#endif
67.357 +
67.358 + void j(Opcode op, Label *label) {
67.359 + // Since jumps can skip around the stream, do not try to do anything
67.360 + // in a potentially truncated state.
67.361 + if (oom())
67.362 + return;
67.363 +
67.364 + assert(op == OP_JT || op == OP_JF || op == OP_JUMP);
67.365 + ensure(OP_JUMP_LENGTH);
67.366 +
67.367 + if (label->bound()) {
67.368 + // We can immediately emit this jump.
67.369 + int distance = label->offset() - position();
67.370 + writeOp(op);
67.371 + writeInt32(distance);
67.372 + } else {
67.373 + // We can't emit this jump yet. Add a placeholder.
67.374 + int old = label->link(position());
67.375 + writeOp(op);
67.376 + writeInt32(old);
67.377 + }
67.378 + }
67.379 + void bind(Label *label) {
67.380 + if (oom())
67.381 + return;
67.382 +
67.383 + assert(!label->bound());
67.384 +
67.385 + int offset = label->offset();
67.386 + while (offset != Label::INVALID_OFFSET)
67.387 + offset = patchJumpAt(offset, position());
67.388 +
67.389 + label->bind(position());
67.390 + }
67.391 + void jump(Label *label) {
67.392 + j(OP_JUMP, label);
67.393 + }
67.394 +
67.395 + void binary(Opcode op) {
67.396 + singleByteOp(op);
67.397 + }
67.398 + void unary(Opcode op) {
67.399 + singleByteOp(op);
67.400 + }
67.401 +
67.402 + void pop() {
67.403 + singleByteOp(OP_POP);
67.404 + }
67.405 + void stop() {
67.406 + singleByteOp(OP_STOP);
67.407 + }
67.408 + void call(Handle<FunctionType> fun, unsigned argc) {
67.409 + recordOops();
67.410 +
67.411 + if (fun->isNative()) {
67.412 + ensure(OP_CALLNATIVE_LENGTH);
67.413 + writeOp(OP_CALLNATIVE);
67.414 + writeUint32(argc);
67.415 + drop(argc + 1);
67.416 + } else {
67.417 + ensure(OP_CALL_LENGTH);
67.418 + writeOp(OP_CALL);
67.419 + drop(argc + 1);
67.420 +
67.421 + if (fun->returnType()->isVoid())
67.422 + drop(1);
67.423 + else if (fun->returnType()->isTraceable())
67.424 + markOop(1);
67.425 + }
67.426 + }
67.427 +
67.428 + void getelem(Type *type) {
67.429 + singleByteOp(OP_GETELEM);
67.430 +
67.431 + if (type->isTraceable())
67.432 + markOop(1);
67.433 + }
67.434 + void setelem(Type *type) {
67.435 + singleByteOp(OP_SETELEM);
67.436 + }
67.437 +
67.438 + void getfield(unsigned index, Type *type) {
67.439 + ensure(OP_GETFIELD_LENGTH);
67.440 + writeOp(OP_GETFIELD);
67.441 + writeUint32(index);
67.442 +
67.443 + if (type->isTraceable())
67.444 + markOop(1);
67.445 + }
67.446 + void setfield(unsigned index, Type *type) {
67.447 + ensure(OP_SETFIELD_LENGTH);
67.448 + writeOp(OP_SETFIELD);
67.449 + writeUint32(index);
67.450 +
67.451 + if (type->isTraceable())
67.452 + markOop(1);
67.453 + }
67.454 +
67.455 +#if 0
67.456 + void getglobal(Variable *var) {
67.457 + ensure(OP_GETGLOBAL_F_LENGTH);
67.458 + if (var->type()->isPrimitive()) {
67.459 + switch (var->type()->primitive()) {
67.460 + case PrimitiveType_Float:
67.461 + writeOp(OP_GETGLOBAL_F);
67.462 + break;
67.463 + default:
67.464 + assert(var->type()->primitive() == PrimitiveType_Int32);
67.465 + writeOp(OP_GETGLOBAL_I);
67.466 + break;
67.467 + }
67.468 + } else {
67.469 + writeOp(OP_GETGLOBAL_O);
67.470 + markOop(1);
67.471 + }
67.472 + writeUint32(var->slot());
67.473 + }
67.474 + void setglobal(Variable *var) {
67.475 + ensure(OP_SETGLOBAL_F_LENGTH);
67.476 + if (var->type()->isPrimitive()) {
67.477 + switch (var->type()->primitive()) {
67.478 + case PrimitiveType_Float:
67.479 + writeOp(OP_SETGLOBAL_F);
67.480 + break;
67.481 + default:
67.482 + assert(var->type()->primitive() == PrimitiveType_Int32);
67.483 + writeOp(OP_SETGLOBAL_I);
67.484 + break;
67.485 + }
67.486 + } else {
67.487 + writeOp(OP_SETGLOBAL_O);
67.488 + }
67.489 + writeUint32(var->slot());
67.490 + }
67.491 +#endif
67.492 +
67.493 + void float_(float value) {
67.494 + ensure(OP_FLOAT_LENGTH);
67.495 + writeOp(OP_FLOAT);
67.496 + writeFloat(value);
67.497 + }
67.498 + void cvt_i2f() {
67.499 + singleByteOp(OP_CVT_I2F);
67.500 + }
67.501 + void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
67.502 + assert(op == OP_NEWFIXED ||
67.503 + op == OP_NEWEMPTY ||
67.504 + op == OP_NEWSIZED);
67.505 +
67.506 + recordOops();
67.507 + ensure(OpcodeInfo[op].length);
67.508 + writeOp(op);
67.509 + writeUint8(tenure);
67.510 + writeObject(map);
67.511 +
67.512 + if (op == OP_NEWSIZED)
67.513 + drop(map->type()->levels());
67.514 +
67.515 + markOop(1);
67.516 + }
67.517 + void newstruct(Handle<Map> map, Heap::Tenure tenure) {
67.518 + recordOops();
67.519 + ensure(OP_NEWSTRUCT_LENGTH);
67.520 + writeOp(OP_NEWSTRUCT);
67.521 + writeUint8(tenure);
67.522 + writeObject(map);
67.523 + markOop(1);
67.524 + }
67.525 + void savelifo(unsigned slot) {
67.526 + ensure(OP_SAVELIFO_LENGTH);
67.527 + writeOp(OP_SAVELIFO);
67.528 + writeUint32(slot);
67.529 + }
67.530 + void unwindlifo(unsigned slot) {
67.531 + ensure(OP_UNWINDLIFO_LENGTH);
67.532 + writeOp(OP_UNWINDLIFO);
67.533 + writeUint32(slot);
67.534 + }
67.535 +#if 0
67.536 + void newref(Variable *var) {
67.537 + recordOops();
67.538 + if (var->location() == Variable::STACK) {
67.539 + ensure(OP_VARREF_LIFO_LENGTH);
67.540 + writeOp(OP_VARREF_LIFO);
67.541 + } else {
67.542 + assert(var->location() == Variable::PARAMETER);
67.543 + ensure(OP_ARGREF_LIFO_LENGTH);
67.544 + writeOp(OP_ARGREF_LIFO);
67.545 + }
67.546 + writeUint32(var->slot());
67.547 + markOop(1);
67.548 + }
67.549 +#endif
67.550 +
67.551 + void slotref_lifo() {
67.552 + recordOops();
67.553 + singleByteOp(OP_SLOTREF_LIFO);
67.554 + markOop(1);
67.555 + }
67.556 + void getref(Type *type) {
67.557 + if (type->pod() == PrimitiveType_Int32) {
67.558 + singleByteOp(OP_GETREF_I);
67.559 + } else {
67.560 + assert(type->pod() == PrimitiveType_Float);
67.561 + singleByteOp(OP_GETREF_F);
67.562 + }
67.563 + }
67.564 + void setref(Type *type) {
67.565 + if (type->pod() == PrimitiveType_Int32) {
67.566 + singleByteOp(OP_SETREF_I);
67.567 + } else {
67.568 + assert(type->pod() == PrimitiveType_Float);
67.569 + singleByteOp(OP_SETREF_F);
67.570 + }
67.571 + }
67.572 + void object(Handle<Object> obj) {
67.573 + ensure(OP_OBJECT_LENGTH);
67.574 + writeOp(OP_OBJECT);
67.575 + writeObject(obj);
67.576 + markOop(1);
67.577 + }
67.578 + void copyarray() {
67.579 + singleByteOp(OP_COPYARRAY);
67.580 + markOop(1);
67.581 + }
67.582 + void copystruct() {
67.583 + singleByteOp(OP_COPYSTRUCT);
67.584 + markOop(1);
67.585 + }
67.586 + void sizeof_() {
67.587 + singleByteOp(OP_SIZEOF);
67.588 + }
67.589 +
67.590 + void dup() {
67.591 + bool oop = getOop(1);
67.592 + singleByteOp(OP_DUP);
67.593 + markOop(1, oop);
67.594 + }
67.595 + void dup2() {
67.596 + bool oop2 = getOop(2);
67.597 + bool oop1 = getOop(1);
67.598 +
67.599 + singleByteOp(OP_DUP2);
67.600 +
67.601 + markOop(2, oop2);
67.602 + markOop(1, oop1);
67.603 + }
67.604 + void swap() {
67.605 + bool oop2 = getOop(2);
67.606 + bool oop1 = getOop(1);
67.607 +
67.608 + singleByteOp(OP_SWAP);
67.609 +
67.610 + markOop(2, oop1);
67.611 + markOop(1, oop2);
67.612 + }
67.613 + void roll3() {
67.614 + bool oop3 = getOop(3);
67.615 + bool oop2 = getOop(2);
67.616 + bool oop1 = getOop(1);
67.617 +
67.618 + singleByteOp(OP_ROLL3);
67.619 +
67.620 + markOop(3, oop2);
67.621 + markOop(2, oop1);
67.622 + markOop(1, oop3);
67.623 + }
67.624 + void pick2() {
67.625 + bool oop2 = getOop(2);
67.626 + bool oop1 = getOop(1);
67.627 +
67.628 + singleByteOp(OP_PICK2);
67.629 +
67.630 + markOop(3, oop2);
67.631 + markOop(2, oop1);
67.632 + markOop(1, oop2);
67.633 + }
67.634 + void pick3() {
67.635 + bool oop3 = getOop(3);
67.636 + bool oop2 = getOop(2);
67.637 + bool oop1 = getOop(1);
67.638 +
67.639 + singleByteOp(OP_PICK3);
67.640 +
67.641 + markOop(4, oop3);
67.642 + markOop(3, oop2);
67.643 + markOop(2, oop1);
67.644 + markOop(1, oop3);
67.645 + }
67.646 +
67.647 + void returnvoid() {
67.648 + singleByteOp(OP_RETURNVOID);
67.649 + }
67.650 + void bitnot() {
67.651 + singleByteOp(OP_BITNOT);
67.652 + }
67.653 + void not_() {
67.654 + singleByteOp(OP_NOT);
67.655 + }
67.656 + void not_f() {
67.657 + singleByteOp(OP_NOT_F);
67.658 + }
67.659 + void neg() {
67.660 + singleByteOp(OP_NEG);
67.661 + }
67.662 + void neg_f() {
67.663 + singleByteOp(OP_NEG_F);
67.664 + }
67.665 + void bits_i2f() {
67.666 + singleByteOp(OP_BITS_I2F);
67.667 + }
67.668 + void bits_f2i() {
67.669 + singleByteOp(OP_BITS_F2I);
67.670 + }
67.671 + void true_() {
67.672 + singleByteOp(OP_TRUE);
67.673 + }
67.674 + void false_() {
67.675 + singleByteOp(OP_FALSE);
67.676 + }
67.677 +
67.678 + unsigned addString(Handle<String> name) {
67.679 + unsigned index;
67.680 + if (!strings_.add(name, &index)) {
67.681 + oom_ |= true;
67.682 + return 0;
67.683 + }
67.684 + return index;
67.685 + }
67.686 +
67.687 + void getglobal(Symbol *sym);
67.688 + void setglobal(Symbol *sym);
67.689 +
67.690 + void public_() {
67.691 + recordOops();
67.692 + singleByteOp(OP_PUBLIC);
67.693 + }
67.694 +
67.695 + void tableswitch(int low, int high, Label *def, Label **labels) {
67.696 + unsigned tablesize = TableSwitchEntries(low, high);
67.697 + assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
67.698 +
67.699 + ensure(OP_TABLESWITCH_LENGTH);
67.700 + writeOp(OP_TABLESWITCH);
67.701 + writeInt32(low);
67.702 + writeInt32(high);
67.703 + jump(def);
67.704 +
67.705 + // When labels are patched, we assume each position is a jump. Rather
67.706 + // than hack position offsets to make labels work without actual
67.707 + // incoming jumps, we emit a jump inline.
67.708 + for (unsigned i = 0; i < tablesize; i++)
67.709 + jump(labels[i]);
67.710 + }
67.711 +
67.712 + bool allocate(VariableSymbol *sym);
67.713 +
67.714 + Code *finish();
67.715 +
67.716 + // Helpers.
67.717 +#if 0
67.718 + void get(Variable *var) {
67.719 + if (var->location() == Variable::STACK) {
67.720 + getlocal(var);
67.721 + } else {
67.722 + assert(var->location() == Variable::PARAMETER);
67.723 + getarg(var);
67.724 + }
67.725 + }
67.726 + void set(Variable *var) {
67.727 + assert(!var->type()->isReference());
67.728 + if (var->location() == Variable::STACK) {
67.729 + setlocal(var);
67.730 + } else {
67.731 + assert(var->location() == Variable::PARAMETER);
67.732 + setarg(var);
67.733 + }
67.734 + }
67.735 +#endif
67.736 +};
67.737 +
67.738 +}
67.739 +
67.740 +#endif // _include_bytecode_emitter_h_
68.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
68.2 +++ b/src/compiler/CompileContext.cpp Sat Nov 17 18:41:01 2012 -0800
68.3 @@ -0,0 +1,268 @@
68.4 +/*
68.5 + * Copyright (C) 2012 David Anderson
68.6 + *
68.7 + * This file is part of JITCraft.
68.8 + *
68.9 + * JITCraft is free software: you can redistribute it and/or modify it under
68.10 + * the terms of the GNU General Public License as published by the Free
68.11 + * Software Foundation, either version 3 of the License, or (at your option)
68.12 + * any later version.
68.13 + *
68.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
68.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
68.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
68.17 + *
68.18 + * You should have received a copy of the GNU General Public License along with
68.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
68.20 + */
68.21 +#include <stdio.h>
68.22 +#include "../Zone.h"
68.23 +#include "../Interpreter.h"
68.24 +#include "Scanner.h"
68.25 +#include "CompileContext.h"
68.26 +#include "Parser.h"
68.27 +#include "NameBinding.h"
68.28 +#include "SemanticAnalysis.h"
68.29 +#include "../Spaces-inl.h"
68.30 +#include "../Heap-inl.h"
68.31 +
68.32 +using namespace ke;
68.33 +
68.34 +CompileContext::CompileContext(Zone *zone, const char *file)
68.35 + : zone_(zone),
68.36 + failures_(0),
68.37 + file_(file)
68.38 +{
68.39 +}
68.40 +
68.41 +CompileContext::~CompileContext()
68.42 +{
68.43 + if (failures_)
68.44 + zone_->endCompilationErrors();
68.45 +}
68.46 +
68.47 +bool
68.48 +CompileContext::addTranslationUnit(TranslationUnit *unit)
68.49 +{
68.50 + if (!units_.append(unit))
68.51 + return false;
68.52 +
68.53 + if (!unparsed_.append(unit))
68.54 + return false;
68.55 +
68.56 + return true;
68.57 +}
68.58 +
68.59 +char *
68.60 +CompileContext::loadSource(const char *file, size_t *lengthp)
68.61 +{
68.62 + char *bytes = NULL;
68.63 + size_t length;
68.64 +
68.65 + FILE *fp = fopen(file, "rb");
68.66 + if (!fp) {
68.67 + reportError(SourcePosition(), Message_CantOpenFile);
68.68 + return NULL;
68.69 + }
68.70 +
68.71 + if (fseek(fp, 0, SEEK_END)) {
68.72 + reportError(SourcePosition(), Message_ErrorSeekingFile);
68.73 + fclose(fp);
68.74 + return NULL;
68.75 + }
68.76 + long size = ftell(fp);
68.77 + if (size < 0) {
68.78 + reportError(SourcePosition(), Message_ErrorSeekingFile);
68.79 + fclose(fp);
68.80 + return NULL;
68.81 + }
68.82 + rewind(fp);
68.83 + length = size_t(size);
68.84 + bytes = new char[length + 1];
68.85 + if (fread(bytes, 1, length, fp) != length) {
68.86 + reportError(SourcePosition(), Message_ErrorReadingFile);
68.87 + fclose(fp);
68.88 + delete [] bytes;
68.89 + return NULL;
68.90 + }
68.91 + fclose(fp);
68.92 +
68.93 + *lengthp = length;
68.94 + return bytes;
68.95 +}
68.96 +
68.97 +bool
68.98 +CompileContext::parse(TranslationUnit *unit)
68.99 +{
68.100 + assert(!unit->tree_);
68.101 +
68.102 + size_t length;
68.103 + char *source = loadSource(unit->path_.c_str(), &length);
68.104 + if (!source)
68.105 + return false;
68.106 +
68.107 + Parser parser(ZONE(), *this, source, length);
68.108 + if ((unit->tree_ = parser.parse()) == NULL)
68.109 + return false;
68.110 +
68.111 + return true;
68.112 +}
68.113 +
68.114 +bool
68.115 +CompileContext::evaluateImports(TranslationUnit *unit)
68.116 +{
68.117 + if (units_.length() > 1)
68.118 + return true;
68.119 +
68.120 +#if 0
68.121 + // For now we hardcode this...
68.122 + TranslationUnit *u2 = new (ZONE()->pool()) TranslationUnit();
68.123 + u2->path_ = "C:\\Users\\dvander\\jitcraft\\jitcraft-2\\src\\Debug\\wizard.sp";
68.124 +
68.125 + ImportStatement *stmt = unit->tree()->imports()->at(0)->toImportStatement();
68.126 + stmt->setImportSource(u2);
68.127 +
68.128 + if (!u2->dependents_.append(unit))
68.129 + return false;
68.130 +
68.131 + if (!addTranslationUnit(u2))
68.132 + return false;
68.133 +#endif
68.134 +
68.135 + return true;
68.136 +}
68.137 +
68.138 +bool
68.139 +CompileContext::propagateFailure()
68.140 +{
68.141 + Vector<TranslationUnit *> worklist;
68.142 + for (size_t i = 0; i < units_.length(); i++) {
68.143 + if (units_[i]->failed() && !worklist.append(units_[i]))
68.144 + return false;
68.145 + }
68.146 +
68.147 + while (!worklist.empty()) {
68.148 + TranslationUnit *unit = worklist.popCopy();
68.149 + for (size_t i = 0; i < unit->dependents().length(); i++) {
68.150 + TranslationUnit *other = unit->dependents().at(i);
68.151 + if (other->failed())
68.152 + continue;
68.153 +
68.154 + other->failed_ = true;
68.155 + if (!worklist.append(other))
68.156 + return false;
68.157 + }
68.158 + }
68.159 +
68.160 + return true;
68.161 +}
68.162 +
68.163 +bool
68.164 +CompileContext::compile()
68.165 +{
68.166 + // Phase 1. Parse all modules we're importing. This process may load new
68.167 + // modules off disk, and add them to the parse queue.
68.168 + while (!unparsed_.empty()) {
68.169 + TranslationUnit *unit = unparsed_.popCopy();
68.170 +
68.171 + if (!parse(unit))
68.172 + unit->failed_ = true;
68.173 +
68.174 + if (!evaluateImports(unit))
68.175 + unit->failed_ = true;
68.176 + }
68.177 +
68.178 + // Phase 2. Create scopes and symbol tables for every lexical region with
68.179 + // a declaration. This phase excludes declarations created via imports.
68.180 + for (size_t i = 0; i < units_.length(); i++) {
68.181 + TranslationUnit *unit = units_[i];
68.182 + if (unit->failed())
68.183 + continue;
68.184 +
68.185 + if (!PopulateNamesAndTypes(zone_, *this, unit))
68.186 + unit->failed_ = true;
68.187 + }
68.188 +
68.189 + // Phase 3. Complete imports and bind all names.
68.190 + for (size_t i = 0; i < units_.length(); i++) {
68.191 + TranslationUnit *unit = units_[i];
68.192 + if (unit->failed())
68.193 + continue;
68.194 +
68.195 + if (!BindNamesAndTypes(zone_, *this, unit))
68.196 + unit->failed_ = true;
68.197 + }
68.198 +
68.199 + // Phase 4. Assign types to every public name in the module.
68.200 + for (size_t i = 0; i < units_.length(); i++) {
68.201 + TranslationUnit *unit = units_[i];
68.202 + if (unit->failed())
68.203 + continue;
68.204 +
68.205 + }
68.206 +
68.207 + // Intermediate phase. Decide which modules we should not perform
68.208 + // semantic analysis on.
68.209 + if (!propagateFailure())
68.210 + return false;
68.211 +
68.212 + // Phase 4. Perform full semantic analysis on each module.
68.213 + for (size_t i = 0; i < units_.length(); i++) {
68.214 + TranslationUnit *unit = units_[i];
68.215 + if (unit->failed())
68.216 + continue;
68.217 +
68.218 +
68.219 + }
68.220 +
68.221 + // Intermediate phase. Propagate failure from semantic analysis.
68.222 + if (!propagateFailure())
68.223 + return false;
68.224 +
68.225 + // Phase 5. Now we can finally perform bytecode compilation.
68.226 + for (size_t i = 0; i < units_.length(); i++) {
68.227 + TranslationUnit *unit = units_[i];
68.228 + if (unit->failed())
68.229 + continue;
68.230 +
68.231 + SemanticAnalysis sema(zone_, *this, unit);
68.232 + sema.analyze();
68.233 + }
68.234 +
68.235 + // Phase 6. Run modules.
68.236 + for (size_t i = 0; i < units_.length(); i++) {
68.237 + TranslationUnit *unit = units_[i];
68.238 + if (unit->failed())
68.239 + continue;
68.240 +
68.241 + InvokeArgs args;
68.242 + if (!zone_->stack().pushModuleFrame(unit->module_, args))
68.243 + assert(false);
68.244 +
68.245 + ke::LocalSlot slot;
68.246 + if (!Interpret(zone_, NULL, &slot))
68.247 + assert(false);
68.248 + }
68.249 +
68.250 + return true;
68.251 +}
68.252 +
68.253 +void
68.254 +CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
68.255 +{
68.256 + if (!failures_)
68.257 + zone_->beginCompilationErrors(file_);
68.258 +
68.259 + zone_->reportCompilationError(msg, pos.line, pos.col, ap);
68.260 +
68.261 + failures_++;
68.262 +}
68.263 +
68.264 +void
68.265 +CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
68.266 +{
68.267 + va_list ap;
68.268 + va_start(ap, msg);
68.269 + reportErrorVa(pos, msg, ap);
68.270 + va_end(ap);
68.271 +}
69.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
69.2 +++ b/src/compiler/CompileContext.h Sat Nov 17 18:41:01 2012 -0800
69.3 @@ -0,0 +1,113 @@
69.4 +/*
69.5 + * Copyright (C) 2012 David Anderson
69.6 + *
69.7 + * This file is part of JITCraft.
69.8 + *
69.9 + * JITCraft is free software: you can redistribute it and/or modify it under
69.10 + * the terms of the GNU General Public License as published by the Free
69.11 + * Software Foundation, either version 3 of the License, or (at your option)
69.12 + * any later version.
69.13 + *
69.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
69.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
69.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
69.17 + *
69.18 + * You should have received a copy of the GNU General Public License along with
69.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
69.20 + */
69.21 +#ifndef _include_jitcraft_compile_context_h_
69.22 +#define _include_jitcraft_compile_context_h_
69.23 +
69.24 +#include <stdarg.h>
69.25 +#include <string>
69.26 +#include "../Messages.h"
69.27 +#include "../PoolAllocator.h"
69.28 +#include "../Handles.h"
69.29 +#include "../Modules.h"
69.30 +
69.31 +namespace ke {
69.32 +
69.33 +class Zone;
69.34 +class ParseTree;
69.35 +class String;
69.36 +class ImportScope;
69.37 +class GlobalScope;
69.38 +struct SourcePosition;
69.39 +struct TranslationUnit;
69.40 +class ImportStatement;
69.41 +
69.42 +struct TranslationUnit : public PoolObject
69.43 +{
69.44 + TranslationUnit()
69.45 + : tree_(NULL),
69.46 + failed_(false),
69.47 + importScope_(NULL),
69.48 + globalScope_(NULL)
69.49 + {
69.50 + }
69.51 +
69.52 + ParseTree *tree_;
69.53 + std::string path_;
69.54 + bool failed_;
69.55 + PoolList<TranslationUnit *> dependents_;
69.56 + ImportScope *importScope_;
69.57 + GlobalScope *globalScope_;
69.58 + ScopedRoot<Module> module_;
69.59 +
69.60 + ParseTree *tree() const {
69.61 + return tree_;
69.62 + }
69.63 + PoolList<TranslationUnit *> &dependents() {
69.64 + return dependents_;
69.65 + }
69.66 + bool failed() const {
69.67 + return failed_;
69.68 + }
69.69 + void setImportScope(ImportScope *scope) {
69.70 + assert(!importScope_);
69.71 + importScope_ = scope;
69.72 + }
69.73 + void setGlobalScope(GlobalScope *scope) {
69.74 + assert(!globalScope_);
69.75 + globalScope_ = scope;
69.76 + }
69.77 + ImportScope *importScope() const {
69.78 + return importScope_;
69.79 + }
69.80 + GlobalScope *globalScope() const {
69.81 + return globalScope_;
69.82 + }
69.83 +};
69.84 +
69.85 +class CompileContext
69.86 +{
69.87 + Zone *zone_;
69.88 + unsigned failures_;
69.89 + const char *file_;
69.90 + Vector<TranslationUnit *> units_;
69.91 + Vector<TranslationUnit *> unparsed_;
69.92 +
69.93 + private:
69.94 + char *loadSource(const char *file, size_t *length);
69.95 + bool parse(TranslationUnit *unit);
69.96 + bool evaluateImports(TranslationUnit *unit);
69.97 + bool propagateFailure();
69.98 +
69.99 + public:
69.100 + CompileContext(Zone *zone, const char *file);
69.101 + ~CompileContext();
69.102 +
69.103 + bool addTranslationUnit(TranslationUnit *unit);
69.104 + bool compile();
69.105 +
69.106 + void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
69.107 + void reportError(const SourcePosition &pos, Message msg, ...);
69.108 +
69.109 + unsigned failures() const {
69.110 + return failures_;
69.111 + }
69.112 +};
69.113 +
69.114 +}
69.115 +
69.116 +#endif // _include_jitcraft_compile_context_h_
70.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
70.2 +++ b/src/compiler/HIR.cpp Sat Nov 17 18:41:01 2012 -0800
70.3 @@ -0,0 +1,246 @@
70.4 +/* vim: set ts=4 sw=4 tw=99 et:
70.5 + *
70.6 + * Copyright (C) 2012 David Anderson
70.7 + *
70.8 + * This file is part of JITCraft.
70.9 + *
70.10 + * JITCraft is free software: you can redistribute it and/or modify it under
70.11 + * the terms of the GNU General Public License as published by the Free
70.12 + * Software Foundation, either version 3 of the License, or (at your option)
70.13 + * any later version.
70.14 + *
70.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
70.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
70.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
70.18 + *
70.19 + * You should have received a copy of the GNU General Public License along with
70.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
70.21 + */
70.22 +#include "HIR.h"
70.23 +#include "BytecodeEmitter.h"
70.24 +
70.25 +using namespace ke;
70.26 +
70.27 +class HIRTranslator : public HIRVisitor
70.28 +{
70.29 + public:
70.30 + HIRTranslator(Zone *zone, BytecodeEmitter &emitter)
70.31 + : zone_(zone),
70.32 + emitter_(emitter)
70.33 + {
70.34 + }
70.35 +
70.36 + void translate(HIR *hir) {
70.37 + hir->accept(this);
70.38 + }
70.39 +
70.40 + void visitFloat(HFloat *hir);
70.41 + void visitInteger(HInteger *hir);
70.42 + void visitCall(HCall *call);
70.43 + void visitStore(HStore *store);
70.44 + void visitBinary(HBinary *binary);
70.45 + void visitLocal(HLocal *local);
70.46 + void visitGlobal(HGlobal *global);
70.47 + void visitConvert(HConvert *convert);
70.48 +
70.49 + private:
70.50 + Zone *zone_;
70.51 + BytecodeEmitter &emitter_;
70.52 +};
70.53 +
70.54 +#define __ emitter_.
70.55 +
70.56 +void
70.57 +HIRTranslator::visitFloat(HFloat *hir)
70.58 +{
70.59 + __ float_(hir->value());
70.60 +}
70.61 +
70.62 +void
70.63 +HIRTranslator::visitInteger(HInteger *hir)
70.64 +{
70.65 + __ int_(hir->value());
70.66 +}
70.67 +
70.68 +void
70.69 +HIRTranslator::visitCall(HCall *call)
70.70 +{
70.71 + Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
70.72 +
70.73 + assert(call->args()->length() == fun->parameters()->length());
70.74 +
70.75 + unsigned argc = call->args()->length();
70.76 +
70.77 + for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) {
70.78 + HIR *hir = call->args()->at(i);
70.79 + hir->accept(this);
70.80 + }
70.81 +
70.82 + call->callee()->accept(this);
70.83 + __ call(fun, argc);
70.84 +}
70.85 +
70.86 +void
70.87 +HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
70.88 +{
70.89 +}
70.90 +
70.91 +void
70.92 +HGlobal::store(BytecodeEmitter &emitter_)
70.93 +{
70.94 + __ setglobal(sym_);
70.95 +}
70.96 +
70.97 +void
70.98 +HGlobal::load(BytecodeEmitter &emitter_)
70.99 +{
70.100 + __ getglobal(sym_);
70.101 +}
70.102 +
70.103 +void
70.104 +HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
70.105 +{
70.106 + if (sym_->type()->isReference())
70.107 + __ getlocal(sym_);
70.108 +}
70.109 +
70.110 +void
70.111 +HLocal::store(BytecodeEmitter &emitter_)
70.112 +{
70.113 + if (sym_->type()->isReference())
70.114 + __ setref(sym_->type()->contained());
70.115 + else
70.116 + __ setlocal(sym_);
70.117 +}
70.118 +
70.119 +void
70.120 +HLocal::load(BytecodeEmitter &emitter_)
70.121 +{
70.122 + if (sym_->type()->isReference())
70.123 + __ getref(sym_->type());
70.124 + else
70.125 + __ getlocal(sym_);
70.126 +}
70.127 +
70.128 +void
70.129 +HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
70.130 +{
70.131 + left_->accept(visitor);
70.132 + right_->accept(visitor);
70.133 +}
70.134 +
70.135 +void
70.136 +HIndex::store(BytecodeEmitter &emitter_)
70.137 +{
70.138 + __ setelem(type());
70.139 +}
70.140 +
70.141 +void
70.142 +HIndex::load(BytecodeEmitter &emitter_)
70.143 +{
70.144 + __ getelem(type());
70.145 +}
70.146 +
70.147 +void
70.148 +HIRTranslator::visitLocal(HLocal *local)
70.149 +{
70.150 + local->bind(this, emitter_);
70.151 + local->load(emitter_);
70.152 +}
70.153 +
70.154 +void
70.155 +HIRTranslator::visitGlobal(HGlobal *global)
70.156 +{
70.157 + __ getglobal(global->sym());
70.158 +}
70.159 +
70.160 +void
70.161 +HIRTranslator::visitStore(HStore *store)
70.162 +{
70.163 + store->lval()->bind(this, emitter_);
70.164 + store->rval()->accept(this);
70.165 + store->lval()->store(emitter_);
70.166 +}
70.167 +
70.168 +static inline Opcode
70.169 +TokenToOpcode(TokenKind kind)
70.170 +{
70.171 + switch (kind) {
70.172 + case TOK_PLUS:
70.173 + return OP_ADD;
70.174 + case TOK_MINUS:
70.175 + return OP_SUB;
70.176 + case TOK_STAR:
70.177 + return OP_MUL;
70.178 + case TOK_SLASH:
70.179 + return OP_DIV;
70.180 + case TOK_PERCENT:
70.181 + return OP_MOD;
70.182 + case TOK_SHR:
70.183 + return OP_SHR;
70.184 + case TOK_USHR:
70.185 + return OP_USHR;
70.186 + case TOK_SHL:
70.187 + return OP_SHL;
70.188 + case TOK_BITAND:
70.189 + return OP_BITAND;
70.190 + case TOK_BITOR:
70.191 + return OP_BITOR;
70.192 + case TOK_GT:
70.193 + return OP_GT;
70.194 + case TOK_GE:
70.195 + return OP_GE;
70.196 + case TOK_LT:
70.197 + return OP_LT;
70.198 + case TOK_LE:
70.199 + return OP_LE;
70.200 + case TOK_EQUALS:
70.201 + return OP_EQ;
70.202 + case TOK_NOTEQUALS:
70.203 + return OP_NE;
70.204 + default:
70.205 + assert(kind == TOK_BITXOR);
70.206 + return OP_BITXOR;
70.207 + }
70.208 +}
70.209 +
70.210 +void
70.211 +HIRTranslator::visitBinary(HBinary *binary)
70.212 +{
70.213 + binary->left()->accept(this);
70.214 + binary->right()->accept(this);
70.215 +
70.216 + // We define three sets of math operators:
70.217 + //
70.218 + // (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce
70.219 + // the same type.
70.220 + // (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce
70.221 + // a boolean.
70.222 + // (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two
70.223 + // equal integer types and return that integer type.
70.224 + //
70.225 + Opcode op = TokenToOpcode(binary->token());
70.226 +
70.227 + if (op >= OP_ADD && op <= OP_NE) {
70.228 + if (binary->type()->isFloat())
70.229 + op = Opcode(int(op) + int(OP_ADD_F - OP_ADD));
70.230 + } else {
70.231 + assert(binary->type()->isInt32());
70.232 + }
70.233 +
70.234 + __ binary(op);
70.235 +}
70.236 +
70.237 +void
70.238 +HIRTranslator::visitConvert(HConvert *convert)
70.239 +{
70.240 + convert->in()->accept(this);
70.241 + __ unary(convert->opcode());
70.242 +}
70.243 +
70.244 +void
70.245 +ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
70.246 +{
70.247 + HIRTranslator translator(zone, emitter);
70.248 + translator.translate(hir);
70.249 +}
71.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
71.2 +++ b/src/compiler/HIR.h Sat Nov 17 18:41:01 2012 -0800
71.3 @@ -0,0 +1,331 @@
71.4 +/*
71.5 + * Copyright (C) 2012 David Anderson
71.6 + *
71.7 + * This file is part of SourcePawn.
71.8 + *
71.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
71.10 + * the terms of the GNU General Public License as published by the Free
71.11 + * Software Foundation, either version 3 of the License, or (at your option)
71.12 + * any later version.
71.13 + *
71.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
71.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
71.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
71.17 + *
71.18 + * You should have received a copy of the GNU General Public License along with
71.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
71.20 + */
71.21 +#ifndef _include_sp2_hir_h_
71.22 +#define _include_sp2_hir_h_
71.23 +
71.24 +#include "../Types.h"
71.25 +#include "../PoolAllocator.h"
71.26 +#include "../Opcodes.h"
71.27 +#include "Symbols.h"
71.28 +
71.29 +namespace ke {
71.30 +
71.31 +#define HIR_OPS(_) \
71.32 + _(Call) \
71.33 + _(Integer) \
71.34 + _(Float) \
71.35 + _(Store) \
71.36 + /* Special LValue types */ \
71.37 + _(Index) \
71.38 + _(Local) \
71.39 + _(Global) \
71.40 + /* End LValues */ \
71.41 + _(Binary) \
71.42 + _(Convert)
71.43 +
71.44 +// Forward declarations.
71.45 +#define _(name) class H##name;
71.46 +HIR_OPS(_)
71.47 +#undef _
71.48 +
71.49 +class HIRVisitor;
71.50 +
71.51 +class HIR : public PoolObject
71.52 +{
71.53 + public:
71.54 + enum HOp {
71.55 +#define _(name) k##name,
71.56 + HIR_OPS(_)
71.57 +#undef _
71.58 + kTotalOps
71.59 + };
71.60 +
71.61 + public:
71.62 + HIR(Type *type)
71.63 + : type_(type)
71.64 + {
71.65 + }
71.66 +
71.67 + Handle<Type> type() {
71.68 + return type_;
71.69 + }
71.70 +
71.71 + virtual bool isLValue() const {
71.72 + return false;
71.73 + }
71.74 +
71.75 + virtual HOp op() const = 0;
71.76 + virtual void accept(HIRVisitor *visitor) = 0;
71.77 +
71.78 + private:
71.79 + ScopedRoot<Type> type_;
71.80 +};
71.81 +
71.82 +class BytecodeEmitter;
71.83 +
71.84 +class HIRVisitor
71.85 +{
71.86 + public:
71.87 +#define _(name) \
71.88 + virtual void visit##name(H##name *hir) { \
71.89 + assert(false); \
71.90 + }
71.91 + HIR_OPS(_)
71.92 +#undef _
71.93 +};
71.94 +
71.95 +typedef PoolList<HIR *> HIRList;
71.96 +
71.97 +#define DEFINE_HIR(name) \
71.98 + virtual HOp op() const { \
71.99 + return k##name; \
71.100 + } \
71.101 + virtual void accept(HIRVisitor *visitor) { \
71.102 + visitor->visit##name(this); \
71.103 + }
71.104 +
71.105 +class HInteger : public HIR
71.106 +{
71.107 + public:
71.108 + HInteger(Type *type, int value)
71.109 + : HIR(type),
71.110 + value_(value)
71.111 + {
71.112 + }
71.113 +
71.114 + DEFINE_HIR(Integer);
71.115 + int value() const {
71.116 + return value_;
71.117 + }
71.118 +
71.119 + private:
71.120 + int value_;
71.121 +};
71.122 +
71.123 +class HConvert : public HIR
71.124 +{
71.125 + public:
71.126 + HConvert(Type *type, Opcode op, HIR *in)
71.127 + : HIR(type),
71.128 + op_(op),
71.129 + in_(in)
71.130 + {
71.131 + }
71.132 +
71.133 + DEFINE_HIR(Convert);
71.134 + Opcode opcode() const {
71.135 + return op_;
71.136 + }
71.137 + HIR *in() const {
71.138 + return in_;
71.139 + }
71.140 +
71.141 + private:
71.142 + Opcode op_;
71.143 + HIR *in_;
71.144 +};
71.145 +
71.146 +class HLValue : public HIR
71.147 +{
71.148 + public:
71.149 + HLValue(Type *type)
71.150 + : HIR(type)
71.151 + {
71.152 + }
71.153 +
71.154 + // Pushes a reference to the LValue on the stack.
71.155 + virtual void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) = 0;
71.156 +
71.157 + // Given a stack layout of the form:
71.158 + // [-1] value
71.159 + // [-2..n] ref
71.160 + //
71.161 + // Emits a store to the reference.
71.162 + virtual void store(BytecodeEmitter &emitter_) = 0;
71.163 + virtual void load(BytecodeEmitter &emitter_) = 0;
71.164 +
71.165 + bool isLValue() const {
71.166 + return true;
71.167 + }
71.168 +};
71.169 +
71.170 +class HLocal : public HLValue
71.171 +{
71.172 + public:
71.173 + HLocal(VariableSymbol *sym)
71.174 + : HLValue(sym->type()),
71.175 + sym_(sym)
71.176 + {
71.177 + }
71.178 +
71.179 + DEFINE_HIR(Local);
71.180 +
71.181 + // Pushes a reference to the LValue on the stack.
71.182 + void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
71.183 + void store(BytecodeEmitter &emitter_);
71.184 + void load(BytecodeEmitter &emitter_);
71.185 +
71.186 + private:
71.187 + VariableSymbol *sym_;
71.188 +};
71.189 +
71.190 +class HIndex : public HLValue
71.191 +{
71.192 + public:
71.193 + HIndex(Type *type, HIR *left, HIR *right)
71.194 + : HLValue(type),
71.195 + left_(left),
71.196 + right_(right)
71.197 + {
71.198 + }
71.199 +
71.200 + DEFINE_HIR(Index);
71.201 +
71.202 + void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
71.203 + void store(BytecodeEmitter &emitter_);
71.204 + void load(BytecodeEmitter &emitter_);
71.205 +
71.206 + private:
71.207 + HIR *left_;
71.208 + HIR *right_;
71.209 +};
71.210 +
71.211 +class HGlobal : public HLValue
71.212 +{
71.213 + public:
71.214 + HGlobal(Symbol *sym)
71.215 + : HLValue(sym->type()),
71.216 + sym_(sym)
71.217 + {
71.218 + }
71.219 +
71.220 + DEFINE_HIR(Global);
71.221 +
71.222 + void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
71.223 + void store(BytecodeEmitter &emitter_);
71.224 + void load(BytecodeEmitter &emitter_);
71.225 +
71.226 + Symbol *sym() const {
71.227 + return sym_;
71.228 + }
71.229 +
71.230 + private:
71.231 + Symbol *sym_;
71.232 +};
71.233 +
71.234 +class HBinary : public HIR
71.235 +{
71.236 + public:
71.237 + HBinary(Type *type, TokenKind token, HIR *left, HIR *right)
71.238 + : HIR(type),
71.239 + token_(token),
71.240 + left_(left),
71.241 + right_(right)
71.242 + {
71.243 + }
71.244 +
71.245 + DEFINE_HIR(Binary);
71.246 + TokenKind token() const {
71.247 + return token_;
71.248 + }
71.249 + HIR *left() const {
71.250 + return left_;
71.251 + }
71.252 + HIR *right() const {
71.253 + return right_;
71.254 + }
71.255 +
71.256 + private:
71.257 + TokenKind token_;
71.258 + HIR *left_;
71.259 + HIR *right_;
71.260 +};
71.261 +
71.262 +class HFloat : public HIR
71.263 +{
71.264 + public:
71.265 + HFloat(Type *type, float value)
71.266 + : HIR(type),
71.267 + value_(value)
71.268 + {
71.269 + }
71.270 +
71.271 + DEFINE_HIR(Float);
71.272 + float value() const {
71.273 + return value_;
71.274 + }
71.275 +
71.276 + private:
71.277 + float value_;
71.278 +};
71.279 +
71.280 +class HStore : public HIR
71.281 +{
71.282 + public:
71.283 + HStore(HLValue *lval, HIR *rval)
71.284 + : HIR(lval->type()),
71.285 + lval_(lval),
71.286 + rval_(rval)
71.287 + {
71.288 + }
71.289 +
71.290 + DEFINE_HIR(Store);
71.291 +
71.292 + HLValue *lval() const {
71.293 + return lval_;
71.294 + }
71.295 + HIR *rval() const {
71.296 + return rval_;
71.297 + }
71.298 +
71.299 + private:
71.300 + HLValue *lval_;
71.301 + HIR *rval_;
71.302 +};
71.303 +
71.304 +class HCall : public HIR
71.305 +{
71.306 + public:
71.307 + HCall(Type *type, HIR *callee, HIRList *args)
71.308 + : HIR(type),
71.309 + callee_(callee),
71.310 + args_(args)
71.311 + {
71.312 + }
71.313 +
71.314 + DEFINE_HIR(Call);
71.315 +
71.316 + HIR *callee() const {
71.317 + return callee_;
71.318 + }
71.319 + HIRList *args() const {
71.320 + return args_;
71.321 + }
71.322 +
71.323 + private:
71.324 + HIR *callee_;
71.325 + HIRList *args_;
71.326 +};
71.327 +
71.328 +#undef DEFINE_HIR
71.329 +
71.330 +void EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir);
71.331 +
71.332 +}
71.333 +
71.334 +#endif // _include_sp2_hir_h_
72.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
72.2 +++ b/src/compiler/NameBinding.cpp Sat Nov 17 18:41:01 2012 -0800
72.3 @@ -0,0 +1,710 @@
72.4 +/* vim: set ts=4 sw=4 tw=99 et:
72.5 + *
72.6 + * Copyright (C) 2012 David Anderson
72.7 + *
72.8 + * This file is part of SourcePawn.
72.9 + *
72.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
72.11 + * the terms of the GNU General Public License as published by the Free
72.12 + * Software Foundation, either version 3 of the License, or (at your option)
72.13 + * any later version.
72.14 + *
72.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
72.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
72.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
72.18 + *
72.19 + * You should have received a copy of the GNU General Public License along with
72.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
72.21 + */
72.22 +#include "../Strings.h"
72.23 +#include "../Zone.h"
72.24 +#include "../TypeManager.h"
72.25 +#include "NameBinding.h"
72.26 +#include "Scopes.h"
72.27 +#include "../Spaces-inl.h"
72.28 +#include "../Heap-inl.h"
72.29 +
72.30 +using namespace ke;
72.31 +
72.32 +// Create symbol tables and symbols for every scope and declaration. For type
72.33 +// declarations and methods, we also pre-allocate a Type object, so that
72.34 +// circular dependencies between types will work.
72.35 +class NamePopulator : public AstVisitor
72.36 +{
72.37 + private:
72.38 + // This class is analagous to a Scope, however, it allows us to create
72.39 + // scopes lazily. If a scope is requested, and the current environment
72.40 + // has no scope, then a scope is created. If no scope is ever requested,
72.41 + // a scope does not need to be created.
72.42 + class SymbolEnv
72.43 + {
72.44 + public:
72.45 + SymbolEnv(SymbolEnv **prevp, Scope *scope = NULL)
72.46 + : envp_(prevp),
72.47 + prev_(*prevp),
72.48 + scope_(scope)
72.49 + {
72.50 + *envp_ = this;
72.51 + }
72.52 + ~SymbolEnv() {
72.53 + *envp_ = prev_;
72.54 + }
72.55 +
72.56 + Scope *scope() {
72.57 + return scope_;
72.58 + }
72.59 + void setScope(Scope *scope) {
72.60 + assert(!scope_);
72.61 + scope_ = scope;
72.62 + }
72.63 + SymbolEnv *prev() const {
72.64 + return prev_;
72.65 + }
72.66 +
72.67 + private:
72.68 + SymbolEnv **envp_;
72.69 + SymbolEnv *prev_;
72.70 + Scope *scope_;
72.71 + };
72.72 +
72.73 + enum ReturnStatus {
72.74 + NoReturn,
72.75 + VoidReturn,
72.76 + ValueReturn
72.77 + };
72.78 +
72.79 + class FunctionScope
72.80 + {
72.81 + public:
72.82 + FunctionScope(FunctionScope **prevp)
72.83 + : prevp_(prevp),
72.84 + prev_(*prevp),
72.85 + status_(NoReturn)
72.86 + {
72.87 + *prevp_ = this;
72.88 + }
72.89 + ~FunctionScope() {
72.90 + *prevp_ = prev_;
72.91 + }
72.92 + ReturnStatus returns() const {
72.93 + return status_;
72.94 + }
72.95 + void returns(ReturnStatus status) {
72.96 + if (status > status_)
72.97 + status_ = status;
72.98 + }
72.99 + private:
72.100 + FunctionScope **prevp_;
72.101 + FunctionScope *prev_;
72.102 + ReturnStatus status_;
72.103 + };
72.104 +
72.105 + public:
72.106 + NamePopulator(Zone *zone, CompileContext &cc, TranslationUnit *unit)
72.107 + : zone_(zone),
72.108 + pool_(zone->pool()),
72.109 + cc_(cc),
72.110 + unit_(unit),
72.111 + env_(NULL),
72.112 + fun_(NULL)
72.113 + {
72.114 + }
72.115 +
72.116 + bool analyze() {
72.117 + ImportScope *importScope = ImportScope::New(pool_);
72.118 + if (!importScope)
72.119 + return false;
72.120 +
72.121 + // At the import level, we declare system types.
72.122 + if (!declareSystemTypes(importScope))
72.123 + return false;
72.124 +
72.125 + GlobalScope *globalScope = GlobalScope::New(pool_, importScope);
72.126 + if (!globalScope)
72.127 + return false;
72.128 +
72.129 + unit_->setImportScope(importScope);
72.130 + unit_->setGlobalScope(globalScope);
72.131 +
72.132 + SymbolEnv env(&env_, globalScope);
72.133 +
72.134 + for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
72.135 + Statement *stmt = unit_->tree()->statements()->at(i);
72.136 + stmt->accept(this);
72.137 + }
72.138 +
72.139 + return true;
72.140 + }
72.141 +
72.142 + bool declareSystemType(ImportScope *scope, const char *name, Handle<Type> type) {
72.143 + Local<String> tag(zone_, zone_->makeSymbol(name));
72.144 + if (!tag)
72.145 + return false;
72.146 +
72.147 + TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type);
72.148 + return scope->addSymbol(sym);
72.149 + }
72.150 +
72.151 + bool declareSystemType(ImportScope *scope, const char *name, PrimitiveType prim) {
72.152 + Local<Type> primitive(zone_, zone_->types()->getPrimitive(prim));
72.153 + assert(primitive);
72.154 + return declareSystemType(scope, name, primitive);
72.155 + }
72.156 +
72.157 + bool declareSystemTypes(ImportScope *scope) {
72.158 + if (!declareSystemType(scope, "float", PrimitiveType_Float))
72.159 + return false;
72.160 + if (!declareSystemType(scope, "_", PrimitiveType_Int32))
72.161 + return false;
72.162 + if (!declareSystemType(scope, "int", PrimitiveType_Int32))
72.163 + return false;
72.164 + if (!declareSystemType(scope, "bool", PrimitiveType_Bool))
72.165 + return false;
72.166 + if (!declareSystemType(scope, "char", PrimitiveType_Char))
72.167 + return false;
72.168 +
72.169 + Local<Type> voidType(zone_, zone_->types()->getVoid());
72.170 + if (!declareSystemType(scope, "void", voidType))
72.171 + return false;
72.172 +
72.173 + return true;
72.174 + }
72.175 +
72.176 + void visitVariableDeclaration(VariableDeclaration *node) {
72.177 + Scope *scope = env_->scope();
72.178 + if (!scope || scope->kind() != Scope::GLOBAL) {
72.179 + if ((scope = getOrCreateBlockScope()) == NULL)
72.180 + return;
72.181 + }
72.182 +
72.183 + if (scope->kind() == Scope::GLOBAL) {
72.184 + // The symbol must be added now, since it could be an export.
72.185 + VariableSymbol *sym = new (pool_) VariableSymbol(scope, node->name(), node->pos());
72.186 + node->setSymbol(sym);
72.187 +
72.188 + if (!registerName(scope, sym))
72.189 + return;
72.190 + } else {
72.191 + // We ensure the scope will exist at the name binding phase, but
72.192 + // we don't actually register the variable symbol yet. Otherwise,
72.193 + // when binding the initializer, we could encounter:
72.194 + // new x = x;
72.195 + //
72.196 + // And we don't necessarily want this to bind.
72.197 + }
72.198 +
72.199 + node->initialization()->accept(this);
72.200 + }
72.201 + void visitEnumStatement(EnumStatement *node) {
72.202 + assert(false);
72.203 + }
72.204 + void visitFunctionStatement(FunctionStatement *node) {
72.205 + // We create function types ahead of time, not for any particular
72.206 + // reason. It makes things consistent with FunctionTypeStatement,
72.207 + // which actually does produce a type.
72.208 + Local<FunctionType> type(zone_, FunctionType::New(zone_, node->token()));
72.209 + if (!type)
72.210 + return;
72.211 +
72.212 + assert(env_->scope());
72.213 +
72.214 + // Function statements are always named, so add the name to the outer scope.
72.215 + FunctionSymbol *sym = new (pool_) FunctionSymbol(env_->scope(), node->name(), node->pos(), type);
72.216 + if (!registerName(env_->scope(), sym))
72.217 + return;
72.218 +
72.219 + if (node->token() == TOK_PUBLIC ||
72.220 + node->token() == TOK_FORWARD ||
72.221 + node->token() == TOK_NATIVE)
72.222 + {
72.223 + // We're in the global scope, for sure.
72.224 + assert(env_->scope()->kind() == Scope::GLOBAL);
72.225 + GlobalScope *globals = (GlobalScope *)env_->scope();
72.226 + if (!globals->addPublic(sym))
72.227 + return;
72.228 + }
72.229 +
72.230 + node->setSymbol(sym);
72.231 +
72.232 + // Scope for the function's arguments.
72.233 + SymbolEnv argEnv(&env_);
72.234 + if (!registerArguments(node->signature()))
72.235 + return;
72.236 +
72.237 + // Scope for function body.
72.238 + SymbolEnv localEnv(&env_);
72.239 + FunctionScope fun(&fun_);
72.240 + if (node->body())
72.241 + node->body()->accept(this);
72.242 +
72.243 + // Function statements have quirky semantics around their return
72.244 + // type. For reasonable compatibility with SP1, we use the following
72.245 + // heuristics for when no explicit type is declared.
72.246 + if (!node->signature().returnType()) {
72.247 + Local<Type> type(zone_);
72.248 + if (node->token() == TOK_FORWARD || node->token() == TOK_NATIVE) {
72.249 + // If the function type is a native or forward, we always
72.250 + // assume it returns an int32.
72.251 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
72.252 + } else if (fun.returns() != ValueReturn) {
72.253 + // This function never returns a value, so mark it as
72.254 + // returning void.
72.255 + type = zone_->types()->getVoid();
72.256 + }
72.257 + // No need to NULL check here, we'll catch OOM later.
72.258 + node->sym()->type()->setReturnType(type);
72.259 + }
72.260 +
72.261 + node->setScopes(argEnv.scope(), localEnv.scope());
72.262 + }
72.263 + void visitStructureStatement(StructureStatement *node) {
72.264 + assert(false);
72.265 + }
72.266 + void visiFunctionTypeStatementt(FunctionTypeStatement *node) {
72.267 + assert(false);
72.268 + }
72.269 +
72.270 + void visitNameProxy(NameProxy *name) {
72.271 + }
72.272 + void visitAssignment(Assignment *node) {
72.273 + node->lvalue()->accept(this);
72.274 + node->expression()->accept(this);
72.275 + }
72.276 + void visitBinaryExpression(BinaryExpression *node) {
72.277 + node->left()->accept(this);
72.278 + node->right()->accept(this);
72.279 + }
72.280 + void visitReturnStatement(ReturnStatement *node) {
72.281 + if (node->expression())
72.282 + fun_->returns(ValueReturn);
72.283 + else
72.284 + fun_->returns(VoidReturn);
72.285 + }
72.286 + void visitForStatement(ForStatement *node) {
72.287 + SymbolEnv env(&env_);
72.288 +
72.289 + if (node->initialization())
72.290 + node->initialization()->accept(this);
72.291 + if (node->condition())
72.292 + node->condition()->accept(this);
72.293 + if (node->update())
72.294 + node->update()->accept(this);
72.295 + node->body()->accept(this);
72.296 +
72.297 + node->setScope(env.scope());
72.298 + }
72.299 + void visitBlockStatement(BlockStatement *node) {
72.300 + SymbolEnv env(&env_);
72.301 +
72.302 + for (size_t i = 0; i < node->statements()->length(); i++)
72.303 + node->statements()->at(i)->accept(this);
72.304 +
72.305 + node->setScope(env.scope());
72.306 + }
72.307 + void visitIntegerLiteral(IntegerLiteral *node) {
72.308 + }
72.309 + void visitExpressionStatement(ExpressionStatement *node) {
72.310 + node->expression()->accept(this);
72.311 + }
72.312 + void visitCallExpression(CallExpression *node) {
72.313 + node->callee()->accept(this);
72.314 + for (size_t i = 0; i < node->arguments()->length(); i++)
72.315 + node->arguments()->at(i)->accept(this);
72.316 + }
72.317 + void visitIfStatement(IfStatement *node) {
72.318 + node->ifTrue()->accept(this);
72.319 + if (node->ifFalse())
72.320 + node->ifFalse()->accept(this);
72.321 + }
72.322 + void visitIndexExpression(IndexExpression *node) {
72.323 + assert(false);
72.324 + }
72.325 + void visitFloatLiteral(FloatLiteral *node) {
72.326 + }
72.327 + void visitWhileStatement(WhileStatement *node) {
72.328 + node->condition()->accept(this);
72.329 + node->body()->accept(this);
72.330 + }
72.331 + void visitBreakStatement(BreakStatement *node) {
72.332 + }
72.333 + void visitContinueStatement(ContinueStatement *node) {
72.334 + }
72.335 + void visitStringLiteral(StringLiteral *node) {
72.336 + }
72.337 + void visitIncDecExpression(IncDecExpression *node) {
72.338 + assert(false);
72.339 + }
72.340 + void visitUnaryExpression(UnaryExpression *node) {
72.341 + assert(false);
72.342 + }
72.343 + void visitTernaryExpression(TernaryExpression *node) {
72.344 + assert(false);
72.345 + }
72.346 + void visitBooleanLiteral(BooleanLiteral *node) {
72.347 + }
72.348 + void visitFieldExpression(FieldExpression *node) {
72.349 + }
72.350 + void visitSwitchStatement(SwitchStatement *node) {
72.351 + if (node->defaultCase())
72.352 + node->defaultCase()->accept(this);
72.353 +
72.354 + for (size_t i = 0; i < node->cases()->length(); i++)
72.355 + node->cases()->at(i)->statement()->accept(this);
72.356 + }
72.357 + void visitArrayLiteral(ArrayLiteral *node) {
72.358 + }
72.359 + void visitImportStatement(ImportStatement *node) {
72.360 + }
72.361 +
72.362 + private:
72.363 + Scope *getOrCreateBlockScope() {
72.364 + if (env_->scope()) {
72.365 + assert(env_->scope()->kind() == Scope::BLOCK);
72.366 + return env_->scope();
72.367 + }
72.368 +
72.369 + LocalScope *scope = LocalScope::New(pool_);
72.370 + if (!scope)
72.371 + return NULL;
72.372 +
72.373 + env_->setScope(scope);
72.374 + return scope;
72.375 + }
72.376 +
72.377 + bool registerName(Scope *scope, Symbol *sym) {
72.378 + if (!scope)
72.379 + return false;
72.380 +
72.381 + if (Symbol *other = scope->localLookup(sym->name())) {
72.382 + // Report, but allow errors to continue.
72.383 + cc_.reportError(sym->pos(), Message_RedeclaredName,
72.384 + sym->name()->chars(),
72.385 + other->pos().line,
72.386 + other->pos().col);
72.387 + return true;
72.388 + }
72.389 +
72.390 + return scope->addSymbol(sym);
72.391 + }
72.392 +
72.393 + bool registerArguments(const FunctionSignature &sig) {
72.394 + if (!sig.parameters()->length())
72.395 + return true;
72.396 +
72.397 + ArgumentScope *argScope = ArgumentScope::New(pool_);
72.398 + if (!argScope)
72.399 + return false;
72.400 + env_->setScope(argScope);
72.401 +
72.402 + for (size_t i = 0; i < sig.parameters()->length(); i++) {
72.403 + Parameter *param = sig.parameters()->at(i);
72.404 + VariableSymbol *sym = new (pool_) VariableSymbol(argScope, param->name(), param->pos());
72.405 + if (!registerName(env_->scope(), sym))
72.406 + return false;
72.407 + param->setSymbol(sym);
72.408 + }
72.409 +
72.410 + return true;
72.411 + }
72.412 +
72.413 + private:
72.414 + Zone *zone_;
72.415 + PoolAllocator &pool_;
72.416 + CompileContext &cc_;
72.417 + TranslationUnit *unit_;
72.418 + SymbolEnv *env_;
72.419 + FunctionScope *fun_;
72.420 +};
72.421 +
72.422 +bool
72.423 +ke::PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
72.424 +{
72.425 + NamePopulator populator(zone, cc, unit);
72.426 + return populator.analyze();
72.427 +}
72.428 +
72.429 +class NameBinder : public AstVisitor
72.430 +{
72.431 + public:
72.432 + class AutoLinkScope
72.433 + {
72.434 + public:
72.435 + AutoLinkScope(AutoLinkScope **prevp, Scope *scope)
72.436 + : prevp_(prevp),
72.437 + prev_(*prevp),
72.438 + scope_(scope)
72.439 + {
72.440 + if (scope_) {
72.441 + *prevp_ = this;
72.442 + if (prev_)
72.443 + scope_->setParent(prev_->scope());
72.444 + }
72.445 + }
72.446 + ~AutoLinkScope() {
72.447 + if (scope_) {
72.448 + assert(*prevp_ == this);
72.449 + *prevp_ = prev_;
72.450 + }
72.451 + }
72.452 + Scope *scope() const {
72.453 + return scope_;
72.454 + }
72.455 +
72.456 + private:
72.457 + AutoLinkScope **prevp_;
72.458 + AutoLinkScope *prev_;
72.459 + Scope *scope_;
72.460 + };
72.461 +
72.462 + public:
72.463 + NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
72.464 + : zone_(zone),
72.465 + pool_(zone->pool()),
72.466 + cc_(cc),
72.467 + unit_(unit),
72.468 + link_(NULL)
72.469 + {
72.470 + }
72.471 +
72.472 + bool bind() {
72.473 + // Start with the import scope, and collect all imported names.
72.474 + AutoLinkScope importScope(&link_, unit_->importScope());
72.475 +
72.476 + for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
72.477 + unit_->tree()->imports()->at(i)->accept(this);
72.478 +
72.479 + // Next, enter the global scope and walk all statements.
72.480 + AutoLinkScope globalScope(&link_, unit_->globalScope());
72.481 + for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
72.482 + Statement *stmt = unit_->tree()->statements()->at(i);
72.483 + stmt->accept(this);
72.484 + }
72.485 +
72.486 + return true;
72.487 + }
72.488 +
72.489 + void visitVariableDeclaration(VariableDeclaration *node) {
72.490 + // Bind the initializer before registering the declaration, so that we
72.491 + // can error on bogus initializers (new x = x).
72.492 + node->initialization()->accept(this);
72.493 +
72.494 + Local<Type> type(zone_, bindType(node->type()));
72.495 + if (!type)
72.496 + return;
72.497 +
72.498 + // If the node already has a symbol (meaning it was a global), then
72.499 + // we don't have to do anything more.
72.500 + if (node->sym()) {
72.501 + assert(node->sym()->scope()->kind() == Scope::GLOBAL);
72.502 + return;
72.503 + }
72.504 +
72.505 + VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type);
72.506 + node->setSymbol(sym);
72.507 +
72.508 + if (Symbol *other = link_->scope()->localLookup(sym->name())) {
72.509 + // Report, but allow errors to continue.
72.510 + cc_.reportError(sym->pos(), Message_RedeclaredName,
72.511 + sym->name()->chars(),
72.512 + other->pos().line,
72.513 + other->pos().col);
72.514 + return;
72.515 + }
72.516 +
72.517 + if (link_->scope()->addSymbol(sym))
72.518 + return;
72.519 + }
72.520 + void visitEnumStatement(EnumStatement *node) {
72.521 + assert(false);
72.522 + }
72.523 + void visitFunctionStatement(FunctionStatement *node) {
72.524 + AutoLinkScope argScope(&link_, node->argScope());
72.525 + AutoLinkScope varScope(&link_, node->varScope());
72.526 +
72.527 + Local<FunctionType> type(zone_, node->sym()->type());
72.528 + if (!fillFunctionType(type, node->signature()))
72.529 + return;
72.530 +
72.531 + if (node->body())
72.532 + node->body()->accept(this);
72.533 + }
72.534 + void visitStructureStatement(StructureStatement *node) {
72.535 + assert(false);
72.536 + }
72.537 + void visitFunctionTypeStatement(FunctionTypeStatement *node) {
72.538 + assert(false);
72.539 + }
72.540 +
72.541 + void visitNameProxy(NameProxy *proxy) {
72.542 + Scope *scope = link_->scope();
72.543 + Symbol *sym = scope->lookup(proxy->name());
72.544 + if (!sym)
72.545 + cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
72.546 + proxy->bind(sym);
72.547 + }
72.548 + void visitAssignment(Assignment *node) {
72.549 + node->lvalue()->accept(this);
72.550 + node->expression()->accept(this);
72.551 + }
72.552 + void visitBinaryExpression(BinaryExpression *node) {
72.553 + node->left()->accept(this);
72.554 + node->right()->accept(this);
72.555 + }
72.556 + void visitReturnStatement(ReturnStatement *node) {
72.557 + node->expression()->accept(this);
72.558 + }
72.559 + void visitForStatement(ForStatement *node) {
72.560 + AutoLinkScope scope(&link_, node->scope());
72.561 +
72.562 + if (node->initialization())
72.563 + node->initialization()->accept(this);
72.564 + if (node->condition())
72.565 + node->condition()->accept(this);
72.566 + if (node->update())
72.567 + node->update()->accept(this);
72.568 + node->body()->accept(this);
72.569 + }
72.570 + void visitBlockStatement(BlockStatement *node) {
72.571 + AutoLinkScope scope(&link_, node->scope());
72.572 + for (size_t i = 0; i < node->statements()->length(); i++)
72.573 + node->statements()->at(i)->accept(this);
72.574 + }
72.575 + void visitIntegerLiteral(IntegerLiteral *node) {
72.576 + }
72.577 + void visitExpressionStatement(ExpressionStatement *node) {
72.578 + node->expression()->accept(this);
72.579 + }
72.580 + void visitCallExpression(CallExpression *node) {
72.581 + node->callee()->accept(this);
72.582 + for (size_t i = 0; i < node->arguments()->length(); i++)
72.583 + node->arguments()->at(i)->accept(this);
72.584 + }
72.585 + void visitIfStatement(IfStatement *node) {
72.586 + node->condition()->accept(this);
72.587 + node->ifTrue()->accept(this);
72.588 + node->ifFalse()->accept(this);
72.589 + }
72.590 + void visitIndexExpression(IndexExpression *node) {
72.591 + node->left()->accept(this);
72.592 + node->right()->accept(this);
72.593 + }
72.594 + void visitFloatLiteral(FloatLiteral *node) {
72.595 + }
72.596 + void visitWhileStatement(WhileStatement *node) {
72.597 + node->condition()->accept(this);
72.598 + node->body()->accept(this);
72.599 + }
72.600 + void visitBreakStatement(BreakStatement *node) {
72.601 + }
72.602 + void visitContinueStatement(ContinueStatement *node) {
72.603 + }
72.604 + void visitStringLiteral(StringLiteral *node) {
72.605 + }
72.606 + void visitIncDecExpression(IncDecExpression *node) {
72.607 + node->expression()->accept(this);
72.608 + }
72.609 + void visitUnaryExpression(UnaryExpression *node) {
72.610 + if (node->tag())
72.611 + node->tag()->accept(this);
72.612 + node->expression()->accept(this);
72.613 + }
72.614 + void visitTernaryExpression(TernaryExpression *node) {
72.615 + node->condition()->accept(this);
72.616 + node->left()->accept(this);
72.617 + node->right()->accept(this);
72.618 + }
72.619 + void visitBooleanLiteral(BooleanLiteral *node) {
72.620 + }
72.621 + void visitFieldExpression(FieldExpression *node) {
72.622 + node->left()->accept(this);
72.623 + }
72.624 + void visitSwitchStatement(SwitchStatement *node) {
72.625 + node->expression()->accept(this);
72.626 + node->defaultCase()->accept(this);
72.627 + for (size_t i = 0; i < node->cases()->length(); i++) {
72.628 + // We don't test case expressions because they are literals.
72.629 + Case *c = node->cases()->at(i);
72.630 + c->statement()->accept(this);
72.631 + }
72.632 + }
72.633 + void visitArrayLiteral(ArrayLiteral *node) {
72.634 + for (size_t i = 0; i < node->expressions()->length(); i++)
72.635 + node->expressions()->at(i)->accept(this);
72.636 + }
72.637 + void visitImportStatement(ImportStatement *node) {
72.638 + if (node->suffix() == TOK_STAR) {
72.639 + // Import every name.
72.640 + assert(false);
72.641 + } else {
72.642 + GlobalScope *other = node->source()->globalScope();
72.643 + Symbol *sym = other->findPublic(node->name());
72.644 + if (!sym) {
72.645 + cc_.reportError(node->pos(), Message_CannotResolveImport, node->name()->chars());
72.646 + return;
72.647 + }
72.648 + link_->scope()->addSymbol(sym);
72.649 + }
72.650 + }
72.651 +
72.652 + private:
72.653 + bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
72.654 + Local<Type> type(zone_);
72.655 + if (!fun->returnType()) {
72.656 + if ((type = bindType(sig.returnType())) == NULL)
72.657 + return false;
72.658 + fun->setReturnType(type);
72.659 + }
72.660 +
72.661 + Local<FixedArray> params(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
72.662 + if (!params)
72.663 + return false;
72.664 +
72.665 + for (size_t i = 0; i < sig.parameters()->length(); i++) {
72.666 + Parameter *param = sig.parameters()->at(i);
72.667 + if ((type = bindType(param->type())) == NULL)
72.668 + return false;
72.669 + params->set(zone_, i, type);
72.670 + }
72.671 +
72.672 + fun->setParameterTypes(params);
72.673 +
72.674 + return true;
72.675 + }
72.676 +
72.677 + Type *bindType(Expression *expr) {
72.678 + if (!expr) {
72.679 + // If no type was declared, we return int32.
72.680 + return zone_->types()->getPrimitive(PrimitiveType_Int32);
72.681 + }
72.682 +
72.683 + expr->accept(this);
72.684 +
72.685 + NameProxy *proxy = expr->asNameProxy();
72.686 + assert(proxy);
72.687 +
72.688 + Symbol *sym = proxy->sym();
72.689 + if (!sym)
72.690 + return NULL;
72.691 +
72.692 + if (!sym->isType()) {
72.693 + cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars());
72.694 + return NULL;
72.695 + }
72.696 +
72.697 + return sym->type();
72.698 + }
72.699 +
72.700 + private:
72.701 + Zone *zone_;
72.702 + PoolAllocator &pool_;
72.703 + CompileContext &cc_;
72.704 + TranslationUnit *unit_;
72.705 + AutoLinkScope *link_;
72.706 +};
72.707 +
72.708 +bool
72.709 +ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
72.710 +{
72.711 + NameBinder binder(zone, cc, unit);
72.712 + return binder.bind();
72.713 +}
73.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
73.2 +++ b/src/compiler/NameBinding.h Sat Nov 17 18:41:01 2012 -0800
73.3 @@ -0,0 +1,40 @@
73.4 +/* vim: set ts=4 sw=4 tw=99 et:
73.5 + *
73.6 + * Copyright (C) 2012 David Anderson
73.7 + *
73.8 + * This file is part of SourcePawn.
73.9 + *
73.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
73.11 + * the terms of the GNU General Public License as published by the Free
73.12 + * Software Foundation, either version 3 of the License, or (at your option)
73.13 + * any later version.
73.14 + *
73.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
73.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
73.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
73.18 + *
73.19 + * You should have received a copy of the GNU General Public License along with
73.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
73.21 + */
73.22 +#ifndef _include_name_binding_h_
73.23 +#define _include_name_binding_h_
73.24 +
73.25 +#include "../PoolAllocator.h"
73.26 +#include "../Types.h"
73.27 +#include "Scanner.h"
73.28 +
73.29 +namespace ke {
73.30 +
73.31 +class Zone;
73.32 +class CompileContext;
73.33 +struct TranslationUnit;
73.34 +
73.35 +// Creates symbols and types for names that are global or can be derived from a global.
73.36 +bool PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
73.37 +
73.38 +// Bind all outstanding names and finalize all unfinished types.
73.39 +bool BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
73.40 +
73.41 +}
73.42 +
73.43 +#endif // _include_name_binding_h_
74.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
74.2 +++ b/src/compiler/Parser.cpp Sat Nov 17 18:41:01 2012 -0800
74.3 @@ -0,0 +1,1737 @@
74.4 +/* vim: set ts=4 sw=4 tw=99 et:
74.5 + *
74.6 + * Copyright (C) 2012 David Anderson
74.7 + *
74.8 + * This file is part of SourcePawn.
74.9 + *
74.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
74.11 + * the terms of the GNU General Public License as published by the Free
74.12 + * Software Foundation, either version 3 of the License, or (at your option)
74.13 + * any later version.
74.14 + *
74.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
74.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
74.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
74.18 + *
74.19 + * You should have received a copy of the GNU General Public License along with
74.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
74.21 + */
74.22 +#include <string.h>
74.23 +#include "../Zone.h"
74.24 +#include "../FixedArray.h"
74.25 +#include "../Heap.h"
74.26 +#include "../Strings.h"
74.27 +#include "../TypeManager.h"
74.28 +#include "Parser.h"
74.29 +#include "../Heap-inl.h"
74.30 +
74.31 +using namespace ke;
74.32 +
74.33 +Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length)
74.34 + : zone_(zone),
74.35 + cc_(cc),
74.36 + pool_(zone_->pool()),
74.37 + scanner_(cc, stream, length),
74.38 + unbound_(NULL)
74.39 +{
74.40 + unbound_ = new (pool_) PoolList<NameProxy *>();
74.41 + imports_ = new (pool_) PoolList<ImportStatement *>();
74.42 +}
74.43 +
74.44 +bool
74.45 +Parser::peek(TokenKind kind)
74.46 +{
74.47 + return scanner_.peek() == kind;
74.48 +}
74.49 +
74.50 +bool
74.51 +Parser::match(TokenKind kind)
74.52 +{
74.53 + if (!peek(kind))
74.54 + return false;
74.55 + scanner_.scan();
74.56 + return true;
74.57 +}
74.58 +
74.59 +bool
74.60 +Parser::matchSemicolon()
74.61 +{
74.62 + return expect(TOK_SEMICOLON);
74.63 +}
74.64 +
74.65 +bool
74.66 +Parser::expect(TokenKind kind)
74.67 +{
74.68 + TokenKind got = scanner_.scan();
74.69 + if (got == kind)
74.70 + return true;
74.71 + cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]);
74.72 + return false;
74.73 +}
74.74 +
74.75 +bool
74.76 +Parser::matchName(String **name, TokenKind kind)
74.77 +{
74.78 + assert(kind == TOK_NAME || kind == TOK_LABEL);
74.79 + *name = NULL;
74.80 + if (!match(kind))
74.81 + return false;
74.82 + *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
74.83 + return true;
74.84 +}
74.85 +
74.86 +String *
74.87 +Parser::expectName()
74.88 +{
74.89 + if (!expect(TOK_NAME))
74.90 + return NULL;
74.91 + return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
74.92 +}
74.93 +
74.94 +Expression *
74.95 +Parser::primitive()
74.96 +{
74.97 + TokenKind kind = scanner_.peek();
74.98 + switch (kind) {
74.99 + case TOK_FLOAT_LITERAL:
74.100 + {
74.101 + scanner_.scan();
74.102 + double value = Scanner::ParseDouble(scanner_.literal());
74.103 + return new (pool_) FloatLiteral(scanner_.begin(), value);
74.104 + }
74.105 +
74.106 + case TOK_HEX_LITERAL:
74.107 + {
74.108 + scanner_.scan();
74.109 + int value = strtol(scanner_.literal(), NULL, 16);
74.110 + return new (pool_) IntegerLiteral(scanner_.begin(), value);
74.111 + }
74.112 +
74.113 + case TOK_INTEGER_LITERAL:
74.114 + {
74.115 + scanner_.scan();
74.116 + int value = atoi(scanner_.literal());
74.117 + return new (pool_) IntegerLiteral(scanner_.begin(), value);
74.118 + }
74.119 +
74.120 + case TOK_TRUE:
74.121 + case TOK_FALSE:
74.122 + scanner_.scan();
74.123 + return new (pool_) BooleanLiteral(scanner_.begin(), kind);
74.124 +
74.125 + case TOK_STRING_LITERAL:
74.126 + {
74.127 + scanner_.scan();
74.128 + Local<ByteArray> array(zone_, ByteArray::New(zone_, scanner_.literal_length() + 1));
74.129 + if (!array)
74.130 + return NULL;
74.131 + memcpy(array->raw(), scanner_.literal(), scanner_.literal_length() + 1);
74.132 + return new (pool_) StringLiteral(scanner_.begin(), array);
74.133 + }
74.134 +
74.135 + default:
74.136 + {
74.137 + if (kind != TOK_ERROR)
74.138 + cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]);
74.139 + return NULL;
74.140 + }
74.141 + }
74.142 +}
74.143 +
74.144 +Expression *
74.145 +Parser::arrayLiteral(TokenKind kind)
74.146 +{
74.147 + assert(kind == TOK_LBRACE || kind == TOK_LBRACKET);
74.148 +
74.149 + TokenKind close = (kind == TOK_LBRACE)
74.150 + ? TOK_RBRACE
74.151 + : TOK_RBRACKET;
74.152 +
74.153 + SourcePosition pos = scanner_.begin();
74.154 +
74.155 + ExpressionList *list = new (pool_) ExpressionList();
74.156 + do {
74.157 + if (match(close))
74.158 + break;
74.159 +
74.160 + Expression *expr = NULL;
74.161 + if (kind == TOK_LBRACE) {
74.162 + if (peek(TOK_LBRACE))
74.163 + expr = arrayLiteral(TOK_LBRACE);
74.164 + else
74.165 + expr = primitive();
74.166 + } else {
74.167 + expr = expression();
74.168 + }
74.169 + if (!expr)
74.170 + return NULL;
74.171 +
74.172 + if (!list->append(expr))
74.173 + return NULL;
74.174 +
74.175 + if (!match(TOK_COMMA)) {
74.176 + if (!expect(close))
74.177 + return NULL;
74.178 + break;
74.179 + }
74.180 + } while (true);
74.181 +
74.182 + return new (pool_) ArrayLiteral(pos, kind, list);
74.183 +}
74.184 +
74.185 +Expression *
74.186 +Parser::prefix()
74.187 +{
74.188 + switch (scanner_.peek()) {
74.189 + case TOK_LPAREN:
74.190 + {
74.191 + scanner_.scan();
74.192 + Expression *expr = expression();
74.193 + if (!expr)
74.194 + return NULL;
74.195 + if (!expect(TOK_RPAREN))
74.196 + return NULL;
74.197 + return expr;
74.198 + }
74.199 +
74.200 + case TOK_NAME:
74.201 + {
74.202 + Local<String> name(zone_, expectName());
74.203 + if (!name)
74.204 + return NULL;
74.205 + return new (pool_) NameProxy(scanner_.begin(), name);
74.206 + }
74.207 +
74.208 + default:
74.209 + return primitive();
74.210 + }
74.211 +}
74.212 +
74.213 +// Parses only old-style declarations.
74.214 +bool
74.215 +Parser::typeAndName(Expression **type, String **namep)
74.216 +{
74.217 + if (match(TOK_LABEL)) {
74.218 + // Old-style declaration:
74.219 + // new X:type
74.220 + Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
74.221 + if (!name)
74.222 + return false;
74.223 +
74.224 + *type = new (pool_) NameProxy(scanner_.begin(), name);
74.225 + *namep = expectName();
74.226 + return !!*namep;
74.227 + }
74.228 +
74.229 + *type = NULL;
74.230 + *namep = expectName();
74.231 +
74.232 + return !!*namep;
74.233 +}
74.234 +
74.235 +// Parses both old and new style declarations.
74.236 +bool
74.237 +Parser::fullTypeAndName(Expression **type, String **namep, DeclKind kind)
74.238 +{
74.239 + // Declaration:
74.240 + // NewDecl ::= Type Ident
74.241 + // OldDecl ::= Label? (Ident | "...")
74.242 + // Type ::= Ident
74.243 + // Label ::= Ident ":"
74.244 + //
74.245 + if (match(TOK_LABEL)) {
74.246 + // We something of the form:
74.247 + // Label Ident
74.248 + // or: Label "..."
74.249 + Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
74.250 + if (!name)
74.251 + return false;
74.252 +
74.253 + *type = new (pool_) NameProxy(scanner_.begin(), name);
74.254 + if (kind == DeclArg && match(TOK_ELLIPSES)) {
74.255 + *namep = NULL;
74.256 + } else {
74.257 + if ((*namep = expectName()) == NULL)
74.258 + return false;
74.259 + }
74.260 + return true;
74.261 + }
74.262 +
74.263 + Local<String> name(zone_, expectName());
74.264 + if (!name)
74.265 + return false;
74.266 +
74.267 + if (peek(TOK_NAME) || (kind == DeclArg && peek(TOK_ELLIPSES))) {
74.268 + // We got something of the form:
74.269 + // Ident Ident
74.270 + *type = new (pool_) NameProxy(scanner_.begin(), name);
74.271 + if (peek(TOK_NAME)) {
74.272 + if ((*namep = expectName()) == NULL)
74.273 + return false;
74.274 + } else {
74.275 + *namep = NULL;
74.276 + }
74.277 + return true;
74.278 + }
74.279 +
74.280 + // We got something of the form:
74.281 + // Ident
74.282 + *type = NULL;
74.283 + *namep = name;
74.284 + return true;
74.285 +}
74.286 +
74.287 +Expression *
74.288 +Parser::call(Expression *callee)
74.289 +{
74.290 + ExpressionList *arguments = new (pool_) ExpressionList();
74.291 +
74.292 + SourcePosition pos = scanner_.begin();
74.293 + expect(TOK_LPAREN);
74.294 +
74.295 + if (!match(TOK_RPAREN)) {
74.296 + while (true) {
74.297 + Expression *expr = expression();
74.298 + if (!expr)
74.299 + return NULL;
74.300 +
74.301 + if (!arguments->append(expr))
74.302 + return NULL;
74.303 +
74.304 + if (!match(TOK_COMMA))
74.305 + break;
74.306 + }
74.307 +
74.308 + if (!expect(TOK_RPAREN))
74.309 + return NULL;
74.310 + }
74.311 +
74.312 + return new (pool_) CallExpression(pos, callee, arguments);
74.313 +}
74.314 +
74.315 +Expression *
74.316 +Parser::index(Expression *left)
74.317 +{
74.318 + expect(TOK_LBRACKET);
74.319 +
74.320 + SourcePosition pos = scanner_.begin();
74.321 + Expression *expr = expression();
74.322 + if (!expr)
74.323 + return NULL;
74.324 +
74.325 + if (!expect(TOK_RBRACKET))
74.326 + return NULL;
74.327 +
74.328 + return new (pool_) IndexExpression(pos, left, expr);
74.329 +}
74.330 +
74.331 +Expression *
74.332 +Parser::field(Expression *left)
74.333 +{
74.334 + expect(TOK_DOT);
74.335 +
74.336 + SourcePosition pos = scanner_.begin();
74.337 + Local<String> name(zone_, expectName());
74.338 + if (!name)
74.339 + return NULL;
74.340 +
74.341 + return new (pool_) FieldExpression(pos, left, name);
74.342 +}
74.343 +
74.344 +Expression *
74.345 +Parser::primary()
74.346 +{
74.347 + Expression *expr = prefix();
74.348 + if (!expr)
74.349 + return NULL;
74.350 +
74.351 + for (;;) {
74.352 + switch (scanner_.peek()) {
74.353 + case TOK_LPAREN:
74.354 + if ((expr = call(expr)) == NULL)
74.355 + return NULL;
74.356 + break;
74.357 +
74.358 + case TOK_LBRACKET:
74.359 + if ((expr = index(expr)) == NULL)
74.360 + return NULL;
74.361 + break;
74.362 +
74.363 + case TOK_DOT:
74.364 + if ((expr = field(expr)) == NULL)
74.365 + return NULL;
74.366 + break;
74.367 +
74.368 + default:
74.369 + return expr;
74.370 + }
74.371 + }
74.372 +}
74.373 +
74.374 +Expression *
74.375 +Parser::unary()
74.376 +{
74.377 + TokenKind token = scanner_.peek();
74.378 +
74.379 + SourcePosition pos = scanner_.begin();
74.380 + switch (token) {
74.381 + case TOK_INCREMENT:
74.382 + case TOK_DECREMENT:
74.383 + {
74.384 + scanner_.scan();
74.385 + Expression *expr = unary();
74.386 + if (!expr)
74.387 + return NULL;
74.388 + return new (pool_) IncDecExpression(pos, token, expr, false);
74.389 + }
74.390 +
74.391 + case TOK_MINUS:
74.392 + case TOK_NOT:
74.393 + case TOK_TILDE:
74.394 + {
74.395 + scanner_.scan();
74.396 + Expression *expr = unary();
74.397 + if (!expr)
74.398 + return NULL;
74.399 + return new (pool_) UnaryExpression(pos, token, expr);
74.400 + }
74.401 +
74.402 + case TOK_SIZEOF:
74.403 + {
74.404 + scanner_.scan();
74.405 + if (!expect(TOK_LPAREN))
74.406 + return NULL;
74.407 + Expression *expr = unary();
74.408 + if (!expr)
74.409 + return NULL;
74.410 + if (!expect(TOK_RPAREN))
74.411 + return NULL;
74.412 + return new (pool_) UnaryExpression(pos, token, expr);
74.413 + }
74.414 +
74.415 + case TOK_LABEL:
74.416 + {
74.417 + scanner_.scan();
74.418 + Local<String> tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
74.419 + if (!tag)
74.420 + return NULL;
74.421 +
74.422 + NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), tag);
74.423 +
74.424 + Expression *expr = unary();
74.425 + if (!expr)
74.426 + return NULL;
74.427 +
74.428 + return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, proxy);
74.429 + }
74.430 +
74.431 + default:
74.432 + break;
74.433 + }
74.434 +
74.435 + Expression *expr = primary();
74.436 +
74.437 + token = scanner_.peek();
74.438 + if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
74.439 + scanner_.scan();
74.440 + return new (pool_) IncDecExpression(pos, token, expr, true);
74.441 + }
74.442 +
74.443 + return expr;
74.444 +}
74.445 +
74.446 +Expression *
74.447 +Parser::multiplication()
74.448 +{
74.449 + Expression *left = unary();
74.450 + do {
74.451 + if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT))
74.452 + break;
74.453 + SourcePosition pos = scanner_.begin();
74.454 + TokenKind kind = scanner_.last();
74.455 + Expression *right = unary();
74.456 + if (!right)
74.457 + return NULL;
74.458 + left = new (pool_) BinaryExpression(pos, kind, left, right);
74.459 + } while (left);
74.460 + return left;
74.461 +}
74.462 +
74.463 +Expression *
74.464 +Parser::addition()
74.465 +{
74.466 + Expression *left = multiplication();
74.467 + while (left) {
74.468 + if (!match(TOK_PLUS) && !match(TOK_MINUS))
74.469 + break;
74.470 + SourcePosition pos = scanner_.begin();
74.471 + TokenKind kind = scanner_.last();
74.472 + Expression *right = multiplication();
74.473 + if (!right)
74.474 + return NULL;
74.475 + left = new (pool_) BinaryExpression(pos, kind, left, right);
74.476 + }
74.477 + return left;
74.478 +}
74.479 +
74.480 +Expression *
74.481 +Parser::shift()
74.482 +{
74.483 + Expression *left = addition();
74.484 + while (left) {
74.485 + if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR))
74.486 + break;
74.487 + SourcePosition pos = scanner_.begin();
74.488 + TokenKind kind = scanner_.last();
74.489 + Expression *right = addition();
74.490 + if (!right)
74.491 + return NULL;
74.492 + left = new (pool_) BinaryExpression(pos, kind, left, right);
74.493 + }
74.494 + return left;
74.495 +}
74.496 +
74.497 +Expression *
74.498 +Parser::bitand_()
74.499 +{
74.500 + Expression *left = shift();
74.501 + while (left) {
74.502 + if (!match(TOK_BITAND))
74.503 + break;
74.504 + SourcePosition pos = scanner_.begin();
74.505 + Expression *right = shift();
74.506 + if (!right)
74.507 + return NULL;
74.508 + left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right);
74.509 + }
74.510 + return left;
74.511 +}
74.512 +
74.513 +Expression *
74.514 +Parser::bitxor()
74.515 +{
74.516 + Expression *left = bitand_();
74.517 + while (left) {
74.518 + if (!match(TOK_BITXOR))
74.519 + break;
74.520 + SourcePosition pos = scanner_.begin();
74.521 + Expression *right = shift();
74.522 + if (!right)
74.523 + return NULL;
74.524 + left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right);
74.525 + }
74.526 + return left;
74.527 +}
74.528 +
74.529 +Expression *
74.530 +Parser::bitor_()
74.531 +{
74.532 + Expression *left = bitxor();
74.533 + while (left) {
74.534 + if (!match(TOK_BITOR))
74.535 + break;
74.536 + SourcePosition pos = scanner_.begin();
74.537 + Expression *right = bitxor();
74.538 + if (!right)
74.539 + return NULL;
74.540 + left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right);
74.541 + }
74.542 + return left;
74.543 +}
74.544 +
74.545 +Expression *
74.546 +Parser::relational()
74.547 +{
74.548 + Expression *left = bitor_();
74.549 + while (left) {
74.550 + TokenKind kind = scanner_.peek();
74.551 + if (kind < TOK_LT || kind > TOK_GE)
74.552 + break;
74.553 + scanner_.scan();
74.554 + SourcePosition pos = scanner_.begin();
74.555 + Expression *right = shift();
74.556 + if (!right)
74.557 + return NULL;
74.558 + left = new (pool_) BinaryExpression(pos, kind, left, right);
74.559 + }
74.560 + return left;
74.561 +}
74.562 +
74.563 +Expression *
74.564 +Parser::equals()
74.565 +{
74.566 + Expression *left = relational();
74.567 + while (left) {
74.568 + if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS))
74.569 + break;
74.570 + TokenKind kind = scanner_.last();
74.571 + SourcePosition pos = scanner_.begin();
74.572 + Expression *right = relational();
74.573 + if (!right)
74.574 + return NULL;
74.575 + left = new (pool_) BinaryExpression(pos, kind, left, right);
74.576 + }
74.577 + return left;
74.578 +}
74.579 +
74.580 +Expression *
74.581 +Parser::and_()
74.582 +{
74.583 + Expression *left = equals();
74.584 + while (left) {
74.585 + if (!match(TOK_AND))
74.586 + break;
74.587 + SourcePosition pos = scanner_.begin();
74.588 + Expression *right = equals();
74.589 + if (!right)
74.590 + return NULL;
74.591 + left = new (pool_) BinaryExpression(pos, TOK_AND, left, right);
74.592 + }
74.593 + return left;
74.594 +}
74.595 +
74.596 +Expression *
74.597 +Parser::or_()
74.598 +{
74.599 + Expression *left = and_();
74.600 + while (left) {
74.601 + if (!match(TOK_OR))
74.602 + break;
74.603 + SourcePosition pos = scanner_.begin();
74.604 + Expression *right = and_();
74.605 + if (!right)
74.606 + return NULL;
74.607 + left = new (pool_) BinaryExpression(pos, TOK_OR, left, right);
74.608 + }
74.609 + return left;
74.610 +}
74.611 +
74.612 +Expression *
74.613 +Parser::ternary()
74.614 +{
74.615 + Expression *cond = or_();
74.616 + if (!cond)
74.617 + return NULL;
74.618 +
74.619 + if (!match(TOK_QMARK))
74.620 + return cond;
74.621 +
74.622 + Expression *left;
74.623 + SourcePosition pos = scanner_.begin();
74.624 + AutoAllowTags<false> disableTags(scanner_);
74.625 + {
74.626 + if ((left = expression()) == NULL)
74.627 + return NULL;
74.628 + }
74.629 +
74.630 + if (!expect(TOK_COLON))
74.631 + return NULL;
74.632 +
74.633 + Expression *right = expression();
74.634 + if (!right)
74.635 + return NULL;
74.636 +
74.637 + return new (pool_) TernaryExpression(pos, cond, left, right);
74.638 +}
74.639 +
74.640 +Expression *
74.641 +Parser::assignment()
74.642 +{
74.643 + Expression *left = ternary();
74.644 + while (left) {
74.645 + TokenKind token = scanner_.peek();
74.646 + if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
74.647 + break;
74.648 + scanner_.scan();
74.649 + SourcePosition pos = scanner_.begin();
74.650 + Expression *expr = ternary();
74.651 + if (!expr)
74.652 + return NULL;
74.653 +
74.654 + left = new (pool_) Assignment(pos, token, left, expr);
74.655 + }
74.656 + return left;
74.657 +}
74.658 +
74.659 +Expression *
74.660 +Parser::expression()
74.661 +{
74.662 + return assignment();
74.663 +}
74.664 +
74.665 +Statement *
74.666 +Parser::while_()
74.667 +{
74.668 + SourcePosition pos = scanner_.begin();
74.669 + scanner_.scan();
74.670 +
74.671 + if (!expect(TOK_LPAREN))
74.672 + return NULL;
74.673 +
74.674 + Expression *condition = expression();
74.675 + if (!condition)
74.676 + return NULL;
74.677 +
74.678 + if (!expect(TOK_RPAREN))
74.679 + return NULL;
74.680 +
74.681 + Statement *body;
74.682 + if (scanner_.peek() == TOK_LBRACE)
74.683 + body = block();
74.684 + else
74.685 + body = localStatement();
74.686 + if (!body)
74.687 + return NULL;
74.688 +
74.689 + return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body);
74.690 +}
74.691 +
74.692 +Statement *
74.693 +Parser::do_()
74.694 +{
74.695 + SourcePosition pos = scanner_.begin();
74.696 + scanner_.scan();
74.697 +
74.698 + Statement *body;
74.699 + if (scanner_.peek() == TOK_LBRACE)
74.700 + body = block();
74.701 + else
74.702 + body = localStatement();
74.703 + if (!body)
74.704 + return NULL;
74.705 +
74.706 + if (!expect(TOK_WHILE))
74.707 + return NULL;
74.708 +
74.709 + if (!expect(TOK_LPAREN))
74.710 + return NULL;
74.711 + Expression *condition = expression();
74.712 + if (!condition)
74.713 + return NULL;
74.714 + if (!expect(TOK_RPAREN))
74.715 + return NULL;
74.716 +
74.717 + return new (pool_) WhileStatement(pos, TOK_DO, condition, body);
74.718 +}
74.719 +
74.720 +Statement *
74.721 +Parser::switch_()
74.722 +{
74.723 + expect(TOK_SWITCH);
74.724 +
74.725 + SourcePosition pos = scanner_.begin();
74.726 +
74.727 + if (!expect(TOK_LPAREN))
74.728 + return NULL;
74.729 + Expression *expr = expression();
74.730 + if (!expr)
74.731 + return NULL;
74.732 + if (!expect(TOK_RPAREN))
74.733 + return NULL;
74.734 +
74.735 + if (!expect(TOK_LBRACE))
74.736 + return NULL;
74.737 +
74.738 + SourcePosition defaultPos;
74.739 + PoolList<Case *> *cases = new (pool_) PoolList<Case *>();
74.740 +
74.741 + Statement *defaultCase = NULL;
74.742 +
74.743 + while (!peek(TOK_RBRACE)) {
74.744 + Expression *expr = NULL;
74.745 + ExpressionList *others = NULL;
74.746 + if (match(TOK_DEFAULT)) {
74.747 + if (defaultCase) {
74.748 + cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch);
74.749 + return NULL;
74.750 + }
74.751 +
74.752 + defaultPos = scanner_.begin();
74.753 + } else {
74.754 + if (defaultCase) {
74.755 + cc_.reportError(defaultPos, Message_DefaultMustBeLastCase);
74.756 + return NULL;
74.757 + }
74.758 +
74.759 + if (!expect(TOK_CASE))
74.760 + return NULL;
74.761 +
74.762 + // A limitation in the grammar is that |case <NAME>:| will be
74.763 + // detected as a label.
74.764 + AutoAllowTags<false> disableTags(scanner_);
74.765 +
74.766 + if ((expr = expression()) == NULL)
74.767 + return NULL;
74.768 +
74.769 + if (peek(TOK_COMMA)) {
74.770 + others = new (pool_) ExpressionList();
74.771 + while (match(TOK_COMMA)) {
74.772 + Expression *other = expression();
74.773 + if (!other)
74.774 + return NULL;
74.775 + if (!others->append(other))
74.776 + return NULL;
74.777 + }
74.778 + }
74.779 + }
74.780 +
74.781 + if (!expect(TOK_COLON))
74.782 + return NULL;
74.783 +
74.784 + Statement *statement = localStatement();
74.785 + if (!statement)
74.786 + return NULL;
74.787 +
74.788 + if (!peek(TOK_CASE) &&
74.789 + !peek(TOK_DEFAULT) &&
74.790 + !peek(TOK_RBRACE))
74.791 + {
74.792 + cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase);
74.793 + return NULL;
74.794 + }
74.795 +
74.796 + if (expr) {
74.797 + Case *caze = new (pool_) Case(expr, others, statement);
74.798 + if (!cases->append(caze))
74.799 + return NULL;
74.800 + } else {
74.801 + defaultCase = statement;
74.802 + }
74.803 + }
74.804 +
74.805 + if (!expect(TOK_RBRACE))
74.806 + return NULL;
74.807 +
74.808 + return new (pool_) SwitchStatement(pos, expr, cases, defaultCase);
74.809 +}
74.810 +
74.811 +Statement *
74.812 +Parser::forStatement()
74.813 +{
74.814 + SourcePosition pos = scanner_.begin();
74.815 + scanner_.scan();
74.816 + if (!expect(TOK_LPAREN))
74.817 + return NULL;
74.818 +
74.819 + Statement *decl = NULL;
74.820 + if (!match(TOK_SEMICOLON)) {
74.821 + if (match(TOK_NEW)) {
74.822 + if ((decl = vars(Qual_None)) == NULL)
74.823 + return NULL;
74.824 + } else {
74.825 + if ((decl = expressionStatement()) == NULL)
74.826 + return NULL;
74.827 + }
74.828 + if (!expect(TOK_SEMICOLON))
74.829 + return NULL;
74.830 + }
74.831 +
74.832 + Expression *condition = NULL;
74.833 + if (!match(TOK_SEMICOLON)) {
74.834 + if ((condition = expression()) == NULL)
74.835 + return NULL;
74.836 + if (!expect(TOK_SEMICOLON))
74.837 + return NULL;
74.838 + }
74.839 +
74.840 + Statement *update = NULL;
74.841 + if (!match(TOK_RPAREN)) {
74.842 + if ((update = expressionStatement()) == NULL)
74.843 + return NULL;
74.844 + if (!expect(TOK_RPAREN))
74.845 + return NULL;
74.846 + }
74.847 +
74.848 + Statement *body;
74.849 + if (scanner_.peek() == TOK_LBRACE)
74.850 + body = block();
74.851 + else
74.852 + body = localStatement();
74.853 + if (!body)
74.854 + return NULL;
74.855 +
74.856 + return new (pool_) ForStatement(pos, decl, condition, update, body);
74.857 +}
74.858 +
74.859 +ExpressionList *
74.860 +Parser::dimensions()
74.861 +{
74.862 + ExpressionList *postDimensions = new (pool_) ExpressionList();
74.863 + while (match(TOK_LBRACKET)) {
74.864 + Expression *dim = NULL;
74.865 + if (!match(TOK_RBRACKET)) {
74.866 + if ((dim = expression()) == NULL)
74.867 + return NULL;
74.868 + if (!expect(TOK_RBRACKET))
74.869 + return NULL;
74.870 + }
74.871 +
74.872 + if (!postDimensions->append(dim))
74.873 + return NULL;
74.874 + }
74.875 + return postDimensions;
74.876 +}
74.877 +
74.878 +VariableDeclaration *
74.879 +Parser::var(TypeQualifiers qual)
74.880 +{
74.881 + Expression *type;
74.882 + Local<String> name(zone_);
74.883 +
74.884 + if (!typeAndName(&type, name.ref()))
74.885 + return NULL;
74.886 +
74.887 + SourcePosition pos = scanner_.begin();
74.888 +
74.889 + Expression *expr = NULL;
74.890 + if (match(TOK_ASSIGN)) {
74.891 + switch (scanner_.peek()) {
74.892 + // Note: we don't support [] literals yet.
74.893 + case TOK_LBRACE:
74.894 + if ((expr = arrayLiteral(scanner_.scan())) == NULL)
74.895 + return NULL;
74.896 + break;
74.897 +
74.898 + default:
74.899 + if ((expr = expression()) == NULL)
74.900 + return NULL;
74.901 + break;
74.902 + }
74.903 + }
74.904 +
74.905 + return new (pool_) VariableDeclaration(pos, qual, name, type, expr);
74.906 +}
74.907 +
74.908 +Statement *
74.909 +Parser::vars(TypeQualifiers qual)
74.910 +{
74.911 + VariableDeclaration *decl = var(qual);
74.912 + if (!decl)
74.913 + return NULL;
74.914 +
74.915 + if (!peek(TOK_COMMA))
74.916 + return decl;
74.917 +
74.918 + StatementList *statements = new (pool_) StatementList();
74.919 + if (!statements->append(decl))
74.920 + return NULL;
74.921 +
74.922 + while (match(TOK_COMMA)) {
74.923 + Statement *decl = var(qual);
74.924 + if (!decl)
74.925 + return NULL;
74.926 + if (!statements->append(decl))
74.927 + return NULL;
74.928 + }
74.929 +
74.930 + // Create a fake-o block with no scope to create a statement list.
74.931 + return new (pool_) BlockStatement(decl->pos(), statements);
74.932 +}
74.933 +
74.934 +Statement *
74.935 +Parser::returnStatement()
74.936 +{
74.937 + SourcePosition pos = scanner_.begin();
74.938 + if (!expect(TOK_RETURN))
74.939 + return NULL;
74.940 +
74.941 + Expression *expr = NULL;
74.942 + if (scanner_.peek() != TOK_SEMICOLON) {
74.943 + if ((expr = expression()) == NULL)
74.944 + return NULL;
74.945 +
74.946 + // We only care about non-void returns when determining whether a
74.947 + // tagless function is non-void.
74.948 + encounteredReturn_ = true;
74.949 + }
74.950 +
74.951 + return new (pool_) ReturnStatement(pos, expr);
74.952 +}
74.953 +
74.954 +Statement *
74.955 +Parser::expressionStatement()
74.956 +{
74.957 + Expression *left = assignment();
74.958 + if (!left)
74.959 + return NULL;
74.960 +
74.961 + return new (pool_) ExpressionStatement(left);
74.962 +}
74.963 +
74.964 +Statement *
74.965 +Parser::block()
74.966 +{
74.967 + if (!expect(TOK_LBRACE))
74.968 + return NULL;
74.969 +
74.970 + SourcePosition pos = scanner_.begin();
74.971 +
74.972 + StatementList *statements = new (pool_) StatementList();
74.973 + while (!match(TOK_RBRACE)) {
74.974 + Statement *statement = localStatement();
74.975 + if (statement == NULL)
74.976 + return NULL;
74.977 + if (!statements->append(statement))
74.978 + return NULL;
74.979 + }
74.980 +
74.981 + BlockStatement *block = new (pool_) BlockStatement(pos, statements);
74.982 + return block;
74.983 +}
74.984 +
74.985 +Statement *
74.986 +Parser::if_()
74.987 +{
74.988 + expect(TOK_IF);
74.989 +
74.990 + SourcePosition pos = scanner_.begin();
74.991 + if (!expect(TOK_LPAREN))
74.992 + return NULL;
74.993 +
74.994 + Expression *cond = expression();
74.995 + if (!cond)
74.996 + return NULL;
74.997 +
74.998 + if (!expect(TOK_RPAREN))
74.999 + return NULL;
74.1000 +
74.1001 + Statement *ifTrue = localStatement();
74.1002 + if (!ifTrue)
74.1003 + return NULL;
74.1004 +
74.1005 + IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue);
74.1006 +
74.1007 + IfStatement *last = outer;
74.1008 + while (match(TOK_ELSE)) {
74.1009 + if (!match(TOK_IF)) {
74.1010 + Statement *ifFalse = localStatement();
74.1011 + if (!ifFalse)
74.1012 + return NULL;
74.1013 +
74.1014 + last->setIfFalse(ifFalse);
74.1015 + break;
74.1016 + }
74.1017 +
74.1018 + SourcePosition pos = scanner_.begin();
74.1019 + if (!expect(TOK_LPAREN))
74.1020 + return NULL;
74.1021 +
74.1022 + Expression *otherCond = expression();
74.1023 + if (!otherCond)
74.1024 + return NULL;
74.1025 +
74.1026 + if (!expect(TOK_RPAREN))
74.1027 + return NULL;
74.1028 +
74.1029 + Statement *otherIfTrue = localStatement();
74.1030 + if (!otherIfTrue)
74.1031 + return NULL;
74.1032 +
74.1033 + IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue);
74.1034 + last->setIfFalse(inner);
74.1035 + last = inner;
74.1036 + }
74.1037 +
74.1038 + return outer;
74.1039 +}
74.1040 +
74.1041 +Statement *
74.1042 +Parser::localStatement()
74.1043 +{
74.1044 + Statement *statement = NULL;
74.1045 +
74.1046 + // Statements which must be followed by a semicolon will break out of the
74.1047 + // switch. If they may end in BlockStatements, they'll immediately return.
74.1048 +
74.1049 + TokenKind kind = scanner_.peek();
74.1050 + switch (kind) {
74.1051 + case TOK_CONST:
74.1052 + case TOK_NEW:
74.1053 + {
74.1054 + TypeQualifiers quals = (kind == TOK_CONST)
74.1055 + ? Qual_Const
74.1056 + : Qual_None;
74.1057 + scanner_.scan();
74.1058 + if ((statement = vars(quals)) == NULL)
74.1059 + return NULL;
74.1060 + break;
74.1061 + }
74.1062 +
74.1063 + case TOK_FOR:
74.1064 + return forStatement();
74.1065 +
74.1066 + case TOK_WHILE:
74.1067 + return while_();
74.1068 +
74.1069 + case TOK_BREAK:
74.1070 + scanner_.scan();
74.1071 + statement = new (pool_) BreakStatement(scanner_.begin());
74.1072 + break;
74.1073 +
74.1074 + case TOK_CONTINUE:
74.1075 + scanner_.scan();
74.1076 + statement = new (pool_) ContinueStatement(scanner_.begin());
74.1077 + break;
74.1078 +
74.1079 + case TOK_DO:
74.1080 + if ((statement = do_()) == NULL)
74.1081 + return NULL;
74.1082 + break;
74.1083 +
74.1084 + case TOK_RETURN:
74.1085 + if ((statement = returnStatement()) == NULL)
74.1086 + return NULL;
74.1087 + break;
74.1088 +
74.1089 + case TOK_ENUM:
74.1090 + if ((statement = enum_()) == NULL)
74.1091 + return NULL;
74.1092 + break;
74.1093 +
74.1094 + case TOK_STRUCT:
74.1095 + if ((statement = struct_()) == NULL)
74.1096 + return NULL;
74.1097 + break;
74.1098 +
74.1099 + case TOK_SWITCH:
74.1100 + return switch_();
74.1101 +
74.1102 + case TOK_IF:
74.1103 + return if_();
74.1104 +
74.1105 + case TOK_LBRACE:
74.1106 + return block();
74.1107 +
74.1108 + default:
74.1109 + break;
74.1110 + }
74.1111 +
74.1112 + if (!statement) {
74.1113 + if ((statement = expressionStatement()) == NULL)
74.1114 + return NULL;
74.1115 + }
74.1116 +
74.1117 + if (!expect(TOK_SEMICOLON))
74.1118 + return NULL;
74.1119 +
74.1120 + return statement;
74.1121 +}
74.1122 +
74.1123 +Statement *
74.1124 +Parser::struct_()
74.1125 +{
74.1126 + expect(TOK_STRUCT);
74.1127 +
74.1128 + Local<String> name(zone_, expectName());
74.1129 + if (!name)
74.1130 + return NULL;
74.1131 +
74.1132 + SourcePosition pos = scanner_.begin();
74.1133 +
74.1134 + if (!expect(TOK_LBRACE))
74.1135 + return NULL;
74.1136 +
74.1137 + FieldList *fields = new (pool_) FieldList();
74.1138 +
74.1139 + while (!peek(TOK_RBRACE)) {
74.1140 + Expression *type;
74.1141 + Local<String> fieldName(zone_);
74.1142 +
74.1143 + if (!fullTypeAndName(&type, fieldName.ref(), DeclField))
74.1144 + return NULL;
74.1145 +
74.1146 + SourcePosition pos = scanner_.begin();
74.1147 +
74.1148 + if (!matchSemicolon())
74.1149 + return NULL;
74.1150 +
74.1151 + StructureStatement::Field *field =
74.1152 + new (pool_) StructureStatement::Field(pos, type, fieldName);
74.1153 + if (!field || !fields->append(field))
74.1154 + return NULL;
74.1155 + }
74.1156 +
74.1157 + if (!expect(TOK_RBRACE))
74.1158 + return NULL;
74.1159 +
74.1160 + if (fields->empty()) {
74.1161 + cc_.reportError(pos, Message_StructCantBeEmpty);
74.1162 + return NULL;
74.1163 + }
74.1164 +
74.1165 + return new (pool_) StructureStatement(pos, name, fields);
74.1166 +}
74.1167 +
74.1168 +Statement *
74.1169 +Parser::enum_()
74.1170 +{
74.1171 + expect(TOK_ENUM);
74.1172 +
74.1173 + SourcePosition pos = scanner_.begin();
74.1174 +
74.1175 + Local<String> name(zone_);
74.1176 + if (matchName(name.ref()) && !name)
74.1177 + return NULL;
74.1178 +
74.1179 + EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList();
74.1180 +
74.1181 + if (!expect(TOK_LBRACE))
74.1182 + return NULL;
74.1183 +
74.1184 + do {
74.1185 + if (scanner_.peek() == TOK_RBRACE)
74.1186 + break;
74.1187 +
74.1188 + Local<String> name(zone_, expectName());
74.1189 + if (!name)
74.1190 + return NULL;
74.1191 +
74.1192 + Expression *expr = NULL;
74.1193 + if (match(TOK_ASSIGN)) {
74.1194 + if ((expr = expression()) == NULL)
74.1195 + return NULL;
74.1196 + }
74.1197 +
74.1198 + if (!entries->append(EnumStatement::Entry(name, expr)))
74.1199 + return NULL;
74.1200 + } while (match(TOK_COMMA));
74.1201 + if (!expect(TOK_RBRACE))
74.1202 + return NULL;
74.1203 +
74.1204 + return new (pool_) EnumStatement(pos, name, entries);
74.1205 +}
74.1206 +
74.1207 +template <class T>
74.1208 +static inline ScopedRoot<T> *
74.1209 +NewScopedRoot(PoolAllocator &pool, Handle<T> obj)
74.1210 +{
74.1211 + ScopedRoot<T> *root = pool.alloc<ScopedRoot<T> >();
74.1212 + new (root) ScopedRoot<T>(obj);
74.1213 + return root;
74.1214 +}
74.1215 +
74.1216 +ImportStatement *
74.1217 +Parser::import()
74.1218 +{
74.1219 + NameList *names = new (pool_) NameList();
74.1220 +
74.1221 + SourcePosition pos = scanner_.begin();
74.1222 +
74.1223 + Local<String> name(zone_, expectName());
74.1224 + if (!name || !names->append(NewScopedRoot<String>(pool_, name)))
74.1225 + return NULL;
74.1226 +
74.1227 + TokenKind suffix = TOK_NONE;
74.1228 + while (match(TOK_DOT)) {
74.1229 + if (match(TOK_STAR)) {
74.1230 + suffix = TOK_STAR;
74.1231 + break;
74.1232 + }
74.1233 +
74.1234 + if ((name = expectName()) == NULL)
74.1235 + return NULL;
74.1236 +
74.1237 + if (!names->append(NewScopedRoot<String>(pool_, name)))
74.1238 + return NULL;
74.1239 + }
74.1240 +
74.1241 + return new (pool_) ImportStatement(pos, names, suffix);
74.1242 +}
74.1243 +
74.1244 +Statement *
74.1245 +Parser::function(TokenKind token)
74.1246 +{
74.1247 + Expression *returnType;
74.1248 + Local<String> name(zone_);
74.1249 +
74.1250 + if (!fullTypeAndName(&returnType, name.ref(), DeclFun))
74.1251 + return NULL;
74.1252 +
74.1253 + SourcePosition pos = scanner_.begin();
74.1254 + ParameterList *parameters = new (pool_) ParameterList();
74.1255 +
74.1256 + if (!expect(TOK_LPAREN))
74.1257 + return NULL;
74.1258 +
74.1259 + bool variadic = false;
74.1260 +
74.1261 + if (!match(TOK_RPAREN)) {
74.1262 + while (true) {
74.1263 + bool isConst = match(TOK_CONST);
74.1264 + bool ref = match(TOK_AMPERSAND);
74.1265 +
74.1266 + SourcePosition begin = scanner_.begin();
74.1267 + Expression *type;
74.1268 + Local<String> name(zone_);
74.1269 + if (!fullTypeAndName(&type, name.ref(), DeclArg))
74.1270 + return NULL;
74.1271 +
74.1272 + if (!name) {
74.1273 + if (isConst || ref) {
74.1274 + cc_.reportError(begin, Message_InvalidVarArgs);
74.1275 + return NULL;
74.1276 + }
74.1277 +
74.1278 + if (token != TOK_NATIVE) {
74.1279 + cc_.reportError(begin, Message_VarArgsOutsideNative);
74.1280 + return NULL;
74.1281 + }
74.1282 +
74.1283 + variadic = true;
74.1284 + break;
74.1285 + }
74.1286 +
74.1287 + Expression *expr = NULL;
74.1288 + if (match(TOK_ASSIGN)) {
74.1289 + if ((expr = expression()) == NULL)
74.1290 + return NULL;
74.1291 + }
74.1292 +
74.1293 + Parameter *parameter = new (pool_) Parameter(name, type, ref, isConst, expr, begin);
74.1294 + if (!parameters->append(parameter))
74.1295 + return NULL;
74.1296 +
74.1297 + if (!match(TOK_COMMA))
74.1298 + break;
74.1299 + }
74.1300 + if (!expect(TOK_RPAREN))
74.1301 + return NULL;
74.1302 + }
74.1303 +
74.1304 + encounteredReturn_ = false;
74.1305 +
74.1306 + Statement *body = NULL;
74.1307 + if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) {
74.1308 + body = block();
74.1309 + if (!body)
74.1310 + return NULL;
74.1311 + }
74.1312 +
74.1313 + FunctionSignature signature(returnType, parameters, variadic);
74.1314 + if (token == TOK_TYPEDEF)
74.1315 + return new (pool_) FunctionTypeStatement(pos, name, signature);
74.1316 +
74.1317 + return new (pool_) FunctionStatement(pos, name, token, body, signature, encounteredReturn_);
74.1318 +}
74.1319 +
74.1320 +static inline bool
74.1321 +DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle<Type> type)
74.1322 +{
74.1323 + Local<String> tag(zone, zone->makeSymbol(name));
74.1324 + if (!tag)
74.1325 + return false;
74.1326 +
74.1327 + assert(false);
74.1328 + return false; //return !!scope->declareType(tag, type);
74.1329 +}
74.1330 +
74.1331 +static inline bool
74.1332 +DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type)
74.1333 +{
74.1334 + Local<Type> primitive(zone, zone->types()->getPrimitive(type));
74.1335 + assert(primitive);
74.1336 + return DeclareIntrinsicType(zone, scope, name, primitive);
74.1337 +}
74.1338 +
74.1339 +bool
74.1340 +Parser::setupIntrinsics()
74.1341 +{
74.1342 +#if 0
74.1343 + if (!DeclareIntrinsicType(zone_, scope_, "Float", PrimitiveType_Float))
74.1344 + return false;
74.1345 + if (!DeclareIntrinsicType(zone_, scope_, "_", PrimitiveType_Int32))
74.1346 + return false;
74.1347 + if (!DeclareIntrinsicType(zone_, scope_, "bool", PrimitiveType_Bool))
74.1348 + return false;
74.1349 + if (!DeclareIntrinsicType(zone_, scope_, "String", PrimitiveType_Char))
74.1350 + return false;
74.1351 +
74.1352 + Local<Type> unchecked(zone_, zone_->types()->getUnchecked());
74.1353 + if (!DeclareIntrinsicType(zone_, scope_, "unchecked", unchecked))
74.1354 + return false;
74.1355 +
74.1356 + Local<Type> voidType(zone_, zone_->types()->getVoid());
74.1357 + if (!DeclareIntrinsicType(zone_, scope_, "void", voidType))
74.1358 + return false;
74.1359 +
74.1360 + Local<Type> intType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
74.1361 + if (!DeclareIntrinsicType(zone_, scope_, "int", intType))
74.1362 + return false;
74.1363 +#endif
74.1364 + return true;
74.1365 +}
74.1366 +
74.1367 +ParseTree *
74.1368 +Parser::parse()
74.1369 +{
74.1370 + StatementList *statements = new (pool_) StatementList();
74.1371 +
74.1372 + if (!setupIntrinsics())
74.1373 + return NULL;
74.1374 +
74.1375 + for (;;) {
74.1376 + Statement *statement = NULL;
74.1377 +
74.1378 + TokenKind kind = scanner_.peek();
74.1379 + switch (kind) {
74.1380 + case TOK_ERROR:
74.1381 + return NULL;
74.1382 +
74.1383 + case TOK_EOF:
74.1384 + break;
74.1385 +
74.1386 + case TOK_NAME:
74.1387 + if ((statement = function(TOK_NAME)) == NULL)
74.1388 + return NULL;
74.1389 + break;
74.1390 +
74.1391 + case TOK_IMPORT:
74.1392 + {
74.1393 + scanner_.scan();
74.1394 + if (statements->length())
74.1395 + cc_.reportError(scanner_.begin(), Message_ImportsMustBeFirst);
74.1396 + ImportStatement *stmt = import();
74.1397 + if (!stmt)
74.1398 + return NULL;
74.1399 + if (!imports_->append(stmt))
74.1400 + return NULL;
74.1401 + if (!matchSemicolon())
74.1402 + return NULL;
74.1403 + continue;
74.1404 + }
74.1405 +
74.1406 + case TOK_FORWARD:
74.1407 + case TOK_PUBLIC:
74.1408 + case TOK_NATIVE:
74.1409 + case TOK_STOCK:
74.1410 + case TOK_LABEL:
74.1411 + case TOK_TYPEDEF:
74.1412 + {
74.1413 + if (kind != TOK_LABEL)
74.1414 + scanner_.scan();
74.1415 + if (kind == TOK_PUBLIC && peek(TOK_CONST)) {
74.1416 + TypeQualifiers quals = TypeQualifiers(Qual_Public | Qual_Const);
74.1417 + if ((statement = var(quals)) == NULL)
74.1418 + return NULL;
74.1419 + if (!matchSemicolon())
74.1420 + return NULL;
74.1421 + } else {
74.1422 + if ((statement = function(kind)) == NULL)
74.1423 + return NULL;
74.1424 + if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon())
74.1425 + return NULL;
74.1426 + }
74.1427 + break;
74.1428 + }
74.1429 +
74.1430 + case TOK_CONST:
74.1431 + case TOK_NEW:
74.1432 + {
74.1433 + TypeQualifiers quals = (kind == TOK_NEW) ? Qual_Const : Qual_None;
74.1434 + // Note: at global scope, we don't accept comma-delimited
74.1435 + // declarations yet, to see if we can get away with forcing
74.1436 + // a nicer top-level style.
74.1437 + scanner_.scan();
74.1438 + if ((statement = var(quals)) == NULL)
74.1439 + return NULL;
74.1440 + if (!matchSemicolon())
74.1441 + return NULL;
74.1442 + break;
74.1443 + }
74.1444 +
74.1445 + case TOK_ENUM:
74.1446 + if ((statement = enum_()) == NULL)
74.1447 + return NULL;
74.1448 + if (!matchSemicolon())
74.1449 + return NULL;
74.1450 + break;
74.1451 +
74.1452 + case TOK_STRUCT:
74.1453 + if ((statement = struct_()) == NULL)
74.1454 + return NULL;
74.1455 + if (!matchSemicolon())
74.1456 + return NULL;
74.1457 + break;
74.1458 +
74.1459 + default:
74.1460 + cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
74.1461 + return NULL;
74.1462 + }
74.1463 +
74.1464 + if (!statement)
74.1465 + break;
74.1466 +
74.1467 + if (!statements->append(statement))
74.1468 + return NULL;
74.1469 + }
74.1470 +
74.1471 + return new (pool_) ParseTree(statements, unbound_, imports_);
74.1472 +}
74.1473 +
74.1474 +class AstPrinter : public AstVisitor
74.1475 +{
74.1476 + FILE *fp_;
74.1477 + size_t level_;
74.1478 +
74.1479 + private:
74.1480 + void prefix() {
74.1481 + for (size_t i = 0; i < level_; i++)
74.1482 + fprintf(fp_, " ");
74.1483 + }
74.1484 + void indent() {
74.1485 + level_++;
74.1486 + }
74.1487 + void unindent() {
74.1488 + level_--;
74.1489 + }
74.1490 +
74.1491 + public:
74.1492 + AstPrinter(FILE *fp)
74.1493 + : fp_(fp),
74.1494 + level_(0)
74.1495 + {
74.1496 + }
74.1497 +
74.1498 + void dump(const FunctionSignature &sig) {
74.1499 + prefix();
74.1500 + fprintf(fp_, "()\n");
74.1501 + }
74.1502 + void visitNameProxy(NameProxy *name) {
74.1503 + prefix();
74.1504 + fprintf(fp_, "[ NameProxy (%s)\n", name->name()->chars());
74.1505 + }
74.1506 + void visitCallExpression(CallExpression *node) {
74.1507 + prefix();
74.1508 + fprintf(fp_, "[ CallExpression\n");
74.1509 + indent();
74.1510 + node->callee()->accept(this);
74.1511 + for (size_t i = 0; i < node->arguments()->length(); i++)
74.1512 + node->arguments()->at(i)->accept(this);
74.1513 + unindent();
74.1514 + }
74.1515 + void visitFunctionTypeStatement(FunctionTypeStatement *node) {
74.1516 + prefix();
74.1517 + fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->name()->chars());
74.1518 + indent();
74.1519 + dump(node->signature());
74.1520 + unindent();
74.1521 + }
74.1522 + void visitFunctionStatement(FunctionStatement *node) {
74.1523 + prefix();
74.1524 + fprintf(fp_, "[ FunctionStatement (%s)\n", node->name()->chars());
74.1525 + indent();
74.1526 + dump(node->signature());
74.1527 + if (node->body())
74.1528 + node->body()->accept(this);
74.1529 + unindent();
74.1530 + }
74.1531 + void visitExpressionStatement(ExpressionStatement *node) {
74.1532 + prefix();
74.1533 + fprintf(fp_, "[ ExpressionStatement\n");
74.1534 + indent();
74.1535 + node->expression()->accept(this);
74.1536 + unindent();
74.1537 + }
74.1538 + void visitAssignment(Assignment *node) {
74.1539 + prefix();
74.1540 + fprintf(fp_, "[ Assignment\n");
74.1541 + indent();
74.1542 + node->lvalue()->accept(this);
74.1543 + node->expression()->accept(this);
74.1544 + unindent();
74.1545 + }
74.1546 + void visitTernaryExpression(TernaryExpression *node) {
74.1547 + prefix();
74.1548 + fprintf(fp_, "[ TernaryExpression\n");
74.1549 + indent();
74.1550 + node->condition()->accept(this);
74.1551 + node->left()->accept(this);
74.1552 + node->right()->accept(this);
74.1553 + unindent();
74.1554 + }
74.1555 + void visitBinaryExpression(BinaryExpression *node) {
74.1556 + prefix();
74.1557 + fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]);
74.1558 + indent();
74.1559 + node->left()->accept(this);
74.1560 + node->right()->accept(this);
74.1561 + unindent();
74.1562 + }
74.1563 + void visitUnaryExpression(UnaryExpression *node) {
74.1564 + prefix();
74.1565 + fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]);
74.1566 + indent();
74.1567 + node->expression()->accept(this);
74.1568 + unindent();
74.1569 + }
74.1570 + void visitReturnStatement(ReturnStatement *node) {
74.1571 + prefix();
74.1572 + fprintf(fp_, "[ ReturnStatement\n");
74.1573 + indent();
74.1574 + if (node->expression())
74.1575 + node->expression()->accept(this);
74.1576 + unindent();
74.1577 + }
74.1578 + void visitForStatement(ForStatement *node) {
74.1579 + prefix();
74.1580 + fprintf(fp_, "[ ForStatement\n");
74.1581 + indent();
74.1582 + if (node->initialization())
74.1583 + node->initialization()->accept(this);
74.1584 + if (node->condition())
74.1585 + node->condition()->accept(this);
74.1586 + if (node->update())
74.1587 + node->update()->accept(this);
74.1588 + node->body()->accept(this);
74.1589 + unindent();
74.1590 + }
74.1591 + void visitBlockStatement(BlockStatement *node) {
74.1592 + prefix();
74.1593 + fprintf(fp_, "[ BlockStatement\n");
74.1594 + indent();
74.1595 + for (size_t i = 0; i < node->statements()->length(); i++)
74.1596 + node->statements()->at(i)->accept(this);
74.1597 + unindent();
74.1598 + }
74.1599 + void visitVariableDeclaration(VariableDeclaration *node) {
74.1600 + prefix();
74.1601 + fprintf(fp_, "[ VariableDeclaration (%s)\n", node->name()->chars());
74.1602 + indent();
74.1603 + if (node->initialization())
74.1604 + node->initialization()->accept(this);
74.1605 + unindent();
74.1606 + }
74.1607 + void visitIntegerLiteral(IntegerLiteral *node) {
74.1608 + prefix();
74.1609 + fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
74.1610 + }
74.1611 + void visitBooleanLiteral(BooleanLiteral *node) {
74.1612 + prefix();
74.1613 + fprintf(fp_, "[ BooleanLiteral (%s)\n",
74.1614 + (node->token() == TOK_TRUE) ? "true" : "false");
74.1615 + }
74.1616 + void visitFloatLiteral(FloatLiteral *node) {
74.1617 + prefix();
74.1618 + fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
74.1619 + }
74.1620 + void visitIfStatement(IfStatement *node) {
74.1621 + prefix();
74.1622 + fprintf(fp_, "[ IfStatement\n");
74.1623 + indent();
74.1624 + node->ifTrue()->accept(this);
74.1625 + if (node->ifFalse())
74.1626 + node->ifFalse()->accept(this);
74.1627 + unindent();
74.1628 + }
74.1629 + void visitIndexExpression(IndexExpression *node) {
74.1630 + prefix();
74.1631 + fprintf(fp_, "[ IndexExpression\n");
74.1632 + indent();
74.1633 + node->left()->accept(this);
74.1634 + node->right()->accept(this);
74.1635 + unindent();
74.1636 + }
74.1637 + void visitEnumStatement(EnumStatement *node) {
74.1638 + prefix();
74.1639 + fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : "<anonymous>");
74.1640 + indent();
74.1641 + for (size_t i = 0; i < node->entries()->length(); i++) {
74.1642 + prefix();
74.1643 + fprintf(fp_, "%s =\n", node->entries()->at(i).name->chars());
74.1644 + if (node->entries()->at(i).expr) {
74.1645 + indent();
74.1646 + node->entries()->at(i).expr->accept(this);
74.1647 + unindent();
74.1648 + }
74.1649 + }
74.1650 + unindent();
74.1651 + }
74.1652 + void visitWhileStatement(WhileStatement *node) {
74.1653 + prefix();
74.1654 + fprintf(fp_, "[ WhileStatement (%s)\n",
74.1655 + (node->token() == TOK_DO) ? "do" : "while");
74.1656 + indent();
74.1657 + if (node->token() == TOK_DO) {
74.1658 + node->condition()->accept(this);
74.1659 + node->body()->accept(this);
74.1660 + } else {
74.1661 + node->condition()->accept(this);
74.1662 + node->body()->accept(this);
74.1663 + }
74.1664 + unindent();
74.1665 + }
74.1666 + void visitBreakStatement(BreakStatement *node) {
74.1667 + prefix();
74.1668 + fprintf(fp_, "[ BreakStatement\n");
74.1669 + }
74.1670 + void visitContinueStatement(ContinueStatement *node) {
74.1671 + prefix();
74.1672 + fprintf(fp_, "[ ContinueStatement\n");
74.1673 + }
74.1674 + void visitStringLiteral(StringLiteral *node) {
74.1675 + prefix();
74.1676 + fprintf(fp_, "[ StringLiteral\n");
74.1677 + }
74.1678 + void visitIncDecExpression(IncDecExpression *node) {
74.1679 + prefix();
74.1680 + fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
74.1681 + indent();
74.1682 + node->expression()->accept(this);
74.1683 + unindent();
74.1684 + }
74.1685 + void visitStructureStatement(StructureStatement *node) {
74.1686 + prefix();
74.1687 + fprintf(fp_, "[ StructureStatement %s\n", node->name()->chars());
74.1688 + }
74.1689 + void visitFieldExpression(FieldExpression *node) {
74.1690 + prefix();
74.1691 + fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars());
74.1692 + indent();
74.1693 + node->left()->accept(this);
74.1694 + unindent();
74.1695 + }
74.1696 + void visitSwitchStatement(SwitchStatement *node) {
74.1697 + prefix();
74.1698 + fprintf(fp_, "[ SwitchStatement\n");
74.1699 + indent();
74.1700 + node->expression()->accept(this);
74.1701 + for (size_t i = 0; i < node->cases()->length(); i++) {
74.1702 + Case *c = node->cases()->at(i);
74.1703 + c->expression()->accept(this);
74.1704 + if (c->others()) {
74.1705 + for (size_t j = 0; j < c->others()->length(); j++)
74.1706 + c->others()->at(j)->accept(this);
74.1707 + }
74.1708 + indent();
74.1709 + c->statement()->accept(this);
74.1710 + unindent();
74.1711 + }
74.1712 + if (node->defaultCase())
74.1713 + node->defaultCase()->accept(this);
74.1714 + unindent();
74.1715 + }
74.1716 + void visitArrayLiteral(ArrayLiteral *node) {
74.1717 + prefix();
74.1718 + fprintf(fp_, "[ ArrayLiteral\n");
74.1719 + indent();
74.1720 + for (size_t i = 0; i < node->expressions()->length(); i++) {
74.1721 + Expression *expr = node->expressions()->at(i);
74.1722 + indent();
74.1723 + expr->accept(this);
74.1724 + unindent();
74.1725 + }
74.1726 + }
74.1727 + void visitImportStatement(ImportStatement *node) {
74.1728 + prefix();
74.1729 + fprintf(fp_, "[ ImportStatement\n");
74.1730 + }
74.1731 +};
74.1732 +
74.1733 +void
74.1734 +ParseTree::dump(FILE *fp)
74.1735 +{
74.1736 + AstPrinter printer(fp);
74.1737 +
74.1738 + for (size_t i = 0; i < statements_->length(); i++)
74.1739 + statements_->at(i)->accept(&printer);
74.1740 +}
75.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
75.2 +++ b/src/compiler/Parser.h Sat Nov 17 18:41:01 2012 -0800
75.3 @@ -0,0 +1,108 @@
75.4 +/* vim: set ts=4 sw=4 tw=99 et:
75.5 + *
75.6 + * Copyright (C) 2012 David Anderson
75.7 + *
75.8 + * This file is part of SourcePawn.
75.9 + *
75.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
75.11 + * the terms of the GNU General Public License as published by the Free
75.12 + * Software Foundation, either version 3 of the License, or (at your option)
75.13 + * any later version.
75.14 + *
75.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
75.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
75.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
75.18 + *
75.19 + * You should have received a copy of the GNU General Public License along with
75.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
75.21 + */
75.22 +#ifndef _include_jitcraft_parser_h_
75.23 +#define _include_jitcraft_parser_h_
75.24 +
75.25 +#include <stdio.h>
75.26 +#include "../Strings.h"
75.27 +#include "AST.h"
75.28 +#include "Scanner.h"
75.29 +#include "Scopes.h"
75.30 +
75.31 +namespace ke {
75.32 +
75.33 +class Parser
75.34 +{
75.35 + Zone *zone_;
75.36 + CompileContext &cc_;
75.37 + PoolAllocator &pool_;
75.38 + Scanner scanner_;
75.39 + PoolList<NameProxy *> *unbound_;
75.40 + PoolList<ImportStatement *> *imports_;
75.41 + bool encounteredReturn_;
75.42 +
75.43 + private:
75.44 + bool peek(TokenKind kind);
75.45 + bool match(TokenKind kind);
75.46 + bool expect(TokenKind kind);
75.47 + bool matchSemicolon();
75.48 +
75.49 + enum DeclKind {
75.50 + DeclArg,
75.51 + DeclFun,
75.52 + DeclField
75.53 + };
75.54 +
75.55 + VariableDeclaration *var(TypeQualifiers qual);
75.56 + Statement *vars(TypeQualifiers qual);
75.57 + bool matchName(String **name, TokenKind kind = TOK_NAME);
75.58 + bool typeAndName(Expression **type, String **namep);
75.59 + bool fullTypeAndName(Expression **type, String **namep, DeclKind kind);
75.60 +
75.61 + ExpressionList *dimensions();
75.62 + String *expectName();
75.63 +
75.64 + Expression *primitive();
75.65 + Expression *arrayLiteral(TokenKind kind);
75.66 + Expression *call(Expression *callee);
75.67 + Expression *field(Expression *left);
75.68 + Expression *index(Expression *left);
75.69 + Expression *prefix();
75.70 + Expression *primary();
75.71 + Expression *unary();
75.72 + Expression *multiplication();
75.73 + Expression *addition();
75.74 + Expression *shift();
75.75 + Expression *bitand_();
75.76 + Expression *bitxor();
75.77 + Expression *bitor_();
75.78 + Expression *relational();
75.79 + Expression *equals();
75.80 + Expression *and_();
75.81 + Expression *or_();
75.82 + Expression *ternary();
75.83 + Expression *assignment();
75.84 + Expression *expression();
75.85 +
75.86 + Statement *switch_();
75.87 + Statement *struct_();
75.88 + Statement *enum_();
75.89 + Statement *if_();
75.90 + Statement *block();
75.91 + Statement *function(TokenKind tok);
75.92 + Statement *expressionStatement();
75.93 + Statement *while_();
75.94 + Statement *do_();
75.95 + Statement *forStatement();
75.96 + Statement *localStatement();
75.97 + Statement *globalStatement();
75.98 + Statement *returnStatement();
75.99 + ImportStatement *import();
75.100 +
75.101 + bool setupIntrinsics();
75.102 +
75.103 + public:
75.104 + Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
75.105 +
75.106 + ParseTree *parse();
75.107 +};
75.108 +
75.109 +}
75.110 +
75.111 +#endif // _include_jitcraft_parser_h_
76.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
76.2 +++ b/src/compiler/Scanner.cpp Sat Nov 17 18:41:01 2012 -0800
76.3 @@ -0,0 +1,681 @@
76.4 +/* vim: set ts=4 sw=4 tw=99 et:
76.5 + *
76.6 + * Copyright (C) 2012 David Anderson
76.7 + *
76.8 + * This file is part of JITCraft.
76.9 + *
76.10 + * JITCraft is free software: you can redistribute it and/or modify it under
76.11 + * the terms of the GNU General Public License as published by the Free
76.12 + * Software Foundation, either version 3 of the License, or (at your option)
76.13 + * any later version.
76.14 + *
76.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
76.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
76.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
76.18 + *
76.19 + * You should have received a copy of the GNU General Public License along with
76.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
76.21 + */
76.22 +#include <assert.h>
76.23 +#include <ctype.h>
76.24 +#include <math.h>
76.25 +#include <limits.h>
76.26 +#include <string.h>
76.27 +#include "../Utility.h"
76.28 +#include "Scanner.h"
76.29 +
76.30 +using namespace ke;
76.31 +
76.32 +const char *ke::TokenNames[] =
76.33 +{
76.34 +#define _(name, str) str,
76.35 + TOKENMAP(_)
76.36 +#undef _
76.37 + NULL
76.38 +};
76.39 +
76.40 +Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
76.41 + : cc_(cc),
76.42 + stream_(stream),
76.43 + length_(length),
76.44 + pushed_(false),
76.45 + allowTags_(true),
76.46 + saved_('\0'),
76.47 + pos_(stream_)
76.48 +{
76.49 + cur_.line = 1;
76.50 + cur_.col = 1;
76.51 + last_ = cur_;
76.52 +}
76.53 +
76.54 +char
76.55 +Scanner::getChar()
76.56 +{
76.57 + if (saved_ != '\0') {
76.58 + char temp = saved_;
76.59 + saved_ = '\0';
76.60 + return temp;
76.61 + }
76.62 + if (pos_ >= stream_ + length_)
76.63 + return '\0';
76.64 + last_.col = cur_.col++;
76.65 + return *pos_++;
76.66 +}
76.67 +
76.68 +void
76.69 +Scanner::putChar(char c)
76.70 +{
76.71 + assert(saved_ == '\0');
76.72 + saved_ = c;
76.73 + cur_.col = last_.col;
76.74 +}
76.75 +
76.76 +void
76.77 +Scanner::calcNewLine(char c)
76.78 +{
76.79 + cur_.line++;
76.80 + cur_.col = 1;
76.81 + last_ = cur_;
76.82 +
76.83 + char o;
76.84 + if (c == '\r' && ((o = getChar()) != '\n'))
76.85 + putChar(o);
76.86 +}
76.87 +
76.88 +void
76.89 +Scanner::eatSingleLine()
76.90 +{
76.91 + char c;
76.92 + while ((c = getChar()) != '\0') {
76.93 + if (c == '\n' || c == '\r') {
76.94 + calcNewLine(c);
76.95 + break;
76.96 + }
76.97 + }
76.98 +}
76.99 +
76.100 +bool
76.101 +Scanner::eatComment()
76.102 +{
76.103 + char c;
76.104 +
76.105 + while ((c = getChar()) != '\0') {
76.106 + while (c == '*') {
76.107 + c = getChar();
76.108 + if (c == '\0')
76.109 + return false;
76.110 + if (c == '/')
76.111 + return true;
76.112 + }
76.113 + if (c == '\r' || c == '\n')
76.114 + calcNewLine(c);
76.115 + }
76.116 +
76.117 + return false;
76.118 +}
76.119 +
76.120 +static inline bool
76.121 +IsDigit(char c)
76.122 +{
76.123 + return c >= '0' && c <= '9';
76.124 +}
76.125 +
76.126 +// Based off the logic in sc2.c's ftoi()...
76.127 +double
76.128 +Scanner::ParseDouble(const char *string)
76.129 +{
76.130 + const char *ptr = string;
76.131 +
76.132 + double number = 0.0;
76.133 + while (IsDigit(*ptr)) {
76.134 + number = (number * 10) + (*ptr - '0');
76.135 + ptr++;
76.136 + }
76.137 +
76.138 + assert(*ptr == '.');
76.139 + ptr++;
76.140 +
76.141 + double fraction = 0.0;
76.142 + double multiplier = 1.0;
76.143 + while (IsDigit(*ptr)) {
76.144 + fraction = (fraction * 10) + (*ptr - '0');
76.145 + multiplier = multiplier / 10.0;
76.146 + ptr++;
76.147 + }
76.148 +
76.149 + number += fraction * multiplier;
76.150 +
76.151 + if (*ptr++ == 'e') {
76.152 + int sign = 1;
76.153 + if (*ptr == '-') {
76.154 + sign = -1;
76.155 + ptr++;
76.156 + }
76.157 +
76.158 + int exponent = 0;
76.159 + while (IsDigit(*ptr)) {
76.160 + exponent = (exponent * 10) + (*ptr - '0');
76.161 + ptr++;
76.162 + }
76.163 +
76.164 + multiplier = pow(10.0, exponent * sign);
76.165 + number *= multiplier;
76.166 + }
76.167 +
76.168 + return number;
76.169 +}
76.170 +
76.171 +static inline bool
76.172 +IsHexDigit(char c)
76.173 +{
76.174 + return IsDigit(c) ||
76.175 + (c >= 'a' && c <= 'f') ||
76.176 + (c >= 'A' && c <= 'F');
76.177 +}
76.178 +
76.179 +// Based on the logic for litchar() in sc2.c.
76.180 +int
76.181 +Scanner::readEscapeCode()
76.182 +{
76.183 + char c = getChar();
76.184 + if (c == '\\')
76.185 + return c;
76.186 +
76.187 + switch (c) {
76.188 + case 'a':
76.189 + return '\a';
76.190 + case 'b':
76.191 + return '\b';
76.192 + case 'e':
76.193 + return 27; // Apparently \e is non-standard.
76.194 + case 'f':
76.195 + return '\f';
76.196 + case 'n':
76.197 + return '\n';
76.198 + case 'r':
76.199 + return '\r';
76.200 + case 't':
76.201 + return '\t';
76.202 + case '\v':
76.203 + return '\v';
76.204 +
76.205 + case 'x':
76.206 + {
76.207 + unsigned digits = 0;
76.208 + char r = 0;
76.209 +
76.210 + c = getChar();
76.211 + while (IsHexDigit(c) && digits < 2) {
76.212 + if (IsDigit(c))
76.213 + c = (c << 4) + (c - '0');
76.214 + else
76.215 + c = (c << 4) + (tolower(c) - 'a' + 10);
76.216 + digits++;
76.217 + c = getChar();
76.218 + }
76.219 +
76.220 + // Swallow a trailing ';'
76.221 + if (c != ';')
76.222 + putChar(c);
76.223 +
76.224 + return r;
76.225 + }
76.226 +
76.227 + case '\'':
76.228 + case '\"':
76.229 + case '%':
76.230 + return c;
76.231 +
76.232 + default:
76.233 + {
76.234 + if (IsDigit(c)) {
76.235 + // \ddd
76.236 + char r = 0;
76.237 + while (IsDigit(c)) {
76.238 + r = r * 10 + (c - '0');
76.239 + c = getChar();
76.240 + }
76.241 +
76.242 + // Swallow a trailing ;
76.243 + if (c != ';')
76.244 + putChar(c);
76.245 +
76.246 + return r;
76.247 + }
76.248 + cc_.reportError(begin(), Message_UnknownEscapeCode, c);
76.249 + return INT_MAX;
76.250 + }
76.251 + }
76.252 +}
76.253 +
76.254 +TokenKind
76.255 +Scanner::stringLiteral()
76.256 +{
76.257 + literal_.clear();
76.258 +
76.259 + for (;;) {
76.260 + char c = getChar();
76.261 + if (c == '\"')
76.262 + break;
76.263 + if (c == '\r' || c == '\n' || c == '\0') {
76.264 + cc_.reportError(begin(), Message_UnterminatedString);
76.265 + return TOK_ERROR;
76.266 + }
76.267 + if (c == '\\') {
76.268 + int code = readEscapeCode();
76.269 + if (code == INT_MAX)
76.270 + return TOK_ERROR;
76.271 + c = char(code);
76.272 + }
76.273 + if (!literal_.append(c))
76.274 + return TOK_ERROR;
76.275 + }
76.276 +
76.277 + if (!literal_.append('\0'))
76.278 + return TOK_ERROR;
76.279 +
76.280 + return TOK_STRING_LITERAL;
76.281 +}
76.282 +
76.283 +TokenKind
76.284 +Scanner::hexLiteral()
76.285 +{
76.286 + literal_.clear();
76.287 +
76.288 + char c;
76.289 + for (;;) {
76.290 + c = getChar();
76.291 + if (!IsHexDigit(c))
76.292 + break;
76.293 + if (!literal_.append(c))
76.294 + return TOK_ERROR;
76.295 + }
76.296 +
76.297 + putChar(c);
76.298 +
76.299 + if (!literal_.append('\0'))
76.300 + return TOK_ERROR;
76.301 + return TOK_HEX_LITERAL;
76.302 +}
76.303 +
76.304 +TokenKind
76.305 +Scanner::numberLiteral(char first)
76.306 +{
76.307 + literal_.clear();
76.308 + if (!literal_.append(first))
76.309 + return TOK_ERROR;
76.310 +
76.311 + char c;
76.312 + for (;;) {
76.313 + c = getChar();
76.314 + if (!IsDigit(c))
76.315 + break;
76.316 + if (!literal_.append(c))
76.317 + return TOK_ERROR;
76.318 + }
76.319 +
76.320 + // Detect a hexadecimal string.
76.321 + if (literal_.length() == 1 &&
76.322 + literal_[0] == '0' &&
76.323 + (c == 'x' || c == 'X'))
76.324 + {
76.325 + return hexLiteral();
76.326 + }
76.327 +
76.328 + if (c != '.') {
76.329 + putChar(c);
76.330 + if (!literal_.append('\0'))
76.331 + return TOK_ERROR;
76.332 + return TOK_INTEGER_LITERAL;
76.333 + }
76.334 + if (!literal_.append(c))
76.335 + return TOK_ERROR;
76.336 +
76.337 + c = getChar();
76.338 + if (!IsDigit(c)) {
76.339 + cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
76.340 + return TOK_ERROR;
76.341 + }
76.342 + if (!literal_.append(c))
76.343 + return TOK_ERROR;
76.344 +
76.345 + for (;;) {
76.346 + c = getChar();
76.347 + if (!IsDigit(c))
76.348 + break;
76.349 + if (!literal_.append(c))
76.350 + return TOK_ERROR;
76.351 + }
76.352 +
76.353 + if (c != 'e') {
76.354 + putChar(c);
76.355 + } else {
76.356 + if (!literal_.append(c))
76.357 + return TOK_ERROR;
76.358 + c = getChar();
76.359 + if (c == '-') {
76.360 + if (!literal_.append(c))
76.361 + return TOK_ERROR;
76.362 + c = getChar();
76.363 + }
76.364 + if (!IsDigit(c)) {
76.365 + cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
76.366 + return TOK_ERROR;
76.367 + }
76.368 + if (!literal_.append(c))
76.369 + return TOK_ERROR;
76.370 + for (;;) {
76.371 + c = getChar();
76.372 + if (!IsDigit(c)) {
76.373 + putChar(c);
76.374 + break;
76.375 + }
76.376 + if (!literal_.append(c))
76.377 + return TOK_ERROR;
76.378 + }
76.379 + }
76.380 +
76.381 + if (!literal_.append('\0'))
76.382 + return TOK_ERROR;
76.383 +
76.384 + return TOK_FLOAT_LITERAL;
76.385 +}
76.386 +
76.387 +static inline TokenKind
76.388 +FindIdentifier(const char *str)
76.389 +{
76.390 + if (!strcmp(str, "new"))
76.391 + return TOK_NEW;
76.392 + if (!strcmp(str, "for"))
76.393 + return TOK_FOR;
76.394 + if (!strcmp(str, "return"))
76.395 + return TOK_RETURN;
76.396 + if (!strcmp(str, "if"))
76.397 + return TOK_IF;
76.398 + if (!strcmp(str, "else"))
76.399 + return TOK_ELSE;
76.400 + if (!strcmp(str, "enum"))
76.401 + return TOK_ENUM;
76.402 + if (!strcmp(str, "while"))
76.403 + return TOK_WHILE;
76.404 + if (!strcmp(str, "do"))
76.405 + return TOK_DO;
76.406 + if (!strcmp(str, "break"))
76.407 + return TOK_BREAK;
76.408 + if (!strcmp(str, "continue"))
76.409 + return TOK_CONTINUE;
76.410 + if (!strcmp(str, "forward"))
76.411 + return TOK_FORWARD;
76.412 + if (!strcmp(str, "public"))
76.413 + return TOK_PUBLIC;
76.414 + if (!strcmp(str, "const"))
76.415 + return TOK_CONST;
76.416 + if (!strcmp(str, "native"))
76.417 + return TOK_NATIVE;
76.418 + if (!strcmp(str, "stock"))
76.419 + return TOK_STOCK;
76.420 + if (!strcmp(str, "true"))
76.421 + return TOK_TRUE;
76.422 + if (!strcmp(str, "false"))
76.423 + return TOK_FALSE;
76.424 + if (!strcmp(str, "struct"))
76.425 + return TOK_STRUCT;
76.426 + if (!strcmp(str, "switch"))
76.427 + return TOK_SWITCH;
76.428 + if (!strcmp(str, "case"))
76.429 + return TOK_CASE;
76.430 + if (!strcmp(str, "default"))
76.431 + return TOK_DEFAULT;
76.432 + if (!strcmp(str, "typedef"))
76.433 + return TOK_TYPEDEF;
76.434 + if (!strcmp(str, "void"))
76.435 + return TOK_VOID;
76.436 + if (!strcmp(str, "int"))
76.437 + return TOK_INT;
76.438 + if (!strcmp(str, "sizeof"))
76.439 + return TOK_SIZEOF;
76.440 + if (!strcmp(str, "import"))
76.441 + return TOK_IMPORT;
76.442 + return TOK_NONE;
76.443 +}
76.444 +
76.445 +TokenKind
76.446 +Scanner::identifier(char first)
76.447 +{
76.448 + literal_.clear();
76.449 + if (!literal_.append(first))
76.450 + return TOK_ERROR;
76.451 +
76.452 + char c;
76.453 + for (;;) {
76.454 + c = getChar();
76.455 + if (!isascii(c) || (!isalnum(c) && c != '_'))
76.456 + break;
76.457 + if (!literal_.append(c))
76.458 + return TOK_ERROR;
76.459 + }
76.460 +
76.461 + if (!literal_.append('\0'))
76.462 + return TOK_ERROR;
76.463 +
76.464 + // Most keywords do not act as labels.
76.465 + TokenKind kind = FindIdentifier(literal());
76.466 + if (kind != TOK_NONE) {
76.467 + putChar(c);
76.468 + return kind;
76.469 + }
76.470 +
76.471 + if (c == ':' && allowTags_)
76.472 + return TOK_LABEL;
76.473 +
76.474 + putChar(c);
76.475 +
76.476 + // _ is a special case which acts as a tag and a keyword.
76.477 + if (!strcmp(literal(), "_"))
76.478 + return TOK_UNDERSCORE;
76.479 +
76.480 + return TOK_NAME;
76.481 +}
76.482 +
76.483 +TokenKind
76.484 +Scanner::next()
76.485 +{
76.486 + assert(!pushed_);
76.487 +
76.488 + for (;;) {
76.489 + begin_ = cur_;
76.490 +
76.491 + char c = getChar();
76.492 + switch (c) {
76.493 + case '/':
76.494 + {
76.495 + c = getChar();
76.496 + if (c == '/') {
76.497 + eatSingleLine();
76.498 + break;
76.499 + }
76.500 + if (c == '*') {
76.501 + if (!eatComment()) {
76.502 + cc_.reportError(begin(), Message_UnterminatedComment);
76.503 + return TOK_ERROR;
76.504 + }
76.505 + break;
76.506 + }
76.507 + putChar(c);
76.508 + return TOK_SLASH;
76.509 + }
76.510 +
76.511 + case '\n':
76.512 + case '\r':
76.513 + calcNewLine(c);
76.514 + break;
76.515 +
76.516 + case ';': return TOK_SEMICOLON;
76.517 + case '{': return TOK_LBRACE;
76.518 + case '}': return TOK_RBRACE;
76.519 + case '(': return TOK_LPAREN;
76.520 + case ')': return TOK_RPAREN;
76.521 + case '[': return TOK_LBRACKET;
76.522 + case ']': return TOK_RBRACKET;
76.523 + case '~': return TOK_TILDE;
76.524 + case '?': return TOK_QMARK;
76.525 + case ':': return TOK_COLON;
76.526 +
76.527 + case '.':
76.528 + c = getChar();
76.529 + if (c == '.') {
76.530 + c = getChar();
76.531 + if (c == '.')
76.532 + return TOK_ELLIPSES;
76.533 + cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
76.534 + return TOK_ERROR;
76.535 + }
76.536 + putChar(c);
76.537 + return TOK_DOT;
76.538 +
76.539 + case '*':
76.540 + c = getChar();
76.541 + if (c == '=')
76.542 + return TOK_ASSIGN_MUL;
76.543 + putChar(c);
76.544 + return TOK_STAR;
76.545 +
76.546 + case '+':
76.547 + c = getChar();
76.548 + if (c == '=')
76.549 + return TOK_ASSIGN_ADD;
76.550 + if (c == '+')
76.551 + return TOK_INCREMENT;
76.552 + putChar(c);
76.553 + return TOK_PLUS;
76.554 +
76.555 + case '&':
76.556 + c = getChar();
76.557 + if (c == '=')
76.558 + return TOK_ASSIGN_BITAND;
76.559 + if (c == '&')
76.560 + return TOK_AND;
76.561 + putChar(c);
76.562 + return TOK_BITAND;
76.563 +
76.564 + case '|':
76.565 + c = getChar();
76.566 + if (c == '=')
76.567 + return TOK_ASSIGN_BITOR;
76.568 + if (c == '|')
76.569 + return TOK_OR;
76.570 + putChar(c);
76.571 + return TOK_BITOR;
76.572 +
76.573 + case '^':
76.574 + c = getChar();
76.575 + if (c == '=')
76.576 + return TOK_ASSIGN_BITXOR;
76.577 + putChar(c);
76.578 + return TOK_BITXOR;
76.579 +
76.580 + case '%':
76.581 + c = getChar();
76.582 + if (c == '=')
76.583 + return TOK_ASSIGN_MOD;
76.584 + putChar(c);
76.585 + return TOK_PERCENT;
76.586 +
76.587 + case '-':
76.588 + c = getChar();
76.589 + if (c == '=')
76.590 + return TOK_ASSIGN_SUB;
76.591 + if (c == '-')
76.592 + return TOK_DECREMENT;
76.593 + putChar(c);
76.594 + return TOK_MINUS;
76.595 +
76.596 + case ',': return TOK_COMMA;
76.597 + case '\0': return TOK_EOF;
76.598 +
76.599 + case '!':
76.600 + c = getChar();
76.601 + if (c == '=')
76.602 + return TOK_NOTEQUALS;
76.603 + putChar(c);
76.604 + return TOK_NOT;
76.605 +
76.606 + case '=':
76.607 + c = getChar();
76.608 + if (c == '=')
76.609 + return TOK_EQUALS;
76.610 + putChar(c);
76.611 + return TOK_ASSIGN;
76.612 +
76.613 +
76.614 + case '<':
76.615 + c = getChar();
76.616 + if (c == '=')
76.617 + return TOK_LE;
76.618 + if (c == '<') {
76.619 + c = getChar();
76.620 + if (c == '=')
76.621 + return TOK_ASSIGN_SHL;
76.622 + putChar(c);
76.623 + return TOK_SHL;
76.624 + }
76.625 + putChar(c);
76.626 + return TOK_LT;
76.627 +
76.628 + case '>':
76.629 + c = getChar();
76.630 + if (c == '=')
76.631 + return TOK_GE;
76.632 + if (c == '>') {
76.633 + c = getChar();
76.634 + if (c == '>') {
76.635 + c = getChar();
76.636 + if (c == '=')
76.637 + return TOK_ASSIGN_USHR;
76.638 + putChar(c);
76.639 + return TOK_USHR;
76.640 + }
76.641 + return TOK_SHR;
76.642 + }
76.643 + putChar(c);
76.644 + return TOK_GT;
76.645 +
76.646 + case ' ':
76.647 + case '\t':
76.648 + case '\f':
76.649 + break;
76.650 +
76.651 + case '"':
76.652 + return stringLiteral();
76.653 +
76.654 + default:
76.655 + if (c >= '0' && c <= '9')
76.656 + return numberLiteral(c);
76.657 + if (c == '_' || (isascii(c) && isalpha(c)))
76.658 + return identifier(c);
76.659 + cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
76.660 + return TOK_ERROR;
76.661 + }
76.662 + }
76.663 +}
76.664 +
76.665 +TokenKind
76.666 +Scanner::scan()
76.667 +{
76.668 + if (pushed_) {
76.669 + pushed_ = false;
76.670 + return lastToken_;
76.671 + }
76.672 + lastToken_ = next();
76.673 + return lastToken_;
76.674 +}
76.675 +
76.676 +TokenKind
76.677 +Scanner::peek()
76.678 +{
76.679 + if (pushed_)
76.680 + return lastToken_;
76.681 + scan();
76.682 + pushed_ = true;
76.683 + return lastToken_;
76.684 +}
77.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
77.2 +++ b/src/compiler/Scanner.h Sat Nov 17 18:41:01 2012 -0800
77.3 @@ -0,0 +1,115 @@
77.4 +/* vim: set ts=4 sw=4 tw=99 et:
77.5 + *
77.6 + * Copyright (C) 2012 David Anderson
77.7 + *
77.8 + * This file is part of SourcePawn.
77.9 + *
77.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
77.11 + * the terms of the GNU General Public License as published by the Free
77.12 + * Software Foundation, either version 3 of the License, or (at your option)
77.13 + * any later version.
77.14 + *
77.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
77.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
77.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
77.18 + *
77.19 + * You should have received a copy of the GNU General Public License along with
77.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
77.21 + */
77.22 +#ifndef _include_jitcraft_scanner_h_
77.23 +#define _include_jitcraft_scanner_h_
77.24 +
77.25 +#include <string>
77.26 +#include "Token.h"
77.27 +#include "CompileContext.h"
77.28 +#include "../Opcodes.h"
77.29 +#include "../Vector.h"
77.30 +
77.31 +namespace ke {
77.32 +
77.33 +class Scanner
77.34 +{
77.35 + template <bool Enabled>
77.36 + friend class AutoAllowTags;
77.37 +
77.38 + CompileContext &cc_;
77.39 + const char *stream_;
77.40 + size_t length_;
77.41 + bool pushed_;
77.42 + bool allowTags_;
77.43 + char saved_;
77.44 + const char *pos_;
77.45 + Vector<char> literal_;
77.46 + TokenKind lastToken_;
77.47 + SourcePosition last_;
77.48 + SourcePosition cur_;
77.49 + SourcePosition begin_;
77.50 +
77.51 + private:
77.52 + char getChar();
77.53 + void putChar(char c);
77.54 + void eatSingleLine();
77.55 + bool eatComment();
77.56 + void calcNewLine(char c);
77.57 + int readEscapeCode();
77.58 + TokenKind stringLiteral();
77.59 + TokenKind hexLiteral();
77.60 + TokenKind numberLiteral(char first);
77.61 + TokenKind identifier(char first);
77.62 +
77.63 + TokenKind next();
77.64 +
77.65 + public:
77.66 + Scanner(CompileContext &cc, const char *stream, size_t length);
77.67 +
77.68 + static double ParseDouble(const char *string);
77.69 +
77.70 + TokenKind scan();
77.71 + TokenKind peek();
77.72 + TokenKind last() const {
77.73 + return lastToken_;
77.74 + }
77.75 +
77.76 + bool tagsEnabled() const {
77.77 + return allowTags_;
77.78 + }
77.79 + void setTagsEnabled(bool enabled) {
77.80 + allowTags_ = enabled;
77.81 + }
77.82 +
77.83 + // Beginning source position of the last instruction.
77.84 + SourcePosition begin() const {
77.85 + return begin_;
77.86 + }
77.87 +
77.88 + // Note: the literal may have embedded NUL characters.
77.89 + const char *literal() const {
77.90 + return literal_.buffer();
77.91 + }
77.92 + size_t literal_length() const {
77.93 + return literal_.length() - 1;
77.94 + }
77.95 +};
77.96 +
77.97 +template <bool Enabled>
77.98 +class AutoAllowTags
77.99 +{
77.100 + Scanner &scanner_;
77.101 + bool prev_;
77.102 +
77.103 + public:
77.104 + AutoAllowTags(Scanner &scanner)
77.105 + : scanner_(scanner),
77.106 + prev_(scanner_.tagsEnabled())
77.107 + {
77.108 + scanner_.setTagsEnabled(Enabled);
77.109 + }
77.110 + ~AutoAllowTags()
77.111 + {
77.112 + scanner_.setTagsEnabled(prev_);
77.113 + }
77.114 +};
77.115 +
77.116 +} // namespace ke
77.117 +
77.118 +#endif // _include_jitcraft_scanner_h_
78.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
78.2 +++ b/src/compiler/Scopes.cpp Sat Nov 17 18:41:01 2012 -0800
78.3 @@ -0,0 +1,225 @@
78.4 +/* vim: set ts=4 sw=4 tw=99 et:
78.5 + *
78.6 + * Copyright (C) 2012 David Anderson
78.7 + *
78.8 + * This file is part of JITCraft.
78.9 + *
78.10 + * JITCraft is free software: you can redistribute it and/or modify it under
78.11 + * the terms of the GNU General Public License as published by the Free
78.12 + * Software Foundation, either version 3 of the License, or (at your option)
78.13 + * any later version.
78.14 + *
78.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
78.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
78.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
78.18 + *
78.19 + * You should have received a copy of the GNU General Public License along with
78.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
78.21 + */
78.22 +#include "../Zone.h"
78.23 +#include "../Types.h"
78.24 +#include "../TypeManager.h"
78.25 +#include "../Strings.h"
78.26 +#include "../Environments.h"
78.27 +#include "../Structures.h"
78.28 +#include "CompileContext.h"
78.29 +#include "Scopes.h"
78.30 +#include "../Spaces-inl.h"
78.31 +#include "../Heap-inl.h"
78.32 +
78.33 +using namespace ke;
78.34 +
78.35 +Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
78.36 + : pool_(pool),
78.37 + kind_(kind),
78.38 + enclosing_(enclosing)
78.39 +{
78.40 +}
78.41 +
78.42 +bool
78.43 +Scope::initialize()
78.44 +{
78.45 + if (enclosing_ && !enclosing_->children_.append(this))
78.46 + return false;
78.47 + return true;
78.48 +}
78.49 +
78.50 +void
78.51 +Scope::unlink()
78.52 +{
78.53 + assert(empty());
78.54 +
78.55 + assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
78.56 + enclosing_->children_.pop();
78.57 +
78.58 + // OOM here is swallowed and checked after compilation.
78.59 + // :TODO: make the above true.
78.60 + for (size_t i = 0; i < children_.length(); i++)
78.61 + enclosing_->children_.append(children_[i]);
78.62 +}
78.63 +
78.64 +Scope *
78.65 +Scope::unlinkIfEmpty()
78.66 +{
78.67 + if (empty()) {
78.68 + unlink();
78.69 + return NULL;
78.70 + }
78.71 + return this;
78.72 +}
78.73 +
78.74 +Symbol *
78.75 +Scope::localLookup(Handle<String> name)
78.76 +{
78.77 + for (size_t i = 0; i < names_.length(); i++) {
78.78 + if (names_[i]->name() == name)
78.79 + return names_[i];
78.80 + }
78.81 + return NULL;
78.82 +}
78.83 +
78.84 +Symbol *
78.85 +Scope::lookup(Handle<String> name)
78.86 +{
78.87 + for (Scope *scope = this; scope; scope = scope->enclosing()) {
78.88 + if (Symbol *bound = scope->localLookup(name))
78.89 + return bound;
78.90 + }
78.91 + return NULL;
78.92 +}
78.93 +
78.94 +#if 0
78.95 +void
78.96 +Scope::setUsesLifoHeap()
78.97 +{
78.98 + // Only one lifo slot is needed per scope.
78.99 +#if 0
78.100 + if (lifoSlot_)
78.101 + return;
78.102 +#endif
78.103 +
78.104 + // If the parent of this scope is the function scope, then this is the
78.105 + // function's block scope, and the lifo slot is part of the Frame instead.
78.106 + // Note we can get a function scope here if we're making a temporary in a
78.107 + // function with no local variables.
78.108 + if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
78.109 + return;
78.110 +
78.111 + Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
78.112 + if (!type)
78.113 + return;
78.114 +
78.115 + Local<String> name(ZONE());
78.116 +#if 0
78.117 + lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
78.118 + lifoSlot_->setType(type);
78.119 +#endif
78.120 +}
78.121 +#endif
78.122 +
78.123 +bool
78.124 +Scope::addSymbol(Symbol *sym)
78.125 +{
78.126 + return names_.append(sym);
78.127 +}
78.128 +
78.129 +LocalScope::LocalScope(PoolAllocator &pool)
78.130 + : Scope(pool, Scope::BLOCK, NULL)
78.131 +{
78.132 +}
78.133 +
78.134 +LocalScope *
78.135 +LocalScope::New(PoolAllocator &pool)
78.136 +{
78.137 + LocalScope *scope = new (pool) LocalScope(pool);
78.138 + if (!scope->initialize())
78.139 + return NULL;
78.140 +
78.141 + return scope;
78.142 +}
78.143 +
78.144 +ArgumentScope::ArgumentScope(PoolAllocator &pool)
78.145 + : Scope(pool, Scope::FUNCTION, NULL)
78.146 +{
78.147 +}
78.148 +
78.149 +ArgumentScope *
78.150 +ArgumentScope::New(PoolAllocator &pool)
78.151 +{
78.152 + ArgumentScope *scope = new (pool) ArgumentScope(pool);
78.153 + if (!scope->initialize())
78.154 + return NULL;
78.155 +
78.156 + return scope;
78.157 +}
78.158 +
78.159 +GlobalScope::GlobalScope(PoolAllocator &pool, ImportScope *parent)
78.160 + : Scope(pool, Scope::GLOBAL, parent)
78.161 +{
78.162 +}
78.163 +
78.164 +GlobalScope *
78.165 +GlobalScope::New(PoolAllocator &pool, ImportScope *parent)
78.166 +{
78.167 + GlobalScope *scope = new (pool) GlobalScope(pool, parent);
78.168 + if (!scope->initialize())
78.169 + return NULL;
78.170 +
78.171 + return scope;
78.172 +}
78.173 +
78.174 +bool
78.175 +GlobalScope::addPublic(Symbol *sym)
78.176 +{
78.177 + return publics_.append(sym);
78.178 +}
78.179 +
78.180 +Symbol *
78.181 +GlobalScope::findPublic(Handle<String> name)
78.182 +{
78.183 + for (size_t i = 0; i < publics_.length(); i++) {
78.184 + if (publics_[i]->name() == name)
78.185 + return publics_[i];
78.186 + }
78.187 + return NULL;
78.188 +}
78.189 +
78.190 +Struct *
78.191 +GlobalScope::build(Zone *zone)
78.192 +{
78.193 + Local<FixedArray> descriptors(zone, FixedArray::New(zone, names_.length(), Heap::Tenure_Old));
78.194 +
78.195 + for (size_t i = 0; i < names_.length(); i++) {
78.196 + Handle<String> name = names_[i]->name();
78.197 + Handle<Type> type = names_[i]->type();
78.198 + assert(type);
78.199 +
78.200 + Local<Descriptor> desc(zone, Descriptor::New(zone, name, type));
78.201 + if (!desc)
78.202 + return NULL;
78.203 +
78.204 + descriptors->set(zone, i, desc);
78.205 + }
78.206 +
78.207 + Local<StructType> type(zone, StructType::New(zone, Handle<String>::Null(), descriptors));
78.208 + if (!type)
78.209 + return NULL;
78.210 +
78.211 + Local<StructMap> map(zone, type->newMap());
78.212 + return Struct::New(zone, map, Heap::Tenure_Old);
78.213 +}
78.214 +
78.215 +ImportScope::ImportScope(PoolAllocator &pool)
78.216 + : Scope(pool, Scope::IMPORT, NULL)
78.217 +{
78.218 +}
78.219 +
78.220 +ImportScope *
78.221 +ImportScope::New(PoolAllocator &pool)
78.222 +{
78.223 + ImportScope *scope = new (pool) ImportScope(pool);
78.224 + if (!scope->initialize())
78.225 + return NULL;
78.226 +
78.227 + return scope;
78.228 +}
79.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
79.2 +++ b/src/compiler/Scopes.h Sat Nov 17 18:41:01 2012 -0800
79.3 @@ -0,0 +1,126 @@
79.4 +/*
79.5 + * Copyright (C) 2012 David Anderson
79.6 + *
79.7 + * This file is part of JITCraft.
79.8 + *
79.9 + * JITCraft is free software: you can redistribute it and/or modify it under
79.10 + * the terms of the GNU General Public License as published by the Free
79.11 + * Software Foundation, either version 3 of the License, or (at your option)
79.12 + * any later version.
79.13 + *
79.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
79.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
79.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
79.17 + *
79.18 + * You should have received a copy of the GNU General Public License along with
79.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
79.20 + */
79.21 +#ifndef _include_jitcraft_scopes_h_
79.22 +#define _include_jitcraft_scopes_h_
79.23 +
79.24 +#include "../PoolAllocator.h"
79.25 +#include "../Structures.h"
79.26 +#include "AST.h"
79.27 +#include "NameBinding.h"
79.28 +
79.29 +namespace ke {
79.30 +
79.31 +class CompileContext;
79.32 +class EnvironmentMap;
79.33 +class Struct;
79.34 +
79.35 +class Scope : public PoolObject
79.36 +{
79.37 + protected:
79.38 + PoolAllocator &pool_;
79.39 + PoolList<Symbol *> names_;
79.40 + PoolList<Scope *> children_;
79.41 +
79.42 + bool empty() const {
79.43 + return names_.length() == 0;
79.44 + }
79.45 + void unlink();
79.46 +
79.47 + public:
79.48 + enum Kind {
79.49 + IMPORT,
79.50 + GLOBAL,
79.51 + FUNCTION,
79.52 + BLOCK
79.53 + };
79.54 +
79.55 + public:
79.56 + Scope(PoolAllocator &pool, Kind kind, Scope *enclosing);
79.57 + bool initialize();
79.58 +
79.59 + Kind kind() const {
79.60 + return kind_;
79.61 + }
79.62 + Scope *enclosing() const {
79.63 + return enclosing_;
79.64 + }
79.65 +
79.66 + bool addSymbol(Symbol *symbol);
79.67 +
79.68 + Scope *unlinkIfEmpty();
79.69 + Symbol *localLookup(Handle<String> name);
79.70 + Symbol *lookup(Handle<String> name);
79.71 +
79.72 + EnvironmentMap *createEnvironmentMap(Zone *zone);
79.73 +
79.74 + void setParent(Scope *parent) {
79.75 + assert(!enclosing_ || enclosing_ == parent);
79.76 + enclosing_ = parent;
79.77 + }
79.78 +
79.79 + private:
79.80 + Kind kind_;
79.81 + Scope *enclosing_;
79.82 +};
79.83 +
79.84 +class ArgumentScope : public Scope
79.85 +{
79.86 + public:
79.87 + static ArgumentScope *New(PoolAllocator &pool);
79.88 +
79.89 + private:
79.90 + ArgumentScope(PoolAllocator &pool);
79.91 +};
79.92 +
79.93 +class LocalScope : public Scope
79.94 +{
79.95 + public:
79.96 + static LocalScope *New(PoolAllocator &pool);
79.97 +
79.98 + private:
79.99 + LocalScope(PoolAllocator &pool);
79.100 +};
79.101 +
79.102 +class GlobalScope : public Scope
79.103 +{
79.104 + public:
79.105 + static GlobalScope *New(PoolAllocator &pool, ImportScope *parent);
79.106 +
79.107 + bool addPublic(Symbol *symbol);
79.108 + Symbol *findPublic(Handle<String> name);
79.109 + Struct *build(Zone *zone);
79.110 +
79.111 + private:
79.112 + GlobalScope(PoolAllocator &pool, ImportScope *parent);
79.113 +
79.114 + private:
79.115 + PoolList<Symbol *> publics_;
79.116 +};
79.117 +
79.118 +class ImportScope : public Scope
79.119 +{
79.120 + public:
79.121 + static ImportScope *New(PoolAllocator &pool);
79.122 +
79.123 + private:
79.124 + ImportScope(PoolAllocator &pool);
79.125 +};
79.126 +
79.127 +}
79.128 +
79.129 +#endif // _include_jitcraft_scopes_h_
80.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
80.2 +++ b/src/compiler/SemanticAnalysis.cpp Sat Nov 17 18:41:01 2012 -0800
80.3 @@ -0,0 +1,624 @@
80.4 +/* vim: set ts=4 sw=4 tw=99 et:
80.5 + *
80.6 + * Copyright (C) 2012 David Anderson
80.7 + *
80.8 + * This file is part of SourcePawn.
80.9 + *
80.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
80.11 + * the terms of the GNU General Public License as published by the Free
80.12 + * Software Foundation, either version 3 of the License, or (at your option)
80.13 + * any later version.
80.14 + *
80.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
80.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
80.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
80.18 + *
80.19 + * You should have received a copy of the GNU General Public License along with
80.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
80.21 + */
80.22 +#include <assert.h>
80.23 +#include "../Zone.h"
80.24 +#include "../Strings.h"
80.25 +#include "../NativeTable.h"
80.26 +#include "../TypeManager.h"
80.27 +#include "../Modules.h"
80.28 +#include "../Code.h"
80.29 +#include "SemanticAnalysis.h"
80.30 +
80.31 +using namespace ke;
80.32 +
80.33 +#define __ emitter_.
80.34 +
80.35 +typedef BytecodeEmitter::Label Label;
80.36 +
80.37 +class AutoEnterScope
80.38 +{
80.39 + public:
80.40 + AutoEnterScope(Scope **prevp, Scope *scope)
80.41 + : prevp_(prevp),
80.42 + prev_(*prevp),
80.43 + scope_(scope)
80.44 + {
80.45 + if (!scope_)
80.46 + return;
80.47 + prev_ = *prevp_;
80.48 + *prevp_ = scope;
80.49 + assert(prev_ == scope->enclosing());
80.50 + }
80.51 + ~AutoEnterScope()
80.52 + {
80.53 + if (scope_)
80.54 + *prevp_ = prev_;
80.55 + }
80.56 + private:
80.57 + Scope **prevp_;
80.58 + Scope *prev_;
80.59 + Scope *scope_;
80.60 +};
80.61 +
80.62 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit)
80.63 + : zone_(zone),
80.64 + pool_(zone->pool()),
80.65 + cc_(cc),
80.66 + unit_(unit),
80.67 + hir_(NULL),
80.68 + emitter_(pool_),
80.69 + module_(NULL),
80.70 + loop_(NULL)
80.71 +{
80.72 +}
80.73 +
80.74 +SemanticAnalysis::SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun)
80.75 + : zone_(parent->zone_),
80.76 + pool_(parent->pool_),
80.77 + cc_(parent->cc_),
80.78 + unit_(parent->unit_),
80.79 + hir_(NULL),
80.80 + scope_(parent->scope_),
80.81 + emitter_(pool_),
80.82 + module_(parent->module_),
80.83 + fun_(fun),
80.84 + loop_(NULL)
80.85 +{
80.86 +
80.87 +}
80.88 +
80.89 +void
80.90 +SemanticAnalysis::analyze()
80.91 +{
80.92 + scope_ = unit_->globalScope();
80.93 +
80.94 + module_ = Module::New(zone_);
80.95 +
80.96 + for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
80.97 + Statement *stmt = unit_->tree()->statements()->at(i);
80.98 + stmt->accept(this);
80.99 + }
80.100 +
80.101 + Local<Struct> globals(zone_, unit_->globalScope()->build(zone_));
80.102 + if (!globals)
80.103 + return;
80.104 + module_->setGlobals(globals);
80.105 +
80.106 + Local<Code> code(zone_, __ finish());
80.107 + if (!code)
80.108 + return;
80.109 + code->setModule(module_);
80.110 + module_->setCode(code);
80.111 +
80.112 +#ifndef NDEBUG
80.113 +// Disassemble(code, stdout);
80.114 +#endif
80.115 +
80.116 + unit_->module_ = module_;
80.117 +}
80.118 +
80.119 +void
80.120 +SemanticAnalysis::visitFunctionStatement(FunctionStatement *stmt)
80.121 +{
80.122 + FunctionSymbol *sym = stmt->sym();
80.123 + Local<FunctionType> type(zone_, sym->type());
80.124 +
80.125 + assert(scope_->kind() == Scope::GLOBAL);
80.126 +
80.127 + if (stmt->token() == TOK_NATIVE) {
80.128 + // Define the native now.
80.129 + size_t index;
80.130 + if (!zone_->nativeTable()->add(stmt->name(), &index))
80.131 + return;
80.132 +
80.133 + Local<Native> native(zone_, Native::New(zone_, type, index));
80.134 + if (!native)
80.135 + return;
80.136 +
80.137 + __ object(native);
80.138 + __ setglobal(sym);
80.139 + __ pop();
80.140 + }
80.141 +
80.142 + // If the function is a forward or native, we don't have to do anything.
80.143 + if (stmt->token() == TOK_NATIVE || stmt->token() == TOK_FORWARD)
80.144 + return;
80.145 +
80.146 + SemanticAnalysis child(this, type);
80.147 + Local<Function> funobj(zone_, child.compile(stmt));
80.148 + if (!funobj)
80.149 + return;
80.150 +
80.151 + __ object(funobj);
80.152 + __ setglobal(sym);
80.153 + __ public_();
80.154 +}
80.155 +
80.156 +Function *
80.157 +SemanticAnalysis::compile(FunctionStatement *stmt)
80.158 +{
80.159 + __ setFirstLine(stmt->pos().line);
80.160 +
80.161 + AutoEnterScope argScope(&scope_, stmt->argScope());
80.162 + AutoEnterScope varScope(&scope_, stmt->varScope());
80.163 +
80.164 + stmt->body()->accept(this);
80.165 +
80.166 + Local<Code> code(zone_, __ finish());
80.167 + if (!code)
80.168 + return NULL;
80.169 + code->setModule(module_);
80.170 +
80.171 + Local<Function> fun(zone_, Function::New(zone_, code, fun_, stmt->name(), stmt->pos()));
80.172 + if (!fun)
80.173 + return NULL;
80.174 +
80.175 +#ifndef NDEBUG
80.176 +// Disassemble(code, stdout);
80.177 +#endif
80.178 +
80.179 + return fun;
80.180 +}
80.181 +
80.182 +void
80.183 +SemanticAnalysis::visitBlockStatement(BlockStatement *node)
80.184 +{
80.185 + AutoEnterScope scope(&scope_, node->scope());
80.186 +
80.187 + for (size_t i = 0; i < node->statements()->length(); i++) {
80.188 + Statement *stmt = node->statements()->at(i);
80.189 + stmt->accept(this);
80.190 + assert(__ stackDepth() == 0);
80.191 + }
80.192 +}
80.193 +
80.194 +void
80.195 +SemanticAnalysis::visitExpressionStatement(ExpressionStatement *node)
80.196 +{
80.197 + // While building HIR, we enter new pool and root scopes, since HIR
80.198 + // creation is purely temporary.
80.199 + PoolScope poolScope(zone_->pool());
80.200 + RootScope rootScope(zone_);
80.201 +
80.202 + HIR *hir = eval(node->expression());
80.203 + if (!hir)
80.204 + return;
80.205 +
80.206 + discharge(hir);
80.207 + __ pop();
80.208 +}
80.209 +
80.210 +void
80.211 +SemanticAnalysis::visitForStatement(ForStatement *node)
80.212 +{
80.213 + AutoEnterScope scope(&scope_, node->scope());
80.214 + PoolScope poolScope(zone_->pool());
80.215 + RootScope rootScope(zone_);
80.216 +
80.217 + Label join, update;
80.218 + LoopScope loop(scope_, &join, &update, &loop_);
80.219 +
80.220 + if (node->initialization())
80.221 + node->initialization()->accept(this);
80.222 +
80.223 + Label header, test;
80.224 + if (node->condition())
80.225 + __ jump(&test);
80.226 +
80.227 + __ bind(&header);
80.228 + node->body()->accept(this);
80.229 +
80.230 + __ bind(&update);
80.231 + if (node->update())
80.232 + node->update()->accept(this);
80.233 +
80.234 + if (node->condition()) {
80.235 + __ bind(&test);
80.236 + visitForTest(node->condition(), &header, &join, &join);
80.237 + } else {
80.238 + __ jump(&header);
80.239 + }
80.240 +
80.241 + __ bind(&join);
80.242 +
80.243 + assert(__ stackDepth() == 0);
80.244 +}
80.245 +
80.246 +void
80.247 +SemanticAnalysis::visitVariableDeclaration(VariableDeclaration *node)
80.248 +{
80.249 + PoolScope poolScope(zone_->pool());
80.250 + RootScope rootScope(zone_);
80.251 +
80.252 + HIR *hir;
80.253 + if (node->initialization()) {
80.254 + if ((hir = eval(node->initialization())) == NULL)
80.255 + return;
80.256 + if ((hir = coerce(hir, node->sym()->type(), Coerce_Assign)) == NULL)
80.257 + return;
80.258 + } else {
80.259 + assert(false);
80.260 + }
80.261 +
80.262 + discharge(hir);
80.263 +
80.264 + if (!__ allocate(node->sym()))
80.265 + return;
80.266 +
80.267 + set(node->sym());
80.268 + __ pop();
80.269 +}
80.270 +
80.271 +void
80.272 +SemanticAnalysis::visitReturnStatement(ReturnStatement *node)
80.273 +{
80.274 + if (!node->expression()) {
80.275 + if (!fun_->returnType()->isVoid()) {
80.276 + cc_.reportError(node->pos(), Message_UsedVoidReturn);
80.277 + return;
80.278 + }
80.279 +
80.280 + __ returnvoid();
80.281 + return;
80.282 + }
80.283 +
80.284 + PoolScope poolScope(zone_->pool());
80.285 + RootScope rootScope(zone_);
80.286 +
80.287 + HIR *hir = eval(node->expression());
80.288 + if (!hir)
80.289 + return;
80.290 +
80.291 + Local<Type> returnType(zone_, fun_->returnType());
80.292 + if ((hir = coerce(hir, returnType, Coerce_Return)) == NULL)
80.293 + return;
80.294 +
80.295 + discharge(hir);
80.296 + __ return_();
80.297 +}
80.298 +
80.299 +void
80.300 +SemanticAnalysis::visitBinaryExpression(BinaryExpression *node)
80.301 +{
80.302 + HIR *left = eval(node->left());
80.303 + HIR *right = eval(node->right());
80.304 + if (!left || !right)
80.305 + return;
80.306 +
80.307 + hir_ = binary(node->token(), left, right);
80.308 +}
80.309 +
80.310 +bool
80.311 +SemanticAnalysis::checkArgumentCount(Handle<FunctionType> type, unsigned actual)
80.312 +{
80.313 + if (type->parameters()->length() == actual)
80.314 + return true;
80.315 +
80.316 + if (actual > type->parameters()->length()) {
80.317 + if (!type->isNative() || !type->isNativeVariadic())
80.318 + return false;
80.319 + return true;
80.320 + }
80.321 +
80.322 + if (!type->defaults())
80.323 + return false;
80.324 +
80.325 + // Missing arguments. See if there's a default argument for each missing
80.326 + // actual.
80.327 + for (unsigned i = actual; i < type->parameters()->length(); i++) {
80.328 + if (!type->defaults()->at(i))
80.329 + return false;
80.330 + }
80.331 +
80.332 + return true;
80.333 +}
80.334 +
80.335 +void
80.336 +SemanticAnalysis::visitNameProxy(NameProxy *proxy)
80.337 +{
80.338 + Symbol *sym = proxy->sym();
80.339 + Handle<Type> type = sym->type();
80.340 +
80.341 + VariableSymbol *var = sym->asVariable();
80.342 +
80.343 + Scope *in = sym->scope();
80.344 + switch (in->kind()) {
80.345 + case Scope::GLOBAL:
80.346 + hir_ = new (pool_) HGlobal(sym);
80.347 + return;
80.348 +
80.349 + default:
80.350 + assert(in->kind() == Scope::BLOCK);
80.351 + assert(var->storage() == VariableSymbol::Local);
80.352 + hir_ = new (pool_) HLocal(var);
80.353 + return;
80.354 + }
80.355 +}
80.356 +
80.357 +void
80.358 +SemanticAnalysis::visitIntegerLiteral(IntegerLiteral *lit)
80.359 +{
80.360 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
80.361 + hir_ = new (pool_) HInteger(type, lit->value());
80.362 +}
80.363 +
80.364 +void
80.365 +SemanticAnalysis::visitFloatLiteral(FloatLiteral *node)
80.366 +{
80.367 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
80.368 + hir_ = new (pool_) HFloat(type, (float)node->value());
80.369 +}
80.370 +
80.371 +void
80.372 +SemanticAnalysis::visitCallExpression(CallExpression *node)
80.373 +{
80.374 + HIR *callee = eval(node->callee());
80.375 + if (!callee)
80.376 + return;
80.377 +
80.378 + if (!callee->type()->isFunction()) {
80.379 + cc_.reportError(node->pos(), Message_CalleeNotFunction);
80.380 + return;
80.381 + }
80.382 +
80.383 + Local<FunctionType> fun(zone_, FunctionType::cast(callee->type()));
80.384 +
80.385 + if (!checkArgumentCount(fun, node->arguments()->length())) {
80.386 + cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
80.387 + return;
80.388 + }
80.389 +
80.390 + if (fun->isForward()) {
80.391 + cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
80.392 + return;
80.393 + }
80.394 +
80.395 + HIRList *args = new (pool_) HIRList;
80.396 + for (unsigned i = 0; i < node->arguments()->length(); i++) {
80.397 + Expression *expression = node->arguments()->at(i);
80.398 + HIR *arg = eval(expression);
80.399 + if (!arg)
80.400 + return;
80.401 +
80.402 + Handle<Type> given = arg->type();
80.403 +
80.404 + bool mustComputeReference;
80.405 + if (i >= fun->parameters()->length()) {
80.406 + // Special handling for natives. Arguments past the formal must
80.407 + // always have references computed. However, arrays are already
80.408 + // references for natives.
80.409 + assert(fun->isNative() && fun->isNativeVariadic());
80.410 + mustComputeReference = !given->isReference() &&
80.411 + !given->isArray();
80.412 + } else {
80.413 + Local<Type> actual(zone_, fun->parameterAt(i));
80.414 +
80.415 + if (expression->isIndexExpression()) {
80.416 + // Temporarily disabled.
80.417 + assert(!actual->isArray());
80.418 + if (actual->isReference()) {
80.419 + cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
80.420 + return;
80.421 + }
80.422 + }
80.423 +
80.424 + // When we start overloading, coercion will have to happen later.
80.425 + arg = coerce(arg, actual, Coerce_Arg);
80.426 + if (!arg)
80.427 + return;
80.428 +
80.429 + mustComputeReference = actual->isReference() && !given->isReference();
80.430 + }
80.431 +
80.432 + // :TODO: handle mustComputeReference
80.433 + assert(!mustComputeReference);
80.434 +
80.435 + if (!args->append(arg))
80.436 + return;
80.437 + }
80.438 +
80.439 + hir_ = new (pool_) HCall(fun->returnType(), callee, args);
80.440 +}
80.441 +
80.442 +void
80.443 +SemanticAnalysis::visitAssignment(Assignment *node)
80.444 +{
80.445 + HLValue *lval = lvalue(node->lvalue());
80.446 + if (!lval)
80.447 + return;
80.448 +
80.449 + HIR *hir = eval(node->expression());
80.450 + if ((hir = coerce(hir, lval->type(), Coerce_Assign)) == NULL)
80.451 + return;
80.452 +
80.453 + hir_ = new (pool_) HStore(lval, hir);
80.454 +}
80.455 +
80.456 +Type *
80.457 +SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right)
80.458 +{
80.459 + Handle<Type> l = left->type();
80.460 + Handle<Type> r = right->type();
80.461 +
80.462 + if (token >= TOK_PLUS && token <= TOK_SLASH) {
80.463 + // We allow: [float|int32] + [float|int32]
80.464 + if (l->isFloat() && r->isInt32())
80.465 + return l;
80.466 + if (l->isInt32() && r->isFloat())
80.467 + return r;
80.468 + if (l->isInt32() && r->isInt32())
80.469 + return l;
80.470 + }
80.471 +
80.472 + assert(l == r);
80.473 +
80.474 + return left->type();
80.475 +}
80.476 +
80.477 +HIR *
80.478 +SemanticAnalysis::coerce(HIR *hir, Handle<Type> to, CoercionKind kind)
80.479 +{
80.480 + Handle<Type> from = hir->type();
80.481 +
80.482 + if (from->isInt32() && to->isFloat())
80.483 + return new (pool_) HConvert(to, OP_CVT_I2F, hir);
80.484 +
80.485 + assert(from == to);
80.486 +
80.487 + return hir;
80.488 +}
80.489 +
80.490 +void
80.491 +SemanticAnalysis::set(VariableSymbol *sym)
80.492 +{
80.493 + if (sym->scope()->kind() == Scope::GLOBAL) {
80.494 + __ setglobal(sym);
80.495 + } else {
80.496 + assert(sym->storage() == VariableSymbol::Local);
80.497 + __ setlocal(sym);
80.498 + }
80.499 +}
80.500 +
80.501 +HIR *
80.502 +SemanticAnalysis::binary(TokenKind token, HIR *left, HIR *right)
80.503 +{
80.504 + Local<Type> coercion(zone_, coercionType(token, left, right));
80.505 + if (!coercion)
80.506 + return NULL;
80.507 + if ((left = coerce(left, coercion, Coerce_Arg)) == NULL)
80.508 + return NULL;
80.509 + if ((right = coerce(right, coercion, Coerce_Arg)) == NULL)
80.510 + return NULL;
80.511 +
80.512 + switch (token) {
80.513 + case TOK_PLUS:
80.514 + case TOK_MINUS:
80.515 + case TOK_STAR:
80.516 + case TOK_SLASH:
80.517 + case TOK_PERCENT:
80.518 + case TOK_AMPERSAND:
80.519 + case TOK_BITOR:
80.520 + case TOK_BITXOR:
80.521 + case TOK_SHR:
80.522 + case TOK_USHR:
80.523 + case TOK_SHL:
80.524 + return new (pool_) HBinary(left->type(), token, left, right);
80.525 +
80.526 + case TOK_EQUALS:
80.527 + case TOK_NOTEQUALS:
80.528 + case TOK_LT:
80.529 + case TOK_LE:
80.530 + case TOK_GT:
80.531 + case TOK_GE:
80.532 + case TOK_AND:
80.533 + case TOK_OR:
80.534 + {
80.535 + Local<Type> result(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
80.536 + return new (pool_) HBinary(result, token, left, right);
80.537 + }
80.538 +
80.539 + default:
80.540 + assert(false);
80.541 + return NULL;
80.542 + }
80.543 +}
80.544 +
80.545 +static inline TokenKind
80.546 +ToCompare(Expression *expr)
80.547 +{
80.548 + if (expr->isBinaryExpression()) {
80.549 + BinaryExpression *b = expr->toBinaryExpression();
80.550 + if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
80.551 + return b->token();
80.552 + } else if (expr->isUnaryExpression()) {
80.553 + UnaryExpression *u = expr->toUnaryExpression();
80.554 + if (u->token() == TOK_NOT)
80.555 + return TOK_NOT;
80.556 + }
80.557 + return TOK_EOF;
80.558 +}
80.559 +
80.560 +void
80.561 +SemanticAnalysis::visitForTest(Expression *expr,
80.562 + Label *trueBranch,
80.563 + Label *falseBranch,
80.564 + Label *fallthrough)
80.565 +{
80.566 + TokenKind token = ToCompare(expr);
80.567 + if (token == TOK_EOF || token == TOK_NOT) {
80.568 + assert(false);
80.569 + //visitForUnaryTest(expr, trueBranch, falseBranch, fallthrough);
80.570 + return;
80.571 + }
80.572 +
80.573 + BinaryExpression *bin = expr->toBinaryExpression();
80.574 + if (token == TOK_AND || token == TOK_OR) {
80.575 + assert(false);
80.576 + //visitForLogicTest(expr, trueBranch, falseBranch, fallthrough);
80.577 + return;
80.578 + }
80.579 +
80.580 + HIR *left = eval(bin->left());
80.581 + HIR *right = eval(bin->right());
80.582 + if (!left || !right)
80.583 + return;
80.584 +
80.585 + HIR *hir = binary(bin->token(), left, right);
80.586 + if (!hir)
80.587 + return;
80.588 +
80.589 + discharge(hir);
80.590 + if (fallthrough == trueBranch)
80.591 + __ j(OP_JF, falseBranch);
80.592 + else
80.593 + __ j(OP_JT, trueBranch);
80.594 +}
80.595 +
80.596 +HLValue *
80.597 +SemanticAnalysis::lvalue(Expression *expr)
80.598 +{
80.599 + HIR *hir = eval(expr);
80.600 + if (!hir)
80.601 + return NULL;
80.602 +
80.603 + if (!hir->isLValue()) {
80.604 + cc_.reportError(expr->pos(), Message_ExpectedLValue);
80.605 + return NULL;
80.606 + }
80.607 +
80.608 + return static_cast<HLValue *>(hir);
80.609 +}
80.610 +
80.611 +HIR *
80.612 +SemanticAnalysis::eval(Expression *expr)
80.613 +{
80.614 + assert(!hir_);
80.615 + expr->accept(this);
80.616 +
80.617 + HIR *hir = hir_;
80.618 + hir_ = NULL;
80.619 +
80.620 + return hir;
80.621 +}
80.622 +
80.623 +void
80.624 +SemanticAnalysis::discharge(HIR *hir)
80.625 +{
80.626 + EmitHIR(zone_, emitter_, hir);
80.627 +}
81.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
81.2 +++ b/src/compiler/SemanticAnalysis.h Sat Nov 17 18:41:01 2012 -0800
81.3 @@ -0,0 +1,159 @@
81.4 +/*
81.5 + * Copyright (C) 2012 David Anderson
81.6 + *
81.7 + * This file is part of SourcePawn.
81.8 + *
81.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
81.10 + * the terms of the GNU General Public License as published by the Free
81.11 + * Software Foundation, either version 3 of the License, or (at your option)
81.12 + * any later version.
81.13 + *
81.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
81.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
81.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
81.17 + *
81.18 + * You should have received a copy of the GNU General Public License along with
81.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
81.20 + */
81.21 +#ifndef _include_sp2_sema_h_
81.22 +#define _include_sp2_sema_h_
81.23 +
81.24 +#include "AST.h"
81.25 +#include "HIR.h"
81.26 +#include "Scopes.h"
81.27 +#include "BytecodeEmitter.h"
81.28 +
81.29 +namespace ke {
81.30 +
81.31 +// Semantic analysis occurs after all names and types have been bound. It
81.32 +// performs the important task of validating the semantics and type safety
81.33 +// of a parse tree.
81.34 +//
81.35 +// The semantic analysis phase also produces bytecode. This occurs on a
81.36 +// statement-by-statement basis. The result of analyzing an expression is a
81.37 +// tree of operations which is then flattened.
81.38 +class SemanticAnalysis : public AstVisitor
81.39 +{
81.40 + public:
81.41 + SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit);
81.42 +
81.43 + void analyze();
81.44 +
81.45 + private:
81.46 + SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun);
81.47 + Function *compile(FunctionStatement *stmt);
81.48 +
81.49 + public:
81.50 + void visitFunctionStatement(FunctionStatement *node);
81.51 + void visitBlockStatement(BlockStatement *node);
81.52 + void visitExpressionStatement(ExpressionStatement *node);
81.53 + void visitReturnStatement(ReturnStatement *node);
81.54 +
81.55 + void visitCallExpression(CallExpression *node);
81.56 + void visitNameProxy(NameProxy *name);
81.57 + void visitIntegerLiteral(IntegerLiteral *node);
81.58 + void visitFloatLiteral(FloatLiteral *node);
81.59 + void visitVariableDeclaration(VariableDeclaration *node);
81.60 + void visitForStatement(ForStatement *node);
81.61 + void visitAssignment(Assignment *node);
81.62 + void visitBinaryExpression(BinaryExpression *node);
81.63 +#if 0
81.64 + void visitFunctionTypeStatement(FunctionTypeStatement *node);
81.65 + void visitImportStatement(ImportStatement *node);
81.66 + void visitExpressionStatement(ExpressionStatement *node);
81.67 + void visitEnumStatement(EnumStatement *node);
81.68 + void visitWhileStatement(WhileStatement *node);
81.69 + void visitBreakStatement(BreakStatement *node);
81.70 + void visitContinueStatement(ContinueStatement *node);
81.71 + void visitStructureStatement(StructureStatement *node);
81.72 + void visitSwitchStatement(SwitchStatement *node);
81.73 +
81.74 + void visitBinaryExpression(BinaryExpression *node);
81.75 + void visitCallExpression(CallExpression *node);
81.76 + void visitIfStatement(IfStatement *node);
81.77 + void visitIndexExpression(IndexExpression *node);
81.78 + void visitStringLiteral(StringLiteral *node);
81.79 + void visitIncDecExpression(IncDecExpression *node);
81.80 + void visitUnaryExpression(UnaryExpression *node);
81.81 + void visitTernaryExpression(TernaryExpression *node);
81.82 + void visitBooleanLiteral(BooleanLiteral *node);
81.83 + void visitFieldExpression(FieldExpression *node);
81.84 + void visitArrayLiteral(ArrayLiteral *node);
81.85 +#endif
81.86 +
81.87 + private:
81.88 + bool checkArgumentCount(Handle<FunctionType> type, unsigned actual);
81.89 +
81.90 + private:
81.91 + enum CoercionKind {
81.92 + Coerce_Arg,
81.93 + Coerce_Return,
81.94 + Coerce_Assign
81.95 + };
81.96 +
81.97 + void visitForTest(Expression *expr,
81.98 + BytecodeEmitter::Label *trueBranch,
81.99 + BytecodeEmitter::Label *falseBranch,
81.100 + BytecodeEmitter::Label *fallthrough);
81.101 + void set(VariableSymbol *sym);
81.102 + HIR *eval(Expression *expr);
81.103 + HIR *binary(TokenKind token, HIR *left, HIR *right);
81.104 + HIR *coerce(HIR *from, Handle<Type> to, CoercionKind kind);
81.105 + Type *coercionType(TokenKind token, HIR *left, HIR *right);
81.106 + HLValue *lvalue(Expression *expr);
81.107 + void discharge(HIR *hir);
81.108 +
81.109 + private:
81.110 + // Used to target break/catch statements.
81.111 + class LoopScope
81.112 + {
81.113 + Scope *scope_;
81.114 + BytecodeEmitter::Label *bk_;
81.115 + BytecodeEmitter::Label *ct_;
81.116 + LoopScope **prevp_;
81.117 + LoopScope *prev_;
81.118 +
81.119 + public:
81.120 + LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
81.121 + LoopScope **prevp)
81.122 + : scope_(scope),
81.123 + bk_(bk),
81.124 + ct_(ct),
81.125 + prevp_(prevp),
81.126 + prev_(*prevp)
81.127 + {
81.128 + *prevp_ = this;
81.129 + }
81.130 +
81.131 + ~LoopScope()
81.132 + {
81.133 + *prevp_ = prev_;
81.134 + }
81.135 +
81.136 + BytecodeEmitter::Label *break_() {
81.137 + return bk_;
81.138 + }
81.139 + BytecodeEmitter::Label *continue_() {
81.140 + return ct_;
81.141 + }
81.142 + Scope *scope() {
81.143 + return scope_;
81.144 + }
81.145 + };
81.146 +
81.147 + private:
81.148 + Zone *zone_;
81.149 + PoolAllocator &pool_;
81.150 + CompileContext &cc_;
81.151 + TranslationUnit *unit_;
81.152 + HIR *hir_;
81.153 + Scope *scope_;
81.154 + BytecodeEmitter emitter_;
81.155 + ScopedRoot<Module> module_;
81.156 + ScopedRoot<FunctionType> fun_;
81.157 + LoopScope *loop_;
81.158 +};
81.159 +
81.160 +} // namespace ke
81.161 +
81.162 +#endif // _include_sp2_sema_h_
82.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82.2 +++ b/src/compiler/Symbols.cpp Sat Nov 17 18:41:01 2012 -0800
82.3 @@ -0,0 +1,20 @@
82.4 +/* vim: set ts=4 sw=4 tw=99 et:
82.5 + *
82.6 + * Copyright (C) 2012 David Anderson
82.7 + *
82.8 + * This file is part of JITCraft.
82.9 + *
82.10 + * JITCraft is free software: you can redistribute it and/or modify it under
82.11 + * the terms of the GNU General Public License as published by the Free
82.12 + * Software Foundation, either version 3 of the License, or (at your option)
82.13 + * any later version.
82.14 + *
82.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
82.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
82.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
82.18 + *
82.19 + * You should have received a copy of the GNU General Public License along with
82.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
82.21 + */
82.22 +#include "Symbols.h"
82.23 +
83.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
83.2 +++ b/src/compiler/Symbols.h Sat Nov 17 18:41:01 2012 -0800
83.3 @@ -0,0 +1,188 @@
83.4 +/* vim: set ts=4 sw=4 tw=99 et:
83.5 + *
83.6 + * Copyright (C) 2012 David Anderson
83.7 + *
83.8 + * This file is part of SourcePawn.
83.9 + *
83.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
83.11 + * the terms of the GNU General Public License as published by the Free
83.12 + * Software Foundation, either version 3 of the License, or (at your option)
83.13 + * any later version.
83.14 + *
83.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
83.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
83.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
83.18 + *
83.19 + * You should have received a copy of the GNU General Public License along with
83.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
83.21 + */
83.22 +#ifndef _include_sp2_symbol_h_
83.23 +#define _include_sp2_symbol_h_
83.24 +
83.25 +#include "../PoolAllocator.h"
83.26 +#include "../Handles.h"
83.27 +#include "../Opcodes.h"
83.28 +#include "../Types.h"
83.29 +
83.30 +namespace ke {
83.31 +
83.32 +class String;
83.33 +
83.34 +#define SYMBOL_KINDS(_) \
83.35 + /* Any kind of variable or argument produces a VariableSymbol. */ \
83.36 + _(Variable) \
83.37 + /* A function declaration produces a FunctionSymbol. */ \
83.38 + _(Function) \
83.39 + /* A named constant produces a ConstantSymbol. */ \
83.40 + _(Constant) \
83.41 + /* A named type (class struct, typedef, etc) produces a TypeSymbol. */ \
83.42 + _(Type) \
83.43 + /* // A module import produces a ModuleSymbol. */ \
83.44 + _(Module)
83.45 +
83.46 +#define _(name) class name##Symbol;
83.47 +SYMBOL_KINDS(_)
83.48 +#undef _
83.49 +
83.50 +class Scope;
83.51 +
83.52 +// A symbol represents the declaration of a named entity.
83.53 +class Symbol : public PoolObject
83.54 +{
83.55 + public:
83.56 + enum Kind {
83.57 +# define _(name) k##name,
83.58 + SYMBOL_KINDS(_)
83.59 +# undef _
83.60 + kTotalSymbolKinds
83.61 + };
83.62 +
83.63 + public:
83.64 + Symbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
83.65 + : scope_(scope),
83.66 + name_(name),
83.67 + pos_(pos)
83.68 + {
83.69 + }
83.70 +
83.71 + virtual Kind kind() const = 0;
83.72 +
83.73 + Handle<String> name() const {
83.74 + return name_;
83.75 + }
83.76 + const SourcePosition &pos() const {
83.77 + return pos_;
83.78 + }
83.79 + Handle<Type> type() const {
83.80 + return type_;
83.81 + }
83.82 + Scope *scope() const {
83.83 + return scope_;
83.84 + }
83.85 +
83.86 + public:
83.87 +#define _(name) \
83.88 + bool is##name() const { \
83.89 + return (kind() == k##name); \
83.90 + } \
83.91 + name##Symbol *as##name() { \
83.92 + if (is##name()) \
83.93 + return to##name(); \
83.94 + return NULL; \
83.95 + } \
83.96 + name##Symbol *to##name() { \
83.97 + assert(is##name()); \
83.98 + return reinterpret_cast<name##Symbol *>(this); \
83.99 + }
83.100 + SYMBOL_KINDS(_)
83.101 +#undef _
83.102 +
83.103 + private:
83.104 + Scope *scope_;
83.105 + ScopedRoot<String> name_;
83.106 + SourcePosition pos_;
83.107 +
83.108 + protected:
83.109 + ScopedRoot<Type> type_;
83.110 +};
83.111 +
83.112 +class VariableSymbol : public Symbol
83.113 +{
83.114 + public:
83.115 + enum Storage {
83.116 + Unknown,
83.117 + Local,
83.118 + Heap
83.119 + };
83.120 +
83.121 + public:
83.122 + VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
83.123 + : Symbol(scope, name, pos),
83.124 + storage_(Unknown)
83.125 + {
83.126 + }
83.127 +
83.128 + VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type)
83.129 + : Symbol(scope, name, pos),
83.130 + storage_(Unknown)
83.131 + {
83.132 + type_ = type;
83.133 + }
83.134 +
83.135 + Kind kind() const {
83.136 + return kVariable;
83.137 + }
83.138 + void setType(Type *type) {
83.139 + type_ = type;
83.140 + }
83.141 + void allocate(Storage storage, unsigned slot) {
83.142 + storage_ = storage;
83.143 + slot_ = slot;
83.144 + }
83.145 + Storage storage() const {
83.146 + return storage_;
83.147 + }
83.148 + unsigned slot() const {
83.149 + assert(storage() != Unknown);
83.150 + return slot_;
83.151 + }
83.152 +
83.153 + private:
83.154 + Storage storage_;
83.155 + unsigned slot_;
83.156 +};
83.157 +
83.158 +class TypeSymbol : public Symbol
83.159 +{
83.160 + public:
83.161 + TypeSymbol(Scope *scope, Handle<String> name, Handle<Type> type)
83.162 + : Symbol(scope, name, SourcePosition())
83.163 + {
83.164 + type_ = type;
83.165 + }
83.166 +
83.167 + Kind kind() const {
83.168 + return kType;
83.169 + }
83.170 +};
83.171 +
83.172 +class FunctionSymbol : public Symbol
83.173 +{
83.174 + public:
83.175 + FunctionSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<FunctionType> type)
83.176 + : Symbol(scope, name, pos)
83.177 + {
83.178 + type_ = type;
83.179 + }
83.180 +
83.181 + Kind kind() const {
83.182 + return kFunction;
83.183 + }
83.184 + FunctionType *type() const {
83.185 + return FunctionType::cast(type_);
83.186 + }
83.187 +};
83.188 +
83.189 +}
83.190 +
83.191 +#endif // _include_sp2_symbol_h_
84.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
84.2 +++ b/src/compiler/Token.h Sat Nov 17 18:41:01 2012 -0800
84.3 @@ -0,0 +1,127 @@
84.4 +/* vim: set ts=4 sw=4 tw=99 et:
84.5 + *
84.6 + * Copyright (C) 2012 David Anderson
84.7 + *
84.8 + * This file is part of SourcePawn.
84.9 + *
84.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
84.11 + * the terms of the GNU General Public License as published by the Free
84.12 + * Software Foundation, either version 3 of the License, or (at your option)
84.13 + * any later version.
84.14 + *
84.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
84.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
84.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
84.18 + *
84.19 + * You should have received a copy of the GNU General Public License along with
84.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
84.21 + */
84.22 +#ifndef _include_jitcraft_token_h_
84.23 +#define _include_jitcraft_token_h_
84.24 +
84.25 +namespace ke {
84.26 +
84.27 +// List of tokens the scanner can recognize.
84.28 +//
84.29 +// Some restrictions:
84.30 +// * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
84.31 +// op-and-assign equivalent.
84.32 +#define TOKENMAP(_) \
84.33 + _(NONE, "<none>") \
84.34 + _(ERROR, "<error>") \
84.35 + _(NEW, "'new'") \
84.36 + _(FOR, "'for'") \
84.37 + _(RETURN, "'return'") \
84.38 + _(NAME, "<name>") \
84.39 + _(INTEGER_LITERAL, "<integer>") \
84.40 + _(HEX_LITERAL, "<hex>") \
84.41 + _(FLOAT_LITERAL, "<float>") \
84.42 + _(STRING_LITERAL, "<string>") \
84.43 + _(IF, "<if>") \
84.44 + _(ELSE, "<else>") \
84.45 + _(ENUM, "<enum>") \
84.46 + _(LABEL, "<label>") \
84.47 + _(WHILE, "<while>") \
84.48 + _(DO, "<do>") \
84.49 + _(BREAK, "<break>") \
84.50 + _(CONTINUE, "<continue>") \
84.51 + _(FORWARD, "<forward>") \
84.52 + _(PUBLIC, "<public>") \
84.53 + _(CONST, "<const>") \
84.54 + _(NATIVE, "<native>") \
84.55 + _(STOCK, "<stock>") \
84.56 + _(TRUE, "<true>") \
84.57 + _(FALSE, "<false>") \
84.58 + _(STRUCT, "<struct>") \
84.59 + _(SWITCH, "<switch>") \
84.60 + _(CASE, "<case>") \
84.61 + _(DEFAULT, "<default>") \
84.62 + _(TYPEDEF, "<typedef>") \
84.63 + _(VOID, "<void>") \
84.64 + _(INT, "<int>") \
84.65 + _(SIZEOF, "<sizeof>") \
84.66 + _(IMPORT, "<import>") \
84.67 + _(ELLIPSES, "...") \
84.68 + _(PLUS, "+") \
84.69 + _(MINUS, "-") \
84.70 + _(STAR, "*") \
84.71 + _(SLASH, "/") \
84.72 + _(PERCENT, "%") \
84.73 + _(AMPERSAND, "&") \
84.74 + _(BITOR, "|") \
84.75 + _(BITXOR, "^") \
84.76 + _(SHR, ">>") \
84.77 + _(USHR, ">>>") \
84.78 + _(SHL, "<<") \
84.79 + _(ASSIGN, "=") \
84.80 + _(SEMICOLON, ";") \
84.81 + _(LBRACE, "{") \
84.82 + _(RBRACE, "}") \
84.83 + _(LPAREN, "(") \
84.84 + _(RPAREN, ")") \
84.85 + _(LBRACKET, "[") \
84.86 + _(RBRACKET, "]") \
84.87 + _(ASSIGN_ADD, "+=") \
84.88 + _(ASSIGN_SUB, "-=") \
84.89 + _(ASSIGN_MUL, "*=") \
84.90 + _(ASSIGN_DIV, "/=") \
84.91 + _(ASSIGN_MOD, "%=") \
84.92 + _(ASSIGN_BITAND, "&=") \
84.93 + _(ASSIGN_BITOR, "|=") \
84.94 + _(ASSIGN_BITXOR, "^=") \
84.95 + _(ASSIGN_SHR, ">>=") \
84.96 + _(ASSIGN_USHR, ">>>=") \
84.97 + _(ASSIGN_SHL, "<<=") \
84.98 + _(INCREMENT, "++") \
84.99 + _(DECREMENT, "--") \
84.100 + _(EQUALS, "==") \
84.101 + _(NOTEQUALS, "!=") \
84.102 + _(LT, "<") \
84.103 + _(LE, "<=") \
84.104 + _(GT, ">") \
84.105 + _(GE, ">=") \
84.106 + _(AND, "&&") \
84.107 + _(OR, "||") \
84.108 + _(COMMA, ",") \
84.109 + _(NOT, "!") \
84.110 + _(TILDE, "~") \
84.111 + _(QMARK, "?") \
84.112 + _(COLON, ":") \
84.113 + _(UNDERSCORE, "_") \
84.114 + _(DOT, ".") \
84.115 + _(EOF, "<end-of-file>")
84.116 +
84.117 +enum TokenKind
84.118 +{
84.119 +# define _(name, str) TOK_##name,
84.120 + TOKENMAP(_)
84.121 +# undef _
84.122 + TOK_BITAND = TOK_AMPERSAND,
84.123 + TOKENS_TOTAL
84.124 +};
84.125 +
84.126 +extern const char *TokenNames[];
84.127 +
84.128 +} // namespace ke
84.129 +
84.130 +#endif //_include_jitcraft_token_h_
85.1 --- a/src/jitcraft.vcxproj Mon Sep 17 00:10:01 2012 -0700
85.2 +++ b/src/jitcraft.vcxproj Sat Nov 17 18:41:01 2012 -0800
85.3 @@ -97,9 +97,15 @@
85.4 <ClCompile Include="API.cpp" />
85.5 <ClCompile Include="Array.cpp" />
85.6 <ClCompile Include="Box.cpp" />
85.7 - <ClCompile Include="BytecodeCompiler.cpp" />
85.8 - <ClCompile Include="BytecodeEmitter.cpp" />
85.9 - <ClCompile Include="CompileContext.cpp" />
85.10 + <ClCompile Include="compiler\BytecodeEmitter.cpp" />
85.11 + <ClCompile Include="compiler\CompileContext.cpp" />
85.12 + <ClCompile Include="compiler\HIR.cpp" />
85.13 + <ClCompile Include="compiler\NameBinding.cpp" />
85.14 + <ClCompile Include="compiler\Parser.cpp" />
85.15 + <ClCompile Include="compiler\Scanner.cpp" />
85.16 + <ClCompile Include="compiler\Scopes.cpp" />
85.17 + <ClCompile Include="compiler\SemanticAnalysis.cpp" />
85.18 + <ClCompile Include="compiler\Symbols.cpp" />
85.19 <ClCompile Include="Environments.cpp" />
85.20 <ClCompile Include="Exception.cpp" />
85.21 <ClCompile Include="FixedArray.cpp" />
85.22 @@ -109,16 +115,12 @@
85.23 <ClCompile Include="Interpreter.cpp" />
85.24 <ClCompile Include="main.cpp" />
85.25 <ClCompile Include="Modules.cpp" />
85.26 - <ClCompile Include="NameBinding.cpp" />
85.27 + <ClCompile Include="NativeTable.cpp" />
85.28 <ClCompile Include="Opcodes.cpp" />
85.29 - <ClCompile Include="Parser.cpp" />
85.30 <ClCompile Include="Platform-Windows.cpp" />
85.31 <ClCompile Include="PoolAllocator.cpp" />
85.32 <ClCompile Include="Reference.cpp" />
85.33 <ClCompile Include="RootScopes.cpp" />
85.34 - <ClCompile Include="Scanner.cpp" />
85.35 - <ClCompile Include="Scopes.cpp" />
85.36 - <ClCompile Include="SemanticAnalysis.cpp" />
85.37 <ClCompile Include="Spaces.cpp" />
85.38 <ClCompile Include="Stack.cpp" />
85.39 <ClCompile Include="StringPool.cpp" />
85.40 @@ -133,13 +135,20 @@
85.41 <ClInclude Include="..\include\keima_util.h" />
85.42 <ClInclude Include="AllocatorPolicies.h" />
85.43 <ClInclude Include="Array.h" />
85.44 - <ClInclude Include="AST.h" />
85.45 <ClInclude Include="Barriers.h" />
85.46 <ClInclude Include="Box.h" />
85.47 - <ClInclude Include="BytecodeEmitter.h" />
85.48 - <ClInclude Include="BytecodeCompiler.h" />
85.49 <ClInclude Include="CompactBuffer.h" />
85.50 - <ClInclude Include="CompileContext.h" />
85.51 + <ClInclude Include="compiler\AST.h" />
85.52 + <ClInclude Include="compiler\BytecodeEmitter.h" />
85.53 + <ClInclude Include="compiler\CompileContext.h" />
85.54 + <ClInclude Include="compiler\HIR.h" />
85.55 + <ClInclude Include="compiler\NameBinding.h" />
85.56 + <ClInclude Include="compiler\Parser.h" />
85.57 + <ClInclude Include="compiler\Scanner.h" />
85.58 + <ClInclude Include="compiler\Scopes.h" />
85.59 + <ClInclude Include="compiler\SemanticAnalysis.h" />
85.60 + <ClInclude Include="compiler\Symbols.h" />
85.61 + <ClInclude Include="compiler\Token.h" />
85.62 <ClInclude Include="Environments.h" />
85.63 <ClInclude Include="FixedArray.h" />
85.64 <ClInclude Include="Functions.h" />
85.65 @@ -151,21 +160,18 @@
85.66 <ClInclude Include="Interpreter.h" />
85.67 <ClInclude Include="Messages.h" />
85.68 <ClInclude Include="Modules.h" />
85.69 - <ClInclude Include="NameBinding.h" />
85.70 <ClInclude Include="Heap.h" />
85.71 + <ClInclude Include="NativeTable.h" />
85.72 <ClInclude Include="Objects.h" />
85.73 <ClInclude Include="ObjectVisitor.h" />
85.74 <ClInclude Include="Opcodes.h" />
85.75 - <ClInclude Include="Parser.h" />
85.76 <ClInclude Include="Platform.h" />
85.77 <ClInclude Include="PoolAllocator.h" />
85.78 <ClInclude Include="Handles.h" />
85.79 + <ClInclude Include="QualType.h" />
85.80 <ClInclude Include="Reference.h" />
85.81 <ClInclude Include="RootScopes.h" />
85.82 - <ClInclude Include="Scanner.h" />
85.83 - <ClInclude Include="Scopes.h" />
85.84 <ClInclude Include="Code.h" />
85.85 - <ClInclude Include="SemanticAnalysis.h" />
85.86 <ClInclude Include="Spaces-inl.h" />
85.87 <ClInclude Include="Spaces.h" />
85.88 <ClInclude Include="Stack.h" />
85.89 @@ -177,7 +183,6 @@
85.90 <ClInclude Include="Vector.h" />
85.91 <ClInclude Include="VirtualObjectVisitor.h" />
85.92 <ClInclude Include="Zone.h" />
85.93 - <ClInclude Include="Token.h" />
85.94 <ClInclude Include="Utility.h" />
85.95 </ItemGroup>
85.96 <ItemGroup>
85.97 @@ -187,4 +192,4 @@
85.98 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
85.99 <ImportGroup Label="ExtensionTargets">
85.100 </ImportGroup>
85.101 -</Project>
85.102 +</Project>
85.103 \ No newline at end of file
86.1 --- a/src/main.cpp Mon Sep 17 00:10:01 2012 -0700
86.2 +++ b/src/main.cpp Sat Nov 17 18:41:01 2012 -0800
86.3 @@ -54,6 +54,31 @@
86.4 }
86.5 } s_Reporter;
86.6
86.7 +class MainCollector : public Ke::IPublicFunctionListener
86.8 +{
86.9 + public:
86.10 + MainCollector()
86.11 + {
86.12 + }
86.13 + void registerPublic(Handle<Function> fun) {
86.14 + Local<String> str = fun->name();
86.15 + if (str && strcmp(str->chars(), "main") == 0)
86.16 + fun_ = fun;
86.17 + }
86.18 +
86.19 + void unregisterPublic(Handle<Function> fun) {
86.20 + if (fun_ == fun)
86.21 + fun_ = Handle<Function>();
86.22 + }
86.23 +
86.24 + Handle<Function> fun() const {
86.25 + return fun_;
86.26 + }
86.27 +
86.28 + private:
86.29 + Root<Function> fun_;
86.30 +};
86.31 +
86.32 intptr_t PrintFloat(void *blah, intptr_t *params)
86.33 {
86.34 fprintf(stdout, "%f", *reinterpret_cast<float *>(¶ms[1]));
86.35 @@ -86,36 +111,22 @@
86.36
86.37 Keima::InstallMessageReporter(&s_Reporter);
86.38 {
86.39 + MainCollector entry;
86.40 + Keima::SetPublicFunctionListener(&entry);
86.41 +
86.42 HandleScope scope;
86.43 - Local<Module> module = Compile(argv[1]);
86.44 - if (!module)
86.45 - return 1;
86.46 + Compile(argv[1]);
86.47
86.48 Keima::CollectGarbage();
86.49
86.50 - // Look for a public named "main".
86.51 - Local<Function> fun;
86.52 - for (unsigned i = 0; i < module->numPublics(); i++) {
86.53 - if (strcmp(module->getPublic(i)->name()->chars(), "main") == 0) {
86.54 - fun = module->getPublic(i);
86.55 - break;
86.56 - }
86.57 - }
86.58 + Keima::BindNative("PrintFloat", PrintFloat);
86.59 + Keima::BindNative("PrintNum", PrintNum);
86.60 + Keima::BindNative("PrintString", PrintString);
86.61
86.62 - for (unsigned i = 0; i < module->numNatives(); i++) {
86.63 - Local<Native> native = module->getNative(i);
86.64 -
86.65 - if (strcmp(native->name()->chars(), "PrintFloat") == 0)
86.66 - native->bind(reinterpret_cast<void *>(PrintFloat));
86.67 - else if (strcmp(native->name()->chars(), "PrintNum") == 0)
86.68 - native->bind(reinterpret_cast<void *>(PrintNum));
86.69 - else if (strcmp(native->name()->chars(), "PrintString") == 0)
86.70 - native->bind(reinterpret_cast<void *>(PrintString));
86.71 - }
86.72 -
86.73 + Handle<Function> fun = entry.fun();
86.74
86.75 if (!fun) {
86.76 - fprintf(stdout, "Plugin compiles!\nNot running; no public 'main'.\n");
86.77 + fprintf(stdout, "Not running; no public 'main'.\n");
86.78 } else {
86.79 if (!Keima::Invoke(fun, NULL, 0, true, &rval))
86.80 rval = 1;
87.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
87.2 +++ b/tests/basic/floats.out Sat Nov 17 18:41:01 2012 -0800
87.3 @@ -0,0 +1,1 @@
87.4 +5012.000000
88.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
88.2 +++ b/tests/basic/floats.sp Sat Nov 17 18:41:01 2012 -0800
88.3 @@ -0,0 +1,9 @@
88.4 +native PrintFloat(float:num);
88.5 +
88.6 +main()
88.7 +{
88.8 + new float:f = 12.0;
88.9 + for (new i = 0; i < 100; i = i + 1)
88.10 + f = f + 0.5 + i;
88.11 + PrintFloat(f);
88.12 +}
89.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
89.2 +++ b/tests/display.py Sat Nov 17 18:41:01 2012 -0800
89.3 @@ -0,0 +1,23 @@
89.4 +# vim: set ts=2 sw=2 tw=99 ft=python et:
89.5 +
89.6 +class Interactive:
89.7 + def __init__(self):
89.8 + self.failures = []
89.9 + self.timeouts = []
89.10 +
89.11 + def begin(self, tests):
89.12 + return
89.13 +
89.14 + def result(self, test, r):
89.15 + if r.ok:
89.16 + print('PASS: ' + test.name)
89.17 + else:
89.18 + if r.timeout:
89.19 + print('TIMEOUT: ' + test.name)
89.20 + else:
89.21 + print('FAIL: ' + test.name)
89.22 + print(' -- Error code: ' + str(r.code))
89.23 + print(' -- message: \n' + r.message)
89.24 + print(' -- stdout: \n' + r.out)
89.25 + print(' -- stderr: \n' + r.err)
89.26 +
90.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
90.2 +++ b/tests/harness.py Sat Nov 17 18:41:01 2012 -0800
90.3 @@ -0,0 +1,118 @@
90.4 +# vim: set ts=2 sw=4 tw=99 ft=python et:
90.5 +import os
90.6 +import re
90.7 +import sys
90.8 +import time
90.9 +import os.path
90.10 +from test import Test
90.11 +from subprocess import *
90.12 +from threading import Thread
90.13 +from display import Interactive
90.14 +
90.15 +def FindTests(tests, root, folder):
90.16 + folders = []
90.17 + for name in os.listdir(os.path.join(root, folder)):
90.18 + path = os.path.join(root, folder, name)
90.19 + if os.path.isdir(path):
90.20 + folders.append(name)
90.21 + continue
90.22 +
90.23 + path = os.path.join(root, folder)
90.24 + out = re.match("^([^\.]+)\.out$", name)
90.25 + err = re.match("^([^\.]+)\.err$", name)
90.26 + if out:
90.27 + name = out.group(1)
90.28 + tests.append(Test(path, name, 'out'))
90.29 + elif err:
90.30 + name = err.group(1)
90.31 + tests.append(Test(path, name, 'err'))
90.32 +
90.33 + for name in folders:
90.34 + path = os.path.join(folder, name)
90.35 + FindTests(tests, root, path)
90.36 +
90.37 +def IsTestRoot(path, name):
90.38 + return os.path.isdir(path)
90.39 +
90.40 +def RunTest_(argv, options, L):
90.41 + if sys.platform != 'win32':
90.42 + options['close_fds'] = True
90.43 +
90.44 + p = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options)
90.45 +
90.46 + L[0] = p
90.47 + out, err = p.communicate()
90.48 + L[1] = (out, err, p.returncode)
90.49 +
90.50 +def RunTest(test, options, shell):
90.51 + argv = [shell, test.cmd()]
90.52 +
90.53 + L = [None, None]
90.54 + timeout = False
90.55 + th = Thread(target = RunTest_, args = (argv, options, L))
90.56 + th.start()
90.57 + th.join(60.0)
90.58 + while th.isAlive():
90.59 + if L[0] is not None:
90.60 + try:
90.61 + L[0].kill()
90.62 + time.sleep(.1)
90.63 + timeout = True
90.64 + except OSError:
90.65 + # Expecting a "No such process" error
90.66 + pass
90.67 +
90.68 + th.join()
90.69 + (out, err, code) = L[1]
90.70 +
90.71 + return test.check(out, err, code, timeout)
90.72 +
90.73 +def RunTests(display, tests, shell):
90.74 + display.begin(tests)
90.75 + ok = True
90.76 + try:
90.77 + for test in tests:
90.78 + options = { }
90.79 + result = RunTest(test, options, shell)
90.80 +
90.81 + ok = ok and result.ok
90.82 +
90.83 + display.result(test, result)
90.84 + except KeyboardInterrupt:
90.85 + display.cancel()
90.86 + ok = False
90.87 +
90.88 + return ok
90.89 +
90.90 +
90.91 +def main(argv):
90.92 + root = os.path.dirname(os.path.abspath(__file__))
90.93 +
90.94 + from optparse import OptionParser
90.95 + op = OptionParser(usage='%prog [options] <shell>')
90.96 + (options, args) = op.parse_args(argv)
90.97 +
90.98 + if len(args) != 1:
90.99 + op.error('missing <shell> argument')
90.100 +
90.101 + shell = os.path.normpath(args[0])
90.102 +
90.103 + tests = []
90.104 + for name in os.listdir(root):
90.105 + path = os.path.join(root, name)
90.106 + if IsTestRoot(path, name):
90.107 + FindTests(tests, root, name)
90.108 +
90.109 + if len(tests) == 0:
90.110 + op.error('no test cases found')
90.111 +
90.112 + display = Interactive()
90.113 + ok = RunTests(display, tests, shell)
90.114 + if ok:
90.115 + sys.exit(0)
90.116 + else:
90.117 + sys.exit(1)
90.118 +
90.119 +if __name__ == '__main__':
90.120 + main(sys.argv[1:])
90.121 +
91.1 --- a/tests/prototype/floats.sp Mon Sep 17 00:10:01 2012 -0700
91.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
91.3 @@ -1,7 +0,0 @@
91.4 -main()
91.5 -{
91.6 - new Float:f = 12.0;
91.7 - for (new i = 0; i < 100; i = i + 1)
91.8 - f = f + 0.5 + i;
91.9 - return f;
91.10 -}
92.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
92.2 +++ b/tests/test.py Sat Nov 17 18:41:01 2012 -0800
92.3 @@ -0,0 +1,60 @@
92.4 +# vim: set ts=2 sw=4 tw=99 ft=python et:
92.5 +import os
92.6 +import os.path
92.7 +
92.8 +class Result:
92.9 + def __init__(self, ok, out, err, code, timeout, message):
92.10 + self.ok = ok
92.11 + self.out = out
92.12 + self.err = err
92.13 + self.code = code
92.14 + self.timeout = timeout
92.15 + self.message = message
92.16 +
92.17 +class Test:
92.18 + def __init__(self, path, name, type):
92.19 + self.path = path
92.20 + self.name = name
92.21 + self.type = type
92.22 +
92.23 + def cmd(self):
92.24 + return os.path.join(self.path, self.name + '.sp')
92.25 +
92.26 + def compare(self, text):
92.27 + ok = True
92.28 + message = None
92.29 + with open(os.path.join(self.path, self.name + '.' + self.type)) as f:
92.30 + lines = text.split('\n')
92.31 + i = 0
92.32 + for line in f:
92.33 + line = line.rstrip('\r\n')
92.34 + if line != lines[i]:
92.35 + message = 'Got "' + lines[i] + '", expected "' + line + '"'
92.36 + ok = False
92.37 + break
92.38 + i += 1
92.39 + return (ok, message)
92.40 +
92.41 + def check(self, out, err, code, timeout):
92.42 + if not out:
92.43 + out = ''
92.44 + if not err:
92.45 + err = ''
92.46 + if self.type == 'err':
92.47 + if code == 0:
92.48 + message = 'Expected failure, got success'
92.49 + ok = False
92.50 + else:
92.51 + (ok, message) = self.compare(err)
92.52 + elif self.type == 'out':
92.53 + if code != 0:
92.54 + message = 'Expected success, got failure (code: ' + str(code) + ')'
92.55 + ok = False
92.56 + else:
92.57 + (ok, message) = self.compare(out)
92.58 +
92.59 + if timeout:
92.60 + ok = false
92.61 + message = 'timeout'
92.62 +
92.63 + return Result(ok, out, err, code, timeout, message)