Version 0.29 : Added new object via functions

Fixed getString() for double on some platforms
master
pur3mail 13 years ago
parent 8c790516ea
commit ecc4cc8fbd

@ -92,9 +92,10 @@
Rudimentary call stack on error
Added String Character functions
Added shift operators
Version 0.29 : Added new object via functions
Fixed getString() for double on some platforms
NOTE: This doesn't support constructors for objects
NOTE:
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
length variable cannot be set
@ -951,7 +952,7 @@ const string &CScriptVar::getString() {
}
if (isDouble()) {
char buffer[32];
sprintf_s(buffer, sizeof(buffer), "%lf", doubleData);
sprintf_s(buffer, sizeof(buffer), "%f", doubleData);
data = buffer;
return data;
}
@ -1429,6 +1430,104 @@ CScriptVarLink *CTinyJS::parseFunctionDefinition() {
return funcVar;
}
/** Handle a function call (assumes we've parsed the function name and we're
* on the start bracket). 'parent' is the object that contains this method,
* if there was one (otherwise it's just a normnal function).
*/
CScriptVarLink *CTinyJS::functionCall(bool &execute, CScriptVarLink *function, CScriptVar *parent) {
if (execute) {
if (!function->var->isFunction()) {
string errorMsg = "Expecting '";
errorMsg = errorMsg + function->name + "' to be a function";
throw new CScriptException(errorMsg.c_str());
}
l->match('(');
// create a new symbol table entry for execution of this function
CScriptVar *functionRoot = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_FUNCTION);
if (parent)
functionRoot->addChildNoDup("this", parent);
// grab in all parameters
CScriptVarLink *v = function->var->firstChild;
while (v) {
CScriptVarLink *value = base(execute);
if (execute) {
if (value->var->isBasic()) {
// pass by value
functionRoot->addChild(v->name, value->var->deepCopy());
} else {
// pass by reference
functionRoot->addChild(v->name, value->var);
}
}
CLEAN(value);
if (l->tk!=')') l->match(',');
v = v->nextSibling;
}
l->match(')');
// setup a return variable
CScriptVarLink *returnVar = NULL;
// execute function!
// add the function's execute space to the symbol table so we can recurse
CScriptVarLink *returnVarLink = functionRoot->addChild(TINYJS_RETURN_VAR);
scopes.push_back(functionRoot);
#ifdef TINYJS_CALL_STACK
call_stack.push_back(function->name + " from " + l->getPosition());
#endif
if (function->var->isNative()) {
ASSERT(function->var->jsCallback);
function->var->jsCallback(functionRoot, function->var->jsCallbackUserData);
} else {
/* we just want to execute the block, but something could
* have messed up and left us with the wrong ScriptLex, so
* we want to be careful here... */
CScriptException *exception = 0;
CScriptLex *oldLex = l;
CScriptLex *newLex = new CScriptLex(function->var->getString());
l = newLex;
try {
block(execute);
// because return will probably have called this, and set execute to false
execute = true;
} catch (CScriptException *e) {
exception = e;
}
delete newLex;
l = oldLex;
if (exception)
throw exception;
}
#ifdef TINYJS_CALL_STACK
if (!call_stack.empty()) call_stack.pop_back();
#endif
scopes.pop_back();
/* get the real return var before we remove it from our function */
returnVar = new CScriptVarLink(returnVarLink->var);
functionRoot->removeLink(returnVarLink);
delete functionRoot;
if (returnVar)
return returnVar;
else
return new CScriptVarLink(new CScriptVar());
} else {
// function, but not executing - just parse args and be done
l->match('(');
while (l->tk != ')') {
CScriptVarLink *value = base(execute);
CLEAN(value);
if (l->tk!=')') l->match(',');
}
l->match(')');
if (l->tk == '{') {
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('(');
@ -1466,94 +1565,7 @@ CScriptVarLink *CTinyJS::factor(bool &execute) {
l->match(LEX_ID);
while (l->tk=='(' || l->tk=='.' || l->tk=='[') {
if (l->tk=='(') { // ------------------------------------- Function Call
if (execute) {
if (!a->var->isFunction()) {
string errorMsg = "Expecting '";
errorMsg = errorMsg + a->name + "' to be a function";
throw new CScriptException(errorMsg.c_str());
}
l->match('(');
// create a new symbol table entry for execution of this function
CScriptVar *functionRoot = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_FUNCTION);
if (parent)
functionRoot->addChildNoDup("this", parent);
// grab in all parameters
CScriptVarLink *v = a->var->firstChild;
while (v) {
CScriptVarLink *value = base(execute);
if (execute) {
if (value->var->isBasic()) {
// pass by value
functionRoot->addChild(v->name, value->var->deepCopy());
} else {
// pass by reference
functionRoot->addChild(v->name, value->var);
}
}
CLEAN(value);
if (l->tk!=')') l->match(',');
v = v->nextSibling;
}
l->match(')');
// setup a return variable
CScriptVarLink *returnVar = NULL;
// execute function!
// add the function's execute space to the symbol table so we can recurse
CScriptVarLink *returnVarLink = functionRoot->addChild(TINYJS_RETURN_VAR);
scopes.push_back(functionRoot);
#ifdef TINYJS_CALL_STACK
call_stack.push_back(a->name + " from " + l->getPosition());
#endif
if (a->var->isNative()) {
ASSERT(a->var->jsCallback);
a->var->jsCallback(functionRoot, a->var->jsCallbackUserData);
} else {
/* we just want to execute the block, but something could
* have messed up and left us with the wrong ScriptLex, so
* we want to be careful here... */
CScriptException *exception = 0;
CScriptLex *oldLex = l;
CScriptLex *newLex = new CScriptLex(a->var->getString());
l = newLex;
try {
block(execute);
// because return will probably have called this, and set execute to false
execute = true;
} catch (CScriptException *e) {
exception = e;
}
delete newLex;
l = oldLex;
if (exception)
throw exception;
}
#ifdef TINYJS_CALL_STACK
if (!call_stack.empty()) call_stack.pop_back();
#endif
scopes.pop_back();
/* get the real return var before we remove it from our function */
returnVar = new CScriptVarLink(returnVarLink->var);
functionRoot->removeLink(returnVarLink);
delete functionRoot;
if (returnVar)
a = returnVar;
else
a = new CScriptVarLink(new CScriptVar());
} else {
// function, but not executing - just parse args and be done
l->match('(');
while (l->tk != ')') {
CScriptVarLink *value = base(execute);
CLEAN(value);
if (l->tk!=')') l->match(',');
}
l->match(')');
if (l->tk == '{') {
block(execute);
}
}
a = functionCall(execute, a, parent);
} else if (l->tk == '.') { // ------------------------------------- Record Access
l->match('.');
if (execute) {
@ -1656,20 +1668,24 @@ CScriptVarLink *CTinyJS::factor(bool &execute) {
l->match(LEX_R_NEW);
const string &className = l->tkStr;
if (execute) {
CScriptVarLink *objClass = findInScopes(className);
if (!objClass) {
CScriptVarLink *objClassOrFunc = findInScopes(className);
if (!objClassOrFunc) {
TRACE("%s is not a valid class name", className.c_str());
return new CScriptVarLink(new CScriptVar());
}
l->match(LEX_ID);
CScriptVar *obj = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT);
obj->addChild(TINYJS_PROTOTYPE_CLASS, objClass->var);
if (l->tk == '(') {
l->match('(');
l->match(')');
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 == '(') {
l->match('(');
l->match(')');
}
}
// TODO: Object constructors
return new CScriptVarLink(obj);
return objLink;
} else {
l->match(LEX_ID);
if (l->tk == '(') {

@ -333,6 +333,7 @@ private:
CScriptVar *arrayClass; /// Built in array class
// parsing - in order of precedence
CScriptVarLink *functionCall(bool &execute, CScriptVarLink *function, CScriptVar *parent);
CScriptVarLink *factor(bool &execute);
CScriptVarLink *unary(bool &execute);
CScriptVarLink *term(bool &execute);

@ -0,0 +1,10 @@
// the 'lf' in the printf caused issues writing doubles on some compilers
function Person(name) {
this.name = name;
this.kill = function() { this.name += " is dead"; };
}
var a = new Person("Kenny");
a.kill();
result = a.name == "Kenny is dead";

@ -0,0 +1,9 @@
// the 'lf' in the printf caused issues writing doubles on some compilers
var a=5.0/10.0*100.0;
var b=5.0*110.0;
var c=50.0/10.0;
a.dump();
b.dump();
c.dump();
result = a==50 && b==550 && c==5;
Loading…
Cancel
Save