Skip to content

Commit 7bcbea7

Browse files
committed
[parser] Implement mixed-type arrays at last, albeit with a change to syntax. Also refactor array related code.
1 parent b5b17ea commit 7bcbea7

File tree

7 files changed

+198
-83
lines changed

7 files changed

+198
-83
lines changed

changes.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ Changed Behaviour
6161
for now, due to their orientation being poorly defined.
6262
- An age-old bug in the inbuilt `f_enneper` isosurface function has been
6363
fixed; the function now results in the originally intended shape.
64+
- Contrary to earlier claims and intentions, v3.7.1-beta.1 failed to lift the
65+
requirement that array elements must be of the same type. It has been
66+
decided to not fix the change to work as originally intended, and instead
67+
only allow type mixing if the array has explicitly been declared as
68+
`mixed`. See the documentation for details.
6469

6570
New Features
6671
------------

source/parser/parser.cpp

Lines changed: 135 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8501,6 +8501,18 @@ bool Parser::Parse_Comma (void)
85018501

85028502
//******************************************************************************
85038503

8504+
bool Parser::AllowToken(TOKEN tokenId)
8505+
{
8506+
Get_Token();
8507+
bool tokenMatches = ((Token.Token_Id == tokenId) ||
8508+
(Token.Function_Id == tokenId));
8509+
if (!tokenMatches)
8510+
Unget_Token();
8511+
return tokenMatches;
8512+
}
8513+
8514+
//******************************************************************************
8515+
85048516
bool Parser::Peek_Token (TOKEN tokenId)
85058517
{
85068518
Get_Token();
@@ -8743,33 +8755,42 @@ void Parser::Parse_Declare(bool is_local, bool after_hash)
87438755
CASE (IDENTIFIER_TOKEN)
87448756
POV_PARSER_ASSERT(!Token.is_array_elem || Token.is_mixed_array_elem);
87458757
allow_redefine = true; // should actually be irrelevant downstream, thanks to Previous==IDENTIFIER_TOKEN
8746-
if (Token.is_array_elem || Token.is_dictionary_elem)
8758+
if (Token.is_array_elem)
87478759
{
8748-
if (is_local && (Token.context != Table_Index))
8749-
Error ("Cannot use '#local' to assign a non-local array or dictionary element.");
8750-
Temp_Entry = Add_Symbol (Token.table, Token.Token_String, IDENTIFIER_TOKEN);
8760+
numberPtr = Token.NumberPtr;
8761+
dataPtr = Token.DataPtr;
8762+
Previous = Token.Token_Id;
87518763
}
87528764
else
8753-
Temp_Entry = Add_Symbol (Local_Index, Token.Token_String, IDENTIFIER_TOKEN);
8754-
numberPtr = &(Temp_Entry->Token_Number);
8755-
dataPtr = &(Temp_Entry->Data);
8756-
Previous = Token.Token_Id;
8757-
if (deprecated)
87588765
{
8759-
Temp_Entry->deprecated = true;;
8760-
if (deprecated_once)
8761-
Temp_Entry->deprecatedOnce = true;
8762-
if (deprecation_message != nullptr)
8766+
if (Token.is_dictionary_elem)
87638767
{
8764-
UCS2String str(deprecation_message);
8765-
POV_FREE(deprecation_message);
8766-
Temp_Entry->Deprecation_Message = POV_STRDUP(UCS2toASCIIString(str).c_str());
8768+
if (is_local && (Token.context != Table_Index))
8769+
Error("Cannot use '#local' to assign a non-local array or dictionary element.");
8770+
Temp_Entry = Add_Symbol(Token.table, Token.Token_String, IDENTIFIER_TOKEN);
87678771
}
87688772
else
8773+
Temp_Entry = Add_Symbol(Local_Index, Token.Token_String, IDENTIFIER_TOKEN);
8774+
numberPtr = &(Temp_Entry->Token_Number);
8775+
dataPtr = &(Temp_Entry->Data);
8776+
Previous = Token.Token_Id;
8777+
if (deprecated)
87698778
{
8770-
char str[256];
8771-
sprintf(str, "Identifier '%.128s' was declared deprecated.", Token.Token_String);
8772-
Temp_Entry->Deprecation_Message = POV_STRDUP(str);
8779+
Temp_Entry->deprecated = true;;
8780+
if (deprecated_once)
8781+
Temp_Entry->deprecatedOnce = true;
8782+
if (deprecation_message != nullptr)
8783+
{
8784+
UCS2String str(deprecation_message);
8785+
POV_FREE(deprecation_message);
8786+
Temp_Entry->Deprecation_Message = POV_STRDUP(UCS2toASCIIString(str).c_str());
8787+
}
8788+
else
8789+
{
8790+
char str[256];
8791+
sprintf(str, "Identifier '%.128s' was declared deprecated.", Token.Token_String);
8792+
Temp_Entry->Deprecation_Message = POV_STRDUP(str);
8793+
}
87738794
}
87748795
}
87758796
END_CASE
@@ -8952,14 +8973,16 @@ void Parser::Parse_Declare(bool is_local, bool after_hash)
89528973
(rvalue->Token_Number != ARRAY_ID_TOKEN))
89538974
Expectation_Error("array RValue");
89548975
POV_ARRAY *a = reinterpret_cast<POV_ARRAY *>(rvalue->Data);
8955-
if (lvalues.size() > a->DataPtrs.size())
8976+
if (a->maxDim != 0)
8977+
Error ("cannot bulk-assign from multi-dimensional array");
8978+
if (lvalues.size() > a->Sizes[0])
89568979
Error ("array size mismatch");
89578980
if (a->DataPtrs.empty())
89588981
Error ("cannot assign from uninitialized array");
89598982

89608983
for (int i = 0; i < lvalues.size(); ++i)
89618984
{
8962-
if (a->DataPtrs[i] == nullptr)
8985+
if (!a->HasElement(i))
89638986
Error ("cannot assign from partially uninitialized array");
89648987

89658988
numberPtr = lvalues[i].numberPtr;
@@ -8968,9 +8991,9 @@ void Parser::Parse_Declare(bool is_local, bool after_hash)
89688991
Temp_Entry = lvalues[i].symEntry;
89698992
allow_redefine = lvalues[i].allowRedefine;
89708993

8971-
*numberPtr = a->Type;
8994+
*numberPtr = a->ElementType(i);
89728995
Test_Redefine(Previous, numberPtr, *dataPtr, allow_redefine);
8973-
*dataPtr = Copy_Identifier(a->DataPtrs[i], a->Type);
8996+
*dataPtr = Copy_Identifier(a->DataPtrs[i], a->ElementType(i));
89748997
}
89758998

89768999
Destroy_Entry (rvalue, false);
@@ -9609,16 +9632,8 @@ void Parser::Destroy_Ident_Data(void *Data, int Type)
96099632
break;
96109633
case ARRAY_ID_TOKEN:
96119634
a = reinterpret_cast<POV_ARRAY *>(Data);
9612-
if(!a->DataPtrs.empty())
9613-
{
9614-
for(i=0; i<a->DataPtrs.size(); i++)
9615-
{
9616-
if (a->Types.empty())
9617-
Destroy_Ident_Data (a->DataPtrs[i], a->Type);
9618-
else
9619-
Destroy_Ident_Data (a->DataPtrs[i], a->Types[i]);
9620-
}
9621-
}
9635+
for (i = 0; i < a->DataPtrs.size(); ++i)
9636+
Destroy_Ident_Data(a->DataPtrs[i], a->ElementType(i));
96229637
delete a;
96239638
break;
96249639
case DICTIONARY_ID_TOKEN:
@@ -10579,7 +10594,7 @@ void Parser::Set_CSG_Tree_Flag(ObjectPtr Object, unsigned int f, int val)
1057910594

1058010595
void *Parser::Copy_Identifier (void *Data, int Type)
1058110596
{
10582-
int i;
10597+
size_t i;
1058310598
POV_ARRAY *a, *na;
1058410599
Vector3d *vp;
1058510600
DBL *dp;
@@ -10683,23 +10698,19 @@ void *Parser::Copy_Identifier (void *Data, int Type)
1068310698
case ARRAY_ID_TOKEN:
1068410699
a = reinterpret_cast<POV_ARRAY *>(Data);
1068510700
na = new POV_ARRAY;
10686-
na->Dims = a->Dims;
10687-
na->Type = a->Type;
10701+
na->maxDim = a->maxDim;
10702+
na->Type_ = a->Type_;
1068810703
na->resizable = a->resizable;
10689-
for (i = 0; i < 5; ++i)
10704+
na->mixedType = a->mixedType;
10705+
for (i = 0; i < POV_ARRAY::kMaxDimensions; ++i)
1069010706
{
1069110707
na->Sizes[i] = a->Sizes[i];
1069210708
na->Mags[i] = a->Mags[i];
1069310709
}
1069410710
na->DataPtrs.resize(a->DataPtrs.size());
10695-
na->Types = a->Types;
1069610711
for (i=0; i<a->DataPtrs.size(); i++)
10697-
{
10698-
if (a->Types.empty())
10699-
na->DataPtrs[i] = reinterpret_cast<void *>(Copy_Identifier (a->DataPtrs[i],a->Type));
10700-
else
10701-
na->DataPtrs[i] = reinterpret_cast<void *>(Copy_Identifier (a->DataPtrs[i], a->Types[i]));
10702-
}
10712+
na->DataPtrs[i] = reinterpret_cast<void *>(Copy_Identifier(a->DataPtrs[i], a->ElementType(i)));
10713+
na->Types = a->Types;
1070310714
New = reinterpret_cast<void *>(na);
1070410715
break;
1070510716
case DICTIONARY_ID_TOKEN:
@@ -11198,4 +11209,84 @@ void Parser::SignalProgress(POV_LONG elapsedTime, POV_LONG tokenCount)
1119811209
RenderBackend::SendSceneOutput(backendSceneData->sceneId, backendSceneData->frontendAddress, kPOVMsgIdent_Progress, obj);
1119911210
}
1120011211

11212+
/*****************************************************************************/
11213+
11214+
bool Parser::POV_ARRAY::IsInitialized() const
11215+
{
11216+
POV_PARSER_ASSERT(resizable || !DataPtrs.empty());
11217+
return !DataPtrs.empty();
11218+
}
11219+
11220+
bool Parser::POV_ARRAY::HasElement(size_t i) const
11221+
{
11222+
return ((i < DataPtrs.size()) && (DataPtrs[i] != nullptr));
11223+
}
11224+
11225+
const int& Parser::POV_ARRAY::ElementType(size_t i) const
11226+
{
11227+
POV_PARSER_ASSERT(i < DataPtrs.size());
11228+
return (mixedType ? Types[i] : Type_);
11229+
}
11230+
11231+
int& Parser::POV_ARRAY::ElementType(size_t i)
11232+
{
11233+
POV_PARSER_ASSERT(i < DataPtrs.size());
11234+
return (mixedType ? Types[i] : Type_);
11235+
}
11236+
11237+
size_t Parser::POV_ARRAY::GetLinearSize() const
11238+
{
11239+
POV_PARSER_ASSERT(!resizable || ((maxDim == 0) && (Sizes[0] == DataPtrs.size())));
11240+
POV_PARSER_ASSERT(!mixedType || (Types.size() == DataPtrs.size()));
11241+
return DataPtrs.size();
11242+
}
11243+
11244+
void Parser::POV_ARRAY::Grow()
11245+
{
11246+
POV_PARSER_ASSERT(resizable && (maxDim == 0));
11247+
++Sizes[0];
11248+
DataPtrs.push_back(nullptr);
11249+
POV_PARSER_ASSERT(DataPtrs.size() == Sizes[0]);
11250+
if (mixedType)
11251+
{
11252+
Types.push_back(IDENTIFIER_TOKEN);
11253+
POV_PARSER_ASSERT(Types.size() == Sizes[0]);
11254+
}
11255+
}
11256+
11257+
void Parser::POV_ARRAY::GrowBy(size_t delta)
11258+
{
11259+
POV_PARSER_ASSERT(resizable && (maxDim == 0));
11260+
Sizes[0] += delta;
11261+
DataPtrs.insert(DataPtrs.end(), delta, nullptr);
11262+
if (mixedType)
11263+
{
11264+
Types.insert(Types.end(), delta, IDENTIFIER_TOKEN);
11265+
POV_PARSER_ASSERT(Types.size() == Sizes[0]);
11266+
}
11267+
}
11268+
11269+
void Parser::POV_ARRAY::GrowTo(size_t delta)
11270+
{
11271+
POV_PARSER_ASSERT(resizable && (maxDim == 0));
11272+
POV_PARSER_ASSERT(delta > Sizes[0]);
11273+
GrowBy(delta - Sizes[0]);
11274+
}
11275+
11276+
void Parser::POV_ARRAY::Shrink()
11277+
{
11278+
POV_PARSER_ASSERT(resizable && (maxDim == 0));
11279+
POV_PARSER_ASSERT(Sizes[0] > 0);
11280+
--Sizes[0];
11281+
POV_PARSER_ASSERT(DataPtrs.back() == nullptr);
11282+
DataPtrs.pop_back();
11283+
POV_PARSER_ASSERT(DataPtrs.size() == Sizes[0]);
11284+
if (mixedType)
11285+
{
11286+
POV_PARSER_ASSERT(Types.back() == IDENTIFIER_TOKEN);
11287+
Types.pop_back();
11288+
POV_PARSER_ASSERT(Types.size() == Sizes[0]);
11289+
}
11290+
}
11291+
1120111292
}

source/parser/parser.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,24 @@ class Parser : public SceneTask
289289

290290
struct POV_ARRAY
291291
{
292-
int Dims, Type;
293-
int Sizes[5];
294-
int Mags[5];
292+
static const int kMaxDimensions = 5;
293+
int maxDim; ///< Index of highest dimension.
294+
int Type_;
295+
int Sizes[kMaxDimensions];
296+
size_t Mags[kMaxDimensions];
295297
vector<void*> DataPtrs;
296298
vector<int> Types;
297-
bool resizable;
299+
bool resizable : 1;
300+
bool mixedType : 1;
301+
bool IsInitialized() const;
302+
bool HasElement(size_t i) const;
303+
const int& ElementType(size_t i) const;
304+
int& ElementType(size_t i);
305+
size_t GetLinearSize() const;
306+
void Grow();
307+
void GrowBy(size_t delta);
308+
void GrowTo(size_t delta);
309+
void Shrink();
298310
};
299311

300312
struct POV_PARAM
@@ -337,6 +349,7 @@ class Parser : public SceneTask
337349
inline bool Parse_Square_Begin (bool mandatory = true) { return Parse_Begin(LEFT_SQUARE_TOKEN, mandatory); }
338350
inline void Parse_Square_End (void) { Parse_End(RIGHT_SQUARE_TOKEN); }
339351
bool Parse_Comma (void);
352+
bool AllowToken(TOKEN TokenId);
340353
bool Peek_Token (TOKEN tokenId);
341354
void Parse_Semi_Colon (bool force_semicolon);
342355
void Destroy_Frame (void);
@@ -765,7 +778,7 @@ class Parser : public SceneTask
765778
void Return_From_Macro(void);
766779
void Add_Entry (SYM_TABLE *table, SYM_ENTRY *Table_Entry);
767780
void Add_Entry (int Index,SYM_ENTRY *Table_Entry);
768-
void Parse_Initalizer (int Sub, int Base, POV_ARRAY *a);
781+
void Parse_Initalizer (int Sub, size_t Base, POV_ARRAY *a);
769782

770783
void Parse_Fopen(void);
771784
void Parse_Fclose(void);

source/parser/parser_expressions.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms)
10891089
Parse_Paren_Begin();
10901090
GET(ARRAY_ID_TOKEN)
10911091
a = reinterpret_cast<POV_ARRAY *>(*(Token.DataPtr));
1092-
Val = a->Dims+1;
1092+
Val = a->maxDim + 1;
10931093
Parse_Paren_End();
10941094
break;
10951095

@@ -1098,9 +1098,12 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms)
10981098
GET(ARRAY_ID_TOKEN)
10991099
Parse_Comma();
11001100
a = reinterpret_cast<POV_ARRAY *>(*(Token.DataPtr));
1101-
i = (int)Parse_Float()-1.0;
1102-
if ((i < 0) || (i > a->Dims))
1101+
i = (int)Parse_Float()-1;
1102+
if ((i < 0) || (i > a->maxDim))
1103+
{
1104+
Warning("Querying size of dimension %d in %d-dimensional array.", i + 1, a->maxDim + 1);
11031105
Val = 0.0;
1106+
}
11041107
else
11051108
Val = a->Sizes[i];
11061109
Parse_Paren_End();

0 commit comments

Comments
 (0)