forked from Mirrors/openclonk
C4Aul: Add new type 'nil'
Adds a new type representing 'no value' as well as a keyword 'nil' for accessing this type from script. nil is not equal to any value that is not nil itself. GetType(nil) returns C4V_Nil.stable-5.2
parent
7ab01aac9c
commit
383b263181
|
@ -194,6 +194,7 @@ enum C4AulBCCType
|
|||
AB_BOOL, // constant: bool
|
||||
AB_STRING, // constant: string
|
||||
AB_C4ID, // constant: C4ID
|
||||
AB_NIL, // constant: nil
|
||||
AB_ARRAY, // semi-constant: array
|
||||
AB_IVARN, // initialization of named var
|
||||
AB_JUMP, // jump
|
||||
|
|
|
@ -45,11 +45,12 @@ enum C4V_Type
|
|||
C4V_Array=6, // pointer on array of values
|
||||
|
||||
C4V_pC4Value=7, // reference on a value (variable)
|
||||
C4V_Nil=8, // nothing
|
||||
|
||||
C4V_C4ObjectEnum=8, // enumerated object
|
||||
C4V_C4ObjectEnum=9, // enumerated object
|
||||
};
|
||||
|
||||
#define C4V_Last (int) C4V_pC4Value
|
||||
#define C4V_Last (int) C4V_Nil
|
||||
|
||||
const char* GetC4VName(const C4V_Type Type);
|
||||
char GetC4VID(const C4V_Type Type);
|
||||
|
@ -80,22 +81,22 @@ class C4Value
|
|||
{
|
||||
public:
|
||||
|
||||
C4Value() : Type(C4V_Any), HasBaseArray(false), NextRef(NULL), FirstRef(NULL) { Data.Ref = 0; }
|
||||
C4Value() : Type(C4V_Nil), HasBaseArray(false), NextRef(NULL), FirstRef(NULL) { Data.Ref = 0; }
|
||||
|
||||
C4Value(const C4Value &nValue) : Data(nValue.Data), Type(nValue.Type), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
{ AddDataRef(); }
|
||||
|
||||
C4Value(C4V_Data nData, C4V_Type nType): Data(nData), Type(nData ? nType : C4V_Any), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
{ AddDataRef(); }
|
||||
C4Value(int32_t nData, C4V_Type nType): Type(nData ? nType : C4V_Any), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
{ Data.Int = nData; AddDataRef(); }
|
||||
explicit C4Value(C4Object *pObj): Type(pObj ? C4V_C4Object : C4V_Any), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
C4Value(C4V_Data nData, C4V_Type nType): HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
{ Set(nData, nType); AddDataRef(); }
|
||||
C4Value(long nData, C4V_Type nType): HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
{ Set(nData, nType); AddDataRef(); }
|
||||
explicit C4Value(C4Object *pObj): Type(pObj ? C4V_C4Object : C4V_Nil), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
{ Data.Obj = pObj; AddDataRef(); }
|
||||
explicit C4Value(C4String *pStr): Type(pStr ? C4V_String : C4V_Any), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
explicit C4Value(C4String *pStr): Type(pStr ? C4V_String : C4V_Nil), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
{ Data.Str = pStr; AddDataRef(); }
|
||||
explicit C4Value(C4ValueArray *pArray): Type(pArray ? C4V_Array : C4V_Any), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
explicit C4Value(C4ValueArray *pArray): Type(pArray ? C4V_Array : C4V_Nil), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
{ Data.Array = pArray; AddDataRef(); }
|
||||
explicit C4Value(C4Value *pVal): Type(pVal ? C4V_pC4Value : C4V_Any), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
explicit C4Value(C4Value *pVal): Type(pVal ? C4V_pC4Value : C4V_Nil), HasBaseArray(false), NextRef(NULL), FirstRef(NULL)
|
||||
{ Data.Ref = pVal; AddDataRef(); }
|
||||
|
||||
C4Value& operator = (const C4Value& nValue);
|
||||
|
@ -215,7 +216,7 @@ protected:
|
|||
C4Value * GetNextRef() { if (HasBaseArray) return 0; else return NextRef; }
|
||||
C4ValueArray * GetBaseArray() { if (HasBaseArray) return BaseArray; else return 0; }
|
||||
|
||||
void Set(long nData, C4V_Type nType = C4V_Any) { C4V_Data d; d.Int = nData; Set(d, nType); }
|
||||
void Set(long nData, C4V_Type nType = C4V_Nil) { C4V_Data d; d.Int = nData; Set(d, nType); }
|
||||
void Set(C4V_Data nData, C4V_Type nType);
|
||||
|
||||
void AddRef(C4Value *pRef);
|
||||
|
|
|
@ -342,6 +342,10 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
PushValue(C4VID(pCPos->Par.i));
|
||||
break;
|
||||
|
||||
case AB_NIL:
|
||||
PushValue(C4VNull);
|
||||
break;
|
||||
|
||||
case AB_EOFN:
|
||||
throw new C4AulExecError(pCurCtx->Obj, "function didn't return");
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
|
||||
#define C4AUL_True "true"
|
||||
#define C4AUL_False "false"
|
||||
#define C4AUL_Nil "nil"
|
||||
|
||||
#define C4AUL_CodeBufSize 16
|
||||
|
||||
|
@ -95,6 +96,7 @@ enum C4AulTokenType
|
|||
ATT_INT, // integer constant
|
||||
ATT_BOOL, // boolean constant
|
||||
ATT_STRING, // string constant
|
||||
ATT_NIL, // "nil"
|
||||
ATT_C4ID, // C4ID constant
|
||||
ATT_COMMA, // ","
|
||||
ATT_COLON, // ":"
|
||||
|
@ -715,6 +717,7 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
|
|||
// check reserved names
|
||||
if(SEqual(pToken, C4AUL_False)) { *pInt = false; return ATT_BOOL; }
|
||||
if(SEqual(pToken, C4AUL_True)) { *pInt = true; return ATT_BOOL; }
|
||||
if(SEqual(pToken, C4AUL_Nil)) { return ATT_NIL; }
|
||||
// everything else is an identifier
|
||||
return ATT_IDTF;
|
||||
}
|
||||
|
@ -913,6 +916,7 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
case AB_BOOL: return "BOOL"; // constant: bool
|
||||
case AB_STRING: return "STRING"; // constant: string
|
||||
case AB_C4ID: return "C4ID"; // constant: C4ID
|
||||
case AB_NIL: return "NIL"; // constant: nil
|
||||
case AB_ARRAY: return "ARRAY"; // semi-constant: array
|
||||
case AB_IVARN: return "IVARN"; // initialization of named var
|
||||
case AB_JUMP: return "JUMP"; // jump
|
||||
|
@ -1026,6 +1030,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
case AB_BOOL:
|
||||
case AB_STRING:
|
||||
case AB_C4ID:
|
||||
case AB_NIL:
|
||||
case AB_VARN_R:
|
||||
case AB_VARN_V:
|
||||
case AB_PARN_R:
|
||||
|
@ -1122,7 +1127,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
}
|
||||
|
||||
// Use stack operation instead of 0-Int (enable optimization)
|
||||
if((eType == AB_INT || eType == AB_BOOL) && !X)
|
||||
if(eType == AB_NIL)
|
||||
{
|
||||
eType = AB_STACK;
|
||||
X = 1;
|
||||
|
@ -1253,6 +1258,7 @@ const char * C4AulParseState::GetTokenName(C4AulTokenType TokenType)
|
|||
case ATT_BOOL: return "boolean constant";
|
||||
case ATT_STRING: return "string constant";
|
||||
case ATT_C4ID: return "id constant";
|
||||
case ATT_NIL: return "nil";
|
||||
case ATT_COMMA: return "','";
|
||||
case ATT_COLON: return "':'";
|
||||
case ATT_DCOLON: return "'::'";
|
||||
|
@ -2265,7 +2271,7 @@ void C4AulParseState::Parse_Array()
|
|||
// [] -> size 0, [*,] -> size 2, [*,*,] -> size 3
|
||||
if (size > 0)
|
||||
{
|
||||
AddBCC(AB_INT);
|
||||
AddBCC(AB_NIL);
|
||||
++size;
|
||||
}
|
||||
fDone = true;
|
||||
|
@ -2273,8 +2279,8 @@ void C4AulParseState::Parse_Array()
|
|||
}
|
||||
case ATT_COMMA:
|
||||
{
|
||||
// got no parameter before a ","? then push a 0-constant
|
||||
AddBCC(AB_INT);
|
||||
// got no parameter before a ","? then push nil
|
||||
AddBCC(AB_NIL);
|
||||
Shift();
|
||||
++size;
|
||||
break;
|
||||
|
@ -2647,6 +2653,7 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
AddBCC(AB_STRING, reinterpret_cast<intptr_t>(val._getStr()));
|
||||
break;
|
||||
case C4V_C4ID: AddBCC(AB_C4ID, val.GetData().Int); break;
|
||||
case C4V_Nil: AddBCC(AB_NIL); break;
|
||||
case C4V_Any:
|
||||
// any: allow zero; add it as int
|
||||
if (!val.GetData())
|
||||
|
@ -2703,6 +2710,12 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
Shift();
|
||||
break;
|
||||
}
|
||||
case ATT_NIL:
|
||||
{
|
||||
AddBCC(AB_NIL);
|
||||
Shift();
|
||||
break;
|
||||
}
|
||||
case ATT_OPERATOR:
|
||||
{
|
||||
// -> must be a prefix operator
|
||||
|
@ -2808,7 +2821,7 @@ void C4AulParseState::Parse_Expression2(int iParentPrio)
|
|||
{
|
||||
switch (TokenType)
|
||||
{
|
||||
case ATT_IDTF: case ATT_INT: case ATT_BOOL: case ATT_STRING: case ATT_C4ID:
|
||||
case ATT_IDTF: case ATT_INT: case ATT_BOOL: case ATT_STRING: case ATT_C4ID: case ATT_NIL:
|
||||
case ATT_OPERATOR: case ATT_BOPEN: case ATT_BOPEN2:
|
||||
Parse_Expression(C4ScriptOpMap[OpID].Priority);
|
||||
// If the operator does not modify the second argument, no reference is necessary
|
||||
|
@ -3085,6 +3098,7 @@ void C4AulParseState::Parse_Const()
|
|||
case ATT_BOOL: vGlobalValue.SetBool(!!cInt); break;
|
||||
case ATT_STRING: vGlobalValue.SetString(reinterpret_cast<C4String *>(cInt)); break; // increases ref count of C4String in cInt to 1
|
||||
case ATT_C4ID: vGlobalValue.SetC4ID(cInt); break;
|
||||
case ATT_NIL: vGlobalValue.Set0(); break;
|
||||
case ATT_IDTF:
|
||||
// identifier is only OK if it's another constant
|
||||
if (!a->Engine->GetGlobalConstant(Idtf, &vGlobalValue))
|
||||
|
|
|
@ -6887,6 +6887,7 @@ C4ScriptConstDef C4ScriptConstMap[]={
|
|||
{ "C4V_C4Object" ,C4V_Int, C4V_C4Object},
|
||||
{ "C4V_String" ,C4V_Int, C4V_String},
|
||||
{ "C4V_Array" ,C4V_Int, C4V_Array},
|
||||
{ "C4V_Nil" ,C4V_Int, C4V_Nil},
|
||||
|
||||
{ "COMD_None" ,C4V_Int, COMD_None},
|
||||
{ "COMD_Stop" ,C4V_Int, COMD_Stop},
|
||||
|
|
|
@ -108,7 +108,7 @@ void C4Value::Set(C4V_Data nData, C4V_Type nType)
|
|||
|
||||
// change
|
||||
Data = nData;
|
||||
Type = nData ? nType : C4V_Any;
|
||||
Type = nData || nType == C4V_Int || nType == C4V_Bool ? nType : C4V_Nil;
|
||||
|
||||
// hold
|
||||
AddDataRef();
|
||||
|
@ -124,7 +124,7 @@ void C4Value::Set0()
|
|||
|
||||
// change
|
||||
Data = 0;
|
||||
Type = C4V_Any;
|
||||
Type = C4V_Nil;
|
||||
|
||||
// clean up (save even if Data was 0 before)
|
||||
DelDataRef(oData, oType, HasBaseArray ? NULL : NextRef, HasBaseArray ? BaseArray : NULL);
|
||||
|
@ -295,6 +295,8 @@ const char* GetC4VName(const C4V_Type Type)
|
|||
return "array";
|
||||
case C4V_pC4Value:
|
||||
return "&";
|
||||
case C4V_Nil:
|
||||
return "nil";
|
||||
default:
|
||||
return "!Fehler!";
|
||||
}
|
||||
|
@ -322,6 +324,8 @@ char GetC4VID(const C4V_Type Type)
|
|||
return 'O';
|
||||
case C4V_Array:
|
||||
return 'a';
|
||||
case C4V_Nil:
|
||||
return 'n';
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
|
@ -348,6 +352,8 @@ C4V_Type GetC4VFromID(const char C4VID)
|
|||
return C4V_C4ObjectEnum;
|
||||
case 'a':
|
||||
return C4V_Array;
|
||||
case 'n':
|
||||
return C4V_Nil;
|
||||
}
|
||||
return C4V_Any;
|
||||
}
|
||||
|
@ -424,6 +430,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] = {
|
|||
{ CnvGuess }, // String
|
||||
{ CnvGuess }, // Array
|
||||
{ CnvError }, // pC4Value
|
||||
{ CnvOK }, // Nil
|
||||
},
|
||||
{ // C4V_Int
|
||||
{ CnvOK }, // any
|
||||
|
@ -434,6 +441,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] = {
|
|||
{ CnvError }, // String NEVER!
|
||||
{ CnvError }, // Array NEVER!
|
||||
{ CnvError }, // pC4Value
|
||||
{ CnvOK }, // Nil
|
||||
},
|
||||
{ // C4V_Bool
|
||||
{ CnvOK }, // any
|
||||
|
@ -444,6 +452,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] = {
|
|||
{ CnvError }, // String NEVER!
|
||||
{ CnvError }, // Array NEVER!
|
||||
{ CnvError }, // pC4Value
|
||||
{ CnvOK }, // Nil
|
||||
},
|
||||
{ // C4V_C4ID
|
||||
{ CnvOK }, // any
|
||||
|
@ -454,6 +463,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] = {
|
|||
{ CnvError }, // String NEVER!
|
||||
{ CnvError }, // Array NEVER!
|
||||
{ CnvError }, // pC4Value
|
||||
{ CnvOK }, // Nil
|
||||
},
|
||||
{ // C4V_Object
|
||||
{ CnvOK }, // any
|
||||
|
@ -464,6 +474,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] = {
|
|||
{ CnvError }, // String NEVER!
|
||||
{ CnvError }, // Array NEVER!
|
||||
{ CnvError }, // pC4Value
|
||||
{ CnvOK }, // Nil
|
||||
},
|
||||
{ // C4V_String
|
||||
{ CnvOK }, // any
|
||||
|
@ -474,6 +485,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] = {
|
|||
{ CnvOK }, // String same
|
||||
{ CnvError }, // Array NEVER!
|
||||
{ CnvError }, // pC4Value
|
||||
{ CnvOK }, // Nil
|
||||
},
|
||||
{ // C4V_Array
|
||||
{ CnvOK }, // any
|
||||
|
@ -484,6 +496,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] = {
|
|||
{ CnvError }, // String NEVER!
|
||||
{ CnvOK }, // Array same
|
||||
{ CnvError }, // pC4Value NEVER!
|
||||
{ CnvOK }, // Nil
|
||||
},
|
||||
{ // C4V_pC4Value - resolve reference and retry type check
|
||||
{ CnvDeref }, // any
|
||||
|
@ -494,6 +507,18 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] = {
|
|||
{ CnvDeref }, // String
|
||||
{ CnvDeref }, // Array
|
||||
{ CnvOK }, // pC4Value same
|
||||
{ CnvOK }, // Nil
|
||||
},
|
||||
{ // C4V_Nil
|
||||
{ CnvOK }, // any
|
||||
{ CnvOK }, // int
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvOK }, // C4ID
|
||||
{ CnvOK }, // C4Object
|
||||
{ CnvOK }, // String
|
||||
{ CnvOK }, // Array
|
||||
{ CnvError}, // pC4Value
|
||||
{ CnvOK }, // Nil same
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -548,6 +573,8 @@ StdStrBuf C4Value::GetDataString()
|
|||
DataString.AppendChar(']');
|
||||
return DataString;
|
||||
}
|
||||
case C4V_Nil:
|
||||
return StdStrBuf("nil");
|
||||
default:
|
||||
return StdStrBuf("-unknown type- ");
|
||||
}
|
||||
|
@ -596,7 +623,7 @@ void C4Value::DenumeratePointer()
|
|||
}
|
||||
// object: invalid value - set to zero
|
||||
else
|
||||
Set(0);
|
||||
Set0();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,7 +645,7 @@ void C4Value::CompileFunc(StdCompiler *pComp)
|
|||
else
|
||||
{
|
||||
// Clear
|
||||
Set(0);
|
||||
Set0();
|
||||
// Read type
|
||||
char cC4VID;
|
||||
try
|
||||
|
@ -712,6 +739,9 @@ void C4Value::CompileFunc(StdCompiler *pComp)
|
|||
// shouldn't happen
|
||||
case C4V_pC4Value:
|
||||
|
||||
case C4V_Nil:
|
||||
// doesn't have a value, so nothing to store
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
|
@ -775,6 +805,8 @@ bool C4Value::operator == (const C4Value& Value2) const
|
|||
return Type == Value2.Type && Data.Str->Data == Value2.Data.Str->Data;
|
||||
case C4V_Array:
|
||||
return Type == Value2.Type && *(Data.Array) == *(Value2.Data.Array);
|
||||
case C4V_Nil:
|
||||
return Type == Value2.Type;
|
||||
default:
|
||||
// C4AulExec should have dereferenced both values, no need to implement comparison here
|
||||
return Data == Value2.Data;
|
||||
|
|
Loading…
Reference in New Issue