#ifndef __OBJECT_SCRIPT_H__
#define __OBJECT_SCRIPT_H__
/******************************************************************************
* Copyright (C) 2012 Evgeniy Golovin (evgeniy.golovin@unitpoint.ru)
*
* Latest source code: https://github.com/unitpoint/objectscript
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
// #include <vector>
#include <stdarg.h>
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#if !defined __GNUC__ || defined IW_SDK
#include <new.h>
#else
inline void *operator new(size_t, void * p){ return p; }
inline void operator delete(void *, void *){}
#endif
#if defined _MSC_VER && !defined IW_SDK
#include <vadefs.h>
#endif
#if defined _DEBUG && !defined OS_RELEASE
#define OS_DEBUG
#endif
// select ObjectScript number type here
#ifndef OS_NUMBER
#define OS_NUMBER double
// #define OS_NUMBER float // could be a bit faster
// #define OS_NUMBER int // not recomended, math.random returns float value [0..1]
#endif // OS_NUMBER
#define OS_MATH_POW_OPERATOR(a, b) (OS_NUMBER)::pow((double)(a), (double)(b))
#define OS_MATH_MOD_OPERATOR(a, b) (OS_NUMBER)((OS_INT)(a) % (OS_INT)(b))
#define OS_CHAR char
#define OS_TEXT(s) s
// does disable _G due to security reason ???
#if !defined OS_GLOBAL_VAR_ENABLED && !defined OS_GLOBAL_VAR_DISABLED
#define OS_GLOBAL_VAR_ENABLED
#endif
#define OS_ENV_VAR_NAME OS_TEXT("_E")
#define OS_GLOBALS_VAR_NAME OS_TEXT("_G")
#define OS_FLOAT double
#define OS_INT8 signed char
#define OS_BYTE unsigned char
#define OS_INT16 short
#define OS_U16 unsigned short
#if defined __GNUC__
#include <inttypes.h>
#define OS_INT int
#define OS_INT32 int32_t
#define OS_INT64 int64_t
#define OS_U32 uint32_t
#define OS_U64 uint64_t
#elif defined IW_SDK
#define OS_INT int
#define OS_INT32 int32
#define OS_INT64 int64
#define OS_U32 uint32
#define OS_U64 uint64
#else
#define OS_INT int
#define OS_INT32 __int32
#define OS_INT64 __int64
#define OS_U32 unsigned __int32
#define OS_U64 unsigned __int64
#endif
#define OS_MEMCMP ::memcmp
#define OS_MEMMOVE ::memmove
#define OS_MEMSET ::memset
#define OS_MEMCPY ::memcpy
#define OS_STRLEN ::strlen
#define OS_STRCMP ::strcmp
#define OS_STRNCMP ::strncmp
#define OS_STRCHR ::strchr
#define OS_STRSTR ::strstr
#define OS_VPRINTF ::vprintf
#define OS_PRINTF ::printf
#define OS_IS_SPACE(c) ((c) > OS_TEXT('\0') && (c) <= OS_TEXT(' '))
#define OS_IS_ALPHA ::isalpha
#define OS_IS_ALNUM(c) ((c) >= OS_TEXT('0') && (c) <= OS_TEXT('9'))
#define OS_IS_SLASH(c) ((c) == OS_TEXT('/') || (c) == OS_TEXT('\\'))
#define OS_AUTO_PRECISION 20
#define OS_TOP_STACK_NULL_VALUES 20
#define OS_DEF_FMT_BUF_LEN (1024*10)
#define OS_PATH_SEPARATOR OS_TEXT("/")
// uncomment it if need
// #define OS_INFINITE_LOOP_OPCODES 100000000
#define OS_CALL_STACK_MAX_SIZE 200
#define OS_VERSION OS_TEXT("0.98-rc")
#define OS_COMPILED_HEADER OS_TEXT("OBJECTSCRIPT")
#define OS_DEBUGINFO_HEADER OS_TEXT("OBJECTSCRIPT.DEBUGINFO")
#define OS_SOURCECODE_EXT OS_TEXT(".os")
#define OS_COMPILED_EXT OS_TEXT(".osc")
#define OS_DEBUG_INFO_EXT OS_TEXT(".osd")
#define OS_DEBUG_OPCODES_EXT OS_TEXT(".txt")
#define OS_MEMORY_MANAGER_PAGE_BLOCKS 32
#define OS_DEBUGGER_SAVE_NUM_LINES 11
#ifdef OS_DEBUG
#define OS_ASSERT assert
#define OS_DBG_FILEPOS_DECL , const OS_CHAR * dbg_filename, int dbg_line
#define OS_DBG_FILEPOS_PARAM , dbg_filename, dbg_line
#define OS_DBG_FILEPOS , __FILE__, __LINE__
#define OS_DBG_FILEPOS_START_DECL const OS_CHAR * dbg_filename, int dbg_line
#define OS_DBG_FILEPOS_START_PARAM dbg_filename, dbg_line
#define OS_DBG_FILEPOS_START __FILE__, __LINE__
#else
#define OS_ASSERT(a)
#define OS_DBG_FILEPOS_DECL
#define OS_DBG_FILEPOS_PARAM
#define OS_DBG_FILEPOS
#define OS_DBG_FILEPOS_START_DECL
#define OS_DBG_FILEPOS_START_PARAM
#define OS_DBG_FILEPOS_START
#endif // OS_DEBUG
#if defined _MSC_VER // && !defined IW_SDK
#define DEBUG_BREAK __debugbreak()
#elif !defined __GNUC__
#include <signal.h>
#define DEBUG_BREAK raise(SIGTRAP)
// #define DEBUG_BREAK __builtin_trap()
#else
#define DEBUG_BREAK
#endif
#ifndef OS_PROFILE_BEGIN_OPCODE
#define OS_PROFILE_BEGIN_OPCODE
#define OS_PROFILE_END_OPCODE
#endif
namespace ObjectScript
{
class OS;
typedef void (*OS_UserdataDtor)(OS*, void * data, void * user_param);
typedef int (*OS_CFunction)(OS*, int params, int closure_values, int need_ret_values, void * user_param);
enum OS_ESettings
{
OS_SETTING_CREATE_DEBUG_OPCODES,
OS_SETTING_CREATE_DEBUG_INFO,
OS_SETTING_CREATE_COMPILED_FILE,
OS_SETTING_PRIMARY_COMPILED_FILE,
};
enum OS_EValueType
{
OS_VALUE_TYPE_NULL,
OS_VALUE_TYPE_BOOL,
OS_VALUE_TYPE_NUMBER,
OS_VALUE_TYPE_STRING,
OS_VALUE_TYPE_ARRAY,
OS_VALUE_TYPE_OBJECT,
OS_VALUE_TYPE_USERDATA,
OS_VALUE_TYPE_USERPTR,
OS_VALUE_TYPE_FUNCTION,
OS_VALUE_TYPE_CFUNCTION,
// internal
OS_VALUE_TYPE_WEAKREF,
OS_VALUE_TYPE_UNKNOWN,
};
enum // OS_ValueRegister
{
OS_REGISTER_GLOBALS = 0x10000000,
OS_REGISTER_USERPOOL
};
enum
{
OS_GC_PHASE_MARK,
OS_GC_PHASE_SWEEP,
};
enum
{
OS_E_ERROR = 1<<0,
OS_E_WARNING = 1<<1,
OS_E_NOTICE = 1<<2,
// --------------------------
OS_ERROR_LEVELS = 3,
OS_E_ALL = (1<<OS_ERROR_LEVELS)-1
};
enum OS_EOpcode
{
// binary operators
OP_COMPARE, // return int
OP_LOGIC_PTR_EQ, // ===
OP_LOGIC_PTR_NE, // !==
OP_LOGIC_EQ, // ==
OP_LOGIC_NE, // !=
OP_LOGIC_GE, // >=
OP_LOGIC_LE, // <=
OP_LOGIC_GREATER, // >
OP_LOGIC_LESS, // <
OP_BIT_AND, // &
OP_BIT_OR, // |
OP_BIT_XOR, // ^
OP_ADD, // +
OP_SUB, // -
OP_MUL, // *
OP_DIV, // /
OP_MOD, // %
OP_LSHIFT, // <<
OP_RSHIFT, // >>
OP_POW, // **
OP_CONCAT, // ..
// unary operators
OP_BIT_NOT, // ~
OP_PLUS, // +
OP_NEG, // -
OP_LENGTH, // #
/*
OP_LOGIC_BOOL,
OP_LOGIC_NOT,
OP_VALUE_OF,
OP_NUMBER_OF,
OP_STRING_OF,
OP_ARRAY_OF,
OP_OBJECT_OF,
OP_USERDATA_OF,
OP_FUNCTION_OF,
OP_CLONE,
*/
};
class OS
#ifdef OBJECT_SCRIPT_EXTENDS_CLASS
: public OBJECT_SCRIPT_EXTENDS_CLASS
#endif
{
public:
class MemoryManager
{
protected:
int ref_count;
virtual ~MemoryManager();
public:
MemoryManager();
MemoryManager * retain();
void release();
virtual void * malloc(int size OS_DBG_FILEPOS_DECL) = 0;
virtual void free(void * p) = 0;
virtual void setBreakpointId(int id) = 0;
virtual int getAllocatedBytes() = 0;
virtual int getMaxAllocatedBytes() = 0;
virtual int getCachedBytes() = 0;
};
class SmartMemoryManager: public MemoryManager
{
protected:
int allocated_bytes;
int max_allocated_bytes;
int cached_bytes;
struct PageDesc
{
int block_size;
int num_blocks;
int allocated_bytes;
};
struct Page
{
int index;
int num_cached_blocks;
Page * next_page;
};
struct CachedBlock
{
#ifdef OS_DEBUG
int mark;
#endif
Page * page;
CachedBlock * next;
};
struct MemBlock
{
Page * page;
#ifdef OS_DEBUG
const OS_CHAR * dbg_filename;
int dbg_line;
int dbg_id;
MemBlock * dbg_mem_prev;
MemBlock * dbg_mem_next;
#endif
int block_size;
#ifdef OS_DEBUG
int mark;
#endif
};
struct StdMemBlock
{
#ifdef OS_DEBUG
const OS_CHAR * dbg_filename;
int dbg_line;
int dbg_id;
StdMemBlock * dbg_mem_prev;
StdMemBlock * dbg_mem_next;
#endif
int block_size;
#ifdef OS_DEBUG
int mark;
#endif
};
enum {
MAX_PAGE_TYPE_COUNT = 17
};
PageDesc page_desc[MAX_PAGE_TYPE_COUNT];
int num_page_desc;
Page * pages[MAX_PAGE_TYPE_COUNT];
CachedBlock * cached_blocks[MAX_PAGE_TYPE_COUNT];
#ifdef OS_DEBUG
MemBlock * dbg_mem_list;
StdMemBlock * dbg_std_mem_list;
int dbg_breakpoint_id;
#endif
int stat_malloc_count;
int stat_free_count;
void registerPageDesc(int block_size, int num_blocks);
static int comparePageDesc(const void * pa, const void * pb);
void sortPageDesc();
void * allocFromCachedBlock(int i OS_DBG_FILEPOS_DECL);
void * allocFromPageType(int i OS_DBG_FILEPOS_DECL);
void freeMemBlock(MemBlock*);
void freeCachedMemory(int new_cached_bytes);
void * stdAlloc(int size OS_DBG_FILEPOS_DECL);
void stdFree(void * p);
public:
SmartMemoryManager();
~SmartMemoryManager();
void * malloc(int size OS_DBG_FILEPOS_DECL);
void free(void * p);
void setBreakpointId(int id);
int getAllocatedBytes();
int getMaxAllocatedBytes();
int getCachedBytes();
};
struct Utils
{
static bool parseFloat(const OS_CHAR *& str, OS_FLOAT& val);
static OS_CHAR * numToStr(OS_CHAR*, OS_INT32 value);
static OS_CHAR * numToStr(OS_CHAR*, OS_INT64 value);
static OS_CHAR * numToStr(OS_CHAR*, float value, int precision = OS_AUTO_PRECISION);
static OS_CHAR * numToStr(OS_CHAR*, double value, int precision = OS_AUTO_PRECISION);
static OS_INT strToInt(const OS_CHAR*);
static OS_FLOAT strToFloat(const OS_CHAR*);
static int addKeyToHash(int hash, const void*, int size);
static int keyToHash(const void*, int size);
static int keyToHash(const void * buf1, int size1, const void * buf2, int size2);
static int cmp(const void * buf1, int len1, const void * buf2, int len2);
};
class String;
class ObjectScriptExtention;
protected:
template<class T>
struct Vector
{
T * buf;
int capacity;
int count;
Vector()
{
buf = NULL;
capacity = 0;
count = 0;
}
~Vector()
{
OS_ASSERT(!buf && !capacity && !count);
}
T& operator [] (int i)
{
OS_ASSERT(i >= 0 && i < count);
return buf[i];
}
const T& operator [] (int i) const
{
OS_ASSERT(i >= 0 && i < count);
return buf[i];
}
T& lastElement()
{
OS_ASSERT(count > 0);
return buf[count-1];
}
const T& lastElement() const
{
OS_ASSERT(count > 0);
return buf[count-1];
}
bool contains(const T& val) const
{
for(int i = count-1; i >= 0; i--){
if(buf[i] == val){
return true;
}
}
return false;
}
int indexOf(const T& val) const
{
for(int i = 0; i < count; i++){
if(buf[i] == val){
return i;
}
}
return -1;
}
};
template<class T> void vectorReserveCapacity(Vector<T>& vec, int new_capacity OS_DBG_FILEPOS_DECL)
{
if(vec.capacity < new_capacity){
vec.capacity = vec.capacity > 0 ? vec.capacity*2 : 4;
if(vec.capacity < new_capacity){
vec.capacity = new_capacity; // (capacity+3) & ~3;
}
T * new_buf = (T*)malloc(sizeof(T)*vec.capacity OS_DBG_FILEPOS_PARAM);
OS_ASSERT(new_buf);
for(int i = 0; i < vec.count; i++){
new (new_buf+i) T(vec.buf[i]);
vec.buf[i].~T();
}
free(vec.buf);
vec.buf = new_buf;
}
}
template<class T> void vectorReserveCapacityExact(Vector<T>& vec, int capacity OS_DBG_FILEPOS_DECL)
{
if(vec.capacity < capacity){
vec.capacity = capacity;
T * new_buf = (T*)malloc(sizeof(T)*vec.capacity OS_DBG_FILEPOS_PARAM);
OS_ASSERT(new_buf);
for(int i = 0; i < vec.count; i++){
new (new_buf+i) T(vec.buf[i]);
vec.buf[i].~T();
}
free(vec.buf);
vec.buf = new_buf;
}
}
template<class T> void vectorAddItem(Vector<T>& vec, const T& val OS_DBG_FILEPOS_DECL)
{
vectorReserveCapacity(vec, vec.count+1 OS_DBG_FILEPOS_PARAM);
new (vec.buf + vec.count++) T(val);
}
template<class T> void vectorClear(Vector<T>& vec)
{
for(int i = 0; i < vec.count; i++){
vec.buf[i].~T();
}
free(vec.buf);
vec.buf = NULL;
vec.capacity = 0;
vec.count = 0;
}
template<class T> void vectorReleaseItems(Vector<T>& vec)
{
for(int i = 0; i < vec.count; i++){
vec.buf[i]->release();
}
// free(vec.buf);
// vec.buf = NULL;
// vec.capacity = 0;
vec.count = 0;
}
template<class T> void vectorDeleteItems(Vector<T*>& vec)
{
for(int i = 0; i < vec.count; i++){
T * item = vec.buf[i];
item->~T();
free(item);
}
// free(vec.buf);
// vec.buf = NULL;
// vec.capacity = 0;
vec.count = 0;
}
template<class T> void vectorInsertAtIndex(Vector<T>& vec, int i, const T& val OS_DBG_FILEPOS_DECL)
{
OS_ASSERT(i >= 0 && i <= vec.count);
vectorReserveCapacity(vec, vec.count+1 OS_DBG_FILEPOS_PARAM);
for(int j = vec.count-1; j >= i; j--){
new (vec.buf+j+1) T(vec.buf[j]);
vec.buf[j].~T();
}
new (vec.buf+i) T(val);
vec.count++;
}
template<class T> void vectorRemoveAtIndex(Vector<T>& vec, int i)
{
OS_ASSERT(i >= 0 && i < vec.count);
// T val = vec.buf[i];
vec.buf[i].~T();
for(i++; i < vec.count; i++){
new (vec.buf+i-1) T(vec.buf[i]);
vec.buf[i].~T();
}
vec.count--;
// return val;
}
template<class T> void releaseObj(T *& obj)
{
if(--obj->ref_count <= 0){
OS_ASSERT(obj->ref_count == 0);
obj->~T();
free(obj);
obj = NULL;
}
}
template<class T> void deleteObj(T *& obj)
{
if(obj){
obj->~T();
free(obj);
obj = NULL;
}
}
class Core
{
public:
class StreamReader;
class StreamWriter
{
public:
OS * allocator;
StreamWriter(OS*);
virtual ~StreamWriter();
virtual int getPos() const = 0;
virtual void setPos(int) = 0;
virtual int getSize() const = 0;
virtual void writeFromStream(StreamReader*);
virtual void writeBytes(const void*, int len) = 0;
virtual void writeBytesAtPos(const void*, int len, int pos) = 0;
virtual void writeByte(int);
virtual void writeByteAtPos(int value, int pos);
virtual void writeUVariable(int);
virtual void writeU16(int);
virtual void writeU16AtPos(int value, int pos);
virtual void writeInt8(int);
virtual void writeInt8AtPos(int value, int pos);
virtual void writeInt16(int);
virtual void writeInt16AtPos(int value, int pos);
virtual void writeInt32(int);
virtual void writeInt32AtPos(int value, int pos);
virtual void writeInt64(OS_INT64);
virtual void writeInt64AtPos(OS_INT64 value, int pos);
virtual void writeFloat(float);
virtual void writeFloatAtPos(float value, int pos);
virtual void writeDouble(double);
virtual void writeDoubleAtPos(double value, int pos);
};
class MemStreamWriter: public StreamWriter
{
public:
Vector<OS_BYTE> buffer;
int pos;
MemStreamWriter(OS*);
~MemStreamWriter();
int getPos() const;
void setPos(int);
int getSize() const;
void writeBytes(const void*, int len);
void writeBytesAtPos(const void*, int len, int pos);
void writeByte(int);
void writeByteAtPos(int value, int pos);
};
class FileStreamWriter: public StreamWriter
{
public:
void * f;
FileStreamWriter(OS*, const OS_CHAR * filename);
~FileStreamWriter();
int getPos() const;
void setPos(int);
int getSize() const;
void writeBytes(const void*, int len);
void writeBytesAtPos(const void*, int len, int pos);
};
class StreamReader
{
public:
OS * allocator; // if NULL then buffer will not be freed
StreamReader(OS*);
virtual ~StreamReader();
virtual int getPos() const = 0;
virtual void setPos(int) = 0;
virtual int getSize() const = 0;
virtual void movePos(int len) = 0;
virtual bool checkBytes(const void*, int len) = 0;
virtual void * readBytes(void*, int len) = 0;
virtual void * readBytesAtPos(void*, int len, int pos) = 0;
virtual OS_BYTE readByte();
virtual OS_BYTE readByteAtPos(int pos);
virtual int readUVariable();
virtual OS_U16 readU16();
virtual OS_U16 readU16AtPos(int pos);
virtual OS_INT8 readInt8();
virtual OS_INT8 readInt8AtPos(int pos);
virtual OS_INT16 readInt16();
virtual OS_INT16 readInt16AtPos(int pos);
virtual OS_INT32 readInt32();
virtual OS_INT32 readInt32AtPos(int pos);
virtual OS_INT64 readInt64();
virtual OS_INT64 readInt64AtPos(int pos);
virtual float readFloat();
virtual float readFloatAtPos(int pos);
virtual double readDouble();
virtual double readDoubleAtPos(int pos);
};
class MemStreamReader: public StreamReader
{
public:
OS_BYTE * buffer;
int size;
// int pos;
OS_BYTE * cur;
// if allocator is NULL then buffer will not be freed
MemStreamReader(OS*, int buf_size);
MemStreamReader(OS*, OS_BYTE * buf, int buf_size);
~MemStreamReader();
int getPos() const;
void setPos(int);
int getSize() const;
void movePos(int len);
bool checkBytes(const void*, int len);
void * readBytes(void*, int len);
void * readBytesAtPos(void*, int len, int pos);
OS_BYTE readByte();
OS_BYTE readByteAtPos(int pos);
OS_INT8 readInt8();
OS_INT16 readInt16();
OS_INT32 readInt32();
};
class FileStreamReader: public StreamReader
{
public:
void * f;
FileStreamReader(OS*, const OS_CHAR * filename);
~FileStreamReader();
int getPos() const;
void setPos(int);
int getSize() const;
void movePos(int len);
bool checkBytes(const void*, int len);
void * readBytes(void*, int len);
void * readBytesAtPos(void*, int len, int pos);
};
struct GCStringValue;
class StringBuffer;
class String
{
public:
#ifdef OS_DEBUG
const OS_CHAR * str;
#endif
GCStringValue * string;
String(OS*);
String(GCStringValue*);
String(const String&);
String(OS*, const String&, const String&);
String(OS*, const OS_CHAR*);
String(OS*, const OS_CHAR*, int len);
String(OS*, const OS_CHAR*, int len, const OS_CHAR*, int len2);
String(OS*, const OS_CHAR*, int len, bool trim_left, bool trim_right);
String(OS*, const void*, int size);
String(OS*, const void * buf1, int len1, const void * buf2, int len2);
String(OS*, const void * buf1, int len1, const void * buf2, int len2, const void * buf3, int len3);
String(OS*, OS_INT value);
String(OS*, OS_FLOAT value, int precision = OS_AUTO_PRECISION);
~String();
static String format(OS*, int temp_buf_len, const OS_CHAR * fmt, ...);
static String formatVa(OS*, int temp_buf_len, const OS_CHAR * fmt, va_list va);
static String format(OS*, const OS_CHAR * fmt, ...);
static String formatVa(OS*, const OS_CHAR * fmt, va_list va);
const OS_CHAR * toChar() const { return string->toChar(); }
operator const OS_CHAR*() const { return string->toChar(); }
OS_CHAR operator[](int i)
{
if(i >= 0 && i < getLen()){
return toChar()[i];
}
return OS_TEXT('\0');
}
int getDataSize() const { return string->data_size; }
int getLen() const { return string->getLen(); }
String& operator=(const String&);
bool operator==(const String&) const;
bool operator==(const OS_CHAR*) const;
bool operator==(GCStringValue*) const;
bool operator!=(const String&) const;
bool operator!=(const OS_CHAR*) const;
bool operator!=(GCStringValue*) const;
bool operator<=(const String&) const;
bool operator<=(const OS_CHAR*) const;
bool operator<(const String&) const;
bool operator<(const OS_CHAR*) const;
bool operator>=(const String&) const;
bool operator>=(const OS_CHAR*) const;
bool operator>(const String&) const;
bool operator>(const OS_CHAR*) const;
int cmp(const String&) const;
int cmp(const OS_CHAR*) const;
int getHash() const;
OS_NUMBER toNumber() const;
};
class StringBuffer: public Vector<OS_CHAR>
{
public:
OS * allocator;
StringBuffer(OS*);
~StringBuffer();
StringBuffer& append(OS_CHAR);
StringBuffer& append(const OS_CHAR*);
StringBuffer& append(const OS_CHAR*, int len);
StringBuffer& append(const String&);
StringBuffer& append(const StringBuffer&);
StringBuffer& operator+=(const String&);
StringBuffer& operator+=(const OS_CHAR*);
operator String() const;
String toString() const;
GCStringValue * toGCStringValue() const;
};
class Tokenizer
{
public:
enum Error
{
ERROR_NOTHING,
ERROR_MULTI_LINE_COMMENT, // multi line comment not end
// ERROR_CONST_VECTOR_3, // cant parse const vec3
// ERROR_CONST_VECTOR_4, // cant parse const vec4
ERROR_CONST_STRING, // string not end
ERROR_CONST_STRING_ESCAPE_CHAR, // string escape error
// ERROR_NAME, // error name, _ - this is error
ERROR_SYNTAX
};
enum TokenType
{
NOTHING,
BEGIN_CODE_BLOCK, // {
END_CODE_BLOCK, // }
BEGIN_BRACKET_BLOCK, // (
END_BRACKET_BLOCK, // )
BEGIN_ARRAY_BLOCK, // [
END_ARRAY_BLOCK, // ]
CODE_SEPARATOR, // ;
PARAM_SEPARATOR, // ,
COMMENT_LINE,
COMMENT_MULTI_LINE,
NAME, // [a..z_$][a..z0..9_$]*
// DOT_NAME, // used in compiler [NAME].[NAME]... - for types
// IDENTIFER, // used in compiler [NAME]
// DOT_IDENTIFER, // used in compiler [NAME].[NAME]... - for types
STRING, // ["].*?["]
// NUM_INT, // -?[0..9]+
NUMBER, // -?[0..9][.]?[0..9]+(e[+-]?[0..9]+)?
// NUM_VECTOR_3, // 'NUMBER NUMBER NUMBER'
// NUM_VECTOR_4, // 'NUMBER NUMBER NUMBER NUMBER'
// NULL, // used in compiler
// [not real operators]
OPERATOR,
BINARY_OPERATOR,
SEPARATOR,
// [/not real operators]
OPERATOR_INDIRECT, // .
OPERATOR_CONCAT, // ..
REST_ARGUMENTS, // ...
OPERATOR_LOGIC_AND, // &&
OPERATOR_LOGIC_OR, // ||
OPERATOR_LOGIC_PTR_EQ, // ===
OPERATOR_LOGIC_PTR_NE, // !==
OPERATOR_LOGIC_EQ, // ==
OPERATOR_LOGIC_NE, // !=
OPERATOR_LOGIC_GE, // >=
OPERATOR_LOGIC_LE, // <=
OPERATOR_LOGIC_GREATER, // >
OPERATOR_LOGIC_LESS, // <
OPERATOR_LOGIC_NOT, // !
OPERATOR_INC, // ++
OPERATOR_DEC, // --
OPERATOR_QUESTION, // ?
OPERATOR_COLON, // :
OPERATOR_IN, // in
OPERATOR_ISPROTOTYPEOF, // is
OPERATOR_IS, // is
OPERATOR_LENGTH, // #
OPERATOR_BIT_AND, // &
OPERATOR_BIT_OR, // |
OPERATOR_BIT_XOR, // ^
OPERATOR_BIT_NOT, // ~
OPERATOR_ADD, // +
OPERATOR_SUB, // -
OPERATOR_MUL, // *
OPERATOR_DIV, // /
OPERATOR_MOD, // %
OPERATOR_LSHIFT, // <<
OPERATOR_RSHIFT, // >>
OPERATOR_POW, // **
OPERATOR_BIT_AND_ASSIGN, // &=
OPERATOR_BIT_OR_ASSIGN, // |=
OPERATOR_BIT_XOR_ASSIGN, // ^=
OPERATOR_BIT_NOT_ASSIGN, // ~=
OPERATOR_ADD_ASSIGN, // +=
OPERATOR_SUB_ASSIGN, // -=
OPERATOR_MUL_ASSIGN, // *=
OPERATOR_DIV_ASSIGN, // /=
OPERATOR_MOD_ASSIGN, // %=
OPERATOR_LSHIFT_ASSIGN, // <<=
OPERATOR_RSHIFT_ASSIGN, // >>=
OPERATOR_POW_ASSIGN, // **=
OPERATOR_ASSIGN, // =
OPERATOR_RESERVED,
OPERATOR_END,
ERROR_TOKEN
};
class TextData
{
protected:
~TextData();
public:
OS * allocator;
String filename;
Vector<String> lines;
int ref_count;
TextData(OS*);
TextData * retain();
void release();
};
class TokenData
{
protected:
union
{
// OS_INT int_value;
OS_FLOAT float_value;
// OS_FLOAT * vec3;
// OS_FLOAT * vec4;
};
~TokenData();
public:
TextData * text_data;
String str;
int line, pos;
int ref_count;
TokenType type;
OS * getAllocator() const;
OS_FLOAT getFloat() const;
TokenData(TextData * text_data, const String& p_str, TokenType p_type, int p_line, int p_pos);
TokenData * retain();
void release();
void setFloat(OS_FLOAT value);
operator String () const { return str; }
bool isTypeOf(TokenType tokenType) const;
};
protected:
struct Settings
{
bool save_comments;
} settings;
OS * allocator;
TextData * text_data;
int cur_line, cur_pos;
// bool loaded;
// bool compiled;
Vector<TokenData*> tokens;
Error error;
struct OperatorDesc
{
TokenType type;
const OS_CHAR * name;
};
static const int operator_count;
static OperatorDesc operator_desc[];
static bool operator_initialized;
void printLines();
void printTokens();
// private:
static int compareOperatorDesc(const void * a, const void * b) ;
static void initOperatorsTable();
TokenData * addToken(const String& token, TokenType type, int line, int pos OS_DBG_FILEPOS_DECL);
bool parseFloat(const OS_CHAR *& str, OS_FLOAT& fval, bool parse_end_spaces);
bool parseLines();
public:
Tokenizer(OS*);
~Tokenizer();
OS * getAllocator();
TextData * getTextData() const { return text_data; }
bool isError() const { return error != ERROR_NOTHING; }
Error getErrorCode() const { return error; }
int getErrorLine() const { return cur_line; }
int getErrorPos() const { return cur_pos; }
static const OS_CHAR * getTokenTypeName(TokenType tokenType);
String getFilename() const { return text_data->filename; }
String getLineString(int i) const { return text_data->lines[i]; }
int getNumLines() const { return text_data->lines.count; }
bool getSettingSaveComment() const { return settings.save_comments; }
void setSettingSaveComment(bool value){ settings.save_comments = value; }
bool parseText(const OS_CHAR * text, int len, const String& filename);
int getNumTokens() const { return tokens.count; }
TokenData * getToken(int i) const { return tokens[i]; }
TokenData * removeToken(int i);
void insertToken(int i, TokenData * token OS_DBG_FILEPOS_DECL);
};
typedef Tokenizer::TokenType TokenType;
typedef Tokenizer::TokenData TokenData;
typedef Tokenizer::TextData TextData;
struct Property;
struct PropertyIndex;
struct Table
{
struct IteratorState
{
Table * table;
Property * prop;
IteratorState * next;
bool ascending;
IteratorState();
~IteratorState();
};
Property ** heads;
int head_mask;
int count;
OS_INT next_index;
Property * first, * last;
IteratorState * iterators;
Table();
~Table();
Property * get(const PropertyIndex& index);
bool containsIterator(IteratorState*);
void addIterator(IteratorState*);
void removeIterator(IteratorState*);
};
enum EGCColor
{
GC_WHITE,
// GC_WHITE_WHITE,
GC_GREY,
GC_BLACK
};
struct GCValue
{
int value_id;
int external_ref_count;
GCValue * prototype;
GCValue * hash_next;
Table * table;
// Value * gc_grey_prev;
GCValue * gc_grey_next;
#ifdef OS_DEBUG
int gc_time;
#endif
OS_EValueType type;
bool is_object_instance;
EGCColor gc_color;
GCValue();
virtual ~GCValue();
};
template <class T>
struct GCValueRetained
{
T * value;
GCValueRetained(T * v)
{
value = v;
if(value){
value->external_ref_count++;
}
}
GCValueRetained(const GCValueRetained& b)
{
value = b.value;
if(value){
value->external_ref_count++;
}
}
~GCValueRetained()
{
if(value){
OS_ASSERT(value->external_ref_count > 0);
value->external_ref_count--;
}
}
T * operator->(){ return value; }
operator T* (){ return value; }
GCValueRetained& operator=(const GCValueRetained& b)
{
if(value != b.value){
if(value){
OS_ASSERT(value->external_ref_count > 0);
value->external_ref_count--;
}
value = b.value;
if(value){
value->external_ref_count++;
}
}
return *this;
}
};
struct GCObjectValue: public GCValue
{
};
struct GCArrayValue;
struct GCStringValue: public GCValue
{
#ifdef OS_DEBUG
OS_CHAR * str;
#endif
int data_size;
int hash;
GCStringValue(int p_data_size);
// ~GCStringValue();
int getDataSize() const { return data_size; }
int getLen() const { return data_size/sizeof(OS_CHAR); }
OS_CHAR * toChar() const { return (OS_CHAR*)(this + 1); }
OS_BYTE * toBytes() const { return (OS_BYTE*)(this + 1); }
void * toMemory() const { return (void*)(this + 1); }
// bool isExternal() const { return str != (OS_CHAR*)(this+1); }
static GCStringValue * alloc(OS*, const void *, int data_size OS_DBG_FILEPOS_DECL);
static GCStringValue * alloc(OS*, const void * buf1, int len1, const void * buf2, int len2 OS_DBG_FILEPOS_DECL);
// static GCStringValue * alloc(OS*, const void * buf1, int len1, const void * buf2, int len2, const void * buf3, int len3);
static GCStringValue * alloc(OS*, GCStringValue * a, GCStringValue * b OS_DBG_FILEPOS_DECL);
// static GCStringValue * alloc(OS*, GCStringValue * a, GCStringValue * b, GCStringValue * c);
bool isNumber(OS_NUMBER*) const;
// bool isNumber(OS_FLOAT*) const;
int cmp(GCStringValue*) const;
int cmp(const OS_CHAR*) const;
int cmp(const OS_CHAR*, int len) const;
bool isEqual(int hash, const void * b, int size) const;
bool isEqual(int hash, const void * buf1, int size1, const void * buf2, int size2) const;
// bool isEqual(int hash, const void * buf1, int size1, const void * buf2, int size2, const void * buf3, int size3) const;
void calcHash();
};
struct GCUserdataValue: public GCValue
{
int crc;
void * ptr;
OS_UserdataDtor dtor;
void * user_param;
};
struct GCCFunctionValue: public GCValue
{
GCStringValue * name;
OS_CFunction func;
void * user_param;
int num_closure_values;
};
struct GCFunctionValue;
struct WeakRef { WeakRef(){} };
struct Value
{
union {
int boolean;
OS_NUMBER number;
int value_id;
GCValue * value;
GCObjectValue * object;
GCArrayValue * arr;
GCStringValue * string;
GCUserdataValue * userdata;
GCFunctionValue * func;
GCCFunctionValue * cfunc;
} v;
OS_EValueType type;
Value();
Value(bool);
Value(OS_INT32);
Value(OS_INT64);
Value(float);
Value(double);
Value(GCValue*);
Value(int, const WeakRef&);
Value& operator=(GCValue*);
Value& operator=(bool);
Value& operator=(OS_INT32);
Value& operator=(OS_INT64);
Value& operator=(float);
Value& operator=(double);
void clear();
GCValue * getGCValue() const;
bool isNull() const;
bool isFunction() const;
bool isUserdata() const;
};
struct ValueRetained: public Value
{
typedef Value super;
ValueRetained();
ValueRetained(bool);
ValueRetained(OS_FLOAT);
ValueRetained(int);
ValueRetained(int, const WeakRef&);
ValueRetained(GCValue*);
ValueRetained(Value);
~ValueRetained();
ValueRetained& operator=(Value);
void clear();
void retain();
void release();
};
struct GCArrayValue: public GCValue
{
Vector<Value> values;
};
class Program;
struct FunctionDecl;
struct Upvalues;
struct GCFunctionValue: public GCValue
{
Program * prog; // retained
FunctionDecl * func_decl;
Value env;
Upvalues * upvalues; // retained
GCStringValue * name;
GCFunctionValue();
~GCFunctionValue();
};
struct PropertyIndex
{
struct KeepStringIndex
{
KeepStringIndex(){}
};
Value index;
PropertyIndex(const PropertyIndex& index);
PropertyIndex(Value index);
PropertyIndex(Value index, const KeepStringIndex&);
PropertyIndex(GCStringValue * index);
PropertyIndex(GCStringValue * index, const KeepStringIndex&);
PropertyIndex(const String& index);
PropertyIndex(const String& index, const KeepStringIndex&);
void convertIndexStringToNumber();
bool isEqual(const PropertyIndex& b) const;
bool isEqual(int hash, const void * b, int size) const;
bool isEqual(int hash, const void * buf1, int size1, const void * buf2, int size2) const;
int getHash() const;
};
struct Property: public PropertyIndex
{
Value value;
Property * hash_next;
Property * prev, * next;
Property(const PropertyIndex& index);
Property(Value index);
Property(Value index, const KeepStringIndex&);
Property(GCStringValue * index);
Property(GCStringValue * index, const KeepStringIndex&);
~Property();
};
class Compiler
{
public:
enum ExpressionType
{
EXP_TYPE_UNKNOWN,
EXP_TYPE_NOP,
EXP_TYPE_NEW_LOCAL_VAR,
EXP_TYPE_SCOPE,
EXP_TYPE_LOOP_SCOPE,
EXP_TYPE_CODE_LIST,
EXP_TYPE_NAME, // temp
// EXP_TYPE_POST_IF,
EXP_TYPE_POP_VALUE,
EXP_TYPE_CALL,
EXP_TYPE_CALL_AUTO_PARAM,
EXP_TYPE_CALL_DIM, // temp
EXP_TYPE_VALUE,
EXP_TYPE_PARAMS,
EXP_TYPE_FUNCTION,
EXP_TYPE_EXTENDS,
EXP_TYPE_CLONE,
EXP_TYPE_DELETE,
EXP_TYPE_RETURN,
EXP_TYPE_BREAK,
EXP_TYPE_CONTINUE,
EXP_TYPE_DEBUGGER,
EXP_TYPE_DEBUG_LOCALS,
EXP_TYPE_IF,
EXP_TYPE_QUESTION,
EXP_TYPE_ARRAY,
EXP_TYPE_OBJECT,
EXP_TYPE_OBJECT_SET_BY_NAME,
EXP_TYPE_OBJECT_SET_BY_INDEX,
EXP_TYPE_OBJECT_SET_BY_EXP,
EXP_TYPE_OBJECT_SET_BY_AUTO_INDEX,
EXP_TYPE_SUPER,
EXP_TYPE_TYPE_OF,
EXP_TYPE_VALUE_OF,
// EXP_TYPE_BOOLEAN_OF, == EXP_TYPE_LOGIC_BOOL
EXP_TYPE_NUMBER_OF,
EXP_TYPE_STRING_OF,
EXP_TYPE_ARRAY_OF,
EXP_TYPE_OBJECT_OF,
EXP_TYPE_USERDATA_OF,
EXP_TYPE_FUNCTION_OF,
EXP_TYPE_GET_THIS,
EXP_TYPE_GET_ARGUMENTS,
EXP_TYPE_GET_REST_ARGUMENTS,
EXP_TYPE_GET_LOCAL_VAR,
EXP_TYPE_GET_LOCAL_VAR_AUTO_CREATE,
EXP_TYPE_SET_LOCAL_VAR,
EXP_TYPE_SET_LOCAL_VAR_BY_BIN_OPERATOR_LOCALS,
EXP_TYPE_SET_LOCAL_VAR_BY_BIN_OPERATOR_LOCAL_AND_NUMBER,
EXP_TYPE_GET_ENV_VAR,
EXP_TYPE_GET_ENV_VAR_AUTO_CREATE,
EXP_TYPE_SET_ENV_VAR,
EXP_TYPE_INDIRECT, // temp
EXP_TYPE_GET_PROPERTY,
EXP_TYPE_GET_PROPERTY_AUTO_CREATE,
EXP_TYPE_SET_PROPERTY,
EXP_TYPE_GET_THIS_PROPERTY_BY_STRING,
EXP_TYPE_GET_PROPERTY_BY_LOCALS,
EXP_TYPE_GET_PROPERTY_BY_LOCAL_AND_NUMBER,
EXP_TYPE_SET_PROPERTY_BY_LOCALS_AUTO_CREATE,
EXP_TYPE_GET_SET_PROPERTY_BY_LOCALS_AUTO_CREATE,
// EXP_TYPE_GET_PROPERTY_DIM,
// EXP_TYPE_SET_PROPERTY_DIM,
// EXP_TYPE_GET_LOCAL_VAR_DIM,
// EXP_TYPE_GET_ENV_VAR_DIM,
// EXP_TYPE_GET_DIM,
EXP_TYPE_SET_DIM,
EXP_TYPE_CALL_METHOD,
EXP_TYPE_TAIL_CALL,
EXP_TYPE_TAIL_CALL_METHOD,
// EXP_TYPE_SET_LOCAL_VAR_DIM,
// EXP_TYPE_SET_ENV_VAR_DIM,
// EXP_CONST_STRING,
// EXP_CONST_FLOAT,
// EXP_VAR_ASSING,
EXP_TYPE_CONST_NULL,
// EXP_TYPE_CONST_VALUE,
EXP_TYPE_CONST_NUMBER,
EXP_TYPE_CONST_STRING,
EXP_TYPE_CONST_TRUE,
EXP_TYPE_CONST_FALSE,
EXP_TYPE_LOGIC_BOOL, // !!
EXP_TYPE_LOGIC_NOT, // !
EXP_TYPE_BIT_NOT, // ~
EXP_TYPE_PLUS, // +
EXP_TYPE_NEG, // -
EXP_TYPE_LENGTH, // #
EXP_TYPE_IN, // in
EXP_TYPE_ISPROTOTYPEOF, // is
EXP_TYPE_IS, // is
// EXP_TYPE_PARAM_SEPARTOR, // ,
EXP_TYPE_BIN_OPERATOR_BY_LOCALS,
EXP_TYPE_BIN_OPERATOR_BY_LOCAL_AND_NUMBER,
EXP_TYPE_CONCAT, // ..
EXP_TYPE_LOGIC_AND, // &&
EXP_TYPE_LOGIC_OR, // ||
EXP_TYPE_LOGIC_PTR_EQ, // ===
EXP_TYPE_LOGIC_PTR_NE, // !==
EXP_TYPE_LOGIC_EQ, // ==
EXP_TYPE_LOGIC_NE, // !=
EXP_TYPE_LOGIC_GE, // >=
EXP_TYPE_LOGIC_LE, // <
EXP_TYPE_LOGIC_GREATER, // >
EXP_TYPE_LOGIC_LESS, // <
// EXP_TYPE_INC, // ++
// EXP_TYPE_DEC, // --
EXP_TYPE_PRE_INC, // ++
EXP_TYPE_PRE_DEC, // --
EXP_TYPE_POST_INC, // ++
EXP_TYPE_POST_DEC, // --
// EXP_TYPE_QUESTION,
EXP_TYPE_BIT_AND, // &
EXP_TYPE_BIT_OR, // |
EXP_TYPE_BIT_XOR, // ^
EXP_TYPE_BIT_AND_ASSIGN, // &=
EXP_TYPE_BIT_OR_ASSIGN, // |=
EXP_TYPE_BIT_XOR_ASSIGN, // ^=
EXP_TYPE_BIT_NOT_ASSIGN, // ~=
EXP_TYPE_ADD, // +
EXP_TYPE_SUB, // -
EXP_TYPE_MUL, // *
EXP_TYPE_DIV, // /
EXP_TYPE_MOD, // %
EXP_TYPE_LSHIFT, // <<
EXP_TYPE_RSHIFT, // >>
EXP_TYPE_POW, // **
EXP_TYPE_ADD_ASSIGN, // +=
EXP_TYPE_SUB_ASSIGN, // -=
EXP_TYPE_MUL_ASSIGN, // *=
EXP_TYPE_DIV_ASSIGN, // /=
EXP_TYPE_MOD_ASSIGN, // %=
EXP_TYPE_LSHIFT_ASSIGN, // <<=
EXP_TYPE_RSHIFT_ASSIGN, // >>=
EXP_TYPE_POW_ASSIGN, // **=
EXP_TYPE_ASSIGN,
};
protected:
friend class Program;
struct Expression;
struct ExpressionList: public Vector<Expression*>
{
OS * allocator;
ExpressionList(OS*);
~ExpressionList();
bool isValue() const;
bool isClear() const;
bool isWriteable() const;
Expression * add(Expression* OS_DBG_FILEPOS_DECL);
Expression * removeIndex(int i);
Expression * removeLast();
void swap(ExpressionList&);
};
enum ELocalVarType
{
LOCAL_GENERIC,
LOCAL_PARAM,
LOCAL_TEMP
};
struct LocalVarDesc
{
OS_U16 up_count;
OS_U16 up_scope_count;
OS_U16 index;
ELocalVarType type;
// bool is_param;
LocalVarDesc();
};
struct Expression
{
TokenData * token;
ExpressionList list;
LocalVarDesc local_var;
OS_U16 active_locals;
OS_U16 ret_values;
OS_U16 target_local;
ExpressionType type;
Expression(ExpressionType type, TokenData*);
Expression(ExpressionType type, TokenData*, Expression * e1 OS_DBG_FILEPOS_DECL);
Expression(ExpressionType type, TokenData*, Expression * e1, Expression * e2 OS_DBG_FILEPOS_DECL);
Expression(ExpressionType type, TokenData*, Expression * e1, Expression * e2, Expression * e3 OS_DBG_FILEPOS_DECL);
virtual ~Expression();
OS * getAllocator(){ return list.allocator; }
OS_NUMBER toNumber();
OS_INT toInt();
String toString();
bool isConstValue() const;
bool isValue() const;
bool isClear() const;
bool isWriteable() const;
bool isOperator() const;
bool isUnaryOperator() const;
bool isBinaryOperator() const;
bool isAssignOperator() const;
bool isLogicOperator() const;
void debugPrint(StringBuffer&, Compiler * compiler, int depth);
};
struct Scope: public Expression
{
Scope * parent;
Scope * function;
struct LocalVar
{
String name;
int index;
LocalVar(const String& name, int index);
};
struct LocalVarCompiled
{
int cached_name_index;
int start_code_pos;
int end_code_pos;
LocalVarCompiled();
};
enum ELoopBreakType
{
LOOP_CONTINUE,
LOOP_BREAK
};
struct LoopBreak
{
int pos;
ELoopBreakType type;
};
// used by function scope
int prog_func_index;
Vector<LocalVar> locals;
Vector<LocalVarCompiled> locals_compiled;
int num_params;
int num_locals;
int opcodes_pos;
int opcodes_size;
int max_up_count;
int func_depth;
int func_index;
int num_local_funcs;
Vector<LoopBreak> loop_breaks;
bool parser_started;
Scope(Scope * parent, ExpressionType, TokenData*);
virtual ~Scope();
bool addLoopBreak(int pos, ELoopBreakType);
void fixLoopBreaks(Compiler*, int scope_start_pos, int scope_end_pos, StreamWriter*);
void addStdVars();
void addLocalVar(const String& name);
void addLocalVar(const String& name, LocalVarDesc&);
};
enum ErrorType {
ERROR_NOTHING,
ERROR_SYNTAX,
ERROR_NESTED_ROOT_BLOCK,
ERROR_LOCAL_VAL_NOT_DECLARED,
ERROR_VAR_ALREADY_EXIST,
ERROR_VAR_NAME,
ERROR_EXPECT_TOKEN_TYPE,
ERROR_EXPECT_TOKEN_STR,
ERROR_EXPECT_TOKEN,
ERROR_EXPECT_VALUE,
ERROR_EXPECT_WRITEABLE,
ERROR_EXPECT_GET_OR_SET,
ERROR_EXPECT_EXPRESSION,
ERROR_EXPECT_FUNCTION_SCOPE,
ERROR_EXPECT_CODE_SEP_BEFORE_NESTED_BLOCK,
ERROR_EXPECT_SWITCH_SCOPE,
ERROR_FINISH_BINARY_OP,
ERROR_FINISH_UNARY_OP,
};
enum OpcodeLevel {
OP_LEVEL_NOTHING = -1,
OP_LEVEL_0,
OP_LEVEL_1, // = += -= *= /= %=
OP_LEVEL_1_1, // ,
OP_LEVEL_2, // ?:
OP_LEVEL_3, // ||
OP_LEVEL_4, // &&
OP_LEVEL_5, // ..
OP_LEVEL_6, // == !=
OP_LEVEL_7, // < <= > >=
OP_LEVEL_8, // |
OP_LEVEL_9, // & ^
OP_LEVEL_10, // << >> >>>
OP_LEVEL_11, // + -
OP_LEVEL_12, // * / %
OP_LEVEL_13, // ** in as is
OP_LEVEL_14, // ++ --
OP_LEVEL_15, // unary ! ~ + #
OP_LEVEL_16, // .
OP_LEVEL_COUNT
};
OS * allocator;
Tokenizer * tokenizer;
ErrorType error;
TokenData * error_token;
TokenType expect_token_type;
String expect_token;
TokenData * recent_token;
int next_token_index;
// String recent_printed_filename;
TextData * recent_printed_text_data;
int recent_printed_line;
// code generation
// Program * prog;
Table * prog_numbers_table;
Table * prog_strings_table;
Table * prog_debug_strings_table;
Vector<OS_NUMBER> prog_numbers;
Vector<String> prog_strings;
Vector<String> prog_debug_strings;
Vector<Scope*> prog_functions;
MemStreamWriter * prog_opcodes;
MemStreamWriter * prog_debug_info;
int prog_num_debug_infos;
int prog_max_up_count;
// int prog_stack_size;
bool isError();
void resetError();
void setError();
void setError(ErrorType value, TokenData * error_token);
void setError(TokenType expect_token_type, TokenData * error_token);
void setError(const String& str, TokenData * error_token);
void * malloc(int size OS_DBG_FILEPOS_DECL);
TokenData * setNextTokenIndex(int i);
TokenData * setNextToken(TokenData * token);
TokenData * putNextTokenType(TokenType tokenType);
TokenData * ungetToken();
bool isNextTokens(TokenType * list, int count);
bool isNextToken(TokenType t0);
bool isNextTokens(TokenType t0, TokenType t1);
bool isNextTokens(TokenType t0, TokenType t1, TokenType t2);
bool isNextTokens(TokenType t0, TokenType t1, TokenType t2, TokenType t3);
void deleteNops(ExpressionList& list);
ExpressionType getUnaryExpressionType(TokenType);
ExpressionType getExpressionType(TokenType);
OpcodeLevel getOpcodeLevel(ExpressionType exp_type);
TokenData * readToken();
TokenData * getPrevToken();
TokenData * expectToken(TokenType);
TokenData * expectToken();
struct Params
{
bool allow_root_blocks;
bool allow_var_decl;
bool allow_inline_nested_block;
bool allow_binary_operator;
bool allow_in_operator;
bool allow_assing;
// bool allow_left_side_params;
// bool allow_right_side_params;
bool allow_params;
// bool allow_var;
bool allow_auto_call;
bool allow_call;
bool allow_nop_result;
Params();
Params(const Params&);
Params& setAllowRootBlocks(bool);
Params& setAllowVarDecl(bool);
Params& setAllowInlineNestedBlock(bool);
Params& setAllowBinaryOperator(bool);
Params& setAllowInOperator(bool);
Params& setAllowAssign(bool);
Params& setAllowParams(bool);
Params& setAllowAutoCall(bool);
Params& setAllowCall(bool);
Params& setAllowNopResult(bool);
};
Expression * expectSingleExpression(Scope*, const Params& p);
Expression * expectSingleExpression(Scope*, bool allow_nop_result = false, bool allow_inline_nested_block = false);
Expression * expectExpressionValues(Expression * exp, int ret_values);
Expression * newExpressionFromList(ExpressionList& list, int ret_values);
Expression * newAssingExpression(Scope * scope, Expression * var_exp, Expression * value_exp);
Expression * newSingleValueExpression(Expression * exp);
Expression * postProcessExpression(Scope * scope, Expression * exp);
Expression * stepPass2(Scope * scope, Expression * exp);
Expression * stepPass3(Scope * scope, Expression * exp);
bool isVarNameValid(const String& name);
Scope * expectTextExpression();
Scope * expectCodeExpression(Scope*, int ret_values = 0);
Expression * expectFunctionExpression(Scope*);
Expression * expectExtendsExpression(Scope*);
Expression * expectCloneExpression(Scope*);
Expression * expectDeleteExpression(Scope*);
Expression * expectValueOfExpression(Scope*, ExpressionType exp_type);
Expression * expectVarExpression(Scope*);
Expression * expectObjectExpression(Scope*, const Params& p, bool allow_finish_exp = true);
Expression * expectArrayExpression(Scope*, const Params& p);
Expression * expectParamsExpression(Scope*);
Expression * expectReturnExpression(Scope*);
Expression * expectIfExpression(Scope*);
Expression * expectForExpression(Scope*);
Expression * expectDebugLocalsExpression(Scope*);
Expression * expectBracketExpression(Scope*, const Params& p);
Expression * finishValueExpression(Scope*, Expression*, const Params& p);
Expression * finishValueExpressionNoAutoCall(Scope*, Expression*, const Params& p);
Expression * finishValueExpressionNoNextCall(Scope*, Expression*, const Params& p);
Expression * finishBinaryOperator(Scope * scope, OpcodeLevel prev_level, Expression * exp, const Params& p, bool& is_finished); // bool allow_param, bool& is_finished);
Expression * finishQuestionOperator(Scope*, TokenData * token, Expression * left_exp, Expression * right_exp);
Expression * newBinaryExpression(Scope * scope, ExpressionType, TokenData*, Expression * left_exp, Expression * right_exp);
bool findLocalVar(LocalVarDesc&, Scope * scope, const String& name, int active_locals, bool all_scopes);
void debugPrintSourceLine(StringBuffer& out, TokenData*);
static const OS_CHAR * getExpName(ExpressionType);
int cacheString(Table * strings_table, Vector<String>& strings, const String& str);
int cacheString(const String& str);
int cacheDebugString(const String& str);
int cacheNumber(OS_NUMBER);
void writeJumpOpcode(int offs);
void fixJumpOpcode(StreamWriter * writer, int offs, int pos);
void fixJumpOpcode(StreamWriter * writer, int offs, int pos, int opcode);
bool writeOpcodes(Scope*, Expression*);
bool writeOpcodes(Scope*, ExpressionList&);
void writeDebugInfo(Expression*);
bool saveToStream(StreamWriter * writer, StreamWriter * debug_info_writer);
public:
static const int EXPRESSION_SIZE = sizeof(Expression);
Compiler(Tokenizer*);
virtual ~Compiler();
bool compile(); // compile text and push text root function
};
struct FunctionDecl
{
struct LocalVar
{
String name;
int start_code_pos;
int end_code_pos;
// Value * value;
LocalVar(const String&);
~LocalVar();
};
#ifdef OS_DEBUG
int prog_func_index;
#endif
int prog_parent_func_index;
LocalVar * locals;
int num_locals;
int num_params;
int max_up_count;
int func_depth;
int func_index; // in parent space
int num_local_funcs;
int opcodes_pos;
int opcodes_size;
// Program * prog; // retained for value of function type
FunctionDecl(); // Program*);
~FunctionDecl();
};
class Program
{
protected:
int ref_count;
virtual ~Program();
public:
enum OpcodeType
{
OP_UNKNOWN,
OP_PUSH_ONE,
OP_PUSH_NUMBER_1,
OP_PUSH_NUMBER_BY_AUTO_INDEX,
OP_PUSH_STRING_1,
OP_PUSH_STRING_BY_AUTO_INDEX,
OP_PUSH_NULL,
OP_PUSH_TRUE,
OP_PUSH_FALSE,
OP_PUSH_FUNCTION,
OP_PUSH_NEW_ARRAY,
OP_PUSH_NEW_OBJECT,
OP_OBJECT_SET_BY_AUTO_INDEX,
OP_OBJECT_SET_BY_EXP,
OP_OBJECT_SET_BY_INDEX,
OP_OBJECT_SET_BY_NAME,
OP_PUSH_ENV_VAR,
OP_PUSH_ENV_VAR_AUTO_CREATE,
OP_SET_ENV_VAR,
OP_PUSH_THIS,
OP_PUSH_ARGUMENTS,
OP_PUSH_REST_ARGUMENTS,
OP_PUSH_LOCAL_VAR_1,
OP_PUSH_LOCAL_VAR_BY_AUTO_INDEX,
OP_PUSH_LOCAL_VAR_AUTO_CREATE,
OP_SET_LOCAL_VAR,
OP_SET_LOCAL_VAR_1,
OP_SET_LOCAL_VAR_BY_BIN_OPERATOR_LOCALS,
OP_SET_LOCAL_VAR_BY_BIN_OPERATOR_LOCAL_AND_NUMBER,
OP_SET_LOCAL_VAR_1_BY_BIN_OPERATOR_LOCAL_AND_NUMBER,
OP_PUSH_UP_LOCAL_VAR,
OP_PUSH_UP_LOCAL_VAR_AUTO_CREATE,
OP_SET_UP_LOCAL_VAR,
/*
OP_LOCAL_VAR_INC,
OP_PUSH_LOCAL_VAR_PRE_INC,
OP_PUSH_LOCAL_VAR_POST_INC,
OP_LOCAL_VAR_DEC,
OP_PUSH_LOCAL_VAR_PRE_DEC,
OP_PUSH_LOCAL_VAR_POST_DEC,
*/
OP_CALL,
OP_TAIL_CALL,
OP_CALL_METHOD,
OP_TAIL_CALL_METHOD,
OP_GET_PROPERTY,
OP_GET_THIS_PROPERTY_BY_STRING,
OP_GET_PROPERTY_BY_LOCALS,
OP_GET_PROPERTY_BY_LOCAL_AND_NUMBER,
OP_GET_PROPERTY_AUTO_CREATE,
OP_SET_PROPERTY,
OP_SET_PROPERTY_BY_LOCALS_AUTO_CREATE,
OP_GET_SET_PROPERTY_BY_LOCALS_AUTO_CREATE,
OP_SET_DIM,
OP_IF_JUMP_1,
OP_IF_JUMP_2,
OP_IF_JUMP_4,
OP_IF_NOT_JUMP_1,
OP_IF_NOT_JUMP_2,
OP_IF_NOT_JUMP_4,
OP_JUMP_1,
OP_JUMP_2,
OP_JUMP_4,
OP_DEBUGGER,
OP_EXTENDS,
OP_DELETE_PROP,
OP_RETURN,
OP_RETURN_AUTO,
OP_POP,
OP_BIN_OPERATOR_BY_LOCALS,
OP_BIN_OPERATOR_BY_LOCAL_AND_NUMBER,
OP_LOGIC_AND_1,
OP_LOGIC_AND_2,
OP_LOGIC_AND_4,
OP_LOGIC_OR_1,
OP_LOGIC_OR_2,
OP_LOGIC_OR_4,
OP_COMPARE,
OP_LOGIC_PTR_EQ,
OP_LOGIC_PTR_NE,
OP_LOGIC_EQ,
OP_LOGIC_NE,
OP_LOGIC_GE,
OP_LOGIC_LE,
OP_LOGIC_GREATER,
OP_LOGIC_LESS,
OP_BIT_AND,
OP_BIT_OR,
OP_BIT_XOR,
OP_ADD, // +
OP_SUB, // -
OP_MUL, // *
OP_DIV, // /
OP_MOD, // %
OP_LSHIFT, // <<
OP_RSHIFT, // >>
OP_POW, // **
OP_CONCAT, // ..
OP_BIT_NOT,
OP_PLUS,
OP_NEG,
OP_LENGTH,
OP_LOGIC_BOOL,
OP_LOGIC_NOT,
OP_IN,
OP_ISPROTOTYPEOF, // is
OP_IS, // is
OP_SUPER,
OP_SUPER_CALL,
OP_TYPE_OF,
OP_VALUE_OF,
OP_NUMBER_OF,
OP_STRING_OF,
OP_ARRAY_OF,
OP_OBJECT_OF,
OP_USERDATA_OF,
OP_FUNCTION_OF,
OP_CLONE,
OP_NOP,
OPCODE_COUNT
};
OS * allocator;
String filename;
GCStringValue ** const_strings;
int num_strings;
OS_NUMBER * const_numbers;
int num_numbers;
FunctionDecl * functions;
int num_functions;
MemStreamReader * opcodes;
struct DebugInfoItem
{
int opcode_pos;
int line;
int pos;
String token;
DebugInfoItem(int opcode_pos, int line, int pos, const String&);
};
Vector<DebugInfoItem> debug_info;
// int gc_time;
Program(OS * allocator);
Program * retain();
void release();
static OpcodeType getOpcodeType(Compiler::ExpressionType);
bool loadFromStream(StreamReader * reader, StreamReader * debuginfo_reader);
DebugInfoItem * getDebugInfo(int opcode_pos);
void pushStartFunction();
};
enum {
ENV_VAR_INDEX,
#ifdef OS_GLOBAL_VAR_ENABLED
GLOBALS_VAR_INDEX,
#endif
};
struct Upvalues
{
int ref_count;
int gc_time;
Program * prog; // retained
FunctionDecl * func_decl;
Value * locals;
int num_locals;
bool is_stack_locals;
int num_parents;
// Upvalues * parent;
// Upvalues();
// ~Upvalues();
Upvalues ** getParents();
Upvalues * getParent(int i);
void setParent(int i, Upvalues*);
Upvalues * retain();
};
struct StackFunction
{
GCFunctionValue * func;
Value self; // allow primitive type for self
GCValue * self_for_proto;
Upvalues * locals;
int num_params;
int num_extra_params;
GCValue * arguments;
GCValue * rest_arguments;
int caller_stack_pos;
int locals_stack_pos;
int stack_pos;
int need_ret_values;
// int opcode_offs;
// cached values
MemStreamReader opcodes;
// StackFunction();
// ~StackFunction();
};
struct StringRef
{
int string_hash;
int string_value_id;
StringRef * hash_next;
};
struct StringRefs
{
StringRef ** heads;
int head_mask;
int count;
StringRefs();
~StringRefs();
};
struct UserptrRef
{
int userptr_hash;
int userptr_value_id;
UserptrRef * hash_next;
};
struct UserptrRefs
{
UserptrRef ** heads;
int head_mask;
int count;
UserptrRefs();
~UserptrRefs();
};
struct Values
{
GCValue ** heads;
int head_mask;
int count;
int next_id;
Values();
~Values();
// Value * add(Value * obj);
// Value * remove(int value_id);
GCValue * get(int value_id);
};
OS * allocator;
struct Strings
{
String __construct;
// String __destruct;
String __object;
String __get;
String __set;
String __getAt;
String __setAt;
String __del;
String __delAt;
String __getempty;
String __setempty;
String __delempty;
String __getdim;
String __setdim;
String __deldim;
String __cmp;
String __iter;
// String __tostring;
String __valueof;
/*
String __booleanof;
String __numberof;
String __stringof;
String __arrayof;
String __objectof;
String __userdataof;
String __functionof;
*/
String __clone;
// String __tobool;
String __concat;
String __bitand;
String __bitor;
String __bitxor;
String __bitnot;
String __plus;
String __neg;
String __len;
String __add;
String __sub;
String __mul;
String __div;
String __mod;
String __lshift;
String __rshift;
String __pow;
String typeof_null;
String typeof_boolean;
String typeof_number;
String typeof_string;
String typeof_object;
String typeof_array;
String typeof_userdata;
String typeof_function;
String syntax_get;
String syntax_set;
String syntax_super;
String syntax_is;
String syntax_isprototypeof;
String syntax_typeof;
String syntax_valueof;
String syntax_booleanof;
String syntax_numberof;
String syntax_stringof;
String syntax_arrayof;
String syntax_objectof;
String syntax_userdataof;
String syntax_functionof;
String syntax_extends;
String syntax_clone;
String syntax_delete;
String syntax_prototype;
String syntax_var;
String syntax_this;
String syntax_arguments;
String syntax_function;
String syntax_null;
String syntax_true;
String syntax_false;
String syntax_return;
String syntax_class;
String syntax_enum;
String syntax_switch;
String syntax_case;
String syntax_default;
String syntax_if;
String syntax_else;
String syntax_elseif;
String syntax_for;
String syntax_in;
String syntax_break;
String syntax_continue;
String syntax_debugger;
String syntax_debuglocals;
#ifdef OS_GLOBAL_VAR_ENABLED
String var_globals;
#endif
String var_env;
int __dummy__;
Strings(OS * allocator);
} * strings;
Values values;
int num_created_values;
int num_destroyed_values;
StringRefs string_refs;
UserptrRefs userptr_refs;
// Table * string_values_table;
GCObjectValue * check_recursion;
Value global_vars;
Value user_pool;
Value error_handlers[OS_ERROR_LEVELS];
enum {
PROTOTYPE_BOOL,
PROTOTYPE_NUMBER,
PROTOTYPE_STRING,
PROTOTYPE_OBJECT,
PROTOTYPE_ARRAY,
PROTOTYPE_FUNCTION,
PROTOTYPE_USERDATA,
// -----------------
PROTOTYPE_COUNT
};
GCObjectValue * prototypes[PROTOTYPE_COUNT];
// Vector<Value> stack_values;
struct StackValues {
Value * buf;
int capacity;
int count;
StackValues();
~StackValues();
Value& operator[](int i)
{
OS_ASSERT(i >= 0 && i < count);
return buf[i];
}
Value& lastElement()
{
OS_ASSERT(count > 0);
return buf[count-1];
}
} stack_values;
void reserveStackValues(int new_capacity);
Vector<StackFunction> call_stack_funcs;
StackFunction * stack_func;
Value * stack_func_locals;
int num_stack_func_locals;
int stack_func_env_index;
OS_NUMBER * stack_func_prog_numbers;
GCStringValue ** stack_func_prog_strings;
GCValue * gc_grey_list_first;
bool gc_grey_root_initialized;
int gc_values_head_index;
int gc_start_allocated_bytes;
int gc_max_allocated_bytes;
int gc_keep_heap_count;
int gc_continuous_count;
bool gc_continuous;
int gc_time;
bool gc_in_process;
int gc_grey_added_count;
float gc_start_values_mult;
float gc_step_size_mult;
float gc_step_size_auto_mult;
int gc_start_next_values;
int gc_step_size;
struct {
bool create_debug_opcodes;
bool create_debug_info;
bool create_compiled_file;
bool primary_compiled_file;
} settings;
enum {
RAND_STATE_SIZE = 624
};
OS_U32 rand_state[RAND_STATE_SIZE+1];
OS_U32 rand_seed;
OS_U32 * rand_next;
int rand_left;
bool terminated;
int terminated_code;
void randInitialize(OS_U32 seed);
void randReload();
double getRand();
double getRand(double up);
double getRand(double min, double max);
void * malloc(int size OS_DBG_FILEPOS_DECL);
void free(void * p);
void error(int code, const OS_CHAR * message);
void error(int code, const String& message);
void errorDivisionByZero();
void gcInitGreyList();
void gcResetGreyList();
void gcAddToGreyList(GCValue*);
void gcAddToGreyList(Value);
void gcRemoveFromGreyList(GCValue*);
void gcMarkProgram(Program * prog);
void gcMarkTable(Table * table);
void gcMarkUpvalues(Upvalues*);
void gcMarkStackFunction(StackFunction*);
void gcMarkList(int step_size);
void gcMarkValue(GCValue * value);
// return next gc phase
int gcStep();
void gcStepIfNeeded();
void gcFinishSweepPhase();
void gcFinishMarkPhase();
void gcFull();
// void clearValue(Value&);
void clearValue(GCValue*);
void deleteValue(GCValue*);
#ifdef OS_DEBUG
bool isValueUsed(GCValue*);
#endif
GCFunctionValue * newFunctionValue(StackFunction*, Program*, FunctionDecl*, Value env);
void clearFunctionValue(GCFunctionValue*);
// Upvalues * newUpvalues(int num_parents);
void releaseUpvalues(Upvalues*);
void deleteUpvalues(Upvalues*);
void clearStackFunction(StackFunction*);
// GCValue * newValue();
// Value newBoolValue(bool);
// Value newNumberValue(OS_FLOAT);
GCStringValue * newStringValue(const String&);
GCStringValue * newStringValue(const String&, const String&);
GCStringValue * newStringValue(const String&, bool trim_left, bool trim_right);
GCStringValue * newStringValue(const OS_CHAR*);
GCStringValue * newStringValue(const OS_CHAR*, int len);
GCStringValue * newStringValue(const OS_CHAR*, int len, const OS_CHAR*, int len2);
GCStringValue * newStringValue(const OS_CHAR*, int len, bool trim_left, bool trim_right);
GCStringValue * newStringValue(const void * buf, int size);
GCStringValue * newStringValue(const void * buf1, int size1, const void * buf2, int size2);
GCStringValue * newStringValue(const void * buf1, int size1, const void * buf2, int size2, const void * buf3, int size3);
GCStringValue * newStringValue(GCStringValue*, GCStringValue*);
GCStringValue * newStringValue(OS_INT);
GCStringValue * newStringValue(OS_FLOAT, int);
GCStringValue * newStringValue(int temp_buf_len, const OS_CHAR * fmt, ...);
GCStringValue * newStringValueVa(int temp_buf_len, const OS_CHAR * fmt, va_list va);
GCCFunctionValue * newCFunctionValue(OS_CFunction func, void * user_param);
GCCFunctionValue * newCFunctionValue(OS_CFunction func, int closure_values, void * user_param);
GCUserdataValue * newUserdataValue(int crc, int data_size, OS_UserdataDtor dtor, void * user_param);
GCUserdataValue * newUserPointerValue(int crc, void * data, OS_UserdataDtor dtor, void * user_param);
GCObjectValue * newObjectValue();
GCObjectValue * newObjectValue(GCValue * prototype);
GCArrayValue * newArrayValue(int initial_capacity = 0);
GCObjectValue * initObjectInstance(GCObjectValue*);
template<class T> T * pushValue(T * val){ pushValue(Value(val)); return val; }
void pushValue(const Value& val);
void pushStackValue(int offs);
void copyValue(int raw_from, int raw_to);
void insertValue(Value val, int offs);
void pushNull();
// void pushTrue();
// void pushFalse();
void pushBool(bool);
void pushNumber(OS_INT32);
void pushNumber(OS_INT64);
void pushNumber(float);
void pushNumber(double);
GCStringValue * pushStringValue(const String&);
GCStringValue * pushStringValue(const OS_CHAR*);
GCStringValue * pushStringValue(const OS_CHAR*, int len);
GCCFunctionValue * pushCFunctionValue(OS_CFunction func, void * user_param);
GCCFunctionValue * pushCFunctionValue(OS_CFunction func, int closure_values, void * user_param);
GCUserdataValue * pushUserdataValue(int crc, int data_size, OS_UserdataDtor dtor, void * user_param);
GCUserdataValue * pushUserPointerValue(int crc, void * data, OS_UserdataDtor dtor, void * user_param);
GCObjectValue * pushObjectValue();
GCObjectValue * pushObjectValue(GCValue * prototype);
GCArrayValue * pushArrayValue(int initial_capacity = 0);
void pushTypeOf(Value val);
bool pushNumberOf(Value val);
bool pushStringOf(Value val);
bool pushValueOf(Value val);
GCArrayValue * pushArrayOf(Value val);
GCObjectValue * pushObjectOf(Value val);
GCUserdataValue * pushUserdataOf(Value val);
bool pushFunctionOf(Value val);
void pushCloneValue(Value val);
// unary operator
void pushOpResultValue(int opcode, Value value);
// binary operator
void pushOpResultValue(int opcode, Value left_value, Value right_value);
void setGlobalValue(const String& name, Value value, bool anonymous_setter_enabled, bool named_setter_enabled);
void setGlobalValue(const OS_CHAR * name, Value value, bool anonymous_setter_enabled, bool named_setter_enabled);
int getStackOffs(int offs);
Value getStackValue(int offs);
void removeStackValues(int offs, int count);
void removeStackValue(int offs = -1);
void removeAllStackValues();
void pop(int count = 1);
void moveStackValues(int offs, int count, int new_offs);
void moveStackValue(int offs, int new_offs);
int syncRetValues(int need_ret_values, int cur_ret_values);
void registerStringRef(StringRef*);
void unregisterStringRef(StringRef*);
void deleteStringRefs();
void registerUserptrRef(UserptrRef*);
void unregisterUserptrRef(UserptrRef*);
void unregisterUserptrRef(void*, int);
void deleteUserptrRefs();
void registerValue(GCValue * val);
GCValue * unregisterValue(int value_id);
void deleteValues(bool del_ref_counted_also);
static int compareGCValues(const void * a, const void * b);
bool valueToBool(const Value& val);
OS_INT valueToInt(const Value& val, bool valueof_enabled = false);
OS_NUMBER valueToNumber(const Value& val, bool valueof_enabled = false);
String valueToString(Value val, bool valueof_enabled = false);
bool isValueNumber(Value val, OS_NUMBER * out = NULL);
bool isValueString(Value val, String * out = NULL);
bool isValueString(Value val, OS::String * out = NULL);
bool isValueInstanceOf(GCValue * val, GCValue * prototype_val);
bool isValueInstanceOf(Value val, Value prototype_val);
bool isValuePrototypeOf(GCValue * val, GCValue * prototype_val);
bool isValuePrototypeOf(Value val, Value prototype_val);
Table * newTable(OS_DBG_FILEPOS_START_DECL);
void clearTable(Table*);
void deleteTable(Table*);
void addTableProperty(Table * table, Property * prop);
Property * removeTableProperty(Table * table, const PropertyIndex& index);
void changePropertyIndex(Table * table, Property * prop, const PropertyIndex& new_index);
bool deleteTableProperty(Table * table, const PropertyIndex& index);
void deleteValueProperty(GCValue * table_value, const PropertyIndex& index, bool anonymous_del_enabled, bool named_del_enabled, bool prototype_enabled);
void deleteValueProperty(Value table_value, const PropertyIndex& index, bool anonymous_del_enabled, bool named_del_enabled, bool prototype_enabled);
void copyTableProperties(Table * dst, Table * src);
void copyTableProperties(GCValue * dst_value, GCValue * src_value, bool anonymous_setter_enabled, bool named_setter_enabled);
void sortTable(Table * table, int(*comp)(OS*, const void*, const void*, void*), void* = NULL, bool reorder_keys = false);
void sortArray(GCArrayValue * arr, int(*comp)(OS*, const void*, const void*, void*), void* = NULL);
static int comparePropValues(OS*, const void*, const void*, void*);
static int comparePropValuesReverse(OS*, const void*, const void*, void*);
static int compareObjectProperties(OS*, const void*, const void*, void*);
static int compareObjectPropertiesReverse(OS*, const void*, const void*, void*);
static int compareUserPropValues(OS*, const void*, const void*, void*);
static int compareUserPropValuesReverse(OS*, const void*, const void*, void*);
static int comparePropKeys(OS*, const void*, const void*, void*);
static int comparePropKeysReverse(OS*, const void*, const void*, void*);
static int compareUserPropKeys(OS*, const void*, const void*, void*);
static int compareUserPropKeysReverse(OS*, const void*, const void*, void*);
static int compareArrayValues(OS*, const void*, const void*, void*);
static int compareArrayValuesReverse(OS*, const void*, const void*, void*);
static int compareUserArrayValues(OS*, const void*, const void*, void*);
static int compareUserArrayValuesReverse(OS*, const void*, const void*, void*);
static int compareUserReverse(OS*, const void*, const void*, void*);
bool hasSpecialPrefix(const Value&);
Property * setTableValue(Table * table, const PropertyIndex& index, Value val);
void setPropertyValue(GCValue * table_value, const PropertyIndex& index, Value val, bool anonymous_setter_enabled, bool named_setter_enabled);
void setPropertyValue(Value table_value, const PropertyIndex& index, Value val, bool anonymous_setter_enabled, bool named_setter_enabled);
bool getPropertyValue(Value& result, Table * table, const PropertyIndex& index);
bool getPropertyValue(Value& result, GCValue * table_value, const PropertyIndex& index, bool prototype_enabled);
bool getPropertyValue(Value& result, Value table_value, const PropertyIndex& index, bool prototype_enabled);
bool hasProperty(GCValue * table_value, const PropertyIndex& index, bool anonymous_getter_enabled, bool named_getter_enabled, bool prototype_enabled);
void pushPropertyValue(GCValue * table_value, const PropertyIndex& index, bool anonymous_getter_enabled, bool named_getter_enabled, bool prototype_enabled, bool auto_create);
void pushPropertyValueForPrimitive(Value self, const PropertyIndex& index, bool anonymous_getter_enabled, bool named_getter_enabled, bool prototype_enabled, bool auto_create);
void pushPropertyValue(Value table_value, const PropertyIndex& index, bool anonymous_getter_enabled, bool named_getter_enabled, bool prototype_enabled, bool auto_create);
void setPrototype(Value val, Value proto, int userdata_crc);
void pushPrototype(Value val);
void pushBackTrace(int skip_funcs, int max_trace_funcs);
void pushArguments(StackFunction*);
void pushArgumentsWithNames(StackFunction*);
void pushRestArguments(StackFunction*);
void enterFunction(GCFunctionValue * func_value, Value self, GCValue * self_for_proto, int params, int extra_remove_from_stack, int need_ret_values);
int execute();
void reloadStackFunctionCache();
int opBreakFunction();
void opDebugger();
// void opPushNumber();
void opPushString();
void opPushFunction();
void opPushArray();
void opPushObject();
void opObjectSetByAutoIndex();
void opObjectSetByExp();
void opObjectSetByIndex();
void opObjectSetByName();
void opPushEnvVar(bool auto_create);
void opSetEnvVar();
void opPushThis();
void opPushArguments();
void opPushRestArguments();
void opPushLocalVar();
void opPushLocalVarAutoCreate();
void opSetLocalVar();
void opPushUpvalue();
void opPushUpvalueAutoCreate();
void opSetUpvalue();
void opIfJump1(bool boolean);
void opIfJump2(bool boolean);
void opIfJump4(bool boolean);
void opJump4();
void opCall();
void opSuperCall(int& ret_values);
void opTailCall(int& ret_values);
void opCallMethod();
void opTailCallMethod(int& ret_values);
int opReturn();
int opReturnAuto();
void opGetProperty(bool auto_create);
void opGetThisPropertyByString();
void opGetPropertyByLocals(bool auto_create);
void opGetPropertyByLocalAndNumber(bool auto_create);
void opSetProperty();
void opSetPropertyByLocals(bool auto_create);
void opGetSetPropertyByLocals(bool auto_create);
void opSetDim();
void opExtends();
void opClone();
void opDeleteProperty();
void opLogicAndOr1(bool is_and);
void opLogicAndOr2(bool is_and);
void opLogicAndOr4(bool is_and);
void opLogicOr();
void opSuper();
void opTypeOf();
void opValueOf();
void opNumberOf();
void opStringOf();
void opArrayOf();
void opObjectOf();
void opUserdataOf();
void opFunctionOf();
void opBooleanOf(bool b);
void opIn();
void opIsPrototypeOf();
void opIs();
void opLength();
void opUnaryOperator(int opcode);
// void opBinaryOperator(int opcode);
void opBinaryOperatorByLocals();
void opBinaryOperatorByLocalAndNumber();
int call(int params, int ret_values, GCValue * self_for_proto = NULL, bool allow_only_enter_func = false);
Core(OS*);
~Core();
bool init();
void shutdown();
};
MemoryManager * memory_manager;
Core * core;
int ref_count;
#ifdef OS_DEBUG
int native_stack_start_mark;
int native_stack_max_usage;
void checkNativeStackUsage(const OS_CHAR * func_name);
#endif
virtual ~OS();
// bool init(ObjectScriptExtention * ext, MemoryManager * manager);
virtual void shutdown();
void qsort(void *base, unsigned num, unsigned width, int (*comp)(OS*, const void *, const void *, void*), void*);
void initGlobalFunctions();
void initObjectClass();
void initArrayClass();
void initFunctionClass();
void initStringClass();
void initMathModule();
void initGCModule();
void initLangTokenizerModule();
void initPreScript();
void initPostScript();
public:
class String: public Core::String // this string retains OS
{
typedef Core::String super;
protected:
OS * allocator;
public:
String(OS*);
String(const String&);
String(OS*, const Core::String&);
String(OS*, const OS_CHAR*);
String(OS*, const OS_CHAR*, int len);
String(OS*, const OS_CHAR*, int len, const OS_CHAR*, int len2);
String(OS*, const OS_CHAR*, int len, bool trim_left, bool trim_right);
String(OS*, const void*, int size);
String(OS*, const void * buf1, int len1, const void * buf2, int len2);
// String(OS*, const void * buf1, int len1, const void * buf2, int len2, const void * buf3, int len3);
String(OS*, OS_INT value);
String(OS*, OS_FLOAT value, int precision = OS_AUTO_PRECISION);
~String();
String& operator=(const Core::String&);
String& operator=(const String&);
String& operator+=(const String&);
String& operator+=(const OS_CHAR*);
String operator+(const String&) const;
String operator+(const OS_CHAR*) const;
String trim(bool trim_left = true, bool trim_right = true) const;
};
static OS * create(MemoryManager* = NULL);
template <class T>
static T * create(T * os, MemoryManager * manager = NULL)
{
OS_ASSERT(dynamic_cast<OS*>(os));
return (T*)os->start(manager);
}
OS();
virtual OS * start(MemoryManager* = NULL);
virtual bool init(MemoryManager* = NULL);
OS * retain();
void release();
void * malloc(int size OS_DBG_FILEPOS_DECL);
void free(void * p);
int getAllocatedBytes();
int getMaxAllocatedBytes();
int getCachedBytes();
void setMemBreakpointId(int id);
bool isTerminated();
int getTerminatedCode();
void setTerminated(bool = true, int = 0);
void resetTerminated();
void getProperty(bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void getProperty(const OS_CHAR*, bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void getProperty(const Core::String&, bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void getProperty(int offs, const OS_CHAR*, bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void getProperty(int offs, const Core::String&, bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void setProperty(bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setProperty(const OS_CHAR*, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setProperty(const Core::String&, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setProperty(int offs, const OS_CHAR*, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setProperty(int offs, const Core::String&, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void addProperty();
void deleteProperty(bool anonymous_del_enabled = true, bool named_del_enabled = true);
void deleteProperty(const OS_CHAR*, bool anonymous_del_enabled = true, bool named_del_enabled = true);
void deleteProperty(const Core::String&, bool anonymous_del_enabled = true, bool named_del_enabled = true);
void getGlobal(const OS_CHAR*, bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void getGlobal(const Core::String&, bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void setGlobal(const OS_CHAR*, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setGlobal(const Core::String&, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
struct FuncDef;
void setGlobal(const FuncDef& func, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void getPrototype();
void setPrototype();
void setPrototype(int userdata_crc);
int getValueId(int offs = -1);
void pushNull();
void pushNumber(OS_INT32);
void pushNumber(OS_INT64);
void pushNumber(float);
void pushNumber(double);
void pushBool(bool);
void pushString(const OS_CHAR*);
void pushString(const OS_CHAR*, int len);
void pushString(const Core::String&);
void pushCFunction(OS_CFunction func, void * user_param = NULL);
void pushCFunction(OS_CFunction func, int closure_values, void * user_param = NULL);
void * pushUserdata(int crc, int data_size, OS_UserdataDtor dtor = NULL, void * user_param = NULL);
void * pushUserdata(int data_size, OS_UserdataDtor dtor = NULL, void * user_param = NULL);
void * pushUserPointer(int crc, void * data, OS_UserdataDtor dtor = NULL, void * user_param = NULL);
void * pushUserPointer(void * data, OS_UserdataDtor dtor = NULL, void * user_param = NULL);
void newObject();
void newArray(int initial_capacity = 0);
void pushStackValue(int offs = -1);
void pushGlobals();
void pushUserPool();
void pushValueById(int id);
void retainValueById(int id);
void releaseValueById(int id);
void clone(int offs = -1);
// int pushArrayNumbers(int offs = -1);
int getStackSize();
int getAbsoluteOffs(int offs);
void remove(int start_offs = -1, int count = 1);
void removeAll();
void pop(int count = 1);
void move(int start_offs, int count, int new_offs);
void move(int offs, int new_offs);
void runOp(OS_EOpcode opcode);
// returns length of object, array, string or result of __len method
// keep stack not changed
int getLen(int offs = -1);
OS_EValueType getType(int offs = -1);
OS_EValueType getTypeById(int id);
bool isNumber(int offs = -1, OS_NUMBER * out = NULL);
bool isString(int offs = -1, String * out = NULL);
bool isType(OS_EValueType, int offs = -1);
bool isNull(int offs = -1);
bool isObject(int offs = -1);
bool isArray(int offs = -1);
bool isFunction(int offs = -1);
bool isUserdata(int crc, int offs);
bool isPrototypeOf(int value_offs = -2, int prototype_offs = -1);
bool is(int value_offs = -2, int prototype_offs = -1);
bool toBool(int offs = -1);
OS_NUMBER toNumber(int offs = -1, bool valueof_enabled = true);
float toFloat(int offs = -1, bool valueof_enabled = true);
double toDouble(int offs = -1, bool valueof_enabled = true);
int toInt(int offs = -1, bool valueof_enabled = true);
String toString(int offs = -1, bool valueof_enabled = true);
void * toUserdata(int crc, int offs = -1);
void clearUserdata(int crc, int offs = -1);
bool toBool(int offs, bool def);
OS_NUMBER toNumber(int offs, OS_NUMBER def, bool valueof_enabled = true);
float toFloat(int offs, float def, bool valueof_enabled = true);
double toDouble(int offs, double def, bool valueof_enabled = true);
int toInt(int offs, int def, bool valueof_enabled = true);
String toString(int offs, const String& def, bool valueof_enabled = true);
bool popBool();
OS_NUMBER popNumber(bool valueof_enabled = true);
float popFloat(bool valueof_enabled = true);
double popDouble(bool valueof_enabled = true);
int popInt(bool valueof_enabled = true);
String popString(bool valueof_enabled = true);
bool popBool(bool def);
OS_NUMBER popNumber(OS_NUMBER def, bool valueof_enabled = true);
float popFloat(float def, bool valueof_enabled = true);
double popDouble(double def, bool valueof_enabled = true);
int popInt(int def, bool valueof_enabled = true);
String popString(const String& def, bool valueof_enabled = true);
int getSetting(OS_ESettings);
int setSetting(OS_ESettings, int);
bool compileFile(const String& filename, bool required = false);
bool compile(const String& str);
bool compile();
int call(int params = 0, int ret_values = 0);
int eval(const OS_CHAR * str, int params = 0, int ret_values = 0);
int eval(const String& str, int params = 0, int ret_values = 0);
int require(const OS_CHAR * filename, bool required = false, int ret_values = 0);
int require(const String& filename, bool required = false, int ret_values = 0);
void getErrorHandler(int code);
void setErrorHandler(int code = OS_E_ALL);
// return next gc phase
int gc();
void gcFull();
struct FuncDef {
const OS_CHAR * name;
OS_CFunction func;
void * user_param;
};
struct NumberDef {
const OS_CHAR * name;
OS_NUMBER value;
};
struct StringDef {
const OS_CHAR * name;
const OS_CHAR * value;
};
struct NullDef {
const OS_CHAR * name;
};
void setFuncs(const FuncDef * list, bool anonymous_setter_enabled = true, bool named_setter_enabled = true, int closure_values = 0, void * user_param = NULL); // null terminated list
void setFunc(const FuncDef& def, bool anonymous_setter_enabled = true, bool named_setter_enabled = true, int closure_values = 0, void * user_param = NULL); // null terminated list
void setNumbers(const NumberDef * list, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setNumber(const NumberDef& def, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setStrings(const StringDef * list, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setString(const StringDef& def, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setNulls(const NullDef * list, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void setNull(const NullDef& def, bool anonymous_setter_enabled = true, bool named_setter_enabled = true);
void getObject(const OS_CHAR * name, bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void getGlobalObject(const OS_CHAR * name, bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void getModule(const OS_CHAR * name, bool anonymous_getter_enabled = true, bool named_getter_enabled = true, bool prototype_enabled = true);
void triggerError(int code, const OS_CHAR * message);
void triggerError(int code, const String& message);
void triggerError(const OS_CHAR * message);
void triggerError(const String& message);
String changeFilenameExt(const String& filename, const String& ext);
String changeFilenameExt(const String& filename, const OS_CHAR * ext);
String getFilenameExt(const String& filename);
String getFilenameExt(const OS_CHAR * filename);
String getFilenameExt(const OS_CHAR * filename, int len);
String getFilename(const String& filename);
String getFilename(const OS_CHAR * filename);
String getFilename(const OS_CHAR * filename, int len);
String getFilenamePath(const String& filename);
String getFilenamePath(const OS_CHAR * filename);
String getFilenamePath(const OS_CHAR * filename, int len);
bool isAbsolutePath(const String& filename);
String resolvePath(const String& filename);
virtual String resolvePath(const String& filename, const String& cur_path);
virtual String getCompiledFilename(const String& resolved_filename);
virtual String getDebugInfoFilename(const String& resolved_filename);
virtual String getDebugOpcodesFilename(const String& resolved_filename);
enum EFileUseType
{
COMPILE_SOURCECODE_FILE,
LOAD_COMPILED_FILE
};
virtual EFileUseType checkFileUsage(const String& sourcecode_filename, const String& compiled_filename);
virtual bool isFileExist(const OS_CHAR * filename);
virtual void * openFile(const OS_CHAR * filename, const OS_CHAR * mode);
virtual int readFile(void * buf, int size, void * f);
virtual int writeFile(const void * buf, int size, void * f);
virtual int seekFile(void * f, int offset, int whence);
virtual void closeFile(void * f);
virtual void printf(const OS_CHAR * fmt, ...);
virtual void onEnterGC();
virtual void onExitGC();
};
} // namespace ObjectScript
#endif // __OBJECT_SCRIPT_H__