YSTest: NPLA1.cpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

NPLA1.cpp
浏览该文件的文档.
1 /*
2 © 2014-2020 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include "NPL/YModules.h"
29 #include YFM_NPL_NPLA1Forms // for YSLib, NPL, Forms, RelaySwitched,
30 // type_index, string_view, std::hash, ystdex::equal_to, YSLib::unordered_map,
31 // std::piecewise_construct, YSLib::lock_guard, YSLib::mutex, ystdex::type_id,
32 // ContextHandler, NPL::make_observer, ystdex::ref, lref, IValueHolder,
33 // YSLib::AllocatedHolderOperations, any, ystdex::as_const,
34 // NPL::forward_as_tuple, uintmax_t, TokenValue, function, std::allocator_arg,
35 // stack, vector, std::find_if, TermTags, TermReference, GetLValueTagsOf,
36 // NPL::TryAccessLeaf, NPL::IsMovable, in_place_type, InvalidReference,
37 // IsBranch, NPL::Deref, IsLeaf, ResolveTerm, ystdex::update_thunk,
38 // NPL::Access, ystdex::retry_on_cond, AccessFirstSubterm, ystdex::bind1,
39 // ystdex::make_transform, IsBranchedList, std::placeholders, NoContainer,
40 // ystdex::try_emplace, Environment, shared_ptr, ystdex::unique_guard,
41 // NPL::AsTermNode, CategorizeBasicLexeme, DeliteralizeUnchecked,
42 // CheckReducible, Deliteralize, ystdex::isdigit, ResolveIdentifier,
43 // IsNPLAExtendedLiteral, ystdex::ref_eq, NPL::TryAccessTerm,
44 // YSLib::share_move, ystdex::call_value_or, Session;
45 #include "NPLA1Internals.h" // for A1::Internals API;
46 #include YFM_NPL_Dependency // for A1::OpenUnique;
47
48 using namespace YSLib;
49
50 namespace NPL
51 {
52
54
55 #ifndef NDEBUG
56 # define NPL_Impl_NPLA1_AssertParameterMatch true
57 #else
58 # define NPL_Impl_NPLA1_AssertParameterMatch false
59 #endif
60
61
62 namespace A1
63 {
64
65 string
66 to_string(ValueToken vt)
67 {
68 switch(vt)
69 {
70 case ValueToken::Null:
71 return "null";
72 case ValueToken::Undefined:
73 return "undefined";
74 case ValueToken::Unspecified:
75 return "unspecified";
76 case ValueToken::GroupingAnchor:
77 return "grouping";
78 case ValueToken::OrderedAnchor:
79 return "ordered";
80 }
81 throw std::invalid_argument("Invalid value token found.");
82 }
83
85 namespace
86 {
87
88 #if NPL_Impl_NPLA1_Enable_Thunked
89 struct PushedAction final
91 {
92 EvaluationPasses::const_iterator First, Last;
93 lref<const ContextHandler> HandlerRef;
94 lref<TermNode> TermRef;
95 lref<ContextNode> ContextRef;
96
97 ReductionStatus
98 operator()(ContextNode&) const;
99 };
100
102 void
103 PushActionsRange(EvaluationPasses::const_iterator first,
104 EvaluationPasses::const_iterator last, TermNode& term, ContextNode& ctx)
105 {
106 if(first != last)
107 {
108 // NOTE: Retrying is recognized from the result since 1st administrative
109 // pass is reduced. The non-skipped administrative reductions are
110 // reduced in the tail context, otherwise they are dropped by no-op.
111 if(ctx.LastStatus != ReductionStatus::Retrying)
112 {
113 const auto& f(first->second);
114
115 ++first;
116 SetupNextTerm(ctx, term);
117 RelaySwitched(ctx, PushedAction{first, last, f, term, ctx});
118 }
119 }
120 else
121 // NOTE: This skips the remained incompleted sequence of passes in the
122 // subsequent evaluation (if any). Otherwise, %ReductionStatus::Neutral
123 // will be set before the 1st pass at %DoAdministratives for a complete
124 // evaluation.
125 ctx.LastStatus = ReductionStatus::Retrying;
126 }
127
128 ReductionStatus
129 PushedAction::operator()(ContextNode&) const
130 {
131 auto& term(TermRef.get());
132 auto& ctx(ContextRef.get());
133
134 PushActionsRange(First, Last, term, ctx);
135
136 const auto res(HandlerRef(term, ctx));
137
138 if(res != ReductionStatus::Partial)
139 ctx.LastStatus
140 = CombineSequenceReductionResult(ctx.LastStatus, res);
141 return ctx.LastStatus;
142 }
143 #endif
144
146 YSLib::mutex NameTableMutex;
147
149
150 using NameTable = YSLib::unordered_map<type_index, string_view,
151 std::hash<type_index>, ystdex::equal_to<type_index>,
152 std::allocator<std::pair<const type_index, string_view>>>;
153
154 template<class _tKey>
155 YB_ATTR_nodiscard inline NameTable&
156 FetchNameTableRef()
157 {
158 return ystdex::parameterize_static_object<NameTable, _tKey>();
159 }
161
162 #if NPL_Impl_NPLA1_Enable_Thunked
163 YB_ATTR(always_inline) inline ReductionStatus
165 ReduceChildrenOrderedAsync(TNIter, TNIter, ContextNode&);
166
168 ReductionStatus
169 ReduceChildrenOrderedAsyncUnchecked(TNIter first, TNIter last, ContextNode& ctx)
170 {
171 YAssert(first != last, "Invalid range found.");
172
173 auto& term(*first++);
174
175 return ReduceSubsequent(term, ctx, Continuation(
176 NameTypedContextHandler([first, last](TermNode&, ContextNode& c){
177 return ReduceChildrenOrderedAsync(first, last, c);
178 }, "eval-argument-list"), ctx));
179 }
180
181 YB_ATTR(always_inline) inline ReductionStatus
182 ReduceChildrenOrderedAsync(TNIter first, TNIter last, ContextNode& ctx)
183 {
184 return first != last ? ReduceChildrenOrderedAsyncUnchecked(first, last, ctx)
185 : ReductionStatus::Neutral;
186 }
187 #endif
188
189
191 template<typename... _tParams>
192 ReductionStatus
193 CombinerReturnThunk(const ContextHandler& h, TermNode& term, ContextNode& ctx,
194 _tParams&&... args)
195 {
196 static_assert(sizeof...(args) < 2, "Unsupported owner arguments found.");
197 #if NPL_Impl_NPLA1_Enable_TCO
198 auto& act(EnsureTCOAction(ctx, term));
199 auto& lf(act.LastFunction);
200
201 ContextState::Access(ctx).ClearCombiningTerm();
202 term.Value.Clear();
203 lf = {};
204 // XXX: Blocked. 'yforward' cause G++ 5.3 crash: internal compiler
205 // error: Segmentation fault.
206 yunseq(0, (lf = NPL::make_observer(
207 &act.AttachFunction(std::forward<_tParams>(args)).get()), 0)...);
208 act.RequestCombined();
209 SetupNextTerm(ctx, term);
210 // XXX: %A1::RelayCurrentOrDirect is not used to allow the underlying
211 // handler optimized with %NPL_Impl_NPLA1_Enable_InlineDirect.
212 return RelaySwitched(ctx, Continuation(std::ref(lf ? *lf : h), ctx));
213 #elif NPL_Impl_NPLA1_Enable_Thunked
214
215 ContextState::Access(ctx).ClearCombiningTerm();
216 term.Value.Clear();
217 // XXX: %A1::ReduceCurrentNext is not used to allow the underlying
218 // handler optimized with %NPL_Impl_NPLA1_Enable_InlineDirect.
219 SetupNextTerm(ctx, term);
220 // TODO: Blocked. Use C++14 lambda initializers to simplify the
221 // implementation.
222 RelaySwitched(ctx,
223 A1::NameTypedReducerHandler(std::bind([&](const _tParams&...){
224 // NOTE: Captured argument pack is only needed when %h actually shares.
225 return RegularizeTerm(term, ctx.LastStatus);
226 }, std::move(args)...), "eval-combine-return"));
227 return RelaySwitched(ctx, Continuation(std::ref(h), ctx));
228 #else
229
230 yunseq(0, args...);
231 ContextState::Access(ctx).ClearCombiningTerm();
232 term.Value.Clear();
233 return RegularizeTerm(term, h(term, ctx));
234 #endif
235 }
236
237
239 YB_ATTR_nodiscard ReductionStatus
240 DoAdministratives(const EvaluationPasses& passes, TermNode& term,
241 ContextNode& ctx)
242 {
243 #if NPL_Impl_NPLA1_Enable_Thunked
244 // XXX: Be cautious with overflow risks in call of %ContextNode::ApplyTail
245 // when TCO is not enabled.
246 ctx.LastStatus = ReductionStatus::Neutral;
247 PushActionsRange(passes.cbegin(), passes.cend(), term, ctx);
248 return ReductionStatus::Partial;
249 #else
250 return passes(term, ctx);
251 #endif
252 }
253
254 #if NPL_Impl_NPLA1_Enable_TCO
255 struct EvalSequence final
257 {
258 lref<TermNode> TermRef;
259 TNIter Iter;
260
262 ReductionStatus
263 operator()(ContextNode&) const;
264 };
265
267 ReductionStatus
268 ReduceSequenceOrderedAsync(TermNode& term, ContextNode& ctx, TNIter i)
269 {
270 YAssert(i != term.end(), "Invalid iterator found for sequence reduction.");
271 // TODO: Allow capture next sequenced evaluations as a single continuation?
272 return std::next(i) == term.end() ? ReduceOnceLifted(term, ctx, *i)
273 : ReduceSubsequent(*i, ctx,
274 NameTypedReducerHandler(EvalSequence{term, i}, "eval-sequence"));
275 }
276
277 ReductionStatus
278 EvalSequence::operator()(ContextNode& ctx) const
279 {
280 return ReduceSequenceOrderedAsync(TermRef, ctx, TermRef.get().erase(Iter));
281 }
282 #else
283 void
285 ReduceOrderedResult(TermNode& term)
286 {
287 if(IsBranch(term))
288 LiftTerm(term, *term.rbegin());
289 else
290 term.Value = ValueToken::Unspecified;
291 }
292 #endif
293
294
296
297 using SourcedByteAllocator = pmr::polymorphic_allocator<yimpl(byte)>;
298
299 using SourceInfoMetadata = lref<const SourceInformation>;
300
301
302 template<typename _type, class _tByteAlloc = SourcedByteAllocator>
303 class SourcedHolder : public AllocatorHolder<_type, _tByteAlloc>
304 {
305 public:
306 using Creation = IValueHolder::Creation;
307 using value_type = _type;
308
309 private:
310 using base = AllocatorHolder<_type, _tByteAlloc>;
311
312 SourceInformation source_information;
313
314 public:
315 using base::value;
316
317 template<typename... _tParams>
318 inline
319 SourcedHolder(const SourceName& name, const SourceLocation& src_loc,
320 _tParams&&... args)
321 : base(yforward(args)...), source_information(name, src_loc)
322 {}
323 template<typename... _tParams>
324 inline
325 SourcedHolder(const SourceInformation& src_info, _tParams&&... args)
326 : base(yforward(args)...), source_information(src_info)
327 {}
328 DefDeCopyMoveCtorAssignment(SourcedHolder)
329
330 YB_ATTR_nodiscard any
331 Create(Creation c, const any& x) const ImplI(IValueHolder)
332 {
333 // XXX: Always use the allocator to hold the source information.
334 return YSLib::AllocatedHolderOperations<SourcedHolder,
335 _tByteAlloc>::CreateHolder(c, x, value, NPL::forward_as_tuple(
336 source_information, ystdex::as_const(value)), NPL::forward_as_tuple(
337 source_information, std::move(value)));
338 }
339
340 YB_ATTR_nodiscard YB_PURE PDefH(any, Query, uintmax_t) const ynothrow
341 ImplI(IValueHolder)
342 ImplRet(ystdex::ref(source_information))
343
344 using base::get_allocator;
345 };
347
348
350
351 class SeparatorPass
352 {
353 private:
354 using Filter = decltype(ystdex::bind1(HasValue<TokenValue>,
355 std::declval<TokenValue&>()));
356
357 TermPasses::allocator_type alloc;
358 TokenValue delim{";"};
359 TokenValue delim2{","};
360 Filter filter{ystdex::bind1(HasValue<TokenValue>, delim)};
361 Filter filter2{ystdex::bind1(HasValue<TokenValue>, delim2)};
362 // XXX: More allocators are not used here for performance in most cases.
363 ValueObject pfx{std::allocator_arg, alloc, ContextHandler(Forms::Sequence)};
364 ValueObject pfx2{std::allocator_arg, alloc,
365 ContextHandler(FormContextHandler(ReduceBranchToList, 1))};
366 #if NPL_Impl_NPLA1_Enable_ThunkedSeparatorPass
367
369 using TermStack = stack<lref<TermNode>, vector<lref<TermNode>>>;
370
372 mutable TermStack remained{alloc};
373 #endif
374
375 public:
377 SeparatorPass(TermPasses::allocator_type a)
378 : alloc(a)
379 {}
380
381 YB_FLATTEN ReductionStatus
382 operator()(TermNode& term) const
383 {
384 #if NPL_Impl_NPLA1_Enable_ThunkedSeparatorPass
385 YAssert(remained.empty(), "Invalid state found.");
386 Transform(term, remained);
387 while(!remained.empty())
388 {
389 const auto term_ref(std::move(remained.top()));
390
391 remained.pop();
392 for(auto& tm : term_ref.get())
393 Transform(tm, remained);
394 }
395 #else
396 Transform(term);
397 #endif
398 return ReductionStatus::Clean;
399 }
400
401 private:
402 #if NPL_Impl_NPLA1_Enable_ThunkedSeparatorPass
403 void
405 Transform(TermNode& term, TermStack& terms) const
406 {
407 terms.push(term);
408 if(std::find_if(term.begin(), term.end(), filter) != term.end())
409 term = SeparatorTransformer::Process(std::move(term), pfx, filter);
410 if(std::find_if(term.begin(), term.end(), filter2) != term.end())
411 term = SeparatorTransformer::Process(std::move(term), pfx2,
412 filter2);
413 }
414 #else
415 void
416 Transform(TermNode& term) const
417 {
418 if(std::find_if(term.begin(), term.end(), filter) != term.end())
419 term = SeparatorTransformer::Process(std::move(term), pfx, filter);
420 if(std::find_if(term.begin(), term.end(), filter2) != term.end())
421 term = SeparatorTransformer::Process(std::move(term), pfx2,
422 filter2);
423 for(auto& tm : term)
424 Transform(tm);
425 }
426 #endif
427 };
429
430
432 inline PDefH(void, CopyTermTags, TermNode& term, const TermNode& tm) ynothrow
433 ImplExpr(term.Tags = GetLValueTagsOf(tm.Tags))
434
435 void
437 MarkTemporaryTerm(TermNode& term, char sigil) ynothrow
438 {
439 if(sigil != char())
440 // XXX: This is like lifetime extension of temporary objects with rvalue
441 // references in the host language.
442 term.Tags |= TermTags::Temporary;
443 }
444
446 struct BindParameterObject
447 {
448 // XXX: This is actually used for references of lvalues and it
449 // is never accurate (see below). It is still necessary to avoid release
450 // TCO frame records too early in next function calls.
452 lref<const EnvironmentReference> Referenced;
453
455 BindParameterObject(const EnvironmentReference& r_env)
456 : Referenced(r_env)
457 {}
458
460 template<typename _fCopy, typename _fMove>
461 void
462 operator()(char sigil, TermTags o_tags, TermNode& o, _fCopy cp, _fMove mv)
463 const
464 {
465 // NOTE: This shall be %true if the operand is stored in a term tree to
466 // be reduced (and eventually cleanup). See also
467 // %GParameterMatcher::Match.
468 const bool temp(bool(o_tags & TermTags::Temporary));
469
470 // NOTE: The binding rules here should be carefully tweaked to make them
471 // exactly accept expression representations (in %TermNode) in NPLA1
472 // all around.
473 if(sigil != '@')
474 {
475 const bool can_modify(!bool(o_tags & TermTags::Nonmodifying));
476
477 // NOTE: Subterms in arguments retained are also transferred for
478 // values.
479 if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
480 {
481 if(sigil != char())
482 {
483 const auto ref_tags(sigil == '&' ? BindReferenceTags(*p)
484 : p->GetTags());
485
486 // XXX: Allocators are not used here on %TermReference for
487 // performance in most cases.
488 if(can_modify && temp)
489 // NOTE: Reference collapsed by move.
490 mv(std::move(o.GetContainerRef()),
491 TermReference(ref_tags, std::move(*p)));
492 else
493 // NOTE: Reference collapsed by copy.
494 mv(TermNode::Container(o.GetContainer()),
495 TermReference(ref_tags, *p));
496 }
497 else
498 {
499 auto& src(p->get());
500
501 // NOTE: Since it is passed by value copy, direct
502 // destructive lifting cannot be used.
503 if(!p->IsMovable())
504 cp(src);
505 else
506 mv(std::move(src.GetContainerRef()),
507 std::move(src.Value));
508 }
509 }
510 // NOTE: This saves non-reference temporary objects into the
511 // environment. No temporary objects outside the environment (in
512 // the tree being reduced) can be referenced in the object language
513 // later. There is no need to save them elsewhere even in the TCO
514 // implementation.
515 else if((can_modify || sigil == '%') && temp)
516 // XXX: The object is bound to reference as temporary, implying
517 // copy elision in the object language.
518 MarkTemporaryTerm(mv(std::move(o.GetContainerRef()),
519 std::move(o.Value)), sigil);
520 // NOTE: Binding on list prvalues is always unsafe. However, since
521 // %TermTags::Nonmodifying is not allowed on prvalues, being not
522 // %can_modify currently implies some ancestor of %o is a
523 // referenceable object, albeit not always an lvalue (which implies
524 // undefined behavior if used as an lvalue).
525 else if(sigil == '&')
526 // XXX: Always move because the value object is newly created.
527 // The anchor here (if any) is not accurate because it refers
528 // to the anchor saved by the reference (if any), not
529 // necessarily the original environment owning the referent.
530 // TODO: Remove anchors without TCO (as it always interferes
531 // %NPL_NPLA_CheckEnvironmentReferenceCount for no
532 // benefits)?
533 mv(TermNode::Container(o.get_allocator()),
534 // XXX: Term tags on prvalues are reserved and should be
535 // ignored normally except for future internal use. Note
536 // that %TermTags::Temporary can be provided by a bound
537 // object (indicated by %o) in an environment.
538 ValueObject(std::allocator_arg, o.get_allocator(),
539 in_place_type<TermReference>,
540 GetLValueTagsOf(o.Tags | o_tags), o, Referenced));
541 else
542 cp(o);
543 }
544 else if(!temp)
545 mv(TermNode::Container(o.get_allocator()),
546 ValueObject(std::allocator_arg, o.get_allocator(),
547 in_place_type<TermReference>, o_tags & TermTags::Nonmodifying,
548 o, Referenced));
549 else
550 throw
551 InvalidReference("Invalid operand found on binding sigil '@'.");
552 }
553 };
554
555
557
558 #if false
559 // NOTE: Examples of types for %GParameterMatcher for exposition only,
560 // equivalent to the instance used in %MatchParameter.
561 using GParameterBinder
562 = function<void(_tParams..., TermTags, const EnvironmentReference&)>;
563
564 using _fBindTrailing
565 = GParameterBinder<TermNode::Container&, TNIter, const TokenValue&>;
566 using _fBindValue = GParameterBinder<const TokenValue&, TermNode&>;
567 #endif
568
569 template<typename _fBindTrailing, typename _fBindValue>
570 class GParameterMatcher
571 {
573
574 public:
575 _fBindTrailing BindTrailing;
576 _fBindValue BindValue;
577
578 private:
579 // XXX: Allocators are not used here for performance in most cases.
580 mutable Action act{};
582
583 public:
584 template<class _type, class _type2>
585 GParameterMatcher(_type&& arg, _type2&& arg2)
586 : BindTrailing(yforward(arg)), BindValue(yforward(arg2))
587 {}
588
589 // NOTE: The environment argument is for rvalues in the caller. All prvalues
590 // are treated as rvalue references introduced in the current environment.
591 // This is necessary to keep the environment alive in the TCO
592 // implementation.
593 // XXX: Currently there is no other effects (esp. collection) in binding,
594 // so without handling of the environment for TCO, it still works. Anyway,
595 // keeping it saner to be friendly to possible TCO compressions in future
596 // seems OK.
597 void
598 operator()(const TermNode& t, TermNode& o, TermTags o_tags,
599 const EnvironmentReference& r_env) const
600 {
601 // NOTE: This is a trampoline to eliminate the call depth limitation.
602 Match(t, o, o_tags, r_env);
603 while(act)
604 {
605 const auto a(std::move(act));
606
607 a();
608 }
609 }
610
611 private:
612 // XXX: The initial %o_tags shall have %TermTags::Temporary unless it is
613 // known to bound to some non-temporary objects not stroed in the term tree
614 // to be reduced.
615 void
616 Match(const TermNode& t, TermNode& o, TermTags o_tags,
617 const EnvironmentReference& r_env) const
618 {
619 if(IsList(t))
620 {
621 if(IsBranch(t))
622 {
623 const auto n_p(t.size());
624 auto last(t.end());
625
626 if(n_p > 0)
627 {
628 const auto& back(NPL::Deref(std::prev(last)));
629
630 // NOTE: Empty list lvalue arguments shall not be matched
631 // here.
632 if(IsLeaf(back))
633 {
634 if(const auto p = NPL::TryAccessLeaf<TokenValue>(back))
635 {
636 if(!p->empty() && p->front() == '.')
637 --last;
638 }
639 else if(!IsList(back))
640 throw ParameterMismatch(ystdex::sfmt(
641 "Invalid term '%s' found for symbol parameter.",
642 TermToString(back).c_str()));
643 }
644 }
645 // XXX: There is only one level of indirection. It should work
646 // with the correct implementation of the reference collapse.
647 ResolveTerm([&, n_p, o_tags](TermNode& nd,
648 ResolvedTermReferencePtr p_ref){
649 const bool ellipsis(last != t.end());
650 const auto n_o(nd.size());
651
652 if(n_p == n_o || (ellipsis && n_o >= n_p - 1))
653 {
654 auto tags(o_tags);
655
656 // NOTE: All tags as type qualifiers should be checked
657 // here. Currently only glvalues can be qualified.
658 // XXX: Term tags are currently not respected in
659 // prvalues.
660 if(p_ref)
661 {
662 const auto ref_tags(p_ref->GetTags());
663
664 tags = (tags
665 & ~(TermTags::Unique | TermTags::Temporary))
666 | (ref_tags & TermTags::Unique);
667 tags |= ref_tags & TermTags::Nonmodifying;
668 }
669 MatchSubterms(t.begin(), last, nd, nd.begin(), tags,
670 p_ref ? p_ref->GetEnvironmentReference() : r_env,
671 ellipsis
672 #if NPL_Impl_NPLA1_AssertParameterMatch
673 , t.end()
674 #endif
675 );
676 }
677 else if(!ellipsis)
678 throw ArityMismatch(n_p, n_o);
679 else
680 ThrowInsufficientTermsError();
681 }, o);
682 }
683 else
684 ResolveTerm([&](const TermNode& nd, bool has_ref){
685 if(nd)
686 throw ParameterMismatch(ystdex::sfmt("Invalid nonempty"
687 " operand value '%s' found for empty list"
688 " parameter.", TermToStringWithReferenceMark(nd,
689 has_ref).c_str()));
690 }, o);
691 }
692 else
693 {
694 const auto& tp(t.Value.type());
695
696 if(tp == ystdex::type_id<TermReference>())
697 ystdex::update_thunk(act, [&, o_tags]{
698 Match(t.Value.GetObject<TermReference>().get(), o, o_tags,
699 r_env);
700 });
701 else if(tp == ystdex::type_id<TokenValue>())
702 BindValue(t.Value.GetObject<TokenValue>(), o, o_tags, r_env);
703 else
704 throw ParameterMismatch(ystdex::sfmt("Invalid parameter value"
705 " '%s' found.", TermToString(t).c_str()));
706 }
707 }
708
710 void
711 MatchSubterms(TNCIter i, TNCIter last, TermNode& o_tm, TNIter j,
712 TermTags tags, const EnvironmentReference& r_env, bool ellipsis
713 #if NPL_Impl_NPLA1_AssertParameterMatch
714 , TNCIter t_end
715 #endif
716 ) const
717 {
718 if(i != last)
719 {
720 ystdex::update_thunk(act, [=, &o_tm, &r_env]{
721 return MatchSubterms(std::next(i), last, o_tm, std::next(j),
722 #if NPL_Impl_NPLA1_AssertParameterMatch
723 tags, r_env, ellipsis, t_end);
724 #else
725 tags, r_env, ellipsis);
726 #endif
727 });
728 YAssert(j != o_tm.end(), "Invalid state of operand found.");
729 Match(NPL::Deref(i), NPL::Deref(j), tags, r_env);
730 }
731 else if(ellipsis)
732 {
733 const auto& lastv(NPL::Deref(last).Value);
734
735 YAssert(lastv.type() == ystdex::type_id<TokenValue>(),
736 "Invalid ellipsis sequence token found.");
737 BindTrailing(o_tm, j, lastv.GetObject<TokenValue>(), tags, r_env);
738 #if NPL_Impl_NPLA1_AssertParameterMatch
739 YAssert(std::next(last) == t_end, "Invalid state found.");
740 #endif
741 }
742 }
743 };
744
746 template<typename _fBindTrailing, typename _fBindValue>
747 YB_ATTR_nodiscard inline GParameterMatcher<_fBindTrailing, _fBindValue>
748 MakeParameterMatcher(_fBindTrailing bind_trailing_seq, _fBindValue bind_value)
749 {
750 return GParameterMatcher<_fBindTrailing, _fBindValue>(
751 std::move(bind_trailing_seq), std::move(bind_value));
752 }
754
755 } // unnamed namespace;
756
757
758 void
759 ThrowInsufficientTermsError()
760 {
761 throw ParameterMismatch("Insufficient terms found for list parameter.");
762 }
763
764 void
765 ThrowInvalidSyntaxError(const char* str)
766 {
767 throw InvalidSyntax(str);
768 }
769 void
770 ThrowInvalidSyntaxError(string_view sv)
771 {
772 throw InvalidSyntax(sv);
773 }
774
775 void
776 ThrowNonmodifiableErrorForAssignee()
777 {
778 throw TypeError("Destination operand of assignment shall be modifiable.");
779 }
780
781 void
782 ThrowUnsupportedLiteralError(const char* id)
783 {
784 throw InvalidSyntax(ystdex::sfmt(
785 id[0] != '#' ? "Unsupported literal prefix found in literal '%s'."
786 : "Invalid literal '%s' found.", id));
787 }
788
789 void
790 ThrowValueCategoryErrorForFirstArgument(const TermNode& term)
791 {
792 throw ValueCategoryMismatch(ystdex::sfmt("Expected a reference for the 1st "
793 "argument, got '%s'.", TermToString(term).c_str()));
794 }
795
796
797 ContextState::ContextState(pmr::memory_resource& rsrc)
798 : ContextNode(rsrc)
799 {
800 // NOTE: The guard object shall be fresh on the calls for reentrancy.
801 Guard += [](TermNode&, ContextNode& ctx){
802 // TODO: Support guarding for other states?
803 return A1::Guard(std::allocator_arg, ctx.get_allocator(),
804 in_place_type<ReductionGuard>, ctx);
805 };
806 }
807 ContextState::ContextState(const ContextState& ctx)
808 : ContextNode(ctx),
809 EvaluateLeaf(ctx.EvaluateLeaf), EvaluateList(ctx.EvaluateList),
810 EvaluateLiteral(ctx.EvaluateLiteral), Guard(ctx.Guard),
811 ReduceOnce(ctx.ReduceOnce)
812 {}
813 ContextState::ContextState(ContextState&& ctx)
814 : ContextNode(std::move(ctx)),
815 EvaluateLeaf(ctx.EvaluateLeaf), EvaluateList(ctx.EvaluateList),
816 EvaluateLiteral(ctx.EvaluateLiteral), Guard(ctx.Guard),
817 ReduceOnce(ctx.ReduceOnce)
818 {
819 swap(next_term_ptr, ctx.next_term_ptr);
820 }
821 ContextState::ImplDeDtor(ContextState)
822
823 TermNode&
824 ContextState::GetNextTermRef() const
825 {
826 if(const auto p = next_term_ptr)
827 return *p;
828 // NOTE: This should not occur unless there exists some invalid low-level
829 // interoperations on the next term pointer in the context.
830 throw NPLException("No next term found to evaluation.");
831 }
832
833 ReductionStatus
834 ContextState::DefaultReduceOnce(TermNode& term, ContextNode& ctx)
835 {
836 auto& cs(ContextState::Access(ctx));
837 const bool non_list(term.Value);
838
839 // NOTE: Empty list or special value token has no-op to do with.
840 if(non_list)
841 {
842 // XXX: Add logic to directly handle special value tokens here?
843 // NOTE: The reduction relies on proper handling of reduction status and
844 // proper tail action for the thunked implementations.
845 if(term.Value.type() != ystdex::type_id<ValueToken>())
846 return DoAdministratives(cs.EvaluateLeaf, term, ctx);
847 }
848 else if(IsBranch(term))
849 {
850 YAssert(term.size() != 0, "Invalid node found.");
851 // NOTE: List with single element shall be reduced as the element.
852 if(term.size() != 1)
853 return DoAdministratives(cs.EvaluateList, term, ctx);
854
855 // XXX: This may be slightly more efficient, and more importantly,
856 // respecting to nested call safety on %ReduceOnce for the thunked
857 // implementation well by only allow one level of direct recursion.
858 auto term_ref(ystdex::ref(term));
859
860 ystdex::retry_on_cond([&]{
861 return term_ref.get().size() == 1;
862 }, [&]{
863 term_ref = AccessFirstSubterm(term_ref);
864 });
865 return ReduceOnceLifted(term, ctx, term_ref);
866 }
867 return ReductionStatus::Retained;
868 }
869
870 ReductionStatus
871 ContextState::RewriteGuarded(TermNode& term, Reducer reduce)
872 {
873 const auto gd(Guard(term, *this));
874 const auto unwind(ystdex::make_guard([this]() ynothrow{
875 TailAction = nullptr;
876 UnwindCurrent();
877 }));
878
879 return Rewrite(std::move(reduce));
880 }
881
882 ReductionStatus
883 ContextState::RewriteTerm(TermNode& term)
884 {
885 SetNextTermRef(term);
886 return Rewrite(NPL::ToReducer(get_allocator(), std::ref(ReduceOnce)));
887 }
888
889 ReductionStatus
890 ContextState::RewriteTermGuarded(TermNode& term)
891 {
892 SetNextTermRef(term);
893 return RewriteGuarded(term,
894 NPL::ToReducer(get_allocator(), std::ref(ReduceOnce)));
895 }
896
897 ReductionStatus
898 Reduce(TermNode& term, ContextNode& ctx)
899 {
900 return ContextState::Access(ctx).RewriteTermGuarded(term);
901 }
902
903 void
904 ReduceArguments(TNIter first, TNIter last, ContextNode& ctx)
905 {
906 if(first != last)
907 // NOTE: This is neutral to %NPL_Impl_NPLA1_Enable_Thunked.
908 // NOTE: The order of evaluation is unspecified by the language
909 // specification. It should not be depended on.
910 ReduceChildren(++first, last, ctx);
911 else
912 ThrowInvalidSyntaxError("Invalid function application found.");
913 }
914
915 void
916 ReduceChildren(TNIter first, TNIter last, ContextNode& ctx)
917 {
918 // NOTE: Separators or other sequence constructs are not handled here. The
919 // evaluation can be potentionally parallel, though the simplest one is
920 // left-to-right.
921 // XXX: Use execution policies to be evaluated concurrently?
922 // NOTE: This does not support PTC, but allow it to be called
923 // in routines which expect proper tail actions, given the guarnatee that
924 // the precondition of %Reduce is not violated.
925 // XXX: The remained tail action would be dropped.
926 #if NPL_Impl_NPLA1_Enable_Thunked
927 ReduceChildrenOrderedAsync(first, last, ctx);
928 #else
929 std::for_each(first, last, ystdex::bind1(ReduceOnce, std::ref(ctx)));
930 #endif
931 }
932
933 ReductionStatus
934 ReduceChildrenOrdered(TNIter first, TNIter last, ContextNode& ctx)
935 {
936 #if NPL_Impl_NPLA1_Enable_Thunked
937 return ReduceChildrenOrderedAsync(first, last, ctx);
938 #else
939 const auto tr([&](TNIter iter){
940 return ystdex::make_transform(iter, [&](TNIter i){
941 return ReduceOnce(*i, ctx);
942 });
943 });
944
945 return ystdex::default_last_value<ReductionStatus>()(tr(first), tr(last),
946 ReductionStatus::Neutral);
947 #endif
948 }
949
950 ReductionStatus
951 ReduceFirst(TermNode& term, ContextNode& ctx)
952 {
953 // NOTE: This is neutral to %NPL_Impl_NPLA1_Enable_Thunked.
954 return IsBranchedList(term) ? ReduceOnce(AccessFirstSubterm(term), ctx)
955 : ReductionStatus::Regular;
956 }
957
958 ReductionStatus
959 ReduceOnce(TermNode& term, ContextNode& ctx)
960 {
961 return A1::RelayDirect(ctx, ContextState::Access(ctx).ReduceOnce, term);
962 }
963
964 ReductionStatus
965 ReduceOrdered(TermNode& term, ContextNode& ctx)
966 {
967 #if NPL_Impl_NPLA1_Enable_Thunked
968 # if NPL_Impl_NPLA1_Enable_TCO
969 if(IsBranch(term))
970 return ReduceSequenceOrderedAsync(term, ctx, term.begin());
971 term.Value = ValueToken::Unspecified;
972 return ReductionStatus::Retained;
973 # else
974 return A1::ReduceCurrentNext(term, ctx, Continuation(
975 static_cast< ReductionStatus(&)(TermNode&, ContextNode&)>(
976 ReduceChildrenOrdered), ctx), A1::NameTypedReducerHandler([&]{
977 ReduceOrderedResult(term);
978 return ReductionStatus::Regular;
979 }, "eval-sequence-return"));
980 # endif
981 #else
982 const auto res(ReduceChildrenOrdered(term, ctx));
983
984 ReduceOrderedResult(term);
985 return res;
986 #endif
987 }
988
989 ReductionStatus
990 ReduceTail(TermNode& term, ContextNode& ctx, TNIter i)
991 {
992 term.erase(term.begin(), i);
993 // NOTE: This is neutral to %NPL_Impl_NPLA1_Enable_Thunked.
994 return ReduceOnce(term, ctx);
995 }
996
997
998 void
999 SetupTraceDepth(ContextState& cs, const string& name)
1000 {
1001 using namespace std::placeholders;
1002 auto p_env(cs.ShareRecord());
1003
1004 ystdex::try_emplace(p_env->GetMapRef(), name, NoContainer,
1005 in_place_type<size_t>);
1006 // TODO: Blocked. Use C++14 lambda initializers to simplify the
1007 // implementation.
1008 cs.Guard += std::bind([name](TermNode& term, ContextNode& ctx,
1009 shared_ptr<Environment>& p_e){
1010 if(const auto p = p_e->LookupName(name))
1011 {
1012 using ystdex::pvoid;
1013 auto& depth(NPL::Access<size_t>(*p));
1014
1015 YTraceDe(Informative, "Depth = %zu, context = %p, semantics = %p.",
1016 depth, pvoid(&ctx), pvoid(&term));
1017 ++depth;
1018 return ystdex::unique_guard([&]() ynothrow{
1019 --depth;
1020 });
1021 }
1022 ValueNode::ThrowWrongNameFound(name);
1023 }, _1, _2, std::move(p_env));
1024 }
1025
1026
1027 void
1028 InsertChild(ValueNode&& node, ValueNode::Container& con)
1029 {
1030 con.insert(node.GetName().empty() ? YSLib::AsNode(node.get_allocator(),
1031 '$' + MakeIndex(con.size()), std::move(node.Value)) : std::move(node));
1032 }
1033
1034 ValueNode
1035 TransformNode(const TermNode& term)
1036 {
1037 auto s(term.size());
1038
1039 if(s == 0)
1040 return MapNPLALeafNode(term);
1041
1042 auto i(term.begin());
1043
1044 if(s == 1)
1045 return TransformNode(*i);
1046
1047 const auto& name(ParseNPLATermString(*i));
1048
1049 if(!name.empty())
1050 yunseq(++i, --s);
1051 if(s == 1)
1052 {
1053 auto&& nd(TransformNode(*i));
1054
1055 if(nd.GetName().empty())
1056 return YSLib::AsNode(ValueNode::allocator_type(
1057 term.get_allocator()), name, std::move(nd.Value));
1058 return
1059 {ValueNode::Container({std::move(nd)}, term.get_allocator()), name};
1060 }
1061
1062 ValueNode::Container node_con;
1063
1064 std::for_each(i, term.end(), [&](const TermNode& tm){
1065 InsertChild(TransformNode(tm), node_con);
1066 });
1067 return
1068 {std::allocator_arg, term.get_allocator(), std::move(node_con), name};
1069 }
1070
1071
1072 TermNode
1073 ParseLeaf(string_view id, TermNode::allocator_type a)
1074 {
1075 YAssertNonnull(id.data());
1076
1077 auto term(NPL::AsTermNode(a));
1078
1079 if(!id.empty())
1080 switch(CategorizeBasicLexeme(id))
1081 {
1082 case LexemeCategory::Code:
1083 // XXX: When do code literals need to be evaluated?
1084 id = DeliteralizeUnchecked(id);
1085 YB_ATTR_fallthrough;
1086 case LexemeCategory::Symbol:
1087 if(CheckReducible(DefaultEvaluateLeaf(term, id)))
1088 term.Value = ValueObject(std::allocator_arg, a,
1089 in_place_type<TokenValue>, id, a);
1090 // NOTE: This is to be evaluated as identifier later.
1091 break;
1092 // XXX: Empty token is ignored.
1093 // XXX: Remained reducible?
1094 case LexemeCategory::Data:
1095 // XXX: This should be prevented being passed to second pass in
1096 // %TermToNamePtr normally. This is guarded by normal form handling
1097 // in the loop in %ContextNode::Rewrite with %ReduceOnce.
1098 term.Value = ValueObject(std::allocator_arg, a,
1099 in_place_type<string>, Deliteralize(id), a);
1100 YB_ATTR_fallthrough;
1101 default:
1102 break;
1103 // XXX: Handle other categories of literal?
1104 }
1105 return term;
1106 }
1107
1108 TermNode
1109 ParseLeafWithSourceInformation(string_view id, const shared_ptr<string>& name,
1110 const SourceLocation& src_loc, TermNode::allocator_type a)
1111 {
1112 // NOTE: Most are same to %ParseLeaf, except for additional source
1113 // information mixed into the values of %TokenValue.
1114 YAssertNonnull(id.data());
1115
1116 auto term(NPL::AsTermNode(a));
1117
1118 if(!id.empty())
1119 switch(CategorizeBasicLexeme(id))
1120 {
1121 case LexemeCategory::Code:
1122 id = DeliteralizeUnchecked(id);
1123 YB_ATTR_fallthrough;
1124 case LexemeCategory::Symbol:
1125 if(CheckReducible(DefaultEvaluateLeaf(term, id)))
1126 term.Value = ValueObject(std::allocator_arg, a,
1127 any_ops::use_holder, in_place_type<SourcedHolder<
1128 TokenValue>>, name, src_loc, id, a);
1129 break;
1130 case LexemeCategory::Data:
1131 term.Value = ValueObject(std::allocator_arg, a, any_ops::use_holder,
1132 in_place_type<SourcedHolder<string>>, name, src_loc,
1133 Deliteralize(id), a);
1134 YB_ATTR_fallthrough;
1135 default:
1136 break;
1137 }
1138 return term;
1139 }
1140
1141
1142 ReductionStatus
1143 FormContextHandler::CallN(size_t n, TermNode& term, ContextNode& ctx) const
1144 {
1145 // NOTE: This implementes arguments evaluation in applicative order when
1146 // %Wrapping is not zero.
1147 #if NPL_Impl_NPLA1_Enable_Thunked
1148 // NOTE: Optimize for cases with no argument.
1149 if(n == 0 || term.size() <= 1)
1150 // XXX: Assume the term has been setup by the caller.
1151 return RelayCurrentOrDirect(ctx, Continuation(std::ref(Handler), ctx),
1152 term);
1153 return A1::ReduceCurrentNext(term, ctx,
1154 Continuation([&](TermNode& t, ContextNode& c){
1155 YAssert(!t.empty(), "Invalid term found.");
1156 ReduceChildrenOrderedAsyncUnchecked(std::next(t.begin()), t.end(), c);
1157 return ReductionStatus::Partial;
1158 }, ctx), NPL::ToReducer(ctx.get_allocator(),
1159 A1::NameTypedReducerHandler([&, n](ContextNode& c){
1160 SetupNextTerm(c, term);
1161 return CallN(n - 1, term, c);
1162 }, "eval-combine-operator")));
1163 #else
1164 // NOTE: This does not support PTC. However, the loop among the wrapping
1165 // calls is almost PTC in reality.
1166 while(n-- != 0)
1167 ReduceArguments(term, ctx);
1168 return Handler(term, ctx);
1169 #endif
1170 }
1171
1172 bool
1173 FormContextHandler::Equals(const FormContextHandler& fch) const
1174 {
1175 if(Wrapping == fch.Wrapping)
1176 {
1177 if(Handler == fch.Handler)
1178 return true;
1179 if(const auto p = Handler.target<RefContextHandler>())
1180 return p->HandlerRef.get() == fch.Handler;
1181 if(const auto p = fch.Handler.target<RefContextHandler>())
1182 return Handler == p->HandlerRef.get();
1183 }
1184 return {};
1185 }
1186
1187
1188 ReductionStatus
1189 DefaultEvaluateLeaf(TermNode& term, string_view id)
1190 {
1191 YAssertNonnull(id.data());
1192 if(!id.empty())
1193 {
1194 const char f(id.front());
1195
1196 if(ystdex::isdigit(f))
1197 {
1198 int ans(0);
1199
1200 for(auto p(id.begin()); p != id.end(); ++p)
1201 if(ystdex::isdigit(*p))
1202 {
1203 if(unsigned((ans << 3) + (ans << 1) + *p - '0')
1204 <= unsigned(INT_MAX))
1205 ans = (ans << 3) + (ans << 1) + *p - '0';
1206 else
1207 ThrowInvalidSyntaxError(ystdex::sfmt("Value of"
1208 " identifier '%s' is out of the range of the"
1209 " supported integer.", id.data()));
1210 }
1211 else
1212 ThrowInvalidSyntaxError(ystdex::sfmt("Literal postfix is"
1213 " unsupported in identifier '%s'.", id.data()));
1214 term.Value = ans;
1215 }
1216 else if(id == "#t" || id == "#true")
1217 term.Value = true;
1218 else if(id == "#f" || id == "#false")
1219 term.Value = false;
1220 else if(id == "#n" || id == "#null")
1221 term.Value = nullptr;
1222 else if(id == "#inert")
1223 term.Value = ValueToken::Unspecified;
1224 else
1225 return ReductionStatus::Retrying;
1226 return ReductionStatus::Clean;
1227 }
1228 return ReductionStatus::Retrying;
1229 }
1230
1231 ReductionStatus
1232 EvaluateIdentifier(TermNode& term, const ContextNode& ctx, string_view id)
1233 {
1234 // NOTE: This is the conversion of lvalue in object to value of expression.
1235 // The referenced term is lived through the evaluation, which is guaranteed
1236 // by the context. This is necessary since the ownership of objects which
1237 // are not temporaries in evaluated terms needs to be always in the
1238 // environment, rather than in the tree. It would be safe if not passed
1239 // directly and without rebinding. Note access of objects denoted by
1240 // invalid reference after rebinding would cause undefined behavior in the
1241 // object language.
1242 auto pr(ResolveName(ctx, id));
1243
1244 if(pr.first)
1245 {
1246 auto& bound(*pr.first);
1247 TermNode* p_rterm;
1248
1249 SetupTailOperatorName(term, ctx);
1250 // NOTE: This is essentially similar to a successful call to
1251 // %ResolveIdentifier plus a call to %EnsureLValueReference, except
1252 // that the term tags are always not touched and the term container is
1253 // also not touched when the result is not a reference.
1254 // NOTE: Every reference to the object in the environment is assumed
1255 // aliased, so no %TermTags::Unique is preserved.
1256 // XXX: Allocators are not used here on %TermReference to avoid G++ from
1257 // folding code with other basic blocks with more inefficient
1258 // implementations.
1259 if(const auto p = NPL::TryAccessLeaf<const TermReference>(bound))
1260 {
1261 p_rterm = &p->get();
1262 term.SetContent(bound.GetContainer(),
1263 EnsureLValueReference(TermReference(*p)));
1264 }
1265 else
1266 {
1267 auto p_env(NPL::Nonnull(pr.second));
1268
1269 p_rterm = &bound;
1270 [&]() YB_FLATTEN{
1271 term.Value = TermReference(p_env->MakeTermTags(bound)
1272 & ~TermTags::Unique, bound, std::move(p_env));
1273 }();
1274 }
1275 EvaluateLiteralHandler(term, ctx, *p_rterm);
1276 // NOTE: Unevaluated term shall be detected and evaluated. See also
1277 // $2017-05 @ %Documentation::Workflow.
1278 return ReductionStatus::Neutral;
1279 }
1280 throw BadIdentifier(id);
1281 }
1282
1283 ReductionStatus
1284 EvaluateLeafToken(TermNode& term, ContextNode& ctx, string_view id)
1285 {
1286 auto& cs(ContextState::Access(ctx));
1287
1288 YAssertNonnull(id.data());
1289 // NOTE: Only string node of identifier is tested.
1290 if(!id.empty() && (cs.EvaluateLiteral.empty()
1291 || CheckReducible(cs.EvaluateLiteral(term, cs, id))))
1292 {
1293 // NOTE: The symbols are lexical results from analysis by %ParseLeaf.
1294 // The term would be normalized by %ReduceCombined. If necessary, there
1295 // can be inserted some additional cleanup to remove empty tokens,
1296 // returning %ReductionStatus::Partial. Separators should have been
1297 // handled in appropriate preprocessing passes.
1298 // XXX: Asynchronous reduction is currently not supported.
1299 if(!IsNPLAExtendedLiteral(id))
1300 return EvaluateIdentifier(term, cs, id);
1301 ThrowUnsupportedLiteralError(id);
1302 }
1303 return ReductionStatus::Retained;
1304 }
1305
1306 ReductionStatus
1307 ReduceCombined(TermNode& term, ContextNode& ctx)
1308 {
1309 return IsCombiningTerm(term) ? ReduceCombinedBranch(term, ctx)
1310 : ReductionStatus::Clean;
1311 }
1312
1313 ReductionStatus
1314 ReduceCombinedBranch(TermNode& term, ContextNode& ctx)
1315 {
1316 YAssert(IsCombiningTerm(term), "Invalid term found for combined term.");
1317
1318 SetupNextTerm(ctx, term);
1319
1320 auto& fm(AccessFirstSubterm(term));
1321 const auto p_ref_fm(NPL::TryAccessLeaf<const TermReference>(fm));
1322
1323 // NOTE: The tag is intended to be consumed by %VauHandler in %NPLA1Forms.
1324 // As the irregular representation has a handler of %RefContextHandler,
1325 // the tag is consumed only by the underlying handler, so the irregular
1326 // representation behaves same to glvalue here. The value of %term.Tags may
1327 // indicate a temporary of %TermReference value of %fm. This shall be
1328 // cleared if the object represented by %fm is not a prvalue.
1329 if(p_ref_fm)
1330 {
1331 term.Tags &= ~TermTags::Temporary;
1332 // XXX: The following irregular term conversion is not necessary. It is
1333 // even better to be avoid for easier handling of reference values.
1334 #if false
1335 // XXX: This converts the term with irregular representation at first.
1336 // See %ReduceForCombinerRef for the introduction of the irregular
1337 // representation.
1338 if(IsBranch(fm))
1339 {
1340 YAssert(fm.size() == 1, "Invalid irregular representation of"
1341 " reference with multiple subterms found.");
1342 YAssert(IsLeaf(*fm.begin()), "Invalid irregular representation of"
1343 " reference with non-leaf 1st subterm found.");
1344
1345 // XXX: Assume nonnull. This is guaranteed in construction
1346 // in %ReduceForCombinerRef.
1347 const auto& referenced(p_ref_fm->get());
1348
1349 YAssert(ystdex::ref_eq<>()(NPL::Deref(NPL::Access<
1350 shared_ptr<TermNode>>(*fm.begin())), referenced),
1351 "Invalid subobject reference found.");
1352 // XXX: %TermNode::SetContent cannot be used here due to subterm
1353 // invalidation.
1354 fm.MoveContent(TermNode(referenced));
1355 YAssert(IsLeaf(fm), "Wrong result of irregular"
1356 " representation conversion found.");
1357 }
1358 else
1359 #endif
1360 if(const auto p_handler
1361 = NPL::TryAccessLeaf<const ContextHandler>(p_ref_fm->get()))
1362 // NOTE: This is neutral to %NPL_Impl_NPLA1_Enable_Thunked.
1363 return CombinerReturnThunk(*p_handler, term, ctx);
1364 }
1365 else
1366 term.Tags |= TermTags::Temporary;
1367 // NOTE: Converted terms are also handled here.
1368 // NOTE: To allow being moved, this shall be not qualified by 'const'.
1369 if(const auto p_handler = NPL::TryAccessTerm<ContextHandler>(fm))
1370 #if NPL_Impl_NPLA1_Enable_TCO
1371 return
1372 CombinerReturnThunk(*p_handler, term, ctx, std::move(*p_handler));
1373 #elif NPL_Impl_NPLA1_Enable_Thunked
1374 {
1375 // XXX: Optimize for performance using context-dependent store?
1376 // XXX: This should ideally be a member of handler. However, it makes no
1377 // sense before allowing %ContextHandler overload for ref-qualifier
1378 // '&&'.
1379 auto p(YSLib::share_move(ctx.get_allocator(), *p_handler));
1380
1381 return CombinerReturnThunk(*p, term, ctx, std::move(p));
1382 }
1383 #else
1384 return CombinerReturnThunk(ContextHandler(std::move(*p_handler)), term,
1385 ctx);
1386 #endif
1387 return ResolveTerm([&](const TermNode& nd, bool has_ref)
1388 YB_ATTR_LAMBDA(noreturn) -> ReductionStatus{
1389 // TODO: Capture contextual information in error.
1390 // TODO: Extract general form information extractor function.
1391 throw ListReductionFailure(ystdex::sfmt("No matching combiner '%s'"
1392 " for operand with %zu argument(s) found.",
1393 TermToStringWithReferenceMark(nd, has_ref).c_str(),
1394 FetchArgumentN(term)));
1395 }, fm);
1396 }
1397
1398 ReductionStatus
1399 ReduceCombinedReferent(TermNode& term, ContextNode& ctx, const TermNode& fm)
1400 {
1401 SetupNextTerm(ctx, term);
1402 term.Tags &= ~TermTags::Temporary;
1403 if(const auto p_handler = NPL::TryAccessLeaf<const ContextHandler>(fm))
1404 return CombinerReturnThunk(*p_handler, term, ctx);
1405 throw ListReductionFailure(ystdex::sfmt("No matching combiner '%s'"
1406 " for operand with %zu argument(s) found.",
1407 TermToStringWithReferenceMark(fm, true).c_str(), FetchArgumentN(term)));
1408 }
1409
1410 ReductionStatus
1411 ReduceLeafToken(TermNode& term, ContextNode& ctx)
1412 {
1413 const auto res(ystdex::call_value_or([&](string_view id){
1414 TryRet(EvaluateLeafToken(term, ctx, id))
1415 catch(BadIdentifier& e)
1416 {
1417 if(const auto p_si = QuerySourceInformation(term.Value))
1418 e.Source = *p_si;
1419 throw;
1420 }
1421 // XXX: A term without token is ignored. This is actually same to
1422 // %ReductionStatus::Regular in the current implementation.
1423 }, TermToNamePtr(term), ReductionStatus::Retained));
1424
1425 return CheckReducible(res) ? ReduceOnce(term, ctx) : res;
1426 }
1427
1428
1429 ReductionStatus
1430 RelayForEval(ContextNode& ctx, TermNode& term, EnvironmentGuard&& gd,
1431 bool no_lift, Continuation next)
1432 {
1433 // XXX: For thunked code, %next shall be a continuation before being
1434 // captured and it is not capturable here. No %SetupNextTerm needs to be
1435 // called in the caller.
1436 return RelayForEvalOrDirect(ctx, term, std::move(gd), no_lift,
1437 std::move(next));
1438 }
1439
1440 ReductionStatus
1441 RelayForCall(ContextNode& ctx, TermNode& term, EnvironmentGuard&& gd,
1442 bool no_lift)
1443 {
1444 // NOTE: With TCO, the operand temporary is been indicated by
1445 // %TermTags::Temporary, no lifetime extension needs to be cared here.
1446 return RelayForEvalOrDirect(ctx, term, std::move(gd), no_lift,
1447 std::ref(ContextState::Access(ctx).ReduceOnce));
1448 }
1449
1450
1451 void
1452 MatchParameter(const TermNode& t, TermNode& o, function<void(TermNode&, TNIter,
1453 const TokenValue&, TermTags, const EnvironmentReference&)>
1454 bind_trailing_seq, function<void(const TokenValue&, TermNode&, TermTags,
1455 const EnvironmentReference&)> bind_value, TermTags o_tags,
1456 const EnvironmentReference& r_env)
1457 {
1458 MakeParameterMatcher(std::move(bind_trailing_seq), std::move(bind_value))(t,
1459 o, o_tags, r_env);
1460 }
1461
1462 void
1463 BindParameter(const shared_ptr<Environment>& p_env, const TermNode& t,
1464 TermNode& o)
1465 {
1466 auto& env(NPL::Deref(p_env));
1467 const auto check_sigil([&](string_view& id){
1468 char sigil(id.front());
1469
1470 if(sigil != '&' && sigil != '%' && sigil != '@')
1471 sigil = char();
1472 else
1473 id.remove_prefix(1);
1474 return sigil;
1475 });
1476
1477 // NOTE: No duplication check here. Symbols can be rebound.
1478 // TODO: Additional ownership and lifetime check to kept away undefined
1479 // behavior?
1480 // NOTE: The call is essentially same as %MatchParameter, with a bit better
1481 // performance by avoiding %function instances.
1482 MakeParameterMatcher([&, check_sigil](TermNode& o_tm,
1483 TNIter first, string_view id, TermTags o_tags,
1484 const EnvironmentReference& r_env){
1485 YAssert(ystdex::begins_with(id, "."), "Invalid symbol found.");
1486 id.remove_prefix(1);
1487 if(!id.empty())
1488 {
1489 const char sigil(check_sigil(id));
1490
1491 if(!id.empty())
1492 {
1493 const auto last(o_tm.end());
1494 TermNode::Container con(t.get_allocator());
1495
1496 if(bool(o_tags & (TermTags::Unique | TermTags::Temporary)))
1497 {
1498 if(sigil == char())
1499 LiftSubtermsToReturn(o_tm);
1500 con.splice(con.end(), o_tm.GetContainerRef(), first, last);
1501 }
1502 else
1503 {
1504 for(; first != last; ++first)
1505 // TODO: Blocked. Use C++17 sequence container return
1506 // value.
1507 BindParameterObject{r_env}(sigil, o_tags,
1508 NPL::Deref(first), [&](const TermNode& tm){
1509 con.emplace_back(tm.GetContainer(), tm.Value);
1510 CopyTermTags(con.back(), tm);
1511 }, [&](TermNode::Container&& c, ValueObject&& vo)
1512 -> TermNode&{
1513 con.emplace_back(std::move(c), std::move(vo));
1514 return con.back();
1515 });
1516 }
1517 MarkTemporaryTerm(env.Bind(id, TermNode(std::move(con))),
1518 sigil);
1519 }
1520 }
1521 }, [&](const TokenValue& n, TermNode& b, TermTags o_tags,
1522 const EnvironmentReference& r_env){
1523 CheckParameterLeafToken(n, [&]{
1524 if(!n.empty())
1525 {
1526 string_view id(n);
1527 const char sigil(check_sigil(id));
1528
1529 if(!id.empty())
1530 BindParameterObject{r_env}(sigil, o_tags, b,
1531 [&](const TermNode& tm){
1532 CopyTermTags(env.Bind(id, tm), tm);
1533 }, [&](TermNode::Container&& c, ValueObject&& vo)
1534 -> TermNode&{
1535 // XXX: Allocators are not used here for performance.
1536 return env.Bind(id,
1537 TermNode(std::move(c), std::move(vo)));
1538 });
1539 }
1540 });
1541 })(t, o, TermTags::Temporary, p_env);
1542 }
1543
1544
1545 void
1546 SetupDefaultInterpretation(ContextState& cs, EvaluationPasses passes)
1547 {
1548 #if true
1549 // NOTE: This is an example of merged passes.
1550 passes += [](TermNode& term, ContextNode& ctx) -> ReductionStatus{
1551 ReduceHeadEmptyList(term);
1552 if(IsBranchedList(term))
1553 {
1554 ContextState::Access(ctx).SetCombiningTermRef(term);
1555 // XXX: Without %NPL_Impl_NPLA1_Enable_InlineDirect, the
1556 // asynchronous calls are actually more inefficient than separated
1557 // calls.
1558 return ReduceSubsequent(AccessFirstSubterm(term), ctx,
1559 A1::NameTypedReducerHandler(std::bind(ReduceCombinedBranch,
1560 std::ref(term), std::placeholders::_1),
1561 "eval-combine-operands"));
1562 }
1563 return ReductionStatus::Clean;
1564 };
1565 #else
1566 # if true
1567 // XXX: Optimized based synchronous call of %ReduceHeadEmptyList.
1568 passes += [](TermNode& term, ContextNode& ctx){
1569 ReduceHeadEmptyList(term);
1570 if(IsBranchedList(term))
1571 ContextState::Access(ctx).SetCombiningTermRef(term);
1572 return ReduceFirst(term, ctx);
1573 };
1574 # else
1575 passes += ReduceHeadEmptyList;
1576 passes += [](TermNode& term, ContextNode& ctx){
1577 if(IsBranchedList(term))
1578 ContextState::Access(ctx).SetCombiningTermRef(term);
1579 };
1580 passes += ReduceFirst;
1581 # endif
1582 // TODO: Insert more optional optimized lifted form evaluation passes.
1583 // NOTE: This implies the %RegularizeTerm call when necessary.
1584 // XXX: This should be the last of list pass for current TCO
1585 // implementation, assumed by TCO action.
1586 passes += ReduceCombined;
1587 #endif
1588 cs.EvaluateList = std::move(passes);
1589 // NOTE: This implies the %RegularizeTerm call when necessary.
1590 cs.EvaluateLeaf = ReduceLeafToken;
1591 }
1592
1593 void
1594 SetupTailContext(ContextNode& ctx, TermNode& term)
1595 {
1596 #if NPL_Impl_NPLA1_Enable_TCO
1597 yunused(EnsureTCOAction(ctx, term));
1598 #else
1599 yunused(ctx), yunused(term);
1600 #endif
1601 }
1602
1603
1604 bool
1605 AddTypeNameTableEntry(const ystdex::type_info& ti, string_view sv)
1606 {
1607 YAssertNonnull(sv.data());
1608
1609 const YSLib::lock_guard<YSLib::mutex> gd(NameTableMutex);
1610
1611 return FetchNameTableRef<NPLA1Tag>().emplace(std::piecewise_construct,
1612 NPL::forward_as_tuple(ti), NPL::forward_as_tuple(sv)).second;
1613 }
1614
1615 string_view
1616 QueryContinuationName(const Reducer& act)
1617 {
1618 if(const auto p_cont = act.target<Continuation>())
1619 return QueryTypeName(p_cont->Handler.target_type());
1620 #if NPL_Impl_NPLA1_Enable_Thunked
1621 if(const auto p_act = act.target<PushedAction>())
1622 {
1623 if(p_act->HandlerRef.get() == ReduceCombined)
1624 return "eval-combine-operands";
1625 // XXX: These type names are not normally used.
1626 return QueryTypeName(p_act->HandlerRef.get().target_type());
1627 }
1628 #endif
1629 #if NPL_Impl_NPLA1_Enable_TCO
1630 if(act.target_type() == ystdex::type_id<TCOAction>())
1631 return "eval-tail";
1632 if(act.target_type() == ystdex::type_id<EvalSequence>())
1633 return "eval-sequence";
1634 #endif
1635 return QueryTypeName(act.target_type());
1636 }
1637
1638 observer_ptr<const SourceInformation>
1639 QuerySourceInformation(const ValueObject& vo)
1640 {
1641 const auto val(vo.Query());
1642
1643 return ystdex::call_value_or([](const SourceInfoMetadata& r) ynothrow{
1644 return make_observer(&r.get());
1645 }, val.try_get_object_ptr<SourceInfoMetadata>());
1646 }
1647
1648 observer_ptr<const ValueObject>
1649 QueryTailOperatorName(const Reducer& act)
1650 {
1651 #if NPL_Impl_NPLA1_Enable_TCO
1652 if(const auto p_act = act.target<TCOAction>())
1653 if(p_act->OperatorName.type() == ystdex::type_id<TokenValue>())
1654 return NPL::make_observer(&p_act->OperatorName);
1655 #else
1656 yunused(act);
1657 #endif
1658 return {};
1659 }
1660
1661 string_view
1662 QueryTypeName(const ystdex::type_info& ti)
1663 {
1664 const YSLib::lock_guard<YSLib::mutex> gd(NameTableMutex);
1665 const auto& tbl(FetchNameTableRef<NPLA1Tag>());
1666 const auto i(tbl.find(ti));
1667
1668 if(i != tbl.cend())
1669 return i->second;
1670 return {};
1671 }
1672
1673 bool
1674 SetupTailOperatorName(TermNode& term, const ContextNode& ctx)
1675 {
1676 if(const auto p_combining = ContextState::Access(ctx).GetCombiningTermPtr())
1677 {
1678 if(!p_combining->empty()
1679 && ystdex::ref_eq<>()(AccessFirstSubterm(*p_combining), term))
1680 {
1681 p_combining->Value = std::move(term.Value);
1682 return true;
1683 }
1684 }
1685 return {};
1686 }
1687
1688
1689 REPLContext::REPLContext(pmr::memory_resource& rsrc)
1690 : REPLContext([this](const GParsedValue<ByteParser>& str){
1691 return ParseLeaf(YSLib::make_string_view(str), Allocator);
1692 }, [this](const GParsedValue<SourcedByteParser>& val){
1693 return ParseLeafWithSourceInformation(YSLib::make_string_view(
1694 val.second), CurrentSource, val.first, Allocator);
1695 }, rsrc)
1696 {}
1697 REPLContext::REPLContext(Tokenizer leaf_conv,
1698 SourcedTokenizer sourced_leaf_conv, pmr::memory_resource& rsrc)
1699 : Allocator(&rsrc), Root(rsrc), Preprocess(SeparatorPass(Allocator)),
1700 ConvertLeaf(std::move(leaf_conv)),
1701 ConvertLeafSourced(std::move(sourced_leaf_conv))
1702 {
1703 SetupDefaultInterpretation(Root, EvaluationPasses(Allocator));
1704 }
1705
1706 bool
1707 REPLContext::IsAsynchronous() const ynothrow
1708 {
1709 return NPL_Impl_NPLA1_Enable_Thunked;
1710 }
1711
1712 TermNode
1713 REPLContext::DefaultLoad(REPLContext& context, ContextNode& ctx,
1714 string filename)
1715 {
1716 return context.ReadFrom(*A1::OpenUnique(context, std::move(filename)), ctx);
1717 }
1718
1719 TermNode
1720 REPLContext::ReadFrom(LoadOptionTag<>, std::streambuf& buf, ContextNode& ctx)
1721 const
1722 {
1723 using s_it_t = std::istreambuf_iterator<char>;
1724 Session sess(ctx.get_allocator());
1725
1726 if(UseSourceLocation)
1727 {
1728 SourcedByteParser parse(sess.Lexer, sess.get_allocator());
1729
1730 return Prepare(sess,
1731 sess.Process(s_it_t(&buf), s_it_t(), ystdex::ref(parse)));
1732 }
1733 return Prepare(sess, sess.Process(s_it_t(&buf), s_it_t()));
1734 }
1735 TermNode
1736 REPLContext::ReadFrom(LoadOptionTag<>, std::streambuf& buf, ReaderState& rs,
1737 ContextNode& ctx) const
1738 {
1739 using s_it_t = std::istreambuf_iterator<char>;
1740 Session sess(ctx.get_allocator());
1741
1742 if(UseSourceLocation)
1743 {
1744 SourcedByteParser parse(sess.Lexer, sess.get_allocator());
1745
1746 return Prepare(sess, sess.ProcessOne(rs, s_it_t(&buf), s_it_t(),
1747 ystdex::ref(parse)).first);
1748 }
1749 return Prepare(sess, sess.ProcessOne(rs, s_it_t(&buf), s_it_t()).first);
1750 }
1751 TermNode
1752 REPLContext::ReadFrom(LoadOptionTag<WithSourceLocation>, std::streambuf& buf,
1753 ContextNode& ctx) const
1754 {
1755 using s_it_t = std::istreambuf_iterator<char>;
1756 Session sess(ctx.get_allocator());
1757 SourcedByteParser parse(sess.Lexer, sess.get_allocator());
1758
1759 return
1760 Prepare(sess, sess.Process(s_it_t(&buf), s_it_t(), ystdex::ref(parse)));
1761 }
1762 TermNode
1763 REPLContext::ReadFrom(LoadOptionTag<WithSourceLocation>, std::streambuf& buf,
1764 ReaderState& rs, ContextNode& ctx) const
1765 {
1766 using s_it_t = std::istreambuf_iterator<char>;
1767 Session sess(ctx.get_allocator());
1768 SourcedByteParser parse(sess.Lexer, sess.get_allocator());
1769
1770 return Prepare(sess,
1771 sess.ProcessOne(rs, s_it_t(&buf), s_it_t(), ystdex::ref(parse)).first);
1772 }
1773 TermNode
1774 REPLContext::ReadFrom(LoadOptionTag<NoSourceInformation>, std::streambuf& buf,
1775 ContextNode& ctx) const
1776 {
1777 using s_it_t = std::istreambuf_iterator<char>;
1778 Session sess(ctx.get_allocator());
1779
1780 return Prepare(sess, sess.Process(s_it_t(&buf), s_it_t()));
1781 }
1782 TermNode
1783 REPLContext::ReadFrom(LoadOptionTag<NoSourceInformation>, std::streambuf& buf,
1784 ReaderState& rs, ContextNode& ctx) const
1785 {
1786 using s_it_t = std::istreambuf_iterator<char>;
1787 Session sess(ctx.get_allocator());
1788
1789 return Prepare(sess, sess.ProcessOne(rs, s_it_t(&buf), s_it_t()).first);
1790 }
1791 TermNode
1792 REPLContext::ReadFrom(LoadOptionTag<>, string_view unit, ContextNode& ctx) const
1793 {
1794 YAssertNonnull(unit.data());
1795 Session sess(ctx.get_allocator());
1796
1797 if(UseSourceLocation)
1798 {
1799 SourcedByteParser parse(sess.Lexer, sess.get_allocator());
1800
1801 return Prepare(sess, sess.Process(unit, ystdex::ref(parse)));
1802 }
1803 return Prepare(sess, sess.Process(unit));
1804 }
1805 TermNode
1806 REPLContext::ReadFrom(LoadOptionTag<WithSourceLocation>, string_view unit,
1807 ContextNode& ctx) const
1808 {
1809 YAssertNonnull(unit.data());
1810
1811 Session sess(ctx.get_allocator());
1812 SourcedByteParser parse(sess.Lexer, sess.get_allocator());
1813
1814 return Prepare(sess, sess.Process(unit, ystdex::ref(parse)));
1815 }
1816 TermNode
1817 REPLContext::ReadFrom(LoadOptionTag<NoSourceInformation>, string_view unit,
1818 ContextNode& ctx) const
1819 {
1820 YAssertNonnull(unit.data());
1821
1822 Session sess(ctx.get_allocator());
1823
1824 return Prepare(sess, sess.Process(unit));
1825 }
1826
1827 } // namesapce A1;
1828
1829 } // namespace NPL;
1830
NPL::SourceLocation
源代码位置。
Definition: Lexical.h:87
NPL::A1::ContextState::RewriteTerm
ReductionStatus RewriteTerm(TermNode &)
重写项：设置下一项为参数并使用 ReduceOnce 重写项。
Definition: NPLA1.cpp:883
ystdex::mapped_set< ValueNode, ystdex::less<>, MappedSetTraits, allocator_type >
NPL::A1::REPLContext::DefaultLoad
static YB_ATTR_nodiscard TermNode DefaultLoad(REPLContext &, ContextNode &, string)
默认加载。
Definition: NPLA1.cpp:1713
NPL::TNCIter
TermNode::const_iterator TNCIter
Definition: SContext.h:503
ystdex::begins_with
bool begins_with(const _tRange1 &input, const _tRange2 &test, _fPred comp)
判断第一参数指定的串是否以第二参数起始。
Definition: string.hpp:1176
NPL::A1::ThrowValueCategoryErrorForFirstArgument
void ThrowValueCategoryErrorForFirstArgument(const TermNode &term)
Definition: NPLA1.cpp:790
NPL::TypeError
类型错误。
Definition: NPLA.h:475
YB_ATTR_nodiscard
#define YB_ATTR_nodiscard
标记返回值不被忽略的属性。
Definition: ydef.h:715
ystdex::fseq::front
identity< _type > front(empty_base< _type, _types... >)
Definition: variadic.hpp:74
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:112
NPL::SourcedByteParser
记录源代码位置的字节解析器。
Definition: Lexical.h:612
NPL::A1::RelayForEval
YF_API ReductionStatus RelayForEval(ContextNode &, TermNode &, EnvironmentGuard &&, bool, Continuation)
设置当前项并直接求值规约。
Definition: NPLA1.cpp:1430
NPL::A1::SourcedTokenizer
GTokenizer< SourcedByteParser > SourcedTokenizer
标记器：分析带有源代码位置信息的词素转换为可能包含记号的节点。
Definition: NPLA1.h:1406
NPL::ParameterMismatch
参数不匹配。
Definition: NPLA.h:575
NPL::A1::Tokenizer
GTokenizer< ByteParser > Tokenizer
标记器：分析词素转换为可能包含记号的节点。
Definition: NPLA1.h:1403
NPL::TermReference
项引用。
Definition: NPLA.h:1068
x
const EncapsulationBase & x
Definition: NPLA1Forms.cpp:1536
NPL::A1::Guard
any Guard
作用域守卫类型。
Definition: NPLA1.h:269
platform::Nonnull
YB_PURE _type && Nonnull(_type &&p) ynothrowv
断言并返回非空参数。
Definition: Debug.h:518
NPL::A1::EvaluateIdentifier
YF_API ReductionStatus EvaluateIdentifier(TermNode &, const ContextNode &, string_view)
求值标识符。
Definition: NPLA1.cpp:1232
NPL::A1::ReduceArguments
PDefH(ReductionStatus, Continuation::operator(), ContextNode &ctx) const ImplRet(Handler(ContextState YF_API void ReduceArguments(TNIter, TNIter, ContextNode &)
NPLA1 表达式节点规约：调用至少一次求值例程规约子表达式。
Definition: NPLA1.cpp:904
NPL::A1::ReduceCombined
ReductionStatus ReduceCombined(TermNode &term, ContextNode &ctx)
Definition: NPLA1.cpp:1307
NPL::YAssert
YB_ATTR_nodiscard YB_PURE yconstfn YAssert(!buf.empty(), "Invalid buffer found.")
ystdex::make_guard
guard< _type > make_guard(_type f)
Definition: scope_guard.hpp:84
YSLib::GEvent
事件模板。
Definition: YEvent.hpp:488
ystdex::single_thread::mutex
Definition: pseudo_mutex.h:747
NPL::A1::ReduceTail
ContextNode &YF_API ReductionStatus ReduceTail(TermNode &, ContextNode &, TNIter)
移除容器第一个子项到指定迭代器的项后规约。
Definition: NPLA1.cpp:990
NPL::A1::ThrowInsufficientTermsError
YB_NORETURN YF_API void ThrowInsufficientTermsError()
抛出缺少项的异常。
Definition: NPLA1.cpp:759
NPL::ParseNPLATermString
YB_ATTR_nodiscard YF_API YB_PURE string ParseNPLATermString(const TermNode &)
解析 NPLA 项节点字符串。
Definition: NPLA.cpp:133
CHRLib::c
c
Definition: CharacterProcessing.h:84
NPL::A1::OpenUnique
YSLib::unique_ptr< std::istream > OpenUnique(REPLContext &context, string filename)
Definition: Dependency.cpp:231
NPL::A1::ContextState::GetNextTermRef
ContextNode &ctx ynothrowv const ContextNode &ctx ynothrowv combining_term_ptr YB_ATTR_nodiscard YB_PURE TermNode & GetNextTermRef() const
取下一求值项引用。
ystdex::lref
左值引用包装。
Definition: ref.hpp:61
ystdex::bind1
auto bind1(_func &&f, _tParams &&... args) -> decltype(std::bind(std::forward< decltype(f)>(f), std::placeholders::_1, std::forward< decltype(args)>(args)...))
复合调用 std::bind 和 std::placeholders::_1 。
Definition: functional.hpp:53
NPL::ReductionStatus::Neutral
@ Neutral
中立规约：规约成功终止，且未指定是否需要保留子项。
NPL::TermToString
YB_ATTR_nodiscard YF_API YB_PURE string TermToString(const TermNode &)
访问项的值并转换为字符串形式的外部表示。
Definition: NPLA.cpp:558
YB_PURE
#define YB_PURE
指示函数或函数模板实例为纯函数。
Definition: ydef.h:919
ystdex::update_thunk
void update_thunk(_tThunk &thunk, _func &&f)
更新间接调用对象。
Definition: functional.hpp:225
NPL::ContextNode::UnwindCurrent
const ynothrow UnwindCurrent
Definition: NPLA.h:2868
NPL::A1::ReduceCombinedReferent
ReductionStatus ReduceCombinedReferent(TermNode &term, ContextNode &ctx, const TermNode &fm)
Definition: NPLA1.cpp:1399
NPL::A1::size
YB_ATTR_nodiscard YB_PURE term size() - 1) YF_API ReductionStatus DefaultEvaluateLeaf(TermNode &
字面量和数值的叶节点求值默认实现。
NPL::RelaySwitched
ReductionStatus RelaySwitched(ContextNode &ctx, _fCurrent &&cur)
异步规约指定动作和上下文中的当前动作。
Definition: NPLA.h:3101
NPL::BadIdentifier
标识符错误。
Definition: NPLA.h:626
ystdex::retry_on_cond
invoke_result_t< _fCallable, _tParams... > retry_on_cond(_fCond cond, _fCallable &&f, _tParams &&... args)
循环重复调用：代替直接使用 do-while 语句以避免过多引入作用域外的变量。
Definition: functional.hpp:554
YSLib::Drawing::r
The boundary is out of the const Graphics const Rect const Point const Point Color c const Rect const Rect & r
Definition: YDraw.h:174
NPL::MapNPLALeafNode
YB_ATTR_nodiscard YF_API YB_PURE ValueNode MapNPLALeafNode(const TermNode &)
映射 NPLA 叶节点。
Definition: NPLA.cpp:139
NPL::A1::ParseLeaf
YF_API TermNode ParseLeaf(string_view, TermNode::allocator_type)
分析参数指定的叶节点词素。
Definition: NPLA1.cpp:1073
NPL::A1::Internals::term
_fCurrent TermNode &decltype(cur(term, ctx)) term
Definition: NPLA1Internals.h:593
NPL::A1::REPLContext::Root
ContextState Root
上下文根节点。
Definition: NPLA1.h:1601
NPL::A1::EvaluationPasses
GPasses< TermNode &, ContextNode & > EvaluationPasses
求值合并遍。
Definition: NPLA1.h:258
ystdex::cpp2017::string_view
basic_string_view< char > string_view
Definition: string_view.hpp:437
NPL::A1::ContextState
NPLA1 上下文状态。
Definition: NPLA1.h:288
NPL::ReaderState
读取器状态：支持解析一个记号或列表的解析器的辅助状态。
Definition: SContext.h:762
NPL::A1::BindParameter
YF_API void BindParameter(const shared_ptr< Environment > &, const TermNode &, TermNode &)
使用操作数结构化匹配并绑定参数。
Definition: NPLA1.cpp:1463
ystdex::mapped_set::insert
std::pair< iterator, bool > insert(const value_type &x)
Definition: set.hpp:528
NPL::A1::MatchParameter
YF_API void MatchParameter(const TermNode &, TermNode &, function< void(TermNode &, TNIter, const TokenValue &, TermTags, const EnvironmentReference &)>, function< void(const TokenValue &, TermNode &, TermTags, const EnvironmentReference &)>, TermTags, const EnvironmentReference &)
匹配参数。
Definition: NPLA1.cpp:1452
NPL::A1::ParseLeafWithSourceInformation
YF_API TermNode ParseLeafWithSourceInformation(string_view, const shared_ptr< string > &, const SourceLocation &, TermNode::allocator_type)
分析参数指定的带有源代码信息和叶节点词素。
Definition: NPLA1.cpp:1109
NPL::string_view
YB_ATTR_nodiscard ctx string_view
Definition: NPLA.h:3020
NPL::A1::Internals::Action
function< void()> Action
Definition: NPLA1Internals.h:800
YB_FLATTEN
#define YB_FLATTEN
标记函数尽可能内联定义内的调用。
Definition: ydef.h:843
TermTags
TermTags
标签：表示引用元数据的位。
Definition: SContext.h:108
BindValue
_fBindValue BindValue
Definition: NPLA1.cpp:576
NPL::A1::ContextState::RewriteGuarded
ReductionStatus RewriteGuarded(TermNode &, Reducer)
构造作用域守卫并重写项。
Definition: NPLA1.cpp:871
ImplDeDtor
#define ImplDeDtor(_t)
Definition: YBaseMacro.h:183
NPL_Impl_NPLA1_Enable_Thunked
#define NPL_Impl_NPLA1_Enable_Thunked
Definition: NPLA1Internals.h:70
pfx2
ValueObject pfx2
Definition: NPLA1.cpp:364
NPL::A1::ContextState::RewriteTermGuarded
ReductionStatus RewriteTermGuarded(TermNode &)
守卫重写项：设置下一项为参数，构造作用域守卫并使用 ReduceOnce 重写项。
Definition: NPLA1.cpp:890
NPL::A1::REPLContext::Allocator
TermNode::allocator_type Allocator
节点分配器。
Definition: NPLA1.h:1596
CHRLib::CharSet::Null
@ Null
空字符集。
Definition: Encoding.h:63
ystdex::cpp2014::equal_to
等于关系仿函数。
Definition: functor.hpp:389
NPL::A1::ThrowInvalidSyntaxError
YB_NORETURN YF_API void ThrowInvalidSyntaxError(string_view)
Definition: NPLA1.cpp:770
next
tidy_ptr< slink > next
Definition: memory_resource.cpp:223
NPL::A1::ContextHandler
YSLib::GHEvent< ReductionStatus(TermNode &, ContextNode &)> ContextHandler
上下文处理器类型。
Definition: NPLA1.h:72
delim2
TokenValue delim2
Definition: NPLA1.cpp:359
ystdex::share_move
std::shared_ptr< decay_t< _type > > share_move(_tValue &&v)
转移值创建对应的 std::shared_ptr 实例的对象。
Definition: memory.hpp:942
pfx
ValueObject pfx
Definition: NPLA1.cpp:363
NPL::TermToNamePtr
YB_ATTR_nodiscard YB_PURE observer_ptr< const TokenValue > TermToNamePtr(const TermNode &)
访问项的值作为记号。
NPL::ReduceHeadEmptyList
ReductionStatus::Retained YF_API ReductionStatus ReduceHeadEmptyList(TermNode &) ynothrow
规约第一个非结尾空列表子项。
Definition: NPLA.cpp:831
NPL::ReductionStatus::Clean
@ Clean
纯值规约：规约成功终止，且要求最终清理子项。
ystdex::mapped_set::size
size_type size() const
Definition: set.hpp:442
YB_ATTR_fallthrough
#define YB_ATTR_fallthrough
用于 switch 语句的 fallthrough 属性。
Definition: ydef.h:655
TermRef
lref< const TermNode > TermRef
Definition: NPLA1Forms.cpp:262
NPL::A1::TransformNode
YF_API ValueNode TransformNode(const TermNode &)
变换 NPLA1 节点 S 表达式抽象语法树为 NPLA1 语义结构。
Definition: NPLA1.cpp:1035
NPL::IsList
YB_ATTR_nodiscard YB_PURE const TermNode &term ynothrow const TermNode &term ynothrow const TermNode &term ynothrow const TermNode &term ynothrow IsList
Definition: SContext.h:545
NPL::Session::Process
YB_ATTR_nodiscard DefaultParser Process(_tIn first, _tIn last)
使用解析器处理输入范围。
Definition: SContext.h:857
NPL::IsNPLAExtendedLiteral
YB_ATTR_nodiscard YF_API YB_PURE bool IsNPLAExtendedLiteral(string_view) ynothrowv
判断不是非扩展字面量的词素是否为 NPLA 扩展字面量。
Definition: NPLA.cpp:541
NPL::A1::Reduce
ReductionStatus Reduce(TermNode &term, ContextNode &ctx)
Definition: NPLA1.cpp:898
NPL::A1::DefaultEvaluateLeaf
ReductionStatus DefaultEvaluateLeaf(TermNode &term, string_view id)
Definition: NPLA1.cpp:1189
NPL::ReductionStatus::Retained
@ Retained
非纯值规约：规约成功终止，且需要保留子项。
NPLA1Internals.h
NPLA1 内部接口。
CHRLib::f
f(d, s)
NPL::A1::EvaluateLeafToken
YF_API ReductionStatus EvaluateLeafToken(TermNode &, ContextNode &, string_view)
求值叶节点记号。
Definition: NPLA1.cpp:1284
YSLib::ValueNode::ThrowWrongNameFound
static YB_NORETURN void ThrowWrongNameFound(string_view)
抛出名称错误异常。
Definition: ValueNode.cpp:88
source_information
SourceInformation source_information
Definition: NPLA1.cpp:312
YSLib::MakeIndex
YB_ATTR_nodiscard YF_API YB_PURE string MakeIndex(size_t)
转换节点大小为新的节点索引值。
Definition: ValueNode.cpp:209
delim
TokenValue delim
Definition: NPLA1.cpp:358
NPL::Deliteralize
YB_ATTR_nodiscard YB_PURE Deliteralize
Definition: Lexical.h:338
NPL::yunused
yunused(msg)
NPL::A1::ReduceChildren
term ctx YF_API void ReduceChildren(TNIter, TNIter, ContextNode &)
规约子项。
Definition: NPLA1.cpp:916
NPL::A1::ValueToken::Unspecified
@ Unspecified
未指定值。
act
Action act
Definition: NPLA1.cpp:580
NPL::LexemeCategory::Symbol
@ Symbol
符号：非字面量。
NPL::tm
tm
Definition: NPLA.h:1941
YSLib::AllocatorHolder
在复制初始化时传播分配器的值持有者。
Definition: YObject.h:672
NPL::LexemeCategory::Data
@ Data
数据字面量。
ystdex::isdigit
bool isdigit(char c)
区域无关的 std::isdigit 。
Definition: cctype.h:129
ystdex::details::_type2
_type2
Definition: operators.hpp:241
NPL::A1::RelayForCall
YF_API ReductionStatus RelayForCall(ContextNode &, TermNode &, EnvironmentGuard &&, bool)
函数调用规约（ β-规约）。
Definition: NPLA1.cpp:1441
NPL::ResolveTerm
auto ResolveTerm(_func do_resolve, _tTerm &&term) -> yimpl(decltype(ystdex::expand_proxy< yimpl(void)(_tTerm &&, ResolvedTermReferencePtr)>::call(do_resolve, yforward(term), ResolvedTermReferencePtr())))
解析并间接引用处理可能是引用值的项。
Definition: NPLA.h:1410
NPL::A1::QueryContinuationName
YB_ATTR_nodiscard YB_PURE YF_API string_view QueryContinuationName(const Reducer &)
查询续延中的名称信息。
Definition: NPLA1.cpp:1616
NPL::ReduceBranchToList
ReductionStatus ReduceBranchToList(TermNode &term) ynothrowv
Definition: NPLA.cpp:816
NPL::A1::ThrowNonmodifiableErrorForAssignee
YB_NORETURN YF_API void ThrowNonmodifiableErrorForAssignee()
抛出被赋值操作数不可修改的异常。
Definition: NPLA1.cpp:776
NPL::A1::ContextState::EvaluateList
EvaluationPasses EvaluateList
列表遍。
Definition: NPLA1.h:294
NPL::A1::GParsedValue
typename ParseResultOf< _fParse >::value_type GParsedValue
解析结果元素类型。
Definition: NPLA1.h:1392
NPL_Impl_NPLA1_AssertParameterMatch
#define NPL_Impl_NPLA1_AssertParameterMatch
Definition: NPLA1.cpp:56
YModules.h
NPL 库模块配置文件。
BindTrailing
_fBindTrailing BindTrailing
Definition: NPLA1.cpp:575
ImplI
#define ImplI(...)
Definition: YBaseMacro.h:396
NPL::A1::QuerySourceInformation
YB_ATTR_nodiscard YB_PURE YF_API observer_ptr< const SourceInformation > QuerySourceInformation(const ValueObject &)
查询对象中的源代码信息。
Definition: NPLA1.cpp:1639
TNIter
TermNode::iterator TNIter
Definition: SContext.h:501
NPL::GetLValueTagsOf
GetLValueTagsOf
Definition: SContext.h:162
DefDeCopyMoveCtorAssignment
#define DefDeCopyMoveCtorAssignment(_t)
Definition: YBaseMacro.h:202
YSLib::YAssert
YAssert(!(v< Deref(a)), "Value less than lower bound found.")
NPL::A1::ReduceCombinedBranch
YF_API ReductionStatus ReduceCombinedBranch(TermNode &, ContextNode &)
规约列表合并项：同 ReduceCombined ，但只适用于枝节点。
Definition: NPLA1.cpp:1314
NPL::A1::FormContextHandler::term
const FormContextHandler const FormContextHandler &y TermNode & term
Definition: NPLA1.h:972
platform::containers::stack
std::stack< _type, _tSeqCon > stack
Definition: Container.h:153
ystdex::make_observer
observer_ptr< _type > make_observer(_type *p)
Definition: pointer.hpp:405
NPL::IsBranchedList
YB_ATTR_nodiscard YB_PURE IsBranchedList
Definition: SContext.h:519
yforward
#define yforward(_expr)
根据参数类型使用 std::forward 转发对应参数。
Definition: ydef.h:1508
YSLib::ValueObject
值类型对象类。
Definition: YObject.h:1068
ystdex::try_emplace
std::pair< typename _tAssocCon::iterator, bool > try_emplace(_tAssocCon &con, _tKey &&k, _tParams &&... args)
Definition: container.hpp:1039
ystdex::threading::lock_guard
Definition: pseudo_mutex.h:223
ystdex::cpp2017::data
auto data(_tRange &c) -> decltype(c.data())
Definition: range.hpp:581
YSLib::Drawing::src
src
Definition: YGDI.h:442
filter
Filter filter
Definition: NPLA1.cpp:360
NPL::InvalidSyntax
无效语法。
Definition: NPLA.h:557
NPL::ByteParser
字节解析器。
Definition: Lexical.h:520
NPL::NPLException
NPL 异常基类。
Definition: NPLA.h:445
NPL::EnvironmentReference
环境引用计数检查支持。
Definition: NPLA.h:986
NPL::A1::REPLContext
Definition: NPLA1.h:1554
NPL::A1::ReduceChildrenOrdered
term ctx YF_API ReductionStatus ReduceChildrenOrdered(TNIter, TNIter, ContextNode &)
有序规约子项。
Definition: NPLA1.cpp:934
YSLib::ValueNode
值类型节点。
Definition: ValueNode.h:73
NPL::A1::REPLContext::UseSourceLocation
bool UseSourceLocation
默认启用源代码位置。
Definition: NPLA1.h:1630
NPL::A1::REPLContext::ReadFrom
YB_ATTR_nodiscard TermNode ReadFrom(_type &&input)
读取：从指定参数指定的来源输入源代码并准备规约项。
Definition: NPLA1.h:1766
NPL::IsLeaf
YB_ATTR_nodiscard YB_PURE const TermNode &term ynothrow const TermNode &term ynothrow const TermNode &term ynothrow IsLeaf
Definition: SContext.h:537
NPL::ReductionStatus::Partial
@ Partial
部分规约：需要继续进行规约。
std
Definition: optional.h:982
YB_ATTR
#define YB_ATTR(...)
GNU 风格属性。
Definition: ydef.h:567
ystdex::sfmt
_tString sfmt(const typename string_traits< _tString >::value_type *fmt,...)
以 C 标准输出格式的输出 basic_string 实例的对象。
Definition: string.hpp:2028
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:165
NPL::ReductionStatus::Regular
@ Regular
已取得正规表示的规约：规约成功且已保证正规化，不指定是否需要保留子项。
platform::containers::unordered_map
std::unordered_map< _tKey, _tMapped, _fHash, _fEqual, _tAlloc > unordered_map
Definition: Container.h:133
platform_ex::Windows::Temporary
@ Temporary
Definition: Win32/include/YCLib/MinGW32.h:470
NPL::ReductionStatus::Retrying
@ Retrying
重规约。
NPL::A1::AddTypeNameTableEntry
YB_ATTR_nodiscard YF_API bool AddTypeNameTableEntry(const ystdex::type_info &, string_view)
添加全局类型名称表项。
Definition: NPLA1.cpp:1605
NPL::A1::ContextState::EvaluateLeaf
EvaluationPasses EvaluateLeaf
叶遍。
Definition: NPLA1.h:292
YSLib::yimpl
YF_API yimpl(GUIApplication &) FetchGlobalInstance()
取全局应用程序实例。
NPL::A1::InsertChild
YF_API void InsertChild(ValueNode &&, ValueNode::Container &)
插入 NPLA1 子节点。
Definition: NPLA1.cpp:1028
YSLib::i
return i
Definition: YCoreUtilities.h:177
NPL::A1::FormContextHandler::Handler
ContextHandler Handler
Definition: NPLA1.h:921
YSLib::UI::ScrollCategory::Last
@ Last
滚动框移动至最大位置。
NPL::A1::ContextState::next_term_ptr
observer_ptr< TermNode > next_term_ptr
下一求值项指针。
Definition: NPLA1.h:312
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1535
NPL::A1::ContextState::swap
friend swap(x.combining_term_ptr, y.combining_term_ptr)
NPL::A1::REPLContext::IsAsynchronous
YB_STATELESS bool IsAsynchronous() const ynothrow
判断当前实现是否为异步实现。
Definition: NPLA1.cpp:1707
NPL::ValueCategoryMismatch
值类别不匹配。
Definition: NPLA.h:494
NPL::A1::SetupTailContext
YF_API void SetupTailContext(ContextNode &, TermNode &)
设置参数指定的上下文为尾上下文。
Definition: NPLA1.cpp:1594
NPL::ContextNode::TailAction
Reducer TailAction
尾动作。
Definition: NPLA.h:2584
NPL::A1::to_string
string to_string(ValueToken vt)
Definition: NPLA1.cpp:66
platform::containers::vector
std::vector< _type, _tAlloc > vector
Definition: Container.h:102
NPL
Definition: NPL/Configuration.h:35
ystdex::ref_eq
引用等价关系仿函数。
Definition: functor.hpp:450
NPL::A1::CheckParameterLeafToken
auto CheckParameterLeafToken(string_view n, _func f) -> decltype(f())
检查记号值是符合匹配条件的参数符号。
Definition: NPLA1.h:1273
NPL::A1::SetupTailOperatorName
YF_API bool SetupTailOperatorName(TermNode &, const ContextNode &)
设置当前尾动作规约的操作符名称。
Definition: NPLA1.cpp:1674
NPL::A1::NameTypedContextHandler
YB_ATTR_nodiscard YB_PURE _fCallable NameTypedContextHandler(_fCallable &&x, string_view desc)
初始化作为上下文处理器的全局类型名称表项并转发参数。
Definition: NPLA1.h:1463
NPL::RegularizeTerm
YF_API ReductionStatus RegularizeTerm(TermNode &, ReductionStatus) ynothrow
按规约结果正规化项。
Definition: NPLA.cpp:686
NPL::A1::Forms::Sequence
YF_API ReductionStatus Sequence(TermNode &, ContextNode &)
序列有序参数规约：移除第一项后顺序规约子项，结果为最后一个子项的规约结果。
Definition: NPLA1Forms.cpp:2605
NPL::ToReducer
Reducer ToReducer(const _tAlloc &a, _tParam &&arg, _tParams &&... args)
Definition: NPLA.h:2368
filter2
Filter filter2
Definition: NPLA1.cpp:361
YSLib::AsNode
YB_ATTR_nodiscard YB_PURE ValueNode AsNode(const ValueNode::allocator_type &a, _tString &&str, _tParams &&... args)
Definition: ValueNode.h:1304
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:46
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:143
NPL::A1::NameTypedReducerHandler
YB_ATTR_nodiscard YB_PURE _fCallable NameTypedReducerHandler(_fCallable &&x, string_view desc)
初始化作为规约器处理器的全局类型名称表项并转发参数。
Definition: NPLA1.h:1481
NPL::A1::ContextState::ReduceOnce
Continuation ReduceOnce
NPLA1 表达式节点一次规约续延。
Definition: NPLA1.h:305
NPL::TermToStringWithReferenceMark
YB_ATTR_nodiscard YF_API YB_PURE string TermToStringWithReferenceMark(const TermNode &, bool)
访问项的值并转换为可选带有引用标记的字符串形式。
Definition: NPLA.cpp:567
YSLib::str
const char * str
Definition: YException.cpp:60
NPL::ListReductionFailure
列表规约失败。
Definition: NPLA.h:537
YSLib::ynothrow
YB_PURE const _type size_t n ynothrow
Definition: YCoreUtilities.h:169
YSLib::ValueNode::Container
ystdex::mapped_set< ValueNode, ystdex::less<>, MappedSetTraits, allocator_type > Container
Definition: ValueNode.h:201
NPL::CheckReducible
bool CheckReducible(ReductionStatus status)
Definition: NPLA.cpp:665
NPL::A1::Internals::ReduceCurrentNext
YB_FLATTEN ReductionStatus ReduceCurrentNext(TermNode &term, ContextNode &ctx, _fCurrent &&cur, _fNext &&next)
Definition: NPLA1Internals.h:644
NPL::ContextNode
上下文节点。
Definition: NPLA.h:2385
NPL::A1::name
const char * name
Definition: NPLA1.h:1876
platform::Deref
YB_PURE yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:547
NPL::A1::SetupTraceDepth
void SetupTraceDepth(ContextState &cs, const string &name)
Definition: NPLA1.cpp:999
NPL::A1::Continuation
NPLA1 一等续延。
Definition: NPLA1.h:120
NPL::A1::FormContextHandler
形式上下文处理器。
Definition: NPLA1.h:919
YSLib::ImplRet
ImplRet(FetchGlobalInstance().GetGUIHostRef()) YF_API void Execute(GUIApplication &
执行程序主消息循环。
YSLib::Text::buf
YB_ATTR_nodiscard YB_PURE const char * buf
Definition: TextFile.h:83
NPL::Session
会话：分析组成 NPL 基本翻译单元的源代码。
Definition: SContext.h:797
NPL::Session::ProcessOne
YB_ATTR_nodiscard pair< DefaultParser, _tIn > ProcessOne(ReaderState &rs, _tIn first, _tIn last)
使用解析器处理输入范围读取列表或元素。
Definition: SContext.h:893
alloc
TermPasses::allocator_type alloc
Definition: NPLA1.cpp:357
NPL::ContextNode::ShareRecord
ShareRecord
Definition: NPLA.h:2861
NPL::A1::ContextState::Access
Access
Definition: NPLA1.h:341
NPL::A1::FormContextHandler::Equals
const FormContextHandler const FormContextHandler &y TermNode ContextNode &ctx const ImplRet(CallN(Wrapping, term, ctx)) private YB_ATTR_nodiscard YB_PURE bool Equals(const FormContextHandler &) const
Definition: NPLA1.cpp:1173
NPL::A1::REPLContext::move
YB_ATTR_nodiscard std::move(term)) template< typename... _tParams > YB_ATTR_nodiscard TermNode Prepare(_tParams &&... args) const
Definition: NPLA1.h:1743
YSLib::_tParams
YB_ATTR_nodiscard YB_PURE typename _tParams
Definition: ValueNode.h:1294
NPL::A1::ContextState::Guard
GuardPasses Guard
守卫遍。
Definition: NPLA1.h:298
NPL::A1::FormContextHandler::Wrapping
size_t Wrapping
包装数。
Definition: NPLA1.h:928
ystdex::cpp2017::in_place_type
uniformed_tags::in_place_tag in_place_type(empty_base< _type >)
Definition: placement.hpp:255
ystdex::any
基于类型擦除的动态泛型对象。
Definition: any.h:1634
NPL::c_str
YF_API const char src c_str())) YF_API void InstallDirectory(const string &
安装目录：复制目录树。
Definition: Dependency.h:140
NPL::A1::Internals::RelayForEvalOrDirect
ReductionStatus RelayForEvalOrDirect(ContextNode &ctx, TermNode &term, EnvironmentGuard &&gd, bool no_lift, _fNext &&next)
Definition: NPLA1Internals.h:655
ImplExpr
#define ImplExpr(...)
简单通用函数实现。
Definition: YBaseMacro.h:96
NPL::LexemeCategory::Code
@ Code
代码字面量。
NPL::A1::SetupDefaultInterpretation
YF_API void SetupDefaultInterpretation(ContextState &, EvaluationPasses)
设置默认解释：解释使用的公共处理遍。
Definition: NPLA1.cpp:1546
NPL::A1::QueryTypeName
YB_ATTR_nodiscard YB_PURE YF_API string_view QueryTypeName(const ystdex::type_info &)
查询全局类型名称表。
Definition: NPLA1.cpp:1662
NPL::Access
YB_ATTR_nodiscard YB_PURE const TermNode &term ynothrow const TermNode &term ynothrow const TermNode &term ynothrow const TermNode &term ynothrow const TermNode &term ynothrow ImplRet(!term.Value) using YSLib YB_ATTR_nodiscard YB_PURE _type & Access(TermNode &term)
Definition: SContext.h:555
NPL::A1::tm
tm
Definition: NPLA1.h:593
platform::p
return p p
Definition: YCLib/FileSystem.h:209
ystdex::default_last_value
合并值序列。
Definition: functional.hpp:851
NPL::A1::ValueToken
ValueToken
值记号：节点中的值的占位符。
Definition: NPLA1.h:83
NPL::A1::ReduceOrdered
ReductionStatus ReduceOrdered(TermNode &term, ContextNode &ctx)
Definition: NPLA1.cpp:965
YSLib::Text::str
YB_ATTR_nodiscard YB_PURE const char const char * str
Definition: TextFile.h:83
YSLib::ValueNode::allocator_type
pmr::polymorphic_allocator< ValueNode > allocator_type
分配器类型。
Definition: ValueNode.h:81
NPL::Session::Lexer
LexicalAnalyzer Lexer
Definition: SContext.h:802
const
const Decapsulate const Decapsulate &y ynothrow ContextNode &ctx const
Definition: NPLA1Forms.cpp:1629
ystdex::make_string_view
basic_string_view< typename string_traits< _tString >::value_type, typename string_traits< _tString >::traits_type > make_string_view(const _tString &str)
从字符串创建 basic_string_view 对象。
Definition: string.hpp:814
NPL::AsTermNode
typename _tParams YB_ATTR_nodiscard YB_PURE ystdex::enable_if_t< ystdex::not_< ystdex::cond_or_t< ystdex::bool_<(sizeof...(_tParams) >=1)>, ystdex::false_, std::is_convertible, ystdex::decay_t< _tParams >..., TermNode::allocator_type > >::value, TermNode > AsTermNode(_tParams &&... args)
Definition: SContext.h:601
NPL::SourceInformation
pair< SourceName, SourceLocation > SourceInformation
源代码信息。
Definition: Lexical.h:109
ystdex::any_ops::use_holder
const struct ystdex::any_ops::use_holder_t use_holder
NPL::A1::ThrowInvalidSyntaxError
void ThrowInvalidSyntaxError(const char *str)
Definition: NPLA1.cpp:765
NPL::A1::Internals::ReduceSubsequent
ReductionStatus ReduceSubsequent(TermNode &term, ContextNode &ctx, _fNext &&next)
Definition: NPLA1Internals.h:699
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:1199
NPL::A1::ReduceOnce
YF_API ReductionStatus ReduceOnce(TermNode &, ContextNode &)
NPLA1 表达式节点一次规约：转发调用到 NPLA1 表达式节点一次规约续延并调用。
Definition: NPLA1.cpp:959
YSLib::vo
vo
Definition: YApplication.h:231
YSLib::AllocatedHolderOperations
带有分配器的持有者操作。
Definition: YObject.h:396
NPL::A1::ThrowUnsupportedLiteralError
void ThrowUnsupportedLiteralError(const char *id)
Definition: NPLA1.cpp:782
TryRet
#define TryRet(...)
指定表达式在 try 块中求值并返回。
Definition: YBaseMacro.h:124
NPL::A1::ReduceFirst
term ctx YF_API ReductionStatus ReduceFirst(TermNode &, ContextNode &)
规约第一个子项。
Definition: NPLA1.cpp:951
NPL::A1::REPLContext::REPLContext
REPLContext(pmr::memory_resource &=NPL::Deref(pmr::new_delete_resource()))
构造：使用默认的解释、指定的存储资源和默认的叶节点词素转换器。
Definition: NPLA1.cpp:1689
NPL::A1::REPLContext::LoadOptionTag
std::integral_constant< LoadOption, _vOpt > LoadOptionTag
代码加载选项标签类型。
Definition: NPLA1.h:1570
YSLib::args
YB_ATTR_nodiscard YB_PURE typename _tParams && args
Definition: ValueNode.h:1299
NPL::A1::string_view
YB_ATTR_nodiscard YB_PURE term string_view
Definition: NPLA1.h:1072
ystdex::ref
void ref(const _type &&)=delete
NPL::A1::ContextState::ContextState
ContextState(pmr::memory_resource &)
构造：使用指定的存储资源。
Definition: NPLA1.cpp:797
YSLib::NoContainer
yconstexpr const struct YSLib::NoContainerTag NoContainer
NPL::CategorizeBasicLexeme
YB_ATTR_nodiscard YF_API YB_PURE LexemeCategory CategorizeBasicLexeme(string_view) ynothrowv
对排除扩展字面量的词素分类。
NPL::A1::ReduceLeafToken
YB_FLATTEN ContextNode const TermNode &YF_API ReductionStatus ReduceLeafToken(TermNode &, ContextNode &)
规约提取名称的叶节点记号。
Definition: NPLA1.cpp:1411
YB_ATTR_LAMBDA
#define YB_ATTR_LAMBDA(...)
允许在 lambda 表达式的参数列表后使用的属性。
Definition: ydef.h:581
YSLib::PDefH
PDefH(Environment &, FetchEnvironment,) ImplRet(FetchGlobalInstance().GetEnvironmentRef()) inline PDefH(GUIHost &
取单一环境对象引用。
ystdex::cpp2017::as_const
add_const_t< _type > & as_const(_type &t)
转换 const 引用。
Definition: utility.hpp:77
NPL::ReductionStatus
ReductionStatus
规约状态：某个项上的一遍规约可能的中间结果。
Definition: NPLA.h:1520
ystdex::call_value_or
auto call_value_or(_func f, _type &&p) -> decay_t< decltype(f(*std::forward< decltype(p)>(p)))>
调用非空值或取默认值。
Definition: deref_op.hpp:152
ystdex::cpp2017::begin
auto begin(_tRange &c) -> decltype(c.begin())
Definition: range.hpp:323
YSLib::a
YB_PURE const _type * a
Definition: YCoreUtilities.h:168
NPL::SourceName
shared_ptr< string > SourceName
可选的源代码名称。
Definition: Lexical.h:80
NPL::A1::QueryTailOperatorName
YB_ATTR_nodiscard YB_PURE YF_API observer_ptr< const ValueObject > QueryTailOperatorName(const Reducer &)
查询续延指定的当前尾动作规约的操作符名称项。
Definition: NPLA1.cpp:1649
ystdex::guard
作用域守卫：析构时调用保存的函数对象或引用。
Definition: scope_guard.hpp:48