|
|
@ -92,9 +92,10 @@
|
|
|
|
Rudimentary call stack on error
|
|
|
|
Rudimentary call stack on error
|
|
|
|
Added String Character functions
|
|
|
|
Added String Character functions
|
|
|
|
Added shift operators
|
|
|
|
Added shift operators
|
|
|
|
|
|
|
|
Version 0.29 : Added new object via functions
|
|
|
|
|
|
|
|
Fixed getString() for double on some platforms
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NOTE:
|
|
|
|
NOTE: This doesn't support constructors for objects
|
|
|
|
|
|
|
|
Constructing an array with an initial length 'Array(5)' doesn't work
|
|
|
|
Constructing an array with an initial length 'Array(5)' doesn't work
|
|
|
|
Recursive loops of data such as a.foo = a; fail to be garbage collected
|
|
|
|
Recursive loops of data such as a.foo = a; fail to be garbage collected
|
|
|
|
length variable cannot be set
|
|
|
|
length variable cannot be set
|
|
|
@ -951,7 +952,7 @@ const string &CScriptVar::getString() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isDouble()) {
|
|
|
|
if (isDouble()) {
|
|
|
|
char buffer[32];
|
|
|
|
char buffer[32];
|
|
|
|
sprintf_s(buffer, sizeof(buffer), "%lf", doubleData);
|
|
|
|
sprintf_s(buffer, sizeof(buffer), "%f", doubleData);
|
|
|
|
data = buffer;
|
|
|
|
data = buffer;
|
|
|
|
return data;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1429,47 +1430,15 @@ CScriptVarLink *CTinyJS::parseFunctionDefinition() {
|
|
|
|
return funcVar;
|
|
|
|
return funcVar;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CScriptVarLink *CTinyJS::factor(bool &execute) {
|
|
|
|
/** Handle a function call (assumes we've parsed the function name and we're
|
|
|
|
if (l->tk=='(') {
|
|
|
|
* on the start bracket). 'parent' is the object that contains this method,
|
|
|
|
l->match('(');
|
|
|
|
* if there was one (otherwise it's just a normnal function).
|
|
|
|
CScriptVarLink *a = base(execute);
|
|
|
|
*/
|
|
|
|
l->match(')');
|
|
|
|
CScriptVarLink *CTinyJS::functionCall(bool &execute, CScriptVarLink *function, CScriptVar *parent) {
|
|
|
|
return a;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_R_TRUE) {
|
|
|
|
|
|
|
|
l->match(LEX_R_TRUE);
|
|
|
|
|
|
|
|
return new CScriptVarLink(new CScriptVar(1));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_R_FALSE) {
|
|
|
|
|
|
|
|
l->match(LEX_R_FALSE);
|
|
|
|
|
|
|
|
return new CScriptVarLink(new CScriptVar(0));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_R_NULL) {
|
|
|
|
|
|
|
|
l->match(LEX_R_NULL);
|
|
|
|
|
|
|
|
return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_NULL));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_R_UNDEFINED) {
|
|
|
|
|
|
|
|
l->match(LEX_R_UNDEFINED);
|
|
|
|
|
|
|
|
return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_UNDEFINED));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_ID) {
|
|
|
|
|
|
|
|
CScriptVarLink *a = execute ? findInScopes(l->tkStr) : new CScriptVarLink(new CScriptVar());
|
|
|
|
|
|
|
|
//printf("0x%08X for %s at %s\n", (unsigned int)a, l->tkStr.c_str(), l->getPosition().c_str());
|
|
|
|
|
|
|
|
/* The parent if we're executing a method call */
|
|
|
|
|
|
|
|
CScriptVar *parent = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (execute && !a) {
|
|
|
|
|
|
|
|
/* Variable doesn't exist! JavaScript says we should create it
|
|
|
|
|
|
|
|
* (we won't add it here. This is done in the assignment operator)*/
|
|
|
|
|
|
|
|
a = new CScriptVarLink(new CScriptVar(), l->tkStr);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
l->match(LEX_ID);
|
|
|
|
|
|
|
|
while (l->tk=='(' || l->tk=='.' || l->tk=='[') {
|
|
|
|
|
|
|
|
if (l->tk=='(') { // ------------------------------------- Function Call
|
|
|
|
|
|
|
|
if (execute) {
|
|
|
|
if (execute) {
|
|
|
|
if (!a->var->isFunction()) {
|
|
|
|
if (!function->var->isFunction()) {
|
|
|
|
string errorMsg = "Expecting '";
|
|
|
|
string errorMsg = "Expecting '";
|
|
|
|
errorMsg = errorMsg + a->name + "' to be a function";
|
|
|
|
errorMsg = errorMsg + function->name + "' to be a function";
|
|
|
|
throw new CScriptException(errorMsg.c_str());
|
|
|
|
throw new CScriptException(errorMsg.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
l->match('(');
|
|
|
|
l->match('(');
|
|
|
@ -1478,7 +1447,7 @@ CScriptVarLink *CTinyJS::factor(bool &execute) {
|
|
|
|
if (parent)
|
|
|
|
if (parent)
|
|
|
|
functionRoot->addChildNoDup("this", parent);
|
|
|
|
functionRoot->addChildNoDup("this", parent);
|
|
|
|
// grab in all parameters
|
|
|
|
// grab in all parameters
|
|
|
|
CScriptVarLink *v = a->var->firstChild;
|
|
|
|
CScriptVarLink *v = function->var->firstChild;
|
|
|
|
while (v) {
|
|
|
|
while (v) {
|
|
|
|
CScriptVarLink *value = base(execute);
|
|
|
|
CScriptVarLink *value = base(execute);
|
|
|
|
if (execute) {
|
|
|
|
if (execute) {
|
|
|
@ -1502,19 +1471,19 @@ CScriptVarLink *CTinyJS::factor(bool &execute) {
|
|
|
|
CScriptVarLink *returnVarLink = functionRoot->addChild(TINYJS_RETURN_VAR);
|
|
|
|
CScriptVarLink *returnVarLink = functionRoot->addChild(TINYJS_RETURN_VAR);
|
|
|
|
scopes.push_back(functionRoot);
|
|
|
|
scopes.push_back(functionRoot);
|
|
|
|
#ifdef TINYJS_CALL_STACK
|
|
|
|
#ifdef TINYJS_CALL_STACK
|
|
|
|
call_stack.push_back(a->name + " from " + l->getPosition());
|
|
|
|
call_stack.push_back(function->name + " from " + l->getPosition());
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
if (a->var->isNative()) {
|
|
|
|
if (function->var->isNative()) {
|
|
|
|
ASSERT(a->var->jsCallback);
|
|
|
|
ASSERT(function->var->jsCallback);
|
|
|
|
a->var->jsCallback(functionRoot, a->var->jsCallbackUserData);
|
|
|
|
function->var->jsCallback(functionRoot, function->var->jsCallbackUserData);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
/* we just want to execute the block, but something could
|
|
|
|
/* we just want to execute the block, but something could
|
|
|
|
* have messed up and left us with the wrong ScriptLex, so
|
|
|
|
* have messed up and left us with the wrong ScriptLex, so
|
|
|
|
* we want to be careful here... */
|
|
|
|
* we want to be careful here... */
|
|
|
|
CScriptException *exception = 0;
|
|
|
|
CScriptException *exception = 0;
|
|
|
|
CScriptLex *oldLex = l;
|
|
|
|
CScriptLex *oldLex = l;
|
|
|
|
CScriptLex *newLex = new CScriptLex(a->var->getString());
|
|
|
|
CScriptLex *newLex = new CScriptLex(function->var->getString());
|
|
|
|
l = newLex;
|
|
|
|
l = newLex;
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
block(execute);
|
|
|
|
block(execute);
|
|
|
@ -1538,9 +1507,9 @@ CScriptVarLink *CTinyJS::factor(bool &execute) {
|
|
|
|
functionRoot->removeLink(returnVarLink);
|
|
|
|
functionRoot->removeLink(returnVarLink);
|
|
|
|
delete functionRoot;
|
|
|
|
delete functionRoot;
|
|
|
|
if (returnVar)
|
|
|
|
if (returnVar)
|
|
|
|
a = returnVar;
|
|
|
|
return returnVar;
|
|
|
|
else
|
|
|
|
else
|
|
|
|
a = new CScriptVarLink(new CScriptVar());
|
|
|
|
return new CScriptVarLink(new CScriptVar());
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// function, but not executing - just parse args and be done
|
|
|
|
// function, but not executing - just parse args and be done
|
|
|
|
l->match('(');
|
|
|
|
l->match('(');
|
|
|
@ -1553,7 +1522,50 @@ CScriptVarLink *CTinyJS::factor(bool &execute) {
|
|
|
|
if (l->tk == '{') {
|
|
|
|
if (l->tk == '{') {
|
|
|
|
block(execute);
|
|
|
|
block(execute);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* function will be a blank scriptvarlink if we're not executing,
|
|
|
|
|
|
|
|
* so just return it rather than an alloc/free */
|
|
|
|
|
|
|
|
return function;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CScriptVarLink *CTinyJS::factor(bool &execute) {
|
|
|
|
|
|
|
|
if (l->tk=='(') {
|
|
|
|
|
|
|
|
l->match('(');
|
|
|
|
|
|
|
|
CScriptVarLink *a = base(execute);
|
|
|
|
|
|
|
|
l->match(')');
|
|
|
|
|
|
|
|
return a;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_R_TRUE) {
|
|
|
|
|
|
|
|
l->match(LEX_R_TRUE);
|
|
|
|
|
|
|
|
return new CScriptVarLink(new CScriptVar(1));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_R_FALSE) {
|
|
|
|
|
|
|
|
l->match(LEX_R_FALSE);
|
|
|
|
|
|
|
|
return new CScriptVarLink(new CScriptVar(0));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_R_NULL) {
|
|
|
|
|
|
|
|
l->match(LEX_R_NULL);
|
|
|
|
|
|
|
|
return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_NULL));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_R_UNDEFINED) {
|
|
|
|
|
|
|
|
l->match(LEX_R_UNDEFINED);
|
|
|
|
|
|
|
|
return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_UNDEFINED));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l->tk==LEX_ID) {
|
|
|
|
|
|
|
|
CScriptVarLink *a = execute ? findInScopes(l->tkStr) : new CScriptVarLink(new CScriptVar());
|
|
|
|
|
|
|
|
//printf("0x%08X for %s at %s\n", (unsigned int)a, l->tkStr.c_str(), l->getPosition().c_str());
|
|
|
|
|
|
|
|
/* The parent if we're executing a method call */
|
|
|
|
|
|
|
|
CScriptVar *parent = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (execute && !a) {
|
|
|
|
|
|
|
|
/* Variable doesn't exist! JavaScript says we should create it
|
|
|
|
|
|
|
|
* (we won't add it here. This is done in the assignment operator)*/
|
|
|
|
|
|
|
|
a = new CScriptVarLink(new CScriptVar(), l->tkStr);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
l->match(LEX_ID);
|
|
|
|
|
|
|
|
while (l->tk=='(' || l->tk=='.' || l->tk=='[') {
|
|
|
|
|
|
|
|
if (l->tk=='(') { // ------------------------------------- Function Call
|
|
|
|
|
|
|
|
a = functionCall(execute, a, parent);
|
|
|
|
} else if (l->tk == '.') { // ------------------------------------- Record Access
|
|
|
|
} else if (l->tk == '.') { // ------------------------------------- Record Access
|
|
|
|
l->match('.');
|
|
|
|
l->match('.');
|
|
|
|
if (execute) {
|
|
|
|
if (execute) {
|
|
|
@ -1656,20 +1668,24 @@ CScriptVarLink *CTinyJS::factor(bool &execute) {
|
|
|
|
l->match(LEX_R_NEW);
|
|
|
|
l->match(LEX_R_NEW);
|
|
|
|
const string &className = l->tkStr;
|
|
|
|
const string &className = l->tkStr;
|
|
|
|
if (execute) {
|
|
|
|
if (execute) {
|
|
|
|
CScriptVarLink *objClass = findInScopes(className);
|
|
|
|
CScriptVarLink *objClassOrFunc = findInScopes(className);
|
|
|
|
if (!objClass) {
|
|
|
|
if (!objClassOrFunc) {
|
|
|
|
TRACE("%s is not a valid class name", className.c_str());
|
|
|
|
TRACE("%s is not a valid class name", className.c_str());
|
|
|
|
return new CScriptVarLink(new CScriptVar());
|
|
|
|
return new CScriptVarLink(new CScriptVar());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
l->match(LEX_ID);
|
|
|
|
l->match(LEX_ID);
|
|
|
|
CScriptVar *obj = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT);
|
|
|
|
CScriptVar *obj = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT);
|
|
|
|
obj->addChild(TINYJS_PROTOTYPE_CLASS, objClass->var);
|
|
|
|
CScriptVarLink *objLink = new CScriptVarLink(obj);
|
|
|
|
|
|
|
|
if (objClassOrFunc->var->isFunction()) {
|
|
|
|
|
|
|
|
CLEAN(functionCall(execute, objClassOrFunc, obj));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
obj->addChild(TINYJS_PROTOTYPE_CLASS, objClassOrFunc->var);
|
|
|
|
if (l->tk == '(') {
|
|
|
|
if (l->tk == '(') {
|
|
|
|
l->match('(');
|
|
|
|
l->match('(');
|
|
|
|
l->match(')');
|
|
|
|
l->match(')');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: Object constructors
|
|
|
|
}
|
|
|
|
return new CScriptVarLink(obj);
|
|
|
|
return objLink;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
l->match(LEX_ID);
|
|
|
|
l->match(LEX_ID);
|
|
|
|
if (l->tk == '(') {
|
|
|
|
if (l->tk == '(') {
|
|
|
|