Skip to content
Permalink
Browse files

Add maps to C4Script

{} creates an empty map, except where a block is expected.
{ key = "value", "key with non-identifier-characters" = 1337, ... } creates a map with according key value-pairs.
in { key = "value", } the last comma is allowed for easier key-value pair additions later on.

The entries of a map can be iterated using for(var key, value in map).
GetKeys(map) and GetValues(map) can be used to get an array of all keys and values of a map.

To access a specific map element the []-operator can be used, e.g. map["foo"].
To access entries with a constant string key, the access-operator . can be used, e.g. map.foo accesses the same entry as map["foo"].
All value types can be used as keys, including arrays and maps.
Though, for the {}-initialization and map.key access, only strings are supported.

By setting an entry to 0, the according key-value pair gets removed from the map.

To stay in sync, the iteration order as well as the order of the result of GetKeys() and GetValues() resembles the order in which the entries have been inserted into the map.

WARNING: When using objects or objects nested inside maps or arrays as keys, the assigned values may become inaccessible when the object is being removed.
  • Loading branch information...
maxmitti authored and Fulgen301 committed Jul 26, 2019
1 parent 92852ed commit d84fcf29fd837cc46dbb57bba5674855fb72bb19
@@ -279,9 +279,13 @@ src/C4UpperBoard.cpp
src/C4UpperBoard.h
src/C4UserMessages.h
src/C4Value.cpp
src/C4ValueContainer.h
src/C4Value.h
src/C4ValueHash.cpp
src/C4ValueHash.h
src/C4ValueList.cpp
src/C4ValueList.h
src/C4ValueStandardRefCountedContainer.h
src/C4ValueMap.cpp
src/C4ValueMap.h
src/C4Version.h
@@ -113,6 +113,8 @@ struct C4AulParSet
// some special script functions defined hard-coded to reduce the exec context
enum C4AulBCCType
{
AB_MAPA_R, // map access via .
AB_MAPA_V, // not creating a reference
AB_ARRAYA_R, // array access
AB_ARRAYA_V, // not creating a reference
AB_ARRAY_APPEND, // always as a reference
@@ -180,25 +182,27 @@ enum C4AulBCCType
AB_XOrIt, // ^=
AB_Set, // =

AB_CALL, // direct object call
AB_CALLFS, // failsafe direct call
AB_CALLNS, // direct object call: namespace operator
AB_STACK, // push nulls / pop
AB_INT, // constant: int
AB_BOOL, // constant: bool
AB_STRING, // constant: string
AB_C4ID, // constant: C4ID
AB_ARRAY, // semi-constant: array
AB_IVARN, // initialization of named var
AB_JUMP, // jump
AB_JUMPAND, // jump if zero, else pop the stack
AB_JUMPOR, // jump if not zero, else pop the stack
AB_CONDN, // conditional jump (negated, pops stack)
AB_FOREACH_NEXT, // foreach: next element
AB_RETURN, // return statement
AB_ERR, // parse error at this position
AB_EOFN, // end of function
AB_EOF, // end of file
AB_CALL, // direct object call
AB_CALLFS, // failsafe direct call
AB_CALLNS, // direct object call: namespace operator
AB_STACK, // push nulls / pop
AB_INT, // constant: int
AB_BOOL, // constant: bool
AB_STRING, // constant: string
AB_C4ID, // constant: C4ID
AB_ARRAY, // semi-constant: array
AB_MAP, // semi-constant: map
AB_IVARN, // initialization of named var
AB_JUMP, // jump
AB_JUMPAND, // jump if zero, else pop the stack
AB_JUMPOR, // jump if not zero, else pop the stack
AB_CONDN, // conditional jump (negated, pops stack)
AB_FOREACH_NEXT, // foreach: next element in array
AB_FOREACH_MAP_NEXT, // foreach: next key-value pair in map
AB_RETURN, // return statement
AB_ERR, // parse error at this position
AB_EOFN, // end of function
AB_EOF, // end of file
};

// ** a definition of an operator
@@ -23,6 +23,7 @@
#include <C4Object.h>
#include <C4Config.h>
#include <C4Game.h>
#include <C4ValueHash.h>
#include <C4Wrappers.h>

C4AulExecError::C4AulExecError(C4Object *pObj, const char *szError) : cObj(pObj)
@@ -181,6 +182,12 @@ class C4AulExec
(++pCurVal)->SetArray(Array);
}

void PushMap(C4ValueHash *Map)
{
CheckOverflow(1);
(++pCurVal)->SetMap(Map);
}

void PushValue(const C4Value &rVal)
{
CheckOverflow(1);
@@ -804,17 +811,50 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
break;
}

case AB_MAP:
{
C4ValueHash *map = new C4ValueHash;
for (int i = 0; i < pCPos->bccX; ++i)
{
(*map)[pCurVal[2 * (i - pCPos->bccX) + 1]] = pCurVal[2 * (i - pCPos->bccX) + 2];
}

if (pCPos->bccX > 0)
{
PopValues(2 * pCPos->bccX - 1);
pCurVal->SetMap(map);
}
else
PushMap(map);

break;
}

case AB_ARRAYA_R: case AB_ARRAYA_V:
{
C4Value &Container = pCurVal[-1].GetRefVal();
C4Value &Index = pCurVal[0];
if (!Index.ConvertTo(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array access: index of type %s, int expected!", Index.GetTypeName()).getData());
auto index = Index._getInt();
if (Container.GetType() == C4V_Any)
{
throw new C4AulExecError(pCurCtx->Obj, "indexed access [index]: array, map or string expected, but got 0");
}

C4Value &Array = pCurVal[-1].GetRefVal();
if (Array.GetType() == C4V_String)
if (Container.ConvertTo(C4V_Map) || Container.ConvertTo(C4V_Array))
{
StdStrBuf &str = Array._getStr()->Data;
Container.GetContainerElement(&Index, pCurVal[-1], pCurCtx, pCPos->bccType == AB_ARRAYA_V);
// Remove index
PopValue();
break;
}


if (Container.ConvertTo(C4V_String))
{
if (!Index.ConvertTo(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("indexed string access: index of type %s, int expected!", Index.GetTypeName()).getData());

auto index = Index._getInt();
StdStrBuf &str = Container._getStr()->Data;
if (index < 0)
{
index += str.getLength();
@@ -833,17 +873,21 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
PopValue();
break;
}
// Typcheck
if (!Array.ConvertTo(C4V_Array))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array access: can't access %s as an array!", Array.GetTypeName()).getData());
// Set reference to array element
if (pCPos->bccType == AB_ARRAYA_R)
Array.GetArrayElement(index, pCurVal[-1], pCurCtx);
else
// do not mark array as having element references
Array.GetArrayElement(index, pCurVal[-1], pCurCtx, true);
// Remove index
PopValue();
throw new C4AulExecError(pCurCtx->Obj, FormatString("indexed access: can't access %s by index!", Container.GetTypeName()).getData());
}

case AB_MAPA_R: case AB_MAPA_V:
{
C4Value &Map = pCurVal->GetRefVal();
if (!Map.ConvertTo(C4V_Map))
{
throw new C4AulExecError(pCurCtx->Obj, FormatString("map access with .: map expected, but got \"%s\"!", GetC4VName(Map.GetType())).getData());
}

C4Value key(reinterpret_cast<C4String *>(pCPos->bccX));
Map.GetContainerElement(&key, *pCurVal, pCurCtx, pCPos->bccType == AB_MAPA_V);

break;
}

@@ -854,7 +898,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
if (!Array.ConvertTo(C4V_Array) || Array.GetType() != C4V_Array)
throw new C4AulExecError(pCurCtx->Obj, FormatString("array append accesss: can't access %s as an array!", Array.GetType() == C4V_Any ? "0" : Array.GetTypeName()).getData());

Array.GetArrayElement(Array._getArray()->GetSize(), pCurVal[0], pCurCtx);
C4Value index = C4VInt(Array._getArray()->GetSize());
Array.GetContainerElement(&index, pCurVal[0], pCurCtx);

break;
}
@@ -1015,6 +1060,44 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
break;
}

case AB_FOREACH_MAP_NEXT:
{
// This should always hold
assert(pCurVal[-1].ConvertTo(C4V_Int));
using Iterator = C4ValueHash::Iterator;
auto iterator = reinterpret_cast<Iterator *>(pCurVal[0]._getRef());
// Check map the first time only
if (!iterator)
{
if (!pCurVal[-2].ConvertTo(C4V_Map))
throw new C4AulExecError(pCurCtx->Obj, FormatString("for: map expected, but got %s!", pCurVal[-1].GetTypeName()).getData());
if (!pCurVal[-2]._getMap())
throw new C4AulExecError(pCurCtx->Obj, FormatString("for: map expected, but got 0!").getData());
}
C4ValueHash *map = pCurVal[-2]._getMap();
if (!iterator)
{
iterator = new Iterator (map->begin());
pCurVal[0].SetInt(1);
pCurVal[0].GetData().Ref = reinterpret_cast<C4Value *>(iterator);
}
// No more entries?
if (*iterator == map->end())
{
delete iterator;
break;
}
// Get next
pCurCtx->Vars[pCPos->bccX] = (**iterator).first;
pCurCtx->Vars[pCurVal[-1]._getInt()] = (**iterator).second;

++(*iterator);
// Jump over next instruction
pCPos += 2;
fJump = true;
break;
}

case AB_IVARN:
pCurCtx->Vars[pCPos->bccX] = pCurVal[0];
PopValue();

0 comments on commit d84fcf2

Please sign in to comment.
You can’t perform that action at this time.