Skip to content

Commit ed77f5e

Browse files
committed
make code completion on dynamic trait properties work
1 parent 58d411c commit ed77f5e

12 files changed

Lines changed: 125 additions & 6 deletions

EidosScribe/EidosTextView.mm

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,7 +2005,7 @@ - (NSMutableArray *)completionsForKeyPathEndingInTokenIndex:(int)lastDotTokenInd
20052005
else
20062006
{
20072007
// We have a property; look up its signature and get the class
2008-
const EidosPropertySignature *property_signature = key_path_class->SignatureForProperty(identifier_id);
2008+
const EidosPropertySignature *property_signature = key_path_class->SignatureForProperty_TYPE_INTERPRETER(identifier_id);
20092009

20102010
if (!property_signature)
20112011
return nil; // no signature, so the class does not support the property given
@@ -2023,7 +2023,7 @@ - (NSMutableArray *)completionsForKeyPathEndingInTokenIndex:(int)lastDotTokenInd
20232023
const EidosClass *terminus = key_path_class;
20242024

20252025
// First, a sorted list of globals
2026-
for (auto symbol_sig : *terminus->Properties())
2026+
for (auto symbol_sig : terminus->Properties_TYPE_INTERPRETER())
20272027
{
20282028
if (!symbol_sig->deprecated_)
20292029
[candidates addObject:[NSString stringWithUTF8String:symbol_sig->property_name_.c_str()]];
@@ -2337,6 +2337,9 @@ - (void)_completionHandlerWithRangeForCompletion:(NSRange *)baseRange completion
23372337
std::cout << "Eidos AST:\n" << parse_stream.str() << std::endl << std::endl;
23382338
#endif
23392339

2340+
// Clear out dynamic property signatures kept by EidosClass, since we're starting a new type-interpretation pass.
2341+
EidosClass::ClearDynamicSignatures();
2342+
23402343
EidosTypeInterpreter typeInterpreter(script, *typeTablePtr, *functionMapPtr, *callTypeTablePtr);
23412344

23422345
typeInterpreter.TypeEvaluateInterpreterBlock_AddArgumentCompletions(&argumentCompletions, script_string.length()); // result not used

QtSLiM/QtSLiMScriptTextEdit.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,7 @@ QStringList QtSLiMTextEdit::completionsForKeyPathEndingInTokenIndexOfTokenStream
15681568
else
15691569
{
15701570
// We have a property; look up its signature and get the class
1571-
const EidosPropertySignature *property_signature = key_path_class->SignatureForProperty(identifier_id);
1571+
const EidosPropertySignature *property_signature = key_path_class->SignatureForProperty_TYPE_INTERPRETER(identifier_id);
15721572

15731573
if (!property_signature)
15741574
return QStringList(); // no signature, so the class does not support the property given
@@ -1586,7 +1586,7 @@ QStringList QtSLiMTextEdit::completionsForKeyPathEndingInTokenIndexOfTokenStream
15861586
const EidosClass *terminus = key_path_class;
15871587

15881588
// First, a sorted list of globals
1589-
for (const auto &symbol_sig : *terminus->Properties())
1589+
for (const auto &symbol_sig : terminus->Properties_TYPE_INTERPRETER())
15901590
{
15911591
if (!symbol_sig->deprecated_)
15921592
candidates << QString::fromStdString(symbol_sig->property_name_);
@@ -2345,6 +2345,9 @@ void QtSLiMTextEdit::_completionHandlerWithRangeForCompletion(NSRange *baseRange
23452345
script.Tokenize(true, false); // make bad tokens as needed, do not keep nonsignificant tokens
23462346
script.ParseInterpreterBlockToAST(true, true); // make bad nodes as needed (i.e. never raise, and produce a correct tree)
23472347

2348+
// Clear out dynamic property signatures kept by EidosClass, since we're starting a new type-interpretation pass.
2349+
EidosClass::ClearDynamicSignatures();
2350+
23482351
EidosTypeInterpreter typeInterpreter(script, *typeTablePtr, *functionMapPtr, *callTypeTablePtr);
23492352

23502353
typeInterpreter.TypeEvaluateInterpreterBlock_AddArgumentCompletions(&argumentCompletions, script_string.length()); // result not used

VERSIONS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ multitrait branch:
5656
draw an individual's trait offsets from the trait individual-offset distributions, at the individual's moment of generation
5757
add Individual properties for each trait in the individual's species, allowing direct access to the phenotype for each trait in an individual
5858
add Species properties for each trait in the species, allowing direct access to traits in this species
59+
make code completion work for the new dynamic properties on Species and Individual generated by initializeTrait()
5960

6061

6162
version 5.1 (Eidos version 4.1):

core/slim_eidos_block.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,9 @@ const std::vector<EidosPropertySignature_CSP> *SLiMEidosBlock_Class::Properties(
18071807
}
18081808

18091809

1810+
#ifdef EIDOS_GUI
1811+
// SLiMTypeTable and SLiMTypeInterpreter are only used in SLiMgui and QtSLiM
1812+
18101813
//
18111814
// SLiMTypeTable
18121815
//
@@ -1996,6 +1999,25 @@ EidosTypeSpecifier SLiMTypeInterpreter::_TypeEvaluate_FunctionCall_Internal(std:
19961999
{
19972000
_SetTypeForISArgumentOfClass(p_arguments[0], 'i', gSLiM_InteractionType_Class);
19982001
}
2002+
else if ((p_function_name == "initializeTrait") && (argument_count >= 1))
2003+
{
2004+
EidosASTNode *trait_name_node = p_arguments[0];
2005+
const EidosToken *trait_name_token = trait_name_node->token_;
2006+
2007+
if (trait_name_token->token_type_ == EidosTokenType::kTokenString)
2008+
{
2009+
// initializeTrait() has the side effect of defining dynamic properties on Species and Individual;
2010+
// we need to set up the information needed to make that work with code completion; we do that
2011+
// with AddSignatureForProperty_TYPE_INTERPRETER(), a version of AddSignatureForProperty() that
2012+
// uses scratch space belonging only to us, so we don't interfere with anything in SLiM itself.
2013+
const std::string &trait_name = trait_name_token->token_string_;
2014+
EidosPropertySignature_CSP species_signature((new EidosPropertySignature(trait_name, true, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Trait_Class))->MarkAsDynamicWithOwner("Trait"));
2015+
EidosPropertySignature_CSP individual_signature((new EidosPropertySignature(trait_name, false, kEidosValueMaskFloat | kEidosValueMaskSingleton))->MarkAsDynamicWithOwner("Trait"));
2016+
2017+
gSLiM_Species_Class->AddSignatureForProperty_TYPE_INTERPRETER(species_signature);
2018+
gSLiM_Individual_Class->AddSignatureForProperty_TYPE_INTERPRETER(individual_signature);
2019+
}
2020+
}
19992021

20002022
return ret;
20012023
}
@@ -2053,6 +2075,7 @@ EidosTypeSpecifier SLiMTypeInterpreter::_TypeEvaluate_MethodCall_Internal(const
20532075
return ret;
20542076
}
20552077

2078+
#endif // EIDOS_GUI
20562079

20572080

20582081

core/slim_eidos_block.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ class SLiMEidosBlock_Class : public EidosClass
255255
virtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;
256256
};
257257

258+
#ifdef EIDOS_GUI
259+
// SLiMTypeTable and SLiMTypeInterpreter are only used in SLiMgui and QtSLiM
258260

259261
#pragma mark -
260262
#pragma mark SLiMTypeTable
@@ -311,6 +313,7 @@ class SLiMTypeInterpreter : public EidosTypeInterpreter
311313
virtual EidosTypeSpecifier _TypeEvaluate_MethodCall_Internal(const EidosClass *p_target, const EidosMethodSignature *p_method_signature, const std::vector<EidosASTNode *> &p_arguments) override;
312314
};
313315

316+
#endif // EIDOS_GUI
314317

315318
#endif /* defined(__SLiM__slim_script_block__) */
316319

core/species_eidos.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,7 @@ EidosValue_SP Species::ExecuteContextFunction_initializeTrait(const std::string
17121712
}
17131713
else
17141714
{
1715+
// see also SLiMTypeInterpreter::_TypeEvaluate_FunctionCall_Internal(), which also tracks this
17151716
EidosPropertySignature_CSP signature((new EidosPropertySignature(name, true, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Trait_Class))->MarkAsDynamicWithOwner("Trait"));
17161717

17171718
gSLiM_Species_Class->AddSignatureForProperty(signature);
@@ -1731,7 +1732,8 @@ EidosValue_SP Species::ExecuteContextFunction_initializeTrait(const std::string
17311732
}
17321733
else
17331734
{
1734-
EidosPropertySignature_CSP signature((new EidosPropertySignature(name, false, kEidosValueMaskFloat | kEidosValueMaskSingleton, gSLiM_Trait_Class))->MarkAsDynamicWithOwner("Trait"));
1735+
// see also SLiMTypeInterpreter::_TypeEvaluate_FunctionCall_Internal(), which also tracks this
1736+
EidosPropertySignature_CSP signature((new EidosPropertySignature(name, false, kEidosValueMaskFloat | kEidosValueMaskSingleton))->MarkAsDynamicWithOwner("Trait"));
17351737

17361738
gSLiM_Individual_Class->AddSignatureForProperty(signature);
17371739
}

eidos/eidos_class_Object.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,57 @@ EidosValue_SP EidosClass::ExecuteMethod_size_length(EidosGlobalStringID p_method
746746
}
747747

748748

749+
#ifdef EIDOS_GUI
750+
// We provide some support here for EidosTypeInterpreter to make code completion work with dynamic properties
751+
752+
void EidosClass::ClearDynamicSignatures(void)
753+
{
754+
std::vector<EidosClass *> classes = EidosClass::RegisteredClasses(/* p_builtin */ true, /* p_context */ true);
755+
756+
for (EidosClass *one_class : classes)
757+
one_class->dynamic_property_signatures_.clear();
758+
}
759+
760+
void EidosClass::AddSignatureForProperty_TYPE_INTERPRETER(EidosPropertySignature_CSP p_property_signature)
761+
{
762+
// if a dynamic property already exists with the given name, we assume it is the same, and just return
763+
for (EidosPropertySignature_CSP dynamic_property : dynamic_property_signatures_)
764+
if (dynamic_property->property_id_ == p_property_signature->property_id_)
765+
return;
766+
767+
dynamic_property_signatures_.push_back(p_property_signature);
768+
}
769+
770+
// This calls Properties() to get the built-in properties, and then adds the dynamic ones
771+
std::vector<EidosPropertySignature_CSP> EidosClass::Properties_TYPE_INTERPRETER(void) const
772+
{
773+
std::vector<EidosPropertySignature_CSP> properties = *Properties(); // make a local copy for ourselves to modify
774+
775+
for (EidosPropertySignature_CSP dynamic_property : dynamic_property_signatures_)
776+
properties.push_back(dynamic_property);
777+
778+
std::sort(properties.begin(), properties.end(), CompareEidosPropertySignatures);
779+
780+
return properties;
781+
}
782+
783+
// This calls SignatureForProperty(), and then checks the dynamic ones if that failed
784+
const EidosPropertySignature *EidosClass::SignatureForProperty_TYPE_INTERPRETER(EidosGlobalStringID p_property_id) const
785+
{
786+
const EidosPropertySignature *signature = SignatureForProperty(p_property_id);
787+
788+
if (signature)
789+
return signature;
790+
791+
for (EidosPropertySignature_CSP dynamic_property : dynamic_property_signatures_)
792+
if (dynamic_property->property_id_ == p_property_id)
793+
return dynamic_property.get();
794+
795+
return nullptr;
796+
}
797+
798+
#endif // EIDOS_GUI
799+
749800

750801

751802

eidos/eidos_class_Object.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,25 @@ class EidosClass
209209
EidosValue_SP ExecuteMethod_propertySignature(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;
210210
EidosValue_SP ExecuteMethod_methodSignature(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;
211211
EidosValue_SP ExecuteMethod_size_length(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;
212+
213+
#ifdef EIDOS_GUI
214+
// We provide some support here for EidosTypeInterpreter to make code completion work with dynamic properties
215+
216+
// This is scratch space for dynamic property signatures generated as a side effect of type-interpretation
217+
std::vector<EidosPropertySignature_CSP> dynamic_property_signatures_;
218+
219+
// This clears out dynamic_property_signatures_ for all registered classes, to reset type-interpreter state.
220+
static void ClearDynamicSignatures(void);
221+
222+
// This adds a signature to the EidosTypeInterpreter scratch space above
223+
void AddSignatureForProperty_TYPE_INTERPRETER(EidosPropertySignature_CSP p_property_signature);
224+
225+
// This calls Properties() to get the built-in properties, and then adds the dynamic ones
226+
std::vector<EidosPropertySignature_CSP> Properties_TYPE_INTERPRETER(void) const;
227+
228+
// This calls SignatureForProperty(), and then checks the dynamic ones if that failed
229+
const EidosPropertySignature *SignatureForProperty_TYPE_INTERPRETER(EidosGlobalStringID p_property_id) const;
230+
#endif // EIDOS_GUI
212231
};
213232

214233

eidos/eidos_symbol_table.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,8 @@ void EidosSymbolTable::PrintSymbolTableChain(std::ostream &p_outstream)
844844
p_outstream << "================================================" << std::endl;
845845
}
846846

847+
#ifdef EIDOS_GUI
848+
// EidosTypeTable and EidosTypeInterpreter are only used in EidosScribe, SLiMguiLegacy, and QtSLiM
847849
void EidosSymbolTable::AddSymbolsToTypeTable(EidosTypeTable *p_type_table) const
848850
{
849851
// recurse to get the symbols from our chained symbol table
@@ -863,6 +865,7 @@ void EidosSymbolTable::AddSymbolsToTypeTable(EidosTypeTable *p_type_table) const
863865
symbol = slot->next_;
864866
}
865867
}
868+
#endif // EIDOS_GUI
866869

867870
// This stream output method for EidosSymbolTable dumps all available symbols
868871
std::ostream &operator<<(std::ostream &p_outstream, const EidosSymbolTable &p_symbols)

eidos/eidos_symbol_table.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,11 @@ class EidosSymbolTable
217217
void PrintSymbolTable(std::ostream &p_outstream);
218218
void PrintSymbolTableChain(std::ostream &p_outstream);
219219

220+
#ifdef EIDOS_GUI
221+
// EidosTypeTable and EidosTypeInterpreter are only used in EidosScribe, SLiMguiLegacy, and QtSLiM
220222
// A utility method to add entries for defined symbols into an EidosTypeTable
221223
void AddSymbolsToTypeTable(EidosTypeTable *p_type_table) const;
224+
#endif // EIDOS_GUI
222225

223226
// Direct access to the symbol table chain. This should only be necessary for clients that are manipulating
224227
// the symbol table chain themselves in some way, since normally the chain is encapsulated by this class.

0 commit comments

Comments
 (0)