into anything yet, but it builds OK inside SimGear.
simgear/bucket/Makefile \
simgear/debug/Makefile \
simgear/ephemeris/Makefile \
+ simgear/interpreter/Makefile \
simgear/io/Makefile \
simgear/magvar/Makefile \
simgear/math/Makefile \
SUBDIRS = \
xml \
+ interpreter \
debug \
misc \
bucket \
--- /dev/null
+.deps
+Makefile
+Makefile.in
--- /dev/null
+includedir = @includedir@/js
+
+lib_LIBRARIES = libsginterp.a
+
+include_HEADERS = \
+ interpreter.hxx
+
+libsginterp_a_SOURCES = \
+ interpreter.cxx interpreter.hxx \
+ ixlib_javascript.hh \
+ js_array.cc \
+ js_expression.cc \
+ js_interpreter.cc \
+ js_value.cc \
+ js_declaration.cc \
+ js_instruction.cc \
+ js_library.cc \
+ lex.javascript.cc ixlib_token_lex.hh ixlib_token_javascript.hh \
+ scanner.cc ixlib_scanner.hh ixlib_scanjs.hh \
+ exbase.cc \
+ numeric.cc ixlib_numeric.hh \
+ numconv.cc ixlib_numconv.hh \
+ re.cc ixlib_re.hh ixlib_re_impl.hh \
+ exgen.cc ixlib_exgen.hh \
+ string.cc ixlib_string.hh \
+ ixlib_base.hh \
+ ixlib_exbase.hh \
+ ixlib_garbage.hh \
+ ixlib_i18n.hh \
+ ixlib_js_internals.hh \
+ ixlib_random.hh
+
+if OLD_AUTOMAKE
+INCLUDES += -I$(top_srcdir)
+else
+INCLUDES = -I$(top_srcdir)
+endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Exception handling
+// ----------------------------------------------------------------------------
+// (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <cstdio>
+#include <cstring>
+#include <ixlib_exbase.hh>
+
+
+
+
+using namespace ixion;
+
+
+
+
+// Description forms ----------------------------------------------------------
+#define T_DESCRIPTION1 "[%s%04X] %s"
+#define T_DESCRIPTION2 "[%s%04X] %s <%s>"
+#define T_DESCRIPTION3 "[%s%04X] %s <%s,%d>"
+#define T_DESCRIPTION1I "[%s%04X] %s (%s)"
+#define T_DESCRIPTION2I "[%s%04X] %s (%s) <%s>"
+#define T_DESCRIPTION3I "[%s%04X] %s (%s) <%s,%d>"
+
+
+
+
+// base_exception -------------------------------------------------------------
+char base_exception::RenderBuffer[EX_INFOMAX+1+100];
+
+
+
+
+base_exception::base_exception(TErrorCode error,char const *info,char *module,
+ TIndex line,char *category)
+: Error(error),Module(module),Line(line),Category(category) {
+ HasInfo = (info!=NULL);
+ if (info) {
+ if (strlen(info)>EX_INFOMAX) {
+ strncpy(Info,info,EX_INFOMAX);
+ Info[EX_INFOMAX] = '\0';
+ }
+ else strcpy(Info,info);
+ }
+ }
+
+
+
+
+char const *base_exception::what() const throw () {
+ if (HasInfo) {
+ if (Module) {
+ if (Line)
+ sprintf(RenderBuffer,T_DESCRIPTION3I,Category,Error,getText(),Info,Module,Line);
+ else
+ sprintf(RenderBuffer,T_DESCRIPTION2I,Category,Error,getText(),Info,Module);
+ }
+ else
+ sprintf(RenderBuffer,T_DESCRIPTION1I,Category,Error,getText(),Info);
+ }
+ else {
+ if (Module) {
+ if (Line)
+ sprintf(RenderBuffer,T_DESCRIPTION3,Category,Error,getText(),Module,Line);
+ else
+ sprintf(RenderBuffer,T_DESCRIPTION2,Category,Error,getText(),Module);
+ }
+ else
+ sprintf(RenderBuffer,T_DESCRIPTION1,Category,Error,getText());
+ }
+ return RenderBuffer;
+ }
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Generic exceptions
+// ----------------------------------------------------------------------------
+// (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include "ixlib_i18n.hh"
+#include <ixlib_exgen.hh>
+#include <ixlib_numconv.hh>
+
+
+
+
+using namespace ixion;
+
+
+
+
+static char *(PlainText[]) = {
+ N_("Unable to evaluate expression"),
+ N_("Function not yet implemented"),
+ N_("General error"),
+ N_("NULL pointer encountered"),
+ N_("Invalid parameter"),
+ N_("Index out of range"),
+ N_("Buffer overrun"),
+ N_("Buffer underrun"),
+ N_("Item not found"),
+ N_("Invalid operation"),
+ N_("Dimension mismatch"),
+ N_("Operation cancelled"),
+ N_("Unable to operate on empty set"),
+ N_("Unable to remove GC entry"),
+ N_("Unable to protect non-freeable entry")
+ };
+
+
+
+
+// generic_exception ----------------------------------------------------------
+char const *generic_exception::getText() const {
+ return _(PlainText[Error]);
+ }
--- /dev/null
+#include "interpreter.hxx"
+
+SGInterpreter::SGInterpreter ()
+{
+}
+
+SGInterpreter::~SGInterpreter ()
+{
+}
--- /dev/null
+#ifndef __INTERPRETER_HXX
+#define __INTERPRETER_HXX 1
+
+class SGInterpreter
+{
+public:
+
+ SGInterpreter ();
+ virtual ~SGInterpreter ();
+
+};
+
+#endif
--- /dev/null
+/* ----------------------------------------------------------------------------
+ Description : iXiONmedia library base declarations
+ ----------------------------------------------------------------------------
+ (c) Copyright 1996 by iXiONmedia, all rights reserved.
+ ----------------------------------------------------------------------------
+ This header must be C-safe for autoconf purposes.
+ */
+
+
+
+
+#ifndef IXLIB_BASE
+#define IXLIB_BASE
+
+
+#undef HAVE_CONFIG_H
+
+#ifdef HAVE_CONFIG_H
+#include <ixlib_config.hh>
+#undef PACKAGE
+#undef VERSION
+#endif
+
+
+
+
+#ifdef __cplusplus
+namespace ixion {
+ extern "C" {
+#endif
+/* Aliases --------------------------------------------------------------------
+*/
+ const double Pi = 3.141592653589793285;
+ const double Euler = 2.718281828;
+ const double Gravity = 9.8065; // m/s^2
+ const double UniGravity = 6.673e-11; // m^3/kg s^2
+ const double Epsilon0 = 8.8542e-12; // F/m
+ const double Mu0 = 1.2566e-6; // H/m
+ const double LightSpeed = 2.9972e8; // m/s
+ const double Planck = 6.6261e-34; // Js
+
+
+
+
+/* STL Helper macro -----------------------------------------------------------
+*/
+#define FOREACH(VAR,LIST,LISTTYPE) \
+ for (LISTTYPE::iterator VAR = (LIST).begin(),last = (LIST).end();VAR != last;VAR++)
+#define FOREACH_CONST(VAR,LIST,LISTTYPE) \
+ for (LISTTYPE::const_iterator VAR = (LIST).begin(),last = (LIST).end();VAR != last;VAR++)
+
+
+
+
+/* Nomenclature typedefs ------------------------------------------------------
+*/
+ typedef unsigned char TUnsigned8;
+ typedef unsigned short TUnsigned16;
+ typedef unsigned long TUnsigned32;
+ typedef unsigned long long TUnsigned64;
+
+ typedef signed char TSigned8;
+ typedef signed short TSigned16;
+ typedef signed long TSigned32;
+ typedef signed long long TSigned64;
+
+ typedef TSigned8 TDelta8;
+ typedef TSigned16 TDelta16;
+ typedef TSigned32 TDelta32;
+ typedef TSigned64 TDelta64;
+ typedef signed TDelta;
+
+ typedef TUnsigned8 TSize8;
+ typedef TUnsigned16 TSize16;
+ typedef TUnsigned32 TSize32;
+ typedef TUnsigned64 TSize64;
+ typedef unsigned TSize;
+
+ typedef TUnsigned8 TIndex8;
+ typedef TUnsigned16 TIndex16;
+ typedef TUnsigned32 TIndex32;
+ typedef TUnsigned64 TIndex64;
+ typedef unsigned TIndex;
+
+ typedef TUnsigned8 TByte;
+
+
+
+
+ int ixlibGetMajorVersion();
+ int ixlibGetMinorVersion();
+ int ixlibGetMicroVersion();
+
+ void ixlibInitI18n();
+
+
+
+
+ #ifdef __cplusplus
+ }
+ }
+ #endif
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Exception handling
+// ----------------------------------------------------------------------------
+// (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_EXBASE
+#define IXLIB_EXBASE
+
+
+
+
+#include <stdexcept>
+#include <ixlib_base.hh>
+
+
+
+
+// constants ------------------------------------------------------------------
+#define EX_INFOMAX 255
+
+
+
+
+// throw macro ----------------------------------------------------------------
+#define EX_THROW(TYPE,CODE)\
+ throw ::ixion::TYPE##_exception(CODE,NULL,__FILE__,__LINE__);
+#define EX_THROWINFO(TYPE,CODE,INFO)\
+ throw ::ixion::TYPE##_exception(CODE,(char const *) INFO,__FILE__,__LINE__);
+#define EX_CATCHCODE(TYPE,CODE,HANDLER)\
+ catch (TYPE##_exception &ex) { \
+ if (ex.Error != CODE) throw; \
+ HANDLER \
+ }
+#define EX_CONVERT(TYPE,CODE,DESTTYPE,DESTCODE)\
+ catch (TYPE##_exception &ex) { \
+ if (ex.Error != CODE) throw; \
+ throw DESTTYPE##_exception(DESTCODE,ex.Info,__FILE__,__LINE__); \
+ }
+
+
+
+
+// xBaseException -------------------------------------------------------------
+namespace ixion {
+ typedef unsigned int TErrorCode;
+
+
+
+
+ struct base_exception : public std::exception {
+ TErrorCode Error;
+ char *Module;
+ TIndex Line;
+ char *Category;
+ bool HasInfo;
+ char Info[EX_INFOMAX+1];
+ static char RenderBuffer[EX_INFOMAX+1+100];
+
+ base_exception(TErrorCode error,char const *info = NULL,char *module = NULL,
+ TIndex line = 0,char *category = NULL);
+ char const *what() const throw ();
+ virtual const char *getText() const = 0;
+ };
+ }
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Generic exceptions
+// ----------------------------------------------------------------------------
+// (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_EXGEN
+#define IXLIB_EXGEN
+
+
+
+
+#include <ixlib_exbase.hh>
+
+
+
+
+// Error codes ----------------------------------------------------------------
+#define EC_CANNOTEVALUATE 0
+#define EC_NOTYETIMPLEMENTED 1
+#define EC_ERROR 2
+#define EC_NULLPOINTER 3
+#define EC_INVALIDPAR 4
+#define EC_INDEX 5
+#define EC_BUFFEROVERFLOW 6
+#define EC_BUFFERUNDERFLOW 7
+#define EC_ITEMNOTFOUND 8
+#define EC_INVALIDOP 9
+#define EC_DIMENSIONMISMATCH 10
+#define EC_CANCELLED 11
+#define EC_EMPTYSET 12
+#define EC_CANNOTREMOVEFROMGC 13
+#define EC_REMAININGREF 14
+
+#define ECMEM_GENERAL 0
+
+
+
+// Throw macro ----------------------------------------------------------------
+#define EXGEN_THROW(CODE)\
+ EX_THROW(generic,CODE)
+#define EXGEN_THROWINFO(CODE,INFO)\
+ EX_THROWINFO(generic,CODE,INFO)
+#define EXGEN_NYI\
+ EXGEN_THROW(EC_NOTYETIMPLEMENTED)
+
+
+
+
+namespace ixion {
+// generic_exception ----------------------------------------------------------
+ struct generic_exception : public base_exception {
+ generic_exception(TErrorCode error,char const *info = NULL,char *module = NULL,
+ TIndex line = 0)
+ : base_exception(error,info,module,line,"GEN") {
+ }
+ virtual char const *getText() const;
+ };
+ }
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Garbage collection
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_GARBAGE
+#define IXLIB_GARBAGE
+
+
+
+
+#include <memory>
+#include <ixlib_exgen.hh>
+#include <ixlib_base.hh>
+
+
+
+
+namespace ixion {
+ template<class T>
+ class delete_deallocator {
+ public:
+ void operator()(T const *instance) {
+ delete instance;
+ }
+ };
+ template<class T>
+ class delete_array_deallocator {
+ public:
+ void operator()(T const *instance) {
+ delete[] instance;
+ }
+ };
+
+ template<class T,class Deallocator = delete_deallocator<T> >
+ class reference_manager;
+
+ template<class T>
+ class ref_base {
+ protected:
+ T *Instance;
+
+ public:
+ ref_base(T *instance = NULL)
+ : Instance(instance) {
+ }
+ ref_base(ref_base const &src)
+ : Instance(src.Instance) {
+ }
+
+ // comparison
+ bool operator==(ref_base const &op2) const {
+ return Instance == op2.Instance;
+ }
+
+ // smart pointer nitty-gritty
+ T &operator*() const {
+ return *Instance;
+ }
+ T *operator->() const {
+ return Instance;
+ }
+ T *operator+(TIndex index) const {
+ return Instance + index;
+ }
+ T &operator[](TIndex index) const {
+ return Instance[index];
+ }
+
+ // methods
+ T *get() const {
+ return Instance;
+ }
+ };
+
+
+
+
+ template<class T,class T_Managed = T>
+ class ref;
+ template<class T,class T_Managed = T>
+ class no_free_ref;
+
+
+
+
+ template<class T_Managed>
+ class reference_manager_keeper {
+ public:
+ // *** FIXME should be private, but cannot be
+ // (partial specializations cannot be declared friends)
+ static reference_manager<T_Managed> Manager;
+ };
+
+
+
+
+
+ /**
+ An object that acts like a reference-counted pointer to an object.
+ The corresponding reference_manager is identified implicitly through
+ static references.
+
+ Example:
+ <code>
+ IXLIB_GARBAGE_DECLARE_MANAGER(int)
+
+ int main() {
+ ref<int> my_int = new int(5);
+ *my_int = 17;
+ ref<int> another_int = my_int;
+ *another_int = 12;
+
+ *my_int == 12; // true
+ }
+ </code>
+ */
+ template<class T,class T_Managed>
+ class ref : public ref_base<T> {
+ public:
+ // we have to have an explicit copy constructor, otherwise the
+ // compiler generates one, which is *ahem* - fatal
+ ref(ref const &src)
+ : ref_base<T>(src) {
+ reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+ }
+ template<class T2>
+ ref(ref<T2,T_Managed> const &src)
+ : ref_base<T>(src.get()) {
+ reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+ }
+ template<class T2>
+ ref(no_free_ref<T2,T_Managed> const &src)
+ : ref_base<T>(src.get()) {
+ reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+ }
+ ref(T *instance = NULL)
+ : ref_base<T>(instance) {
+ reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+ }
+ ~ref() {
+ reference_manager_keeper<T_Managed>::Manager.freeReference(Instance);
+ }
+
+ ref &operator=(ref const &src) {
+ set(src.get());
+ return *this;
+ }
+ ref &operator=(T *ptr) {
+ set(ptr);
+ return *this;
+ }
+
+ // methods
+ void release() {
+ reference_manager_keeper<T_Managed>::Manager.freeReference(Instance);
+ Instance = NULL;
+ }
+ void set(T *instance) {
+ if (instance == Instance) return;
+
+ reference_manager_keeper<T_Managed>::Manager.freeReference(Instance);
+ Instance = instance;
+ reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+ }
+ T *releaseFromGCArena() {
+ T *oldinst = Instance;
+ reference_manager_keeper<T_Managed>::Manager.forgetReference(Instance);
+ Instance = NULL;
+ return oldinst;
+ }
+ };
+
+
+
+
+ /**
+ An object that acts like a reference-counted pointer to an object.
+ However, the referenced object is not freed if the no_free_ref
+ is the last reference to the object to go out of scope.
+
+ This is useful to pass objects allocated e.g. on the stack along
+ inside ref's, while making sure they aren't freed.
+ (which would most probably lead to disaster)
+
+ no_free_ref's are mostly a hack, but there are situations where you cannot
+ avoid them. But even so, you should try not to use them where possible.
+
+ The corresponding reference_manager is identified implicitly through
+ static references.
+ */
+ template<class T,class T_Managed>
+ class no_free_ref : public ref_base<T>{
+ public:
+ // we have to have an explicit copy constructor, otherwise the
+ // compiler generates one, which is *ahem* - fatal
+ no_free_ref(no_free_ref const &src)
+ : ref_base<T>(src) {
+ reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+ }
+ template<class T2>
+ no_free_ref(ref<T2,T_Managed> const &src)
+ : ref_base<T>(src.get()) {
+ reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+ }
+ template<class T2>
+ no_free_ref(no_free_ref<T2,T_Managed> const &src)
+ : ref_base<T>(src.get()) {
+ reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+ }
+ no_free_ref(T *instance = NULL)
+ : ref_base<T>(instance) {
+ reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+ }
+ ~no_free_ref() {
+ reference_manager_keeper<T_Managed>::Manager.removeNoFreeReference(Instance);
+ }
+
+ // assignment
+ no_free_ref &operator=(no_free_ref const &src) {
+ set(src.get());
+ return *this;
+ }
+ no_free_ref &operator=(T *ptr) {
+ set(ptr);
+ return *this;
+ }
+
+ // methods
+ void release() {
+ reference_manager_keeper<T_Managed>::Manager.removeNoFreeReference(Instance);
+ Instance = NULL;
+ }
+ void set(T *instance) {
+ if (instance == Instance) return;
+
+ reference_manager_keeper<T_Managed>::Manager.removeNoFreeReference(Instance);
+ Instance = instance;
+ reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+ }
+ T *releaseFromGCArena() {
+ T *oldinst = Instance;
+ reference_manager_keeper<T_Managed>::Manager.forgetReference(Instance);
+ Instance = NULL;
+ return oldinst;
+ }
+ };
+
+
+
+
+ /**
+ An object that acts like a reference-counted pointer to an object.
+ The corresponding reference_manager is identified explicitly.
+ */
+ template<class T>
+ class dynamic_ref : public ref_base<T> {
+ protected:
+ reference_manager<T> &Manager;
+
+ public:
+ dynamic_ref(dynamic_ref const &src)
+ : ref_base<T>(src),Manager(src.Manager) {
+ Manager.addReference(Instance);
+ }
+ dynamic_ref(reference_manager<T> &mgr,T *instance = NULL)
+ : ref_base<T>(instance),Manager(mgr) {
+ Manager.addReference(Instance);
+ }
+ ~dynamic_ref() {
+ Manager.freeReference(Instance);
+ }
+
+ // assignment
+ dynamic_ref &operator=(dynamic_ref const &src) {
+ set(src.get());
+ return *this;
+ }
+ dynamic_ref &operator=(T *ptr) {
+ set(ptr);
+ return *this;
+ }
+
+ // methods
+ void release() {
+ Manager.freeReference(Instance);
+ Instance = NULL;
+ }
+ void set(T *instance) {
+ if (instance == Instance) return;
+
+ Manager.freeReference(Instance);
+ Instance = instance;
+ Manager.addReference(Instance);
+ }
+ T *releaseFromGCArena() {
+ T *oldinst = Instance;
+ Manager.forgetReference(Instance);
+ Instance = NULL;
+ return oldinst;
+ }
+ };
+
+
+
+
+ /**
+ An object that acts like a reference-counted pointer to an object.
+ However, the referenced object is not freed if the no_free_ref
+ is the last reference to the object to go out of scope.
+
+ This is useful to pass objects allocated e.g. on the stack along
+ inside ref's, while making sure they aren't freed.
+ (which would most probably lead to disaster)
+
+ no_free_ref's are mostly a hack, but there are situations where you cannot
+ avoid them. But even so, you should try not to use them where possible.
+
+ The corresponding reference_manager is identified explicitly.
+ */
+ template<class T>
+ class no_free_dynamic_ref : public ref_base<T> {
+ protected:
+ reference_manager<T> &Manager;
+
+ public:
+ no_free_dynamic_ref(no_free_dynamic_ref const &src)
+ : ref_base<T>(src),Manager(src.Manager) {
+ Manager.addNoFreeReference(Instance);
+ }
+ no_free_dynamic_ref(reference_manager<T> &mgr,T *instance = NULL)
+ : ref_base<T>(instance),Manager(mgr) {
+ Manager.addNoFreeReference(Instance);
+ }
+ ~no_free_dynamic_ref() {
+ Manager.removeNoFreeReference(Instance);
+ }
+
+ // assignment
+ no_free_dynamic_ref &operator=(no_free_dynamic_ref const &src) {
+ set(src.get());
+ return *this;
+ }
+ no_free_dynamic_ref &operator=(T *ptr) {
+ set(ptr);
+ return *this;
+ }
+
+ // methods
+ void release() {
+ Manager.removeNoFreeReference(Instance);
+ Instance = NULL;
+ }
+ void set(T *instance) {
+ if (instance == Instance) return;
+
+ Manager.removeNoFreeReference(Instance);
+ Instance = instance;
+ Manager.addNoFreeReference(Instance);
+ }
+ T *releaseFromGCArena() {
+ T *oldinst = Instance;
+ Manager.forgetReference(Instance);
+ Instance = NULL;
+ return oldinst;
+ }
+ };
+
+
+
+
+ template<class T,class Deallocator>
+ class reference_manager {
+ protected:
+
+ struct instance_data {
+ T const *Instance;
+ TSize ReferenceCount,NoFreeReferenceCount;
+ instance_data *Next,*Previous;
+ };
+
+ class pointer_hash {
+ public:
+ };
+
+ typedef unsigned hash_value;
+ static hash_value const HASH_MAX = 0x3ff;
+
+ instance_data *Instances[HASH_MAX+1];
+ Deallocator Dealloc;
+
+ public:
+ reference_manager(Deallocator const &dealloc = Deallocator())
+ : Dealloc(dealloc) {
+ for (hash_value hv = 0;hv <= HASH_MAX;hv++)
+ Instances[hv] = NULL;
+ }
+
+ // *** FIXME should be
+ // protected:
+ // but cannot because partial specializations cannot be declared friends
+ void addReference(T const *instance) {
+ if (!instance) return;
+ instance_data *data = getHashEntry(instance);
+ data->ReferenceCount++;
+ }
+ void freeReference(T const *instance) {
+ if (!instance) return;
+ instance_data *data = getHashEntry(instance);
+ if (--data->ReferenceCount == 0 && data->NoFreeReferenceCount == 0) {
+ removeHashEntry(data);
+ Dealloc(instance);
+ }
+ }
+ void addNoFreeReference(T const *instance) {
+ if (!instance) return;
+ instance_data *data = getHashEntry(instance);
+ data->NoFreeReferenceCount++;
+ }
+ void removeNoFreeReference(T const *instance) {
+ if (!instance) return;
+ instance_data *data = getHashEntry(instance);
+ if (--data->NoFreeReferenceCount == 0) {
+ if (data->ReferenceCount != 0)
+ EXGEN_THROW(EC_REMAININGREF)
+ removeHashEntry(data);
+ }
+ }
+ void forgetReference(T const *instance) {
+ if (!instance) return;
+ instance_data *data = getHashEntry(instance);
+ if (data->ReferenceCount != 1)
+ EXGEN_THROW(EC_CANNOTREMOVEFROMGC)
+ removeHashEntry(data);
+ }
+
+ private:
+ hash_value hash(T const *ptr) const {
+ unsigned u = reinterpret_cast<unsigned>(ptr);
+ return (u ^ (u >> 8) ^ (u >> 16) ^ (u >> 24)) & HASH_MAX;
+ }
+ instance_data *getHashEntry(T const *instance) {
+ instance_data *data = Instances[hash(instance)];
+ while (data) {
+ if (data->Instance == instance) return data;
+ data = data->Next;
+ }
+
+ // not found, add new at front
+ instance_data *link = Instances[hash(instance)];
+ data = new instance_data;
+
+ data->Instance = instance;
+ data->ReferenceCount = 0;
+ data->NoFreeReferenceCount = 0;
+ data->Previous = NULL;
+ data->Next = link;
+ if (link) link->Previous = data;
+ Instances[hash(instance)] = data;
+ return data;
+ }
+ void removeHashEntry(instance_data *data) {
+ instance_data *prev = data->Previous;
+ if (prev) {
+ prev->Next = data->Next;
+ if (data->Next) data->Next->Previous = prev;
+ delete data;
+ }
+ else {
+ Instances[hash(data->Instance)] = data->Next;
+ if (data->Next) data->Next->Previous = NULL;
+ delete data;
+ }
+ }
+ };
+
+
+
+
+ #define IXLIB_GARBAGE_DECLARE_MANAGER(TYPE) \
+ ixion::reference_manager<TYPE> ixion::reference_manager_keeper<TYPE>::Manager;
+ }
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : ixlib internationalization wrapper
+// ----------------------------------------------------------------------------
+// (c) Copyright 2001 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_I18N
+
+
+
+
+#include <string>
+#include <libintl.h>
+#define _(String) gettext(String)
+#define N_(String) (String)
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript interpreter
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_JAVASCRIPT
+#define IXLIB_JAVASCRIPT
+
+
+
+
+#include <vector>
+#if __GNUC__ < 3
+ #include <hash_map>
+#else
+ #include <ext/hash_map>
+#endif
+#include <ixlib_string.hh>
+#include <ixlib_exbase.hh>
+#include <ixlib_garbage.hh>
+#include <ixlib_scanner.hh>
+
+
+
+
+// Error codes ----------------------------------------------------------------
+#define ECJS_UNTERMINATED_COMMENT 0
+#define ECJS_CANNOT_CONVERT 1
+#define ECJS_INVALID_OPERATION 2
+#define ECJS_UNEXPECTED 3
+#define ECJS_UNEXPECTED_EOF 4
+#define ECJS_CANNOT_MODIFY_RVALUE 5
+#define ECJS_UNKNOWN_IDENTIFIER 6
+#define ECJS_UNKNOWN_OPERATOR 7
+#define ECJS_INVALID_NON_LOCAL_EXIT 8
+#define ECJS_INVALID_NUMBER_OF_ARGUMENTS 9
+#define ECJS_INVALID_TOKEN 10
+#define ECJS_CANNOT_REDECLARE 11
+#define ECJS_DOUBLE_CONSTRUCTION 12
+#define ECJS_NO_SUPERCLASS 13
+#define ECJS_DIVISION_BY_ZERO 14
+
+
+
+
+// helpful macros -------------------------------------------------------------
+#define IXLIB_JS_ASSERT_PARAMETERS(NAME,ARGMIN,ARGMAX) \
+ if (parameters.size() < ARGMIN || parameters.size() > ARGMAX) \
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,NAME)
+
+#define IXLIB_JS_IF_METHOD(NAME,ARGMIN,ARGMAX) \
+ if (identifier == NAME) \
+ if (parameters.size() < ARGMIN || parameters.size() > ARGMAX) \
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,NAME) \
+ else
+
+#define IXLIB_JS_DECLARE_FUNCTION(NAME) \
+ namespace { \
+ class NAME : public value { \
+ public: \
+ value_type getType() const { \
+ return VT_FUNCTION; \
+ } \
+ ixion::ref<ixion::javascript::value> call(parameter_list const ¶meters); \
+ }; \
+ } \
+ ixion::ref<ixion::javascript::value> NAME::call(parameter_list const ¶meters)
+
+#define IXLIB_JS_CONVERT_PARAMETERS_0 \
+
+
+
+
+// Exception throw macros -----------------------------------------------------
+#define EXJS_THROW(CODE)\
+ EX_THROW(javascript,CODE)
+#define EXJS_THROWINFO(CODE,INFO)\
+ EX_THROWINFO(javascript,CODE,INFO)
+#define EXJS_THROW_NO_LOCATION(CODE)\
+ EX_THROW(no_location_javascript,CODE)
+#define EXJS_THROWINFO_NO_LOCATION(CODE,INFO)\
+ EX_THROWINFO(no_location_javascript,CODE,INFO)
+#define EXJS_THROWINFOLOCATION(CODE,INFO,LOCATION)\
+ throw ixion::javascript_exception(CODE,LOCATION,INFO,__FILE__,__LINE__);
+#define EXJS_THROWINFOTOKEN(CODE,INFO,TOKEN)\
+ EXJS_THROWINFOLOCATION(CODE,INFO,code_location(TOKEN))
+#define EXJS_THROWINFOEXPRESSION(CODE,INFO,EXPR)\
+ EXJS_THROWINFOLOCATION(CODE,INFO,(EXPR).getCodeLocation())
+
+
+
+
+
+namespace ixion {
+ namespace javascript {
+ struct code_location;
+ }
+
+ // exceptions ---------------------------------------------------------------
+ struct no_location_javascript_exception : public base_exception {
+ no_location_javascript_exception(TErrorCode error,char const *info = NULL,char *module = NULL,
+ TIndex line = 0)
+ : base_exception(error,info,module,line,"JS") {
+ }
+ virtual char *getText() const;
+ };
+
+
+
+
+ struct javascript_exception : public base_exception {
+ javascript_exception(TErrorCode error,char const *info = NULL,char *module = NULL,
+ TIndex line = 0)
+ : base_exception(error,info,module,line,"JS") {
+ }
+ javascript_exception(TErrorCode error,javascript::code_location const &loc,char const *info = 0,char *module = NULL,
+ TIndex line = 0);
+ javascript_exception(no_location_javascript_exception const &half_ex,javascript::code_location const &loc);
+ virtual char *getText() const;
+ };
+
+
+
+
+ // javascript ---------------------------------------------------------------
+ /**
+ This code tries to be an implementation of ECMAScript 4, as available at
+ http://www.mozilla.org/js/language/
+ Note that ES4 is still in the process of standardization.
+
+ It is meant to behave like an ES4 interpreter in strict mode, none
+ of the backward-compatible braindead-isms like newline semicolon
+ insertion and other stuff will ever be implemented.
+
+ This is the list of its shortcomings:
+ <ul>
+ <li> exceptions
+ <li> namespaces,packages
+ <li> constness
+ <li> Number/String constructor and class methods
+ <li> real regexp's
+ <li> the methods listed in FIXME's (js_library.cc js_value.cc)
+ <li> cannot cross-assign predefined methods [won't be]
+ <li> Grammatical semicolon insertion [won't be]
+ <li> type declaration [won't be]
+ </ul>
+
+ Be advised that a javascript value that is passed to you through the
+ interpreter, e.g. as a call parameter, may not be of the type that
+ you expect. For example, in "var x = 4; f(x);", what comes in as
+ the parameter x into f is a wrapper value that adds assign()ability
+ to a value that is wrapped inside. The advised solution to get the
+ object that you expect is to call eliminateWrappers() on the potentially
+ wrapped value.
+ */
+ namespace javascript {
+ class value;
+ class list_scope;
+ struct context {
+ ref<list_scope,value> DeclarationScope;
+ ref<value> LookupScope;
+
+ context(ref<list_scope,value> scope);
+ context(ref<value> scope);
+ context(ref<list_scope,value> decl_scope,ref<value> lookup_scope);
+ };
+
+ class expression;
+
+ class value {
+ public:
+ enum operator_id {
+ // unary, modifying
+ OP_PRE_INCREMENT,OP_POST_INCREMENT,
+ OP_PRE_DECREMENT,OP_POST_DECREMENT,
+ // unary, non-modifying
+ OP_UNARY_PLUS,OP_UNARY_MINUS,
+ OP_LOG_NOT,OP_BIN_NOT,
+ // binary, modifying
+ OP_PLUS_ASSIGN,OP_MINUS_ASSIGN,
+ OP_MUTLIPLY_ASSIGN,OP_DIVIDE_ASSIGN,OP_MODULO_ASSIGN,
+ OP_BIT_AND_ASSIGN,OP_BIT_OR_ASSIGN,OP_BIT_XOR_ASSIGN,
+ OP_LEFT_SHIFT_ASSIGN,OP_RIGHT_SHIFT_ASSIGN,
+ // binary, non-modifying
+ OP_PLUS,OP_MINUS,
+ OP_MULTIPLY,OP_DIVIDE,OP_MODULO,
+ OP_BIT_AND,OP_BIT_OR,OP_BIT_XOR,
+ OP_LEFT_SHIFT,OP_RIGHT_SHIFT,
+ OP_LOGICAL_OR,OP_LOGICAL_AND,
+ OP_EQUAL,OP_NOT_EQUAL,OP_IDENTICAL,OP_NOT_IDENTICAL,
+ OP_LESS_EQUAL,OP_GREATER_EQUAL,OP_LESS,OP_GREATER,
+ // special
+ OP_ASSIGN,
+ };
+
+ enum value_type {
+ VT_UNDEFINED,VT_NULL,
+ VT_INTEGER,VT_FLOATING_POINT,VT_STRING,
+ VT_FUNCTION,VT_OBJECT,VT_BUILTIN,VT_HOST,
+ VT_SCOPE,VT_BOUND_METHOD,VT_TYPE
+ };
+ typedef std::vector<ref<value> > parameter_list;
+
+ virtual ~value() {
+ }
+
+ virtual value_type getType() const = 0;
+ virtual std::string toString() const;
+ virtual int toInt() const;
+ virtual double toFloat() const;
+ virtual bool toBoolean() const;
+ // toString is meant as a type conversion, whereas stringify
+ // is for debuggers and the like
+ virtual std::string stringify() const;
+
+ virtual ref<value> eliminateWrappers();
+ virtual ref<value> duplicate();
+
+ virtual ref<value> lookup(std::string const &identifier);
+ virtual ref<value> subscript(value const &index);
+ virtual ref<value> call(parameter_list const ¶meters);
+ virtual ref<value> callAsMethod(ref<value> instance,parameter_list const ¶meters);
+ virtual ref<value> construct(parameter_list const ¶meters);
+ virtual ref<value> assign(ref<value> op2);
+
+ virtual ref<value> operatorUnary(operator_id op) const;
+ virtual ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+ virtual ref<value> operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const;
+ virtual ref<value> operatorUnaryModifying(operator_id op);
+ virtual ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+
+ static operator_id token2operator(scanner::token const &token,bool unary = false,bool prefix = false);
+ static std::string operator2string(operator_id op);
+ static std::string valueType2string(value_type vt);
+ };
+
+ // obviously, any value can have methods, but with this neat little
+ // interface implementing methods has just become easier.
+ class value_with_methods : public value {
+ class bound_method : public value {
+ std::string Identifier;
+ ref<value_with_methods,value> Parent;
+
+ public:
+ bound_method(std::string const &identifier,ref<value_with_methods,value> parent);
+
+ value_type getType() const {
+ return VT_BOUND_METHOD;
+ }
+
+ ref<value> duplicate();
+ ref<value> call(parameter_list const ¶meters);
+ };
+
+ public:
+ ref<value> lookup(std::string const &identifier);
+ virtual ref<value> callMethod(std::string const &identifier,parameter_list const ¶meters) = 0;
+ };
+
+ // obviously, any value can already represent a scope ("lookup" member!).
+ // the list_scope class is an explicit scope that can "swallow"
+ // (=unite with) other scopes and keeps a list of registered members
+ class list_scope : public value {
+ protected:
+ typedef std::hash_map<std::string,ref<value>,string_hash> member_map;
+ typedef std::vector<ref<value> > swallowed_list;
+
+ member_map MemberMap;
+ swallowed_list SwallowedList;
+
+ public:
+ value_type getType() const {
+ return VT_SCOPE;
+ }
+
+ ref<value> lookup(std::string const &identifier);
+
+ void unite(ref<value> scope);
+ void separate(ref<value> scope);
+ void clearScopes();
+
+ bool hasMember(std::string const &name) const;
+ void addMember(std::string const &name,ref<value> member);
+ void removeMember(std::string const &name);
+ void clearMembers();
+
+ void clear();
+ };
+
+ class js_array : public value_with_methods {
+ private:
+ typedef value_with_methods super;
+
+ protected:
+ typedef std::vector<ref<value> > value_array;
+ value_array Array;
+
+ public:
+ js_array() {
+ }
+ js_array(TSize size);
+ js_array(value_array::const_iterator first,value_array::const_iterator last)
+ : Array(first,last) {
+ }
+ js_array(js_array const &src)
+ : Array(src.Array) {
+ }
+
+ value_type getType() const {
+ return VT_BUILTIN;
+ }
+
+ std::string stringify() const;
+
+ ref<value> duplicate();
+
+ ref<value> lookup(std::string const &identifier);
+ ref<value> subscript(value const &index);
+ ref<value> callMethod(std::string const &identifier,parameter_list const ¶meters);
+
+ TSize size() const {
+ return Array.size();
+ }
+ void resize(TSize size);
+ ref<value> &operator[](TIndex idx);
+ void push_back(ref<value> val);
+ };
+
+ class expression;
+
+ ref<value> makeUndefined();
+ ref<value> makeNull();
+ ref<value> makeValue(signed long val);
+ ref<value> makeConstant(signed long val);
+ ref<value> makeValue(signed int val);
+ ref<value> makeConstant(signed int val);
+ ref<value> makeValue(unsigned long val);
+ ref<value> makeConstant(unsigned long val);
+ ref<value> makeValue(unsigned int val);
+ ref<value> makeConstant(unsigned int val);
+ ref<value> makeValue(double val);
+ ref<value> makeConstant(double val);
+ ref<value> makeValue(std::string const &val);
+ ref<value> makeConstant(std::string const &val);
+ ref<value> makeArray(TSize size = 0);
+ ref<value> makeLValue(ref<value> target);
+ ref<value> wrapConstant(ref<value> val);
+
+ class interpreter {
+ public:
+ ref<list_scope,value> RootScope;
+
+ public:
+ interpreter();
+ ~interpreter();
+
+ ref<expression> parse(std::string const &str);
+ ref<expression> parse(std::istream &istr);
+ ref<value> execute(std::string const &str);
+ ref<value> execute(std::istream &istr);
+ ref<value> execute(ref<expression> expr);
+
+ private:
+ ref<value> evaluateCatchExits(ref<expression> expr);
+ };
+
+ void addGlobal(interpreter &ip);
+ void addMath(interpreter &ip);
+ void addStandardLibrary(interpreter &ip);
+ }
+ }
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript interpreter
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_JS_INTERNALS
+#define IXLIB_JS_INTERNALS
+
+
+
+
+#include <ixlib_javascript.hh>
+
+
+
+
+using namespace std;
+
+
+
+
+namespace ixion {
+ namespace javascript {
+ struct code_location {
+ TIndex Line;
+
+ code_location(scanner::token &tok);
+ explicit code_location(TIndex line);
+ string stringify() const;
+ };
+
+ struct return_exception {
+ ref<value> ReturnValue;
+ code_location Location;
+
+ return_exception(ref<value> retval,code_location const &loc)
+ : ReturnValue(retval),Location(loc) {
+ }
+ };
+
+ struct break_exception {
+ bool HasLabel;
+ string Label;
+ code_location Location;
+
+ break_exception(bool has_label,string const &label,code_location const &loc)
+ : HasLabel(has_label),Label(label),Location(loc) {
+ }
+ };
+
+ struct continue_exception {
+ bool HasLabel;
+ string Label;
+ code_location Location;
+
+ continue_exception(bool has_label,string const &label,code_location const &loc)
+ : HasLabel(has_label),Label(label),Location(loc) {
+ }
+ };
+
+ // values -----------------------------------------------------------------
+ class null : public value {
+ private:
+ typedef value super;
+
+ public:
+ value_type getType() const;
+ bool toBoolean() const;
+
+ ref<value> duplicate();
+ };
+
+ class const_floating_point : public value_with_methods {
+ private:
+ typedef value_with_methods super;
+
+ protected:
+ double Value;
+
+ public:
+ const_floating_point(double value);
+
+ value_type getType() const;
+ int toInt() const;
+ double toFloat() const;
+ bool toBoolean() const;
+ string toString() const;
+
+ ref<value> duplicate();
+
+ ref<value> callMethod(string const &identifier,parameter_list const ¶meters);
+
+ ref<value> operatorUnary(operator_id op) const;
+ ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+ };
+
+ class floating_point : public const_floating_point {
+ private:
+ typedef const_floating_point super;
+
+ public:
+ floating_point(double value);
+
+ ref<value> operatorUnaryModifying(operator_id op);
+ ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+ };
+
+ class const_integer : public value_with_methods {
+ private:
+ typedef value_with_methods super;
+
+ protected:
+ long Value;
+
+ public:
+ const_integer(long value);
+
+ value_type getType() const;
+ int toInt() const;
+ double toFloat() const;
+ bool toBoolean() const;
+ string toString() const;
+
+ ref<value> duplicate();
+
+ ref<value> callMethod(string const &identifier,parameter_list const ¶meters);
+
+ ref<value> operatorUnary(operator_id op) const;
+ ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+ };
+
+ class integer : public const_integer {
+ private:
+ typedef const_integer super;
+
+ public:
+ integer(long value);
+
+ ref<value> operatorUnaryModifying(operator_id op);
+ ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+ };
+
+ class js_string : public value_with_methods {
+ private:
+ typedef value_with_methods super;
+
+ protected:
+ string Value;
+
+ public:
+ js_string(string const &value);
+
+ value_type getType() const;
+ string toString() const;
+ bool toBoolean() const;
+ string stringify() const;
+
+ ref<value> duplicate();
+
+ ref<value> lookup(string const &identifier);
+ ref<value> callMethod(string const &identifier,parameter_list const ¶meters);
+
+ ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+ ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+ };
+
+ class lvalue : public value {
+ protected:
+ ref<value> Reference;
+
+ public:
+ lvalue(ref<value> ref);
+
+ value_type getType() const;
+ string toString() const;
+ int toInt() const;
+ double toFloat() const;
+ bool toBoolean() const;
+ string stringify() const;
+
+ ref<value> eliminateWrappers();
+ ref<value> duplicate();
+
+ ref<value> lookup(string const &identifier);
+ ref<value> subscript(value const &index);
+ ref<value> call(parameter_list const ¶meters);
+ ref<value> callAsMethod(ref<value> instance,parameter_list const ¶meters);
+ ref<value> construct(parameter_list const ¶meters);
+ ref<value> assign(ref<value> op2);
+
+ ref<value> operatorUnary(operator_id op) const;
+ ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+ ref<value> operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const;
+ ref<value> operatorUnaryModifying(operator_id op);
+ ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+ };
+
+ class constant_wrapper : public value {
+ protected:
+ ref<value> Constant;
+
+ public:
+ constant_wrapper(ref<value> val);
+
+ value_type getType() const;
+ string toString() const;
+ int toInt() const;
+ double toFloat() const;
+ bool toBoolean() const;
+ string stringify() const;
+
+ ref<value> eliminateWrappers();
+ ref<value> duplicate();
+
+ ref<value> lookup(string const &identifier);
+ ref<value> subscript(value const &index);
+ ref<value> call(parameter_list const ¶meters) const;
+ ref<value> callAsMethod(ref<value> instance,parameter_list const ¶meters);
+ ref<value> construct(parameter_list const ¶meters);
+ ref<value> assign(ref<value> value);
+
+ ref<value> operatorUnary(operator_id op) const;
+ ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+ ref<value> operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const;
+ ref<value> operatorUnaryModifying(operator_id op);
+ ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+ };
+
+ class callable_with_parameters : public value {
+ public:
+ typedef vector<string> parameter_name_list;
+
+ protected:
+ parameter_name_list ParameterNameList;
+
+ public:
+ callable_with_parameters(parameter_name_list const &pnames);
+
+ void addParametersTo(list_scope &scope,parameter_list const ¶meters) const;
+ static ref<value> evaluateBody(expression &body,context const &ctx);
+ };
+
+ class function : public callable_with_parameters {
+ typedef callable_with_parameters super;
+ ref<expression> Body;
+ ref<value> LexicalScope;
+
+ public:
+ function(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope);
+
+ value_type getType() const{
+ return VT_FUNCTION;
+ }
+
+ ref<value> duplicate();
+
+ ref<value> call(parameter_list const ¶meters);
+ };
+
+ class method : public callable_with_parameters {
+ typedef callable_with_parameters super;
+ ref<expression> Body;
+ ref<value> LexicalScope;
+
+ public:
+ method(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope);
+
+ value_type getType() const{
+ return VT_FUNCTION;
+ }
+
+ ref<value> duplicate();
+
+ ref<value> callAsMethod(ref<value> instance,parameter_list const ¶meters);
+ };
+
+ class constructor : public callable_with_parameters {
+ typedef callable_with_parameters super;
+ ref<expression> Body;
+ ref<value> LexicalScope;
+
+ public:
+ constructor(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope);
+
+ value_type getType() const{
+ return VT_FUNCTION;
+ }
+
+ ref<value> duplicate();
+ ref<value> callAsMethod(ref<value> instance,parameter_list const ¶meters);
+ };
+
+ class js_class : public value {
+ class super_instance_during_construction : public value {
+ // this object constructs the superclass
+ // a) if it is called, by calling the super constructor
+ // with the aprropriate parameters
+ // b) implicitly with no super constructor arguments,
+ // if the super object is referenced explicitly
+
+ ref<value> SuperClass;
+ ref<value> SuperClassInstance;
+
+ public:
+ super_instance_during_construction(ref<value> super_class);
+
+ value_type getType() const {
+ return VT_OBJECT;
+ }
+
+ ref<value> call(parameter_list const ¶meters);
+ ref<value> lookup(string const &identifier);
+
+ ref<value> getSuperClassInstance();
+ };
+
+ typedef vector<ref<expression> > declaration_list;
+
+ ref<value> LexicalScope;
+ ref<value> SuperClass;
+ ref<value> Constructor;
+ ref<value> StaticMethodScope;
+ ref<value> MethodScope;
+ ref<value> StaticVariableScope;
+ declaration_list VariableList;
+
+ public:
+ js_class(ref<value> lex_scope,ref<value> super_class,ref<value> constructor,
+ ref<value> static_method_scope,ref<value> method_scope,
+ ref<value> static_variable_scope,declaration_list const &variable_list);
+
+ value_type getType() const {
+ return VT_TYPE;
+ }
+
+ ref<value> duplicate();
+ ref<value> lookup(string const &identifier);
+ ref<value> lookupLocal(string const &identifier);
+ ref<value> construct(parameter_list const ¶meters);
+ };
+
+ class js_class_instance : public value {
+ class bound_method : public value {
+ ref<value> Instance;
+ ref<value> Method;
+
+ public:
+ bound_method(ref<value> instance,ref<value> method);
+
+ value_type getType() const {
+ return VT_BOUND_METHOD;
+ }
+
+ ref<value> call(parameter_list const ¶meters);
+ };
+
+ ref<value> SuperClassInstance;
+ ref<js_class,value> Class;
+ ref<value> MethodScope;
+ ref<value> VariableScope;
+
+ public:
+ js_class_instance(ref<js_class,value> cls,ref<value> method_scope,
+ ref<value> variable_scope);
+
+ void setSuperClassInstance(ref<value> super_class_instance);
+
+ value_type getType() const {
+ return VT_OBJECT;
+ }
+
+ ref<value> duplicate();
+ ref<value> lookup(string const &identifier);
+ };
+
+ class js_array_constructor : public value {
+ public:
+ value_type getType() const {
+ return VT_TYPE;
+ }
+
+ ref<value> duplicate();
+ ref<value> construct(parameter_list const ¶meters);
+ };
+
+ // expressions ----------------------------------------------------------
+ class expression {
+ code_location Location;
+
+ public:
+ expression(code_location const &loc);
+ virtual ~expression();
+ virtual ref<value> evaluate(context const &ctx) const = 0;
+
+ code_location const &getCodeLocation() const {
+ return Location;
+ }
+ };
+
+ class constant : public expression {
+ ref<value> Value;
+ public:
+ constant(ref<value> val,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class unary_operator : public expression {
+ value::operator_id Operator;
+ ref<expression> Operand;
+
+ public:
+ unary_operator(value::operator_id opt,ref<expression> opn,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class modifying_unary_operator : public expression {
+ value::operator_id Operator;
+ ref<expression> Operand;
+
+ public:
+ modifying_unary_operator(value::operator_id opt,ref<expression> opn,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class binary_operator : public expression {
+ value::operator_id Operator;
+ ref<expression> Operand1;
+ ref<expression> Operand2;
+
+ public:
+ binary_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class binary_shortcut_operator : public expression {
+ value::operator_id Operator;
+ ref<expression> Operand1;
+ ref<expression> Operand2;
+
+ public:
+ binary_shortcut_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class modifying_binary_operator : public expression {
+ value::operator_id Operator;
+ ref<expression> Operand1;
+ ref<expression> Operand2;
+
+ public:
+ modifying_binary_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class ternary_operator : public expression {
+ ref<expression> Operand1;
+ ref<expression> Operand2;
+ ref<expression> Operand3;
+
+ public:
+ ternary_operator(ref<expression> opn1,ref<expression> opn2,ref<expression> opn3,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class subscript_operation : public expression {
+ ref<expression> Operand1;
+ ref<expression> Operand2;
+
+ public:
+ subscript_operation(ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class lookup_operation : public expression {
+ ref<expression> Operand;
+ string Identifier;
+
+ public:
+ lookup_operation(string const &id,code_location const &loc);
+ lookup_operation(ref<expression> opn,string const &id,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class assignment : public expression {
+ ref<expression> Operand1;
+ ref<expression> Operand2;
+
+ public:
+ assignment(ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class basic_call : public expression {
+ public:
+ typedef vector<ref<expression> > parameter_expression_list;
+ typedef vector<ref<value> > parameter_value_list;
+
+ private:
+ parameter_expression_list ParameterExpressionList;
+
+ public:
+ basic_call(parameter_expression_list const &pexps,code_location const &loc);
+ void makeParameterValueList(context const &ctx,parameter_value_list &pvalues) const;
+ };
+
+ class function_call : public basic_call {
+ typedef basic_call super;
+ ref<expression> Function;
+
+ public:
+ function_call(ref<expression> fun,parameter_expression_list const &pexps,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class construction : public basic_call {
+ typedef basic_call super;
+ ref<expression> Class;
+
+ public:
+ construction(ref<expression> cls,parameter_expression_list const &pexps,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ // declarations -----------------------------------------------------------
+ class variable_declaration : public expression {
+ protected:
+ string Identifier;
+ ref<expression> DefaultValue;
+
+ public:
+ variable_declaration(string const &id,ref<expression> def_value,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class constant_declaration : public expression {
+ protected:
+ string Identifier;
+ ref<expression> DefaultValue;
+
+ public:
+ constant_declaration(string const &id,ref<expression> def_value,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class function_declaration : public expression {
+ public:
+ typedef function::parameter_name_list parameter_name_list;
+
+ private:
+ string Identifier;
+ parameter_name_list ParameterNameList;
+ ref<expression> Body;
+
+ public:
+ function_declaration(string const &id,parameter_name_list const &pnames,
+ ref<expression> body,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class method_declaration : public expression {
+ public:
+ typedef method::parameter_name_list parameter_name_list;
+
+ private:
+ string Identifier;
+ parameter_name_list ParameterNameList;
+ ref<expression> Body;
+
+ public:
+ method_declaration(string const &id,parameter_name_list const &pnames,
+ ref<expression> body,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class constructor_declaration : public expression {
+ public:
+ typedef method::parameter_name_list parameter_name_list;
+
+ private:
+ parameter_name_list ParameterNameList;
+ ref<expression> Body;
+
+ public:
+ constructor_declaration(parameter_name_list const &pnames,
+ ref<expression> body,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_class_declaration : public expression {
+ typedef vector<ref<expression> > declaration_list;
+
+ string Identifier;
+ ref<expression> SuperClass;
+ ref<expression> ConstructorDeclaration;
+ declaration_list StaticMethodList;
+ declaration_list MethodList;
+ declaration_list StaticVariableList;
+ declaration_list VariableList;
+
+ public:
+ js_class_declaration(string const &id,ref<expression> superclass,
+ code_location const &loc);
+
+ ref<value> evaluate(context const &ctx) const;
+
+ void setConstructor(ref<expression> decl);
+ void addStaticMethod(ref<expression> decl);
+ void addMethod(ref<expression> decl);
+ void addStaticVariable(ref<expression> decl);
+ void addVariable(ref<expression> decl);
+ };
+
+ // instructions ---------------------------------------------------------
+ class instruction_list : public expression {
+ typedef vector<ref<expression> > expression_list;
+ expression_list ExpressionList;
+
+ public:
+ instruction_list(code_location const &loc)
+ : expression(loc) {
+ }
+ ref<value> evaluate(context const &ctx) const;
+ void add(ref<expression> expr);
+ };
+
+ class scoped_instruction_list : public instruction_list {
+ public:
+ scoped_instruction_list(code_location const &loc)
+ : instruction_list(loc) {
+ }
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_if : public expression {
+ ref<expression> Conditional;
+ ref<expression> IfExpression;
+ ref<expression> IfNotExpression;
+
+ public:
+ js_if(ref<expression> cond,ref<expression> ifex,ref<expression> ifnotex,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_while : public expression {
+ ref<expression> Conditional;
+ ref<expression> LoopExpression;
+ bool HasLabel;
+ string Label;
+
+ public:
+ js_while(ref<expression> cond,ref<expression> loopex,code_location const &loc);
+ js_while(ref<expression> cond,ref<expression> loopex,string const &Label,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_do_while : public expression {
+ ref<expression> Conditional;
+ ref<expression> LoopExpression;
+ bool HasLabel;
+ string Label;
+
+ public:
+ js_do_while(ref<expression> cond,ref<expression> loopex,code_location const &loc);
+ js_do_while(ref<expression> cond,ref<expression> loopex,string const &Label,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_for : public expression {
+ ref<expression> Initialization;
+ ref<expression> Conditional;
+ ref<expression> Update;
+ ref<expression> LoopExpression;
+ bool HasLabel;
+ string Label;
+
+ public:
+ js_for(ref<expression> init,ref<expression> cond,ref<expression> update,ref<expression> loop,code_location const &loc);
+ js_for(ref<expression> init,ref<expression> cond,ref<expression> update,ref<expression> loop,string const &label,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_for_in : public expression {
+ ref<expression> Iterator;
+ ref<expression> Array;
+ ref<expression> LoopExpression;
+ bool HasLabel;
+ string Label;
+
+ public:
+ js_for_in(ref<expression> iter,ref<expression> array,ref<expression> loop,code_location const &loc);
+ js_for_in(ref<expression> iter,ref<expression> array,ref<expression> loop,string const &label,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_return : public expression {
+ ref<expression> ReturnValue;
+
+ public:
+ js_return(ref<expression> retval,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_break : public expression {
+ bool HasLabel;
+ string Label;
+
+ public:
+ js_break(code_location const &loc);
+ js_break(string const &label,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_continue : public expression {
+ bool HasLabel;
+ string Label;
+
+ public:
+ js_continue(code_location const &loc);
+ js_continue(string const &label,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class break_label : public expression {
+ string Label;
+ ref<expression> Expression;
+
+ public:
+ break_label(string const &label,ref<expression> expr,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ };
+
+ class js_switch : public expression {
+ bool HasLabel;
+ string Label;
+ ref<expression> Discriminant;
+
+ struct case_label {
+ ref<expression> DiscriminantValue;
+ ref<expression> Expression;
+ };
+ typedef vector<case_label> case_list;
+ case_list CaseList;
+
+ public:
+ js_switch(ref<expression> discriminant,code_location const &loc);
+ js_switch(ref<expression> discriminant,string const &label,code_location const &loc);
+ ref<value> evaluate(context const &ctx) const;
+ void addCase(ref<expression> dvalue,ref<expression> expr);
+ };
+ }
+ }
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Numeric conversions
+// ----------------------------------------------------------------------------
+// (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_NUMCONV
+#define IXLIB_NUMCONV
+
+
+
+
+#include <ixlib_base.hh>
+#include <ixlib_string.hh>
+
+
+
+
+// Macros ---------------------------------------------------------------------
+#define IXLIB_NUMCHARS "0123456789ABCDEF"
+
+
+
+
+// Functions ------------------------------------------------------------------
+namespace ixion {
+ std::string float2dec(double value);
+ std::string float2dec(double value,unsigned int precision);
+ std::string unsigned2base(unsigned long value,char digits = 0,char radix = 10);
+ inline std::string unsigned2dec(unsigned long value,char digits = 0)
+ { return unsigned2base(value,digits,10); }
+ inline std::string unsigned2hex(unsigned long value,char digits = 0)
+ { return unsigned2base(value,digits,16); }
+ inline std::string unsigned2bin(unsigned long value,char digits = 0)
+ { return unsigned2base(value,digits,2); }
+ inline std::string unsigned2oct(unsigned long value,char digits = 0)
+ { return unsigned2base(value,digits,8); }
+ std::string signed2base(signed long value,char digits = 0,char radix = 10);
+ inline std::string signed2dec(signed long value,char digits = 0)
+ { return signed2base(value,digits,10); }
+ inline std::string signed2hex(signed long value,char digits = 0)
+ { return signed2base(value,digits,16); }
+ inline std::string signed2bin(signed long value,char digits = 0)
+ { return signed2base(value,digits,2); }
+ inline std::string signed2oct(signed long value,char digits = 0)
+ { return signed2base(value,digits,8); }
+
+ std::string bytes2dec(TSize bytes);
+
+ unsigned long evalNumeral(std::string const &numeral,unsigned radix = 10);
+ double evalFloat(std::string const &numeral);
+ unsigned long evalUnsigned(std::string const &numeral,unsigned default_base = 10);
+ signed long evalSigned(std::string const &numeral,unsigned default_base = 10);
+ }
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : numeric / order processing
+// ----------------------------------------------------------------------------
+// (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_NUMERIC
+#define IXLIB_NUMERIC
+
+
+
+
+#include <cstring>
+#include <ixlib_base.hh>
+#include <ixlib_exgen.hh>
+
+
+
+
+// Macros ---------------------------------------------------------------------
+#ifdef _GNUC_
+ #define NUM_MIN(a,b) ( (a)<?(b) )
+ #define NUM_MAX(a,b) ( (a)>?(b) )
+ #define NUM_ABS(a) ( (a)<0 ? (-(a)) : (a) )
+#else
+ #define NUM_MIN(a,b) ( (a)<(b) ? (a) : (b) )
+ #define NUM_MAX(a,b) ( (a)>(b) ? (a) : (b) )
+ #define NUM_ABS(a) ( (a)<0 ? (-(a)) : (a) )
+#endif
+
+#define NUM_LIMIT(lower,value,upper) \
+ ( NUM_MAX(lower,NUM_MIN(upper,vallue)) )
+#define NUM_INBOUND(lower,value,upper) \
+ (((lower) <= (value)) && ((value) <= (upper)))
+#define NUM_OVERLAP(a1,a2,b1,b2) \
+ ((((a1)<=(b1))&&((a2)>(b1)))||(((a1)<(b2))&&((a2)>(b2)))||(((a1)>=(b1))&&((a2)<=(b2))))
+#define NUM_CIRCLEINC(index,size) \
+ ( ((index)+1) >= (size) ? 0 : ((index)+1) )
+#define NUM_CIRCLEDIST(head,tail,size) \
+ ( (head)<(tail) ? ((head)+(size)-(tail)) : ((head)-(tail)) )
+
+
+
+
+// Primitive inlines ---------------------------------------------------------
+namespace ixion {
+ inline signed short sgn(signed long value);
+ inline bool getBit(unsigned long value,char bit);
+ inline TUnsigned8 hiByte(TUnsigned16 value);
+ inline TUnsigned16 hiWord(TUnsigned32 value);
+ inline TUnsigned8 loByte(TUnsigned16 value);
+ inline TUnsigned16 loWord(TUnsigned32 value);
+ inline TUnsigned16 makeWord(TUnsigned8 hi,TUnsigned8 lo);
+ inline TUnsigned32 makeDWord(TUnsigned16 hi,TUnsigned16 lo);
+
+
+
+
+// BCD encoding ---------------------------------------------------------------
+ unsigned long unsigned2BCD(unsigned long value);
+ unsigned long BCD2unsigned(unsigned long value);
+
+
+
+
+// Primitive inlines ---------------------------------------------------------
+ inline signed short ixion::sgn(signed long value) {
+ return (value<0) ? -1 : ( (value>0) ? 1 : 0);
+ }
+
+
+
+
+ inline bool ixion::getBit(unsigned long value,char bit) {
+ return (value >> bit) & 1;
+ }
+
+
+
+
+ inline TUnsigned8 ixion::hiByte(TUnsigned16 value) {
+ return value >> 8;
+ }
+
+
+
+
+ inline TUnsigned16 ixion::hiWord(TUnsigned32 value) {
+ return value >> 16;
+ }
+
+
+
+
+ inline TUnsigned8 ixion::loByte(TUnsigned16 value) {
+ return value & 0xff;
+ }
+
+
+
+
+ inline TUnsigned16 ixion::loWord(TUnsigned32 value) {
+ return value & 0xffff;
+ }
+
+
+
+
+ inline TUnsigned16 ixion::makeWord(TUnsigned8 hi,TUnsigned8 lo) {
+ return (TUnsigned16) hi << 8 | lo;
+ }
+
+
+
+
+ inline TUnsigned32 ixion::makeDWord(TUnsigned16 hi,TUnsigned16 lo) {
+ return (TUnsigned32) hi << 16 | lo;
+ }
+ }
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Random numbers
+// ----------------------------------------------------------------------------
+// (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_RANDOM
+#define IXLIB_RANDOM
+
+
+
+
+#include <cstdlib>
+#include <cmath>
+#include <ctime>
+#include <ixlib_base.hh>
+#include <ixlib_numeric.hh>
+
+
+
+
+namespace ixion {
+ class float_random {
+ double Seed;
+
+ public:
+ float_random()
+ : Seed(1)
+ { }
+
+ void init() {
+ double current_time = time(NULL);
+ Seed = current_time*sin(current_time);
+ }
+ void init(double seed)
+ { Seed = NUM_ABS(seed); }
+
+ /// Generate one random number in the interval [0,max).
+ double operator()(double max = 1) {
+ // normalize
+ while (Seed > 3) Seed = log(Seed);
+ Seed -= floor(Seed);
+ Seed = pow(Seed+Pi,8);
+ Seed -= floor(Seed);
+ return Seed*max;
+ }
+ };
+
+
+
+
+ class int_random {
+ float_random Generator;
+
+ public:
+ int_random()
+ { }
+
+ void init()
+ { Generator.init(); }
+ void init(unsigned seed)
+ { Generator.init(seed); }
+
+ /// Generate one random number in the interval [0,max).
+ unsigned operator()(unsigned max = 32768) {
+ unsigned num = rng8() + (rng8() << 7) + (rng8() << 14) + (rng8() << 21) + (rng8() << 28);
+ return num % max;
+ }
+ private:
+ TUnsigned8 rng8() {
+ return (TUnsigned8) (Generator()*256);
+ }
+ };
+ }
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Regular expressions string object
+// ----------------------------------------------------------------------------
+// (c) Copyright 1998 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_RE
+#define IXLIB_RE
+
+
+
+
+#include <vector>
+#include <memory>
+#include <ixlib_exgen.hh>
+#include <ixlib_string.hh>
+
+
+
+
+// Regex exceptions -----------------------------------------------------------
+#define ECRE_INVQUANTIFIER 0
+#define ECRE_UNBALBACKREF 1
+#define ECRE_INVESCAPE 2
+#define ECRE_INVBACKREF 3
+#define ECRE_UNTERMCLASS 4
+#define ECRE_NOPATTERN 5
+
+
+
+
+namespace ixion {
+ class regex_exception : public base_exception {
+ public:
+ regex_exception(TErrorCode error,char const *info = NULL,char *module = NULL,TIndex line = 0);
+ virtual char *getText() const;
+ };
+ }
+
+
+
+
+// Regex token macros ---------------------------------------------------------
+#define XSTRRE_LITERAL '\\'
+#define XSTRRE_BACKREF '\\'
+#define XSTRRE_ESCAPESEQ '\\'
+#define XSTRRE_ANYCHAR '.'
+#define XSTRRE_START '^'
+#define XSTRRE_END '$'
+#define XSTRRE_ALTERNATIVE '|'
+#define XSTRRE_CLASSSTART '['
+#define XSTRRE_CLASSNEG '^'
+#define XSTRRE_CLASSRANGE '-'
+#define XSTRRE_CLASSSTOP ']'
+
+#define XSTRRE_BACKREFSTART '('
+#define XSTRRE_BACKREFSTOP ')'
+
+#define XSTRREQ_0PLUS '*'
+#define XSTRREQ_1PLUS '+'
+#define XSTRREQ_01 '?'
+#define XSTRREQ_START '{'
+#define XSTRREQ_RANGE ','
+#define XSTRREQ_STOP '}'
+#define XSTRREQ_NONGREEDY '?'
+
+
+
+
+namespace ixion {
+ /**
+ A class implementing a generic regular expression matcher not only for strings.
+ If you are looking for a usual regular expresion parser, look at
+ ixion::regex_string.
+
+ If you query anything about the last match, and that last match did
+ never happen, behavior is undefined.
+ */
+
+ template<class T>
+ class regex {
+ protected:
+ // various helper classes -----------------------------------------------
+ class backref_stack {
+ private:
+ struct backref_entry {
+ enum { OPEN,CLOSE } Type;
+ TIndex Index;
+ };
+
+ typedef std::vector<backref_entry> internal_stack;
+
+ internal_stack Stack;
+
+ public:
+ typedef TSize rewind_info;
+
+ void open(TIndex index);
+ void close(TIndex index);
+
+ rewind_info getRewindInfo() const;
+ void rewind(rewind_info ri);
+ void clear();
+
+ TSize size();
+ T get(TIndex number,T const &candidate) const;
+ };
+
+
+
+
+ // matchers -------------------------------------------------------------
+ class matcher {
+ protected:
+ matcher *Next;
+ bool OwnNext;
+ TSize MatchLength;
+
+ public:
+ matcher();
+ virtual ~matcher();
+
+ virtual matcher *duplicate() const = 0;
+
+ TSize getMatchLength() const {
+ return MatchLength;
+ }
+ TSize subsequentMatchLength() const;
+ virtual TSize minimumMatchLength() const = 0;
+ TSize minimumSubsequentMatchLength() const;
+
+ matcher *getNext() const {
+ return Next;
+ }
+ virtual void setNext(matcher *next,bool ownnext = true) {
+ Next = next;
+ OwnNext = ownnext;
+ }
+
+ // this routine must set the MatchLength member correctly.
+ virtual bool match(backref_stack &brstack,T const &candidate,TIndex at)
+ = 0;
+
+ protected:
+ bool matchNext(backref_stack &brstack,T const &candidate,TIndex at) const {
+ return Next ? Next->match(brstack,candidate,at) : true;
+ }
+ void copy(matcher const *src);
+ };
+
+
+
+
+ class quantifier : public matcher {
+ private:
+ typedef matcher super;
+ bool Greedy,MaxValid;
+ TSize MinCount,MaxCount;
+ matcher *Quantified;
+
+ struct backtrack_stack_entry {
+ TIndex Index;
+ backref_stack::rewind_info RewindInfo;
+ };
+
+ public:
+ quantifier()
+ : Quantified(NULL) {
+ }
+ quantifier(bool greedy,TSize mincount);
+ quantifier(bool greedy,TSize mincount,TSize maxcount);
+ ~quantifier();
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const;
+
+ void setQuantified(matcher *quantified) {
+ Quantified = quantified;
+ }
+ bool match(backref_stack &brstack,T const &candidate,TIndex at);
+
+ protected:
+ void copy(quantifier const *src);
+ };
+
+
+
+
+ class sequence_matcher : public matcher {
+ T MatchStr;
+
+ public:
+ sequence_matcher(T const &matchstr);
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const {
+ return MatchStr.size();
+ }
+ bool match(backref_stack &brstack,T const &candidate,TIndex at);
+ };
+
+
+
+
+ class any_matcher : public matcher {
+ public:
+ any_matcher() {
+ MatchLength = 1;
+ }
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const {
+ return 1;
+ }
+ bool match(backref_stack &brstack,T const &candidate,TIndex at) {
+ return at < candidate.size() && matchNext(brstack,candidate,at+1);
+ }
+ };
+
+
+
+
+ class start_matcher : public matcher {
+ public:
+ start_matcher() {
+ MatchLength = 0;
+ }
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const {
+ return 0;
+ }
+ bool match(backref_stack &brstack,T const &candidate,TIndex at);
+ };
+
+
+
+
+ class end_matcher : public matcher {
+ public:
+ end_matcher() {
+ MatchLength = 0;
+ }
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const {
+ return 0;
+ }
+ bool match(backref_stack &brstack,T const &candidate,TIndex at);
+ };
+
+
+
+
+ class backref_open_matcher : public matcher {
+ public:
+ backref_open_matcher() {
+ MatchLength = 0;
+ }
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const {
+ return 0;
+ }
+ bool match(backref_stack &brstack,T const &candidate,TIndex at);
+ };
+
+
+
+
+ class backref_close_matcher : public matcher {
+ public:
+ backref_close_matcher() {
+ MatchLength = 0;
+ }
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const {
+ return 0;
+ }
+ bool match(backref_stack &brstack,T const &candidate,TIndex at);
+ };
+
+
+
+
+ class alternative_matcher : public matcher {
+ // The connector serves two purposes:
+ // a) be a null-matcher that re-unites the different alternate token
+ // sequences
+ // b) make the end of each sequence identifiable to be able to compute
+ // the match length
+
+ class connector : public matcher {
+ public:
+ matcher *duplicate() const {
+ return NULL;
+ }
+
+ TSize minimumMatchLength() const {
+ return 0;
+ }
+ bool match(backref_stack &brstack,T const &candidate,TIndex at);
+ };
+
+ typedef matcher super;
+ typedef std::vector<matcher *> alt_list;
+ alt_list AltList;
+ connector Connector;
+
+ public:
+ ~alternative_matcher();
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const;
+ void setNext(matcher *next,bool ownnext = true);
+ void addAlternative(matcher *alternative);
+ bool match(backref_stack &brstack,T const &candidate,TIndex at);
+
+ protected:
+ void copy(alternative_matcher const *src);
+ };
+
+
+
+
+ class backref_matcher : public matcher {
+ TIndex Backref;
+
+ public:
+ backref_matcher(TIndex backref);
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const {
+ return 0;
+ }
+ bool match(backref_stack &brstack,T const &candidate,TIndex at);
+ };
+
+ // instance data --------------------------------------------------------
+ std::auto_ptr<matcher> ParsedRegex;
+ backref_stack BackrefStack;
+ T LastCandidate;
+ TIndex MatchIndex;
+ TSize MatchLength;
+
+ public:
+ // interface ------------------------------------------------------------
+ regex();
+ regex(regex const &src);
+
+ regex &operator=(regex const &src);
+
+ bool match(T const &candidate,TIndex from = 0);
+ bool matchAt(T const &candidate,TIndex at = 0);
+
+ // Queries pertaining to the last match
+ TIndex getMatchIndex() {
+ return MatchIndex;
+ }
+ TSize getMatchLength() {
+ return MatchLength;
+ }
+ std::string getMatch() {
+ return T(LastCandidate.begin()+MatchIndex,
+ LastCandidate.begin()+MatchIndex+MatchLength);
+ }
+ TSize countBackrefs() {
+ return BackrefStack.size();
+ }
+ T getBackref(TIndex index) {
+ return BackrefStack.get(index,LastCandidate);
+ }
+ };
+
+
+
+ /**
+ A regular expression parser and matcher.
+
+ Backref numbering starts at \0.
+
+ ReplaceAll does not set the MatchIndex/MatchGlobal members.
+
+ What is there is compatible with perl5. (See man perlre or
+ http://www.cpan.org/doc/manual/html/pod/perlre.html)
+ However, not everything is there. Here's what's missing:
+
+ <ul>
+ <li> \Q-\E,\b,\B,\A,\Z,\z
+ <li> discerning between line and string
+ <li> (?#comments)
+ <li> (?:clustering)
+ <li> (?=positive lookahead assumptions)
+ <li> (?!negative lookahead assumptions
+ <li> (?<=positive lookbehind assumptions)
+ <li> (?<!negative lookbehind assumptions
+ <li> (?>independent substrings)
+ <li> modifiers such as "case independent"
+ </ul>
+
+ as well as all the stuff involving perl code, naturally.
+ None of these is actually hard to hack in. If you want them,
+ pester me or try for yourself (and submit patches!)
+ */
+ class regex_string : public regex<std::string> {
+ private:
+ class class_matcher : public regex<std::string>::matcher {
+ private:
+ typedef regex<std::string>::matcher super;
+ static TSize const CharValues = 256;
+ bool Set[CharValues];
+ bool Negated;
+
+ public:
+ class_matcher();
+ class_matcher(std::string const &cls);
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const {
+ return 1;
+ }
+ bool match(backref_stack &brstack,std::string const &candidate,TIndex at);
+
+ private:
+ void expandClass(std::string const &cls);
+
+ protected:
+ void copy(class_matcher const *src);
+ };
+
+
+
+
+ class special_class_matcher : public regex<std::string>::matcher {
+ public:
+ enum type { DIGIT,NONDIGIT,ALNUM,NONALNUM,SPACE,NONSPACE };
+
+ private:
+ type Type;
+
+ public:
+ special_class_matcher(type tp);
+
+ matcher *duplicate() const;
+
+ TSize minimumMatchLength() const {
+ return 1;
+ }
+ bool match(backref_stack &brstack,std::string const &candidate,TIndex at);
+ };
+
+
+
+
+ public:
+ regex_string() {
+ }
+ regex_string(std::string const &str) {
+ parse(str);
+ }
+ regex_string(char const *s) {
+ parse(s);
+ }
+
+ void parse(std::string const &expr);
+
+ std::string replaceAll(std::string const &candidate,std::string const &replacement,
+ TIndex from = 0);
+
+ private:
+ regex<std::string>::matcher *parseRegex(std::string const &expr);
+ quantifier *parseQuantifier(std::string const &expr,TIndex &at);
+ bool isGreedy(std::string const &expr,TIndex &at);
+ };
+ }
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Regular expressions string object.
+// ----------------------------------------------------------------------------
+// (c) Copyright 1998 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <stack>
+#include <cctype>
+#include "ixlib_i18n.hh"
+#include <ixlib_exgen.hh>
+#include <ixlib_numeric.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_re.hh>
+
+
+
+
+// regex::backref_stack -------------------------------------------------------
+template<class T>
+void ixion::regex<T>::backref_stack::open(TIndex index) {
+ backref_entry entry = { backref_entry::OPEN,index };
+ Stack.push_back(entry);
+ }
+
+
+
+
+template<class T>
+void ixion::regex<T>::backref_stack::close(TIndex index) {
+ backref_entry entry = { backref_entry::CLOSE,index };
+ Stack.push_back(entry);
+ }
+
+
+
+
+template<class T>
+ixion::regex<T>::backref_stack::rewind_info
+ixion::regex<T>::backref_stack::getRewindInfo() const {
+ return Stack.size();
+ }
+
+
+
+
+template<class T>
+void ixion::regex<T>::backref_stack::rewind(rewind_info ri) {
+ Stack.erase(Stack.begin()+ri,Stack.end());
+ }
+
+
+
+
+template<class T>
+void ixion::regex<T>::backref_stack::clear() {
+ Stack.clear();
+ }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::backref_stack::size() {
+ TSize result = 0;
+ FOREACH_CONST(first,Stack,internal_stack)
+ if (first->Type == backref_entry::OPEN) result++;
+ return result;
+ }
+
+
+
+
+template<class T>
+T ixion::regex<T>::backref_stack::get(TIndex number,T const &candidate) const {
+ TIndex level = 0,next_index = 0;
+ TIndex start;
+ TIndex startlevel;
+
+ internal_stack::const_iterator first = Stack.begin(),last = Stack.end();
+ while (first != last) {
+ if (first->Type == backref_entry::OPEN) {
+ if (number == next_index) {
+ start = first->Index;
+ startlevel = level;
+ level++;
+ break;
+ }
+ next_index++;
+ level++;
+ }
+ if (first->Type == backref_entry::CLOSE)
+ level--;
+ first++;
+ }
+
+ if (first == last)
+ EX_THROW(regex,ECRE_INVBACKREF)
+
+ first++;
+
+ while (first != last) {
+ if (first->Type == backref_entry::OPEN)
+ level++;
+ if (first->Type == backref_entry::CLOSE) {
+ level--;
+ if (startlevel == level)
+ return candidate.substr(start,first->Index - start);
+ }
+ first++;
+ }
+ EX_THROW(regex,ECRE_UNBALBACKREF)
+ }
+
+
+
+
+// regex::matcher -------------------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher::matcher()
+ : Next(NULL) {
+ }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher::~matcher() {
+ if (Next && OwnNext)
+ delete Next;
+ }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::matcher::subsequentMatchLength() const {
+ TSize totalml = 0;
+ matcher const *object = this;
+ while (object) {
+ totalml += object->MatchLength;
+ object = object->Next;
+ }
+ return totalml;
+ }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::matcher::minimumSubsequentMatchLength() const {
+ TSize totalml = 0;
+ matcher const *object = this;
+ while (object) {
+ totalml += object->minimumMatchLength();
+ object = object->Next;
+ }
+ return totalml;
+ }
+
+
+
+
+template<class T>
+void ixion::regex<T>::matcher::copy(matcher const *src) {
+ if (src->Next && src->OwnNext)
+ setNext(src->Next->duplicate(),src->OwnNext);
+ else
+ setNext(NULL);
+ }
+
+
+
+
+// regex::quantifier ----------------------------------------------------------
+template<class T>
+ixion::regex<T>::quantifier::quantifier(bool greedy,TSize mincount)
+ : Greedy(greedy),MaxValid(false),MinCount(mincount) {
+ }
+
+
+
+
+template<class T>
+ixion::regex<T>::quantifier::quantifier(bool greedy,TSize mincount,TSize maxcount)
+ : Greedy(greedy),MaxValid(true),MinCount(mincount),MaxCount(maxcount) {
+ }
+
+
+
+
+template<class T>
+ixion::regex<T>::quantifier::~quantifier() {
+ if (Quantified)
+ delete Quantified;
+ }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::quantifier::duplicate() const {
+ quantifier *dupe = new quantifier();
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::quantifier::minimumMatchLength() const {
+ if (Quantified)
+ return MinCount * Quantified->minimumMatchLength();
+ else
+ return 0;
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::quantifier::match(backref_stack &brstack,T const &candidate,TIndex at) {
+ // this routine does speculative matching, so it must pay close attention
+ // to rewind the backref stack appropriately.
+ // NB: matchNext does the rewinding automatically, whereas speculative
+ // matches of the quantified portion must be rewound.
+
+ // There should be at least one character in each match, we'd
+ // run to Baghdad otherwise.
+
+ if (!Quantified)
+ return matchNext(brstack,candidate,at);
+
+ // calculate accurate maximum match count
+ TSize quant_min = Quantified->minimumSubsequentMatchLength();
+ if (quant_min == 0) quant_min = 1;
+
+ TSize max_count = candidate.size() - at;
+ if (Next) max_count -= Next->minimumSubsequentMatchLength();
+ max_count = max_count/quant_min + 1;
+
+ if (MaxValid) max_count = NUM_MIN(max_count,MaxCount);
+
+ // check that at least MinCount matches take place (non-speculative)
+ TIndex idx = at;
+ for (TSize c = 1;c <= MinCount;c++)
+ if (Quantified->match(brstack,candidate,idx))
+ idx += Quantified->subsequentMatchLength();
+ else
+ return false;
+
+ // determine number of remaining matches
+ TSize remcount = max_count-MinCount;
+
+ // test for the remaining matches in a way that depends on Greedy flag
+ if (Greedy) {
+ // try to gobble up as many matches of quantified part as possible
+ // (speculative)
+
+ std::stack<backtrack_stack_entry> successful_indices;
+ { backtrack_stack_entry entry = { idx,brstack.getRewindInfo() };
+ successful_indices.push(entry);
+ }
+
+ while (Quantified->match(brstack,candidate,idx) && successful_indices.size()-1 < remcount) {
+ idx += Quantified->subsequentMatchLength();
+ backtrack_stack_entry entry = { idx,brstack.getRewindInfo() };
+ successful_indices.push(entry);
+ }
+
+ // backtrack until rest of sequence also matches
+ while (successful_indices.size() && !matchNext(brstack,candidate,successful_indices.top().Index)) {
+ brstack.rewind(successful_indices.top().RewindInfo);
+ successful_indices.pop();
+ }
+
+ if (successful_indices.size()) {
+ MatchLength = successful_indices.top().Index - at;
+ return true;
+ }
+ else return false;
+ }
+ else {
+ for (TSize c = 0;c <= remcount;c++) {
+ if (matchNext(brstack,candidate,idx)) {
+ MatchLength = idx-at;
+ return true;
+ }
+ // following part runs once too much, effectively:
+ // if c == remcount, idx may be increased, but the search fails anyway
+ // => no problem
+ if (Quantified->match(brstack,candidate,idx))
+ idx += Quantified->subsequentMatchLength();
+ else
+ return false;
+ }
+ return false;
+ }
+ }
+
+
+
+
+template<class T>
+void ixion::regex<T>::quantifier::copy(quantifier const *src) {
+ super::copy(src);
+ Greedy = src->Greedy;
+ MaxValid = src->MaxValid;
+ MinCount = src->MinCount;
+ MaxCount = src->MaxCount;
+ Quantified = src->Quantified->duplicate();
+ }
+
+
+
+
+// regex::sequence_matcher ------------------------------------------------------
+template<class T>
+ixion::regex<T>::sequence_matcher::sequence_matcher(T const &matchstr)
+ : MatchStr(matchstr) {
+ MatchLength = MatchStr.size();
+ }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::sequence_matcher::duplicate() const {
+ sequence_matcher *dupe = new sequence_matcher(MatchStr);
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::sequence_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+ if (at+MatchStr.size() > candidate.size()) return false;
+ return (T(candidate.begin()+at,candidate.begin()+at+MatchStr.size()) == MatchStr) &&
+ matchNext(brstack,candidate,at+MatchStr.size());
+ }
+
+
+
+
+// regex::any_matcher ---------------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::any_matcher::duplicate() const {
+ any_matcher *dupe = new any_matcher();
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+// regex::start_matcher ---------------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::start_matcher::duplicate() const {
+ start_matcher *dupe = new start_matcher();
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::start_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+ return (at == 0) && matchNext(brstack,candidate,at);
+ }
+
+
+
+
+// regex::end_matcher ---------------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::end_matcher::duplicate() const {
+ end_matcher *dupe = new end_matcher();
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::end_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+ return (at == candidate.size()) && matchNext(brstack,candidate,at);
+ }
+
+
+
+
+// regex::backref_open_matcher ------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::backref_open_matcher::duplicate() const {
+ backref_open_matcher *dupe = new backref_open_matcher();
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::backref_open_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+ backref_stack::rewind_info ri = brstack.getRewindInfo();
+ brstack.open(at);
+
+ bool result = matchNext(brstack,candidate,at);
+
+ if (!result)
+ brstack.rewind(ri);
+ return result;
+ }
+
+
+
+
+// regex::backref_close_matcher -----------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::backref_close_matcher::duplicate() const {
+ backref_close_matcher *dupe = new backref_close_matcher();
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::backref_close_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+ backref_stack::rewind_info ri = brstack.getRewindInfo();
+ brstack.close(at);
+
+ bool result = matchNext(brstack,candidate,at);
+
+ if (!result)
+ brstack.rewind(ri);
+ return result;
+ }
+
+
+
+
+// regex::alternative_matcher::connector --------------------------------------
+template<class T>
+bool ixion::regex<T>::alternative_matcher::connector::match(backref_stack &brstack,T const &candidate,TIndex at) {
+ return matchNext(brstack,candidate,at);
+ }
+
+
+
+
+// regex::alternative_matcher -------------------------------------------------
+template<class T>
+ixion::regex<T>::alternative_matcher::~alternative_matcher() {
+ while (AltList.size()) {
+ delete AltList.back();
+ AltList.pop_back();
+ }
+ }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::alternative_matcher::duplicate() const {
+ alternative_matcher *dupe = new alternative_matcher();
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::alternative_matcher::minimumMatchLength() const {
+ TSize result = 0;
+ bool is_first = true;
+
+ FOREACH_CONST(first,AltList,alt_list)
+ if (is_first) {
+ result = (*first)->minimumMatchLength();
+ is_first = true;
+ }
+ else {
+ TSize current = (*first)->minimumMatchLength();
+ if (current < result) result = current;
+ }
+ return result;
+ }
+
+
+
+
+template<class T>
+void ixion::regex<T>::alternative_matcher::setNext(matcher *next,bool ownnext = true) {
+ matcher::setNext(next);
+ Connector.setNext(next,false);
+ }
+
+
+
+
+template<class T>
+void ixion::regex<T>::alternative_matcher::addAlternative(matcher *alternative) {
+ AltList.push_back(alternative);
+ matcher *searchlast = alternative,*last = NULL;
+ while (searchlast) {
+ last = searchlast;
+ searchlast = searchlast->getNext();
+ }
+ last->setNext(&Connector,false);
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::alternative_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+ std::vector<matcher *>::iterator first = AltList.begin(),last = AltList.end();
+ while (first != last) {
+ if ((*first)->match(brstack,candidate,at)) {
+ MatchLength = 0;
+ matcher const *object = *first;
+ while (object != &Connector) {
+ MatchLength += object->getMatchLength();
+ object = object->getNext();
+ }
+ return true;
+ }
+ first++;
+ }
+ return false;
+ }
+
+
+
+
+template<class T>
+void ixion::regex<T>::alternative_matcher::copy(alternative_matcher const *src) {
+ super::copy(src);
+ Connector.setNext(Next,false);
+
+ FOREACH_CONST(first,src->AltList,alt_list)
+ addAlternative((*first)->duplicate());
+ }
+
+
+
+
+// regex::backref_matcher -----------------------------------------------------
+template<class T>
+ixion::regex<T>::backref_matcher::backref_matcher(TIndex backref)
+ : Backref(backref) {
+ }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::backref_matcher::duplicate() const {
+ backref_matcher *dupe = new backref_matcher(Backref);
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::backref_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+ T matchstr = brstack.get(Backref,candidate);
+ MatchLength = matchstr.size();
+
+ if (at+matchstr.size() > candidate.size()) return false;
+ return (T(candidate.begin()+at,candidate.begin()+at+matchstr.size()) == matchstr) &&
+ matchNext(brstack,candidate,at+matchstr.size());
+ }
+
+
+
+
+// regex ----------------------------------------------------------------------
+template<class T>
+ixion::regex<T>::regex()
+ : MatchIndex(0),MatchLength(0) {
+ }
+
+
+
+
+template<class T>
+ixion::regex<T>::regex(regex const &src)
+ : ParsedRegex(src.ParsedRegex->duplicate()),
+ MatchIndex(0),MatchLength(0) {
+ }
+
+
+
+
+template<class T>
+ixion::regex<T> &ixion::regex<T>::operator=(regex const &src) {
+ std::auto_ptr<matcher> regex_copy(src.ParsedRegex->duplicate());
+ ParsedRegex = regex_copy;
+ return *this;
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::match(T const &candidate,TIndex from) {
+ LastCandidate = candidate;
+ BackrefStack.clear();
+
+ if (ParsedRegex.get() == NULL)
+ EX_THROW(regex,ECRE_NOPATTERN)
+
+ for (TIndex index = from;index < candidate.size();index++)
+ if (ParsedRegex->match(BackrefStack,candidate,index)) {
+ MatchIndex = index;
+ MatchLength = ParsedRegex->subsequentMatchLength();
+ return true;
+ }
+ return false;
+ }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::matchAt(T const &candidate,TIndex at) {
+ LastCandidate = candidate;
+ BackrefStack.clear();
+
+ if (ParsedRegex.get() == NULL)
+ EX_THROW(regex,ECRE_NOPATTERN)
+
+ if (ParsedRegex->match(BackrefStack,candidate,at)) {
+ MatchIndex = at;
+ MatchLength = ParsedRegex->subsequentMatchLength();
+ return true;
+ }
+ return false;
+ }
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript scanner
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_SCANJS
+#define IXLIB_SCANJS
+
+
+
+
+#undef yyFlexLexer
+#define yyFlexLexer jsFlexLexer
+#include <FlexLexer.h>
+#undef yyFlexLexer
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : scanner wrapper for FlexLexer
+// ----------------------------------------------------------------------------
+// (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_SCANNER
+#define IXLIB_SCANNER
+
+
+
+
+#include <ixlib_base.hh>
+#include <ixlib_exbase.hh>
+#include <vector>
+#include <ixlib_string.hh>
+
+
+
+
+class FlexLexer;
+
+
+
+
+// possible errors during execution -------------------------------------------
+#define ECSCAN_UNKNOWN_TOKEN 0
+#define ECSCAN_EOF 1
+
+
+
+
+// scanner_exception ----------------------------------------------------------
+namespace ixion {
+ struct scanner_exception : public base_exception {
+ scanner_exception(TErrorCode const error,TIndex const line,std::string const &info);
+ virtual char *getText() const;
+ };
+
+
+
+
+// scanner --------------------------------------------------------------------
+ class scanner {
+ public:
+ typedef unsigned token_type;
+
+ struct token {
+ token_type Type;
+ TIndex Line;
+ std::string Text;
+ };
+
+ typedef std::vector<token> token_list;
+ typedef std::vector<token>::iterator token_iterator;
+
+ scanner(FlexLexer &lexer);
+ token_list scan();
+
+ protected:
+ FlexLexer &Lexer;
+ token CurrentToken;
+
+ token getNextToken();
+ bool reachedEOF() const;
+ };
+ }
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : String crunching tools
+// ----------------------------------------------------------------------------
+// (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_STRING
+#define IXLIB_STRING
+
+
+
+
+#include <string>
+#include <ixlib_base.hh>
+#include <ixlib_exgen.hh>
+
+
+
+
+namespace ixion {
+ template<class InputIterator>
+ inline std::string concat(InputIterator first,InputIterator last,std::string const &sep = " ") {
+ std::string str;
+ while (first != last) {
+ if (str.size()) str += sep;
+ str += *first++;
+ }
+ return str;
+ }
+
+
+
+
+ std::string findReplace(std::string const &target,std::string const &src,std::string const &dest);
+ std::string findReplace(std::string const &target,char* src,char *dest);
+ std::string findReplace(std::string const &target,char src,char dest);
+ std::string upper(std::string const &original);
+ std::string lower(std::string const &original);
+ std::string removeLeading(std::string const &original,char ch = ' ');
+ std::string removeTrailing(std::string const &original,char ch = ' ');
+ std::string removeLeadingTrailing(std::string const &original,char ch = ' ');
+ std::string parseCEscapes(std::string const &original);
+
+ TSize getMaxBase64DecodedSize(TSize encoded);
+ // data must provide enough space for the maximal size determined by the
+ // above function
+ TSize base64decode(TByte *data,std::string const &base64);
+ void base64encode(std::string &base64,TByte const *data,TSize size);
+
+
+
+
+ class string_hash {
+ public:
+ unsigned long operator()(std::string const &str) const;
+ };
+ }
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Token definitions for Javascript scanner
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_TOKEN_JAVASCRIPT
+#define IXLIB_TOKEN_JAVASCRIPT
+
+
+
+
+#include <ixlib_token_lex.hh>
+
+
+
+
+// keywords
+#define TT_JS_THIS (TT_USER + 0)
+#define TT_JS_FUNCTION (TT_USER + 1)
+#define TT_JS_VAR (TT_USER + 2)
+#define TT_JS_NULL (TT_USER + 3)
+#define TT_JS_IF (TT_USER + 4)
+#define TT_JS_WHILE (TT_USER + 5)
+#define TT_JS_DO (TT_USER + 6)
+#define TT_JS_ELSE (TT_USER + 7)
+#define TT_JS_FOR (TT_USER + 8)
+#define TT_JS_RETURN (TT_USER + 9)
+#define TT_JS_SWITCH (TT_USER + 10)
+#define TT_JS_CASE (TT_USER + 11)
+#define TT_JS_CONTINUE (TT_USER + 12)
+#define TT_JS_BREAK (TT_USER + 13)
+#define TT_JS_DEFAULT (TT_USER + 14)
+#define TT_JS_IN (TT_USER + 15)
+#define TT_JS_CONST (TT_USER + 16)
+#define TT_JS_CLASS (TT_USER + 17)
+#define TT_JS_EXTENDS (TT_USER + 18)
+#define TT_JS_NAMESPACE (TT_USER + 19)
+#define TT_JS_STATIC (TT_USER + 20)
+#define TT_JS_CONSTRUCTOR (TT_USER + 21)
+
+// operators
+#define TT_JS_NEW (TT_USER + 1024)
+
+#define TT_JS_PLUS_ASSIGN (TT_USER + 1025)
+#define TT_JS_MINUS_ASSIGN (TT_USER + 1026)
+#define TT_JS_MULTIPLY_ASSIGN (TT_USER + 1027)
+#define TT_JS_DIVIDE_ASSIGN (TT_USER + 1028)
+#define TT_JS_MODULO_ASSIGN (TT_USER + 1029)
+#define TT_JS_BIT_XOR_ASSIGN (TT_USER + 1030)
+#define TT_JS_BIT_AND_ASSIGN (TT_USER + 1031)
+#define TT_JS_BIT_OR_ASSIGN (TT_USER + 1032)
+#define TT_JS_LEFT_SHIFT (TT_USER + 1033)
+#define TT_JS_RIGHT_SHIFT (TT_USER + 1034)
+#define TT_JS_LEFT_SHIFT_ASSIGN (TT_USER + 1035)
+#define TT_JS_RIGHT_SHIFT_ASSIGN (TT_USER + 1036)
+#define TT_JS_EQUAL (TT_USER + 1037)
+#define TT_JS_NOT_EQUAL (TT_USER + 1038)
+#define TT_JS_LESS_EQUAL (TT_USER + 1039)
+#define TT_JS_GREATER_EQUAL (TT_USER + 1040)
+#define TT_JS_LOGICAL_AND (TT_USER + 1041)
+#define TT_JS_LOGICAL_OR (TT_USER + 1042)
+#define TT_JS_INCREMENT (TT_USER + 1043)
+#define TT_JS_DECREMENT (TT_USER + 1044)
+#define TT_JS_IDENTICAL (TT_USER + 1045)
+#define TT_JS_NOT_IDENTICAL (TT_USER + 1046)
+
+// literals
+#define TT_JS_LIT_INT (TT_USER + 2048)
+#define TT_JS_LIT_FLOAT (TT_USER + 2049)
+#define TT_JS_LIT_STRING (TT_USER + 2050)
+#define TT_JS_LIT_TRUE (TT_USER + 2051)
+#define TT_JS_LIT_FALSE (TT_USER + 2052)
+#define TT_JS_LIT_UNDEFINED (TT_USER + 2053)
+
+// identifier
+#define TT_JS_IDENTIFIER (TT_USER + 3072)
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Basic definitions
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_TOKENLEX
+#define IXLIB_TOKENLEX
+
+
+
+
+// Basic token types
+#define TT_EOF 1024
+#define TT_UNKNOWN 1025
+#define TT_WHITESPACE 1026
+#define TT_USER 2048
+
+
+
+
+#endif
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript interpreter
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_js_internals.hh>
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// js_array -------------------------------------------------------------------
+js_array::
+js_array(TSize size) {
+ Array.resize(size);
+
+ ref<value> null = javascript::makeNull();
+ for (TIndex i = 0;i < size;i++)
+ Array[i] = makeLValue(null);
+ }
+
+
+
+
+string js_array::stringify() const {
+ value_array::const_iterator first = Array.begin(),last = Array.end();
+
+ string result = "{ ";
+ bool at_first = true;
+ while (first != last) {
+ if (!at_first) result += ',';
+ else at_first = false;
+ result += (*first)->stringify();
+ first++;
+ }
+ return result + " }";
+ }
+
+
+
+
+ref<javascript::value>
+js_array::
+duplicate() {
+ ref<value> result = new js_array(*this);
+ return result;
+ }
+
+
+
+
+ref<javascript::value>
+js_array::
+lookup(string const &identifier) {
+ if (identifier == "length") return javascript::makeConstant(Array.size());
+ return super::lookup(identifier);
+ }
+
+
+
+
+ref<javascript::value>
+js_array::
+subscript(value const &index) {
+ TIndex idx = index.toInt();
+ return operator[](idx);
+ }
+
+
+
+
+ref<javascript::value>
+js_array::
+callMethod(string const &id,parameter_list const ¶meters) {
+ if (id == "pop" && parameters.size() == 0) {
+ if (Array.size() == 0) return javascript::makeNull();
+ else {
+ ref<value> back = Array.back();
+ Array.pop_back();
+ return back;
+ }
+ }
+ else if (id == "push") {
+ FOREACH_CONST(first,parameters,parameter_list) {
+ Array.push_back((*first)->duplicate());
+ }
+ return javascript::makeConstant(Array.size());
+ }
+ else if (id == "reverse" && parameters.size() == 0) {
+ reverse(Array.begin(),Array.end());
+ return this;
+ }
+ else if (id == "shift" && parameters.size() == 0) {
+ if (Array.size() == 0) return javascript::makeNull();
+ else {
+ ref<value> front = Array.front();
+ Array.erase(Array.begin());
+ return front;
+ }
+ }
+ else if (id == "slice" && parameters.size() == 2) {
+ value_array::const_iterator first = Array.begin() + parameters[0]->toInt();
+ value_array::const_iterator last = Array.begin() + parameters[1]->toInt();
+
+ auto_ptr<js_array> array(new js_array(first,last));
+ return array.release();
+ }
+ else if (id == "unshift") {
+ TIndex i = 0;
+ FOREACH_CONST(first,parameters,parameter_list) {
+ Array.insert(Array.begin() + i++,(*first)->duplicate());
+ }
+ return javascript::makeConstant(Array.size());
+ }
+ else if (id == "join" && parameters.size() == 1) {
+ string sep = parameters[0]->toString();
+ string result;
+
+ for( TIndex i = 0; i < Array.size(); ++i ) {
+ if (i != 0)
+ result += sep;
+
+ result += Array[i]->toString();
+ }
+
+ return javascript::makeValue(result);
+ }
+ // *** FIXME: implement splice and sort
+
+ EXJS_THROWINFO(ECJS_UNKNOWN_IDENTIFIER,("Array."+id).c_str())
+ }
+
+
+
+
+void js_array::resize(TSize size) {
+ if (size >= Array.size()) {
+ TSize prevsize = Array.size();
+
+ Array.resize(size);
+
+ ref<value> null = javascript::makeNull();
+ for (TIndex i = prevsize;i < size;i++)
+ Array[i] = makeLValue(null);
+ }
+ }
+
+
+
+
+ref<value> &js_array::operator[](TIndex idx) {
+ if (idx >= Array.size())
+ resize((Array.size()+1)*2);
+
+ return Array[idx];
+ }
+
+
+
+
+
+void js_array::push_back(ref<value> val) {
+ Array.push_back(val);
+ }
+
+
+
+
+// js_array_constructor -------------------------------------------------------
+ref<javascript::value> js_array_constructor::duplicate() {
+ // array_constructor is not mutable
+ return this;
+ }
+
+
+
+
+ref<javascript::value>
+js_array_constructor::
+construct(parameter_list const ¶meters) {
+ if (parameters.size() == 0) return makeArray();
+ else if (parameters.size() == 1) return makeArray(parameters[0]->toInt());
+ else /* parameters.size() >= 2 */ {
+ auto_ptr<js_array> result(new js_array(parameters.size()));
+
+ TIndex i = 0;
+ FOREACH_CONST(first,parameters,parameter_list) {
+ (*result)[i++] = (*first)->duplicate();
+ }
+ return result.release();
+ }
+ }
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript interpreter
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+
+
+#define EXJS_ADD_CODE_LOCATION \
+ catch (no_location_javascript_exception &half) { \
+ throw javascript_exception(half,getCodeLocation()); \
+ }
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// variable_declaration -------------------------------------------------------
+variable_declaration::variable_declaration(string const &id,ref<expression> def_value,code_location const &loc)
+ : expression(loc),Identifier(id),DefaultValue(def_value) {
+ }
+
+
+
+
+ref<value> variable_declaration::evaluate(context const &ctx) const {
+ try {
+ ref<value> def;
+ if (DefaultValue.get() != NULL) def = DefaultValue->evaluate(ctx)->eliminateWrappers()->duplicate();
+ else def = makeNull();
+
+ ref<value> lv = makeLValue(def);
+ ctx.DeclarationScope->addMember(Identifier,lv);
+ return lv;
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// constant_declaration -------------------------------------------------------
+constant_declaration::constant_declaration(string const &id,ref<expression> def_value,code_location const &loc)
+ : expression(loc),Identifier(id),DefaultValue(def_value) {
+ }
+
+
+
+
+ref<value> constant_declaration::evaluate(context const &ctx) const {
+ try {
+ ref<value> def;
+ if (DefaultValue.get() != NULL) def = DefaultValue->evaluate(ctx)->eliminateWrappers()->duplicate();
+ else def = makeNull();
+
+ ref<value> cns = wrapConstant(def);
+ ctx.DeclarationScope->addMember(Identifier,cns);
+ return cns;
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// function_declaration -------------------------------------------------------
+function_declaration::
+function_declaration(string const &id,parameter_name_list const &pnames,
+ref<expression> body,code_location const &loc)
+ : expression(loc),Identifier(id),ParameterNameList(pnames),Body(body) {
+ }
+
+
+
+
+ref<value> function_declaration::evaluate(context const &ctx) const {
+ try {
+ ref<value> fun = new function(ParameterNameList,Body,ctx.LookupScope);
+ ctx.DeclarationScope->addMember(Identifier,fun);
+ return ref<value>(NULL);
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// method_declaration ---------------------------------------------------------
+method_declaration::
+method_declaration(string const &id,parameter_name_list const &pnames,
+ref<expression> body,code_location const &loc)
+ : expression(loc),Identifier(id),ParameterNameList(pnames),Body(body) {
+ }
+
+
+
+
+ref<value> method_declaration::evaluate(context const &ctx) const {
+ try {
+ ref<value> fun = new method(ParameterNameList,Body,ctx.LookupScope);
+ ctx.DeclarationScope->addMember(Identifier,fun);
+ return ref<value>(NULL);
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// constructor_declaration ---------------------------------------------------------
+constructor_declaration::
+constructor_declaration(parameter_name_list const &pnames,
+ref<expression> body,code_location const &loc)
+ : expression(loc),ParameterNameList(pnames),Body(body) {
+ }
+
+
+
+
+ref<value> constructor_declaration::evaluate(context const &ctx) const {
+ try {
+ ref<value> fun = new constructor(ParameterNameList,Body,ctx.LookupScope);
+ return fun;
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// js_class_declaration -------------------------------------------------------
+js_class_declaration::js_class_declaration(string const &id,ref<expression> superclass,code_location const &loc)
+ : expression(loc),Identifier(id),SuperClass(superclass) {
+ }
+
+
+
+
+ref<value> js_class_declaration::evaluate(context const &ctx) const {
+ try {
+ ref<list_scope,value> sml(new list_scope);
+ ref<list_scope,value> ml(new list_scope);
+ ref<list_scope,value> svl(new list_scope);
+
+ ref<value> sc;
+ if (SuperClass.get())
+ sc = SuperClass->evaluate(ctx);
+
+ ref<value> constructor;
+ if (ConstructorDeclaration.get())
+ constructor = ConstructorDeclaration->evaluate(ctx);
+ ref<value> cls(new js_class(ctx.LookupScope,sc,constructor,sml,ml,svl,VariableList));
+
+ ref<list_scope,value> static_scope(new list_scope);
+ static_scope->unite(ctx.LookupScope);
+ static_scope->unite(cls);
+
+ FOREACH_CONST(first,StaticMethodList,declaration_list)
+ (*first)->evaluate(context(sml,static_scope));
+ FOREACH_CONST(first,MethodList,declaration_list)
+ (*first)->evaluate(context(ml,ctx.LookupScope));
+ FOREACH_CONST(first,StaticVariableList,declaration_list)
+ (*first)->evaluate(context(svl,static_scope));
+
+ ctx.DeclarationScope->addMember(Identifier,cls);
+ return cls;
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+void js_class_declaration::setConstructor(ref<expression> decl) {
+ ConstructorDeclaration = decl;
+ }
+
+
+
+
+void js_class_declaration::addStaticMethod(ref<expression> decl) {
+ StaticMethodList.push_back(decl);
+ }
+
+
+
+
+void js_class_declaration::addMethod(ref<expression> decl) {
+ MethodList.push_back(decl);
+ }
+
+
+
+
+void js_class_declaration::addStaticVariable(ref<expression> decl) {
+ StaticVariableList.push_back(decl);
+ }
+
+
+
+
+void js_class_declaration::addVariable(ref<expression> decl) {
+ VariableList.push_back(decl);
+ }
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript interpreter
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+
+
+#define EXJS_ADD_CODE_LOCATION \
+ catch (no_location_javascript_exception &half) { \
+ throw javascript_exception(half,getCodeLocation()); \
+ }
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// expression -----------------------------------------------------------------
+expression::expression(code_location const &loc)
+ : Location(loc) {
+ }
+
+
+
+
+expression::~expression() {
+ }
+
+
+
+
+// constant -------------------------------------------------------------------
+constant::constant(ref<value> val,code_location const &loc)
+ : expression(loc),Value(val) {
+ }
+
+
+
+
+ref<value>
+constant::
+evaluate(context const &ctx) const {
+ return Value;
+ }
+
+
+
+
+// unary_operator -------------------------------------------------
+unary_operator::unary_operator(value::operator_id opt,ref<expression> opn,code_location const &loc)
+ : expression(loc),Operator(opt),Operand(opn) {
+ }
+
+
+
+
+ref<value>
+unary_operator::
+evaluate(context const &ctx) const {
+ try {
+ return Operand->evaluate(ctx)->operatorUnary(Operator);
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// modifying_unary_operator ---------------------------------------------------
+modifying_unary_operator::
+modifying_unary_operator(value::operator_id opt,ref<expression> opn,code_location const &loc)
+ : expression(loc),Operator(opt),Operand(opn) {
+ }
+
+
+
+
+ref<value>
+modifying_unary_operator::
+evaluate(context const &ctx) const {
+ try {
+ return Operand->evaluate(ctx)->operatorUnaryModifying(Operator);
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// binary_operator ------------------------------------------------------------
+binary_operator::binary_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+ : expression(loc),Operator(opt),Operand1(opn1),Operand2(opn2) {
+ }
+
+
+
+
+ref<value> binary_operator::evaluate(context const &ctx) const {
+ try {
+ return Operand1->evaluate(ctx)->operatorBinary(Operator,Operand2->evaluate(ctx));
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// binary_shortcut_operator ---------------------------------------------------
+binary_shortcut_operator::binary_shortcut_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+ : expression(loc),Operator(opt),Operand1(opn1),Operand2(opn2) {
+ }
+
+
+
+
+ref<value> binary_shortcut_operator::evaluate(context const &ctx) const {
+ try {
+ return Operand1->evaluate(ctx)->operatorBinaryShortcut(Operator,*Operand2,ctx);
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// modifying_binary_operator --------------------------------------
+modifying_binary_operator::
+modifying_binary_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+ : expression(loc),Operator(opt),Operand1(opn1),Operand2(opn2) {
+ }
+
+
+
+
+ref<value>
+modifying_binary_operator::
+evaluate(context const &ctx) const {
+ try {
+ return Operand1->evaluate(ctx)->operatorBinaryModifying(Operator,Operand2->evaluate(ctx));
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// ternary_operator -----------------------------------------------------------
+ternary_operator::
+ternary_operator(ref<expression> opn1,ref<expression> opn2,ref<expression> opn3,code_location const &loc)
+ : expression(loc),Operand1(opn1),Operand2(opn2),Operand3(opn3) {
+ }
+
+
+
+
+ref<value>
+ternary_operator::
+evaluate(context const &ctx) const {
+ try {
+ if (Operand1->evaluate(ctx)->toBoolean())
+ return Operand2->evaluate(ctx);
+ else
+ return Operand3->evaluate(ctx);
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// subscript_operation --------------------------------------------------------
+subscript_operation::subscript_operation(ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+ : expression(loc),Operand1(opn1),Operand2(opn2) {
+ }
+
+
+
+
+ref<value> subscript_operation::evaluate(context const &ctx) const {
+ try {
+ ref<value> op2 = Operand2->evaluate(ctx);
+ return Operand1->evaluate(ctx)->subscript(*op2);
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// lookup_operation -----------------------------------------------------------
+lookup_operation::lookup_operation(string const &id,code_location const &loc)
+ : expression(loc),Identifier(id) {
+ }
+
+
+
+
+lookup_operation::lookup_operation(ref<expression> opn,string const &id,code_location const &loc)
+ : expression(loc),Operand(opn),Identifier(id) {
+ }
+
+
+
+
+ref<value> lookup_operation::evaluate(context const &ctx) const {
+ try {
+ ref<value> scope(ctx.LookupScope);
+ if (Operand.get() != NULL)
+ scope = Operand->evaluate(ctx);
+ return scope->lookup(Identifier);
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// assignment -----------------------------------------------------------------
+assignment::
+assignment(ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+ : expression(loc),Operand1(opn1),Operand2(opn2) {
+ }
+
+
+
+
+ref<value>
+assignment::evaluate(context const &ctx) const {
+ try {
+ return Operand1->evaluate(ctx)->assign(Operand2->evaluate(ctx)->eliminateWrappers()->duplicate());
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// basic_call -----------------------------------------------------------------
+basic_call::basic_call(parameter_expression_list const &pexps,code_location const &loc)
+ : expression(loc),ParameterExpressionList(pexps) {
+ }
+
+
+
+
+void basic_call::makeParameterValueList(context const &ctx,parameter_value_list &pvalues) const {
+ FOREACH_CONST(first,ParameterExpressionList,parameter_expression_list) {
+ pvalues.push_back((*first)->evaluate(ctx));
+ }
+ }
+
+
+
+
+// function_call --------------------------------------------------------------
+function_call::function_call(ref<expression> fun,parameter_expression_list const &pexps,code_location const &loc)
+ : super(pexps,loc),Function(fun) {
+ }
+
+
+
+
+ref<value> function_call::evaluate(context const &ctx) const {
+ try {
+ ref<value> func_value = Function->evaluate(ctx);
+
+ value::parameter_list pvalues;
+ makeParameterValueList(ctx,pvalues);
+ ref<value> result = func_value->call(pvalues);
+
+ if (result.get() == NULL) return makeNull();
+ else return result;
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
+
+
+
+
+// construction ---------------------------------------------------------------
+construction::construction(ref<expression> cls,parameter_expression_list const &pexps,code_location const &loc)
+ : super(pexps,loc),Class(cls) {
+ }
+
+
+
+
+ref<value> construction::evaluate(context const &ctx) const {
+ try {
+ ref<value> class_value = Class->evaluate(ctx);
+
+ value::parameter_list pvalues;
+ makeParameterValueList(ctx,pvalues);
+
+ return class_value->construct(pvalues);
+ }
+ EXJS_ADD_CODE_LOCATION
+ }
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript interpreter
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// instruction_list -----------------------------------------------------------
+ref<value>
+instruction_list::evaluate(context const &ctx) const {
+ ref<value> result;
+ FOREACH_CONST(first,ExpressionList,expression_list)
+ result = (*first)->evaluate(ctx);
+ return result;
+ }
+
+
+
+
+void instruction_list::add(ref<expression> expr) {
+ ExpressionList.push_back(expr);
+ }
+
+
+
+
+// scoped_instruction_list ----------------------------------------
+ref<value> scoped_instruction_list::evaluate(context const &ctx) const {
+ ref<list_scope,value> scope = new list_scope;
+ scope->unite(ctx.LookupScope);
+
+ ref<value> result = instruction_list::evaluate(context(scope));
+ if (result.get()) return result->duplicate();
+ return ref<value>(NULL);
+
+ // ATTENTION: this is a scope cancellation point.
+ }
+
+
+
+
+// js_if ----------------------------------------------------------------------
+js_if::js_if(ref<expression> cond,ref<expression> ifex,ref<expression> ifnotex,code_location const &loc)
+ : expression(loc),Conditional(cond),IfExpression(ifex),IfNotExpression(ifnotex) {
+ }
+
+
+
+
+ref<value> js_if::evaluate(context const &ctx) const {
+ if (Conditional->evaluate(ctx)->toBoolean())
+ return IfExpression->evaluate(ctx);
+ else
+ if (IfNotExpression.get())
+ return IfNotExpression->evaluate(ctx);
+ else
+ return ref<value>(NULL);
+ }
+
+
+
+
+// js_while -------------------------------------------------------------------
+js_while::js_while(ref<expression> cond,ref<expression> loopex,code_location const &loc)
+ : expression(loc),Conditional(cond),LoopExpression(loopex),HasLabel(false) {
+ }
+
+
+
+
+js_while::js_while(ref<expression> cond,ref<expression> loopex,string const &label,code_location const &loc)
+ : expression(loc),Conditional(cond),LoopExpression(loopex),HasLabel(true),Label(label) {
+ }
+
+
+
+
+ref<value> js_while::evaluate(context const &ctx) const {
+ ref<value> result;
+ while (Conditional->evaluate(ctx)->toBoolean()) {
+ try {
+ result = LoopExpression->evaluate(ctx);
+ }
+ catch (break_exception &be) {
+ if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label))
+ break;
+ else throw;
+ }
+ catch (continue_exception &ce) {
+ if (!ce.HasLabel || (HasLabel && ce.HasLabel && ce.Label == Label))
+ continue;
+ else throw;
+ }
+ }
+ return result;
+ }
+
+
+
+
+// js_do_while ----------------------------------------------------------------
+js_do_while::js_do_while(ref<expression> cond,ref<expression> loopex,code_location const &loc)
+ : expression(loc),Conditional(cond),LoopExpression(loopex),HasLabel(false) {
+ }
+
+
+
+
+js_do_while::js_do_while(ref<expression> cond,ref<expression> loopex,string const &label,code_location const &loc)
+ : expression(loc),Conditional(cond),LoopExpression(loopex),HasLabel(true),Label(label) {
+ }
+
+
+
+
+ref<value> js_do_while::evaluate(context const &ctx) const {
+ ref<value> result;
+ do {
+ try {
+ result = LoopExpression->evaluate(ctx);
+ }
+ catch (break_exception &be) {
+ if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label))
+ break;
+ else throw;
+ }
+ catch (continue_exception &ce) {
+ if (!ce.HasLabel || (HasLabel && ce.HasLabel && ce.Label == Label))
+ continue;
+ else throw;
+ }
+ } while (Conditional->evaluate(ctx)->toBoolean());
+ return result;
+ }
+
+
+
+
+// js_for ---------------------------------------------------------------------
+js_for::js_for(ref<expression> init,ref<expression> cond,ref<expression> update,ref<expression> loop,code_location const &loc)
+ : expression(loc),Initialization(init),Conditional(cond),Update(update),
+ LoopExpression(loop),HasLabel(false) {
+ }
+
+
+
+
+js_for::js_for(ref<expression> init,ref<expression> cond,ref<expression> update,ref<expression> loop,string const &label,code_location const &loc)
+ : expression(loc),Initialization(init),Conditional(cond),Update(update),LoopExpression(loop),
+ HasLabel(true),Label(label) {
+ }
+
+
+
+
+ref<value> js_for::evaluate(context const &ctx) const {
+ ref<list_scope,value> scope = new list_scope;
+ scope->unite(ctx.LookupScope);
+ context inner_context(scope);
+
+ ref<value> result;
+ for (Initialization->evaluate(inner_context);Conditional->evaluate(inner_context)->toBoolean();
+ Update->evaluate(inner_context)) {
+ try {
+ result = LoopExpression->evaluate(inner_context);
+ }
+ catch (break_exception &be) {
+ if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label))
+ break;
+ else throw;
+ }
+ catch (continue_exception &ce) {
+ if (!ce.HasLabel || (HasLabel && ce.HasLabel && ce.Label == Label))
+ continue;
+ else throw;
+ }
+ }
+ return result;
+ }
+
+
+
+
+// js_for_in ------------------------------------------------------------------
+js_for_in::js_for_in(ref<expression> iter,ref<expression> array,ref<expression> loop,code_location const &loc)
+ : expression(loc),Iterator(iter),Array(array),LoopExpression(loop),HasLabel(false) {
+ }
+
+
+
+
+js_for_in::js_for_in(ref<expression> iter,ref<expression> array,ref<expression> loop,string const &label,code_location const &loc)
+ : expression(loc),Iterator(iter),Array(array),LoopExpression(loop),
+ HasLabel(true),Label(label) {
+ }
+
+
+
+
+ref<value> js_for_in::evaluate(context const &ctx) const {
+ ref<list_scope,value> scope = new list_scope;
+ scope->unite(ctx.LookupScope);
+ context inner_context(scope);
+
+ ref<value> result;
+ ref<value> iterator = Iterator->evaluate(inner_context);
+ ref<value> array = Array->evaluate(inner_context);
+
+ TSize size = array->lookup("length")->toInt();
+
+ for (TIndex i = 0;i < size;i++) {
+ try {
+ iterator->assign(array->subscript(*makeConstant(i)));
+ result = LoopExpression->evaluate(inner_context);
+ }
+ catch (break_exception &be) {
+ if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label))
+ break;
+ else throw;
+ }
+ catch (continue_exception &ce) {
+ if (!ce.HasLabel || (HasLabel && ce.HasLabel && ce.Label == Label))
+ continue;
+ else throw;
+ }
+ }
+ if (result.get()) return result->duplicate();
+ return ref<value>(NULL);
+
+ // ATTENTION: this is a scope cancellation point.
+ }
+
+
+
+
+// js_return ------------------------------------------------------------------
+js_return::js_return(ref<expression> retval,code_location const &loc)
+ : expression(loc),ReturnValue(retval) {
+ }
+
+
+
+
+ref<value> js_return::evaluate(context const &ctx) const {
+ ref<value> retval;
+ if (ReturnValue.get())
+ retval = ReturnValue->evaluate(ctx);
+
+ throw return_exception(retval,getCodeLocation());
+ }
+
+
+
+
+// js_break -------------------------------------------------------------------
+js_break::js_break(code_location const &loc)
+ : expression(loc),HasLabel(false) {
+ }
+
+
+
+
+js_break::js_break(string const &label,code_location const &loc)
+ : expression(loc),HasLabel(true),Label(label) {
+ }
+
+
+
+
+ref<value> js_break::evaluate(context const &ctx) const {
+ throw break_exception(HasLabel,Label,getCodeLocation());
+ }
+
+
+
+
+// js_continue ----------------------------------------------------------------
+js_continue::js_continue(code_location const &loc)
+ : expression(loc),HasLabel(false) {
+ }
+
+
+
+
+js_continue::js_continue(string const &label,code_location const &loc)
+ : expression(loc),HasLabel(true),Label(label) {
+ }
+
+
+
+
+ref<value> js_continue::evaluate(context const &ctx) const {
+ throw continue_exception(HasLabel,Label,getCodeLocation());
+ }
+
+
+
+
+// break_label ----------------------------------------------------------------
+break_label::break_label(string const &label,ref<expression> expr,code_location const &loc)
+ : expression(loc),Label(label),Expression(expr) {
+ }
+
+
+
+
+ref<value>
+break_label::evaluate(context const &ctx) const {
+ try {
+ return Expression->evaluate(ctx);
+ }
+ catch (break_exception &be) {
+ if (be.HasLabel && be.Label == Label) return ref<value>(NULL);
+ else throw;
+ }
+ }
+
+
+
+
+// js_switch -----------------------------------------------------------------
+js_switch::js_switch(ref<expression> discriminant,code_location const &loc)
+ : expression(loc),HasLabel(false),Discriminant(discriminant) {
+ }
+
+
+
+
+js_switch::js_switch(ref<expression> discriminant,string const &label,code_location const &loc)
+ : expression(loc),HasLabel(true),Label(label),Discriminant(discriminant) {
+ }
+
+
+
+
+ref<value>
+js_switch::
+evaluate(context const &ctx) const {
+ ref<list_scope,value> scope = new list_scope;
+ scope->unite(ctx.LookupScope);
+ context inner_context(scope);
+
+ ref<value> discr = Discriminant->evaluate(inner_context);
+
+ case_list::const_iterator expr,def;
+ bool expr_found = false,def_found = false;
+ FOREACH_CONST(first,CaseList,case_list) {
+ if (first->DiscriminantValue.get()) {
+ if (first->DiscriminantValue->evaluate(inner_context)->
+ operatorBinary(value::OP_EQUAL,Discriminant->evaluate(inner_context))->toBoolean()) {
+ expr = first;
+ expr_found = true;
+ break;
+ }
+ }
+ else {
+ if (!def_found) {
+ def = first;
+ def_found = true;
+ }
+ }
+ }
+
+ try {
+ case_list::const_iterator exec,last = CaseList.end();
+ if (expr_found)
+ exec = expr;
+ else if (def_found)
+ exec = def;
+ else
+ return ref<value>(NULL);
+
+ ref<value> result;
+ while (exec != last) {
+ result = exec->Expression->evaluate(inner_context);
+ exec++;
+ }
+ if (result.get()) return result->duplicate();
+ return ref<value>(NULL);
+ }
+ catch (break_exception &be) {
+ if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label))
+ return ref<value>(NULL);
+ else
+ throw;
+ }
+
+ // ATTENTION: this is a scope cancellation point.
+ }
+
+
+
+
+void js_switch::addCase(ref<expression> dvalue,ref<expression> expr) {
+ case_label cl;
+ cl.DiscriminantValue = dvalue;
+ cl.Expression = expr;
+ CaseList.push_back(cl);
+ }
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript interpreter
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <strstream>
+#include "ixlib_i18n.hh"
+#include <ixlib_base.hh>
+#include <ixlib_scanjs.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+
+
+// tools ----------------------------------------------------------------------
+#define ADVANCE \
+ first++; \
+ if (first == last) EXJS_THROW(ECJS_UNEXPECTED_EOF)
+#define EXPECT(WHAT,STRINGIFIED) \
+ if (first == last) EXJS_THROW(ECJS_UNEXPECTED_EOF) \
+ if (first->Type != WHAT) \
+ EXJS_THROWINFOTOKEN(ECJS_UNEXPECTED,("'"+first->Text+"' "+_("instead of ")+STRINGIFIED).c_str(),*first)
+
+
+
+
+static char *dummy_i18n_referencer = N_("instead of ");
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+namespace {
+ ref<expression>
+ makeConstantExpression(ref<value> val,code_location const &loc) {
+ ref<expression> result(new constant(val,loc));
+ return result;
+ }
+ }
+
+
+
+
+// garbage collectors ---------------------------------------------------------
+IXLIB_GARBAGE_DECLARE_MANAGER(value)
+IXLIB_GARBAGE_DECLARE_MANAGER(expression)
+
+
+
+
+// exception texts ------------------------------------------------------------
+static char *(PlainText[]) ={
+ N_("Unterminated comment"),
+ N_("Cannot convert"),
+ N_("Invalid operation"),
+ N_("Unexpected token encountered"),
+ N_("Unexpected end of file"),
+ N_("Cannot modify rvalue"),
+ N_("Unknown identifier"),
+ N_("Unknown operator"),
+ N_("Invalid non-local exit"),
+ N_("Invalid number of arguments"),
+ N_("Invalid token encountered"),
+ N_("Cannot redeclare identifier"),
+ N_("Constructor called on constructed object"),
+ N_("No superclass available"),
+ N_("Division by zero"),
+ };
+
+
+
+
+// no_location_javascript_exception -------------------------------------------
+char *no_location_javascript_exception::getText() const {
+ return _(PlainText[Error]);
+ }
+
+
+
+
+// javascript_exception -------------------------------------------------------
+javascript_exception::javascript_exception(TErrorCode error,code_location const &loc,char const *info,char *module = NULL,
+ TIndex line = 0)
+: base_exception(error, NULL, module, line, "JS") {
+ HasInfo = true;
+ try {
+ string temp = loc.stringify();
+ if (info) {
+ temp += ": ";
+ temp += info;
+ }
+ strcpy(Info,temp.c_str());
+ }
+ catch (...) { }
+ }
+
+
+
+javascript_exception::javascript_exception(no_location_javascript_exception const &half_ex,javascript::code_location const &loc)
+: base_exception(half_ex.Error,NULL,half_ex.Module,half_ex.Line,half_ex.Category) {
+ HasInfo = true;
+ try {
+ string temp = loc.stringify() + ": " + half_ex.Info;
+ strcpy(Info,temp.c_str());
+ }
+ catch (...) { }
+ }
+
+
+
+
+char *javascript_exception::getText() const {
+ return _(PlainText[Error]);
+ }
+
+
+
+
+// code_location --------------------------------------------------------------
+code_location::code_location(scanner::token &tok)
+ : Line(tok.Line) {
+ }
+
+
+
+
+code_location::code_location(TIndex line)
+ : Line(line) {
+ }
+
+
+
+
+string code_location::stringify() const {
+ return "l"+unsigned2dec(Line);
+ }
+
+
+
+
+// context --------------------------------------------------------------------
+context::context(ref<list_scope,value> scope)
+ : DeclarationScope(scope),LookupScope(scope) {
+ }
+
+
+
+
+context::context(ref<value> scope)
+ : LookupScope(scope) {
+ }
+
+
+
+
+context::context(ref<list_scope,value> decl_scope,ref<value> lookup_scope)
+ : DeclarationScope(decl_scope),LookupScope(lookup_scope) {
+ }
+
+
+
+
+// parser ---------------------------------------------------------------------
+namespace {
+ ref<expression>
+ parseInstructionList(scanner::token_iterator &first,scanner::token_iterator const &last,bool scoped);
+ ref<expression>
+ parseSwitch(scanner::token_iterator &first,scanner::token_iterator const &last,string const &label);
+ ref<expression>
+ parseVariableDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+ ref<expression>
+ parseConstantDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+ ref<expression>
+ parseFunctionDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+ ref<expression>
+ parseMethodDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+ ref<expression>
+ parseConstructorDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last,string const &class_id);
+ ref<expression>
+ parseClassDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+ ref<expression>
+ parseInstruction(scanner::token_iterator &first,scanner::token_iterator const &last);
+ ref<expression>
+ parseExpression(scanner::token_iterator &first,scanner::token_iterator const &last,int precedence = 0);
+
+
+
+
+ ref<expression>
+ parseInstructionList(scanner::token_iterator &first,scanner::token_iterator const &last,bool scoped) {
+ auto_ptr<instruction_list> ilist(
+ scoped
+ ? new scoped_instruction_list(*first)
+ : new instruction_list(*first));
+
+ while (first != last && first->Type != '}') {
+ ref<expression> expr = parseInstruction(first,last);
+ if (expr.get() != NULL)
+ ilist->add(expr);
+ }
+ return ilist.release();
+ }
+
+
+
+
+ ref<expression>
+ parseSwitch(scanner::token_iterator &first,scanner::token_iterator const &last,string const &label) {
+ code_location loc(*first);
+
+ ADVANCE
+ EXPECT('(',_("'(' in switch statement"))
+ ADVANCE
+
+ ref<expression> discr = parseExpression(first,last);
+ EXPECT(')',_("')' in switch statement"))
+ ADVANCE
+
+ EXPECT('{',_("'{' in switch statement"))
+ ADVANCE
+
+ auto_ptr<js_switch> sw;
+ if (label.size()) {
+ auto_ptr<js_switch> tsw(new js_switch(discr,label,loc));
+ sw = tsw;
+ }
+ else {
+ auto_ptr<js_switch> tsw(new js_switch(discr,loc));
+ sw = tsw;
+ }
+
+ ref<expression> dvalue;
+ auto_ptr<instruction_list> ilist;
+
+ while (first != last && first->Type != '}') {
+ if (first->Type == TT_JS_CASE) {
+ if (ilist.get())
+ sw->addCase(dvalue,ilist.release());
+
+ auto_ptr<instruction_list> tilist(new instruction_list(*first));
+ ilist = tilist;
+
+ ADVANCE
+
+ dvalue = parseExpression(first,last);
+ EXPECT(':',_("':' in case label"))
+ ADVANCE
+ }
+ else if (first->Type == TT_JS_DEFAULT) {
+ if (ilist.get())
+ sw->addCase(dvalue,ilist.release());
+
+ auto_ptr<instruction_list> tilist(new instruction_list(*first));
+ ilist = tilist;
+
+ ADVANCE
+ dvalue = NULL;
+ EXPECT(':',_("':' in default label"))
+ ADVANCE
+ }
+ else {
+ ref<expression> expr = parseInstruction(first,last);
+ if (ilist.get() && expr.get() != NULL)
+ ilist->add(expr);
+ }
+ }
+
+ if (ilist.get())
+ sw->addCase(dvalue,ilist.release());
+
+ EXPECT('}',_("'}' in switch statement"))
+ ADVANCE
+
+ return sw.release();
+ }
+
+
+
+
+ ref<expression>
+ parseVariableDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+ code_location loc(*first);
+
+ EXPECT(TT_JS_IDENTIFIER,_("variable identifier"))
+ string id = first->Text;
+ ADVANCE
+
+ ref<expression> def;
+ if (first->Type == '=') {
+ ADVANCE
+ def = parseExpression(first,last);
+ }
+ ref<expression> result = new variable_declaration(id,def,loc);
+
+ if (first->Type == ',') {
+ auto_ptr<instruction_list> ilist(new instruction_list(*first));
+ ilist->add(result);
+
+ while (first->Type == ',') {
+ ADVANCE
+
+ code_location loc(*first);
+
+ EXPECT(TT_JS_IDENTIFIER,_("variable identifier"))
+ id = first->Text;
+ ADVANCE
+
+ if (first->Type == '=') {
+ ADVANCE
+ def = parseExpression(first,last);
+ }
+ ref<expression> decl = new variable_declaration(id,def,loc);
+ ilist->add(decl);
+ }
+ result = ilist.release();
+ }
+
+ return result;
+ }
+
+
+
+
+ ref<expression>
+ parseConstantDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+ code_location loc(*first);
+
+ EXPECT(TT_JS_IDENTIFIER,_("constant identifier"))
+ string id = first->Text;
+ ADVANCE
+
+ ref<expression> def;
+ EXPECT('=',_("initializer for constant"))
+ ADVANCE
+ def = parseExpression(first,last);
+
+ ref<expression> result = new constant_declaration(id,def,loc);
+
+ if (first->Type == ',') {
+ auto_ptr<instruction_list> ilist(new instruction_list(*first));
+ ilist->add(result);
+
+ while (first->Type == ',') {
+ ADVANCE
+
+ code_location loc(*first);
+
+ EXPECT(TT_JS_IDENTIFIER,_("constant identifier"))
+ id = first->Text;
+ ADVANCE
+
+ EXPECT('=',_("initializer for constant"))
+ ADVANCE
+ def = parseExpression(first,last);
+
+ ref<expression> decl = new constant_declaration(id,def,loc);
+ ilist->add(decl);
+ }
+ result = ilist.release();
+ }
+
+ return result;
+ }
+
+
+
+
+ ref<expression>
+ parseFunctionDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+ code_location loc(*first);
+
+ EXPECT(TT_JS_IDENTIFIER,_("function identifier"))
+ string id = first->Text;
+ ADVANCE
+
+ EXPECT('(',_("'(' in function declaration"))
+ ADVANCE
+
+ function::parameter_name_list pnames;
+
+ while (first->Type != ')') {
+ EXPECT(TT_JS_IDENTIFIER,_("parameter identifier"))
+ pnames.push_back(first->Text);
+ ADVANCE
+
+ if (first->Type == ',') {
+ ADVANCE
+ }
+ }
+ EXPECT(')',_("')' in function declaration"))
+ ADVANCE
+
+ EXPECT('{',_("'{' in function definition"))
+ ADVANCE
+
+ ref<expression> body = parseInstructionList(first,last,false);
+
+ EXPECT('}',"'}' in method definition")
+ first++;
+
+ ref<expression> result = new function_declaration(id,pnames,body,loc);
+ return result;
+ }
+
+
+
+
+ ref<expression>
+ parseMethodDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+ code_location loc(*first);
+
+ EXPECT(TT_JS_IDENTIFIER,_("method identifier"))
+ string id = first->Text;
+ ADVANCE
+
+ EXPECT('(',_("'(' in method declaration"))
+ ADVANCE
+
+ method::parameter_name_list pnames;
+
+ while (first->Type != ')') {
+ EXPECT(TT_JS_IDENTIFIER,_("parameter identifier"))
+ pnames.push_back(first->Text);
+ ADVANCE
+
+ if (first->Type == ',') {
+ ADVANCE
+ }
+ }
+ EXPECT(')',_("')' in method declaration"))
+ ADVANCE
+
+ EXPECT('{',_("'{' in method definition"))
+ ADVANCE
+
+ ref<expression> body = parseInstructionList(first,last,false);
+
+ EXPECT('}',"'}' in method definition")
+ first++;
+
+ ref<expression> result = new method_declaration(id,pnames,body,loc);
+ return result;
+ }
+
+
+
+
+ ref<expression>
+ parseConstructorDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last,string const &class_id) {
+ code_location loc(*first);
+
+ EXPECT(TT_JS_IDENTIFIER,_("constructor identifier"))
+ if (first->Text != class_id) {
+ EXJS_THROWINFOTOKEN(ECJS_UNEXPECTED,("'"+first->Text+"' "+_("instead of ")+_("class identifier")).c_str(),*first)
+ }
+ ADVANCE
+
+ EXPECT('(',_("'(' in constructor declaration"))
+ ADVANCE
+
+ method::parameter_name_list pnames;
+
+ while (first->Type != ')') {
+ EXPECT(TT_JS_IDENTIFIER,_("parameter identifier"))
+ pnames.push_back(first->Text);
+ ADVANCE
+
+ if (first->Type == ',') {
+ ADVANCE
+ }
+ }
+ EXPECT(')',_("')' in constructor declaration"))
+ ADVANCE
+
+ EXPECT('{',_("'{' in constructor definition"))
+ ADVANCE
+
+ ref<expression> body = parseInstructionList(first,last,false);
+
+ EXPECT('}',"'}' in constructor definition")
+ first++;
+
+ ref<expression> result = new constructor_declaration(pnames,body,loc);
+ return result;
+ }
+
+
+
+
+ ref<expression>
+ parseClassDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+ code_location loc(*first);
+
+ EXPECT(TT_JS_IDENTIFIER,_("class identifier"))
+ string id = first->Text;
+ ADVANCE
+
+ ref<expression> superclass;
+ if (first->Type == TT_JS_EXTENDS) {
+ ADVANCE
+ superclass = parseExpression(first,last);
+ }
+
+ EXPECT('{',_("'{' in class declaration"))
+ ADVANCE
+
+ auto_ptr<js_class_declaration> decl(new js_class_declaration(id,superclass,loc));
+
+ while (first != last && first->Type != '}') {
+ if (first->Type == TT_JS_STATIC) {
+ ADVANCE
+
+ if (first->Type == TT_JS_FUNCTION) {
+ ADVANCE
+ decl->addStaticMethod(parseFunctionDeclaration(first,last));
+ }
+ else {
+ if (first->Type == TT_JS_CONST) {
+ ADVANCE
+ decl->addStaticVariable(parseConstantDeclaration(first,last));
+ }
+ else {
+ ADVANCE
+ decl->addStaticVariable(parseVariableDeclaration(first,last));
+ }
+ EXPECT(';',"';'")
+ first++;
+ }
+ }
+ else {
+ if (first->Type == TT_JS_FUNCTION) {
+ ADVANCE
+ decl->addMethod(parseMethodDeclaration(first,last));
+ }
+ else if (first->Type == TT_JS_CONSTRUCTOR) {
+ ADVANCE
+
+ EXPECT(TT_JS_FUNCTION,_("'function' keyword"))
+ ADVANCE
+
+ decl->setConstructor(parseConstructorDeclaration(first,last,id));
+ }
+ else {
+ if (first->Type == TT_JS_CONST) {
+ ADVANCE
+ decl->addVariable(parseConstantDeclaration(first,last));
+ }
+ else {
+ ADVANCE
+ decl->addVariable(parseVariableDeclaration(first,last));
+ }
+ EXPECT(';',"';'")
+ first++;
+ }
+ }
+ }
+
+ EXPECT('}',"'}' in class declaration")
+ first++;
+
+ return decl.release();
+ }
+
+
+
+
+ ref<expression>
+ parseInstruction(scanner::token_iterator &first,scanner::token_iterator const &last) {
+ if (first == last) EXJS_THROW(ECJS_UNEXPECTED_EOF)
+
+ string label;
+ if (first+1 != last && first[1].Type == ':') {
+ label = first->Text;
+ ADVANCE
+ ADVANCE
+ }
+
+ ref<expression> result;
+
+ if (first->Type == '{') {
+ ADVANCE
+ result = parseInstructionList(first,last,true);
+ EXPECT('}',"'}'")
+ first++;
+ }
+ else if (first->Type == TT_JS_VAR) {
+ ADVANCE
+
+ result = parseVariableDeclaration(first,last);
+
+ EXPECT(';',"';'")
+ first++;
+ }
+ else if (first->Type == TT_JS_CONST) {
+ ADVANCE
+
+ result = parseConstantDeclaration(first,last);
+
+ EXPECT(';',"';'")
+ first++;
+ }
+ else if (first->Type == TT_JS_FUNCTION) {
+ ADVANCE
+ result = parseFunctionDeclaration(first,last);
+ }
+ else if (first->Type == TT_JS_CLASS) {
+ ADVANCE
+ result = parseClassDeclaration(first,last);
+ }
+ else if (first->Type == TT_JS_IF) {
+ code_location loc(*first);
+ ADVANCE
+
+ EXPECT('(',_("'(' in if statement"))
+ ADVANCE
+
+ ref<expression> cond = parseExpression(first,last);
+ EXPECT(')',_("')' in if statement"))
+ first++;
+ ref<expression> if_expr = parseInstruction(first,last);
+ ref<expression> else_expr;
+
+ if (first != last && first->Type == TT_JS_ELSE) {
+ ADVANCE
+ else_expr = parseInstruction(first,last);
+ }
+ result = new js_if(cond,if_expr,else_expr,loc);
+ }
+ else if (first->Type == TT_JS_SWITCH) {
+ result = parseSwitch(first,last,label);
+ }
+ else if (first->Type == TT_JS_WHILE) {
+ code_location loc(*first);
+
+ ADVANCE
+ EXPECT('(',_("'(' in while statement"))
+ ADVANCE
+
+ ref<expression> cond = parseExpression(first,last);
+ EXPECT(')',_("')' in while statement"))
+ first++;
+
+ ref<expression> loop_expr = parseInstruction(first,last);
+
+ if (label.size()) {
+ result = new js_while(cond,loop_expr,label,loc);
+ label = "";
+ }
+ else
+ result = new js_while(cond,loop_expr,loc);
+ }
+ else if (first->Type == TT_JS_DO) {
+ code_location loc(*first);
+
+ ADVANCE
+ ref<expression> loop_expr = parseInstruction(first,last);
+
+ EXPECT(TT_JS_WHILE,_("'while' in do-while"))
+ ADVANCE
+
+ EXPECT('(',_("'(' in do-while statement"))
+ ADVANCE
+
+ ref<expression> cond = parseExpression(first,last);
+ EXPECT(')',_("')' in do-while statement"))
+ first++;
+
+ if (label.size()) {
+ result = new js_do_while(cond,loop_expr,label,loc);
+ label = "";
+ }
+ else
+ result = new js_do_while(cond,loop_expr,loc);
+ }
+ else if (first->Type == TT_JS_FOR) {
+ code_location loc(*first);
+
+ ADVANCE
+
+ EXPECT('(',_("'(' in for statement"))
+ ADVANCE
+
+ ref<expression> init_expr;
+ if (first->Type == TT_JS_VAR) {
+ ADVANCE
+
+ init_expr = parseVariableDeclaration(first,last);
+ }
+ else
+ init_expr = parseExpression(first,last);
+
+ if (first->Type == TT_JS_IN) {
+ // for (iterator in list)
+ ADVANCE
+ ref<expression> array_expr = parseExpression(first,last);
+
+ EXPECT(')',_("')' in for statement"))
+ first++;
+
+ ref<expression> loop_expr = parseInstruction(first,last);
+
+ if (label.size()) {
+ result = new js_for_in(init_expr,array_expr,loop_expr,label,loc);
+ label = "";
+ }
+ else
+ result = new js_for_in(init_expr,array_expr,loop_expr,label,loc);
+ }
+ else {
+ // for (;;) ...
+ EXPECT(';',_("';' in for statement"))
+ ADVANCE
+
+ ref<expression> cond_expr = parseExpression(first,last);
+
+ EXPECT(';',_("';' in for statement"))
+ ADVANCE
+
+ ref<expression> update_expr = parseExpression(first,last);
+
+ EXPECT(')',_("')' in for statement"))
+ first++;
+
+ ref<expression> loop_expr = parseInstruction(first,last);
+
+ if (label.size()) {
+ result = new js_for(init_expr,cond_expr,update_expr,loop_expr,label,loc);
+ label = "";
+ }
+ else
+ result = new js_for(init_expr,cond_expr,update_expr,loop_expr,loc);
+ }
+ }
+ else if (first->Type == TT_JS_RETURN) {
+ code_location loc(*first);
+ ADVANCE
+
+ if (first->Type != ';')
+ result = new js_return(parseExpression(first,last),loc);
+ else
+ result = new js_return(makeConstantExpression(makeNull(),loc),loc);
+
+ EXPECT(';',"';'")
+ first++;
+ }
+ else if (first->Type == TT_JS_BREAK) {
+ code_location loc(*first);
+ ADVANCE
+
+ if (first->Type != ';') {
+ EXPECT(TT_JS_IDENTIFIER,_("break label"))
+ result = new js_break(first->Text,loc);
+ ADVANCE
+ }
+ else
+ result = new js_break(loc);
+
+ EXPECT(';',"';'")
+ first++;
+ }
+ else if (first->Type == TT_JS_CONTINUE) {
+ code_location loc(*first);
+ ADVANCE
+
+ if (first->Type != ';') {
+ EXPECT(TT_JS_IDENTIFIER,_("continue label"))
+ result = new js_continue(first->Text,loc);
+ ADVANCE
+ }
+ else
+ result = new js_continue(loc);
+
+ EXPECT(';',"';'")
+ first++;
+ }
+ else if (first->Type == ';') {
+ first++;
+ result = makeConstantExpression(ref<value>(NULL),*first);
+ }
+ else {
+ // was nothing else, must be expression
+ result = parseExpression(first,last);
+ EXPECT(';',"';'")
+ first++;
+ }
+
+ if (label.size()) {
+ result = new break_label(label,result,*first);
+ }
+
+ return result;
+ }
+
+
+
+
+ namespace {
+ int const
+ PREC_COMMA = 10, // , (if implemented)
+ PREC_THROW = 20, // throw (if implemented)
+ PREC_ASSIGN = 30, // += and friends [ok]
+ PREC_CONDITIONAL = 40, // ?: [ok]
+ PREC_LOG_OR = 50, // || [ok]
+ PREC_LOG_AND = 60, // && [ok]
+ PREC_BIT_OR = 70, // | [ok]
+ PREC_BIT_XOR = 80, // ^ [ok]
+ PREC_BIT_AND = 90, // & [ok]
+ PREC_EQUAL = 100, // == != === !=== [ok]
+ PREC_COMP = 110, // < <= > >= [ok]
+ PREC_SHIFT = 120, // << >> [ok]
+ PREC_ADD = 130, // + - [ok]
+ PREC_MULT = 140, // * / % [ok]
+ PREC_UNARY = 160, // new + - ++ -- ! ~
+ PREC_FUNCALL = 170, // ()
+ PREC_SUBSCRIPT = 180, // [] .
+ PREC_TERM = 200; // literal identifier
+ }
+
+
+
+
+ ref<expression>
+ parseExpression(scanner::token_iterator &first,scanner::token_iterator const &last,int precedence) {
+ /*
+ precedence:
+ the called routine will continue parsing as long as the encountered
+ operators all have precedence greater than or equal to the given parameter.
+ */
+
+ // an EOF condition cannot legally occur inside
+ // or at the end of an expression.
+
+ if (first == last) EXJS_THROW(ECJS_UNEXPECTED_EOF)
+
+ ref<expression> expr;
+
+ // parse prefix unaries -----------------------------------------------------
+ if (precedence <= PREC_UNARY) {
+ if (first->Type == TT_JS_NEW) {
+ code_location loc(*first);
+ ADVANCE
+
+ ref<expression> cls = parseExpression(first,last,PREC_SUBSCRIPT);
+
+ EXPECT('(',_("'(' in 'new' expression"))
+ ADVANCE
+
+ function_call::parameter_expression_list pexps;
+ while (first->Type != ')') {
+ pexps.push_back(parseExpression(first,last));
+
+ if (first->Type == ',') {
+ ADVANCE
+ }
+ }
+
+ EXPECT(')',_("')' in 'new' expression"))
+ ADVANCE
+
+ expr = new construction(cls,pexps,loc);
+ }
+ if (first->Type == TT_JS_INCREMENT || first->Type == TT_JS_DECREMENT) {
+ code_location loc(*first);
+ value::operator_id op = value::token2operator(*first,true,true);
+ ADVANCE
+ expr = new modifying_unary_operator(op,parseExpression(first,last,PREC_UNARY),loc);
+ }
+ if (first->Type == '+' ||first->Type == '-'
+ || first->Type == '!' || first->Type == '~') {
+ code_location loc(*first);
+ value::operator_id op = value::token2operator(*first,true,true);
+ ADVANCE
+ expr = new unary_operator(op,parseExpression(first,last,PREC_UNARY),loc);
+ }
+ }
+
+ // parse parentheses --------------------------------------------------------
+ if (first->Type == '(') {
+ ADVANCE
+ expr = parseExpression(first,last);
+ EXPECT(')',"')'")
+ ADVANCE
+ }
+
+ // parse term ---------------------------------------------------------------
+ if (expr.get() == NULL && precedence <= PREC_TERM) {
+ if (first->Type == TT_JS_LIT_INT) {
+ expr = makeConstantExpression(makeConstant(evalUnsigned(first->Text)),*first);
+ ADVANCE
+ }
+ else if (first->Type == TT_JS_LIT_FLOAT) {
+ expr = makeConstantExpression(makeConstant(evalFloat(first->Text)),*first);
+ ADVANCE
+ }
+ else if (first->Type == TT_JS_LIT_STRING) {
+ expr = makeConstantExpression(makeConstant(parseCEscapes(
+ first->Text.substr(1,first->Text.size()-2)
+ )),*first);
+ ADVANCE
+ }
+ else if (first->Type == TT_JS_LIT_TRUE) {
+ expr = makeConstantExpression(makeConstant(true),*first);
+ ADVANCE
+ }
+ else if (first->Type == TT_JS_LIT_FALSE) {
+ expr = makeConstantExpression(makeConstant(false),*first);
+ ADVANCE
+ }
+ else if (first->Type == TT_JS_LIT_UNDEFINED) {
+ expr = makeConstantExpression(makeUndefined(),*first);
+ ADVANCE
+ }
+ else if (first->Type == TT_JS_IDENTIFIER) {
+ expr = new lookup_operation(first->Text,*first);
+ ADVANCE
+ }
+ else if (first->Type == TT_JS_NULL) {
+ expr = makeConstantExpression(makeNull(),*first);
+ ADVANCE
+ }
+ }
+
+ if (expr.get() == NULL)
+ EXJS_THROWINFOTOKEN(ECJS_UNEXPECTED,("'"+first->Text+"' instead of expression").c_str(),*first)
+
+ bool parsed_something;
+ do {
+ parsed_something = false;
+
+ // parse postfix "subscripts" ---------------------------------------------
+ if (first->Type == '(' && precedence <= PREC_FUNCALL) {
+ code_location loc(*first);
+ ADVANCE
+
+ function_call::parameter_expression_list pexps;
+ while (first->Type != ')') {
+ pexps.push_back(parseExpression(first,last));
+
+ if (first->Type == ',') {
+ ADVANCE
+ }
+ }
+
+ EXPECT(')',_("')' in function call"))
+ ADVANCE
+
+ expr = new function_call(expr,pexps,loc);
+ parsed_something = true;
+ }
+ // parse postfix unary ----------------------------------------------------
+ else if ((first->Type == TT_JS_INCREMENT || first->Type == TT_JS_DECREMENT) && precedence <= PREC_UNARY) {
+ value::operator_id op = value::token2operator(*first,true);
+ expr = new modifying_unary_operator(op,expr,*first);
+ parsed_something = true;
+ ADVANCE
+ }
+ // parse special binary operators -----------------------------------------
+ else if (first->Type == '.' && precedence <= PREC_SUBSCRIPT) {
+ ADVANCE
+ expr = new lookup_operation(expr,first->Text,*first);
+ ADVANCE
+ parsed_something = true;
+ }
+ else if (first->Type == '[' && precedence <= PREC_SUBSCRIPT) {
+ code_location loc(*first);
+ ADVANCE
+
+ ref<expression> index = parseExpression(first,last);
+
+ EXPECT(']',_("']' in subscript"))
+ ADVANCE
+
+ expr = new subscript_operation(expr,index,loc);
+
+ parsed_something = true;
+ }
+
+ // parse regular binary operators -----------------------------------------
+ #define BINARY_OP(PRECEDENCE,EXPRESSION,TYPE) \
+ else if ((EXPRESSION) && precedence <= PRECEDENCE) { \
+ code_location loc(*first); \
+ value::operator_id op = value::token2operator(*first); \
+ ADVANCE \
+ ref<expression> right = parseExpression(first,last,PRECEDENCE); \
+ expr = new TYPE##_operator(op,expr,right,loc); \
+ parsed_something = true; \
+ }
+
+ BINARY_OP(PREC_MULT,first->Type == '*' || first->Type == '/' || first->Type == '%',binary)
+ BINARY_OP(PREC_ADD,first->Type == '+' || first->Type == '-',binary)
+ BINARY_OP(PREC_SHIFT,first->Type == TT_JS_LEFT_SHIFT || first->Type == TT_JS_RIGHT_SHIFT,binary)
+ BINARY_OP(PREC_COMP,first->Type == '>' || first->Type == '<'
+ || first->Type == TT_JS_LESS_EQUAL || first->Type == TT_JS_GREATER_EQUAL
+ || first->Type == TT_JS_IDENTICAL || first->Type == TT_JS_NOT_IDENTICAL,binary)
+ BINARY_OP(PREC_EQUAL,first->Type == TT_JS_EQUAL || first->Type == TT_JS_NOT_EQUAL,binary)
+ BINARY_OP(PREC_BIT_AND,first->Type == '&',binary)
+ BINARY_OP(PREC_BIT_XOR,first->Type == '^',binary)
+ BINARY_OP(PREC_BIT_OR,first->Type == '|',binary)
+ BINARY_OP(PREC_LOG_AND,first->Type == TT_JS_LOGICAL_AND,binary_shortcut)
+ BINARY_OP(PREC_LOG_OR,first->Type == TT_JS_LOGICAL_OR,binary_shortcut)
+ else if (first->Type == '?') {
+ code_location loc(*first);
+ ADVANCE
+ ref<expression> op2 = parseExpression(first,last);
+ if (first->Type != ':')
+ EXJS_THROWINFO(ECJS_UNEXPECTED,(first->Text+" instead of ':'").c_str())
+ ADVANCE
+ ref<expression> op3 = parseExpression(first,last,PREC_CONDITIONAL);
+ expr = new ternary_operator(expr,op2,op3,loc);
+ parsed_something = true;
+ }
+ else if (first->Type == '=' && precedence <= PREC_ASSIGN) {
+ code_location loc(*first);
+ ADVANCE
+ ref<expression> op2 = parseExpression(first,last);
+ expr = new assignment(expr,op2,loc);
+ parsed_something = true;
+ }
+ BINARY_OP(PREC_ASSIGN,first->Type == TT_JS_PLUS_ASSIGN
+ || first->Type == TT_JS_MINUS_ASSIGN
+ || first->Type == TT_JS_MULTIPLY_ASSIGN
+ || first->Type == TT_JS_DIVIDE_ASSIGN
+ || first->Type == TT_JS_MODULO_ASSIGN
+ || first->Type == TT_JS_BIT_XOR_ASSIGN
+ || first->Type == TT_JS_BIT_AND_ASSIGN
+ || first->Type == TT_JS_BIT_OR_ASSIGN
+ || first->Type == TT_JS_LEFT_SHIFT_ASSIGN
+ || first->Type == TT_JS_RIGHT_SHIFT_ASSIGN,modifying_binary)
+ } while (parsed_something);
+
+ return expr;
+ }
+ }
+
+
+
+
+// interpreter -----------------------------------------------------------------
+interpreter::interpreter() {
+ RootScope = new list_scope;
+
+ ref<value> ac = new js_array_constructor();
+ RootScope->addMember("Array",ac);
+ }
+
+
+
+
+interpreter::~interpreter() {
+ }
+
+
+
+
+ref<expression> interpreter::parse(string const &str) {
+ // *** FIXME: this works around a bug in istrstream
+ if (str.size() == 0) {
+ return ref<expression>(NULL);
+ }
+ istrstream strm(str.data(),str.size());
+ return parse(strm);
+ }
+
+
+
+
+ref<expression> interpreter::parse(istream &istr) {
+ jsFlexLexer lexer(&istr);
+ scanner scanner(lexer);
+
+ scanner::token_list tokenlist = scanner.scan();
+ scanner::token_iterator text = tokenlist.begin();
+ return parseInstructionList(text,tokenlist.end(),false);
+ }
+
+
+
+
+ref<value> interpreter::execute(string const &str) {
+ return execute(parse(str));
+ }
+
+
+
+
+ref<value> interpreter::execute(istream &istr) {
+ return execute(parse(istr));
+ }
+
+
+
+
+ref<value> interpreter::execute(ref<expression> expr) {
+ if (expr.get() == NULL) return ref<value>(NULL);
+ return evaluateCatchExits(expr);
+ }
+
+
+
+
+ref<value> interpreter::evaluateCatchExits(ref<expression> expr) {
+ ref<value> result;
+ try {
+ context ctx(RootScope);
+ result = expr->evaluate(ctx);
+ }
+ catch (return_exception &re) {
+ EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"return",re.Location)
+ }
+ catch (break_exception &be) {
+ if (be.HasLabel)
+ EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,("break "+be.Label).c_str(),be.Location)
+ else
+ EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"break",be.Location)
+ }
+ catch (continue_exception &ce) {
+ if (ce.HasLabel)
+ EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,("continue "+ce.Label).c_str(),ce.Location)
+ else
+ EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"continue",ce.Location)
+ }
+ return result;
+ }
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript interpreter library
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+#include <cmath>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <ixlib_js_internals.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_random.hh>
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+namespace {
+ class eval : public value {
+ protected:
+ interpreter &Interpreter;
+
+ public:
+ value_type getType() const {
+ return VT_FUNCTION;
+ }
+ eval(interpreter &interpreter)
+ : Interpreter(interpreter) {
+ }
+ ref<value> call(parameter_list const ¶meters);
+ };
+
+ class Math : public value_with_methods {
+ private:
+ typedef value_with_methods super;
+
+ protected:
+ float_random RNG;
+
+ public:
+ value_type getType() const {
+ return VT_BUILTIN;
+ }
+
+ ref<value> duplicate() const;
+
+ ref<value> lookup(string const &identifier);
+ ref<value> callMethod(string const &identifier,parameter_list const ¶meters);
+ };
+ }
+
+
+
+
+// eval -----------------------------------------------------------------------
+ref<value>
+eval::
+call(parameter_list const ¶meters) {
+ if (parameters.size() != 1) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"eval")
+ }
+ if (parameters[0]->getType() != VT_STRING) return parameters[0];
+ return Interpreter.execute(parameters[0]->toString());
+ }
+
+
+
+
+// parseInt -------------------------------------------------------------------
+IXLIB_JS_DECLARE_FUNCTION(parseInt) {
+ if (parameters.size() != 1 && parameters.size() != 2) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"parseInt")
+ }
+ unsigned radix = 10;
+ if (parameters.size() == 2)
+ radix = parameters[1]->toInt();
+ return makeConstant(evalSigned(parameters[0]->toString(),radix));
+ }
+
+
+
+
+// parseFloat -----------------------------------------------------------------
+IXLIB_JS_DECLARE_FUNCTION(parseFloat) {
+ if (parameters.size() != 1) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"parseFloat")
+ }
+ return makeConstant(evalFloat(parameters[0]->toString()));
+ }
+
+
+
+
+// isNaN ----------------------------------------------------------------------
+#ifdef ADVANCED_MATH_AVAILABLE
+IXLIB_JS_DECLARE_FUNCTION(isNaN) {
+ if (parameters.size() != 1) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"isNaN")
+ }
+ int classification = fpclassify(parameters[0]->toFloat());
+ return makeConstant(classification == FP_NAN);
+ }
+#endif
+
+
+
+
+// isFinite -------------------------------------------------------------------
+#ifdef ADVANCED_MATH_AVAILABLE
+IXLIB_JS_DECLARE_FUNCTION(isFinite) {
+ if (parameters.size() != 1) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"isFinite")
+ }
+ int classification = fpclassify(parameters[0]->toFloat());
+ return makeConstant(classification != FP_NAN && classification != FP_INFINITE);
+ }
+#endif
+
+
+
+
+// Math -----------------------------------------------------------------------
+ref<value> Math::duplicate() const {
+ // Math is not mutable
+ return const_cast<Math *>(this);
+ }
+
+
+
+
+ref<value> Math::lookup(string const &identifier) {
+ #define MATH_CONSTANT(NAME,VALUE) \
+ if (identifier == NAME) return makeConstant(VALUE);
+
+ MATH_CONSTANT("E",2.7182818284590452354)
+ MATH_CONSTANT("LN10",2.30258509299404568402)
+ MATH_CONSTANT("LN2",0.69314718055994530942)
+ MATH_CONSTANT("LOG2E",1.4426950408889634074)
+ MATH_CONSTANT("LOG10E,",0.43429448190325182765)
+ MATH_CONSTANT("PI",3.14159265358979323846)
+ MATH_CONSTANT("SQRT1_2",0.70710678118654752440)
+ MATH_CONSTANT("SQRT2",1.41421356237309504880)
+
+ return super::lookup(identifier);
+ }
+
+
+
+
+ref<value> Math::callMethod(string const &identifier,parameter_list const ¶meters) {
+ #define MATH_FUNCTION(NAME,C_NAME) \
+ if (identifier == NAME) { \
+ if (parameters.size() != 1) { \
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math." NAME) \
+ } \
+ return makeConstant(C_NAME(parameters[0]->toFloat())); \
+ }
+
+ MATH_FUNCTION("abs",NUM_ABS)
+ MATH_FUNCTION("acos",acos)
+ MATH_FUNCTION("asin",asin)
+ MATH_FUNCTION("atan",atan)
+ MATH_FUNCTION("ceil",ceil)
+ MATH_FUNCTION("cos",cos)
+ MATH_FUNCTION("exp",exp)
+ MATH_FUNCTION("floor",floor)
+ MATH_FUNCTION("log",log)
+ #ifdef ADVANCED_MATH_AVAILABLE
+ MATH_FUNCTION("round",round)
+ #endif
+ MATH_FUNCTION("sin",sin)
+ MATH_FUNCTION("sqrt",sqrt)
+ MATH_FUNCTION("tan",tan)
+ if (identifier == "atan2") {
+ if (parameters.size() != 2) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math.atan2")
+ }
+ return makeConstant(atan2(parameters[0]->toFloat(),parameters[1]->toFloat()));
+ }
+ if (identifier == "pow") {
+ if (parameters.size() != 2) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math.pow")
+ }
+ return makeConstant(pow(parameters[0]->toFloat(),parameters[1]->toFloat()));
+ }
+ if (identifier == "random") {
+ if (parameters.size() != 0) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math.random")
+ }
+ return makeConstant(RNG());
+ }
+ // *** FIXME this is non-compliant, but there is no equivalent standard function
+ if (identifier == "initRandom") {
+ if (parameters.size() >= 2) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math.initRandom")
+ }
+ if (parameters.size() == 0)
+ RNG.init();
+ else if (parameters.size() == 1)
+ RNG.init(parameters[0]->toFloat());
+ return makeNull();
+ }
+
+ // *** FIXME: implement max, min
+ EXJS_THROWINFO(ECJS_UNKNOWN_IDENTIFIER,("Math." + identifier).c_str())
+ }
+
+
+
+
+// external interface functions -----------------------------------------------
+#define ADD_GLOBAL_OBJECT(NAME,TYPE) \
+ { ref<value> x = new TYPE(); \
+ ip.RootScope->addMember(NAME,x); \
+ }
+
+
+
+
+void javascript::addGlobal(interpreter &ip) {
+ ref<value> ev = new eval(ip);
+ ip.RootScope->addMember("eval",ev);
+
+ ADD_GLOBAL_OBJECT("parseInt",parseInt)
+ ADD_GLOBAL_OBJECT("parseFloat",parseFloat)
+ #ifdef ADVANCED_MATH_AVAILABLE
+ ADD_GLOBAL_OBJECT("isNaN",isNaN)
+ ADD_GLOBAL_OBJECT("isFinite",isFinite)
+ #endif
+
+ // *** FIXME hope this is portable
+ float zero = 0;
+ ip.RootScope->addMember("NaN",makeConstant(0.0/zero));
+ ip.RootScope->addMember("Infinity",makeConstant(1.0/zero));
+ ip.RootScope->addMember("undefined",makeUndefined());
+ }
+
+
+
+
+void javascript::addMath(interpreter &ip) {
+ ADD_GLOBAL_OBJECT("Math",Math)
+ }
+
+
+
+
+void javascript::addStandardLibrary(interpreter &ip) {
+ addGlobal(ip);
+ addMath(ip);
+ }
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Javascript interpreter
+// ----------------------------------------------------------------------------
+// (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <cstdio>
+#include <ixlib_i18n.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_re.hh>
+#include <ixlib_string.hh>
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+using namespace std;
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// value ----------------------------------------------------------------------
+string value::toString() const {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_CONVERT,
+ (valueType2string(getType())+string(_("-> string"))).c_str())
+ }
+
+
+
+
+int value::toInt() const {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_CONVERT,
+ (valueType2string(getType())+_(" -> int")).c_str())
+ }
+
+
+
+
+double value::toFloat() const {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_CONVERT,
+ (valueType2string(getType())+_(" -> float")).c_str())
+ }
+
+
+
+
+bool value::toBoolean() const {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_CONVERT,
+ (valueType2string(getType())+_(" -> bool")).c_str())
+ }
+
+
+
+
+string value::stringify() const {
+ try {
+ return toString();
+ }
+ catch (...) {
+ return string("#<")+valueType2string(getType())+">";
+ }
+ }
+
+
+
+
+ref<value> value::eliminateWrappers() {
+ return this;
+ }
+
+
+
+
+ref<value> value::duplicate() {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+_(": duplication")).c_str())
+ }
+
+
+
+
+ref<value>
+value::lookup(string const &identifier) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+_(": lookup of ")+identifier).c_str())
+ }
+
+
+
+
+ref<value>
+value::subscript(value const &index) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+_(": subscript")).c_str())
+ }
+
+
+
+
+ref<value>
+value::call(parameter_list const ¶meters) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+_(": call")).c_str())
+ }
+
+
+
+
+ref<value>
+value::callAsMethod(ref<value> instance,parameter_list const ¶meters) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+_(": call as method")).c_str())
+ }
+
+
+
+
+ref<value>
+value::construct(parameter_list const ¶meters) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+_(": construction")).c_str())
+ }
+
+
+
+
+ref<value> value::assign(ref<value> op2) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+_(": assignment")).c_str())
+ }
+
+
+
+
+ref<value>
+value::operatorUnary(operator_id op) const {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+_(": operator ")+operator2string(op)).c_str())
+ }
+
+
+
+
+ref<value>
+value::operatorBinary(operator_id op,ref<value> op2) const {
+ if (op == OP_EQUAL) {
+ if (getType() == VT_NULL)
+ return makeConstant(op2->getType() == VT_NULL);
+ if (op2->getType() == VT_NULL)
+ return makeConstant(getType() == VT_NULL);
+ }
+ if (op == OP_NOT_EQUAL) {
+ if (getType() == VT_NULL)
+ return makeConstant(op2->getType() != VT_NULL);
+ if (op2->getType() == VT_NULL)
+ return makeConstant(getType() != VT_NULL);
+ }
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+" "+string(operator2string(op))+" "+valueType2string(op2->getType())).c_str())
+ }
+
+
+
+
+ref<value>
+value::operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const {
+ if (op == OP_LOGICAL_OR)
+ return makeConstant(toBoolean() || op2.evaluate(ctx)->toBoolean());
+ if (op == OP_LOGICAL_AND)
+ return makeConstant(toBoolean() && op2.evaluate(ctx)->toBoolean());
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (string(operator2string(op))+_(" on ")+valueType2string(getType())).c_str())
+ }
+
+
+
+
+ref<value>
+value::operatorUnaryModifying(operator_id op) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (string(operator2string(op))+_(" on ")+valueType2string(getType())).c_str())
+ }
+
+
+
+
+ref<value>
+value::operatorBinaryModifying(operator_id op,ref<value> op2) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+ (valueType2string(getType())+" "+string(operator2string(op))+" "+valueType2string(op2->getType())).c_str())
+ }
+
+
+
+
+value::operator_id
+value::token2operator(scanner::token const &token,bool unary,bool prefix) {
+ switch (token.Type) {
+ case TT_JS_INCREMENT: return prefix ? OP_PRE_INCREMENT : OP_POST_INCREMENT;
+ case TT_JS_DECREMENT: return prefix ? OP_PRE_DECREMENT : OP_POST_DECREMENT;
+ case '+': return unary ? OP_UNARY_PLUS : OP_PLUS;
+ case '-': return unary ? OP_UNARY_MINUS : OP_MINUS;
+ case '!': return OP_LOG_NOT;
+ case '~': return OP_BIN_NOT;
+ case TT_JS_PLUS_ASSIGN: return OP_PLUS_ASSIGN;
+ case TT_JS_MINUS_ASSIGN: return OP_MINUS_ASSIGN;
+ case TT_JS_MULTIPLY_ASSIGN: return OP_MUTLIPLY_ASSIGN;
+ case TT_JS_DIVIDE_ASSIGN: return OP_DIVIDE_ASSIGN;
+ case TT_JS_MODULO_ASSIGN: return OP_MODULO_ASSIGN;
+ case TT_JS_BIT_AND_ASSIGN: return OP_BIT_AND_ASSIGN;
+ case TT_JS_BIT_OR_ASSIGN: return OP_BIT_OR_ASSIGN;
+ case TT_JS_BIT_XOR_ASSIGN: return OP_BIT_XOR_ASSIGN;
+ case TT_JS_LEFT_SHIFT_ASSIGN: return OP_LEFT_SHIFT_ASSIGN;
+ case TT_JS_RIGHT_SHIFT_ASSIGN: return OP_RIGHT_SHIFT_ASSIGN;
+ case '*': return OP_MULTIPLY;
+ case '/': return OP_DIVIDE;
+ case '%': return OP_MODULO;
+ case '&': return OP_BIT_AND;
+ case '|': return OP_BIT_OR;
+ case '^': return OP_BIT_XOR;
+ case TT_JS_LEFT_SHIFT: return OP_LEFT_SHIFT;
+ case TT_JS_RIGHT_SHIFT: return OP_RIGHT_SHIFT;
+ case TT_JS_LOGICAL_OR: return OP_LOGICAL_OR;
+ case TT_JS_LOGICAL_AND: return OP_LOGICAL_AND;
+ case TT_JS_EQUAL: return OP_EQUAL;
+ case TT_JS_NOT_EQUAL: return OP_NOT_EQUAL;
+ case TT_JS_IDENTICAL: return OP_IDENTICAL;
+ case TT_JS_NOT_IDENTICAL: return OP_NOT_IDENTICAL;
+ case TT_JS_LESS_EQUAL: return OP_LESS_EQUAL;
+ case TT_JS_GREATER_EQUAL: return OP_GREATER_EQUAL;
+ case '<': return OP_LESS;
+ case '>': return OP_GREATER;
+ default: EXJS_THROWINFO(ECJS_UNKNOWN_OPERATOR,token.Text.c_str())
+ }
+ }
+
+
+
+
+string
+value::operator2string(operator_id op) {
+ switch (op) {
+ case OP_PRE_INCREMENT: return _("prefix ++");
+ case OP_POST_INCREMENT: return _("postfix ++");
+ case OP_PRE_DECREMENT: return _("prefix --");
+ case OP_POST_DECREMENT: return _("postfix ++");
+
+ case OP_UNARY_PLUS: return _("unary +");
+ case OP_UNARY_MINUS: return _("unary -");
+ case OP_LOG_NOT: return "!";
+ case OP_BIN_NOT: return "~";
+
+ case OP_PLUS_ASSIGN: return "+=";
+ case OP_MINUS_ASSIGN: return "-=";
+ case OP_MUTLIPLY_ASSIGN: return "*=";
+ case OP_DIVIDE_ASSIGN: return "/=";
+ case OP_MODULO_ASSIGN: return "%=";
+
+ case OP_BIT_AND_ASSIGN: return "&=";
+ case OP_BIT_OR_ASSIGN: return "|=";
+ case OP_BIT_XOR_ASSIGN: return "^=";
+ case OP_LEFT_SHIFT_ASSIGN: return "<<=";
+ case OP_RIGHT_SHIFT_ASSIGN: return ">>=";
+
+ case OP_PLUS: return "+";
+ case OP_MINUS: return "-";
+ case OP_MULTIPLY: return "*";
+ case OP_DIVIDE: return "/";
+ case OP_MODULO: return "%";
+
+ case OP_BIT_AND: return "&";
+ case OP_BIT_OR: return "|";
+ case OP_BIT_XOR: return "^";
+ case OP_LEFT_SHIFT: return "<<";
+ case OP_RIGHT_SHIFT: return ">>";
+
+ case OP_LOGICAL_OR: return "|";
+ case OP_LOGICAL_AND: return "&";
+ case OP_EQUAL: return "==";
+ case OP_NOT_EQUAL: return "!=";
+ case OP_IDENTICAL: return "===";
+ case OP_NOT_IDENTICAL: return "!==";
+ case OP_LESS_EQUAL: return "<=";
+ case OP_GREATER_EQUAL: return ">=";
+ case OP_LESS: return "<";
+ case OP_GREATER: return ">";
+
+ case OP_ASSIGN: return "=";
+ default: EXJS_THROW(ECJS_UNKNOWN_OPERATOR)
+ }
+ }
+
+
+
+
+string value::valueType2string(value_type vt) {
+ switch (vt) {
+ case VT_UNDEFINED: return _("undefined");
+ case VT_NULL: return _("null");
+ case VT_INTEGER: return _("integer");
+ case VT_FLOATING_POINT: return _("floating point");
+ case VT_STRING: return _("string");
+ case VT_FUNCTION: return _("function");
+ case VT_OBJECT: return _("object");
+ case VT_BUILTIN: return _("built-in object");
+ case VT_HOST: return _("host object");
+ case VT_SCOPE: return _("scope");
+ case VT_BOUND_METHOD: return _("bound method");
+ case VT_TYPE: return _("type");
+ default: return _("unknown value type");
+ }
+ }
+
+
+
+
+// value_with_methods ---------------------------------------------------------
+value_with_methods::bound_method::
+bound_method(string const &identifier,ref<value_with_methods,value> parent)
+ : Identifier(identifier),Parent(parent) {
+ }
+
+
+
+
+ref<value>
+value_with_methods::bound_method::duplicate() {
+ // bound_methods are immutable
+ return this;
+ }
+
+
+
+
+ref<value>
+value_with_methods::bound_method::
+call(parameter_list const ¶meters) {
+ return Parent->callMethod(Identifier,parameters);
+ }
+
+
+
+
+ref<value>
+value_with_methods::
+lookup(string const &identifier) {
+ ref<value> result = new bound_method(identifier,this);
+ return result;
+ }
+
+
+
+
+// null -----------------------------------------------------------------------
+value::value_type null::getType() const {
+ return VT_NULL;
+ }
+
+
+
+
+bool null::toBoolean() const {
+ return false;
+ }
+
+
+
+
+ref<value> null::duplicate() {
+ return makeNull();
+ }
+
+
+
+
+// const_floating_point -------------------------------------------------------
+const_floating_point::const_floating_point(double value)
+ : Value(value) {
+ }
+
+
+
+
+value::value_type const_floating_point::getType() const {
+ return VT_FLOATING_POINT;
+ }
+
+
+
+
+int const_floating_point::toInt() const {
+ return (int) Value;
+ }
+
+
+
+
+double const_floating_point::toFloat() const {
+ return (double) Value;
+ }
+
+
+
+
+bool const_floating_point::toBoolean() const {
+ return (bool) Value;
+ }
+
+
+
+
+string const_floating_point::toString() const {
+ return float2dec(Value);
+ }
+
+
+
+
+ref<value> const_floating_point::duplicate() {
+ return makeValue(Value);
+ }
+
+
+
+
+ref<value>
+const_floating_point::
+callMethod(string const &identifier,parameter_list const ¶meters) {
+ IXLIB_JS_IF_METHOD("toInt",0,0)
+ return makeConstant((signed long) Value);
+ IXLIB_JS_IF_METHOD("toFloat",0,0)
+ return makeConstant(Value);
+ IXLIB_JS_IF_METHOD("toString",0,1) {
+ unsigned radix = 10;
+ if (parameters.size() == 1) radix = parameters[0]->toInt();
+ if (radix == 10)
+ return makeConstant(float2dec(Value));
+ else
+ return makeConstant(signed2base((int) Value,0,radix));
+ }
+ IXLIB_JS_IF_METHOD("toFixed",0,1) {
+ unsigned digits = 0;
+ if (parameters.size() == 1) digits = parameters[0]->toInt();
+
+ char buffer[1024];
+ sprintf(buffer,("%."+unsigned2dec(digits)+"f").c_str(),Value);
+ return makeConstant(buffer);
+ }
+ IXLIB_JS_IF_METHOD("toExponential",0,1) {
+ char buffer[1024];
+ if (parameters.size() == 1)
+ sprintf(buffer,("%."+unsigned2dec(parameters[0]->toInt())+"e").c_str(),Value);
+ else
+ sprintf(buffer,"%e",Value);
+ return makeConstant(buffer);
+ }
+ IXLIB_JS_IF_METHOD("toPrecision",0,1) {
+ if (parameters.size() == 1)
+ return makeConstant(float2dec(Value,parameters[0]->toInt()));
+ else
+ return makeConstant(float2dec(Value));
+ }
+ EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,("float." + identifier).c_str())
+ }
+
+
+
+
+ref<value>
+const_floating_point::operatorUnary(operator_id op) const {
+ switch (op) {
+ case OP_UNARY_PLUS: return makeConstant(+Value);
+ case OP_UNARY_MINUS: return makeConstant(-Value);
+ case OP_LOG_NOT: return makeConstant(!Value);
+ case OP_BIN_NOT: return makeConstant(~ (long) Value);
+ default:
+ return super::operatorUnary(op);
+ }
+ }
+
+
+
+
+ref<value>
+const_floating_point::operatorBinary(operator_id op,ref<value> op2) const {
+ #define FLOAT_OPERATOR(OP) \
+ if (op2->getType() == VT_FLOATING_POINT || op2->getType() == VT_INTEGER) \
+ return makeConstant(Value OP op2->toFloat());
+ #define PASS_UP \
+ return super::operatorBinary(op,op2);
+
+ switch (op) {
+ case OP_PLUS:
+ FLOAT_OPERATOR(+)
+ PASS_UP
+ case OP_MINUS:
+ FLOAT_OPERATOR(-)
+ PASS_UP
+ case OP_MULTIPLY:
+ FLOAT_OPERATOR(*)
+ PASS_UP
+ case OP_DIVIDE:
+ if (op2->getType() == VT_FLOATING_POINT || op2->getType() == VT_INTEGER) {
+ double op2value = op2->toFloat();
+ if (op2value == 0)
+ EXJS_THROW(ECJS_DIVISION_BY_ZERO)
+ return makeConstant(Value / op2value);
+ }
+ PASS_UP
+ case OP_EQUAL:
+ FLOAT_OPERATOR(==)
+ PASS_UP
+ case OP_NOT_EQUAL:
+ FLOAT_OPERATOR(!=)
+ PASS_UP
+ case OP_LESS_EQUAL:
+ FLOAT_OPERATOR(<=)
+ PASS_UP
+ case OP_GREATER_EQUAL:
+ FLOAT_OPERATOR(>=)
+ PASS_UP
+ case OP_LESS:
+ FLOAT_OPERATOR(<)
+ PASS_UP
+ case OP_GREATER:
+ FLOAT_OPERATOR(>)
+ PASS_UP
+ default:
+ return super::operatorBinary(op,op2);
+ }
+ #undef FLOAT_OPERATOR
+ #undef PASS_UP
+ }
+
+
+
+
+// floating_point -------------------------------------------------------------
+floating_point::floating_point(double val)
+ : const_floating_point(val) {
+ }
+
+
+
+
+ref<value>
+floating_point::operatorUnaryModifying(operator_id op) {
+ switch (op) {
+ case OP_PRE_INCREMENT:
+ Value++;
+ return ref<value>(this);
+ case OP_POST_INCREMENT:
+ // *** FIXME this should be an lvalue
+ return makeConstant(Value++);
+ case OP_PRE_DECREMENT:
+ Value--;
+ return ref<value>(this);
+ case OP_POST_DECREMENT:
+ // *** FIXME this should be an lvalue
+ return makeConstant(Value--);
+ default:
+ return super::operatorUnaryModifying(op);
+ }
+ }
+
+
+
+
+ref<value>
+floating_point::operatorBinaryModifying(operator_id op,ref<value> op2) {
+ int val;
+ switch (op) {
+ case OP_PLUS_ASSIGN:
+ Value += op2->toFloat();
+ return ref<value>(this);
+ case OP_MINUS_ASSIGN:
+ Value -= op2->toFloat();
+ return ref<value>(this);
+ case OP_MUTLIPLY_ASSIGN:
+ Value *= op2->toFloat();
+ return ref<value>(this);
+ case OP_DIVIDE_ASSIGN: {
+ double op2value = op2->toFloat();
+ if (op2value == 0)
+ EXJS_THROW(ECJS_DIVISION_BY_ZERO)
+ Value /= op2value;
+ return ref<value>(this);
+ }
+ case OP_MODULO_ASSIGN:
+ val = (int) Value;
+ val %= (int) op2->toFloat();
+ Value = val;
+ return ref<value>(this);
+ case OP_BIT_AND_ASSIGN:
+ val = (int) Value;
+ val &= (int) op2->toFloat();
+ Value = val;
+ return ref<value>(this);
+ case OP_BIT_OR_ASSIGN:
+ val = (int) Value;
+ val |= (int) op2->toFloat();
+ Value = val;
+ return ref<value>(this);
+ case OP_BIT_XOR_ASSIGN:
+ val = (int) Value;
+ val ^= (int) op2->toFloat();
+ Value = val;
+ return ref<value>(this);
+ case OP_LEFT_SHIFT_ASSIGN:
+ val = (int) Value;
+ val <<= (int) op2->toFloat();
+ Value = val;
+ return ref<value>(this);
+ case OP_RIGHT_SHIFT_ASSIGN:
+ val = (int) Value;
+ val >>= (int) op2->toFloat();
+ Value = val;
+ return ref<value>(this);
+ default:
+ return super::operatorBinaryModifying(op,op2);
+ }
+ }
+
+
+
+
+// const_integer --------------------------------------------------------------
+const_integer::const_integer(long value)
+ : Value(value) {
+ }
+
+
+
+
+value::value_type const_integer::getType() const {
+ return VT_INTEGER;
+ }
+
+
+
+
+int const_integer::toInt() const {
+ return (int) Value;
+ }
+
+
+
+
+double const_integer::toFloat() const {
+ return (double) Value;
+ }
+
+
+
+
+bool const_integer::toBoolean() const {
+ return (bool) Value;
+ }
+
+
+
+
+string const_integer::toString() const {
+ return signed2dec(Value);
+ }
+
+
+
+
+ref<value> const_integer::duplicate() {
+ return makeValue(Value);
+ }
+
+
+
+
+ref<value>
+const_integer::
+callMethod(string const &identifier,parameter_list const ¶meters) {
+ IXLIB_JS_IF_METHOD("toInt",0,0)
+ return makeConstant(Value);
+ IXLIB_JS_IF_METHOD("toFloat",0,0)
+ return makeConstant((double) Value);
+ IXLIB_JS_IF_METHOD("toString",0,1) {
+ unsigned radix = 10;
+ if (parameters.size() == 1) radix = parameters[0]->toInt();
+ return makeConstant(signed2base(Value,0,radix));
+ }
+ EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,("integer." + identifier).c_str())
+ }
+
+
+
+
+ref<value>
+const_integer::operatorUnary(operator_id op) const {
+ switch (op) {
+ case OP_UNARY_PLUS: return makeConstant(+Value);
+ case OP_UNARY_MINUS: return makeConstant(-Value);
+ case OP_LOG_NOT: return makeConstant(!Value);
+ case OP_BIN_NOT: return makeConstant(~ (long) Value);
+ default:
+ return super::operatorUnary(op);
+ }
+ }
+
+
+
+
+ref<value>
+const_integer::operatorBinary(operator_id op,ref<value> op2) const {
+ #define FLOAT_OPERATOR(OP) \
+ if (op2->getType() == VT_FLOATING_POINT) \
+ return makeConstant(toFloat() OP op2->toFloat());
+ #define INT_OPERATOR(OP) \
+ if (op2->getType() == VT_INTEGER) \
+ return makeConstant(Value OP op2->toInt());
+ #define PASS_UP \
+ return super::operatorBinary(op,op2);
+
+ switch (op) {
+ case OP_PLUS:
+ FLOAT_OPERATOR(+)
+ INT_OPERATOR(+)
+ PASS_UP
+ case OP_MINUS:
+ FLOAT_OPERATOR(-)
+ INT_OPERATOR(-)
+ PASS_UP
+ case OP_MULTIPLY:
+ FLOAT_OPERATOR(*)
+ INT_OPERATOR(*)
+ PASS_UP
+ case OP_DIVIDE:
+ if (op2->toFloat() == 0)
+ EXJS_THROW(ECJS_DIVISION_BY_ZERO)
+ FLOAT_OPERATOR(/)
+ INT_OPERATOR(/)
+ PASS_UP
+ case OP_MODULO:
+ INT_OPERATOR(%)
+ PASS_UP
+ case OP_BIT_AND:
+ INT_OPERATOR(&)
+ PASS_UP
+ case OP_BIT_OR:
+ INT_OPERATOR(|)
+ PASS_UP
+ case OP_BIT_XOR:
+ INT_OPERATOR(^)
+ PASS_UP
+ case OP_LEFT_SHIFT:
+ INT_OPERATOR(<<)
+ PASS_UP
+ case OP_RIGHT_SHIFT:
+ INT_OPERATOR(>>)
+ PASS_UP
+ case OP_EQUAL:
+ FLOAT_OPERATOR(==)
+ INT_OPERATOR(==)
+ PASS_UP
+ case OP_NOT_EQUAL:
+ FLOAT_OPERATOR(!=)
+ INT_OPERATOR(!=)
+ PASS_UP
+ case OP_LESS_EQUAL:
+ FLOAT_OPERATOR(<=)
+ INT_OPERATOR(<=)
+ PASS_UP
+ case OP_GREATER_EQUAL:
+ FLOAT_OPERATOR(>=)
+ INT_OPERATOR(>=)
+ PASS_UP
+ case OP_LESS:
+ FLOAT_OPERATOR(<)
+ INT_OPERATOR(<)
+ PASS_UP
+ case OP_GREATER:
+ FLOAT_OPERATOR(>)
+ INT_OPERATOR(>)
+ PASS_UP
+ default:
+ PASS_UP
+ }
+ #undef FLOAT_OPERATOR
+ #undef INT_OPERATOR
+ #undef PASS_UP
+ }
+
+
+
+
+// integer --------------------------------------------------------------------
+integer::integer(long val)
+ : const_integer(val) {
+ }
+
+
+
+
+ref<value>
+integer::operatorUnaryModifying(operator_id op) {
+ switch (op) {
+ case OP_PRE_INCREMENT:
+ Value++;
+ return ref<value>(this);
+ case OP_POST_INCREMENT:
+ // *** FIXME this should be an lvalue
+ return makeConstant(Value++);
+ case OP_PRE_DECREMENT:
+ Value--;
+ return ref<value>(this);
+ case OP_POST_DECREMENT:
+ // *** FIXME this should be an lvalue
+ return makeConstant(Value--);
+ default:
+ return super::operatorUnaryModifying(op);
+ }
+ }
+
+
+
+
+ref<value>
+integer::operatorBinaryModifying(operator_id op,ref<value> op2) {
+ int val;
+ int op2value = op2->toInt();
+ switch (op) {
+ case OP_PLUS_ASSIGN:
+ Value += op2value;
+ return ref<value>(this);
+ case OP_MINUS_ASSIGN:
+ Value -= op2value;
+ return ref<value>(this);
+ case OP_MUTLIPLY_ASSIGN:
+ Value *= op2value;
+ return ref<value>(this);
+ case OP_DIVIDE_ASSIGN:
+ if (op2value == 0)
+ EXJS_THROW(ECJS_DIVISION_BY_ZERO)
+ Value /= op2value;
+ return ref<value>(this);
+ case OP_MODULO_ASSIGN:
+ val = Value;
+ val %= op2value;
+ Value = val;
+ return ref<value>(this);
+ case OP_BIT_AND_ASSIGN:
+ val = Value;
+ val &= op2value;
+ Value = val;
+ return ref<value>(this);
+ case OP_BIT_OR_ASSIGN:
+ val = Value;
+ val |= op2value;
+ Value = val;
+ return ref<value>(this);
+ case OP_BIT_XOR_ASSIGN:
+ val = Value;
+ val ^= op2value;
+ Value = val;
+ return ref<value>(this);
+ case OP_LEFT_SHIFT_ASSIGN:
+ val = Value;
+ val <<= op2value;
+ Value = val;
+ return ref<value>(this);
+ case OP_RIGHT_SHIFT_ASSIGN:
+ val = Value;
+ val >>= op2value;
+ Value = val;
+ return ref<value>(this);
+ default:
+ return super::operatorBinaryModifying(op,op2);
+ }
+ }
+
+
+
+
+// js_string ------------------------------------------------------------------
+js_string::js_string(string const &value)
+ : Value(value) {
+ }
+
+
+
+
+value::value_type js_string::getType() const {
+ return VT_STRING;
+ }
+
+
+
+
+string js_string::toString() const {
+ return Value;
+ }
+
+
+
+
+bool js_string::toBoolean() const {
+ return Value.size() == 0;
+ }
+
+
+
+
+string js_string::stringify() const {
+ return '"'+Value+'"';
+ }
+
+
+
+
+ref<value> js_string::duplicate() {
+ return makeValue(Value);
+ }
+
+
+
+
+ref<value> js_string::lookup(string const &identifier) {
+ if (identifier == "length") return makeConstant(Value.size());
+ return super::lookup(identifier);
+ }
+
+
+
+
+ref<value> js_string::callMethod(string const &identifier,parameter_list const ¶meters) {
+ IXLIB_JS_IF_METHOD("toString",0,0)
+ return makeConstant(Value);
+ IXLIB_JS_IF_METHOD("charAt",1,1)
+ return makeConstant(string(1,Value.at(parameters[0]->toInt())));
+ IXLIB_JS_IF_METHOD("charCodeAt",1,1)
+ return makeConstant(Value.at(parameters[0]->toInt()));
+ if (identifier == "concat") {
+ string result = Value;
+ FOREACH_CONST(first,parameters,parameter_list)
+ Value += (*first)->toString();
+ return makeConstant(Value);
+ }
+ IXLIB_JS_IF_METHOD("indexOf",1,2) {
+ string::size_type startpos = 0;
+ if (parameters.size() == 2) startpos = parameters[1]->toInt();
+ string::size_type result = Value.find(parameters[0]->toString(),startpos);
+ if (result == string::npos) return makeConstant(-1);
+ else return makeConstant(result);
+ }
+ IXLIB_JS_IF_METHOD("lastIndexOf",1,2) {
+ string::size_type startpos = string::npos;
+ if (parameters.size() == 2) startpos = parameters[1]->toInt();
+ string::size_type result = Value.rfind(parameters[0]->toString(),startpos);
+ if (result == string::npos) return makeConstant(-1);
+ else return makeConstant(result);
+ }
+ // *** FIXME we need proper regexps
+ IXLIB_JS_IF_METHOD("match",1,1) {
+ regex_string re(parameters[0]->toString());
+ return makeConstant(re.matchAt(Value,0));
+ }
+ IXLIB_JS_IF_METHOD("replace",2,2) {
+ regex_string re(parameters[0]->toString());
+ return makeConstant(re.replaceAll(Value,parameters[1]->toString()));
+ }
+ IXLIB_JS_IF_METHOD("search",1,1) {
+ regex_string re(parameters[0]->toString());
+ return makeConstant(re.match(Value));
+ }
+ IXLIB_JS_IF_METHOD("slice",2,2) {
+ TIndex start = parameters[0]->toInt(),end = parameters[1]->toInt();
+ return makeConstant(string(Value,start,end-start));
+ }
+
+ /*
+ Allow 2 parameters here, the first one is the separator and the second
+ one is the maximum allowed number of elements of the resulting array
+ if the function is called without a parameter the string is split
+ into a character array.
+ The second parameter sets the maximum number of elements of the
+ resulting array.
+ */
+
+ IXLIB_JS_IF_METHOD("split", 0, 2 ) {
+ string::size_type start = 0, last = 0;
+ int count = 0;
+ int max = -1;
+
+ if (parameters.size() == 2)
+ max = parameters[1]->toInt();
+
+ string sep;
+
+ auto_ptr<js_array> result(new js_array(0));
+
+ if (parameters.size() == 0 || (sep = parameters[0]->toString()).empty()) {
+ for (string::size_type i = 0; i < Value.size(); ++i) {
+ string s;
+ s += Value[i];
+ result->push_back(makeValue(s));
+ }
+ }
+ else {
+ while (true) {
+ if (max > 0)
+ count++;
+
+ if (count >= max && max > 0) {
+ result->push_back(makeValue(Value.substr(last)));
+ break;
+ }
+
+ start = Value.find(sep, last);
+
+ if (start == string::npos) {
+ result->push_back(makeValue(Value.substr(last)));
+ break;
+ }
+
+ result->push_back(makeValue(Value.substr(last, start - last)));
+ last = start + sep.size();
+ }
+ }
+
+ return result.release();
+ }
+
+ IXLIB_JS_IF_METHOD("substring",2,2) {
+ TIndex start = parameters[0]->toInt(),end = parameters[1]->toInt();
+ if (start > end) swap(start,end);
+ return makeConstant(string(Value,start,end-start));
+ }
+ IXLIB_JS_IF_METHOD("toLowerCase",0,0) {
+ return makeConstant(lower(Value));
+ }
+ IXLIB_JS_IF_METHOD("toUpperCase",0,0) {
+ return makeConstant(upper(Value));
+ }
+ EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,("String." + identifier).c_str())
+ }
+
+
+
+
+ref<value> js_string::operatorBinary(operator_id op,ref<value> op2) const {
+ switch (op) {
+ case OP_PLUS: return makeConstant(Value+op2->toString());
+ case OP_EQUAL:
+ if (op2->getType() == VT_STRING) return makeConstant(Value == op2->toString());
+ else return super::operatorBinary(op,op2);
+ case OP_NOT_EQUAL:
+ if (op2->getType() == VT_STRING) return makeConstant(Value != op2->toString());
+ else return super::operatorBinary(op,op2);
+ case OP_LESS_EQUAL:
+ if (op2->getType() == VT_STRING) return makeConstant(Value <= op2->toString());
+ else return super::operatorBinary(op,op2);
+ case OP_GREATER_EQUAL:
+ if (op2->getType() == VT_STRING) return makeConstant(Value >= op2->toString());
+ else return super::operatorBinary(op,op2);
+ case OP_LESS:
+ if (op2->getType() == VT_STRING) return makeConstant(Value < op2->toString());
+ else return super::operatorBinary(op,op2);
+ case OP_GREATER:
+ if (op2->getType() == VT_STRING) return makeConstant(Value > op2->toString());
+ else return super::operatorBinary(op,op2);
+ default:
+ return super::operatorBinary(op,op2);
+ }
+ }
+
+
+
+
+ref<value> js_string::operatorBinaryModifying(operator_id op,ref<value> op2) {
+ switch (op) {
+ case OP_PLUS_ASSIGN:
+ Value += op2->toString();
+ return ref<value>(this);
+ default:
+ return super::operatorBinaryModifying(op,op2);
+ }
+ }
+
+
+
+
+// lvalue ---------------------------------------------------------------------
+lvalue::lvalue(ref<value> ref)
+ : Reference(ref) {
+ }
+
+
+
+
+value::value_type lvalue::getType() const {
+ return Reference->getType();
+ }
+
+
+
+
+string lvalue::toString() const {
+ return Reference->toString();
+ }
+
+
+
+
+int lvalue::toInt() const {
+ return Reference->toInt();
+ }
+
+
+
+
+double lvalue::toFloat() const {
+ return Reference->toFloat();
+ }
+
+
+
+
+bool lvalue::toBoolean() const {
+ return Reference->toBoolean();
+ }
+
+
+
+
+string lvalue::stringify() const {
+ return Reference->stringify();
+ }
+
+
+
+
+ref<value> lvalue::eliminateWrappers() {
+ return Reference.get();
+ }
+
+
+
+
+ref<value> lvalue::duplicate() {
+ return makeLValue(Reference->duplicate());
+ }
+
+
+
+
+ref<value> lvalue::lookup(string const &identifier) {
+ return Reference->lookup(identifier);
+ }
+
+
+
+
+ref<value> lvalue::subscript(value const &index) {
+ return Reference->subscript(index);
+ }
+
+
+
+
+ref<value> lvalue::call(parameter_list const ¶meters) {
+ return Reference->call(parameters);
+ }
+
+
+
+
+ref<value>
+lvalue::callAsMethod(ref<value> instance,parameter_list const ¶meters) {
+ return Reference->callAsMethod(instance,parameters);
+ }
+
+
+
+
+ref<value>
+lvalue::construct(parameter_list const ¶meters) {
+ return Reference->construct(parameters);
+ }
+
+
+
+
+ref<value> lvalue::assign(ref<value> op2) {
+ Reference = op2;
+ return this;
+ }
+
+
+
+
+ref<value> lvalue::operatorUnary(operator_id op) const {
+ return Reference->operatorUnary(op);
+ }
+
+
+
+
+ref<value> lvalue::operatorBinary(operator_id op,ref<value> op2) const {
+ return Reference->operatorBinary(op,op2);
+ }
+
+
+
+
+ref<value> lvalue::operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const {
+ return Reference->operatorBinaryShortcut(op,op2,ctx);
+ }
+
+
+
+
+#define LVALUE_RETURN(VALUE) \
+ ref<value> __result = VALUE; \
+ if (__result.get() == Reference.get()) \
+ return this; \
+ else \
+ return __result;
+
+
+
+
+ref<value> lvalue::operatorUnaryModifying(operator_id op) {
+ LVALUE_RETURN(Reference->operatorUnaryModifying(op))
+ }
+
+
+
+
+ref<value> lvalue::operatorBinaryModifying(operator_id op,ref<value> op2) {
+ LVALUE_RETURN(Reference->operatorBinaryModifying(op,op2))
+ }
+
+
+
+
+// constant_wrapper -----------------------------------------------------------
+constant_wrapper::constant_wrapper(ref<value> val)
+ : Constant(val) {
+ }
+
+
+
+
+value::value_type constant_wrapper::getType() const {
+ return Constant->getType();
+ }
+
+
+
+
+string constant_wrapper::toString() const {
+ return Constant->toString();
+ }
+
+
+
+
+int constant_wrapper::toInt() const {
+ return Constant->toInt();
+ }
+
+
+
+
+double constant_wrapper::toFloat() const {
+ return Constant->toFloat();
+ }
+
+
+
+
+bool constant_wrapper::toBoolean() const {
+ return Constant->toBoolean();
+ }
+
+
+
+
+string constant_wrapper::stringify() const {
+ return Constant->stringify();
+ }
+
+
+
+
+ref<value>
+constant_wrapper::eliminateWrappers() {
+ return Constant.get();
+ }
+
+
+
+
+ref<value>
+constant_wrapper::duplicate() {
+ return wrapConstant(Constant->duplicate());
+ }
+
+
+
+
+ref<value>
+constant_wrapper::lookup(string const &identifier) {
+ return Constant->lookup(identifier);
+ }
+
+
+
+
+ref<value>
+constant_wrapper::subscript(value const &index) {
+ return Constant->subscript(index);
+ }
+
+
+
+
+ref<value>
+constant_wrapper::call(parameter_list const ¶meters) const {
+ return Constant->call(parameters);
+ }
+
+
+
+
+ref<value>
+constant_wrapper::callAsMethod(ref<value> instance,parameter_list const ¶meters) {
+ return Constant->callAsMethod(instance,parameters);
+ }
+
+
+
+
+ref<value>
+constant_wrapper::construct(parameter_list const ¶meters) {
+ return Constant->construct(parameters);
+ }
+
+
+
+
+ref<value>
+constant_wrapper::assign(ref<value> value) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_MODIFY_RVALUE,_("by assignment"))
+ }
+
+
+
+
+ref<value>
+constant_wrapper::operatorUnary(operator_id op) const {
+ return Constant->operatorUnary(op);
+ }
+
+
+
+
+ref<value>
+constant_wrapper::operatorBinary(operator_id op,ref<value> op2) const {
+ return Constant->operatorBinary(op,op2);
+ }
+
+
+
+
+ref<value>
+constant_wrapper::operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const {
+ return Constant->operatorBinaryShortcut(op,op2,ctx);
+ }
+
+
+
+ref<value>
+constant_wrapper::operatorUnaryModifying(operator_id op) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_MODIFY_RVALUE,operator2string(op).c_str())
+ }
+
+
+
+ref<value>
+constant_wrapper::operatorBinaryModifying(operator_id op,ref<value> op2) {
+ EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_MODIFY_RVALUE,operator2string(op).c_str())
+ }
+
+
+
+
+// list_scope -----------------------------------------------------------------
+ref<value>
+list_scope::lookup(string const &identifier) {
+ member_map::iterator item = MemberMap.find(identifier);
+ if (item != MemberMap.end())
+ return item->second;
+
+ FOREACH_CONST(first,SwallowedList,swallowed_list) {
+ try {
+ return (*first)->lookup(identifier);
+ }
+ catch (...) { }
+ }
+ EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,identifier.c_str())
+ }
+
+
+
+
+void list_scope::unite(ref<value> scope) {
+ SwallowedList.push_back(scope);
+ }
+
+
+
+
+void list_scope::separate(ref<value> scope) {
+ FOREACH(first,SwallowedList,swallowed_list) {
+ if (*first == scope) {
+ SwallowedList.erase(first);
+ return;
+ }
+ }
+ EXGEN_THROW(EC_ITEMNOTFOUND)
+ }
+
+
+
+
+void list_scope::clearScopes() {
+ SwallowedList.clear();
+ }
+
+
+
+
+bool list_scope::hasMember(string const &name) const {
+ member_map::const_iterator item = MemberMap.find(name);
+ return item != MemberMap.end();
+ }
+
+
+
+
+void list_scope::addMember(string const &name,ref<value> member) {
+ if (hasMember(name))
+ EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_REDECLARE,name.c_str())
+
+ MemberMap[name] = member;
+ }
+
+
+
+
+void list_scope::removeMember(string const &name) {
+ MemberMap.erase(name);
+ }
+
+
+
+
+void list_scope::clearMembers() {
+ MemberMap.clear();
+ }
+
+
+
+
+void list_scope::clear() {
+ clearScopes();
+ clearMembers();
+ }
+
+
+
+
+// callable_with_parameters ---------------------------------------------------
+callable_with_parameters::callable_with_parameters(parameter_name_list const &pnames)
+ : ParameterNameList(pnames) {
+ }
+
+
+
+
+void callable_with_parameters::addParametersTo(list_scope &scope,parameter_list const ¶meters) const {
+ parameter_list::const_iterator
+ firstp = parameters.begin(),
+ lastp = parameters.end();
+
+ FOREACH_CONST(first,ParameterNameList,parameter_name_list) {
+ if (firstp == lastp)
+ scope.addMember(*first,makeLValue(makeNull()));
+ else
+ scope.addMember(*first,makeLValue((*firstp)->eliminateWrappers()->duplicate()));
+
+ firstp++;
+ }
+ }
+
+
+
+
+ref<value> callable_with_parameters::evaluateBody(expression &body,context const &ctx) {
+ ref<value> result;
+
+ try {
+ result = body.evaluate(ctx);
+ }
+ catch (return_exception &fr) {
+ result = fr.ReturnValue;
+ }
+ catch (break_exception &be) {
+ if (be.HasLabel)
+ EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,("break "+be.Label).c_str(),be.Location)
+ else
+ EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"break",be.Location)
+ }
+ catch (continue_exception &ce) {
+ if (ce.HasLabel)
+ EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,("continue "+ce.Label).c_str(),ce.Location)
+ else
+ EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"continue",ce.Location)
+ }
+ if (result.get()) return result->eliminateWrappers()->duplicate();
+ return ref<value>(NULL);
+ }
+
+
+
+
+// function -------------------------------------------------------------------
+function::function(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope)
+ : super(pnames),Body(body),LexicalScope(lex_scope) {
+ }
+
+
+
+
+ref<value> function::duplicate() {
+ // functions are not mutable
+ return this;
+ }
+
+
+
+
+ref<value>
+function::
+call(parameter_list const ¶meters) {
+ ref<list_scope,value> scope = new list_scope;
+ scope->unite(LexicalScope);
+
+ addParametersTo(*scope,parameters);
+ return evaluateBody(*Body,context(scope));
+
+ // ATTENTION: this is a scope cancellation point.
+ }
+
+
+
+
+// method ---------------------------------------------------------------------
+method::method(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope)
+ : super(pnames),Body(body),LexicalScope(lex_scope) {
+ }
+
+
+
+
+ref<value> method::duplicate() {
+ // methods are not mutable
+ return this;
+ }
+
+
+
+
+ref<value>
+method::
+callAsMethod(ref<value> instance,parameter_list const ¶meters) {
+ ref<list_scope,value> scope = new list_scope;
+ scope->unite(instance);
+ scope->unite(LexicalScope);
+ scope->addMember("this",instance);
+
+ addParametersTo(*scope,parameters);
+ return evaluateBody(*Body,context(scope));
+
+ // ATTENTION: this is a scope cancellation point.
+ }
+
+
+
+
+// constructor ----------------------------------------------------------------
+constructor::constructor(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope)
+ : super(pnames),Body(body),LexicalScope(lex_scope) {
+ }
+
+
+
+
+ref<value> constructor::duplicate() {
+ // constructors are not mutable
+ return this;
+ }
+
+
+
+
+ref<value>
+constructor::
+callAsMethod(ref<value> instance,parameter_list const ¶meters) {
+ ref<list_scope,value> scope = new list_scope;
+ scope->unite(LexicalScope);
+ scope->unite(instance);
+ scope->addMember("this",instance);
+
+ addParametersTo(*scope,parameters);
+ return evaluateBody(*Body,context(scope));
+
+ // ATTENTION: this is a scope cancellation point.
+ }
+
+
+
+
+// js_class -------------------------------------------------------------------
+js_class::super_instance_during_construction::super_instance_during_construction(
+ref<value> super_class)
+ : SuperClass(super_class) {
+ }
+
+
+
+
+ref<value> js_class::super_instance_during_construction::call(parameter_list const ¶meters) {
+ if (SuperClassInstance.get())
+ EXJS_THROW_NO_LOCATION(ECJS_DOUBLE_CONSTRUCTION)
+
+ SuperClassInstance = SuperClass->construct(parameters);
+ return SuperClassInstance;
+ }
+
+
+
+
+ref<value> js_class::super_instance_during_construction::lookup(string const &identifier) {
+ return getSuperClassInstance()->lookup(identifier);
+ }
+
+
+
+
+ref<value> js_class::super_instance_during_construction::getSuperClassInstance() {
+ if (SuperClassInstance.get())
+ return SuperClassInstance;
+
+ SuperClassInstance = SuperClass->construct(parameter_list());
+ return SuperClassInstance;
+ }
+
+
+
+
+js_class::js_class(ref<value> lex_scope,ref<value> super_class,ref<value> constructor,
+ref<value> static_method_scope,ref<value> method_scope,
+ref<value> static_variable_scope,declaration_list const &variable_list)
+ : LexicalScope(lex_scope),SuperClass(super_class),Constructor(constructor),
+ StaticMethodScope(static_method_scope),
+ MethodScope(method_scope),StaticVariableScope(static_variable_scope),
+ VariableList(variable_list) {
+ }
+
+
+
+
+ref<value> js_class::duplicate() {
+ // classes are not mutable
+ return this;
+ }
+
+
+
+
+ref<value> js_class::lookup(string const &identifier) {
+ try {
+ return lookupLocal(identifier);
+ }
+ catch (...) { }
+
+ if (SuperClass.get())
+ return SuperClass->lookup(identifier);
+
+ EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,identifier.c_str())
+ }
+
+
+
+
+ref<value> js_class::lookupLocal(string const &identifier) {
+ try {
+ return StaticMethodScope->lookup(identifier);
+ }
+ catch (...) { }
+
+ return StaticVariableScope->lookup(identifier);
+ }
+
+
+
+
+ref<value> js_class::construct(parameter_list const ¶meters) {
+ ref<list_scope,value> vl(new list_scope);
+
+ ref<js_class_instance,value> instance(
+ new js_class_instance(this,MethodScope,vl));
+
+ ref<list_scope,value> construction_scope(new list_scope);
+ construction_scope->unite(LexicalScope);
+ construction_scope->unite(instance);
+
+ FOREACH_CONST(first,VariableList,declaration_list)
+ (*first)->evaluate(context(vl,construction_scope));
+
+ ref<super_instance_during_construction,value> temp_super;
+ if (SuperClass.get()) {
+ temp_super = new super_instance_during_construction(SuperClass);
+ vl->addMember("super",temp_super);
+ }
+
+ if (Constructor.get())
+ Constructor->callAsMethod(instance,parameters);
+
+ if (temp_super.get()) {
+ ref<value> super = temp_super->getSuperClassInstance();
+ vl->removeMember("super");
+ instance->setSuperClassInstance(super);
+ vl->addMember("super",super);
+ }
+ return instance;
+ }
+
+
+
+
+// js_class_instance ----------------------------------------------------------
+js_class_instance::bound_method::bound_method(ref<value> instance,ref<value> method)
+ : Instance(instance),Method(method) {
+ }
+
+
+
+
+ref<value> js_class_instance::bound_method::call(parameter_list const ¶meters) {
+ return Method->callAsMethod(Instance,parameters);
+ }
+
+
+
+
+js_class_instance::js_class_instance(ref<js_class,value> cls,
+ref<value> method_scope,ref<value> variable_scope)
+ : Class(cls),MethodScope(method_scope),VariableScope(variable_scope) {
+ }
+
+
+
+
+void js_class_instance::setSuperClassInstance(ref<value> super_class_instance) {
+ SuperClassInstance = super_class_instance;
+ }
+
+
+
+
+ref<value> js_class_instance::duplicate() {
+ return this;
+ }
+
+
+
+
+ref<value> js_class_instance::lookup(string const &identifier) {
+ try {
+ ref<value> method = MethodScope->lookup(identifier);
+ ref<value> bound = new bound_method(this,method);
+ return bound;
+ }
+ catch (...) { }
+
+ try {
+ return VariableScope->lookup(identifier);
+ }
+ catch (...) { }
+
+ try {
+ return Class->lookupLocal(identifier);
+ }
+ catch (...) { }
+
+ if (SuperClassInstance.get())
+ return SuperClassInstance->lookup(identifier);
+
+ EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,identifier.c_str())
+ }
+
+
+
+
+// value creation -------------------------------------------------------------
+ref<value>
+javascript::makeUndefined() {
+ // *** FIXME: this is non-compliant
+ ref<value> result(new null());
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeNull() {
+ ref<value> result(new null());
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeValue(signed int val) {
+ ref<value> result(new integer(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeConstant(signed int val) {
+ ref<value> result(new const_integer(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeValue(unsigned int val) {
+ ref<value> result(new integer(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeConstant(unsigned int val) {
+ ref<value> result(new const_integer(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeValue(signed long val) {
+ ref<value> result(new integer(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeConstant(signed long val) {
+ ref<value> result(new const_integer(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeValue(unsigned long val) {
+ ref<value> result(new integer(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeConstant(unsigned long val) {
+ ref<value> result(new const_integer(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeValue(double val) {
+ ref<value> result(new floating_point(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeConstant(double val) {
+ ref<value> result(new const_floating_point(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeValue(string const &val) {
+ ref<value> result(new js_string(val));
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::makeConstant(string const &val) {
+ return wrapConstant(makeValue(val));
+ }
+
+
+
+
+ref<value> javascript::makeArray(TSize size) {
+ auto_ptr<js_array> result(new js_array(size));
+ return result.release();
+ }
+
+
+
+
+ref<value>
+javascript::makeLValue(ref<value> target) {
+ ref<value> result = new lvalue(target);
+ return result;
+ }
+
+
+
+
+ref<value>
+javascript::wrapConstant(ref<value> val) {
+ ref<value> result(new constant_wrapper(val));
+ return result;
+ }
--- /dev/null
+#define yyFlexLexer jsFlexLexer
+
+#line 4 "lex.javascript.cc"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <fstream>
+using std::istream;
+using std::ostream;
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+ istream* yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define YY_USES_REJECT
+
+#define yywrap() 1
+#define YY_SKIP_YYWRAP
+typedef unsigned char YY_CHAR;
+#define yytext_ptr yytext
+
+#include <FlexLexer.h>
+
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 86
+#define YY_END_OF_BUFFER 87
+static yyconst short int yy_acclist[314] =
+ { 0,
+ 87, 85, 86, 84, 85, 86, 84, 86, 26, 85,
+ 86, 85, 86, 21, 85, 86, 23, 85, 86, 85,
+ 86, 13, 85, 86, 14, 85, 86, 19, 85, 86,
+ 17, 85, 86, 30, 85, 86, 18, 85, 86, 31,
+ 85, 86, 20, 85, 86, 80, 85, 86, 80, 85,
+ 86, 16, 85, 86, 10, 85, 86, 28, 85, 86,
+ 27, 85, 86, 29, 85, 86, 15, 85, 86, 83,
+ 85, 86, 11, 85, 86, 12, 85, 86, 22, 85,
+ 86, 83, 85, 86, 83, 85, 86, 83, 85, 86,
+ 83, 85, 86, 83, 85, 86, 83, 85, 86, 83,
+
+ 85, 86, 83, 85, 86, 83, 85, 86, 83, 85,
+ 86, 83, 85, 86, 83, 85, 86, 83, 85, 86,
+ 8, 85, 86, 24, 85, 86, 9, 85, 86, 25,
+ 85, 86, 3, 86, 4, 86, 3, 86, 7, 86,
+ 6, 86, 6, 7, 86, 84, 47, 82, 36, 50,
+ 38, 82, 34, 52, 32, 53, 33, 81, 1, 5,
+ 35, 81, 80, 80, 40, 48, 46, 49, 41, 83,
+ 37, 83, 83, 83, 83, 83, 61, 83, 83, 83,
+ 83, 83, 83, 59, 83, 73, 83, 83, 83, 83,
+ 83, 83, 83, 83, 83, 83, 83, 83, 39, 51,
+
+ 2, 6, 45, 81, 80, 42, 44, 43, 83, 83,
+ 83, 83, 83, 83, 83, 83, 63, 83, 83, 83,
+ 54, 83, 83, 83, 83, 83, 83, 83, 83, 57,
+ 83, 83, 81, 83, 66, 83, 83, 83, 83, 83,
+ 62, 83, 83, 83, 83, 83, 58, 83, 83, 83,
+ 83, 55, 83, 70, 83, 83, 83, 68, 83, 75,
+ 83, 74, 83, 83, 83, 83, 71, 83, 83, 83,
+ 83, 83, 83, 83, 60, 83, 83, 83, 83, 83,
+ 83, 83, 64, 83, 78, 83, 65, 83, 83, 83,
+ 83, 69, 83, 76, 83, 83, 83, 83, 83, 67,
+
+ 83, 56, 83, 83, 83, 83, 77, 83, 72, 83,
+ 83, 79, 83
+ } ;
+
+static yyconst short int yy_accept[225] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 2, 4, 7,
+ 9, 12, 14, 17, 20, 22, 25, 28, 31, 34,
+ 37, 40, 43, 46, 49, 52, 55, 58, 61, 64,
+ 67, 70, 73, 76, 79, 82, 85, 88, 91, 94,
+ 97, 100, 103, 106, 109, 112, 115, 118, 121, 124,
+ 127, 130, 133, 135, 137, 139, 141, 143, 146, 147,
+ 148, 148, 149, 149, 150, 151, 152, 152, 153, 153,
+ 154, 155, 156, 157, 158, 159, 160, 161, 162, 163,
+ 164, 164, 164, 164, 165, 166, 167, 168, 169, 170,
+ 171, 172, 173, 174, 175, 176, 177, 179, 180, 181,
+
+ 182, 183, 184, 186, 188, 189, 190, 191, 192, 193,
+ 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+ 204, 204, 204, 204, 204, 204, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215, 216, 217,
+ 219, 220, 221, 223, 224, 225, 226, 227, 228, 229,
+ 230, 232, 233, 233, 233, 233, 233, 233, 234, 235,
+ 237, 238, 239, 240, 241, 243, 244, 245, 246, 247,
+ 249, 250, 251, 252, 254, 256, 257, 258, 258, 258,
+ 258, 258, 260, 262, 264, 265, 266, 267, 269, 270,
+ 271, 272, 273, 274, 275, 277, 278, 279, 280, 281,
+
+ 282, 283, 285, 287, 289, 290, 291, 292, 294, 296,
+ 297, 298, 299, 300, 302, 304, 305, 306, 307, 309,
+ 311, 312, 314, 314
+ } ;
+
+static yyconst int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 5, 6, 1, 1, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 19,
+ 19, 19, 19, 19, 19, 20, 20, 21, 22, 23,
+ 24, 25, 26, 1, 27, 27, 27, 27, 28, 27,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 30, 29, 29,
+ 31, 32, 33, 34, 29, 1, 35, 36, 37, 38,
+
+ 39, 40, 29, 41, 42, 29, 43, 44, 45, 46,
+ 47, 48, 29, 49, 50, 51, 52, 53, 54, 55,
+ 29, 29, 56, 57, 58, 59, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst int yy_meta[60] =
+ { 0,
+ 1, 1, 2, 1, 1, 3, 1, 1, 4, 1,
+ 1, 1, 1, 1, 1, 1, 1, 5, 5, 6,
+ 1, 1, 1, 1, 1, 4, 6, 6, 7, 7,
+ 1, 4, 1, 1, 5, 5, 6, 6, 6, 5,
+ 7, 7, 7, 7, 7, 8, 7, 7, 8, 7,
+ 8, 7, 8, 7, 8, 1, 1, 1, 1
+ } ;
+
+static yyconst short int yy_base[234] =
+ { 0,
+ 0, 0, 57, 58, 59, 61, 393, 394, 64, 69,
+ 368, 68, 367, 67, 67, 394, 394, 366, 64, 394,
+ 63, 61, 72, 74, 87, 394, 394, 59, 365, 61,
+ 394, 0, 394, 394, 364, 338, 73, 62, 66, 76,
+ 72, 92, 347, 44, 73, 339, 349, 342, 394, 73,
+ 394, 394, 394, 394, 365, 394, 121, 129, 132, 357,
+ 110, 394, 119, 394, 394, 394, 130, 131, 127, 394,
+ 394, 394, 394, 394, 129, 394, 394, 394, 132, 157,
+ 170, 146, 0, 175, 356, 394, 355, 394, 354, 0,
+ 394, 338, 326, 340, 328, 333, 0, 322, 320, 326,
+
+ 320, 322, 0, 0, 322, 312, 321, 313, 328, 320,
+ 319, 308, 321, 309, 315, 394, 394, 394, 150, 394,
+ 137, 0, 183, 0, 192, 160, 198, 0, 394, 394,
+ 394, 321, 316, 304, 133, 318, 313, 312, 300, 0,
+ 312, 309, 0, 303, 294, 294, 293, 293, 303, 302,
+ 0, 296, 181, 213, 211, 245, 203, 206, 289, 0,
+ 281, 275, 283, 260, 0, 265, 264, 228, 228, 0,
+ 227, 233, 237, 0, 0, 231, 231, 135, 202, 149,
+ 195, 0, 0, 220, 222, 223, 228, 0, 220, 213,
+ 214, 222, 217, 215, 0, 204, 203, 196, 196, 197,
+
+ 207, 0, 0, 0, 193, 201, 198, 0, 0, 190,
+ 198, 189, 155, 0, 0, 158, 134, 123, 0, 0,
+ 70, 0, 394, 285, 293, 301, 309, 313, 319, 325,
+ 329, 331, 333
+ } ;
+
+static yyconst short int yy_def[234] =
+ { 0,
+ 223, 1, 224, 224, 225, 225, 223, 223, 223, 223,
+ 223, 226, 223, 223, 227, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 228, 223, 223, 223, 228, 228, 228, 228, 228,
+ 228, 228, 228, 228, 228, 228, 228, 228, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 226, 223, 229, 223, 223, 223, 227, 227, 230, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 231, 223, 223, 223, 223, 223, 223, 228,
+ 223, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+
+ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+ 228, 228, 228, 228, 228, 223, 223, 223, 223, 223,
+ 226, 232, 227, 233, 223, 223, 223, 231, 223, 223,
+ 223, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+ 228, 228, 226, 226, 227, 227, 223, 223, 228, 228,
+ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+ 228, 228, 228, 228, 228, 228, 228, 226, 226, 227,
+ 227, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+
+ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+ 228, 228, 0, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223
+ } ;
+
+static yyconst short int yy_nxt[454] =
+ { 0,
+ 8, 9, 10, 9, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 25,
+ 26, 27, 28, 29, 30, 31, 32, 32, 32, 32,
+ 33, 8, 34, 35, 32, 36, 37, 38, 39, 40,
+ 32, 41, 32, 32, 32, 42, 32, 32, 43, 44,
+ 45, 46, 47, 48, 32, 49, 50, 51, 52, 54,
+ 54, 57, 58, 57, 58, 59, 59, 59, 55, 55,
+ 59, 59, 59, 62, 65, 68, 71, 73, 75, 75,
+ 75, 85, 86, 76, 88, 89, 74, 72, 77, 79,
+ 66, 80, 80, 81, 109, 78, 116, 110, 69, 63,
+
+ 96, 82, 79, 83, 84, 84, 84, 93, 97, 98,
+ 100, 103, 82, 111, 82, 62, 94, 104, 222, 95,
+ 99, 112, 101, 119, 119, 82, 105, 102, 83, 117,
+ 106, 119, 119, 59, 59, 59, 121, 121, 68, 68,
+ 62, 63, 62, 107, 123, 123, 75, 75, 75, 75,
+ 75, 75, 119, 119, 153, 153, 125, 68, 126, 125,
+ 126, 69, 69, 127, 127, 127, 63, 125, 63, 221,
+ 125, 220, 79, 122, 80, 80, 81, 127, 127, 127,
+ 69, 124, 162, 163, 82, 79, 62, 81, 81, 81,
+ 79, 68, 84, 84, 84, 82, 219, 82, 178, 178,
+
+ 155, 155, 82, 68, 157, 218, 157, 62, 82, 158,
+ 158, 158, 63, 82, 69, 127, 127, 127, 62, 68,
+ 158, 158, 158, 158, 158, 158, 69, 217, 180, 180,
+ 179, 179, 179, 63, 216, 215, 214, 213, 212, 179,
+ 179, 211, 69, 210, 63, 209, 208, 179, 179, 179,
+ 179, 179, 179, 68, 207, 206, 205, 204, 203, 202,
+ 201, 200, 181, 181, 181, 199, 198, 197, 196, 195,
+ 194, 181, 181, 193, 192, 191, 69, 190, 189, 181,
+ 181, 181, 181, 181, 181, 53, 53, 53, 53, 53,
+ 53, 53, 53, 56, 56, 56, 56, 56, 56, 56,
+
+ 56, 61, 188, 61, 61, 61, 61, 61, 61, 67,
+ 187, 186, 67, 67, 67, 67, 67, 90, 90, 90,
+ 90, 61, 61, 61, 185, 184, 61, 67, 67, 67,
+ 183, 182, 67, 128, 128, 154, 154, 156, 156, 177,
+ 176, 175, 174, 173, 172, 171, 170, 169, 168, 167,
+ 166, 165, 164, 161, 160, 159, 152, 151, 150, 149,
+ 148, 147, 146, 145, 144, 143, 142, 141, 140, 139,
+ 138, 137, 136, 135, 134, 133, 132, 131, 130, 129,
+ 120, 118, 115, 114, 113, 108, 92, 91, 87, 70,
+ 64, 60, 223, 7, 223, 223, 223, 223, 223, 223,
+
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223
+ } ;
+
+static yyconst short int yy_chk[454] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
+ 4, 5, 5, 6, 6, 9, 9, 9, 3, 4,
+ 10, 10, 10, 12, 14, 15, 19, 21, 22, 22,
+ 22, 28, 28, 23, 30, 30, 21, 19, 23, 24,
+ 14, 24, 24, 24, 44, 23, 50, 44, 15, 12,
+
+ 38, 24, 25, 24, 25, 25, 25, 37, 38, 39,
+ 40, 41, 24, 45, 25, 61, 37, 41, 221, 37,
+ 39, 45, 40, 57, 57, 25, 42, 40, 24, 50,
+ 42, 58, 58, 59, 59, 59, 63, 63, 67, 68,
+ 178, 61, 121, 42, 69, 69, 75, 75, 75, 79,
+ 79, 79, 119, 119, 121, 121, 75, 180, 82, 79,
+ 82, 67, 68, 82, 82, 82, 178, 75, 121, 218,
+ 79, 217, 80, 63, 80, 80, 80, 126, 126, 126,
+ 180, 69, 135, 135, 80, 81, 153, 81, 81, 81,
+ 84, 123, 84, 84, 84, 80, 216, 81, 153, 153,
+
+ 123, 123, 84, 181, 125, 213, 125, 179, 81, 125,
+ 125, 125, 153, 84, 123, 127, 127, 127, 154, 155,
+ 157, 157, 157, 158, 158, 158, 181, 212, 155, 155,
+ 154, 154, 154, 179, 211, 210, 207, 206, 205, 154,
+ 154, 201, 155, 200, 154, 199, 198, 154, 154, 154,
+ 154, 154, 154, 156, 197, 196, 194, 193, 192, 191,
+ 190, 189, 156, 156, 156, 187, 186, 185, 184, 177,
+ 176, 156, 156, 173, 172, 171, 156, 169, 168, 156,
+ 156, 156, 156, 156, 156, 224, 224, 224, 224, 224,
+ 224, 224, 224, 225, 225, 225, 225, 225, 225, 225,
+
+ 225, 226, 167, 226, 226, 226, 226, 226, 226, 227,
+ 166, 164, 227, 227, 227, 227, 227, 228, 228, 228,
+ 228, 229, 229, 229, 163, 162, 229, 230, 230, 230,
+ 161, 159, 230, 231, 231, 232, 232, 233, 233, 152,
+ 150, 149, 148, 147, 146, 145, 144, 142, 141, 139,
+ 138, 137, 136, 134, 133, 132, 115, 114, 113, 112,
+ 111, 110, 109, 108, 107, 106, 105, 102, 101, 100,
+ 99, 98, 96, 95, 94, 93, 92, 89, 87, 85,
+ 60, 55, 48, 47, 46, 43, 36, 35, 29, 18,
+ 13, 11, 7, 223, 223, 223, 223, 223, 223, 223,
+
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223
+ } ;
+
+#define REJECT \
+{ \
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \
+yy_cp = yy_full_match; /* restore poss. backed-over text */ \
+++yy_lp; \
+goto find_rule; \
+}
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "lex.javascript.yy"
+#define INITIAL 0
+/* -------- definitions ------- */
+#line 6 "lex.javascript.yy"
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+using namespace ixion;
+using namespace javascript;
+/* higher-level entities ------------------------------------------------------
+*/
+/* literals -------------------------------------------------------------------
+*/
+/* Contexts -------------------------------------------------------------------
+*/
+#define Comment 1
+
+#define LineComment 2
+
+/* Rules ----------------------------------------------------------------------
+*/
+#line 569 "lex.javascript.cc"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+#define ECHO LexerOutput( yytext, yyleng )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) LexerError( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yyFlexLexer::yylex()
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 72 "lex.javascript.yy"
+
+
+#line 699 "lex.javascript.cc"
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = &cin;
+
+ if ( ! yyout )
+ yyout = &cout;
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+ yy_state_ptr = yy_state_buf;
+ *yy_state_ptr++ = yy_current_state;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 224 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *yy_state_ptr++ = yy_current_state;
+ ++yy_cp;
+ }
+ while ( yy_current_state != 223 );
+
+yy_find_action:
+ yy_current_state = *--yy_state_ptr;
+ yy_lp = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+ for ( ; ; ) /* until we find what rule we matched */
+ {
+ if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] )
+ {
+ yy_act = yy_acclist[yy_lp];
+ {
+ yy_full_match = yy_cp;
+ break;
+ }
+ }
+ --yy_cp;
+ yy_current_state = *--yy_state_ptr;
+ yy_lp = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER )
+ {
+ int yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+ ++yylineno;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+case 1:
+YY_RULE_SETUP
+#line 74 "lex.javascript.yy"
+BEGIN(Comment);
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 75 "lex.javascript.yy"
+BEGIN(INITIAL);
+ YY_BREAK
+case YY_STATE_EOF(Comment):
+#line 76 "lex.javascript.yy"
+EXJS_THROW(ECJS_UNTERMINATED_COMMENT)
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 77 "lex.javascript.yy"
+/* nothing */
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 78 "lex.javascript.yy"
+/* nothing */
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 79 "lex.javascript.yy"
+BEGIN(LineComment);
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 80 "lex.javascript.yy"
+BEGIN(INITIAL);
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 81 "lex.javascript.yy"
+/* nothing */
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(LineComment):
+#line 83 "lex.javascript.yy"
+return TT_EOF;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 85 "lex.javascript.yy"
+return '{';
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 86 "lex.javascript.yy"
+return '}';
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 87 "lex.javascript.yy"
+return ';';
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 89 "lex.javascript.yy"
+return '[';
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 90 "lex.javascript.yy"
+return ']';
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 91 "lex.javascript.yy"
+return '(';
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 92 "lex.javascript.yy"
+return ')';
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 93 "lex.javascript.yy"
+return '?';
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 94 "lex.javascript.yy"
+return ':';
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 95 "lex.javascript.yy"
+return '+';
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 96 "lex.javascript.yy"
+return '-';
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 97 "lex.javascript.yy"
+return '*';
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 98 "lex.javascript.yy"
+return '/';
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 99 "lex.javascript.yy"
+return '%';
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 100 "lex.javascript.yy"
+return '^';
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 101 "lex.javascript.yy"
+return '&';
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 102 "lex.javascript.yy"
+return '|';
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 103 "lex.javascript.yy"
+return '~';
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 104 "lex.javascript.yy"
+return '!';
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 105 "lex.javascript.yy"
+return '=';
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 106 "lex.javascript.yy"
+return '<';
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 107 "lex.javascript.yy"
+return '>';
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 108 "lex.javascript.yy"
+return ',';
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 109 "lex.javascript.yy"
+return '.';
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 110 "lex.javascript.yy"
+return TT_JS_PLUS_ASSIGN;
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 111 "lex.javascript.yy"
+return TT_JS_MINUS_ASSIGN;
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 112 "lex.javascript.yy"
+return TT_JS_MULTIPLY_ASSIGN;
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 113 "lex.javascript.yy"
+return TT_JS_DIVIDE_ASSIGN;
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 114 "lex.javascript.yy"
+return TT_JS_MODULO_ASSIGN;
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 115 "lex.javascript.yy"
+return TT_JS_BIT_XOR_ASSIGN;
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 116 "lex.javascript.yy"
+return TT_JS_BIT_AND_ASSIGN;
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 117 "lex.javascript.yy"
+return TT_JS_BIT_OR_ASSIGN;
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 118 "lex.javascript.yy"
+return TT_JS_LEFT_SHIFT;
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 119 "lex.javascript.yy"
+return TT_JS_RIGHT_SHIFT;
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 120 "lex.javascript.yy"
+return TT_JS_LEFT_SHIFT_ASSIGN;
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 121 "lex.javascript.yy"
+return TT_JS_RIGHT_SHIFT_ASSIGN;
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 122 "lex.javascript.yy"
+return TT_JS_IDENTICAL;
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 123 "lex.javascript.yy"
+return TT_JS_NOT_IDENTICAL;
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 124 "lex.javascript.yy"
+return TT_JS_EQUAL;
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 125 "lex.javascript.yy"
+return TT_JS_NOT_EQUAL;
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 126 "lex.javascript.yy"
+return TT_JS_LESS_EQUAL;
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 127 "lex.javascript.yy"
+return TT_JS_GREATER_EQUAL;
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 128 "lex.javascript.yy"
+return TT_JS_LOGICAL_AND;
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 129 "lex.javascript.yy"
+return TT_JS_LOGICAL_OR;
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 130 "lex.javascript.yy"
+return TT_JS_INCREMENT;
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 131 "lex.javascript.yy"
+return TT_JS_DECREMENT;
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 133 "lex.javascript.yy"
+return TT_JS_NEW;
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 135 "lex.javascript.yy"
+return TT_JS_THIS;
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 136 "lex.javascript.yy"
+return TT_JS_FUNCTION;
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 137 "lex.javascript.yy"
+return TT_JS_VAR;
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 138 "lex.javascript.yy"
+return TT_JS_NULL;
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 139 "lex.javascript.yy"
+return TT_JS_IF;
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 140 "lex.javascript.yy"
+return TT_JS_WHILE;
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 141 "lex.javascript.yy"
+return TT_JS_DO;
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 142 "lex.javascript.yy"
+return TT_JS_ELSE;
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 143 "lex.javascript.yy"
+return TT_JS_FOR;
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 144 "lex.javascript.yy"
+return TT_JS_RETURN;
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 145 "lex.javascript.yy"
+return TT_JS_SWITCH;
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 146 "lex.javascript.yy"
+return TT_JS_CASE;
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 147 "lex.javascript.yy"
+return TT_JS_CONTINUE;
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 148 "lex.javascript.yy"
+return TT_JS_BREAK;
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 149 "lex.javascript.yy"
+return TT_JS_DEFAULT;
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 150 "lex.javascript.yy"
+return TT_JS_LIT_TRUE;
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 151 "lex.javascript.yy"
+return TT_JS_LIT_FALSE;
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 152 "lex.javascript.yy"
+return TT_JS_LIT_UNDEFINED;
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 153 "lex.javascript.yy"
+return TT_JS_IN;
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 154 "lex.javascript.yy"
+return TT_JS_CONST;
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 155 "lex.javascript.yy"
+return TT_JS_CLASS;
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 156 "lex.javascript.yy"
+return TT_JS_EXTENDS;
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 157 "lex.javascript.yy"
+return TT_JS_NAMESPACE;
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 158 "lex.javascript.yy"
+return TT_JS_STATIC;
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 159 "lex.javascript.yy"
+return TT_JS_CONSTRUCTOR;
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 161 "lex.javascript.yy"
+return TT_JS_LIT_INT;
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 162 "lex.javascript.yy"
+return TT_JS_LIT_FLOAT;
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 163 "lex.javascript.yy"
+return TT_JS_LIT_STRING;
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 165 "lex.javascript.yy"
+return TT_JS_IDENTIFIER;
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 167 "lex.javascript.yy"
+/* nothing */
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 168 "lex.javascript.yy"
+EXJS_THROWINFOLOCATION(ECJS_INVALID_TOKEN,YYText(),code_location(lineno()))
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 169 "lex.javascript.yy"
+ECHO;
+ YY_BREAK
+#line 1229 "lex.javascript.cc"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+yyFlexLexer::yyFlexLexer( istream* arg_yyin, ostream* arg_yyout )
+ {
+ yyin = arg_yyin;
+ yyout = arg_yyout;
+ yy_c_buf_p = 0;
+ yy_init = 1;
+ yy_start = 0;
+ yy_flex_debug = 0;
+ yylineno = 1; // this will only get updated if %option yylineno
+
+ yy_did_buffer_switch_on_eof = 0;
+
+ yy_looking_for_trail_begin = 0;
+ yy_more_flag = 0;
+ yy_more_len = 0;
+ yy_more_offset = yy_prev_more_offset = 0;
+
+ yy_start_stack_ptr = yy_start_stack_depth = 0;
+ yy_start_stack = 0;
+
+ yy_current_buffer = 0;
+
+#ifdef YY_USES_REJECT
+ yy_state_buf = new yy_state_type[YY_BUF_SIZE + 2];
+#else
+ yy_state_buf = 0;
+#endif
+ }
+
+yyFlexLexer::~yyFlexLexer()
+ {
+ delete yy_state_buf;
+ yy_delete_buffer( yy_current_buffer );
+ }
+
+void yyFlexLexer::switch_streams( istream* new_in, ostream* new_out )
+ {
+ if ( new_in )
+ {
+ yy_delete_buffer( yy_current_buffer );
+ yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) );
+ }
+
+ if ( new_out )
+ yyout = new_out;
+ }
+
+#ifdef YY_INTERACTIVE
+int yyFlexLexer::LexerInput( char* buf, int /* max_size */ )
+#else
+int yyFlexLexer::LexerInput( char* buf, int max_size )
+#endif
+ {
+ if ( yyin->eof() || yyin->fail() )
+ return 0;
+
+#ifdef YY_INTERACTIVE
+ yyin->get( buf[0] );
+
+ if ( yyin->eof() )
+ return 0;
+
+ if ( yyin->bad() )
+ return -1;
+
+ return 1;
+
+#else
+ (void) yyin->read( buf, max_size );
+
+ if ( yyin->bad() )
+ return -1;
+ else
+ return yyin->gcount();
+#endif
+ }
+
+void yyFlexLexer::LexerOutput( const char* buf, int size )
+ {
+ (void) yyout->write( buf, size );
+ }
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+int yyFlexLexer::yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+yy_state_type yyFlexLexer::yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+ yy_state_ptr = yy_state_buf;
+ *yy_state_ptr++ = yy_current_state;
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 224 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ *yy_state_ptr++ = yy_current_state;
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state )
+ {
+ register int yy_is_jam;
+
+ register YY_CHAR yy_c = 1;
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 224 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 223);
+ if ( ! yy_is_jam )
+ *yy_state_ptr++ = yy_current_state;
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+void yyFlexLexer::yyunput( int c, register char* yy_bp )
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ if ( c == '\n' )
+ --yylineno;
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+
+
+int yyFlexLexer::yyinput()
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+ if ( c == '\n' )
+ ++yylineno;
+
+ return c;
+ }
+
+
+void yyFlexLexer::yyrestart( istream* input_file )
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+void yyFlexLexer::yy_load_buffer_state()
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( istream* file, int size )
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b )
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+extern "C" int isatty YY_PROTO(( int ));
+void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, istream* file )
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ b->yy_is_interactive = 0;
+ }
+
+
+void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b )
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+void yyFlexLexer::yy_push_state( int new_state )
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+void yyFlexLexer::yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+int yyFlexLexer::yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+
+void yyFlexLexer::LexerError( yyconst char msg[] )
+ {
+ cerr << msg << '\n';
+ exit( YY_EXIT_FAILURE );
+ }
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
+#line 169 "lex.javascript.yy"
--- /dev/null
+/* -------- definitions ------- */
+
+%option c++ yylineno noyywrap prefix="js" outfile="lex.javascript.cc" batch
+
+%{
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+using namespace ixion;
+using namespace javascript;
+%}
+
+WHITESPACE [ \t\n\r]
+
+DIGIT [0-9]
+DIGIT_NZ [1-9]
+DIGIT_OCT [0-7]
+DIGIT_HEX [0-9a-fA-F]
+DIGIT_SEQ {DIGIT}+
+
+NONDIGIT [_a-zA-Z]
+ID_COMPONENT [_a-zA-Z0-9]
+
+ESCAPE_SIMPLE \\['"?\\abfnrtv]
+ESCAPE_OCTAL \\{DIGIT_OCT}{1,3}
+ESCAPE_HEX \\x{DIGIT_HEX}{1,2}
+ESCAPE {ESCAPE_SIMPLE}|{ESCAPE_OCTAL}|{ESCAPE_HEX}
+S_CHAR [^"\\\n]|{ESCAPE}
+
+SIGN \+|\-
+SIGNopt {SIGN}?
+
+
+
+
+/* higher-level entities ------------------------------------------------------
+*/
+IDENTIFIER {NONDIGIT}{ID_COMPONENT}*
+
+
+
+
+/* literals -------------------------------------------------------------------
+*/
+LIT_DECIMAL {DIGIT_NZ}{DIGIT}*
+LIT_OCTAL 0{DIGIT_OCT}*
+LIT_HEX 0[xX]{DIGIT_HEX}+
+LIT_INT ({LIT_DECIMAL}|{LIT_OCTAL}|{LIT_HEX})
+
+LIT_STRING \"{S_CHAR}*\"|\'{S_CHAR}*\'
+
+LIT_FRACTION {DIGIT_SEQ}?\.{DIGIT_SEQ}|{DIGIT_SEQ}\.
+LIT_EXPONENT [eE]{SIGNopt}{DIGIT_SEQ}
+LIT_FLOAT {LIT_FRACTION}{LIT_EXPONENT}?|{DIGIT_SEQ}{LIT_EXPONENT}
+
+
+
+
+
+
+/* Contexts -------------------------------------------------------------------
+*/
+
+%x Comment
+%x LineComment
+
+
+
+
+/* Rules ----------------------------------------------------------------------
+*/
+%%
+
+\/\* BEGIN(Comment);
+<Comment>\*\/ BEGIN(INITIAL);
+<Comment><<EOF>> EXJS_THROW(ECJS_UNTERMINATED_COMMENT)
+<Comment>. /* nothing */
+<Comment>\n /* nothing */
+\/\/ BEGIN(LineComment);
+<LineComment>[\n\r]+ BEGIN(INITIAL);
+<LineComment>. /* nothing */
+
+<<EOF>> return TT_EOF;
+
+\{ return '{';
+\} return '}';
+\; return ';';
+
+\[ return '[';
+\] return ']';
+\( return '(';
+\) return ')';
+\? return '?';
+\: return ':';
+\+ return '+';
+\- return '-';
+\* return '*';
+\/ return '/';
+\% return '%';
+\^ return '^';
+\& return '&';
+\| return '|';
+\~ return '~';
+\! return '!';
+\= return '=';
+\< return '<';
+\> return '>';
+\, return ',';
+\. return '.';
+\+\= return TT_JS_PLUS_ASSIGN;
+\-\= return TT_JS_MINUS_ASSIGN;
+\*\= return TT_JS_MULTIPLY_ASSIGN;
+\/\= return TT_JS_DIVIDE_ASSIGN;
+\%\= return TT_JS_MODULO_ASSIGN;
+\^\= return TT_JS_BIT_XOR_ASSIGN;
+\&\= return TT_JS_BIT_AND_ASSIGN;
+\|\= return TT_JS_BIT_OR_ASSIGN;
+\<\< return TT_JS_LEFT_SHIFT;
+\>\> return TT_JS_RIGHT_SHIFT;
+\<\<\= return TT_JS_LEFT_SHIFT_ASSIGN;
+\>\>\= return TT_JS_RIGHT_SHIFT_ASSIGN;
+\=\=\= return TT_JS_IDENTICAL;
+\!\=\= return TT_JS_NOT_IDENTICAL;
+\=\= return TT_JS_EQUAL;
+\!\= return TT_JS_NOT_EQUAL;
+\<\= return TT_JS_LESS_EQUAL;
+\>\= return TT_JS_GREATER_EQUAL;
+\&\& return TT_JS_LOGICAL_AND;
+\|\| return TT_JS_LOGICAL_OR;
+\+\+ return TT_JS_INCREMENT;
+\-\- return TT_JS_DECREMENT;
+
+new return TT_JS_NEW;
+
+this return TT_JS_THIS;
+function return TT_JS_FUNCTION;
+var return TT_JS_VAR;
+null return TT_JS_NULL;
+if return TT_JS_IF;
+while return TT_JS_WHILE;
+do return TT_JS_DO;
+else return TT_JS_ELSE;
+for return TT_JS_FOR;
+return return TT_JS_RETURN;
+switch return TT_JS_SWITCH;
+case return TT_JS_CASE;
+continue return TT_JS_CONTINUE;
+break return TT_JS_BREAK;
+default return TT_JS_DEFAULT;
+true return TT_JS_LIT_TRUE;
+false return TT_JS_LIT_FALSE;
+undefined return TT_JS_LIT_UNDEFINED;
+in return TT_JS_IN;
+const return TT_JS_CONST;
+class return TT_JS_CLASS;
+extends return TT_JS_EXTENDS;
+namespace return TT_JS_NAMESPACE;
+static return TT_JS_STATIC;
+constructor return TT_JS_CONSTRUCTOR;
+
+{LIT_INT} return TT_JS_LIT_INT;
+{LIT_FLOAT} return TT_JS_LIT_FLOAT;
+{LIT_STRING} return TT_JS_LIT_STRING;
+
+{IDENTIFIER} return TT_JS_IDENTIFIER;
+
+{WHITESPACE}+ /* nothing */
+. EXJS_THROWINFOLOCATION(ECJS_INVALID_TOKEN,YYText(),code_location(lineno()))
--- /dev/null
+#include <ixlib_js_internals.hh>
+#include <ixlib_exbase.hh>
+#include <ixlib_javascript.hh>
+
+#include <fstream>
+
+using namespace ixion;
+using namespace ixion::javascript;
+
+IXLIB_JS_DECLARE_FUNCTION(write)
+{
+ if (parameters.size() != 1) {
+ EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS, "write");
+ }
+ std::cout << parameters[0]->toString();
+ return makeConstant(parameters[0]->toString());
+}
+
+int main (int ac, char ** av) {
+ interpreter *jsint = new interpreter();
+ addStandardLibrary(*jsint);
+ ref<value> x = new write();
+ jsint->RootScope->addMember("write", x);
+
+ if (ac == 1) {
+ std::cerr << "Usage: " << av[0] << "<file+>" << std::endl;
+ exit(1);
+ }
+ for (int i = 1; i < ac; i++) {
+ std::ifstream input(av[i]);
+ try {
+ ref<value> result = jsint->execute(input);
+ std::cout << av[i] << " returned " << result->stringify() << std::endl;
+ } catch (base_exception &ex) {
+ std::cerr << ex.getText() << ex.what() << std::endl;
+ }
+ input.close();
+ }
+ delete jsint;
+}
+
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Numeric conversions
+// ----------------------------------------------------------------------------
+// (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_exgen.hh>
+#include <ixlib_numconv.hh>
+#include <stdio.h>
+
+
+
+
+using namespace std;
+using namespace ixion;
+
+
+
+
+// data objects --------------------------------------------------------------
+static string numChars = IXLIB_NUMCHARS;
+
+
+
+
+// exported subroutines -------------------------------------------------------
+string ixion::float2dec(double value) {
+ char buf[255];
+ sprintf((char *)&buf,"%f",value);
+ return string(buf);
+ }
+
+
+
+
+string ixion::float2dec(double value, unsigned int precision) {
+ char buf[255];
+ string cmd("%.");
+
+ cmd += unsigned2dec(precision) + "f";
+ sprintf((char *)&buf,cmd.c_str(),value);
+ return string(buf);
+ }
+
+
+
+
+string ixion::unsigned2base(unsigned long value,char digits,char radix) {
+ string temp;
+ do {
+ temp = numChars[value % radix]+temp;
+ value /= radix;
+ if (digits) digits--;
+ } while (value || digits);
+ return temp;
+ }
+
+
+
+
+string ixion::signed2base(signed long value,char digits,char radix) {
+ if (value < 0) return "-"+unsigned2base(-value,digits,radix);
+ else return unsigned2base(value,digits,radix);
+ }
+
+
+
+
+string ixion::bytes2dec(TSize bytes) {
+ if (bytes>(TSize) 10*1024*1024)
+ return unsigned2dec(bytes / ((TSize) 1024*1024))+" MB";
+ if (bytes>(TSize) 10*1024)
+ return unsigned2dec(bytes / ((TSize) 1024))+" KB";
+ return unsigned2dec(bytes)+" Byte";
+ }
+
+
+
+
+unsigned long ixion::evalNumeral(string const &numeral,unsigned radix) {
+ string numstr = upper(numeral);
+
+ if (numstr.size() == 0) return 0;
+ unsigned long value = 0, mulvalue = 1;
+ TIndex index = numstr.size()-1;
+
+ do {
+ string::size_type digvalue = numChars.find(numstr[index]);
+ if (digvalue == string::npos)
+ EXGEN_THROWINFO(EC_CANNOTEVALUATE,numstr.c_str())
+ value += mulvalue * digvalue;
+ mulvalue *= radix;
+ } while (index--);
+
+ return value;
+ }
+
+
+
+
+double ixion::evalFloat(string const &numeral) {
+ double result;
+ int count = sscanf(numeral.c_str(), "%le", &result);
+ if (count == 0) EXGEN_THROWINFO(EC_CANNOTEVALUATE,numeral.c_str())
+ else return result;
+ }
+
+
+
+
+unsigned long ixion::evalUnsigned(string const &numeral,unsigned default_base) {
+ if (numeral.size() == 0) return 0;
+
+ if (numeral.substr(0,2) == "0X" || numeral.substr(0,2) == "0x")
+ return evalNumeral(numeral.substr(2),0x10);
+ if (numeral.substr(0,1) == "$")
+ return evalNumeral(numeral.substr(1),0x10);
+
+ char lastchar = numeral[numeral.size()-1];
+ if (lastchar == 'H' || lastchar == 'h') return evalNumeral(numeral.substr(0,numeral.size()-1),0x10);
+ if (lastchar == 'B' || lastchar == 'b') return evalNumeral(numeral.substr(0,numeral.size()-1),2);
+ if (lastchar == 'D' || lastchar == 'd') return evalNumeral(numeral.substr(0,numeral.size()-1),10);
+ if (lastchar == 'O' || lastchar == 'o') return evalNumeral(numeral.substr(0,numeral.size()-1),8);
+
+ return evalNumeral(numeral,default_base);
+ }
+
+
+
+
+signed long ixion::evalSigned(string const &numeral,unsigned default_base) {
+ if (numeral.size() == 0) return 0;
+ if (numeral[0] == '-')
+ return - (signed long) evalUnsigned(numeral.substr(1),default_base);
+ else {
+ if (numeral[0] == '+')
+ return evalUnsigned(numeral.substr(1),default_base);
+ else
+ return evalUnsigned(numeral,default_base);
+ }
+ }
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Numeric / order processing
+// ----------------------------------------------------------------------------
+// (c) Copyright 1998 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_numeric.hh>
+
+
+
+
+// BCD encoding ---------------------------------------------------------------
+unsigned long ixion::unsigned2BCD(unsigned long value)
+{
+ unsigned long bcdvalue = 0,bcdshift = 0;
+ while (value) {
+ bcdvalue += (value % 10) << bcdshift;
+ bcdshift += 4;
+ value /= 10;
+ }
+ return bcdvalue;
+}
+
+
+
+
+unsigned long ixion::BCD2unsigned(unsigned long value)
+{
+ unsigned long decvalue = 0;
+ for (unsigned long i = 1;value;i *= 10) {
+ decvalue += (value & 0xf) * i;
+ value >>= 4;
+ }
+ return decvalue;
+}
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Regular expressions string object.
+// ----------------------------------------------------------------------------
+// (c) Copyright 1998 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <stack>
+#include <cctype>
+#include "ixlib_i18n.hh"
+#include <ixlib_exgen.hh>
+#include <ixlib_numeric.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_re.hh>
+#include <ixlib_re_impl.hh>
+
+
+
+
+using namespace std;
+using namespace ixion;
+
+
+
+
+// Template instantiations ----------------------------------------------------
+template regex<string>;
+
+
+
+
+// Error texts ----------------------------------------------------------------
+static char *RegexPlainText[] = {
+ N_("Invalid quantifier"),
+ N_("Unbalanced backreference"),
+ N_("Invalid escape sequence"),
+ N_("Invalid backreference"),
+ N_("Unterminated character class"),
+ N_("Unable to match without expression"),
+ };
+
+
+
+
+// regex_exception ------------------------------------------------------------
+regex_exception::regex_exception(TErrorCode error,
+ char const *info,char *module,TIndex line)
+: base_exception(error,info,module,line,"RE") {
+ }
+
+
+
+
+char *regex_exception::getText() const {
+ return _(RegexPlainText[Error]);
+ }
+
+
+
+
+// regex_string::class_matcher ------------------------------------------------
+regex_string::class_matcher::class_matcher()
+ : Negated(false) {
+ MatchLength = 1;
+ }
+
+
+
+
+regex_string::class_matcher::class_matcher(string const &cls)
+ : Negated(false) {
+ MatchLength = 1;
+
+ if (cls.size() && cls[0] == XSTRRE_CLASSNEG) {
+ expandClass(cls.substr(1));
+ Negated = true;
+ }
+ else
+ expandClass(cls);
+ }
+
+
+
+
+ixion::regex<string>::matcher *ixion::regex_string::class_matcher::duplicate() const {
+ class_matcher *dupe = new class_matcher();
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+bool regex_string::class_matcher::match(backref_stack &brstack,string const &candidate,TIndex at) {
+ if (at >= candidate.size()) return false;
+
+ bool result = Set[candidate[at]];
+ if (Negated) result = !result;
+
+ return result && matchNext(brstack,candidate,at+1);
+ }
+
+
+
+
+void regex_string::class_matcher::expandClass(string const &cls) {
+ memset(&Set,0,sizeof(Set));
+
+ if (cls.size() == 0) return;
+ Set[cls[0]] = true;
+ char lastchar = cls[0];
+
+ for (TIndex index = 1;index < cls.size();index++) {
+ if ((cls[index] == XSTRRE_CLASSRANGE) && (index < cls.size()-1)) {
+ for (char ch = lastchar+1;ch < cls[index+1];ch++)
+ Set[ch] = true;
+ }
+ else Set[cls[index]] = true;
+ lastchar = cls[index];
+ }
+ }
+
+
+
+
+void ixion::regex_string::class_matcher::copy(class_matcher const *src) {
+ super::copy(src);
+ for (TIndex i = 0;i < CharValues;i++)
+ Set[i] = src->Set[i];
+ Negated = src->Negated;
+ }
+
+
+
+
+// regex_string::special_class_matcher ----------------------------------------
+regex_string::special_class_matcher::special_class_matcher(type tp)
+ : Type(tp) {
+ MatchLength = 1;
+ }
+
+
+
+
+ixion::regex<string>::matcher *ixion::regex_string::special_class_matcher::duplicate() const {
+ special_class_matcher *dupe = new special_class_matcher(Type);
+ dupe->copy(this);
+ return dupe;
+ }
+
+
+
+
+bool regex_string::special_class_matcher::match(backref_stack &brstack,string const &candidate,TIndex at) {
+ if (at >= candidate.size()) return false;
+ enum type { DIGIT,NONDIGIT,ALNUM,NONALNUM,SPACE,NONSPACE };
+
+ bool result;
+ switch (Type) {
+ case DIGIT: result = isdigit(candidate[at]);
+ break;
+ case NONDIGIT: result = !isdigit(candidate[at]);
+ break;
+ case ALNUM: result = isalnum(candidate[at]);
+ break;
+ case NONALNUM: result = !isalnum(candidate[at]);
+ break;
+ case SPACE: result = isspace(candidate[at]);
+ break;
+ case NONSPACE: result = !isspace(candidate[at]);
+ break;
+ default:
+ EX_THROW(regex,ECRE_INVESCAPE)
+ }
+
+ return result && matchNext(brstack,candidate,at+1);
+ }
+
+
+
+
+// regex_string ---------------------------------------------------------------
+void regex_string::parse(string const &expr) {
+ auto_ptr<matcher> new_re(parseRegex(expr));
+ ParsedRegex = new_re;
+ }
+
+
+
+
+string regex_string::replaceAll(string const &candidate,string const &replacement,TIndex from) {
+ string result;
+ string tempreplacement;
+
+ LastCandidate = candidate;
+ if (ParsedRegex.get() == NULL)
+ EX_THROW(regex,ECRE_NOPATTERN)
+
+ for (TIndex index = from;index < candidate.size();) {
+ BackrefStack.clear();
+ if (ParsedRegex->match(BackrefStack,candidate,index)) {
+ TIndex matchlength = ParsedRegex->subsequentMatchLength();
+ tempreplacement = replacement;
+
+ TSize backrefs = BackrefStack.size();
+ for (TIndex i = 0;i < backrefs;i++)
+ tempreplacement = findReplace(tempreplacement,XSTRRE_BACKREF+unsigned2dec(i),
+ BackrefStack.get(i,LastCandidate));
+
+ result += tempreplacement;
+ index += matchlength;
+ }
+ else result += candidate[index++];
+ }
+ return result;
+ }
+
+
+
+
+regex_string::matcher *regex_string::parseRegex(string const &expr) {
+ if (!expr.size()) return NULL;
+ TIndex index = 0;
+ matcher *firstobject,*lastobject = NULL;
+ alternative_matcher *alternative = NULL;
+
+ while (index < expr.size()) {
+ matcher *object = NULL;
+ quantifier *quantifier = NULL;
+ bool quantified = true;
+ char ch;
+
+ // several objects may be inserted in one loop run
+ switch (expr[index++]) {
+ // case XSTRRE_BACKREF: (dupe)
+ // case XSTRRE_ESCAPESEQ: (dupe)
+ case XSTRRE_LITERAL: {
+ if (index >= expr.size()) EX_THROW(regex,ECRE_INVESCAPE)
+
+ ch = expr[index++];
+ if (isdigit(ch))
+ object = new backref_matcher(ch-'0');
+ else {
+ switch (ch) {
+ case 'd': object = new special_class_matcher(special_class_matcher::DIGIT);
+ break;
+ case 'D': object = new special_class_matcher(special_class_matcher::NONDIGIT);
+ break;
+ case 'w': object = new special_class_matcher(special_class_matcher::ALNUM);
+ break;
+ case 'W': object = new special_class_matcher(special_class_matcher::NONALNUM);
+ break;
+ case 's': object = new special_class_matcher(special_class_matcher::SPACE);
+ break;
+ case 'S': object = new special_class_matcher(special_class_matcher::NONSPACE);
+ break;
+ default: object = new sequence_matcher(string(1,ch));
+ }
+ }
+ break;
+ }
+ case XSTRRE_ANYCHAR:
+ object = new any_matcher;
+ break;
+ case XSTRRE_START:
+ quantified = false;
+ object = new start_matcher;
+ break;
+ case XSTRRE_END:
+ quantified = false;
+ object = new end_matcher;
+ break;
+ case XSTRRE_ALTERNATIVE: {
+ if (!alternative)
+ alternative = new alternative_matcher;
+ alternative->addAlternative(firstobject);
+ firstobject = NULL;
+ lastobject = NULL;
+ break;
+ }
+ case XSTRRE_CLASSSTART: {
+ TIndex classend = expr.find(XSTRRE_CLASSSTOP,index);
+ if (classend == string::npos)
+ EX_THROW(regex,ECRE_UNTERMCLASS)
+ object = new class_matcher(expr.substr(index,classend-index));
+
+ index = classend+1;
+ break;
+ }
+ case XSTRRE_BACKREFSTART: {
+ matcher *parsed;
+
+ TSize brlevel = 1;
+ for (TIndex searchstop = index;searchstop < expr.size();searchstop++) {
+ if ((expr[searchstop] == XSTRRE_BACKREFSTART) &&
+ (expr[searchstop-1] != XSTRRE_LITERAL))
+ brlevel++;
+ if ((expr[searchstop] == XSTRRE_BACKREFSTOP) &&
+ (expr[searchstop-1] != XSTRRE_LITERAL)) {
+ brlevel--;
+ if (brlevel == 0) {
+ parsed = parseRegex(expr.substr(index,searchstop-index));
+ if (!parsed) EX_THROW(regex,ECRE_INVBACKREF)
+
+ index = searchstop+1;
+ break;
+ }
+ }
+ }
+
+ if (!parsed) EX_THROW(regex,ECRE_UNBALBACKREF)
+
+ object = new backref_open_matcher;
+ object->setNext(parsed);
+
+ matcher *closer = new backref_close_matcher;
+
+ matcher *searchlast = parsed,*foundlast;
+ while (searchlast) {
+ foundlast = searchlast;
+ searchlast = searchlast->getNext();
+ }
+ foundlast->setNext(closer);
+
+ break;
+ }
+ case XSTRRE_BACKREFSTOP:
+ EX_THROW(regex,ECRE_UNBALBACKREF)
+ default:
+ object = new sequence_matcher(expr.substr(index-1,1));
+ break;
+ }
+
+ if (object) {
+ if (quantified) quantifier = parseQuantifier(expr,index);
+ if (quantifier) {
+ quantifier->setQuantified(object);
+ if (lastobject) lastobject->setNext(quantifier);
+ else firstobject = quantifier;
+ }
+ else {
+ if (lastobject) lastobject->setNext(object);
+ else firstobject = object;
+ }
+ }
+
+ // we need this for the alternative matcher, which also inserts
+ // its connector
+ matcher *searchlast = quantifier ? quantifier : object;
+ while (searchlast) {
+ lastobject = searchlast;
+ searchlast = searchlast->getNext();
+ }
+ }
+ if (alternative) {
+ alternative->addAlternative(firstobject);
+ return alternative;
+ }
+ else return firstobject;
+ }
+
+
+
+
+regex_string::quantifier *regex_string::parseQuantifier(string const &expr,TIndex &at) {
+ quantifier *quant = NULL;
+ if (at == expr.size()) return NULL;
+ if (expr[at] == XSTRREQ_0PLUS) {
+ quant = new quantifier(isGreedy(expr,++at),0);
+ return quant;
+ }
+ if (expr[at] == XSTRREQ_1PLUS) {
+ quant = new quantifier(isGreedy(expr,++at),1);
+ return quant;
+ }
+ if (expr[at] == XSTRREQ_01) {
+ quant = new quantifier(isGreedy(expr,++at),0,1);
+ return quant;
+ }
+ if (expr[at] == XSTRREQ_START) {
+ TSize min,max;
+
+ at++;
+ TIndex endindex;
+ endindex = expr.find(XSTRREQ_STOP,at);
+ if (endindex == string::npos)
+ EXGEN_THROW(ECRE_INVQUANTIFIER)
+
+ string quantspec = expr.substr(at,endindex-at);
+ at = endindex+1;
+
+ try {
+ string::size_type rangeindex = quantspec.find(XSTRREQ_RANGE);
+ if (rangeindex == string::npos) {
+ min = evalUnsigned(quantspec);
+ quant = new quantifier(isGreedy(expr,at),min,min);
+ }
+ else if (rangeindex == quantspec.size()-1) {
+ min = evalUnsigned(quantspec.substr(0,rangeindex));
+ quant = new quantifier(isGreedy(expr,at),min);
+ }
+ else {
+ min = evalUnsigned(quantspec.substr(0,rangeindex));
+ max = evalUnsigned(quantspec.substr(rangeindex+1));
+ quant = new quantifier(isGreedy(expr,at),min,max);
+ }
+ return quant;
+ }
+ EX_CONVERT(generic,EC_CANNOTEVALUATE,regex,ECRE_INVQUANTIFIER)
+ }
+ return NULL;
+ }
+
+
+
+
+bool regex_string::isGreedy(string const &expr,TIndex &at)
+{
+ if (at == expr.size()) return true;
+ if (expr[at] == XSTRREQ_NONGREEDY) {
+ at++;
+ return false;
+ }
+ else return true;
+}
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : Scanner for xTextFile
+// ----------------------------------------------------------------------------
+// (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <FlexLexer.h>
+#include "ixlib_i18n.hh"
+#include <ixlib_numconv.hh>
+#include <ixlib_token_lex.hh>
+#include <ixlib_scanner.hh>
+
+
+
+
+using namespace std;
+using namespace ixion;
+
+
+
+
+// Plain text rendering table -------------------------------------------------
+static char *(PlainText[]) = {
+ N_("Unknown token"),
+ N_("End of input")
+ };
+
+
+
+
+// scanner_exception ----------------------------------------------------------
+scanner_exception::scanner_exception(TErrorCode error, TIndex line,
+string const &info)
+: base_exception(error, NULL, NULL, 0, "SCAN") {
+ HasInfo = true;
+ try {
+ string temp = "line ";
+ temp += unsigned2dec(line);
+ if (info != "") {
+ temp += " : ";
+ temp += info;
+ }
+ strcpy(Info, temp.c_str());
+ }
+ catch (...) { }
+ }
+
+
+
+
+char *scanner_exception::getText() const {
+ return PlainText[Error];
+ }
+
+
+
+
+// scanner --------------------------------------------------------------------
+scanner::scanner(FlexLexer &lexer)
+: Lexer(lexer) {
+ }
+
+
+
+
+scanner::token_list scanner::scan() {
+ CurrentToken.Type = Lexer.yylex();
+ CurrentToken.Line = Lexer.lineno();
+ CurrentToken.Text = Lexer.YYText();
+
+ token_list tokenlist;
+ while (!reachedEOF()) {
+ tokenlist.push_back(getNextToken());
+ }
+ return tokenlist;
+ }
+
+
+
+
+scanner::token scanner::getNextToken() {
+ if (!reachedEOF()) {
+ token lasttoken = CurrentToken;
+
+ CurrentToken.Type = Lexer.yylex();
+ CurrentToken.Line = Lexer.lineno();
+ CurrentToken.Text = Lexer.YYText();
+
+ if (CurrentToken.Type == TT_UNKNOWN)
+ throw scanner_exception(ECSCAN_UNKNOWN_TOKEN,CurrentToken.Line,CurrentToken.Text);
+ else return lasttoken;
+ }
+ throw scanner_exception(ECSCAN_UNKNOWN_TOKEN, CurrentToken.Line, "");
+ }
+
+
+
+
+bool scanner::reachedEOF() const {
+ return (CurrentToken.Type == TT_EOF);
+ }
+
+
+
+
--- /dev/null
+// ----------------------------------------------------------------------------
+// Description : String object
+// ----------------------------------------------------------------------------
+// (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <cstring>
+#include <cctype>
+#include <ixlib_numconv.hh>
+#include <ixlib_string.hh>
+
+
+
+
+using namespace std;
+using namespace ixion;
+
+
+
+
+// String utility functions ---------------------------------------------------
+string ixion::findReplace(string const &target,string const &src,string const &dest) {
+ string result = target;
+ TIndex foundpos = string::npos;
+ TIndex n = src.size();
+ while ((foundpos = result.find(src)) != string::npos)
+ result.replace(foundpos,n,dest);
+ return result;
+ }
+
+
+
+
+string ixion::findReplace(string const &target,char* src,char *dest) {
+ string result = target;
+ TSize foundpos = string::npos;
+ TSize n = strlen(src);
+ while ((foundpos = result.find(src)) != string::npos)
+ result.replace(foundpos,n,dest);
+ return result;
+ }
+
+
+
+
+string ixion::findReplace(string const &target,char src,char dest) {
+ string result = target;
+ string::iterator first = result.begin(),last = result.end();
+
+ while (first != last) {
+ if (*first == src) *first = dest;
+ first++;
+ }
+ return result;
+ }
+
+
+
+
+string ixion::upper(string const &original) {
+ string temp(original);
+ string::iterator first = temp.begin(),last = temp.end();
+
+ while (first != last) {
+ *first = toupper(*first);
+ first++;
+ }
+ return temp;
+ }
+
+
+
+
+string ixion::lower(string const &original) {
+ string temp(original);
+ string::iterator first = temp.begin(),last = temp.end();
+
+ while (first != last) {
+ *first = tolower(*first);
+ first++;
+ }
+ return temp;
+ }
+
+
+
+
+string ixion::removeLeading(string const &original,char ch) {
+ string copy(original);
+ string::iterator first = copy.begin(), last = copy.end();
+
+ while (first != last && *first == ch) first++;
+ if (first != copy.begin()) copy.erase(copy.begin(),first);
+ return copy;
+ }
+
+
+
+
+string ixion::removeTrailing(string const &original,char ch) {
+ string copy(original);
+ string::iterator first = copy.begin(), last = copy.end();
+
+ if (first != last) {
+ last--;
+ while (first != last && *last == ch) last--;
+ if (*last != ch) last++;
+ }
+
+ if (last != copy.end()) copy.erase(last,copy.end());
+ return copy;
+ }
+
+
+
+
+string ixion::removeLeadingTrailing(string const &original,char ch) {
+ string copy(original);
+ string::iterator first = copy.begin(), last = copy.end();
+
+ while (first != last && *first == ch) first++;
+ if (first != copy.begin()) copy.erase(copy.begin(),first);
+
+ first = copy.begin();
+ last = copy.end();
+
+ if (first != last) {
+ last--;
+ while (first != last && *last == ch) last--;
+ if (*last != ch) last++;
+ }
+
+ if (last != copy.end()) copy.erase(last,copy.end());
+ return copy;
+ }
+
+
+
+
+string ixion::parseCEscapes(string const &original) {
+ string result = "";
+ string::const_iterator first = original.begin(),last = original.end();
+ while (first != last) {
+ if (*first == '\\') {
+ first++;
+ if (first == last) {
+ result += '\\';
+ break;
+ }
+
+ #define GET_TEMP_STRING(LENGTH) \
+ if (original.end()-first < LENGTH) \
+ EXGEN_THROWINFO(EC_INVALIDPAR,"invalid escape sequence") \
+ tempstring = string(first,first+LENGTH); \
+ first += LENGTH;
+
+ char value;
+ string tempstring;
+ switch (*first) {
+ case 'b': result += '\b'; first++; break;
+ case 'f': result += '\f'; first++; break;
+ case 'n': result += '\n'; first++; break;
+ case 't': result += '\t'; first++; break;
+ case 'v': result += '\v'; first++; break;
+ case 'X':
+ case 'x': first++;
+ GET_TEMP_STRING(2)
+ value = evalNumeral(tempstring,16);
+ result += value;
+ break;
+ case 'u': first++;
+ GET_TEMP_STRING(4)
+ value = evalNumeral(tempstring,16);
+ result += value;
+ break;
+ case '0':
+ GET_TEMP_STRING(3)
+ value = evalNumeral(tempstring,8);
+ result += value;
+ break;
+ default: result += *first++;
+ }
+ }
+ else result += *first++;
+ }
+ return result;
+ }
+
+
+
+
+namespace {
+ TByte const B64_INVALID = 0xff;
+ TByte const B64_PAD = 0xfe;
+ char const B64_PAD_CHAR = '=';
+ char Base64EncodeTable[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ TByte Base64DecodeTable[] = { // based at 0
+ // see test/invertmap.js on how to generate this table
+ B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+ B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+ B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+ B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+ B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+ B64_INVALID,B64_INVALID,B64_INVALID,62,B64_INVALID,B64_INVALID,B64_INVALID,63,52,53,54,
+ 55,56,57,58,59,60,61,B64_INVALID,B64_INVALID,B64_INVALID,B64_PAD,B64_INVALID,
+ B64_INVALID,B64_INVALID,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,
+ 19,20,21,22,23,24,25,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+ B64_INVALID,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,
+ 44,45,46,47,48,49,50,51,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+ };
+
+ }
+
+
+
+
+TSize ixion::getMaxBase64DecodedSize(TSize encoded) {
+ return ((encoded+3)/4)*3;
+ }
+
+
+
+
+TSize ixion::base64decode(TByte *data,string const &base64) {
+ string::const_iterator first = base64.begin(),last = base64.end();
+
+ TByte *data_start = data;
+
+ TUnsigned32 block;
+ TByte a,b,c,d;
+
+ while (first != last) {
+ a = Base64DecodeTable[*(first++)];
+ b = Base64DecodeTable[*(first++)];
+ c = Base64DecodeTable[*(first++)];
+ d = Base64DecodeTable[*(first++)];
+ if (c == B64_PAD) {
+ block = a << 3*6 | b << 2*6;
+ *data++ = (block >> 16) & 0xff;
+ }
+ else if (d == B64_PAD) {
+ block = a << 3*6 | b << 2*6 | c << 1*6;
+ *data++ = (block >> 16) & 0xff;
+ *data++ = (block >> 8) & 0xff;
+ }
+ else {
+ block = a << 3*6 | b << 2*6 | c << 1*6 | d << 0*6;
+ *data++ = (block >> 16) & 0xff;
+ *data++ = (block >> 8) & 0xff;
+ *data++ = (block >> 0) & 0xff;
+ }
+ }
+ return data-data_start;
+ }
+
+
+
+
+void ixion::base64encode(string &base64,TByte const *data,TSize size) {
+ base64.resize((size+2)/3*4);
+
+ TUnsigned32 block;
+ TByte a,b,c,d;
+
+ TByte const *end = data+size;
+ string::iterator first = base64.begin();
+ while (data < end)
+ if (data+1 == end) {
+ block = data[0] << 16;
+ a = (block >> 3*6) & 0x3f;
+ b = (block >> 2*6) & 0x3f;
+ *first++ = Base64EncodeTable[a];
+ *first++ = Base64EncodeTable[b];
+ *first++ = B64_PAD_CHAR;
+ *first++ = B64_PAD_CHAR;
+ data++;
+ }
+ else if (data+2 == end) {
+ block = data[0] << 16 | data[1] << 8;
+ a = (block >> 3*6) & 0x3f;
+ b = (block >> 2*6) & 0x3f;
+ c = (block >> 1*6) & 0x3f;
+ *first++ = Base64EncodeTable[a];
+ *first++ = Base64EncodeTable[b];
+ *first++ = Base64EncodeTable[c];
+ *first++ = B64_PAD_CHAR;
+ data += 2;
+ }
+ else {
+ block = data[0] << 16 | data[1] << 8 | data[2];
+ a = (block >> 3*6) & 0x3f;
+ b = (block >> 2*6) & 0x3f;
+ c = (block >> 1*6) & 0x3f;
+ d = (block >> 0*6) & 0x3f;
+ *first++ = Base64EncodeTable[a];
+ *first++ = Base64EncodeTable[b];
+ *first++ = Base64EncodeTable[c];
+ *first++ = Base64EncodeTable[d];
+ data += 3;
+ }
+ }
+
+
+
+
+// string_hash ----------------------------------------------------------------
+unsigned long ixion::string_hash::operator()(string const &str) const {
+ // the sgi stl uses the same hash algorithm
+ unsigned long h = 0;
+ FOREACH_CONST(first,str,string)
+ h = 5*h + *first;
+ return h;
+ }