Beispiel #1
0
C4Value C4Effect::DoCall(C4Object *pObj, const char *szFn, C4Value &rVal1,
                         C4Value &rVal2, C4Value &rVal3, C4Value &rVal4,
                         C4Value &rVal5, C4Value &rVal6, C4Value &rVal7) {
  // def script or global only?
  C4AulScript *pSrcScript;
  C4Def *pDef;
  if (pCommandTarget) {
    pSrcScript = &pCommandTarget->Def->Script;
    // overwrite ID for sync safety in runtime join
    idCommandTarget = pCommandTarget->id;
  } else if (idCommandTarget && (pDef = Game.Defs.ID2Def(idCommandTarget)))
    pSrcScript = &pDef->Script;
  else
    pSrcScript = &Game.ScriptEngine;
  // compose function name
  char fn[C4AUL_MAX_Identifier + 1];
  sprintf(fn, PSF_FxCustom, Name, szFn);
  // call it
  C4AulFunc *pFn = pSrcScript->GetFuncRecursive(fn);
  if (!pFn)
    return C4Value();
  return pFn->Exec(pCommandTarget,
                   &C4AulParSet(C4VObj(pObj), C4VInt(iNumber), rVal1, rVal2,
                                rVal3, rVal4, rVal5, rVal6, rVal7));
}
Beispiel #2
0
// ResolveAppends and ResolveIncludes must be called both
// for each script. ResolveAppends has to be called first!
BOOL C4AulScript::ResolveAppends(C4DefList *rDefs) {
  // resolve children appends
  for (C4AulScript *s = Child0; s; s = s->Next) s->ResolveAppends(rDefs);
  // resolve local appends
  if (State != ASS_PREPARSED) return FALSE;
  for (C4AListEntry *a = Appends; a; a = a->next()) {
    if ((long)a->Var != -1) {
      C4Def *Def = rDefs->ID2Def(C4ID(a->Var));
      if (Def)
        AppendTo(Def->Script, true);
      else {
        // save id in buffer because AulWarn will use the buffer of C4IdText
        // to get the id of the object in which the error occurs...
        // (stupid static buffers...)
        char strID[5];
        *strID = 0;
        strcpy(strID, C4IdText(C4ID(a->Var)));
        Warn("script to #appendto not found: ", strID);
      }
    } else {
      // append to all defs
      for (int i = 0; i < rDefs->GetDefCount(); i++) {
        C4Def *pDef = rDefs->GetDef(i);
        if (!pDef) break;
        if (pDef == Def) continue;
        // append
        AppendTo(pDef->Script, true);
      }
    }
  }
  return TRUE;
}
Beispiel #3
0
bool C4AulScriptEngine::ReloadScript(const char *szScript, const char *szLanguage)
{
	C4AulScript * s;
	for (s = Child0; s; s = s->Next)
		if (s->ReloadScript(szScript, szLanguage))
			break;
	return !!s;
}
TEST(DirectExecTest, SanityTests)
{
	C4AulScript * pScript = new C4AulScript();
	ASSERT_TRUE(pScript);
	C4Value rVal(pScript->DirectExec(nullptr, "5*8", "unit test script", false, nullptr));
	EXPECT_EQ(rVal, C4Value(5*8));
	delete pScript;
}
Beispiel #5
0
void C4AulScriptEngine::UnLink()
{
	warnCnt = errCnt = lineCnt = 0;

	// unlink scripts
	for (C4AulScript *s = Child0; s; s = s->Next)
		s->UnLink();
	GetPropList()->Thaw();
	if (State > ASS_PREPARSED) State = ASS_PREPARSED;
	// Do not clear global variables and constants, because they are registered by the
	// preparser or other parts. Note that keeping those fields means that you cannot delete a global
	// variable or constant at runtime by removing it from the script.
}
void C4AulScriptEngine::Link(C4DefList *rDefs)
{
	try
	{
		// resolve appends
		for (C4AulScript *s = Child0; s; s = s->Next)
			s->ResolveAppends(rDefs);

		// resolve includes
		for (C4AulScript *s = Child0; s; s = s->Next)
			s->ResolveIncludes(rDefs);

		// parse the scripts to byte code
		for (C4AulScript *s = Child0; s; s = s->Next)
			s->Parse();

		// engine is always parsed (for global funcs)
		State = ASS_PARSED;

		if (rDefs)
			rDefs->CallEveryDefinition();

		// Done modifying the proplists now
		for (C4AulScript *s = Child0; s; s = s->Next)
			s->GetPropList()->Freeze();
		GetPropList()->Freeze();
	}
	catch (C4AulError &err)
	{
		// error??! show it!
		err.show();
	}


}
Beispiel #7
0
BOOL C4AulScript::ResolveIncludes(C4DefList *rDefs) {
  // resolve children includes
  for (C4AulScript *s = Child0; s; s = s->Next) s->ResolveIncludes(rDefs);
  // Had been preparsed?
  if (State != ASS_PREPARSED) return FALSE;
  // has already been resolved?
  if (IncludesResolved) return TRUE;
  // catch circular includes
  if (Resolving) {
    C4AulParseError(this,
                    "Circular include chain detected - ignoring all includes!")
        .show();
    IncludesResolved = true;
    State = ASS_LINKED;
    return FALSE;
  }
  Resolving = true;
  // append all includes to local script
  for (C4AListEntry *i = Includes; i; i = i->next()) {
    C4Def *Def = rDefs->ID2Def(C4ID(i->Var));
    if (Def) {
      // resolve #includes in included script first (#include-chains :( )
      if (!((C4AulScript &)Def->Script).IncludesResolved)
        if (!Def->Script.ResolveIncludes(rDefs))
          continue;  // skip this #include

      Def->Script.AppendTo(*this, false);
    } else {
      // save id in buffer because AulWarn will use the buffer of C4IdText
      // to get the id of the object in which the error occurs...
      // (stupid static buffers...)
      char strID[5];
      *strID = 0;
      strcpy(strID, C4IdText(C4ID(i->Var)));
      Warn("script to #include not found: ", strID);
    }
  }
  IncludesResolved = true;
  // includes/appends are resolved now (for this script)
  Resolving = false;
  State = ASS_LINKED;
  return TRUE;
}
Beispiel #8
0
void C4AulScript::AfterLink() {
  // for all funcs: search functions that have the same name in
  // the whole script tree (for great fast direct object call)
  for (C4AulFunc *Func = Func0; Func; Func = Func->Next)
    // same-name ring not yet build for this function name?
    if (!Func->NextSNFunc && !Func->OverloadedBy) {
      // init
      Func->NextSNFunc = Func;
      // search complete tree for functions with same name
      // (expect all scripts "behind" this point to be already checked
      //  - so after-link calls for childs must be done after this).
      C4AulScript *pPos = this;
      while (pPos) {
        // has children? go down in hierarchy
        if (pPos->Child0)
          pPos = pPos->Child0;
        else {
          // last child? go up in hierarchy
          while (!pPos->Next && pPos->Owner) pPos = pPos->Owner;
          // next node
          pPos = pPos->Next;
        }
        if (!pPos) break;
        // has function with same name?
        C4AulFunc *pFn = pPos->GetFunc(Func->Name);
        if (pFn) {
          // resolve overloads
          while (pFn->OverloadedBy) pFn = pFn->OverloadedBy;
          // link
          pFn->NextSNFunc = Func->NextSNFunc;
          Func->NextSNFunc = pFn;
        }
      }
    }
  // call for childs
  for (C4AulScript *s = Child0; s; s = s->Next) s->AfterLink();
}
Beispiel #9
0
void C4AulScript::UnLink() {
  // unlink children
  for (C4AulScript *s = Child0; s; s = s->Next) s->UnLink();

  // do not unlink temporary (e.g., DirectExec-script in ReloadDef)
  if (Temporary) return;

  // check if byte code needs to be freed
  if (Code) {
    delete[] Code;
    Code = NULL;
  }

  // delete included/appended functions
  C4AulFunc *pFunc = Func0;
  while (pFunc) {
    C4AulFunc *pNextFunc = pFunc->Next;

    // clear stuff that's set in AfterLink
    pFunc->UnLink();

    if (pFunc->SFunc())
      if (pFunc->Owner != pFunc->SFunc()->pOrgScript)
        if (!pFunc->LinkedTo ||
            pFunc->LinkedTo->SFunc())  // do not kill global links; those will
                                       // be deleted if corresponding sfunc in
                                       // script is deleted
          delete pFunc;

    pFunc = pNextFunc;
  }
  // includes will have to be re-resolved now
  IncludesResolved = false;

  if (State > ASS_PREPARSED) State = ASS_PREPARSED;
}
Beispiel #10
0
void C4Effect::AssignCallbackFunctions() {
  C4AulScript *pSrcScript = GetCallbackScript();
  // compose function names and search them
  char fn[C4AUL_MAX_Identifier + 1];
  sprintf(fn, PSF_FxStart, Name);
  pFnStart = pSrcScript->GetFuncRecursive(fn);
  sprintf(fn, PSF_FxStop, Name);
  pFnStop = pSrcScript->GetFuncRecursive(fn);
  sprintf(fn, PSF_FxTimer, Name);
  pFnTimer = pSrcScript->GetFuncRecursive(fn);
  sprintf(fn, PSF_FxEffect, Name);
  pFnEffect = pSrcScript->GetFuncRecursive(fn);
  sprintf(fn, PSF_FxDamage, Name);
  pFnDamage = pSrcScript->GetFuncRecursive(fn);
}
C4AulDebug::ProcessLineResult C4AulDebug::ProcessLine(const StdStrBuf &Line)
{
	// Get command
	StdStrBuf Cmd;
	Cmd.CopyUntil(Line.getData(), ' ');
	// Get data
	const char *szData = Line.getPtr(Cmd.getLength());
	if (*szData) szData++;
	// Identify command
	const char *szCmd = Cmd.getData();
	if (SEqualNoCase(szCmd, "HELP"))
		return ProcessLineResult(false, "Yeah, like I'm going to explain that /here/");
	else if (SEqualNoCase(szCmd, "BYE") || SEqualNoCase(szCmd, "QUIT"))
		C4NetIOTCP::Close(PeerAddr);
	else if (SEqualNoCase(szCmd, "SAY"))
		::Control.DoInput(CID_Message, new C4ControlMessage(C4CMT_Normal, szData), CDT_Direct);
	else if (SEqualNoCase(szCmd, "CMD"))
		::MessageInput.ProcessCommand(szData);
	else if (SEqualNoCase(szCmd, "STP") || SEqualNoCase(szCmd, "S"))
		eState = DS_Step;
	else if (SEqualNoCase(szCmd, "GO") || SEqualNoCase(szCmd, "G"))
		eState = DS_Go;
	else if (SEqualNoCase(szCmd, "STO") || SEqualNoCase(szCmd, "O"))
		eState = DS_StepOver;
	else if (SEqualNoCase(szCmd, "STR") || SEqualNoCase(szCmd, "R"))
		eState = DS_StepOut;
	else if (SEqualNoCase(szCmd, "EXC") || SEqualNoCase(szCmd, "E"))
	{
		C4AulScriptContext* context = pExec->GetContext(pExec->GetContextDepth()-1);
		int32_t objectNum = C4ControlScript::SCOPE_Global;
		if (context && context->Obj && context->Obj->GetObject())
			objectNum = context->Obj->GetObject()->Number;
		::Control.DoInput(CID_Script, new C4ControlScript(szData, objectNum, true), CDT_Decide);
	}
	else if (SEqualNoCase(szCmd, "PSE"))
		if (Game.IsPaused())
		{
			Game.Unpause();
			return ProcessLineResult(true, "Game unpaused.");
		}
		else
		{
			Game.Pause();
			return ProcessLineResult(true, "Game paused.");
		}
	else if (SEqualNoCase(szCmd, "LST"))
	{
		for (C4AulScript* script = ScriptEngine.Child0; script; script = script->Next)
		{
			SendLine(RelativePath(script->ScriptName));
		}
	}

	// toggle breakpoint
	else if (SEqualNoCase(szCmd, "TBR"))
	{
		using namespace std;
		// FIXME: this doesn't find functions which were included/appended
		string scriptPath = szData;
		size_t colonPos = scriptPath.find(':');
		if (colonPos == string::npos)
			return ProcessLineResult(false, "Missing line in breakpoint request");
		int line = atoi(&scriptPath[colonPos+1]);
		scriptPath.erase(colonPos);

		C4AulScript *script;
		for (script = ScriptEngine.Child0; script; script = script->Next)
		{
			if (SEqualNoCase(RelativePath(script->ScriptName), scriptPath.c_str()))
				break;
		}

		auto sh = script ? script->GetScriptHost() : NULL;
		if (sh)
		{
			C4AulBCC * found = NULL;
			for (auto script = ::ScriptEngine.Child0; script; script = script->Next)
			for (C4PropList *props = script->GetPropList(); props; props = props->GetPrototype())
			for (auto fname = props->EnumerateOwnFuncs(); fname; fname = props->EnumerateOwnFuncs(fname))
			{
				C4Value val;
				if (!props->GetPropertyByS(fname, &val)) continue;
				auto func = val.getFunction();
				if (!func) continue;
				auto sfunc = func->SFunc();
				if (!sfunc) continue;
				if (sfunc->pOrgScript != sh) continue;
				for (auto chunk = sfunc->GetCode(); chunk->bccType != AB_EOFN; chunk++)
				{
					if (chunk->bccType == AB_DEBUG)
					{
						int lineOfThisOne = sfunc->GetLineOfCode(chunk);
						if (lineOfThisOne == line)
						{
							found = chunk;
							goto Found;
						}
					}
				}
			}
			Found:
			if (found)
				found->Par.i = !found->Par.i; // activate breakpoint
			else
				return ProcessLineResult(false, "Can't set breakpoint (wrong line?)");
		}
		else
			return ProcessLineResult(false, "Can't find script");
	}
	else if (SEqualNoCase(szCmd, "SST"))
	{
		std::list<StdStrBuf*>::iterator it = StackTrace.begin();
		for (it++; it != StackTrace.end(); it++)
		{
			SendLine("AT", (*it)->getData());
		}
		SendLine("EST");
	}
	else if (SEqualNoCase(szCmd, "VAR"))
	{
		
		C4Value *val = NULL;
		int varIndex;
		C4AulScriptContext* pCtx = pExec->GetContext(pExec->GetContextDepth() - 1);
		if (pCtx)
		{
			if ((varIndex = pCtx->Func->ParNamed.GetItemNr(szData)) != -1)
			{
				val = &pCtx->Pars[varIndex];
			}
			else if ((varIndex = pCtx->Func->VarNamed.GetItemNr(szData)) != -1)
			{
				val = &pCtx->Vars[varIndex];
			}
		}
		const char* typeName = val ? GetC4VName(val->GetType()) : "any";
		StdStrBuf output = FormatString("%s %s %s", szData, typeName, val ? val->GetDataString().getData() : "Unknown");
		SendLine("VAR", output.getData());
	}
	else
		return ProcessLineResult(false, "Can't do that");
	
	return ProcessLineResult(true, "");
}
Beispiel #12
0
void C4AulScriptEngine::Link(C4DefList *rDefs) {
#ifdef C4ENGINE

  try {
    // resolve appends
    ResolveAppends(rDefs);

    // resolve includes
    ResolveIncludes(rDefs);

    // parse script funcs descs
    ParseDescs();

    // parse the scripts to byte code
    Parse();

    // engine is always parsed (for global funcs)
    State = ASS_PARSED;

    // get common funcs
    AfterLink();

    // non-strict scripts?
    if (nonStrictCnt) {
      // warn!
      // find first non-#strict script
      C4AulScript *pNonStrictScr = FindFirstNonStrictScript();
      if (pNonStrictScr)
        pNonStrictScr->Warn("using non-#strict syntax!", NULL);
      else {
        Warn("non-#strict script detected, but def is lost", NULL);
        Warn(
            "please contact [email protected] for further "
            "instructions",
            NULL);
      }
      Warn(FormatString("%d script%s use non-#strict syntax!", nonStrictCnt,
                        (nonStrictCnt != 1 ? "s" : "")).getData(),
           NULL);
    }

    // update material pointers
    Game.Material.UpdateScriptPointers();

    // display state
    sprintf(OSTR,
            "C4AulScriptEngine linked - %d line%s, %d warning%s, %d error%s",
            lineCnt, (lineCnt != 1 ? "s" : ""), warnCnt,
            (warnCnt != 1 ? "s" : ""), errCnt, (errCnt != 1 ? "s" : ""));
    Log(OSTR);

    // reset counters
    warnCnt = errCnt = nonStrictCnt = lineCnt = 0;
  } catch (C4AulError *err) {
    // error??! show it!
    err->show();
    delete err;
  }

#endif
}
Beispiel #13
0
BOOL C4AulScript::ReloadScript(const char *szPath) {
  // call for childs
  for (C4AulScript *s = Child0; s; s = s->Next)
    if (s->ReloadScript(szPath)) return TRUE;
  return FALSE;
}