String ScriptParser::run(W3GReplay* w3g) { if (!errors.isEmpty()) return errors; ScriptGlobal* global = ScriptGlobal::create(w3g); Array<StackItem> stack; String result = ""; CodeBlock* cur = code; while (cur) { bool sub = false; if (cur->type == BLOCK_FOR) { Array<String> match; if (cur->text.match("for (\\w+) in ([a-zA-Z0-9_.]+)", &match)) { if (cur->child) { ScriptValue* val = global->getGlobalValue(match[2]); if (val && val->getEnumCount() > 0) { StackItem& fs = stack.push(); fs.type = cur->type; fs.list = val; fs.pos = 0; fs.var = match[1]; global->setGlobalValue(match[1], val->getEnum(0)); sub = true; } } } else return mkerror(cur, "Invalid for loop (expected {for <name> in <list>})"); } else if (cur->type == BLOCK_IF || cur->type == BLOCK_ELSEIF) { String result; if (!eval(cur->text.substring(cur->type == BLOCK_IF ? 2 : 6), result, global)) return mkerror(cur, "Invalid condition"); if (!result.isEmpty() && result.icompare("false")) { StackItem& fs = stack.push(); fs.type = cur->type; sub = true; } } else if (cur->type == BLOCK_ALIGN) { StackItem& fs = stack.push(); fs.type = cur->type; fs.pos = result.length(); sub = true; } else if (cur->type == BLOCK_VAR) { ScriptValue* val = global->getGlobalValue(cur->text); if (val) result += val->getValue(); } else if (cur->type == BLOCK_ELSE) { StackItem& fs = stack.push(); fs.type = cur->type; sub = true; } else if (cur->type == BLOCK_TEXT) result += cur->text; if (cur->child && sub) cur = cur->child; else if (cur->next && !sub) cur = cur->next; else { if (!sub) cur = cur->parent; if (cur == NULL) break; int top = stack.length() - 1; if (top < 0 || stack[top].type != cur->type) return mkerror(cur, "Error handling structure"); if (cur->type == BLOCK_FOR) { stack[top].pos++; if (stack[top].pos < stack[top].list->getEnumCount() && cur->child) { cur = cur->child; global->setGlobalValue(stack[top].var, stack[top].list->getEnum(stack[top].pos)); } else { cur = cur->next; global->unsetGlobalValue(stack[top].var); stack.pop(); } } else if (cur->type == BLOCK_IF || cur->type == BLOCK_ELSEIF || cur->type == BLOCK_ELSE) { stack.pop(); while (cur && (cur->type == BLOCK_IF || cur->type == BLOCK_ELSEIF || cur->type == BLOCK_ELSE)) cur = cur->next; } else if (cur->type == BLOCK_ALIGN) { Array<String> match; if (cur->text.match("align (left|right) (\\d+)", &match)) { int len = result.length() - stack[top].pos; int align = match[2].toInt(); if (align > len) { if (match[1] == "left") result += String(' ') * (align - len); else result.insert(stack[top].pos, String(' ') * (align - len)); } } else return mkerror(cur, "Invalid align (expected {align <left|right> <width>})"); stack.pop(); cur = cur->next; } else return mkerror(cur, "Unexpected block type"); } } if (stack.length() != 0) return "Generic script execution error"; delete global; return result; }
ScriptValue ScriptNodeFunctionCall::execute( ScriptExecutionContext* theContext) { try { theContext->countNodeExecution(this); ScriptValue fctRef = functionM->execute(theContext); ScriptObject* object = fctRef.getBase(); // Create argument array ScriptValueArray arguments; arguments.reserve(argumentListM.size()); // Evaluate function call arguments for (ScriptNodeArray::iterator iter = argumentListM.begin(); iter != argumentListM.end(); iter++) { ScriptValue result((*iter)->execute(theContext)); if (result.getDataType() == ScriptValue::ReferenceE) { result = result.getReferenceValue(); } arguments.push_back(result); } const std::string fctName = fctRef.getPropertyName(); theContext->traceFunctionCall(object, fctName, arguments); if (object != 0) { return object->call(fctName, theContext, arguments, isConstructorM); } else { ScriptValue fct = fctRef.getValue(); if (fct.getDataType() != ScriptValue::ObjectE) { std::string errorMessage("Identifier '"); errorMessage += fctName; errorMessage += "' does not refer to a function."; throw ScriptTypeError(errorMessage, getFile(), getLine()); } object = fct.toObject(); if (object->getObjectType() != ScriptObject::FunctionE) { std::string errorMessage("Identifier '"); errorMessage += fctName; errorMessage += "' does not refer to a function."; throw ScriptTypeError(errorMessage, getFile(), getLine()); } ScriptObjectActivation* activationObject = new ScriptObjectActivation; if (isConstructorM == false) { // Function is not used as a constructor. theContext->addObjectToScopeChain(activationObject); ScriptValue result(object->call(theContext, arguments)); theContext->removeObjectFromScopeChain(); return result; } else { // Function is used as a constructor. // Create a new object ScriptObject* newObject = new ScriptObject(ScriptObject::ObjectE); ScriptValue result(newObject); newObject->putProperty( PrototypeC, ScriptValue(object), ScriptProperty::DontEnumE | ScriptProperty::DontDeleteE | ScriptProperty::ReadOnlyE); activationObject->putProperty(ThisC, newObject); theContext->addObjectToScopeChain(activationObject); object->call(theContext, arguments); theContext->removeObjectFromScopeChain(); return result; } } } catch (ScriptReferenceError& e) { if (e.getLine() == 0) { e.setLineAndFile(getLine(), getFile()); } throw e; } catch (ScriptTypeError& e) { if (e.getLine() == 0) { e.setLineAndFile(getLine(), getFile()); } throw e; } catch (ScriptUserDefinedException& e) { if (e.getLine() == 0) { e.setLineAndFile(getLine(), getFile()); } throw e; } }