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;
   }
}