- actually implemented the step-extension reordering logic
- added StepCustomIndirection, a callback-based lexer production type that can select the next step based on calculation-path properties such as previously built nodes + made unit tests for it
@@ -101,13 +101,16 @@ | ||
101 | 101 | |
102 | 102 | typename cenv_t::SerializedStep spaced_comma_tok = &cenv; |
103 | 103 | |
104 | + typename cenv_t::StepToken tok_attributes_begin = &cenv; | |
105 | + typename cenv_t::StepToken tok_attributes_end = &cenv; | |
106 | + | |
104 | 107 | typename cenv_t::StepToken sepstep_tok_allow_item_term = &cenv; |
105 | 108 | typename cenv_t::StepToken comma_tok = &cenv; |
106 | 109 | typename cenv_t::SerializedStep sepstep_allow_item_term = &cenv; |
107 | 110 | typename cenv_t::StepRepeatByInterval sepstep_opt_allow_item_term = &cenv; |
108 | 111 | typename cenv_t::StepAttribution sepstep_attrib_mincnt = &cenv; |
109 | - typename cenv_t::StepToken sepstep_tok_attributes_begin = &cenv; | |
110 | - typename cenv_t::StepToken sepstep_tok_attributes_end = &cenv; | |
112 | + // sepstep_tok_attributes_begin = tok_attributes_begin | |
113 | + // sepstep_tok_attributes_end = tok_attributes_end | |
111 | 114 | typename cenv_t::SerializedStep sepstep_attributes = &cenv; |
112 | 115 | typename cenv_t::StepRepeatByInterval sepstep_opt_attributes = &cenv; |
113 | 116 | typename cenv_t::StepToken sepstep_tok_begin = &cenv; |
@@ -123,6 +126,9 @@ | ||
123 | 126 | typename cenv_t::StepAlternatives extstep_attrib = &cenv; |
124 | 127 | typename cenv_t::SerializedStep extstep_attrib_spacesappend = &cenv; |
125 | 128 | typename cenv_t::StepRepeatByInterval extstep_opt_attrib = &cenv; |
129 | + typename cenv_t::StepToken extstep_tok_before_usual = &cenv; | |
130 | + typename cenv_t::SerializedStep extstep_seq_itemattrib = &cenv; | |
131 | + typename cenv_t::StepRepeatByInterval extstep_opt_seq_itemattrib = &cenv; | |
126 | 132 | typename cenv_t::SerializedStep seqextend_prodseq = &cenv; |
127 | 133 | typename cenv_t::SerializedStep seqextend = &cenv; |
128 | 134 |
@@ -536,6 +542,9 @@ | ||
536 | 542 | // We now get to the steps which are either procgated or have enclosings/prefixes. |
537 | 543 | producible.AddConnection( &safe_enclosed_prod ); |
538 | 544 | |
545 | + tok_attributes_begin.token_str = _Token_LessThan <charType> (); | |
546 | + tok_attributes_end.token_str = _Token_GreaterThan <charType> (); | |
547 | + | |
539 | 548 | // *** SEPARATIONS *** |
540 | 549 | |
541 | 550 | // [<min,e>item,sep], [<min>item,sep], [item,sep] |
@@ -556,16 +565,13 @@ | ||
556 | 565 | sepstep_attrib_mincnt.SetNode( &numeric ); |
557 | 566 | sepstep_attrib_mincnt.attribute_key = _AttribKey_MinToken <charType> (); |
558 | 567 | |
559 | - sepstep_tok_attributes_begin.token_str = _Token_LessThan <charType> (); | |
560 | - sepstep_tok_attributes_end.token_str = _Token_GreaterThan <charType> (); | |
561 | - | |
562 | 568 | sepstep_attributes.SetConnections( { |
563 | - &sepstep_tok_attributes_begin, | |
569 | + &tok_attributes_begin, | |
564 | 570 | &spaces, |
565 | 571 | &sepstep_attrib_mincnt, |
566 | 572 | &sepstep_opt_allow_item_term, |
567 | 573 | &spaces, |
568 | - &sepstep_tok_attributes_end | |
574 | + &tok_attributes_end | |
569 | 575 | } ); |
570 | 576 | |
571 | 577 | sepstep_opt_attributes.SetNode( &sepstep_attributes ); |
@@ -624,7 +630,7 @@ | ||
624 | 630 | |
625 | 631 | // *** EXTEND STEP *** |
626 | 632 | |
627 | - // ^( ("extended")^0:1 extended, extension ) | |
633 | + // ^( ("extended")^0:1 extended, ("<b>")^0:1 extension ) | |
628 | 634 | tok_extend_beg.token_str = _Token_Elevation <charType> (); |
629 | 635 | tok_extend_beg.token_str += _Token_CurlyBrackets_Begin <charType> (); |
630 | 636 |
@@ -638,6 +644,21 @@ | ||
638 | 644 | extstep_opt_attrib.max_rep_cnt = 1; |
639 | 645 | extstep_opt_attrib.attribute_key = _AttribKey_Attribute <charType> (); |
640 | 646 | |
647 | + extstep_tok_before_usual.token_str = _Token_ExtensionProcessBefore <charType> (); | |
648 | + extstep_tok_before_usual.attribute_key = _AttribKey_ExtensionAttrib <charType> (); | |
649 | + | |
650 | + extstep_seq_itemattrib.SetConnections( { | |
651 | + &tok_attributes_begin, | |
652 | + &extstep_tok_before_usual, | |
653 | + &tok_attributes_end, | |
654 | + &spaces | |
655 | + } ); | |
656 | + | |
657 | + extstep_opt_seq_itemattrib.SetNode( &extstep_seq_itemattrib ); | |
658 | + extstep_opt_seq_itemattrib.min_rep_cnt = 0; | |
659 | + extstep_opt_seq_itemattrib.has_maximum = true; | |
660 | + extstep_opt_seq_itemattrib.max_rep_cnt = 1; | |
661 | + | |
641 | 662 | seqextend_prodseq.SetConnections( { |
642 | 663 | &extstep_opt_attrib, |
643 | 664 | &spaces, |
@@ -649,6 +670,7 @@ | ||
649 | 670 | &spaces, |
650 | 671 | &seqextend_prodseq, |
651 | 672 | &spaced_comma_tok, |
673 | + &extstep_opt_seq_itemattrib, | |
652 | 674 | &producible_procgate, |
653 | 675 | &spaces, |
654 | 676 | &tok_cbrackets_end |
@@ -670,7 +692,7 @@ | ||
670 | 692 | |
671 | 693 | // *** EXTENSION-POINT STEP *** |
672 | 694 | |
673 | - // ^!(p, extend1+extension1, extend2+extension2, ..., extendn+extensionn) | |
695 | + // ^!(p, ("<b>")^0:1 extend1+extension1, ("<b>")^0:1 extend2+extension2, ..., ("<b>")^0:1 extendn+extensionn) | |
674 | 696 | tok_extpt_begin.token_str = _Token_Elevation <charType> (); |
675 | 697 | tok_extpt_begin.token_str += _Token_ExclamationPoint <charType> (); |
676 | 698 | tok_extpt_begin.token_str += _Token_CurlyBrackets_Begin <charType> (); |
@@ -678,6 +700,7 @@ | ||
678 | 700 | tok_plus.token_str = _Token_Plus <charType> (); |
679 | 701 | |
680 | 702 | seqextpt_extitem.SetConnections( { |
703 | + &extstep_opt_seq_itemattrib, | |
681 | 704 | &seqextend_prodseq, |
682 | 705 | &spaces, |
683 | 706 | &tok_plus, |
@@ -1107,7 +1130,7 @@ | ||
1107 | 1130 | template <eir::CharacterType charType> |
1108 | 1131 | static AINLINE bool IsAttribCharacter( charType ucp ) |
1109 | 1132 | { |
1110 | - static const char validchars[] = "abcdefghijklmnopqrstuvwyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"; | |
1133 | + static const char validchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"; | |
1111 | 1134 | |
1112 | 1135 | for ( char c : validchars ) |
1113 | 1136 | { |
@@ -1303,6 +1326,31 @@ | ||
1303 | 1326 | } |
1304 | 1327 | |
1305 | 1328 | template <eir::CharacterType charType> |
1329 | + static AINLINE const charType* _AttribKey_ExtensionAttrib( void ) noexcept | |
1330 | + { | |
1331 | + if constexpr ( std::same_as <charType, char> ) | |
1332 | + { | |
1333 | + return "extattrib"; | |
1334 | + } | |
1335 | + if constexpr ( std::same_as <charType, wchar_t> ) | |
1336 | + { | |
1337 | + return L"extattrib"; | |
1338 | + } | |
1339 | + if constexpr ( std::same_as <charType, char8_t> ) | |
1340 | + { | |
1341 | + return u8"extattrib"; | |
1342 | + } | |
1343 | + if constexpr ( std::same_as <charType, char16_t> ) | |
1344 | + { | |
1345 | + return u"extattrib"; | |
1346 | + } | |
1347 | + if constexpr ( std::same_as <charType, char32_t> ) | |
1348 | + { | |
1349 | + return U"extattrib"; | |
1350 | + } | |
1351 | + } | |
1352 | + | |
1353 | + template <eir::CharacterType charType> | |
1306 | 1354 | static AINLINE const charType* _AttribKey_ProductionNode( void ) noexcept |
1307 | 1355 | { |
1308 | 1356 | if constexpr ( std::same_as <charType, char> ) |
@@ -1777,6 +1825,31 @@ | ||
1777 | 1825 | } |
1778 | 1826 | |
1779 | 1827 | template <eir::CharacterType charType> |
1828 | + static AINLINE const charType* _Token_ExtensionProcessBefore( void ) noexcept | |
1829 | + { | |
1830 | + if constexpr ( std::same_as <charType, char> ) | |
1831 | + { | |
1832 | + return "b"; | |
1833 | + } | |
1834 | + if constexpr ( std::same_as <charType, wchar_t> ) | |
1835 | + { | |
1836 | + return L"b"; | |
1837 | + } | |
1838 | + if constexpr ( std::same_as <charType, char8_t> ) | |
1839 | + { | |
1840 | + return u8"b"; | |
1841 | + } | |
1842 | + if constexpr ( std::same_as <charType, char16_t> ) | |
1843 | + { | |
1844 | + return u"b"; | |
1845 | + } | |
1846 | + if constexpr ( std::same_as <charType, char32_t> ) | |
1847 | + { | |
1848 | + return U"b"; | |
1849 | + } | |
1850 | + } | |
1851 | + | |
1852 | + template <eir::CharacterType charType> | |
1780 | 1853 | static AINLINE const charType* _Token_LessThan( void ) noexcept |
1781 | 1854 | { |
1782 | 1855 | if constexpr ( std::same_as <charType, char> ) |
@@ -1917,6 +1990,13 @@ | ||
1917 | 1990 | { |
1918 | 1991 | this->SetExtendedNode( &this->env->nonterminal_namespace.get( value, this->env ) ); |
1919 | 1992 | } |
1993 | + else if ( attrib == _AttribKey_ExtensionAttrib <charType> () ) | |
1994 | + { | |
1995 | + if ( value == _Token_ExtensionProcessBefore <charType> () ) | |
1996 | + { | |
1997 | + this->extension_is_before_usual = true; | |
1998 | + } | |
1999 | + } | |
1920 | 2000 | } |
1921 | 2001 | |
1922 | 2002 | bool AssignNode( const eir::FixedString <charType>& attrib, ExecStep *node ) override |
@@ -1507,10 +1507,12 @@ | ||
1507 | 1507 | this->extended = right.extended; |
1508 | 1508 | this->extension = right.extension; |
1509 | 1509 | this->extended_base_on_extension = right.extended_base_on_extension; |
1510 | + this->extension_is_before_usual = right.extension_is_before_usual; | |
1510 | 1511 | |
1511 | 1512 | right.extended = nullptr; |
1512 | 1513 | right.extension = nullptr; |
1513 | 1514 | right.extended_base_on_extension = false; |
1515 | + right.extension_is_before_usual = false; | |
1514 | 1516 | } |
1515 | 1517 | inline StepExtend( const StepExtend& right ) = default; |
1516 | 1518 |
@@ -1587,8 +1589,9 @@ | ||
1587 | 1589 | bool extended_base_on_extension = false; // if true then we look for a most-recent extension of the step to base ourselves on, if failure then the step directly. |
1588 | 1590 | private: |
1589 | 1591 | Step *extension = nullptr; |
1592 | + public: | |
1593 | + bool extension_is_before_usual = false; // if true then the extension steps are executed before the extended steps; by default extensions are executed afterward. | |
1590 | 1594 | |
1591 | - public: | |
1592 | 1595 | void SetExtendedNode( Step *node ) |
1593 | 1596 | { |
1594 | 1597 | Step *extended = this->extended; |
@@ -2101,6 +2104,110 @@ | ||
2101 | 2104 | } |
2102 | 2105 | }; |
2103 | 2106 | |
2107 | + // Forward declaration. | |
2108 | + struct ProductionMachine; | |
2109 | + | |
2110 | + struct StepCustomIndirection : public Step | |
2111 | + { | |
2112 | + friend struct LexingEnvironment; | |
2113 | + | |
2114 | + using Step::Step; | |
2115 | + | |
2116 | + inline StepCustomIndirection( const StepCustomIndirection& ) = default; | |
2117 | + inline StepCustomIndirection( StepCustomIndirection&& ) = default; | |
2118 | + | |
2119 | + inline ~StepCustomIndirection( void ) | |
2120 | + { | |
2121 | + auto *env = this->env; | |
2122 | + | |
2123 | + for ( Step *n : refs ) | |
2124 | + { | |
2125 | + env->gcReachSched.OnRemoveConnection( this, n ); | |
2126 | + } | |
2127 | + } | |
2128 | + | |
2129 | + Step* Clone( void ) override | |
2130 | + { | |
2131 | + return this->env->CloneStep <StepCustomIndirection> ( this ); | |
2132 | + } | |
2133 | + | |
2134 | + Step* GetNextConnectionsToNode( Step *prev ) override | |
2135 | + { | |
2136 | + auto *nextNode = this->refs.FindJustAbove( prev ); | |
2137 | + | |
2138 | + return ( nextNode ? nextNode->GetValue() : nullptr ); | |
2139 | + } | |
2140 | + | |
2141 | + bool IsUnambiguousCall( void ) const noexcept override | |
2142 | + { | |
2143 | + // Just like call or attribution, this Step does pick a next one. | |
2144 | + return true; | |
2145 | + } | |
2146 | + | |
2147 | + bool IsUndeniableChange( void ) const noexcept override | |
2148 | + { | |
2149 | + // This step itself does not change a thing but the below one which gets picked next would | |
2150 | + // be re-evaluated based on it's own metrics so we are safe to return true regardless. | |
2151 | + return true; | |
2152 | + } | |
2153 | + | |
2154 | + size_t GetChoiceCount( void ) const noexcept override | |
2155 | + { | |
2156 | + // We do know that there would always be just one step at maximum. | |
2157 | + // It is not valid to return different steps for the same calculation path conditions. | |
2158 | + return 1; | |
2159 | + } | |
2160 | + | |
2161 | + private: | |
2162 | + DEFINE_HEAP_REDIR_ALLOC_BYSTRUCT( refs_redirAlloc, allocatorType ); | |
2163 | + | |
2164 | + eir::Set <Step*, refs_redirAlloc> refs; | |
2165 | + | |
2166 | + DEFINE_HEAP_REDIR_ALLOC_BYSTRUCT( callback_redirAlloc, allocatorType ); | |
2167 | + | |
2168 | + public: | |
2169 | + eir::Function <callback_redirAlloc, eir::DefaultExceptionManager, Step*, ProductionMachine& /* machine */> callback; | |
2170 | + | |
2171 | + // Sets the use-connections for the garbage collectors. | |
2172 | + // This way the sub-steps are kept alive for at-least as long as this step is. | |
2173 | + inline void SetConnections( const depVector <Step*> refs ) | |
2174 | + { | |
2175 | + LexingEnvironment *env = this->env; | |
2176 | + | |
2177 | + for ( Step *n : refs ) | |
2178 | + { | |
2179 | + if ( this->refs.Find( n ) == nullptr ) | |
2180 | + { | |
2181 | + this->refs.Insert( n ); | |
2182 | + | |
2183 | + env->gcReachSched.OnAddedConnection( this, n ); | |
2184 | + } | |
2185 | + } | |
2186 | + } | |
2187 | + | |
2188 | + inline void AddConnection( Step *n ) | |
2189 | + { | |
2190 | + if ( this->refs.Find( n ) ) | |
2191 | + return; | |
2192 | + | |
2193 | + this->refs.Insert( n ); | |
2194 | + | |
2195 | + this->env->gcReachSched.OnAddedConnection( this, n ); | |
2196 | + } | |
2197 | + | |
2198 | + inline void RemoveConnection( Step *n ) | |
2199 | + { | |
2200 | + auto *findNode = this->refs.Find( n ); | |
2201 | + | |
2202 | + if ( findNode == nullptr ) | |
2203 | + return; | |
2204 | + | |
2205 | + this->refs.RemoveNode( findNode ); | |
2206 | + | |
2207 | + this->env->gcReachSched.OnRemoveConnection( this, n ); | |
2208 | + } | |
2209 | + }; | |
2210 | + | |
2104 | 2211 | struct EnvironmentAllocator |
2105 | 2212 | { |
2106 | 2213 | inline EnvironmentAllocator( LexingEnvironment *env ) noexcept : env( env ) |
@@ -2489,9 +2596,13 @@ | ||
2489 | 2596 | this->debug_breaks = std::move( right.debug_breaks ); |
2490 | 2597 | this->resultNode = right.resultNode; |
2491 | 2598 | this->successful = right.successful; |
2599 | + this->current_calc_stack = right.current_calc_stack; | |
2600 | + this->current_calc_stack_top = right.current_calc_stack_top; | |
2492 | 2601 | |
2493 | 2602 | right.resultNode = nullptr; |
2494 | 2603 | right.successful = false; |
2604 | + right.current_calc_stack = nullptr; | |
2605 | + right.current_calc_stack_top = nullptr; | |
2495 | 2606 | } |
2496 | 2607 | inline ProductionMachine( const ProductionMachine& ) = delete; |
2497 | 2608 |
@@ -2516,6 +2627,16 @@ | ||
2516 | 2627 | eir::Vector <CalcPathEntry, EnvironmentAllocator> _calc_stack( eir::constr_with_alloc::DEFAULT, this->env ); |
2517 | 2628 | CalcPathEntry entry( start_step ); // top of the calc_stack, on the C++-stack for better performance. |
2518 | 2629 | |
2630 | + // We mandate that there can be only one concurrent execution task at a time. | |
2631 | + this->current_calc_stack = &_calc_stack; | |
2632 | + this->current_calc_stack_top = &entry; | |
2633 | + | |
2634 | + auto cleanup_calc_links = [&]( void ) | |
2635 | + { | |
2636 | + this->current_calc_stack = nullptr; | |
2637 | + this->current_calc_stack_top = nullptr; | |
2638 | + }; | |
2639 | + | |
2519 | 2640 | auto get_calcstack_size = [&]( void ) -> size_t |
2520 | 2641 | { |
2521 | 2642 | return ( _calc_stack.GetCount() + 1 ); |
@@ -3434,7 +3555,9 @@ | ||
3434 | 3555 | } |
3435 | 3556 | else |
3436 | 3557 | { |
3437 | - if ( idx == 0 ) | |
3558 | + bool extension_is_before_usual = extstep->extension_is_before_usual; | |
3559 | + | |
3560 | + if ( extension_is_before_usual == false && idx == 0 || extension_is_before_usual == true && idx == 1 ) | |
3438 | 3561 | { |
3439 | 3562 | size_t calcstack_size = get_calcstack_size(); |
3440 | 3563 |
@@ -3457,7 +3580,7 @@ | ||
3457 | 3580 | // Extension-search should know that the frame is not the most-special one. |
3458 | 3581 | entry.was_called_by_extend = true; |
3459 | 3582 | } |
3460 | - else | |
3583 | + else if ( extension_is_before_usual == false && idx == 1 || extension_is_before_usual == true && idx == 0 ) | |
3461 | 3584 | { |
3462 | 3585 | Step *next_step = extstep->extension; |
3463 | 3586 |
@@ -3531,6 +3654,16 @@ | ||
3531 | 3654 | } |
3532 | 3655 | } |
3533 | 3656 | } |
3657 | + else if ( StepCustomIndirection *indirstep = dynamic_cast <StepCustomIndirection*> ( current_step ) ) | |
3658 | + { | |
3659 | + Step *next_step = indirstep->callback( *this ); | |
3660 | + | |
3661 | + if ( next_step == nullptr || push_onto_execution( next_step ) == false ) | |
3662 | + { | |
3663 | + has_op_finished = true; | |
3664 | + is_op_successful = false; | |
3665 | + } | |
3666 | + } | |
3534 | 3667 | else |
3535 | 3668 | { |
3536 | 3669 | FATAL_ABORT(); |
@@ -3849,6 +3982,7 @@ | ||
3849 | 3982 | |
3850 | 3983 | if ( has_node || has_selector ) |
3851 | 3984 | { |
3985 | + entry.appendAttributePrefix( current_step->attribute_key.ToFixed() ); | |
3852 | 3986 | entry.appendAttributePrefix( prev_step->attribute_key.ToFixed() ); |
3853 | 3987 | try |
3854 | 3988 | { |
@@ -3888,6 +4022,7 @@ | ||
3888 | 4022 | is_op_successful = false; |
3889 | 4023 | } |
3890 | 4024 | entry.debuildAttributePrefix( prev_step->attribute_key.ToFixed() ); |
4025 | + entry.debuildAttributePrefix( current_step->attribute_key.ToFixed() ); | |
3891 | 4026 | } |
3892 | 4027 | // If we are successful and there is no node in the previous step and the previous |
3893 | 4028 | // step is not ambiguous, then write the node as result. |
@@ -4025,6 +4160,7 @@ | ||
4025 | 4160 | // StepCall |
4026 | 4161 | // StepAttribution |
4027 | 4162 | // StepProceduralSequence |
4163 | + // StepCustomIndirection | |
4028 | 4164 | |
4029 | 4165 | // This opcode has no further special handling. |
4030 | 4166 | has_op_finished = true; |
@@ -4060,8 +4196,12 @@ | ||
4060 | 4196 | leave_execution( entry ); |
4061 | 4197 | } |
4062 | 4198 | |
4199 | + cleanup_calc_links(); | |
4200 | + | |
4063 | 4201 | throw; |
4064 | 4202 | } |
4203 | + | |
4204 | + cleanup_calc_links(); | |
4065 | 4205 | } |
4066 | 4206 | |
4067 | 4207 | inline cNodeType* DetachNode( void ) noexcept |
@@ -4099,10 +4239,119 @@ | ||
4099 | 4239 | } |
4100 | 4240 | } |
4101 | 4241 | |
4242 | + // *** BEGIN METHODS FOR STEPS WITH CUSTOM CALLBACKS *** | |
4243 | + | |
4244 | + inline size_t GetCurrentCalcStackSize( void ) const noexcept | |
4245 | + { | |
4246 | + size_t calc_stack_size = 0; | |
4247 | + | |
4248 | + if ( this->current_calc_stack_top ) | |
4249 | + { | |
4250 | + calc_stack_size++; | |
4251 | + } | |
4252 | + | |
4253 | + if ( auto *current_calc_stack = this->current_calc_stack ) | |
4254 | + { | |
4255 | + calc_stack_size += current_calc_stack->GetCount(); | |
4256 | + } | |
4257 | + | |
4258 | + return calc_stack_size; | |
4259 | + } | |
4260 | + | |
4261 | + inline size_t GetCurrentCalcStackMostRecentIndex( Step *node ) const | |
4262 | + { | |
4263 | + auto *current_calc_stack = this->current_calc_stack; | |
4264 | + CalcPathEntry *current_calc_stack_top = this->current_calc_stack_top; | |
4265 | + | |
4266 | + if ( current_calc_stack == nullptr || current_calc_stack_top == nullptr ) | |
4267 | + { | |
4268 | + throw eir::eir_exception(); | |
4269 | + } | |
4270 | + | |
4271 | + size_t _calc_stack_size_notop = ( current_calc_stack->GetCount() ); | |
4272 | + | |
4273 | + if ( node == current_calc_stack_top->current_step ) | |
4274 | + { | |
4275 | + return _calc_stack_size_notop; | |
4276 | + } | |
4277 | + | |
4278 | + while ( _calc_stack_size_notop > 0 ) | |
4279 | + { | |
4280 | + _calc_stack_size_notop--; | |
4281 | + | |
4282 | + CalcPathEntry& cur_ent = (*current_calc_stack)[ _calc_stack_size_notop ]; | |
4283 | + | |
4284 | + if ( cur_ent.current_step == node ) | |
4285 | + { | |
4286 | + return _calc_stack_size_notop; | |
4287 | + } | |
4288 | + } | |
4289 | + | |
4290 | + throw eir::eir_exception(); | |
4291 | + } | |
4292 | + | |
4293 | + private: | |
4294 | + AINLINE CalcPathEntry& GetCurrentExecutionCalcPathEntryByIndex( size_t cstack_idx ) const | |
4295 | + { | |
4296 | + auto *current_calc_stack = this->current_calc_stack; | |
4297 | + CalcPathEntry *current_calc_stack_top = this->current_calc_stack_top; | |
4298 | + | |
4299 | + if ( current_calc_stack == nullptr || current_calc_stack_top == nullptr ) | |
4300 | + { | |
4301 | + throw eir::eir_exception(); | |
4302 | + } | |
4303 | + | |
4304 | + size_t _cstack_size_notop = current_calc_stack->GetCount(); | |
4305 | + size_t cstack_size = ( 1 + _cstack_size_notop ); | |
4306 | + | |
4307 | + if ( cstack_idx >= cstack_size ) | |
4308 | + { | |
4309 | + throw eir::eir_exception(); | |
4310 | + } | |
4311 | + | |
4312 | + if ( cstack_idx == _cstack_size_notop ) | |
4313 | + { | |
4314 | + return *current_calc_stack_top; | |
4315 | + } | |
4316 | + | |
4317 | + CalcPathEntry& ent = (*current_calc_stack)[ cstack_idx ]; | |
4318 | + | |
4319 | + return ent; | |
4320 | + } | |
4321 | + | |
4322 | + public: | |
4323 | + inline Step* GetCurrentExecutionStepByIndex( size_t cstack_idx ) const | |
4324 | + { | |
4325 | + CalcPathEntry& ent = GetCurrentExecutionCalcPathEntryByIndex( cstack_idx ); | |
4326 | + | |
4327 | + return ent.current_step; | |
4328 | + } | |
4329 | + | |
4330 | + inline cNodeType* GetCurrentExecutionNodeByIndex( size_t cstack_idx ) const | |
4331 | + { | |
4332 | + CalcPathEntry& ent = GetCurrentExecutionCalcPathEntryByIndex( cstack_idx ); | |
4333 | + | |
4334 | + return std::get <cNodeType*> ( ent.pcalc ); | |
4335 | + } | |
4336 | + | |
4337 | + // Returns the selector-meta-data that is provided for construction by the setSelector template parameter. | |
4338 | + // Using this method does require knowledge about the production hierarchy and their node construction behaviour. | |
4339 | + inline void* GetCurrentExecutionSelectorDataByIndex( size_t cstack_idx ) const | |
4340 | + { | |
4341 | + CalcPathEntry& ent = GetCurrentExecutionCalcPathEntryByIndex( cstack_idx ); | |
4342 | + | |
4343 | + return ent.selectorMetaData; | |
4344 | + } | |
4345 | + | |
4346 | + // *** END METHODS FOR STEPS WITH CUSTOM CALLBACKS *** | |
4347 | + | |
4102 | 4348 | LexingEnvironment *env; |
4103 | 4349 | bool successful = false; |
4104 | 4350 | cNodeType *resultNode = nullptr; |
4105 | 4351 | |
4352 | + eir::Vector <CalcPathEntry, EnvironmentAllocator> *current_calc_stack = nullptr; | |
4353 | + CalcPathEntry *current_calc_stack_top = nullptr; | |
4354 | + | |
4106 | 4355 | private: |
4107 | 4356 | DEFINE_HEAP_REDIR_ALLOC_BYSTRUCT( debug_breaks_redirAlloc, allocatorType ); |
4108 | 4357 |
@@ -4150,6 +4399,8 @@ | ||
4150 | 4399 | IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepExtensionPoint::extensions_redirAlloc, StepExtensionPoint, extensions, env->allocMan, allocatorType ); |
4151 | 4400 | IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepProceduralAlternatives::alts_redirAlloc, StepProceduralAlternatives, alts, env->allocMan, allocatorType ); |
4152 | 4401 | IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepProceduralSequence::steps_redirAlloc, StepProceduralSequence, steps, env->allocMan, allocatorType ); |
4402 | +IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepCustomIndirection::refs_redirAlloc, StepCustomIndirection, refs, env->allocMan, allocatorType ); | |
4403 | +IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepCustomIndirection::callback_redirAlloc, StepCustomIndirection, callback, env->allocMan, allocatorType ); | |
4153 | 4404 | 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 ); |
4154 | 4405 | 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 ); |
4155 | 4406 | IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, ProductionMachine::debug_breaks_redirAlloc, ProductionMachine, debug_breaks, env->allocMan, allocatorType ); |
@@ -674,8 +674,8 @@ | ||
674 | 674 | }; |
675 | 675 | lexer.GetNamedProduction( "S" ).setSelector <mintwo_specialized_selector <char, Program, COSNode, program_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
676 | 676 | } |
677 | - assert( lexer.CompileProduction( compiler, "statement", "function | typedef | block | loop | if | except | objmod | takefirst declaration spaces ';' | takefirst operation spaces ';'" ) == true ); | |
678 | - assert( lexer.CompileProduction( compiler, "function", "(type:spec spaces)^0:1 (\"func\" | \"operator\") spaces name:spec spaces '(' spaces param:paramlist spaces ')' spaces body:funcbody" ) == true ); | |
677 | + assert( lexer.CompileProduction( compiler, "statement", "function | typedef | block | loop | if | except | objmod | takefirst multdecl spaces ';' | takefirst operation spaces ';'" ) == true ); | |
678 | + assert( lexer.CompileProduction( compiler, "function", "(type:spec spaces)^0:1 (\"func\" | \"operator\") spaces name:spec spaces '(' spaces paramlist spaces ')' spaces body:funcbody" ) == true ); | |
679 | 679 | { |
680 | 680 | struct function_dispatcher |
681 | 681 | { |
@@ -706,7 +706,7 @@ | ||
706 | 706 | }; |
707 | 707 | lexer.GetNamedProduction( "function" ).setSelector <direct_obj_build_selector <char, FunctionDefinition, COSNode, function_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
708 | 708 | } |
709 | - assert( lexer.CompileProduction( compiler, "paramlist", "[<0>declaration, spaces ',' spaces]" ) == true ); | |
709 | + assert( lexer.CompileProduction( compiler, "paramlist", "[<0>param:declaration, spaces ',' spaces]" ) == true ); | |
710 | 710 | assert( lexer.CompileProduction( compiler, "funcbody", "^!(block, <b> statement+funcstatement)" ) == true ); |
711 | 711 | assert( lexer.CompileProduction( compiler, "funcstatement", "\"return\" spaces (op:operation spaces)^0:1 ';'" ) == true ); |
712 | 712 | { |
@@ -757,32 +757,6 @@ | ||
757 | 757 | }; |
758 | 758 | lexer.GetNamedProduction( "spec" ).GetLastStep()->setSelector <direct_obj_build_selector <char, PointerTypeSpecifier, COSNode, ptr_spec_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
759 | 759 | } |
760 | - assert( lexer.CompileProduction( compiler, "declaration", "(type:spec spaces)^0:1 name:spec ( spaces '=' spaces init:operation | spaces init:curlypack )^0:1" ) == true ); | |
761 | - { | |
762 | - struct declaration_dispatcher | |
763 | - { | |
764 | - static inline bool AssignNodeTo( DeclarationStatement *assign_to, const eir::FixedString <char>& attrib, COSNode *node ) | |
765 | - { | |
766 | - if ( attrib == "type" ) | |
767 | - { | |
768 | - assign_to->type = node; | |
769 | - return true; | |
770 | - } | |
771 | - else if ( attrib == "name" ) | |
772 | - { | |
773 | - assign_to->name = node; | |
774 | - return true; | |
775 | - } | |
776 | - else if ( attrib == "init" ) | |
777 | - { | |
778 | - assign_to->initializer = node; | |
779 | - return true; | |
780 | - } | |
781 | - return false; | |
782 | - } | |
783 | - }; | |
784 | - lexer.GetNamedProduction( "declaration" ).setSelector <direct_obj_build_selector <char, DeclarationStatement, COSNode, declaration_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); | |
785 | - } | |
786 | 760 | assert( lexer.CompileProduction( compiler, "dtypedef", "\"typedef\" spaces srctype:spec spaces dsttype:spec spaces ';'" ) == true ); |
787 | 761 | { |
788 | 762 | struct typedef_dispatcher |
@@ -1385,7 +1359,7 @@ | ||
1385 | 1359 | |
1386 | 1360 | auto tailop = lexer.MakeStep <decltype(lexer)::RuntimeEnv::StepAlternatives> (); |
1387 | 1361 | |
1388 | - assert( lexer.CompileInto( compiler, tailop, "\"new\" spaces type:spec spaces ('(' spaces param:paramlist spaces ')')^0:1" ) == true ); | |
1362 | + assert( lexer.CompileInto( compiler, tailop, "\"new\" spaces type:spec spaces ('(' spaces paramlist spaces ')')^0:1" ) == true ); | |
1389 | 1363 | { |
1390 | 1364 | struct new_dispatcher |
1391 | 1365 | { |
@@ -1741,7 +1715,7 @@ | ||
1741 | 1715 | } |
1742 | 1716 | assert( lexer.CompileProduction( compiler, "typedef", "dtypedef | structdef" ) == true ); |
1743 | 1717 | assert( lexer.CompileProduction( compiler, "typestatement", "constructor | destructor" ) == true ); |
1744 | - assert( lexer.CompileProduction( compiler, "constructor", "\"constructor\" spaces '(' spaces param:paramlist spaces ')' spaces body:extended funcbody" ) == true ); | |
1718 | + assert( lexer.CompileProduction( compiler, "constructor", "\"constructor\" spaces '(' spaces paramlist spaces ')' spaces body:extended funcbody" ) == true ); | |
1745 | 1719 | { |
1746 | 1720 | struct constructor_dispatcher |
1747 | 1721 | { |
@@ -1848,7 +1822,58 @@ | ||
1848 | 1822 | }; |
1849 | 1823 | lexer.GetNamedProduction( "curlypack" ).setSelector <direct_obj_build_selector <char, CurlyPack, COSNode, curlypack_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
1850 | 1824 | } |
1825 | + | |
1826 | + // Type system COS structures. | |
1827 | + assert( lexer.CompileProduction( compiler, "declinit", "( spaces '=' spaces init:operation | spaces init:curlypack )^0:1" ) == true ); | |
1828 | + assert( lexer.CompileProduction( compiler, "locator", "loc:'*' spaces locator | loc:'&' | loc:'*'" ) == true ); | |
1829 | + assert( lexer.CompileProduction( compiler, "multdecl", "(utype:spec spaces)^0:1 [locatedname declinit, spaces ',' spaces]" ) == true ); | |
1830 | + { | |
1831 | + struct declaratory_type_builder | |
1832 | + { | |
1851 | 1833 | |
1834 | + }; | |
1835 | + | |
1836 | + struct multdecl_simple_selector | |
1837 | + { | |
1838 | + | |
1839 | + COSNode *type; | |
1840 | + }; | |
1841 | + } | |
1842 | + assert( lexer.CompileProduction( compiler, "multdecl", "[funcsigdecl declinit, spaces ',' spaces]" ) == true ); | |
1843 | + assert( lexer.CompileProduction( compiler, "funcsigdecl", "rtype:type spaces (\"func\" | \"proto\") spaces '(' spaces locatedname spaces ')' spaces '(' spaces paramlist spaces ')'" ) == true ); | |
1844 | + assert( lexer.CompileProduction( compiler, "locatedname", "(locator spaces)^0:1 name:spec (spaces [arrspec:arrayspec, spaces])" ) == true ); | |
1845 | + assert( lexer.CompileProduction( compiler, "arrayspec", "'[' spaces (idx:operation spaces)^0:1 ']'" ) == true ); | |
1846 | + assert( lexer.CompileProduction( compiler, "declaration", "(type:spec spaces)^0:1 locatedname declinit" ) == true ); | |
1847 | + { | |
1848 | + // TODO: adjust this to match the lexing capabilities. | |
1849 | + struct declaration_dispatcher | |
1850 | + { | |
1851 | + static inline bool AssignNodeTo( DeclarationStatement *assign_to, const eir::FixedString <char>& attrib, COSNode *node ) | |
1852 | + { | |
1853 | + if ( attrib == "type" ) | |
1854 | + { | |
1855 | + assign_to->type = node; | |
1856 | + return true; | |
1857 | + } | |
1858 | + else if ( attrib == "name" ) | |
1859 | + { | |
1860 | + assign_to->name = node; | |
1861 | + return true; | |
1862 | + } | |
1863 | + else if ( attrib == "init" ) | |
1864 | + { | |
1865 | + assign_to->initializer = node; | |
1866 | + return true; | |
1867 | + } | |
1868 | + return false; | |
1869 | + } | |
1870 | + }; | |
1871 | + lexer.GetNamedProduction( "declaration" ).setSelector <direct_obj_build_selector <char, DeclarationStatement, COSNode, declaration_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); | |
1872 | + } | |
1873 | + assert( lexer.CompileProduction( compiler, "declaration", "funcsigdecl declinit" ) == true ); | |
1874 | + assert( lexer.CompileProduction( compiler, "type", "utype:spec (spaces locator)^0:1 (spaces [arrspec:arrayspec, spaces])" ) == true ); | |
1875 | + assert( lexer.CompileProduction( compiler, "type", "rtype:type spaces (\"func\" | \"proto\") spaces '(' spaces (locator spaces)^0:1 ([arrspec:arrayspec, spaces] spaces)^0:1 ')' spaces '(' spaces paramlist spaces ')'" ) == true ); | |
1876 | + | |
1852 | 1877 | printf( "testing COS operations (non-deep)..." ); |
1853 | 1878 | { |
1854 | 1879 | assert( lexer.TestProduction( "1 + 1;" ) == true ); |
@@ -5615,6 +5615,558 @@ | ||
5615 | 5615 | } |
5616 | 5616 | printf( "ok.\n" ); |
5617 | 5617 | |
5618 | + printf( "testing ProductionMachine StepCustomIndirection..." ); | |
5619 | + { | |
5620 | + // We perform a declaration-building test, which is what we would do in COS anyway but more complex. | |
5621 | + | |
5622 | + static size_t _alive_node_count = 0; | |
5623 | + | |
5624 | + struct node | |
5625 | + { | |
5626 | + inline node( void ) noexcept | |
5627 | + { | |
5628 | + _alive_node_count++; | |
5629 | + } | |
5630 | + inline node( const node& right ) | |
5631 | + { | |
5632 | + _alive_node_count++; | |
5633 | + } | |
5634 | + inline node( node&& right ) noexcept | |
5635 | + { | |
5636 | + _alive_node_count++; | |
5637 | + } | |
5638 | + | |
5639 | + virtual ~node( void ) | |
5640 | + { | |
5641 | + _alive_node_count--; | |
5642 | + } | |
5643 | + | |
5644 | + inline void Delete( void ) noexcept | |
5645 | + { | |
5646 | + delete this; | |
5647 | + } | |
5648 | + }; | |
5649 | + | |
5650 | + struct spec : public node | |
5651 | + { | |
5652 | + inline spec( depString <char> token = {} ) noexcept : token( std::move( token ) ) | |
5653 | + {} | |
5654 | + | |
5655 | + depString <char> token; | |
5656 | + }; | |
5657 | + | |
5658 | + struct unary : public node | |
5659 | + { | |
5660 | + inline unary( node *sub ) noexcept : sub( sub ) | |
5661 | + {} | |
5662 | + | |
5663 | + node *sub; | |
5664 | + }; | |
5665 | + | |
5666 | + struct ptrloc : public unary | |
5667 | + { | |
5668 | + using unary::unary; | |
5669 | + }; | |
5670 | + struct refloc : public unary | |
5671 | + { | |
5672 | + using unary::unary; | |
5673 | + }; | |
5674 | + | |
5675 | + struct arrspec : public unary | |
5676 | + { | |
5677 | + using unary::unary; | |
5678 | + }; | |
5679 | + | |
5680 | + struct decl : public node | |
5681 | + { | |
5682 | + inline decl( node *type = nullptr, node *name = nullptr, node *init = nullptr ) noexcept : type( type ), name( name ), init( init ) | |
5683 | + { | |
5684 | + return; | |
5685 | + } | |
5686 | + | |
5687 | + node *type = nullptr; | |
5688 | + node *name = nullptr; | |
5689 | + node *init = nullptr; | |
5690 | + }; | |
5691 | + | |
5692 | + struct arrnode : public node | |
5693 | + { | |
5694 | + depVector <node*> items; | |
5695 | + }; | |
5696 | + | |
5697 | + LexingEnvironment <char, node, EirHeapLinkAllocator> env( eir::constr_with_alloc::DEFAULT, &globalHeapAlloc ); | |
5698 | + | |
5699 | + decltype(env)::StepToken tok_arrspec( &env ); | |
5700 | + tok_arrspec.token_str = "[]"; | |
5701 | + | |
5702 | + decltype(env)::StepToken tok_ptr( &env ); | |
5703 | + tok_ptr.token_str = "*"; | |
5704 | + | |
5705 | + decltype(env)::StepToken tok_ref( &env ); | |
5706 | + tok_ref.token_str = "&"; | |
5707 | + | |
5708 | + decltype(env)::StepRepeatAny repptr( &env ); | |
5709 | + repptr.SetNode( &tok_ptr ); | |
5710 | + repptr.attribute_key = "loc"; | |
5711 | + | |
5712 | + decltype(env)::StepRepeatByInterval opt_ref( &env ); | |
5713 | + opt_ref.SetNode( &tok_ref ); | |
5714 | + opt_ref.min_rep_cnt = 0; | |
5715 | + opt_ref.has_maximum = true; | |
5716 | + opt_ref.max_rep_cnt = 1; | |
5717 | + opt_ref.attribute_key = "loc"; | |
5718 | + | |
5719 | + decltype(env)::StepToken tok_whitespace( &env ); | |
5720 | + tok_whitespace.token_str = " "; | |
5721 | + | |
5722 | + decltype(env)::StepRepeatAny spaces( &env ); | |
5723 | + spaces.SetNode( &tok_whitespace ); | |
5724 | + | |
5725 | + decltype(env)::SerializedStep locator( &env ); | |
5726 | + locator.SetConnections( { &repptr, &opt_ref, &spaces } ); | |
5727 | + | |
5728 | + decltype(env)::StepRepeatAny reparrspec( &env ); | |
5729 | + reparrspec.SetNode( &tok_arrspec ); | |
5730 | + reparrspec.attribute_key = "arrspec"; | |
5731 | + | |
5732 | + decltype(env)::StepProgrammableToken tok_spec( &env ); | |
5733 | + tok_spec.callback = []( decltype(env)::LexingPoint& pt ) -> std::optional <eir::FixedString <char>> | |
5734 | + { | |
5735 | + const char *start_ptr = pt.GetCurrentData(); | |
5736 | + | |
5737 | + while ( pt.GetRemainder() > 0 ) | |
5738 | + { | |
5739 | + char ucp = pt.ReadCharacter(); | |
5740 | + | |
5741 | + if ( !( ucp >= 'a' && ucp <= 'z' || ucp >= 'A' && ucp <= 'Z' || ucp == '_' ) ) | |
5742 | + { | |
5743 | + pt.SetOffset( pt.GetOffset() - 1 ); | |
5744 | + break; | |
5745 | + } | |
5746 | + } | |
5747 | + | |
5748 | + const char *end_ptr = pt.GetCurrentData(); | |
5749 | + | |
5750 | + size_t cnt = ( end_ptr - start_ptr ); | |
5751 | + | |
5752 | + if ( cnt == 0 ) | |
5753 | + return std::nullopt; | |
5754 | + | |
5755 | + return eir::FixedString <char> ( start_ptr, cnt ); | |
5756 | + }; | |
5757 | + | |
5758 | + decltype(env)::StepAttribution spec_utype( &env ); | |
5759 | + spec_utype.SetNode( &tok_spec ); | |
5760 | + spec_utype.attribute_key = "utype"; | |
5761 | + | |
5762 | + decltype(env)::StepAttribution spec_name( &env ); | |
5763 | + spec_name.SetNode( &tok_spec ); | |
5764 | + spec_name.attribute_key = "name"; | |
5765 | + | |
5766 | + decltype(env)::StepToken tok_arrbeg( &env ); | |
5767 | + tok_arrbeg.token_str = "{"; | |
5768 | + | |
5769 | + decltype(env)::StepToken tok_arrend( &env ); | |
5770 | + tok_arrend.token_str = "}"; | |
5771 | + | |
5772 | + decltype(env)::StepProgrammableToken vspec( &env ); | |
5773 | + vspec.callback = []( decltype(env)::LexingPoint& pt ) -> std::optional <eir::FixedString <char>> | |
5774 | + { | |
5775 | + const char *start_ptr = pt.GetCurrentData(); | |
5776 | + | |
5777 | + while ( pt.GetRemainder() > 0 ) | |
5778 | + { | |
5779 | + char ucp = pt.ReadCharacter(); | |
5780 | + | |
5781 | + if ( !( ucp >= 'a' && ucp <= 'z' || ucp >= 'A' && ucp <= 'Z' || ucp >= '0' && ucp <= '9' || ucp == '_' ) ) | |
5782 | + { | |
5783 | + pt.SetOffset( pt.GetOffset() - 1 ); | |
5784 | + break; | |
5785 | + } | |
5786 | + } | |
5787 | + | |
5788 | + const char *end_ptr = pt.GetCurrentData(); | |
5789 | + | |
5790 | + size_t cnt = ( end_ptr - start_ptr ); | |
5791 | + | |
5792 | + if ( cnt == 0 ) | |
5793 | + return std::nullopt; | |
5794 | + | |
5795 | + return eir::FixedString <char> ( start_ptr, cnt ); | |
5796 | + }; | |
5797 | + | |
5798 | + decltype(env)::StepAttribution vspec_attrib_spec( &env ); | |
5799 | + vspec_attrib_spec.SetNode( &vspec ); | |
5800 | + vspec_attrib_spec.attribute_key = "spec"; | |
5801 | + | |
5802 | + struct valinit_builder | |
5803 | + { | |
5804 | + static inline void AssignAttributeTo( spec *assign_to, const eir::FixedString <char>& attrib, const eir::FixedString <char>& value ) | |
5805 | + { | |
5806 | + assign_to->token = value; | |
5807 | + } | |
5808 | + }; | |
5809 | + | |
5810 | + decltype(env)::SerializedStep valinit_outer( &env ); | |
5811 | + valinit_outer.SetConnections( { &tok_arrbeg, &vspec_attrib_spec, &tok_arrend } ); | |
5812 | + valinit_outer.setSelector <direct_obj_build_selector <char, spec, node, valinit_builder, decltype(env)>> ( &env ); | |
5813 | + | |
5814 | + decltype(env)::StepAttribution valinit_inner( &env ); | |
5815 | + valinit_inner.SetNode( &vspec ); | |
5816 | + valinit_inner.attribute_key = "spec"; | |
5817 | + valinit_inner.setSelector <direct_obj_build_selector <char, spec, node, valinit_builder, decltype(env)>> ( &env ); | |
5818 | + | |
5819 | + decltype(env)::StepCustomIndirection init_expr( &env ); | |
5820 | + init_expr.attribute_key = "init"; | |
5821 | + | |
5822 | + decltype(env)::StepToken tok_comma( &env ); | |
5823 | + tok_comma.token_str = ","; | |
5824 | + | |
5825 | + decltype(env)::StepSeparation sepinit( &env ); | |
5826 | + sepinit.SetItemStep( &init_expr ); | |
5827 | + sepinit.SetSeparationStep( &tok_comma ); | |
5828 | + sepinit.min_item_cnt = 0; | |
5829 | + sepinit.is_alternation = false; | |
5830 | + sepinit.attribute_key = "item"; | |
5831 | + | |
5832 | + struct arr_builder | |
5833 | + { | |
5834 | + static inline bool AssignNodeTo( arrnode *assign_to, const eir::FixedString <char>& attrib, node *n ) | |
5835 | + { | |
5836 | + assign_to->items.AddToBack( n ); | |
5837 | + return true; | |
5838 | + } | |
5839 | + }; | |
5840 | + | |
5841 | + decltype(env)::SerializedStep arrinit( &env ); | |
5842 | + arrinit.SetConnections( { &tok_arrbeg, &sepinit, &tok_arrend } ); | |
5843 | + arrinit.setSelector <direct_obj_build_selector <char, arrnode, node, arr_builder, decltype(env)>> ( &env ); | |
5844 | + | |
5845 | + struct producible_selector | |
5846 | + { | |
5847 | + inline void AssignAttribute( const eir::FixedString <char>& attrib, const eir::FixedString <char>& value ) | |
5848 | + { | |
5849 | + if ( attrib == "utype" ) | |
5850 | + { | |
5851 | + this->type = new spec( value ); | |
5852 | + } | |
5853 | + else if ( attrib == "loc" ) | |
5854 | + { | |
5855 | + if ( value == "*" ) | |
5856 | + { | |
5857 | + this->type = new ptrloc( this->type ); | |
5858 | + } | |
5859 | + else if ( value == "&" ) | |
5860 | + { | |
5861 | + this->type = new refloc( this->type ); | |
5862 | + } | |
5863 | + } | |
5864 | + else if ( attrib == "arrspec" ) | |
5865 | + { | |
5866 | + this->type = new arrspec( this->type ); | |
5867 | + } | |
5868 | + else if ( attrib == "name" ) | |
5869 | + { | |
5870 | + this->name = new spec( value ); | |
5871 | + } | |
5872 | + } | |
5873 | + | |
5874 | + inline bool AssignNode( const eir::FixedString <char>& attrib, node *n ) | |
5875 | + { | |
5876 | + if ( attrib == "init" ) | |
5877 | + { | |
5878 | + this->init = n; | |
5879 | + return true; | |
5880 | + } | |
5881 | + | |
5882 | + return false; | |
5883 | + } | |
5884 | + | |
5885 | + inline node* DetachFinishedNode( void ) | |
5886 | + { | |
5887 | + return new decl( this->type, this->name, this->init ); | |
5888 | + } | |
5889 | + | |
5890 | + node *type = nullptr; | |
5891 | + node *name = nullptr; | |
5892 | + node *init = nullptr; | |
5893 | + }; | |
5894 | + | |
5895 | + decltype(env)::SerializedStep producible( &env ); | |
5896 | + producible.SetConnections( { &spec_utype, &locator, &spec_name, &reparrspec, &init_expr } ); | |
5897 | + producible.setSelector <producible_selector> (); | |
5898 | + | |
5899 | + init_expr.callback = [&]( decltype(env)::ProductionMachine& machine ) -> decltype(env)::Step* | |
5900 | + { | |
5901 | + size_t prod_idx = machine.GetCurrentCalcStackMostRecentIndex( &producible ); | |
5902 | + size_t idx_below_cur = ( machine.GetCurrentCalcStackSize() - 1 ); | |
5903 | + | |
5904 | + // Returns the depth of this production. | |
5905 | + size_t init_depth = 0; | |
5906 | + | |
5907 | + for ( size_t n = prod_idx; n < idx_below_cur; n++ ) | |
5908 | + { | |
5909 | + auto *s = machine.GetCurrentExecutionStepByIndex( n ); | |
5910 | + | |
5911 | + if ( s == &init_expr ) | |
5912 | + { | |
5913 | + init_depth++; | |
5914 | + } | |
5915 | + } | |
5916 | + | |
5917 | + producible_selector *prod_man = (producible_selector*)machine.GetCurrentExecutionSelectorDataByIndex( prod_idx ); | |
5918 | + | |
5919 | + node *type = prod_man->type; | |
5920 | + | |
5921 | + size_t init_iter = init_depth; | |
5922 | + | |
5923 | + while ( init_iter > 0 ) | |
5924 | + { | |
5925 | + init_iter--; | |
5926 | + | |
5927 | + if ( ptrloc *ploc = dynamic_cast <ptrloc*> ( type ) ) | |
5928 | + { | |
5929 | + type = ploc->sub; | |
5930 | + } | |
5931 | + else if ( refloc *rloc = dynamic_cast <refloc*> ( type ) ) | |
5932 | + { | |
5933 | + type = rloc->sub; | |
5934 | + } | |
5935 | + else if ( arrspec *as = dynamic_cast <arrspec*> ( type ) ) | |
5936 | + { | |
5937 | + type = as->sub; | |
5938 | + } | |
5939 | + } | |
5940 | + | |
5941 | + if ( dynamic_cast <arrspec*> ( type ) != nullptr ) | |
5942 | + { | |
5943 | + return &arrinit; | |
5944 | + } | |
5945 | + else if ( init_depth > 0 ) | |
5946 | + { | |
5947 | + return &valinit_inner; | |
5948 | + } | |
5949 | + else | |
5950 | + { | |
5951 | + return &valinit_outer; | |
5952 | + } | |
5953 | + }; | |
5954 | + | |
5955 | + decltype(env)::ProductionMachine machine( &env ); | |
5956 | + | |
5957 | + // 1) | |
5958 | + machine.Execute( "int a[]{1,2,3}", &producible ); | |
5959 | + | |
5960 | + assert( machine.successful == true ); | |
5961 | + { | |
5962 | + decl *root = dynamic_cast <decl*> ( machine.DetachNode() ); | |
5963 | + | |
5964 | + assert( root != nullptr ); | |
5965 | + | |
5966 | + arrspec *type = dynamic_cast <arrspec*> ( root->type ); | |
5967 | + | |
5968 | + assert( type != nullptr ); | |
5969 | + | |
5970 | + spec *type_sub = dynamic_cast <spec*> ( type->sub ); | |
5971 | + | |
5972 | + assert( type_sub != nullptr ); | |
5973 | + assert( type_sub->token == "int" ); | |
5974 | + | |
5975 | + type_sub->Delete(); | |
5976 | + | |
5977 | + type->Delete(); | |
5978 | + | |
5979 | + spec *name = dynamic_cast <spec*> ( root->name ); | |
5980 | + | |
5981 | + assert( name != nullptr ); | |
5982 | + assert( name->token == "a" ); | |
5983 | + | |
5984 | + name->Delete(); | |
5985 | + | |
5986 | + arrnode *init = dynamic_cast <arrnode*> ( root->init ); | |
5987 | + | |
5988 | + assert( init != nullptr ); | |
5989 | + assert( init->items.GetCount() == 3 ); | |
5990 | + | |
5991 | + spec *first = dynamic_cast <spec*> ( init->items[0] ); | |
5992 | + spec *second = dynamic_cast <spec*> ( init->items[1] ); | |
5993 | + spec *third = dynamic_cast <spec*> ( init->items[2] ); | |
5994 | + | |
5995 | + assert( first != nullptr ); | |
5996 | + assert( first->token == "1" ); | |
5997 | + assert( second != nullptr ); | |
5998 | + assert( second->token == "2" ); | |
5999 | + assert( third != nullptr ); | |
6000 | + assert( third->token == "3" ); | |
6001 | + | |
6002 | + first->Delete(); | |
6003 | + second->Delete(); | |
6004 | + third->Delete(); | |
6005 | + | |
6006 | + init->Delete(); | |
6007 | + root->Delete(); | |
6008 | + } | |
6009 | + | |
6010 | + // 2) | |
6011 | + machine.Execute( "int*b{nullptr}", &producible ); | |
6012 | + | |
6013 | + assert( machine.successful == true ); | |
6014 | + { | |
6015 | + decl *root = dynamic_cast <decl*> ( machine.DetachNode() ); | |
6016 | + | |
6017 | + assert( root != nullptr ); | |
6018 | + | |
6019 | + ptrloc *type = dynamic_cast <ptrloc*> ( root->type ); | |
6020 | + | |
6021 | + assert( type != nullptr ); | |
6022 | + | |
6023 | + spec *type_sub = dynamic_cast <spec*> ( type->sub ); | |
6024 | + | |
6025 | + assert( type_sub != nullptr ); | |
6026 | + assert( type_sub->token == "int" ); | |
6027 | + | |
6028 | + type_sub->Delete(); | |
6029 | + | |
6030 | + type->Delete(); | |
6031 | + | |
6032 | + spec *name = dynamic_cast <spec*> ( root->name ); | |
6033 | + | |
6034 | + assert( name != nullptr ); | |
6035 | + assert( name->token == "b" ); | |
6036 | + | |
6037 | + name->Delete(); | |
6038 | + | |
6039 | + spec *first = dynamic_cast <spec*> ( root->init ); | |
6040 | + | |
6041 | + assert( first != nullptr ); | |
6042 | + assert( first->token == "nullptr" ); | |
6043 | + | |
6044 | + first->Delete(); | |
6045 | + | |
6046 | + root->Delete(); | |
6047 | + } | |
6048 | + | |
6049 | + // 3) | |
6050 | + machine.Execute( "int c[][]{{9,7},{},{1}}", &producible ); | |
6051 | + | |
6052 | + assert( machine.successful == true ); | |
6053 | + { | |
6054 | + decl *root = dynamic_cast <decl*> ( machine.DetachNode() ); | |
6055 | + | |
6056 | + assert( root != nullptr ); | |
6057 | + | |
6058 | + arrspec *type = dynamic_cast <arrspec*> ( root->type ); | |
6059 | + | |
6060 | + assert( type != nullptr ); | |
6061 | + | |
6062 | + arrspec *type_sub = dynamic_cast <arrspec*> ( type->sub ); | |
6063 | + | |
6064 | + assert( type_sub != nullptr ); | |
6065 | + | |
6066 | + spec *type_sub_sub = dynamic_cast <spec*> ( type_sub->sub ); | |
6067 | + | |
6068 | + assert( type_sub_sub != nullptr ); | |
6069 | + assert( type_sub_sub->token == "int" ); | |
6070 | + | |
6071 | + type_sub_sub->Delete(); | |
6072 | + | |
6073 | + type_sub->Delete(); | |
6074 | + type->Delete(); | |
6075 | + | |
6076 | + spec *name = dynamic_cast <spec*> ( root->name ); | |
6077 | + | |
6078 | + assert( name != nullptr ); | |
6079 | + assert( name->token == "c" ); | |
6080 | + | |
6081 | + name->Delete(); | |
6082 | + | |
6083 | + arrnode *init = dynamic_cast <arrnode*> ( root->init ); | |
6084 | + | |
6085 | + assert( init != nullptr ); | |
6086 | + assert( init->items.GetCount() == 3 ); | |
6087 | + | |
6088 | + arrnode *init_first = dynamic_cast <arrnode*> ( init->items[0] ); | |
6089 | + | |
6090 | + assert( init_first != nullptr ); | |
6091 | + assert( init_first->items.GetCount() == 2 ); | |
6092 | + | |
6093 | + spec *init_first_first = dynamic_cast <spec*> ( init_first->items[0] ); | |
6094 | + | |
6095 | + assert( init_first_first != nullptr ); | |
6096 | + assert( init_first_first->token == "9" ); | |
6097 | + | |
6098 | + init_first_first->Delete(); | |
6099 | + | |
6100 | + spec *init_first_second = dynamic_cast <spec*> ( init_first->items[1] ); | |
6101 | + | |
6102 | + assert( init_first_second != nullptr ); | |
6103 | + assert( init_first_second->token == "7" ); | |
6104 | + | |
6105 | + init_first_second->Delete(); | |
6106 | + | |
6107 | + init_first->Delete(); | |
6108 | + | |
6109 | + arrnode *init_second = dynamic_cast <arrnode*> ( init->items[1] ); | |
6110 | + | |
6111 | + assert( init_second != nullptr ); | |
6112 | + assert( init_second->items.GetCount() == 0 ); | |
6113 | + | |
6114 | + init_second->Delete(); | |
6115 | + | |
6116 | + arrnode *init_third = dynamic_cast <arrnode*> ( init->items[2] ); | |
6117 | + | |
6118 | + assert( init_third != nullptr ); | |
6119 | + assert( init_third->items.GetCount() == 1 ); | |
6120 | + | |
6121 | + spec *init_third_first = dynamic_cast <spec*> ( init_third->items[0] ); | |
6122 | + | |
6123 | + assert( init_third_first != nullptr ); | |
6124 | + assert( init_third_first->token == "1" ); | |
6125 | + | |
6126 | + init_third_first->Delete(); | |
6127 | + | |
6128 | + init_third->Delete(); | |
6129 | + init->Delete(); | |
6130 | + root->Delete(); | |
6131 | + } | |
6132 | + | |
6133 | + // 4) | |
6134 | + machine.Execute( "int a{0}", &producible ); | |
6135 | + | |
6136 | + assert( machine.successful == true ); | |
6137 | + { | |
6138 | + decl *root = dynamic_cast <decl*> ( machine.DetachNode() ); | |
6139 | + | |
6140 | + assert( root != nullptr ); | |
6141 | + | |
6142 | + spec *type = dynamic_cast <spec*> ( root->type ); | |
6143 | + | |
6144 | + assert( type != nullptr ); | |
6145 | + assert( type->token == "int" ); | |
6146 | + | |
6147 | + type->Delete(); | |
6148 | + | |
6149 | + spec *name = dynamic_cast <spec*> ( root->name ); | |
6150 | + | |
6151 | + assert( name != nullptr ); | |
6152 | + assert( name->token == "a" ); | |
6153 | + | |
6154 | + name->Delete(); | |
6155 | + | |
6156 | + spec *init = dynamic_cast <spec*> ( root->init ); | |
6157 | + | |
6158 | + assert( init != nullptr ); | |
6159 | + assert( init->token == "0" ); | |
6160 | + | |
6161 | + init->Delete(); | |
6162 | + | |
6163 | + root->Delete(); | |
6164 | + } | |
6165 | + | |
6166 | + assert( _alive_node_count == 0 ); | |
6167 | + } | |
6168 | + printf( "ok.\n" ); | |
6169 | + | |
5618 | 6170 | printf( "testing ProductionMachine mintwo-specialized-selector (simple list)..." ); |
5619 | 6171 | { |
5620 | 6172 | struct Node |