- 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
@@ -32,7 +32,8 @@ | ||
32 | 32 | concept CompilationTargetStep = ( |
33 | 33 | std::derived_from <typename std::remove_cvref <cStepType>::type, typename envType::StepAlternatives> || |
34 | 34 | 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> | |
36 | 37 | ); |
37 | 38 | |
38 | 39 | template <eir::CharacterType charType, LexerCompatibleNode <charType> nodeType, eir::MemoryAllocator allocatorType = CRTHeapAllocator> |
@@ -149,7 +150,7 @@ | ||
149 | 150 | |
150 | 151 | // Compiles the requested step and appends it onto the requested step type. |
151 | 152 | 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 ) | |
153 | 154 | { |
154 | 155 | if ( typename RuntimeEnv::Step *produced = compiler.CompileProduction( &defEnv, rulestring ) ) |
155 | 156 | { |
@@ -156,7 +157,7 @@ | ||
156 | 157 | try |
157 | 158 | { |
158 | 159 | appendToStep.AddConnection( produced ); |
159 | - return true; | |
160 | + return produced; | |
160 | 161 | } |
161 | 162 | catch( ... ) |
162 | 163 | { |
@@ -165,7 +166,7 @@ | ||
165 | 166 | } |
166 | 167 | } |
167 | 168 | |
168 | - return false; | |
169 | + return nullptr; | |
169 | 170 | } |
170 | 171 | |
171 | 172 | template <typename... otherCompilerArgs> |
@@ -173,12 +174,12 @@ | ||
173 | 174 | { |
174 | 175 | typename RuntimeEnv::StepAlternatives& altStep = defEnv.nonterminal_namespace.get( prodname, &defEnv ); |
175 | 176 | |
176 | - return CompileInto( compiler, altStep, rulestring ); | |
177 | + return ( CompileInto( compiler, altStep, rulestring ) != nullptr ); | |
177 | 178 | } |
178 | 179 | |
179 | 180 | // Compiles the requested step and appends it onto the requested step type. |
180 | 181 | 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 ) | |
182 | 183 | { |
183 | 184 | LexingCompiler <charType, RuntimeEnv, typename RuntimeEnv::EnvironmentAllocator> compiler( eir::constr_with_alloc::DEFAULT, &this->defEnv ); |
184 | 185 |
@@ -26,6 +26,60 @@ | ||
26 | 26 | #include <assert.h> |
27 | 27 | #endif //_DEBUG |
28 | 28 | |
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. | |
29 | 83 | namespace LexingEnvHelpers |
30 | 84 | { |
31 | 85 |
@@ -701,10 +755,12 @@ | ||
701 | 755 | this->exec = right.exec; |
702 | 756 | this->is_procedural_gate = right.is_procedural_gate; |
703 | 757 | this->base_on_extension = right.base_on_extension; |
758 | + this->replaceable = right.replaceable; | |
704 | 759 | |
705 | 760 | right.exec = nullptr; |
706 | 761 | right.is_procedural_gate = false; |
707 | 762 | right.base_on_extension = false; |
763 | + right.replaceable = false; | |
708 | 764 | } |
709 | 765 | |
710 | 766 | ~StepAttribution( void ) |
@@ -751,7 +807,8 @@ | ||
751 | 807 | Step *exec = nullptr; |
752 | 808 | public: |
753 | 809 | 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 | |
755 | 812 | |
756 | 813 | void SetNode( Step *node ) |
757 | 814 | { |
@@ -818,6 +875,7 @@ | ||
818 | 875 | public: |
819 | 876 | bool is_inline = false; |
820 | 877 | 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 | |
821 | 879 | bool is_procedural_gate = false; // if true then a procedural step will have to start at 0 if this is the most-recent find. |
822 | 880 | |
823 | 881 | void SetProductionName( const eir::FixedString <charType>& prodname ) |
@@ -2209,6 +2267,355 @@ | ||
2209 | 2267 | } |
2210 | 2268 | }; |
2211 | 2269 | |
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 | + | |
2212 | 2619 | struct EnvironmentAllocator |
2213 | 2620 | { |
2214 | 2621 | inline EnvironmentAllocator( LexingEnvironment *env ) noexcept : env( env ) |
@@ -3500,6 +3907,7 @@ | ||
3500 | 3907 | else if ( cstack_step == next_step ) |
3501 | 3908 | { |
3502 | 3909 | // Since there is no extension we just execute ourselves. |
3910 | + // This can be done by design. | |
3503 | 3911 | break; |
3504 | 3912 | } |
3505 | 3913 | } |
@@ -3508,6 +3916,50 @@ | ||
3508 | 3916 | return next_step; |
3509 | 3917 | }; |
3510 | 3918 | |
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 | + | |
3511 | 3963 | try |
3512 | 3964 | { |
3513 | 3965 | while ( has_op_finished == false ) |
@@ -3667,11 +4119,23 @@ | ||
3667 | 4119 | // This is done so that we can attach any attributes to nodes. |
3668 | 4120 | Step *next_step = attribstep->exec; |
3669 | 4121 | |
3670 | - if ( attribstep->base_on_extension ) | |
4122 | + Step *actual_call_step = nullptr; | |
4123 | + | |
4124 | + if ( attribstep->replaceable ) | |
3671 | 4125 | { |
3672 | - next_step = find_next_specialized_step( next_step, false ); | |
4126 | + actual_call_step = find_replacement_step( next_step ); | |
3673 | 4127 | } |
3674 | 4128 | |
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 | + | |
3675 | 4139 | if ( push_onto_execution( next_step ) == false ) |
3676 | 4140 | { |
3677 | 4141 | has_op_finished = true; |
@@ -3696,11 +4160,23 @@ | ||
3696 | 4160 | { |
3697 | 4161 | Step *next_step = &altsNode->GetValue(); |
3698 | 4162 | |
3699 | - if ( callstep->base_on_extension ) | |
4163 | + Step *actual_call_step = nullptr; | |
4164 | + | |
4165 | + if ( callstep->replaceable ) | |
3700 | 4166 | { |
3701 | - next_step = find_next_specialized_step( next_step, false ); | |
4167 | + actual_call_step = find_replacement_step( next_step ); | |
3702 | 4168 | } |
3703 | 4169 | |
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 | + | |
3704 | 4180 | if ( push_onto_execution( next_step, callstep->is_inline ) == false ) |
3705 | 4181 | { |
3706 | 4182 | has_op_finished = true; |
@@ -3933,6 +4409,16 @@ | ||
3933 | 4409 | is_op_successful = false; |
3934 | 4410 | } |
3935 | 4411 | } |
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 | + } | |
3936 | 4422 | else |
3937 | 4423 | { |
3938 | 4424 | FATAL_ABORT(); |
@@ -4464,6 +4950,7 @@ | ||
4464 | 4950 | // StepAttribution |
4465 | 4951 | // StepProceduralSequence |
4466 | 4952 | // StepCustomIndirection |
4953 | + // StepReplacementPoint | |
4467 | 4954 | |
4468 | 4955 | // This opcode has no further special handling. |
4469 | 4956 | has_op_finished = true; |
@@ -4704,6 +5191,8 @@ | ||
4704 | 5191 | IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepProceduralSequence::steps_redirAlloc, StepProceduralSequence, steps, env->allocMan, allocatorType ); |
4705 | 5192 | IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, StepCustomIndirection::refs_redirAlloc, StepCustomIndirection, refs, env->allocMan, allocatorType ); |
4706 | 5193 | 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 ); | |
4707 | 5196 | 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 ); |
4708 | 5197 | 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 ); |
4709 | 5198 | IMPL_HEAP_REDIR_DYN_ALLOC_TEMPLATEBASE( LexingEnvironment, LEXENV_TEMPLARGS_NODEF, LEXENV_TEMPLUSE, ProductionMachine::debug_breaks_redirAlloc, ProductionMachine, debug_breaks, env->allocMan, allocatorType ); |
@@ -325,7 +325,7 @@ | ||
325 | 325 | |
326 | 326 | struct DeclarationStatement : public COSNode |
327 | 327 | { |
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 ) | |
329 | 329 | { |
330 | 330 | return; |
331 | 331 | } |
@@ -345,7 +345,18 @@ | ||
345 | 345 | COSNode *type; |
346 | 346 | COSNode *initializer; |
347 | 347 | }; |
348 | +struct MultiDeclarationStatement : public COSNode | |
349 | +{ | |
350 | + // Just a pack of declarations because we cannot keep them outside. | |
348 | 351 | |
352 | + inline MultiDeclarationStatement( void ) noexcept | |
353 | + {} | |
354 | + inline MultiDeclarationStatement( const MultiDeclarationStatement& ) = default; | |
355 | + inline MultiDeclarationStatement( MultiDeclarationStatement&& ) = default; | |
356 | + | |
357 | + depVector <DeclarationStatement*> decls; | |
358 | +}; | |
359 | + | |
349 | 360 | struct TypedefStatement : public COSNode |
350 | 361 | { |
351 | 362 | inline TypedefStatement( COSNode *srctype = nullptr, COSNode *dsttype = nullptr ) noexcept : srctype( srctype ), dsttype( dsttype ) |
@@ -365,7 +376,18 @@ | ||
365 | 376 | COSNode *srctype; |
366 | 377 | COSNode *dsttype; |
367 | 378 | }; |
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; | |
368 | 387 | |
388 | + depVector <TypedefStatement*> defs; | |
389 | +}; | |
390 | + | |
369 | 391 | struct BlockStatement : public COSNode |
370 | 392 | { |
371 | 393 | inline BlockStatement( depVector <COSNode*> statements = {} ) noexcept : statements( std::move( statements ) ) |
@@ -596,6 +618,19 @@ | ||
596 | 618 | right.return_type = nullptr; |
597 | 619 | } |
598 | 620 | |
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 | + | |
599 | 634 | COSNode *return_type; |
600 | 635 | depVector <COSNode*> params; |
601 | 636 | }; |
@@ -698,7 +733,6 @@ | ||
698 | 733 | lexer.GetNamedProduction( "S" ).setSelector <mintwo_specialized_selector <char, Program, COSNode, program_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
699 | 734 | } |
700 | 735 | 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 ); | |
702 | 736 | assert( lexer.CompileProduction( compiler, "funcbody", "^!(block, <b> statement+funcstatement)" ) == true ); |
703 | 737 | assert( lexer.CompileProduction( compiler, "funcstatement", "\"return\" spaces (op:operation spaces)^0:1 ';'" ) == true ); |
704 | 738 | { |
@@ -734,29 +768,6 @@ | ||
734 | 768 | lexer.GetNamedProduction( "spec" ).GetLastStep()->setSelector <direct_obj_build_selector <char, ResolveSpecifierOperation, COSNode, dynspec_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
735 | 769 | } |
736 | 770 | 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 | - } | |
760 | 771 | assert( lexer.CompileProduction( compiler, "block", "'{' spaces [<0>statement:extended statement, spaces] spaces '}'" ) == true ); |
761 | 772 | { |
762 | 773 | struct block_dispatcher |
@@ -778,7 +789,7 @@ | ||
778 | 789 | { |
779 | 790 | auto operation = lexer.MakeStep <decltype(lexer)::RuntimeEnv::StepProceduralSequence> (); |
780 | 791 | |
781 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'=' spaces]" ) == true ); | |
792 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'=' spaces]" ) != nullptr ); | |
782 | 793 | { |
783 | 794 | struct assignment_dispatcher |
784 | 795 | { |
@@ -794,7 +805,7 @@ | ||
794 | 805 | }; |
795 | 806 | operation.GetLastStep()->setSelector <right_associative_selector <char, COSNode, assignment_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
796 | 807 | } |
797 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:\"||\" spaces]" ) == true ); | |
808 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:\"||\" spaces]" ) != nullptr ); | |
798 | 809 | { |
799 | 810 | struct logical_or_dispatcher |
800 | 811 | { |
@@ -810,7 +821,7 @@ | ||
810 | 821 | }; |
811 | 822 | operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, logical_or_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
812 | 823 | } |
813 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:\"&&\" spaces]" ) == true ); | |
824 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:\"&&\" spaces]" ) != nullptr ); | |
814 | 825 | { |
815 | 826 | struct logical_and_dispatcher |
816 | 827 | { |
@@ -826,7 +837,7 @@ | ||
826 | 837 | }; |
827 | 838 | operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, logical_and_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
828 | 839 | } |
829 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:(\"==\" | \"!=\" | \"<=\" | \">=\" | '<' | '>') spaces]" ) == true ); | |
840 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:(\"==\" | \"!=\" | \"<=\" | \">=\" | '<' | '>') spaces]" ) != nullptr ); | |
830 | 841 | { |
831 | 842 | struct logical_comparison_dispatcher |
832 | 843 | { |
@@ -910,7 +921,7 @@ | ||
910 | 921 | }; |
911 | 922 | operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, logical_comparison_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
912 | 923 | } |
913 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'|' spaces]" ) == true ); | |
924 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'|' spaces]" ) != nullptr ); | |
914 | 925 | { |
915 | 926 | struct bor_dispatcher |
916 | 927 | { |
@@ -926,7 +937,7 @@ | ||
926 | 937 | }; |
927 | 938 | operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, bor_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
928 | 939 | } |
929 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'^' spaces]" ) == true ); | |
940 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'^' spaces]" ) != nullptr ); | |
930 | 941 | { |
931 | 942 | struct bxor_dispatcher |
932 | 943 | { |
@@ -942,7 +953,7 @@ | ||
942 | 953 | }; |
943 | 954 | operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, bxor_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
944 | 955 | } |
945 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'&' spaces]" ) == true ); | |
956 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'&' spaces]" ) != nullptr ); | |
946 | 957 | { |
947 | 958 | struct band_dispatcher |
948 | 959 | { |
@@ -958,7 +969,7 @@ | ||
958 | 969 | }; |
959 | 970 | operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, band_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
960 | 971 | } |
961 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:('-'|'+') spaces]" ) == true ); | |
972 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:('-'|'+') spaces]" ) != nullptr ); | |
962 | 973 | { |
963 | 974 | struct summation_dispatcher |
964 | 975 | { |
@@ -1004,7 +1015,7 @@ | ||
1004 | 1015 | }; |
1005 | 1016 | operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, summation_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
1006 | 1017 | } |
1007 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:('*'|'/'|'%') spaces]" ) == true ); | |
1018 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:('*'|'/'|'%') spaces]" ) != nullptr ); | |
1008 | 1019 | { |
1009 | 1020 | struct muldiv_dispatcher |
1010 | 1021 | { |
@@ -1059,7 +1070,7 @@ | ||
1059 | 1070 | }; |
1060 | 1071 | operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, muldiv_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
1061 | 1072 | } |
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 ); | |
1063 | 1074 | { |
1064 | 1075 | struct quickunamod_dispatcher |
1065 | 1076 | { |
@@ -1126,7 +1137,7 @@ | ||
1126 | 1137 | }; |
1127 | 1138 | operation.GetLastStep()->setSelector <unary_operation_selector <char, COSNode, quickunamod_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
1128 | 1139 | } |
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 ); | |
1130 | 1141 | { |
1131 | 1142 | struct unary_negation_dispatcher |
1132 | 1143 | { |
@@ -1190,7 +1201,7 @@ | ||
1190 | 1201 | }; |
1191 | 1202 | operation.GetLastStep()->setSelector <unary_operation_selector <char, COSNode, unary_negation_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
1192 | 1203 | } |
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 ); | |
1194 | 1205 | { |
1195 | 1206 | struct call_selector |
1196 | 1207 | { |
@@ -1303,7 +1314,7 @@ | ||
1303 | 1314 | }; |
1304 | 1315 | operation.GetLastStep()->setSelector <call_selector> ( &lexer.GetRuntimeEnvironment() ); |
1305 | 1316 | } |
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 ); | |
1307 | 1318 | { |
1308 | 1319 | struct key_dispatcher |
1309 | 1320 | { |
@@ -1319,7 +1330,7 @@ | ||
1319 | 1330 | }; |
1320 | 1331 | operation.GetLastStep()->setSelector <left_associative_selector <char, COSNode, key_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
1321 | 1332 | } |
1322 | - assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'.' spaces]" ) == true ); | |
1333 | + assert( lexer.CompileInto( compiler, operation, "[opitem:operation, spaces optype:'.' spaces]" ) != nullptr ); | |
1323 | 1334 | { |
1324 | 1335 | struct dot_dispatcher |
1325 | 1336 | { |
@@ -1338,7 +1349,7 @@ | ||
1338 | 1349 | |
1339 | 1350 | auto tailop = lexer.MakeStep <decltype(lexer)::RuntimeEnv::StepAlternatives> (); |
1340 | 1351 | |
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 ); | |
1342 | 1353 | { |
1343 | 1354 | struct new_dispatcher |
1344 | 1355 | { |
@@ -1360,9 +1371,9 @@ | ||
1360 | 1371 | }; |
1361 | 1372 | tailop.GetLastStep()->setSelector <direct_obj_build_selector <char, NewOperation, COSNode, new_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
1362 | 1373 | } |
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 ); | |
1366 | 1377 | { |
1367 | 1378 | struct array_dispatcher |
1368 | 1379 | { |
@@ -1380,7 +1391,7 @@ | ||
1380 | 1391 | } |
1381 | 1392 | // Not ideal for again serializing into text, but we should be automatically detecting such a case anyway due to a fixed |
1382 | 1393 | // 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 ); | |
1384 | 1395 | |
1385 | 1396 | lexer.AddStepInto( operation, std::move( tailop ) ); |
1386 | 1397 |
@@ -1597,7 +1608,7 @@ | ||
1597 | 1608 | }; |
1598 | 1609 | lexer.GetNamedProduction( "except" ).GetLastStep()->setSelector <direct_obj_build_selector <char, ThrowStatement, COSNode, throw_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
1599 | 1610 | } |
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 ); | |
1601 | 1612 | { |
1602 | 1613 | struct catch_dispatcher |
1603 | 1614 | { |
@@ -1694,7 +1705,7 @@ | ||
1694 | 1705 | } |
1695 | 1706 | assert( lexer.CompileProduction( compiler, "typedef", "dtypedef | structdef" ) == true ); |
1696 | 1707 | 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 ); | |
1698 | 1709 | { |
1699 | 1710 | struct constructor_dispatcher |
1700 | 1711 | { |
@@ -1802,61 +1813,636 @@ | ||
1802 | 1813 | lexer.GetNamedProduction( "curlypack" ).setSelector <direct_obj_build_selector <char, CurlyPack, COSNode, curlypack_dispatcher, decltype(lexer)::RuntimeEnv>> ( &lexer.GetRuntimeEnvironment() ); |
1803 | 1814 | } |
1804 | 1815 | |
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 | |
1808 | 1817 | { |
1809 | - struct declaratory_type_builder | |
1818 | + enum class eLocatorType | |
1810 | 1819 | { |
1820 | + POINTER, | |
1821 | + REFERENCE | |
1822 | + }; | |
1811 | 1823 | |
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; | |
1812 | 1837 | }; |
1813 | 1838 | |
1814 | - struct multdecl_simple_selector | |
1839 | + inline void AssignAttribute( const eir::FixedString <char>& attrib, const eir::FixedString <char>& value ) | |
1815 | 1840 | { |
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 | + } | |
1816 | 1941 | |
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; | |
1818 | 2008 | }; |
2009 | + lexer.GetNamedProduction( "tmultdecl" ).setSelector <tmultdecl_selector> (); | |
1819 | 2010 | } |
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 ); | |
1822 | 2013 | { |
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> (); | |
1824 | 2072 | } |
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 ); | |
1828 | 2081 | { |
1829 | - // TODO: adjust this to match the lexing capabilities. | |
1830 | - struct declaration_dispatcher | |
2082 | + struct declaration_selector | |
1831 | 2083 | { |
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 ) | |
1833 | 2085 | { |
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" ) | |
1835 | 2092 | { |
1836 | - assign_to->type = node; | |
2093 | + this->utype = node; | |
1837 | 2094 | return true; |
1838 | 2095 | } |
1839 | - else if ( attrib == "name" ) | |
2096 | + else if ( attrib == "func" ) | |
1840 | 2097 | { |
1841 | - assign_to->name = node; | |
2098 | + this->func = dynamic_cast <FuncsigDefinition*> ( node ); | |
1842 | 2099 | return true; |
1843 | 2100 | } |
1844 | 2101 | else if ( attrib == "init" ) |
1845 | 2102 | { |
1846 | - assign_to->initializer = node; | |
2103 | + this->decl.initializer = node; | |
1847 | 2104 | return true; |
1848 | 2105 | } |
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 | + } | |
1849 | 2115 | return false; |
1850 | 2116 | } |
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; | |
1851 | 2170 | }; |
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 ) ); | |
1853 | 2337 | } |
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 | + } | |
1858 | 2395 | 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 | + } | |
1859 | 2404 | |
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 | + | |
1860 | 2446 | printf( "testing COS operations (non-deep)..." ); |
1861 | 2447 | { |
1862 | 2448 | assert( lexer.TestProduction( "1 + 1;" ) == true ); |
@@ -16,6 +16,30 @@ | ||
16 | 16 | |
17 | 17 | void LEXINGENV_TESTS( void ) |
18 | 18 | { |
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 | + | |
19 | 43 | printf( "testing LexingEnvironment default-construction..." ); |
20 | 44 | { |
21 | 45 | LexingEnvironment <char, LexNodeType> env; |
@@ -888,6 +912,46 @@ | ||
888 | 912 | } |
889 | 913 | printf( "ok.\n" ); |
890 | 914 | |
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 | + | |
891 | 955 | printf( "testing ProductionMachine StepProceduralAlternatives..." ); |
892 | 956 | { |
893 | 957 | // This step is no-longer considered the optimal way for operation associativity anymore. |
@@ -2515,7 +2579,7 @@ | ||
2515 | 2579 | // based on loops that create the empty word. Instead we want to limit our machine to syntaxes that do not produce |
2516 | 2580 | // the empty word in interim looping step sequences. If your syntax DOES produce the empty word in a sequence of steps |
2517 | 2581 | // 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. | |
2519 | 2583 | |
2520 | 2584 | TestAllocEnv env( eir::constr_with_alloc::DEFAULT, &globalHeapAlloc ); |
2521 | 2585 |