• R/O
  • SSH
  • HTTPS

eircompile: Commit


Commit MetaInfo

Revision60 (tree)
Time2021-12-16 09:08:44
Authorquiret

Log Message

- fleshed out COS some more
- added StepReplacementPoint which is used to replace existing steps so that graphs do not have to cloned in case of partial modification requirements for correctness + unit test

Change Summary

Incremental Difference

--- eircompile/include/eircompile/lexing.h (revision 59)
+++ eircompile/include/eircompile/lexing.h (revision 60)
@@ -32,7 +32,8 @@
3232 concept CompilationTargetStep = (
3333 std::derived_from <typename std::remove_cvref <cStepType>::type, typename envType::StepAlternatives> ||
3434 std::derived_from <typename std::remove_cvref <cStepType>::type, typename envType::StepProceduralAlternatives> ||
35- std::derived_from <typename std::remove_cvref <cStepType>::type, typename envType::StepProceduralSequence>
35+ std::derived_from <typename std::remove_cvref <cStepType>::type, typename envType::StepProceduralSequence> ||
36+ std::derived_from <typename std::remove_cvref <cStepType>::type, typename envType::StepCustomIndirection>
3637 );
3738
3839 template <eir::CharacterType charType, LexerCompatibleNode <charType> nodeType, eir::MemoryAllocator allocatorType = CRTHeapAllocator>
@@ -149,7 +150,7 @@
149150
150151 // Compiles the requested step and appends it onto the requested step type.
151152 template <CompilationTargetStep <RuntimeEnv> cStepType, typename... otherCompilerArgs>
152- inline bool CompileInto( LexingCompiler <charType, RuntimeEnv, otherCompilerArgs...>& compiler, cStepType& appendToStep, const eir::FixedString <charType>& rulestring )
153+ inline typename RuntimeEnv::Step* CompileInto( LexingCompiler <charType, RuntimeEnv, otherCompilerArgs...>& compiler, cStepType& appendToStep, const eir::FixedString <charType>& rulestring )
153154 {
154155 if ( typename RuntimeEnv::Step *produced = compiler.CompileProduction( &defEnv, rulestring ) )
155156 {
@@ -156,7 +157,7 @@
156157 try
157158 {
158159 appendToStep.AddConnection( produced );
159- return true;
160+ return produced;
160161 }
161162 catch( ... )
162163 {
@@ -165,7 +166,7 @@
165166 }
166167 }
167168
168- return false;
169+ return nullptr;
169170 }
170171
171172 template <typename... otherCompilerArgs>
@@ -173,12 +174,12 @@
173174 {
174175 typename RuntimeEnv::StepAlternatives& altStep = defEnv.nonterminal_namespace.get( prodname, &defEnv );
175176
176- return CompileInto( compiler, altStep, rulestring );
177+ return ( CompileInto( compiler, altStep, rulestring ) != nullptr );
177178 }
178179
179180 // Compiles the requested step and appends it onto the requested step type.
180181 template <CompilationTargetStep <RuntimeEnv> stepType>
181- inline bool CompileInto( stepType& step, const eir::FixedString <charType>& rulestring )
182+ inline typename RuntimeEnv::Step* CompileInto( stepType& step, const eir::FixedString <charType>& rulestring )
182183 {
183184 LexingCompiler <charType, RuntimeEnv, typename RuntimeEnv::EnvironmentAllocator> compiler( eir::constr_with_alloc::DEFAULT, &this->defEnv );
184185
--- eircompile/include/eircompile/lexing_env.h (revision 59)
+++ eircompile/include/eircompile/lexing_env.h (revision 60)
@@ -26,6 +26,60 @@
2626 #include <assert.h>
2727 #endif //_DEBUG
2828
29+// For runtime helpers.
30+namespace LexingEnvUtils
31+{
32+
33+template <eir::CharacterType charType>
34+static inline eir::FixedString <charType> GetLastAttributionItemInPathFixed( const eir::FixedString <charType>& attr_path )
35+{
36+ const charType *start_of_item = attr_path.GetConstString();
37+
38+ charenv_charprov_tocplen <charType> cprov( start_of_item, attr_path.GetLength() );
39+ character_env_iterator <charType, decltype(cprov)> iter( start_of_item, std::move( cprov ) );
40+
41+ typedef typename character_env <charType>::ucp_t ucp_t;
42+
43+ while ( !iter.IsEnd() )
44+ {
45+ ucp_t ucp = iter.ResolveAndIncrement();
46+
47+ if ( ucp == eir::GetDotCharacter <ucp_t> () )
48+ {
49+ start_of_item = iter.GetPointer();
50+ }
51+ }
52+
53+ size_t found_cplen = ( iter.GetPointer() - start_of_item );
54+
55+ return eir::FixedString <charType> ( start_of_item, found_cplen );
56+}
57+
58+template <eir::CharacterType charType>
59+static inline const charType* GetLastAttributionItemInPath( const charType *attr_path )
60+{
61+ character_env_iterator_tozero <charType> iter( attr_path );
62+
63+ typedef typename character_env <charType>::ucp_t ucp_t;
64+
65+ const charType *start_of_item = attr_path;
66+
67+ while ( !iter.IsEnd() )
68+ {
69+ ucp_t ucp = iter.ResolveAndIncrement();
70+
71+ if ( ucp == eir::GetDotCharacter <ucp_t> () )
72+ {
73+ start_of_item = iter.GetPointer();
74+ }
75+ }
76+
77+ return start_of_item;
78+}
79+
80+} // namespace LexingEnvUtils
81+
82+// For meta helpers.
2983 namespace LexingEnvHelpers
3084 {
3185
@@ -701,10 +755,12 @@
701755 this->exec = right.exec;
702756 this->is_procedural_gate = right.is_procedural_gate;
703757 this->base_on_extension = right.base_on_extension;
758+ this->replaceable = right.replaceable;
704759
705760 right.exec = nullptr;
706761 right.is_procedural_gate = false;
707762 right.base_on_extension = false;
763+ right.replaceable = false;
708764 }
709765
710766 ~StepAttribution( void )
@@ -751,7 +807,8 @@
751807 Step *exec = nullptr;
752808 public:
753809 bool is_procedural_gate = false;
754- bool base_on_extension = false;
810+ bool base_on_extension = false; // look for additional extensions
811+ bool replaceable = false; // look for replacement
755812
756813 void SetNode( Step *node )
757814 {
@@ -818,6 +875,7 @@
818875 public:
819876 bool is_inline = false;
820877 bool base_on_extension = false; // if true then we call the last extended-call instead of the base version.
878+ bool replaceable = false; // if true then this call will look for a replacement of the production first
821879 bool is_procedural_gate = false; // if true then a procedural step will have to start at 0 if this is the most-recent find.
822880
823881 void SetProductionName( const eir::FixedString <charType>& prodname )
@@ -2209,6 +2267,355 @@
22092267 }
22102268 };
22112269
2270+ // Replacement-map for known steps/productions. Hosts those replacements for
2271+ // calculation entries further down the calculation path as indexing point.
2272+ struct StepReplacementPoint : public Step
2273+ {
2274+ friend struct LexingEnvironment;
2275+
2276+ using Step::Step;
2277+
2278+ inline StepReplacementPoint( const StepReplacementPoint& ) = default;
2279+ inline StepReplacementPoint( StepReplacementPoint&& right ) noexcept
2280+ : replacements( std::move( right.replacements ) ), valrefs( std::move( right.valrefs ) )
2281+ {
2282+ this->exec = right.exec;
2283+
2284+ right.exec = nullptr;
2285+ }
2286+
2287+ inline ~StepReplacementPoint( void )
2288+ {
2289+ LexingEnvironment *env = this->env;
2290+
2291+ for ( auto *kvNode : this->replacements )
2292+ {
2293+ env->gcReachSched.OnRemoveConnection( this, kvNode->GetKey() );
2294+ }
2295+
2296+ for ( const valinfo& vinfo : this->valrefs )
2297+ {
2298+ Step *valstep = vinfo.step;
2299+
2300+ if ( this->replacements.Find( valstep ) == nullptr )
2301+ {
2302+ env->gcReachSched.OnRemoveConnection( this, valstep );
2303+ }
2304+ }
2305+ }
2306+
2307+ Step* Clone( void ) override
2308+ {
2309+ return this->env->CloneStep <StepReplacementPoint> ( this );
2310+ }
2311+
2312+ Step* GetNextConnectionsToNode( Step *prev ) override
2313+ {
2314+ // First we iterate through all keys.
2315+ // Then we iterate through all values which are not - at the same time - keys.
2316+
2317+ auto findNextValNode = [&]( Step *val_prev ) -> Step*
2318+ {
2319+ auto *findNode = this->valrefs.FindJustAbove( val_prev );
2320+
2321+ if ( findNode == nullptr )
2322+ return nullptr;
2323+
2324+ typename decltype(this->valrefs)::iterator iter( findNode );
2325+
2326+ while ( iter.IsEnd() == false )
2327+ {
2328+ Step *attempt_return = iter.Resolve()->GetValue().step;
2329+
2330+ if ( this->replacements.Find( attempt_return ) == nullptr )
2331+ {
2332+ return attempt_return;
2333+ }
2334+
2335+ iter.Increment();
2336+ }
2337+
2338+ return nullptr;
2339+ };
2340+
2341+ Step *first = this->exec;
2342+
2343+ if ( prev == nullptr || first != nullptr && prev == first )
2344+ {
2345+ if ( prev == nullptr && first != nullptr )
2346+ {
2347+ return first;
2348+ }
2349+
2350+ auto *keyMinNode = this->replacements.GetMinimumByKey();
2351+
2352+ if ( keyMinNode )
2353+ {
2354+ return keyMinNode->GetKey();
2355+ }
2356+
2357+ return findNextValNode( nullptr );
2358+ }
2359+
2360+ // If the previous node is inside the keys, then return the next key.
2361+ // If there is no more next key then we return the first value.
2362+ if ( this->replacements.Find( prev ) != nullptr )
2363+ {
2364+ auto *nextByKeys = this->replacements.FindMinimumByCriteria(
2365+ [&]( auto *leftNode )
2366+ {
2367+ eir::eCompResult cmpRes = eir::DefaultValueCompare( leftNode->GetKey(), prev );
2368+
2369+ if ( cmpRes == eir::eCompResult::LEFT_LESS || cmpRes == eir::eCompResult::EQUAL )
2370+ {
2371+ return eir::eCompResult::LEFT_LESS;
2372+ }
2373+
2374+ return eir::eCompResult::EQUAL;
2375+ }
2376+ );
2377+
2378+ if ( nextByKeys == nullptr )
2379+ {
2380+ return findNextValNode( nullptr );
2381+ }
2382+
2383+ return nextByKeys->GetValue();
2384+ }
2385+
2386+ return findNextValNode( prev );
2387+ }
2388+
2389+ bool IsUnambiguousCall( void ) const noexcept override
2390+ {
2391+ return true;
2392+ }
2393+
2394+ bool IsUndeniableChange( void ) const noexcept override
2395+ {
2396+ return true;
2397+ }
2398+
2399+ size_t GetChoiceCount( void ) const noexcept override
2400+ {
2401+ return 1;
2402+ }
2403+
2404+ private:
2405+ Step *exec = nullptr;
2406+
2407+ DEFINE_HEAP_REDIR_ALLOC_BYSTRUCT( replacements_redirAlloc, allocatorType );
2408+
2409+ eir::Map <Step*, Step*, replacements_redirAlloc> replacements;
2410+
2411+ DEFINE_HEAP_REDIR_ALLOC_BYSTRUCT( valrefs_redirAlloc, allocatorType );
2412+
2413+ struct valinfo
2414+ {
2415+ inline valinfo( Step *step = nullptr, size_t refcnt = 0 ) noexcept : step( step ), refcnt( refcnt )
2416+ {
2417+ return;
2418+ }
2419+ inline valinfo( const valinfo& ) = default;
2420+ inline valinfo( valinfo&& right ) noexcept
2421+ {
2422+ this->step = right.step;
2423+ this->refcnt = right.refcnt;
2424+
2425+ right.step = nullptr;
2426+ right.refcnt = 0;
2427+ }
2428+
2429+ static inline eir::eCompResult compare_values( const valinfo& left, const valinfo& right )
2430+ {
2431+ return eir::DefaultValueCompare( left.step, right.step );
2432+ }
2433+
2434+ static inline eir::eCompResult compare_values( const valinfo& left, Step *right )
2435+ {
2436+ return eir::DefaultValueCompare( left.step, right );
2437+ }
2438+
2439+ static inline eir::eCompResult compare_values( Step *left, const valinfo& right )
2440+ {
2441+ return eir::DefaultValueCompare( left, right.step );
2442+ }
2443+
2444+ Step *step = nullptr;
2445+ mutable size_t refcnt = 0;
2446+ };
2447+
2448+ eir::Set <valinfo, valrefs_redirAlloc, valinfo> valrefs;
2449+
2450+ inline bool _is_step_referenced( Step *step ) const
2451+ {
2452+ return ( this->exec == step || this->replacements.Find( step ) != nullptr || this->valrefs.Find( step ) != nullptr );
2453+ }
2454+
2455+ public:
2456+ inline void SetNode( Step *exec )
2457+ {
2458+ Step *old_exec = this->exec;
2459+
2460+ if ( old_exec == exec )
2461+ return;
2462+
2463+ bool prev_is_new_exec_referenced = _is_step_referenced( exec );
2464+
2465+ this->exec = exec;
2466+
2467+ LexingEnvironment *env = this->env;
2468+
2469+ if ( _is_step_referenced( old_exec ) == false )
2470+ {
2471+ env->gcReachSched.OnRemoveConnection( this, old_exec );
2472+ }
2473+
2474+ if ( prev_is_new_exec_referenced == false )
2475+ {
2476+ env->gcReachSched.OnAddedConnection( this, exec );
2477+ }
2478+ }
2479+
2480+ inline Step* GetNode( void ) const
2481+ {
2482+ return this->exec;
2483+ }
2484+
2485+ inline void SetReplacement( Step *to_replace, Step *replace_with )
2486+ {
2487+ if ( to_replace == nullptr )
2488+ return;
2489+
2490+ bool is_value_different_and_valid = ( replace_with != nullptr && to_replace != replace_with );
2491+
2492+ // Check whether the pointers are present before registration.
2493+ bool prev_to_replace_present = _is_step_referenced( to_replace );
2494+ bool prev_replace_with_present;
2495+
2496+ if ( is_value_different_and_valid )
2497+ {
2498+ prev_replace_with_present = _is_step_referenced( replace_with );
2499+ }
2500+
2501+ LexingEnvironment *env = this->env;
2502+
2503+ auto on_value_remove = [&]( Step *value )
2504+ {
2505+ auto *valrefnode = this->valrefs.Find( value );
2506+
2507+#ifdef _DEBUG
2508+ assert( valrefnode != nullptr );
2509+#endif //_DEBUG
2510+
2511+ if ( valrefnode )
2512+ {
2513+ const valinfo& vinfo = valrefnode->GetValue();
2514+
2515+#ifdef _DEBUG
2516+ assert( vinfo.refcnt > 0 );
2517+#endif //_DEBUG
2518+
2519+ size_t newrefcnt = --vinfo.refcnt;
2520+
2521+ if ( newrefcnt == 0 )
2522+ {
2523+ this->valrefs.RemoveNode( valrefnode );
2524+ }
2525+ }
2526+ };
2527+
2528+ if ( replace_with == nullptr )
2529+ {
2530+ auto *findNode = this->replacements.Find( to_replace );
2531+
2532+ if ( findNode != nullptr )
2533+ {
2534+ Step *old_value = findNode->GetValue();
2535+
2536+ this->replacements.RemoveNode( findNode );
2537+
2538+ on_value_remove( old_value );
2539+ }
2540+ }
2541+ else
2542+ {
2543+ Step*& replacement_storage = this->replacements[ to_replace ];
2544+
2545+ Step *old_step = replacement_storage;
2546+
2547+ if ( old_step && old_step != replace_with )
2548+ {
2549+ on_value_remove( old_step );
2550+ }
2551+
2552+ this->valrefs[ replace_with ].refcnt++;
2553+
2554+ replacement_storage = replace_with;
2555+ }
2556+
2557+ // Check whether the pointers are present after registration.
2558+ bool post_to_replace_present = _is_step_referenced( to_replace );
2559+ bool post_replace_with_present;
2560+
2561+ if ( is_value_different_and_valid )
2562+ {
2563+ post_replace_with_present = _is_step_referenced( replace_with );
2564+ }
2565+
2566+ // Take care about the GC registration.
2567+ if ( prev_to_replace_present == false && post_to_replace_present == true )
2568+ {
2569+ env->gcReachSched.OnAddedConnection( this, to_replace );
2570+ }
2571+ else if ( prev_to_replace_present == true && post_to_replace_present == false )
2572+ {
2573+ env->gcReachSched.OnRemoveConnection( this, to_replace );
2574+ }
2575+
2576+ if ( is_value_different_and_valid )
2577+ {
2578+ if ( prev_replace_with_present == false && post_replace_with_present == true )
2579+ {
2580+ env->gcReachSched.OnAddedConnection( this, replace_with );
2581+ }
2582+ else if ( prev_replace_with_present == true && post_replace_with_present == false )
2583+ {
2584+ env->gcReachSched.OnRemoveConnection( this, replace_with );
2585+ }
2586+ }
2587+ }
2588+
2589+ inline Step* GetReplacement( Step *to_replace )
2590+ {
2591+ auto *find_node = this->replacements.Find( to_replace );
2592+
2593+ return ( find_node ? find_node->GetValue() : nullptr );
2594+ }
2595+
2596+ void ClearReplacements( void )
2597+ {
2598+ LexingEnvironment *env = this->env;
2599+
2600+ for ( auto *kvNode : this->replacements )
2601+ {
2602+ Step *keyStep = kvNode->GetKey();
2603+
2604+ env->gcReachSched.OnRemoveConnection( this, keyStep );
2605+ }
2606+
2607+ for ( const valinfo& vinfo : this->valrefs )
2608+ {
2609+ Step *valueStep = vinfo.step;
2610+
2611+ env->gcReachSched.OnRemoveConnection( this, valueStep );
2612+ }
2613+
2614+ this->replacements.Clear();
2615+ this->valrefs.Clear();
2616+ }
2617+ };
2618+
22122619 struct EnvironmentAllocator
22132620 {
22142621 inline EnvironmentAllocator( LexingEnvironment *env ) noexcept : env( env )
@@ -3500,6 +3907,7 @@
35003907 else if ( cstack_step == next_step )
35013908 {
35023909 // Since there is no extension we just execute ourselves.
3910+ // This can be done by design.
35033911 break;
35043912 }
35053913 }
@@ -3508,6 +3916,50 @@
35083916 return next_step;
35093917 };
35103918
3919+ auto find_replacement_step = [&]( Step *to_replace ) -> Step*
3920+ {
3921+ // Look for a replacement down the calculation stack.
3922+ // * if we find the to_replace step itself then it means that steps above it either have
3923+ // no valid replacements (optimization) or that it does not want replacements so we
3924+ // should stop looking ourselves too (policy); thus returning nullptr is valid.
3925+ // * for any replacement point we find along we way, we look for a replacement; if it does
3926+ // exist then we return it, effectively returning the closest replacement to the top of the
3927+ // stack that we can find.
3928+
3929+ size_t calcstack_size = get_calcstack_size();
3930+
3931+ size_t calcstack_iter = ( calcstack_size - 1 ); // skip the top of the calcstack (entry).
3932+
3933+ while ( calcstack_iter > 0 )
3934+ {
3935+ calcstack_iter--;
3936+
3937+ CalcPathEntry& pentry = get_calcstack_idx( calcstack_iter );
3938+
3939+ Step *cstack_step = pentry.current_step;
3940+
3941+ if ( cstack_step == to_replace )
3942+ {
3943+ // No replacement found.
3944+ break;
3945+ }
3946+
3947+ if ( StepReplacementPoint *replpt = dynamic_cast <StepReplacementPoint*> ( cstack_step ) )
3948+ {
3949+ // Try to see if we have a valid replacement.
3950+ auto *findNode = replpt->replacements.Find( to_replace );
3951+
3952+ if ( findNode != nullptr )
3953+ {
3954+ // Return the first replacement that we can find.
3955+ return findNode->GetValue();
3956+ }
3957+ }
3958+ }
3959+
3960+ return nullptr;
3961+ };
3962+
35113963 try
35123964 {
35133965 while ( has_op_finished == false )
@@ -3667,11 +4119,23 @@
36674119 // This is done so that we can attach any attributes to nodes.
36684120 Step *next_step = attribstep->exec;
36694121
3670- if ( attribstep->base_on_extension )
4122+ Step *actual_call_step = nullptr;
4123+
4124+ if ( attribstep->replaceable )
36714125 {
3672- next_step = find_next_specialized_step( next_step, false );
4126+ actual_call_step = find_replacement_step( next_step );
36734127 }
36744128
4129+ if ( actual_call_step == nullptr && attribstep->base_on_extension )
4130+ {
4131+ actual_call_step = find_next_specialized_step( next_step, false );
4132+ }
4133+
4134+ if ( actual_call_step )
4135+ {
4136+ next_step = actual_call_step;
4137+ }
4138+
36754139 if ( push_onto_execution( next_step ) == false )
36764140 {
36774141 has_op_finished = true;
@@ -3696,11 +4160,23 @@
36964160 {
36974161 Step *next_step = &altsNode->GetValue();
36984162
3699- if ( callstep->base_on_extension )
4163+ Step *actual_call_step = nullptr;
4164+
4165+ if ( callstep->replaceable )
37004166 {
3701- next_step = find_next_specialized_step( next_step, false );
4167+ actual_call_step = find_replacement_step( next_step );
37024168 }
37034169
4170+ if ( actual_call_step == nullptr && callstep->base_on_extension )
4171+ {
4172+ actual_call_step = find_next_specialized_step( next_step, false );
4173+ }
4174+
4175+ if ( actual_call_step )
4176+ {
4177+ next_step = actual_call_step;
4178+ }
4179+
37044180 if ( push_onto_execution( next_step, callstep->is_inline ) == false )
37054181 {
37064182 has_op_finished = true;
@@ -3933,6 +4409,16 @@
39334409 is_op_successful = false;
39344410 }
39354411 }
4412+ else if ( StepReplacementPoint *replstep = dynamic_cast <StepReplacementPoint*> ( current_step ) )
4413+ {
4414+ Step *next_step = replstep->exec;
4415+
4416+ if ( push_onto_execution( next_step ) == false )
4417+ {
4418+ has_op_finished = true;
4419+ is_op_successful = false;
4420+ }
4421+ }
39364422 else
39374423 {
39384424 FATAL_ABORT();
@@ -4464,6 +4950,7 @@
44644950 // StepAttribution
44654951 // StepProceduralSequence
44664952 // StepCustomIndirection
4953+ // StepReplacementPoint
44674954
44684955 // This opcode has no further special handling.
44694956 has_op_finished = true;
@@ -4704,6 +5191,8 @@
47045191 IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepProceduralSequence::steps_redirAlloc, StepProceduralSequence, steps, env->allocMan, allocatorType );
47055192 IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepCustomIndirection::refs_redirAlloc, StepCustomIndirection, refs, env->allocMan, allocatorType );
47065193 IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepCustomIndirection::callback_redirAlloc, StepCustomIndirection, callback, env->allocMan, allocatorType );
5194+IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepReplacementPoint::replacements_redirAlloc, StepReplacementPoint, replacements, env->allocMan, allocatorType );
5195+IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepReplacementPoint::valrefs_redirAlloc, StepReplacementPoint, valrefs, env->allocMan, allocatorType );
47075196 IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, ProductionMachine::CalcPathEntry::attrib_prefix_redirAlloc, CalcPathEntry, attrib_prefix, current_step->env->allocMan, allocatorType );
47085197 IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, ProductionMachine::CalcPathEntry::noprogress_map_redirAlloc, CalcPathEntry, noprogress_map, current_step->env->allocMan, allocatorType );
47095198 IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, ProductionMachine::debug_breaks_redirAlloc, ProductionMachine, debug_breaks, env->allocMan, allocatorType );
--- testcompiler/src/cos_tests.cpp (revision 59)
+++ testcompiler/src/cos_tests.cpp (revision 60)
@@ -325,7 +325,7 @@
325325
326326 struct DeclarationStatement : public COSNode
327327 {
328- inline DeclarationStatement( COSNode *name = nullptr, COSNode *type = nullptr, COSNode *initializer = nullptr ) noexcept : type( type ), initializer( initializer )
328+ inline DeclarationStatement( COSNode *name = nullptr, COSNode *type = nullptr, COSNode *initializer = nullptr ) noexcept : name( name ), type( type ), initializer( initializer )
329329 {
330330 return;
331331 }
@@ -345,7 +345,18 @@
345345 COSNode *type;
346346 COSNode *initializer;
347347 };
348+struct MultiDeclarationStatement : public COSNode
349+{
350+ // Just a pack of declarations because we cannot keep them outside.
348351
352+ inline MultiDeclarationStatement( void ) noexcept
353+ {}
354+ inline MultiDeclarationStatement( const MultiDeclarationStatement& ) = default;
355+ inline MultiDeclarationStatement( MultiDeclarationStatement&& ) = default;
356+
357+ depVector <DeclarationStatement*> decls;
358+};
359+
349360 struct TypedefStatement : public COSNode
350361 {
351362 inline TypedefStatement( COSNode *srctype = nullptr, COSNode *dsttype = nullptr ) noexcept : srctype( srctype ), dsttype( dsttype )
@@ -365,7 +376,18 @@
365376 COSNode *srctype;
366377 COSNode *dsttype;
367378 };
379+struct MultiTypedefStatement : public COSNode
380+{
381+ inline MultiTypedefStatement( depVector <TypedefStatement*> defs = {} ) noexcept : defs( std::move( defs ) )
382+ {
383+ return;
384+ }
385+ inline MultiTypedefStatement( const MultiTypedefStatement& ) = default;
386+ inline MultiTypedefStatement( MultiTypedefStatement&& ) = default;
368387
388+ depVector <TypedefStatement*> defs;
389+};
390+
369391 struct BlockStatement : public COSNode
370392 {
371393 inline BlockStatement( depVector <COSNode*> statements = {} ) noexcept : statements( std::move( statements ) )
@@ -596,6 +618,19 @@
596618 right.return_type = nullptr;
597619 }
598620
621+ // Returns the left-most function signature definition of this node.
622+ inline FuncsigDefinition* GetDeepestReturnValueFunctionSignatureType( void )
623+ {
624+ FuncsigDefinition *deepest = this;
625+
626+ while ( FuncsigDefinition *any_deeper = dynamic_cast <FuncsigDefinition*> ( this->return_type ) )
627+ {
628+ deepest = any_deeper;
629+ }
630+
631+ return deepest;
632+ }
633+
599634 COSNode *return_type;
600635 depVector <COSNode*> params;
601636 };
@@ -698,7 +733,6 @@
698733 lexer.GetNamedProduction( "S" ).setSelector <mintwo_specialized_selector <char, Program, COSNode, program_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
699734 }
700735 assert( lexer.CompileProduction( compiler, "statement", "typedef | block | loop | if | except | objmod | takefirst multdecl spaces ';' | takefirst operation spaces ';'" ) == true );
701- assert( lexer.CompileProduction( compiler, "paramlist", "[<0>param:declaration, spaces ',' spaces]" ) == true );
702736 assert( lexer.CompileProduction( compiler, "funcbody", "^!(block, <b> statement+funcstatement)" ) == true );
703737 assert( lexer.CompileProduction( compiler, "funcstatement", "\"return\" spaces (op:operation spaces)^0:1 ';'" ) == true );
704738 {
@@ -734,29 +768,6 @@
734768 lexer.GetNamedProduction( "spec" ).GetLastStep()->setSelector <direct_obj_build_selector <char, ResolveSpecifierOperation, COSNode, dynspec_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
735769 }
736770 assert( lexer.CompileProduction( compiler, "dtypedef", "\"typedef\" spaces tmultdecl spaces ';'" ) == true );
737- {
738- struct typedef_dispatcher
739- {
740- // TODO: implement this statement after we have done the regular multdecl statement.
741-#if 0
742- static inline bool AssignNodeTo( TypedefStatement *assign_to, const eir::FixedString <char>& attrib, COSNode *node )
743- {
744- if ( attrib == "srctype" )
745- {
746- assign_to->srctype = node;
747- return true;
748- }
749- else if ( attrib == "dsttype" )
750- {
751- assign_to->dsttype = node;
752- return true;
753- }
754- return false;
755- }
756-#endif //0
757- };
758- //lexer.GetNamedProduction( "dtypedef" ).setSelector <direct_obj_build_selector <char, TypedefStatement, COSNode, typedef_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
759- }
760771 assert( lexer.CompileProduction( compiler, "block", "'{' spaces [<0>statement:extended statement, spaces] spaces '}'" ) == true );
761772 {
762773 struct block_dispatcher
@@ -778,7 +789,7 @@
778789 {
779790 auto operation = lexer.MakeStep <decltype(lexer)::RuntimeEnv::StepProceduralSequence> ();
780791
781- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'=' spaces]" ) == true );
792+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'=' spaces]" ) != nullptr );
782793 {
783794 struct assignment_dispatcher
784795 {
@@ -794,7 +805,7 @@
794805 };
795806 operation.GetLastStep()->setSelector <right_associative_selector <char, COSNode, assignment_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
796807 }
797- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:\"||\" spaces]" ) == true );
808+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:\"||\" spaces]" ) != nullptr );
798809 {
799810 struct logical_or_dispatcher
800811 {
@@ -810,7 +821,7 @@
810821 };
811822 operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, logical_or_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
812823 }
813- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:\"&&\" spaces]" ) == true );
824+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:\"&&\" spaces]" ) != nullptr );
814825 {
815826 struct logical_and_dispatcher
816827 {
@@ -826,7 +837,7 @@
826837 };
827838 operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, logical_and_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
828839 }
829- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:(\"==\" | \"!=\" | \"<=\" | \">=\" | '<' | '>') spaces]" ) == true );
840+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:(\"==\" | \"!=\" | \"<=\" | \">=\" | '<' | '>') spaces]" ) != nullptr );
830841 {
831842 struct logical_comparison_dispatcher
832843 {
@@ -910,7 +921,7 @@
910921 };
911922 operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, logical_comparison_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
912923 }
913- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'|' spaces]" ) == true );
924+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'|' spaces]" ) != nullptr );
914925 {
915926 struct bor_dispatcher
916927 {
@@ -926,7 +937,7 @@
926937 };
927938 operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, bor_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
928939 }
929- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'^' spaces]" ) == true );
940+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'^' spaces]" ) != nullptr );
930941 {
931942 struct bxor_dispatcher
932943 {
@@ -942,7 +953,7 @@
942953 };
943954 operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, bxor_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
944955 }
945- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'&' spaces]" ) == true );
956+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'&' spaces]" ) != nullptr );
946957 {
947958 struct band_dispatcher
948959 {
@@ -958,7 +969,7 @@
958969 };
959970 operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, band_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
960971 }
961- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:('-'|'+') spaces]" ) == true );
972+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:('-'|'+') spaces]" ) != nullptr );
962973 {
963974 struct summation_dispatcher
964975 {
@@ -1004,7 +1015,7 @@
10041015 };
10051016 operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, summation_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
10061017 }
1007- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:('*'|'/'|'%') spaces]" ) == true );
1018+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:('*'|'/'|'%') spaces]" ) != nullptr );
10081019 {
10091020 struct muldiv_dispatcher
10101021 {
@@ -1059,7 +1070,7 @@
10591070 };
10601071 operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, muldiv_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
10611072 }
1062- assert( lexer.CompileInto( compiler, operation, "[<0,e>pre_optype:(\"++\" | \"--\"), spaces] opitem:operation [<0,e> spaces, post_optype:(\"++\" | \"--\")]" ) == true );
1073+ assert( lexer.CompileInto( compiler, operation, "[<0,e>pre_optype:(\"++\" | \"--\"), spaces] opitem:operation [<0,e> spaces, post_optype:(\"++\" | \"--\")]" ) != nullptr );
10631074 {
10641075 struct quickunamod_dispatcher
10651076 {
@@ -1126,7 +1137,7 @@
11261137 };
11271138 operation.GetLastStep()->setSelector <unary_operation_selector <char, COSNode, quickunamod_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
11281139 }
1129- assert( lexer.CompileInto( compiler, operation, "[<0,e>optype:'-~!*', spaces] opitem:operation" ) == true );
1140+ assert( lexer.CompileInto( compiler, operation, "[<0,e>optype:'-~!*', spaces] opitem:operation" ) != nullptr );
11301141 {
11311142 struct unary_negation_dispatcher
11321143 {
@@ -1190,7 +1201,7 @@
11901201 };
11911202 operation.GetLastStep()->setSelector <unary_operation_selector <char, COSNode, unary_negation_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
11921203 }
1193- assert( lexer.CompileInto( compiler, operation, "tocall:operation (spaces [begcall:'(' spaces [<0>param:procgate operation, spaces ',' spaces] spaces endcall:')', spaces])^0:1" ) == true );
1204+ assert( lexer.CompileInto( compiler, operation, "tocall:operation (spaces [begcall:'(' spaces [<0>param:procgate operation, spaces ',' spaces] spaces endcall:')', spaces])^0:1" ) != nullptr );
11941205 {
11951206 struct call_selector
11961207 {
@@ -1303,7 +1314,7 @@
13031314 };
13041315 operation.GetLastStep()->setSelector <call_selector> ( &lexer.GetRuntimeEnvironment() );
13051316 }
1306- assert( lexer.CompileInto( compiler, operation, "base:operation (spaces ['[' spaces key:procgate operation spaces ']', spaces])^0:1" ) == true );
1317+ assert( lexer.CompileInto( compiler, operation, "base:operation (spaces ['[' spaces key:procgate operation spaces ']', spaces])^0:1" ) != nullptr );
13071318 {
13081319 struct key_dispatcher
13091320 {
@@ -1319,7 +1330,7 @@
13191330 };
13201331 operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, key_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
13211332 }
1322- assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'.' spaces]" ) == true );
1333+ assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'.' spaces]" ) != nullptr );
13231334 {
13241335 struct dot_dispatcher
13251336 {
@@ -1338,7 +1349,7 @@
13381349
13391350 auto tailop = lexer.MakeStep <decltype(lexer)::RuntimeEnv::StepAlternatives> ();
13401351
1341- assert( lexer.CompileInto( compiler, tailop, "\"new\" spaces type:spec spaces ('(' spaces paramlist spaces ')')^0:1" ) == true );
1352+ assert( lexer.CompileInto( compiler, tailop, "\"new\" spaces type:spec spaces (curlypack)^0:1" ) != nullptr );
13421353 {
13431354 struct new_dispatcher
13441355 {
@@ -1360,9 +1371,9 @@
13601371 };
13611372 tailop.GetLastStep()->setSelector <direct_obj_build_selector <char, NewOperation, COSNode, new_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
13621373 }
1363- assert( lexer.CompileInto( compiler, tailop, "name" ) == true );
1364- assert( lexer.CompileInto( compiler, tailop, "number" ) == true );
1365- assert( lexer.CompileInto( compiler, tailop, "'{' spaces [item:procgate operation, spaces ',' spaces] spaces '}'" ) == true );
1374+ assert( lexer.CompileInto( compiler, tailop, "name" ) != nullptr );
1375+ assert( lexer.CompileInto( compiler, tailop, "number" ) != nullptr );
1376+ assert( lexer.CompileInto( compiler, tailop, "'{' spaces [item:procgate operation, spaces ',' spaces] spaces '}'" ) != nullptr );
13661377 {
13671378 struct array_dispatcher
13681379 {
@@ -1380,7 +1391,7 @@
13801391 }
13811392 // Not ideal for again serializing into text, but we should be automatically detecting such a case anyway due to a fixed
13821393 // operational binding strength.
1383- assert( lexer.CompileInto( compiler, tailop, "'(' spaces procgate operation spaces ')'" ) == true );
1394+ assert( lexer.CompileInto( compiler, tailop, "'(' spaces procgate operation spaces ')'" ) != nullptr );
13841395
13851396 lexer.AddStepInto( operation, std::move( tailop ) );
13861397
@@ -1597,7 +1608,7 @@
15971608 };
15981609 lexer.GetNamedProduction( "except" ).GetLastStep()->setSelector <direct_obj_build_selector <char, ThrowStatement, COSNode, throw_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
15991610 }
1600- assert( lexer.CompileProduction( compiler, "catch", "\"catch\" spaces '(' spaces (caught_decl:declaration spaces)^0:1 ')' spaces catch_body:extended statement" ) == true );
1611+ assert( lexer.CompileProduction( compiler, "catch", "\"catch\" spaces '(' spaces (caught_decl:decl_optnoinit spaces)^0:1 ')' spaces catch_body:extended statement" ) == true );
16011612 {
16021613 struct catch_dispatcher
16031614 {
@@ -1694,7 +1705,7 @@
16941705 }
16951706 assert( lexer.CompileProduction( compiler, "typedef", "dtypedef | structdef" ) == true );
16961707 assert( lexer.CompileProduction( compiler, "typestatement", "constructor | destructor" ) == true );
1697- assert( lexer.CompileProduction( compiler, "constructor", "\"constructor\" spaces '(' spaces paramlist spaces ')' spaces body:extended funcbody" ) == true );
1708+ assert( lexer.CompileProduction( compiler, "constructor", "\"constructor\" spaces '(' spaces paramlist_opt spaces ')' spaces body:extended funcbody" ) == true );
16981709 {
16991710 struct constructor_dispatcher
17001711 {
@@ -1802,61 +1813,636 @@
18021813 lexer.GetNamedProduction( "curlypack" ).setSelector <direct_obj_build_selector <char, CurlyPack, COSNode, curlypack_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
18031814 }
18041815
1805- // Type system COS structures.
1806- assert( lexer.CompileProduction( compiler, "locator", "[<0>loc:'*',spaces] (spaces loc:'&')^0:1" ) == true );
1807- assert( lexer.CompileProduction( compiler, "multdecl", "utype:spec spaces [locator spaces (funcsigdecl|locatedname) declinit, spaces ',' spaces]" ) == true );
1816+ struct declaratory_locator_builder
18081817 {
1809- struct declaratory_type_builder
1818+ enum class eLocatorType
18101819 {
1820+ POINTER,
1821+ REFERENCE
1822+ };
18111823
1824+ struct array_spec
1825+ {
1826+ inline array_spec( COSNode *size_op = nullptr ) noexcept : size_op( size_op )
1827+ {}
1828+ inline array_spec( const array_spec& ) = default;
1829+ inline array_spec( array_spec&& right ) noexcept
1830+ {
1831+ this->size_op = right.size_op;
1832+
1833+ right.size_op = nullptr;
1834+ }
1835+
1836+ COSNode *size_op;
18121837 };
18131838
1814- struct multdecl_simple_selector
1839+ inline void AssignAttribute( const eir::FixedString <char>& attrib, const eir::FixedString <char>& value )
18151840 {
1841+ if ( attrib == "loc" )
1842+ {
1843+ if ( value == "*" )
1844+ {
1845+ locators.AddToBack( eLocatorType::POINTER );
1846+ }
1847+ else if ( value == "&" )
1848+ {
1849+ locators.AddToBack( eLocatorType::REFERENCE );
1850+ }
1851+ }
1852+ else if ( attrib == "arrspec.endtok" )
1853+ {
1854+ locators.AddToBack( std::move( _build_arrspec ) );
1855+ }
1856+ }
1857+
1858+ inline bool AssignNode( const eir::FixedString <char>& attrib, COSNode *node )
1859+ {
1860+ if ( attrib == "arrspec.idx" )
1861+ {
1862+ _build_arrspec.size_op = node;
1863+ return true;
1864+ }
1865+ return false;
1866+ }
1867+
1868+ inline COSNode* EncapsulateByTypeLocators( COSNode *node )
1869+ {
1870+ COSNode *return_node = node;
1871+
1872+ for ( loc_variant_t& item : this->locators )
1873+ {
1874+ if ( std::holds_alternative <eLocatorType> ( item ) )
1875+ {
1876+ eLocatorType basic_loctype = std::get <eLocatorType> ( item );
1877+
1878+ if ( basic_loctype == eLocatorType::POINTER )
1879+ {
1880+ return_node = new PointerTypeSpecifier( return_node );
1881+ }
1882+ else if ( basic_loctype == eLocatorType::REFERENCE )
1883+ {
1884+ return_node = new RefTypeSpecifier( return_node );
1885+ }
1886+ }
1887+ else if ( std::holds_alternative <array_spec> ( item ) )
1888+ {
1889+ array_spec& arrspec = std::get <array_spec> ( item );
1890+
1891+ return_node = new ArrayTypeSpecifier( return_node, arrspec.size_op );
1892+ }
1893+ }
1894+
1895+ return return_node;
1896+ }
1897+
1898+ inline void Reset( void )
1899+ {
1900+ this->locators.Clear();
1901+ this->_build_arrspec.size_op = nullptr;
1902+ }
1903+
1904+ typedef std::variant <eLocatorType, array_spec> loc_variant_t;
1905+
1906+ depVector <loc_variant_t> locators;
1907+
1908+ // Temporary build variables.
1909+ array_spec _build_arrspec;
1910+ };
1911+
1912+ // Type system COS structures.
1913+ assert( lexer.CompileProduction( compiler, "locator", "[<0>loc:'*',spaces] (spaces loc:'&')^0:1" ) == true ); // helper
1914+ assert( lexer.CompileProduction( compiler, "tmultdecl", "utype:spec spaces [locator spaces (func:funcsigdecl|locatedname), spaces nextdef:',' spaces]" ) == true );
1915+ {
1916+ struct tmultdecl_selector
1917+ {
1918+ inline TypedefStatement* DetachTypedef( void )
1919+ {
1920+ COSNode *underlying_type = this->locbuild.EncapsulateByTypeLocators( this->utype );
1921+
1922+ COSNode *srctype;
1923+
1924+ if ( FuncsigDefinition *func = this->func )
1925+ {
1926+ FuncsigDefinition *left_most_func = func->GetDeepestReturnValueFunctionSignatureType();
1927+
1928+ left_most_func->return_type = underlying_type;
1929+
1930+ srctype = func;
1931+ }
1932+ else
1933+ {
1934+ srctype = underlying_type;
1935+ }
1936+
1937+ this->tdef.srctype = srctype;
1938+
1939+ return new TypedefStatement( std::move( this->tdef ) );
1940+ }
18161941
1817- COSNode *type;
1942+ inline void PushDefinition( void )
1943+ {
1944+ this->multidef.defs.AddToBack( this->DetachTypedef() );
1945+
1946+ // Reset the typedef builder fields, but not utype.
1947+ this->locbuild.Reset();
1948+ this->func = nullptr;
1949+ }
1950+
1951+ inline void AssignAttribute( const eir::FixedString <char>& attrib, const eir::FixedString <char>& value )
1952+ {
1953+ if ( attrib == "nextdef" )
1954+ {
1955+ this->PushDefinition();
1956+ }
1957+ else
1958+ {
1959+ locbuild.AssignAttribute( attrib, value );
1960+ }
1961+ }
1962+
1963+ inline bool AssignNode( const eir::FixedString <char>& attrib, COSNode *node )
1964+ {
1965+ if ( attrib == "utype" )
1966+ {
1967+ this->utype = node;
1968+ return true;
1969+ }
1970+ else if ( attrib == "func" )
1971+ {
1972+ this->func = dynamic_cast <FuncsigDefinition*> ( node );
1973+ return true;
1974+ }
1975+ else if ( LexingEnvUtils::GetLastAttributionItemInPathFixed( attrib ) == "name" )
1976+ {
1977+ this->tdef.dsttype = node;
1978+ return true;
1979+ }
1980+ else if ( locbuild.AssignNode( attrib, node ) )
1981+ {
1982+ return true;
1983+ }
1984+
1985+ return false;
1986+ }
1987+
1988+ inline COSNode* DetachFinishedNode( void )
1989+ {
1990+ if ( this->multidef.defs.GetCount() == 0 )
1991+ {
1992+ // Just return the single typedef.
1993+ return this->DetachTypedef();
1994+ }
1995+ else
1996+ {
1997+ this->PushDefinition();
1998+
1999+ return new MultiTypedefStatement( std::move( this->multidef ) );
2000+ }
2001+ }
2002+
2003+ COSNode *utype = nullptr;
2004+ FuncsigDefinition *func = nullptr;
2005+ declaratory_locator_builder locbuild;
2006+ TypedefStatement tdef;
2007+ MultiTypedefStatement multidef;
18182008 };
2009+ lexer.GetNamedProduction( "tmultdecl" ).setSelector <tmultdecl_selector> ();
18192010 }
1820- assert( lexer.CompileProduction( compiler, "tmultdecl", "utype:spec spaces [locator spaces (funcsigdecl|locatedname), spaces ',' spaces]" ) == true );
1821- assert( lexer.CompileProduction( compiler, "funcsigdecl", "isfunc:functag spaces '(' spaces locator spaces (subfunc:funcsigdecl|locatedname) spaces ')' spaces '(' spaces paramlist spaces ')'" ) == true );
2011+ assert( lexer.CompileProduction( compiler, "funcsigdecl", "functag spaces ( '(' spaces locator spaces (subfunc:funcsigdecl|locatedname) spaces ')' | name:spec ) spaces '(' spaces paramlist_opt spaces ')'" ) == true );
2012+ assert( lexer.CompileProduction( compiler, "funcsigdecl_opt", "functag spaces ('(' spaces locator spaces (subfunc:funcsigdecl_opt|locatedname_opt) spaces ')' | (name:spec)^0:1) spaces '(' spaces paramlist_opt spaces ')'" ) == true );
18222013 {
1823- // TODO.
2014+ struct funcsig_selector
2015+ {
2016+ inline void AssignAttribute( const eir::FixedString <char>& attrib, const eir::FixedString <char>& value )
2017+ {
2018+ locbuild.AssignAttribute( attrib, value );
2019+ }
2020+
2021+ inline bool AssignNode( const eir::FixedString <char>& attrib, COSNode *node )
2022+ {
2023+ if ( attrib == "param" )
2024+ {
2025+ this->funcsig.params.AddToBack( node );
2026+ return true;
2027+ }
2028+ else if ( attrib == "subfunc" )
2029+ {
2030+ this->subfunc = dynamic_cast <FuncsigDefinition*> ( node );
2031+ return true;
2032+ }
2033+ else if ( LexingEnvUtils::GetLastAttributionItemInPathFixed( attrib ) == "name" )
2034+ {
2035+ throw lexing_value_transgression_exception();
2036+ }
2037+ else if ( locbuild.AssignNode( attrib, node ) )
2038+ {
2039+ return true;
2040+ }
2041+ return false;
2042+ }
2043+
2044+ inline COSNode* DetachFinishedNode( void )
2045+ {
2046+ COSNode *return_node;
2047+
2048+ COSNode *detached_func = this->locbuild.EncapsulateByTypeLocators( new FuncsigDefinition( std::move( this->funcsig ) ) );
2049+
2050+ if ( FuncsigDefinition *subfunc = this->subfunc )
2051+ {
2052+ FuncsigDefinition *left_most_sig = subfunc->GetDeepestReturnValueFunctionSignatureType();
2053+
2054+ left_most_sig->return_type = detached_func;
2055+
2056+ return_node = subfunc;
2057+ }
2058+ else
2059+ {
2060+ return_node = detached_func;
2061+ }
2062+
2063+ return return_node;
2064+ }
2065+
2066+ declaratory_locator_builder locbuild;
2067+ FuncsigDefinition funcsig;
2068+ FuncsigDefinition *subfunc = nullptr;
2069+ };
2070+ lexer.GetNamedProduction( "funcsigdecl" ).setSelector <funcsig_selector> ();
2071+ lexer.GetNamedProduction( "funcsigdecl_opt" ).setSelector <funcsig_selector> ();
18242072 }
1825- assert( lexer.CompileProduction( compiler, "locatedname", "name:spec (spaces [arrspec:arrayspec, spaces])" ) == true );
1826- assert( lexer.CompileProduction( compiler, "arrayspec", "'[' spaces (idx:operation spaces)^0:1 ']'" ) == true );
1827- assert( lexer.CompileProduction( compiler, "declaration", "utype:spec spaces locator spaces (funcsigdecl|locatedname) declinit" ) == true );
2073+ assert( lexer.CompileProduction( compiler, "locatedname", "name:spec (spaces [arrspec:arrayspec, spaces])" ) == true ); // helper
2074+ assert( lexer.CompileProduction( compiler, "locatedname_opt", "(name:spec)^0:1 (spaces [arrspec:arrayspec, spaces])" ) == true ); // helper.
2075+ assert( lexer.CompileProduction( compiler, "arrayspec", "'[' spaces (idx:operation spaces)^0:1 endtok:']'" ) == true ); // helper
2076+ // Set-up both of the following productions in one block.
2077+ assert( lexer.CompileProduction( compiler, "declaration", "utype:spec spaces locator spaces (func:funcsigdecl|locatedname) declinit" ) == true );
2078+ assert( lexer.CompileProduction( compiler, "decl_optnoinit", "utype:spec spaces locator spaces (func:funcsigdecl_opt|locatedname_opt)" ) == true );
2079+ assert( lexer.CompileProduction( compiler, "decl_opt", "inline decl_optnoinit declinit" ) == true );
2080+ assert( lexer.CompileProduction( compiler, "multdecl", "utype:spec spaces [locator spaces (func:funcsigdecl|locatedname) declinit, spaces nextdecl:',' spaces]" ) == true );
18282081 {
1829- // TODO: adjust this to match the lexing capabilities.
1830- struct declaration_dispatcher
2082+ struct declaration_selector
18312083 {
1832- static inline bool AssignNodeTo( DeclarationStatement *assign_to, const eir::FixedString <char>& attrib, COSNode *node )
2084+ inline void AssignAttribute( const eir::FixedString <char>& attrib, const eir::FixedString <char>& value )
18332085 {
1834- if ( attrib == "type" )
2086+ locbuild.AssignAttribute( attrib, value );
2087+ }
2088+
2089+ inline bool AssignNode( const eir::FixedString <char>& attrib, COSNode *node )
2090+ {
2091+ if ( attrib == "utype" )
18352092 {
1836- assign_to->type = node;
2093+ this->utype = node;
18372094 return true;
18382095 }
1839- else if ( attrib == "name" )
2096+ else if ( attrib == "func" )
18402097 {
1841- assign_to->name = node;
2098+ this->func = dynamic_cast <FuncsigDefinition*> ( node );
18422099 return true;
18432100 }
18442101 else if ( attrib == "init" )
18452102 {
1846- assign_to->initializer = node;
2103+ this->decl.initializer = node;
18472104 return true;
18482105 }
2106+ else if ( LexingEnvUtils::GetLastAttributionItemInPathFixed( attrib ) == "name" )
2107+ {
2108+ this->decl.name = node;
2109+ return true;
2110+ }
2111+ else if ( locbuild.AssignNode( attrib, node ) )
2112+ {
2113+ return true;
2114+ }
18492115 return false;
18502116 }
2117+
2118+ inline COSNode* GetBuiltType( void )
2119+ {
2120+ if ( COSNode *built_type = this->built_type )
2121+ return built_type;
2122+
2123+ // Build the underlying type completely.
2124+ COSNode *underlying_type = locbuild.EncapsulateByTypeLocators( this->utype );
2125+
2126+ COSNode *built_type;
2127+
2128+ if ( FuncsigDefinition *func = this->func )
2129+ {
2130+ FuncsigDefinition *left_most_sig = func->GetDeepestReturnValueFunctionSignatureType();
2131+
2132+ left_most_sig->return_type = underlying_type;
2133+
2134+ built_type = func;
2135+ }
2136+ else
2137+ {
2138+ built_type = underlying_type;
2139+ }
2140+
2141+ this->built_type = built_type;
2142+
2143+ return built_type;
2144+ }
2145+
2146+ inline DeclarationStatement* DetachFinishedNode( void )
2147+ {
2148+ this->decl.type = this->GetBuiltType();
2149+
2150+ return new DeclarationStatement( std::move( this->decl ) );
2151+ }
2152+
2153+ inline void ResetForMulti( void )
2154+ {
2155+ // Do not reset utype field.
2156+
2157+ this->func = nullptr;
2158+ this->locbuild.Reset();
2159+ this->decl.type = nullptr;
2160+ this->decl.name = nullptr;
2161+ this->decl.initializer = nullptr;
2162+ this->built_type = nullptr;
2163+ }
2164+
2165+ COSNode *utype = nullptr;
2166+ FuncsigDefinition *func = nullptr;
2167+ declaratory_locator_builder locbuild;
2168+ DeclarationStatement decl;
2169+ COSNode *built_type = nullptr;
18512170 };
1852- lexer.GetNamedProduction( "declaration" ).setSelector <direct_obj_build_selector <char, DeclarationStatement, COSNode, declaration_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() );
2171+ lexer.GetNamedProduction( "declaration" ).setSelector <declaration_selector> ();
2172+ lexer.GetNamedProduction( "decl_optnoinit" ).setSelector <declaration_selector> ();
2173+ lexer.GetNamedProduction( "decl_opt" ).setSelector <declaration_selector> ();
2174+
2175+ struct multdecl_selector
2176+ {
2177+ inline void PushDeclaration( void )
2178+ {
2179+ this->multdecl.decls.AddToBack( this->declsel.DetachFinishedNode() );
2180+
2181+ // Clear type information other than the utype field.
2182+ this->declsel.ResetForMulti();
2183+ }
2184+
2185+ inline void AssignAttribute( const eir::FixedString <char>& attrib, const eir::FixedString <char>& value )
2186+ {
2187+ if ( attrib == "nextdecl" )
2188+ {
2189+ this->PushDeclaration();
2190+ }
2191+ else
2192+ {
2193+ declsel.AssignAttribute( attrib, value );
2194+ }
2195+ }
2196+
2197+ inline bool AssignNode( const eir::FixedString <char>& attrib, COSNode *node )
2198+ {
2199+ return declsel.AssignNode( attrib, node );
2200+ }
2201+
2202+ inline COSNode* DetachFinishedNode( void )
2203+ {
2204+ if ( this->multdecl.decls.GetCount() == 0 )
2205+ {
2206+ // Just return a single declaration.
2207+ return this->declsel.DetachFinishedNode();
2208+ }
2209+ else
2210+ {
2211+ this->PushDeclaration();
2212+
2213+ return new MultiDeclarationStatement( std::move( this->multdecl ) );
2214+ }
2215+ }
2216+
2217+ MultiDeclarationStatement multdecl;
2218+ declaration_selector declsel;
2219+ };
2220+ lexer.GetNamedProduction( "multdecl" ).setSelector <multdecl_selector> ();
2221+
2222+ auto special_declinit = lexer.MakeStep <decltype(lexer)::RuntimeEnv::StepCustomIndirection> ();
2223+
2224+ // INDEX 0: array enclosure.
2225+ auto *step_arrenclose = lexer.CompileInto( special_declinit, "'{' spaces ([initexpr, spaces ',' spaces] spaces)^0:1 '}'" );
2226+
2227+ // INDEX 1: outer value.
2228+ auto *step_outerval = lexer.CompileInto( special_declinit, "'{' spaces operation spaces '}'" );
2229+
2230+ // We also need the following productions which are already defined:
2231+ // * operation
2232+ // * funcbody
2233+
2234+ special_declinit.callback = [&lexer, step_arrenclose, step_outerval]( decltype(lexer)::RuntimeEnv::ProductionMachine& machine ) -> decltype(lexer)::RuntimeEnv::Step*
2235+ {
2236+ auto& step_declaration = lexer.GetNamedProduction( "declaration" );
2237+ auto& step_decl_opt = lexer.GetNamedProduction( "decl_opt" );
2238+ auto& step_multdecl = lexer.GetNamedProduction( "multdecl" );
2239+ auto& step_declinit = lexer.GetNamedProduction( "initexpr" );
2240+
2241+ size_t cstack_cnt = machine.GetCurrentCalcStackSize();
2242+
2243+ size_t cstack_idx = ( cstack_cnt - 1 ); // skip us.
2244+
2245+ declaration_selector *decl_sel = nullptr;
2246+ multdecl_selector *multdecl_sel = nullptr;
2247+
2248+ size_t init_depth = 0;
2249+
2250+ while ( cstack_idx > 0 )
2251+ {
2252+ cstack_idx--;
2253+
2254+ auto *step = machine.GetCurrentExecutionStepByIndex( cstack_idx );
2255+
2256+ if ( step == &step_declaration || step == &step_decl_opt )
2257+ {
2258+ decl_sel = (declaration_selector*)machine.GetCurrentExecutionSelectorDataByIndex( cstack_idx );
2259+ break;
2260+ }
2261+ else if ( step == &step_multdecl )
2262+ {
2263+ multdecl_sel = (multdecl_selector*)machine.GetCurrentExecutionSelectorDataByIndex( cstack_idx );
2264+ break;
2265+ }
2266+ else if ( step == &step_declinit )
2267+ {
2268+ init_depth++;
2269+ }
2270+ }
2271+
2272+ COSNode *type = nullptr;
2273+
2274+ if ( decl_sel )
2275+ {
2276+ type = decl_sel->GetBuiltType();
2277+ }
2278+ else if ( multdecl_sel )
2279+ {
2280+ type = multdecl_sel->declsel.GetBuiltType();
2281+ }
2282+
2283+ if ( type )
2284+ {
2285+ // Go as deep as required by init_depth to find the init-type.
2286+ COSNode *init_type = type;
2287+
2288+ while ( init_depth > 0 )
2289+ {
2290+ init_depth--;
2291+
2292+ if ( PointerTypeSpecifier *ptrspec = dynamic_cast <PointerTypeSpecifier*> ( init_type ) )
2293+ {
2294+ init_type = ptrspec->spec;
2295+ }
2296+ else if ( RefTypeSpecifier *refspec = dynamic_cast <RefTypeSpecifier*> ( init_type ) )
2297+ {
2298+ init_type = refspec->spec;
2299+ }
2300+ else if ( ArrayTypeSpecifier *arrspec = dynamic_cast <ArrayTypeSpecifier*> ( init_type ) )
2301+ {
2302+ init_type = arrspec->spec;
2303+ }
2304+ else
2305+ {
2306+ // Unknown.
2307+ return nullptr;
2308+ }
2309+ }
2310+
2311+ if ( dynamic_cast <ArrayTypeSpecifier*> ( init_type ) )
2312+ {
2313+ // We want to build an array.
2314+ return step_arrenclose;
2315+ }
2316+ else if ( dynamic_cast <FuncsigDefinition*> ( init_type ) )
2317+ {
2318+ // Expect function body.
2319+ return &lexer.GetNamedProduction( "funcbody" );
2320+ }
2321+ else if ( init_depth > 0 )
2322+ {
2323+ // Expect operation.
2324+ return &lexer.GetNamedProduction( "operation" );
2325+ }
2326+ else
2327+ {
2328+ // Expect an outer-value.
2329+ return step_outerval;
2330+ }
2331+ }
2332+
2333+ return nullptr;
2334+ };
2335+
2336+ lexer.AddStep( "initexpr", std::move( special_declinit ) );
18532337 }
1854- assert( lexer.CompileProduction( compiler, "typelocator", "[<0>arrspec:arrayspec, spaces]" ) == true );
1855- assert( lexer.CompileProduction( compiler, "type", "utype:spec spaces locator spaces (typefuncsig|typelocator)" ) == true );
1856- assert( lexer.CompileProduction( compiler, "typefuncsig", "isfunc:functag spaces ( '('spaces locator spaces (subfunc:typefuncsig|typelocator) spaces ')' spaces )^0:1 '(' spaces paramlist spaces ')'" ) == true );
1857- assert( lexer.CompileProduction( compiler, "declinit", "( spaces '=' spaces init:operation | spaces init:curlypack )^0:1" ) == true );
2338+ assert( lexer.CompileProduction( compiler, "declinit", "( spaces init:initexpr | spaces '=' spaces init:operation | spaces init:curlypack )^0:1" ) == true );
2339+ assert( lexer.CompileProduction( compiler, "typelocator", "[<0>arrspec:arrayspec, spaces]" ) == true ); // helper
2340+ assert( lexer.CompileProduction( compiler, "typefuncsig", "functag spaces ( '(' spaces locator spaces (subfunc:typefuncsig|typelocator) spaces ')' spaces )^0:1 '(' spaces paramlist_opt spaces ')'" ) == true );
2341+ {
2342+ struct typefuncsig_selector
2343+ {
2344+ inline void AssignAttribute( const eir::FixedString <char>& attrib, const eir::FixedString <char>& value )
2345+ {
2346+ locbuild.AssignAttribute( attrib, value );
2347+ }
2348+
2349+ inline bool AssignNode( const eir::FixedString <char>& attrib, COSNode *node )
2350+ {
2351+ if ( attrib == "param" )
2352+ {
2353+ this->funcsig.params.AddToBack( node );
2354+ return true;
2355+ }
2356+ else if ( attrib == "subfunc" )
2357+ {
2358+ this->subfunc = dynamic_cast <FuncsigDefinition*> ( node );
2359+ return true;
2360+ }
2361+ else
2362+ {
2363+ return locbuild.AssignNode( attrib, node );
2364+ }
2365+ }
2366+
2367+ inline COSNode* DetachFinishedNode( void )
2368+ {
2369+ COSNode *type;
2370+
2371+ COSNode *detached_func = this->locbuild.EncapsulateByTypeLocators( new FuncsigDefinition( std::move( this->funcsig ) ) );
2372+
2373+ if ( FuncsigDefinition *subfunc = this->subfunc )
2374+ {
2375+ FuncsigDefinition *left_most_func = subfunc->GetDeepestReturnValueFunctionSignatureType();
2376+
2377+ left_most_func->return_type = detached_func;
2378+
2379+ type = subfunc;
2380+ }
2381+ else
2382+ {
2383+ type = detached_func;
2384+ }
2385+
2386+ return type;
2387+ }
2388+
2389+ declaratory_locator_builder locbuild;
2390+ FuncsigDefinition *subfunc = nullptr;
2391+ FuncsigDefinition funcsig;
2392+ };
2393+ lexer.GetNamedProduction( "typefuncsig" ).setSelector <typefuncsig_selector> ();
2394+ }
18582395 assert( lexer.CompileProduction( compiler, "functag", "\"func\" | \"operator\" | \"proc\"" ) == true );
2396+ assert( lexer.CompileProduction( compiler, "type", "utype:spec spaces locator spaces (func:typefuncsig|typelocator)" ) == true );
2397+ {
2398+ struct type_selector
2399+ {
2400+ inline void AssignAttribute( const eir::FixedString <char>& attrib, const eir::FixedString <char>& value )
2401+ {
2402+ locbuild.AssignAttribute( attrib, value );
2403+ }
18592404
2405+ inline bool AssignNode( const eir::FixedString <char>& attrib, COSNode *node )
2406+ {
2407+ if ( attrib == "utype" )
2408+ {
2409+ this->utype = node;
2410+ return true;
2411+ }
2412+ else if ( attrib == "func" )
2413+ {
2414+ this->func = dynamic_cast <FuncsigDefinition*> ( node );
2415+ return true;
2416+ }
2417+ return locbuild.AssignNode( attrib, node );
2418+ }
2419+
2420+ inline COSNode* DetachFinishedNode( void )
2421+ {
2422+ COSNode *underlying_type = this->locbuild.EncapsulateByTypeLocators( this->utype );
2423+
2424+ if ( FuncsigDefinition *func = this->func )
2425+ {
2426+ FuncsigDefinition *left_most_func = func->GetDeepestReturnValueFunctionSignatureType();
2427+
2428+ left_most_func->return_type = underlying_type;
2429+
2430+ return func;
2431+ }
2432+ else
2433+ {
2434+ return underlying_type;
2435+ }
2436+ }
2437+
2438+ COSNode *utype = nullptr;
2439+ declaratory_locator_builder locbuild;
2440+ FuncsigDefinition *func = nullptr;
2441+ };
2442+ lexer.GetNamedProduction( "type" ).setSelector <type_selector> ();
2443+ }
2444+ assert( lexer.CompileProduction( compiler, "paramlist_opt", "[<0>decl_opt, spaces ',' spaces]" ) == true );
2445+
18602446 printf( "testing COS operations (non-deep)..." );
18612447 {
18622448 assert( lexer.TestProduction( "1 + 1;" ) == true );
--- testcompiler/src/lexingenv_tests.cpp (revision 59)
+++ testcompiler/src/lexingenv_tests.cpp (revision 60)
@@ -16,6 +16,30 @@
1616
1717 void LEXINGENV_TESTS( void )
1818 {
19+ printf( "testing LexingEnvUtils::GetLastAttributionItemInPath..." );
20+ {
21+ const char *attrp1 = "meow.woof";
22+
23+ assert( LexingEnvUtils::GetLastAttributionItemInPath( attrp1 ) == attrp1 + 5 );
24+
25+ const char *attrp2 = "test";
26+
27+ assert( LexingEnvUtils::GetLastAttributionItemInPath( attrp2 ) == attrp2 );
28+
29+ const char *attrp3 = "retro.";
30+
31+ assert( LexingEnvUtils::GetLastAttributionItemInPath( attrp3 ) == attrp3 + 6 );
32+
33+ const char *attrp4 = ".tooty";
34+
35+ assert( LexingEnvUtils::GetLastAttributionItemInPath( attrp4 ) == attrp4 + 1 );
36+
37+ const char *attrp5 = "root.loot.toot";
38+
39+ assert( LexingEnvUtils::GetLastAttributionItemInPath( attrp5 ) == attrp5 + 10 );
40+ }
41+ printf( "ok.\n" );
42+
1943 printf( "testing LexingEnvironment default-construction..." );
2044 {
2145 LexingEnvironment <char, LexNodeType> env;
@@ -888,6 +912,46 @@
888912 }
889913 printf( "ok.\n" );
890914
915+ printf( "testing ProductionMachine StepReplacementPoint..." );
916+ {
917+ // We test simple replacement execution, basically that replacements even work.
918+
919+ TestAllocEnv env( eir::constr_with_alloc::DEFAULT, &globalHeapAlloc );
920+
921+ decltype(env)::StepToken tok_basic( &env );
922+ tok_basic.token_str = "woof";
923+
924+ decltype(env)::StepAttribution replaceable_tok_basic( &env );
925+ replaceable_tok_basic.SetNode( &tok_basic );
926+ replaceable_tok_basic.replaceable = true;
927+
928+ decltype(env)::StepToken tok_replacement( &env );
929+ tok_replacement.token_str = "meow";
930+
931+ decltype(env)::StepReplacementPoint repl( &env );
932+ repl.SetNode( &replaceable_tok_basic );
933+ repl.SetReplacement( &tok_basic, &tok_replacement );
934+
935+ TestAllocEnv::ProductionMachine machine( &env );
936+
937+ machine.Execute( "woof", &tok_basic );
938+
939+ assert( machine.successful == true );
940+
941+ machine.Execute( "meow", &tok_basic );
942+
943+ assert( machine.successful == false );
944+
945+ machine.Execute( "meow", &repl );
946+
947+ assert( machine.successful == true );
948+
949+ machine.Execute( "woof", &repl );
950+
951+ assert( machine.successful == false );
952+ }
953+ printf( "ok.\n" );
954+
891955 printf( "testing ProductionMachine StepProceduralAlternatives..." );
892956 {
893957 // This step is no-longer considered the optimal way for operation associativity anymore.
@@ -2515,7 +2579,7 @@
25152579 // based on loops that create the empty word. Instead we want to limit our machine to syntaxes that do not produce
25162580 // the empty word in interim looping step sequences. If your syntax DOES produce the empty word in a sequence of steps
25172581 // that loop, then it will NOT work properly in our lexer, ever! This should be a fair requirement because you ought
2518- // to create such syntaxes for all programming languages anyway. If not then consult a smart book about this topic.
2582+ // to not create such syntaxes for all programming languages anyway. It is recommended to consult a smart book about this topic.
25192583
25202584 TestAllocEnv env( eir::constr_with_alloc::DEFAULT, &globalHeapAlloc );
25212585
Show on old repository browser