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
Nicolas Hake 2009-07-17 04:50:50 +02:00
parent 7ab01aac9c
commit 383b263181
6 changed files with 74 additions and 21 deletions

View File

@ -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

View File

@ -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);

View File

@ -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");

View File

@ -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))

View File

@ -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},

View File

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