YSTest: NPLA1Forms.cpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

NPLA1Forms.cpp
浏览该文件的文档.
1 /*
2 © 2016-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, std::next, ReduceOnceLifted,
30 // NPL::IsMovable, function, NPL::TryAccessReferencedTerm, ystdex::value_or,
31 // ThrowInsufficientTermsError, NPL::Deref, A1::NameTypedReducerHandler,
32 // ReduceReturnUnspecified, RemoveHead, IsBranch, AccessFirstSubterm,
33 // ReduceNextCombinedBranch, std::placeholders, ystdex::as_const, IsLeaf,
34 // ystdex::ref_eq, ContextHandler, shared_ptr, string, unordered_map,
35 // Environment, lref, list, IsBranchedList, TokenValue, NPL::TryAccessLeaf,
36 // ValueObject, weak_ptr, any_ops::use_holder, in_place_type, ystdex::type_id,
37 // YSLib::allocate_shared, InvalidReference, MoveFirstSubterm, ShareMoveTerm,
38 // ThrowInvalidSyntaxError, ReduceCombinedBranch, ResolvedTermReferencePtr,
39 // LiftOtherOrCopy, ResolveTerm, ystdex::equality_comparable,
40 // std::allocator_arg, NPL::AsTermNode, ystdex::exchange,
41 // NPL::SwitchToFreshEnvironment, TermTags, ystdex::expand_proxy,
42 // NPL::AccessRegular, GetLValueTagsOf, RegularizeTerm,
43 // ThrowValueCategoryErrorForFirstArgument, TermReference,
44 // NPL::TryAccessReferencedLeaf, ystdex::invoke_value_or,
45 // ystdex::call_value_or, RelaySwitched, LiftMovedOther, LiftCollapsed,
46 // ystdex::make_transform, NPL::AllocateEnvironment, NPL::TryAccessTerm,
47 // std::mem_fn;
48 #include "NPLA1Internals.h" // for A1::Internals API;
49 #include YFM_NPL_SContext // for Session;
50
51 using namespace YSLib;
52
53 namespace NPL
54 {
55
57
58 #ifndef NDEBUG
59 # define NPL_Impl_NPLA1_TraceVauCall true
60 #else
61 # define NPL_Impl_NPLA1_TraceVauCall false
62 #endif
63
64
65 namespace A1
66 {
67
69 namespace
70 {
71
73
74 using Forms::CallRegularUnaryAs;
76 using Forms::CallResolvedUnary;
77 using Forms::CallUnary;
78 using Forms::Retain;
79 using Forms::RetainN;
81
82
84 // XXX: This is more efficient, at least in code generation by x86_64-pc-linux
85 // G++ 9.2 for %WrapN.
86 template<typename _fCopy, typename _fMove>
87 YB_ATTR_nodiscard YB_FLATTEN auto
88 MakeValueOrMove(ResolvedTermReferencePtr p_ref, _fCopy cp, _fMove mv)
89 -> decltype(NPL::IsMovable(p_ref) ? mv() : cp())
90 {
91 return NPL::IsMovable(p_ref) ? mv() : cp();
92 }
93
94
96 YB_ATTR_nodiscard YB_PURE bool
97 ExtractBool(const TermNode& term)
98 {
99 return ystdex::value_or(NPL::TryAccessReferencedTerm<bool>(term), true);
100 }
101
103
104 YB_ATTR_nodiscard TNIter
105 CondClauseCheck(TermNode& clause)
106 {
107 if(YB_UNLIKELY(clause.empty()))
108 ThrowInsufficientTermsError();
109 return clause.begin();
110 }
111
112 YB_ATTR_nodiscard bool
113 CondTest(TermNode& clause, TNIter j)
114 {
115 if(ExtractBool(*j))
116 {
117 clause.erase(j);
118 return true;
119 }
120 return {};
121 }
122
123 #if NPL_Impl_NPLA1_Enable_Thunked
124 ReductionStatus
125 CondImpl(TermNode& term, ContextNode& ctx, TNIter i)
126 {
127 if(i != term.end())
128 {
129 auto& clause(NPL::Deref(i));
130 auto j(CondClauseCheck(clause));
131
132 // NOTE: This also supports TCO.
133 return ReduceSubsequent(NPL::Deref(j), ctx,
134 A1::NameTypedReducerHandler([&, i, j](ContextNode& c){
135 if(CondTest(clause, j))
136 return ReduceOnceLifted(term, c, clause);
137 return CondImpl(term, c, std::next(i));
138 }, "eval-cond-list"));
139 }
140 return ReduceReturnUnspecified(term);
141 }
142 #endif
143
144 ReductionStatus
145 WhenUnless(TermNode& term, ContextNode& ctx, bool is_when)
146 {
147 using namespace Forms;
148
149 Retain(term);
150 RemoveHead(term);
151 if(IsBranch(term))
152 {
153 auto& test(AccessFirstSubterm(term));
154
155 return ReduceSubsequent(test, ctx,
156 A1::NameTypedReducerHandler([&, is_when](ContextNode& c){
157 if(ExtractBool(test) == is_when)
158 {
159 RemoveHead(term);
160 return ReduceOrdered(term, c);
161 }
162 return ReduceReturnUnspecified(term);
163 }, "conditional-eval-sequence"));
164 }
165 else
166 ThrowInsufficientTermsError();
167 }
168
169 ReductionStatus
170 And2(TermNode& term, ContextNode& ctx, TNIter i)
171 {
172 if(ExtractBool(NPL::Deref(i)))
173 {
174 term.Remove(i);
175 return ReduceNextCombinedBranch(term, ContextState::Access(ctx));
176 }
177 term.Value = false;
178 return ReductionStatus::Clean;
179 }
180
181 ReductionStatus
182 Or2(TermNode& term, ContextNode& ctx, TNIter i)
183 {
184 auto& tm(NPL::Deref(i));
185
186 if(!ExtractBool(tm))
187 {
188 term.Remove(i);
189 return ReduceNextCombinedBranch(term, ContextState::Access(ctx));
190 }
191 LiftOther(term, tm);
192 return ReductionStatus::Retained;
193 }
194
195 ReductionStatus
196 AndOr(TermNode& term, ContextNode& ctx,
197 ReductionStatus (&and_or)(TermNode&, ContextNode&, TNIter))
198 {
199 Retain(term);
200
201 auto i(term.begin());
202
203 if(++i != term.end())
204 return std::next(i) == term.end() ? ReduceOnceLifted(term, ctx, *i)
205 : ReduceSubsequent(*i, ctx,
206 A1::NameTypedReducerHandler(std::bind(and_or, std::ref(term),
207 std::placeholders::_1, i), "eval-booleans"));
208 term.Value = and_or == And2;
209 return ReductionStatus::Clean;
210 }
212
214
215 template<typename _fComp, typename _func>
216 void
217 EqualTerm(TermNode& term, _fComp f, _func g)
218 {
219 RetainN(term, 2);
220
221 auto i(term.begin());
222 const auto& x(*++i);
223
224 term.Value = f(g(x), g(ystdex::as_const(*++i)));
225 }
226
227 template<typename _func>
228 void
229 EqualTermValue(TermNode& term, _func f)
230 {
231 EqualTerm(term, f, [](const TermNode& x) -> const ValueObject&{
232 return ReferenceTerm(x).Value;
233 });
234 }
235
236 template<typename _func>
237 void
238 EqualTermReference(TermNode& term, _func f)
239 {
240 EqualTerm(term, [f](const TermNode& x, const TermNode& y) YB_PURE{
241 return IsLeaf(x) && IsLeaf(y) ? f(x.Value, y.Value)
242 : ystdex::ref_eq<>()(x, y);
243 }, static_cast<const TermNode&(&)(const TermNode&)>(ReferenceTerm));
244 }
246
247
248 // NOTE: See $2019-03 @ %Documentation::Workflow.
250 class RecursiveThunk final
251 {
252 private:
254 using shared_ptr_t = shared_ptr<ContextHandler>;
256 unordered_map<string, shared_ptr_t> store{};
257
258 public:
260 shared_ptr<Environment> RecordPtr;
262 lref<const TermNode> TermRef;
263
265 RecursiveThunk(const shared_ptr<Environment>& p_env, const TermNode& t)
266 ynothrow
267 : RecordPtr(p_env), TermRef(t)
268 {
269 Fix(RecordPtr, TermRef);
270 }
272 DefDeMoveCtor(RecursiveThunk)
273
274
275 DefDeMoveAssignment(RecursiveThunk)
276
277 private:
279 void
280 Fix(const shared_ptr<Environment>& p_env, const TermNode& t)
281 {
282 auto& env(NPL::Deref(p_env));
283
284 if(IsBranchedList(t))
285 for(const auto& tm : t)
286 Fix(p_env, tm);
287 else if(const auto p = NPL::TryAccessLeaf<TokenValue>(t))
288 {
289 const auto& n(*p);
290
291 // XXX: This is served as the addtional static environment.
292 CheckParameterLeafToken(n, [&]{
293 // NOTE: The symbol can be bound more than once. Only one
294 // instance is supported.
295 if(store.find(n) == store.cend())
296 // NOTE: The bound symbol can then be rebound to an ordinary
297 // (non-sharing) object.
298 env.Bind(n, TermNode(TermNode::Container(t.get_allocator()),
299 ValueObject(any_ops::use_holder, in_place_type<
300 HolderFromPointer<shared_ptr_t>>,
301 store[n] = YSLib::allocate_shared<ContextHandler>(
302 t.get_allocator(), ThrowInvalidCyclicReference))));
303 });
304 }
305 }
306
308 YB_NORETURN static ReductionStatus
309 ThrowInvalidCyclicReference(TermNode&, ContextNode&)
310 {
311 throw InvalidReference("Invalid cyclic reference found.");
312 }
313 };
314
315
317 YB_ATTR_nodiscard inline PDefH(const shared_ptr<Environment>&,
318 FetchDefineOrSetEnvironment, ContextNode& ctx) ynothrow
319 ImplRet(ctx.GetRecordPtr())
321 YB_ATTR_nodiscard inline PDefH(const shared_ptr<Environment>&,
322 FetchDefineOrSetEnvironment, ContextNode&,
323 const shared_ptr<Environment>& p_env)
324 ImplRet(Environment::EnsureValid(p_env), p_env)
325
327 YB_NORETURN inline void
328 ThrowInsufficientTermsErrorFor(InvalidSyntax&& e)
329 {
330 TryExpr(ThrowInsufficientTermsError())
331 CatchExpr(..., std::throw_with_nested(std::move(e)))
332 }
333
335 YF_API void
336 BindParameterChecked(const shared_ptr<Environment>& p_env, const TermNode& t,
337 TermNode& o)
338 {
339 if(!p_env->Frozen)
340 BindParameter(p_env, t, o);
341 else
342 throw TypeError("Cannot define variables in a frozen environment.");
343 }
344
346
347 template<typename _func>
348 auto
349 DoDefineSet(TermNode& term, size_t n, _func f) -> decltype(f())
350 {
351 Retain(term);
352 if(term.size() > n)
353 return f();
354 ThrowInsufficientTermsErrorFor(
355 InvalidSyntax("Invalid syntax found in definition."));
356 }
357
358 // XXX: Both %YB_FLATTEN are needed in the following code. Otherwise,
359 // optimization of G++ 9.1 would try reusing the basic blocks inside the
360 // instantiated functions and the resulted code would be inefficient even all
361 // calls in the client code of the public interface (e.g.
362 // %Forms::DefineWithNoRecursion) are only relying on one of them.
363
364 template<typename _func>
365 YB_FLATTEN auto
366 DoDefine(TermNode& term, _func f) -> decltype(f(term))
367 {
368 return DoDefineSet(term, 2, [&]{
369 RemoveHead(term);
370
371 auto formals(MoveFirstSubterm(term));
372
373 RemoveHead(term);
374 return f(formals);
375 });
376 }
377
378 template<typename _func>
379 YB_FLATTEN ReductionStatus
380 DoSet(TermNode& term, ContextNode& ctx, _func f)
381 {
382 return DoDefineSet(term, 3, [&]{
383 RemoveHead(term);
384
385 const auto i(term.begin());
386
387 return ReduceSubsequent(*i, ctx, [&, f, i]{
388 auto p_env(ResolveEnvironment(*i).first);
389
390 RemoveHead(term);
391
392 auto formals(MoveFirstSubterm(term));
393
394 RemoveHead(term);
395 // NOTE: It is necessary to save %p_env here. The necessary check is
396 // in the call of %FetchDefineOrSetEnvironment.
397 return f(formals, std::move(p_env));
398 });
399 });
400 }
401
402
403 template<bool = false>
404 struct DoDefineOrSet final
405 {
407 template<typename... _tParams>
408 static ReductionStatus
409 Call(TermNode& term, ContextNode& ctx, shared_ptr<Environment> p_env,
410 TermNode& formals, _tParams&&... args)
411 {
412 #if NPL_Impl_NPLA1_Enable_Thunked
413 // XXX: Terms shall be moved and saved into the actions.
414 // TODO: Blocked. Use C++14 lambda initializers to simplify the
415 // implementation.
416 return ReduceSubsequent(term, ctx,
417 A1::NameTypedReducerHandler(std::bind([&](const TermNode& saved,
418 const shared_ptr<Environment>& p_e, const _tParams&...){
419 BindParameterChecked(p_e, saved, term);
420 return ReduceReturnUnspecified(term);
421 }, std::move(formals), std::move(p_env), std::move(args)...),
422 "match-ptree"));
423 #else
424 yunseq(0, args...);
425 // NOTE: This does not support PTC.
426 CallImpl(term, ctx, p_env, formals);
427 return ReduceReturnUnspecified(term);
428 #endif
429 }
430
431 #if !NPL_Impl_NPLA1_Enable_Thunked
432 static void
434 CallImpl(TermNode& term, ContextNode& ctx,
435 const shared_ptr<Environment>& p_env, TermNode& formals)
436 {
437 ReduceOnce(term, ctx);
438 BindParameterChecked(p_env, formals, term);
439 }
440 #endif
441 };
442
443 template<>
444 struct DoDefineOrSet<true> final
445 {
447 template<typename... _tParams>
448 static ReductionStatus
449 Call(TermNode& term, ContextNode& ctx, shared_ptr<Environment> p_env,
450 TermNode& formals, _tParams&&... args)
451 {
452 #if NPL_Impl_NPLA1_Enable_Thunked
453 // XXX: Terms shall be moved and saved into the actions.
454 auto p_saved(ShareMoveTerm(formals));
455
456 // TODO: Avoid %shared_ptr.
457 // TODO: Blocked. Use C++14 lambda initializers to simplify the
458 // implementation.
459 return ReduceSubsequent(term, ctx,
460 A1::NameTypedReducerHandler(std::bind([&](const
461 shared_ptr<TermNode>&, const shared_ptr<RecursiveThunk>& p_gd,
462 const _tParams&...){
463 BindParameterChecked(p_gd->RecordPtr, p_gd->TermRef, term);
464 // NOTE: This support PTC only when the thunk cleanup is not existed
465 // at the tail context.
466 return ReduceReturnUnspecified(term);
467 }, std::move(p_saved), YSLib::allocate_shared<RecursiveThunk>(
468 term.get_allocator(), std::move(p_env), *p_saved),
469 std::move(args)...), "match-ptree-recursive"));
470 #else
471 // NOTE: This does not support PTC.
472 RecursiveThunk gd(std::move(p_env), formals);
473
474 yunseq(0, args...);
475 DoDefineOrSet<>::CallImpl(term, ctx, gd.RecordPtr, formals);
476 // NOTE: This support PTC only when the thunk cleanup is not existed at
477 // the tail context.
478 return ReduceReturnUnspecified(term);
479 #endif
480 }
481 };
482
483
484 template<bool _bRecur = false>
485 struct DefineOrSetDispatcher final
486 {
487 TermNode& TermRef;
488 ContextNode& Context;
489
490 template<typename... _tParams>
491 inline ReductionStatus
492 operator()(TermNode& formals, _tParams&&... args) const
493 {
494 return DoDefineOrSet<_bRecur>::Call(TermRef, Context,
495 FetchDefineOrSetEnvironment(Context, args...), formals,
496 yforward(args)...);
497 }
498 };
500
501
503
504 YB_ATTR_nodiscard YB_PURE inline
505 PDefH(bool, IsIgnore, const TokenValue& s) ynothrow
506 // XXX: This is more efficient than cast to %basic_string_view if the
507 // %basic_string implementation is optimized.
508 ImplRet(s == "#ignore")
509
510 YB_ATTR_nodiscard YB_PURE inline
511 PDefH(bool, IsIgnoreOrNPLASymbol, const TokenValue& s) ynothrow
512 ImplRet(IsIgnore(s) || IsNPLASymbol(s))
513
514 YB_NONNULL(2) void
515 CheckVauSymbol(const TokenValue& s, const char* target, bool is_valid)
516 {
517 if(YB_UNLIKELY(!is_valid))
518 ThrowInvalidSyntaxError(ystdex::sfmt("Token '%s' is not a symbol or"
519 " '#ignore' expected for %s.", s.data(), target));
520 }
522
524 YB_NORETURN YB_NONNULL(2) void
525 ThrowInvalidSymbolType(const TermNode& term, const char* n)
526 {
527 ThrowInvalidSyntaxError(ystdex::sfmt("Invalid %s type '%s' found.", n,
528 term.Value.type().name()));
529 }
530
532 YB_ATTR_nodiscard YB_PURE string
533 CheckEnvFormal(const TermNode& eterm)
534 {
535 const auto& term(ReferenceTerm(eterm));
536
537 if(const auto p = TermToNamePtr(term))
538 {
539 if(!IsIgnore(*p))
540 {
541 CheckVauSymbol(*p, "environment formal parameter",
542 IsNPLASymbol(*p));
543 return *p;
544 }
545 }
546 else
547 ThrowInvalidSymbolType(term, "environment formal parameter");
548 return {};
549 }
550
551
553
554 // XXX: Same to %RelayForEvalOrDirect, except that %no_lift is always %true, and
555 // no TCO is enforced.
556 template<typename _fNext>
557 YB_FLATTEN inline ReductionStatus
558 RelayNextGuarded(ContextNode& ctx, TermNode& term, EnvironmentGuard&& gd,
559 _fNext&& next)
560 {
561 // XXX: See %RelayForEvalOrDirect.
562 #if NPL_Impl_NPLA1_Enable_Thunked
563 // TODO: Blocked. Use C++14 lambda initializers to simplify the
564 // implementation.
565 return A1::RelayCurrentNext(term, ctx, yforward(next), MakeMoveGuard(gd));
566 #else
567 yunused(gd);
568 return A1::RelayDirect(ctx, next, term);
569 #endif
570 }
571
572 // XXX: Same to %RelayForEvalOrDirect, except that %no_lift is always %true.
573 template<typename _fNext>
574 YB_FLATTEN inline ReductionStatus
575 RelayNextGuardedTail(ContextNode& ctx, TermNode& term,
576 EnvironmentGuard&& gd, _fNext&& next)
577 {
578 // XXX: See %RelayForEvalOrDirect.
579 #if NPL_Impl_NPLA1_Enable_TCO
580 PrepareTCOEvaluation(ctx, term, std::move(gd));
581 return A1::RelayCurrentOrDirect(ctx, yforward(next), term);
582 #else
583 return A1::RelayNextGuarded(ctx, term, std::move(gd), yforward(next));
584 #endif
585 }
586
587 // XXX: A combination of an operative and its operand shall always be evaluated
588 // in a tail context. However, for a combiner call, sometimes it is not in the
589 // tail context in the enclosing context. If the call needs no creation of
590 // %TCOAction (e.g. fully implemented native code), avoiding calling
591 // %PrepareTCOEvaluation needs no precondition of the existence of %TCOAction,
592 // and this can be an optimization.
593 #if false
594 YB_FLATTEN inline ReductionStatus
595 RelayCombined(ContextNode& ctx, TermNode& term, shared_ptr<Environment> p_env)
596 {
597 // NOTE: %ReduceFirst and other passes would not be called again. The
598 // unwrapped combiner should have been evaluated and it would not be
599 // wrongly evaluated again.
600 // XXX: Consider optimization when the combiner subterm is known regular.
601 // NOTE: Term is set in %A1::RelayNextGuarded, even for direct
602 // inlining call of %ReduceCombinedBranch.
603 return A1::RelayNextGuarded(ctx, term,
604 EnvironmentGuard(ctx, ctx.SwitchEnvironment(std::move(p_env))),
605 std::ref(ReduceCombinedBranch));
606 }
607 #endif
608
609 YB_FLATTEN inline ReductionStatus
610 RelayCombinedTail(ContextNode& ctx, TermNode& term,
611 shared_ptr<Environment> p_env)
612 {
613 // NOTE: See %RelayCombined.
614 // NOTE: Term is set in %A1::RelayNextGuardedTail, even for direct
615 // inlining call of %ReduceCombinedBranch.
616 return A1::RelayNextGuardedTail(ctx, term,
617 EnvironmentGuard(ctx, ctx.SwitchEnvironment(std::move(p_env))),
618 std::ref(ReduceCombinedBranch));
619 }
621
627 ReductionStatus
628 EvalImplUnchecked(TermNode& term, ContextNode& ctx, bool no_lift)
629 {
630 const auto i(std::next(term.begin()));
631 auto p_env(ResolveEnvironment(NPL::Deref(std::next(i))).first);
632
633 ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
634 LiftOtherOrCopy(term, nd, NPL::IsMovable(p_ref));
635 }, NPL::Deref(i));
636 return RelayForEvalOrDirect(ctx, term, EnvironmentGuard(ctx,
637 ctx.SwitchEnvironment(std::move(p_env))), no_lift,
638 std::ref(ContextState::Access(ctx).ReduceOnce));
639 }
640
642 ReductionStatus
643 EvalImpl(TermNode& term, ContextNode& ctx, bool no_lift)
644 {
645 RetainN(term, 2);
646 return EvalImplUnchecked(term, ctx, no_lift);
647 }
648
649 ReductionStatus
650 EvalStringImpl(TermNode& term, ContextNode& ctx, bool no_lift)
651 {
652 RetainN(term, 2);
653
654 auto& expr(*std::next(term.begin()));
655 Session sess(ctx.get_allocator());
656
657 SContext::Analyze(std::allocator_arg, ctx.get_allocator(), sess,
658 sess.Process(NPL::ResolveRegular<const string>(expr)))
659 .SwapContainer(expr);
660 return EvalImplUnchecked(term, ctx, no_lift);
661 }
663
664
666 YB_ATTR_nodiscard YB_PURE inline
667 PDefH(InvalidSyntax, MakeFunctionAbstractionError, ) ynothrow
668 ImplRet(InvalidSyntax("Invalid syntax found in function abstraction."))
669
670
672 class VauHandler final : private ystdex::equality_comparable<VauHandler>
673 {
674 private:
679 string eformal{};
685 shared_ptr<TermNode> p_formals;
691 EnvironmentReference parent;
696 mutable shared_ptr<Environment> p_static;
701 mutable shared_ptr<TermNode> p_eval_struct;
706 ReductionStatus(VauHandler::*p_call)(TermNode&, ContextNode&) const;
707
708 public:
710 bool NoLifting = {};
711
716 VauHandler(string&& ename, shared_ptr<TermNode>&& p_fm,
717 shared_ptr<Environment>&& p_env, bool owning, TermNode& term, bool nl)
718 : eformal(std::move(ename)), p_formals((CheckParameterTree(Deref(p_fm)),
719 std::move(p_fm))), parent((Environment::EnsureValid(p_env), p_env)),
720 // XXX: Optimize with region inference?
721 p_static(owning ? std::move(p_env) : nullptr),
722 p_eval_struct(ShareMoveTerm(ystdex::exchange(term,
723 NPL::AsTermNode(term.get_allocator())))), p_call(eformal.empty()
724 ? &VauHandler::CallStatic : &VauHandler::CallDynamic), NoLifting(nl)
725 {}
726
728 friend bool
729 operator==(const VauHandler& x, const VauHandler& y)
730 {
731 return x.eformal == y.eformal && x.p_formals == y.p_formals
732 && x.parent == y.parent && x.p_static == y.p_static
733 && x.NoLifting == y.NoLifting;
734 }
735
737 ReductionStatus
738 operator()(TermNode& term, ContextNode& ctx) const
739 {
740 if(IsBranchedList(term))
741 {
742 if(p_eval_struct)
743 return (this->*p_call)(term, ctx);
744 // XXX: The call has been performed on the handler, see the notes in
745 // %DoCall.
746 throw NPLException("Invalid handler of call found.");
747 }
748 throw LoggedEvent("Invalid composition found.", Alert);
749 }
750
751 private:
753
754 void
755 BindEnvironment(ContextNode& ctx, ValueObject&& vo) const
756 {
757 YAssert(!eformal.empty(), "Empty dynamic environment name found.");
758 // NOTE: Bound the dynamic environment.
759 ctx.GetRecordRef().AddValue(eformal, std::move(vo));
760 // NOTE: The dynamic environment is either out of TCO action or
761 // referenced by other environments already in TCO action, so there
762 // is no need to treat as root.
763 }
764
765 ReductionStatus
766 CallDynamic(TermNode& term, ContextNode& ctx) const
767 {
768 // NOTE: Evaluation in the local context: using the activation
769 // record frame with outer scope bindings.
770 auto wenv(ctx.WeakenRecord());
771 // XXX: Reuse of frame cannot be done here unless it can be proved all
772 // bindings would behave as in the old environment, which is too
773 // expensive for direct execution of programs with first-class
774 // environments.
775 EnvironmentGuard gd(ctx, NPL::SwitchToFreshEnvironment(ctx));
776
777 BindEnvironment(ctx, std::move(wenv));
778 // XXX: Referencing escaped variables (now only parameters need to be
779 // cared) form the context would cause undefined behavior (e.g.
780 // returning a reference to automatic object in the host language). The
781 // lifting of call result is enabled to prevent this, unless
782 // %NoLifting is %true. See also %BindParameter.
783 return DoCall(term, ctx, gd);
784 }
785
786 ReductionStatus
787 CallStatic(TermNode& term, ContextNode& ctx) const
788 {
789 // NOTE: See above.
790 EnvironmentGuard gd(ctx, NPL::SwitchToFreshEnvironment(ctx));
791
792 return DoCall(term, ctx, gd);
793 }
794
795 public:
797 static void
798 CheckParameterTree(const TermNode& term)
799 {
800 for(const auto& child : term)
801 CheckParameterTree(child);
802 if(term.Value)
803 {
804 if(const auto p = TermToNamePtr(term))
805 CheckVauSymbol(*p, "parameter in a parameter tree",
806 IsIgnoreOrNPLASymbol(*p));
807 else
808 ThrowInvalidSymbolType(term, "parameter tree node");
809 }
810 }
811
812 private:
813 ReductionStatus
814 DoCall(TermNode& term, ContextNode& ctx, EnvironmentGuard& gd) const
815 {
816 YAssert(p_eval_struct, "Invalid evaluation structure found.");
817
818 const bool move(p_eval_struct.use_count() == 1
819 && bool(term.Tags & TermTags::Temporary));
820
821 // NOTE: Since the first term is expected to be saved (e.g. by
822 // %ReduceCombined), it is safe to be removed directly.
823 RemoveHead(term);
824 // NOTE: Forming beta-reducible terms using parameter binding, to
825 // substitute them as arguments for later closure reduction.
826 // XXX: Do not lift terms if provable to be safe?
827 // NOTE: Since now binding does not rely on temporaries stored elsewhere
828 // (by using %TermTags::Temporary instead), this should be safe even
829 // with TCO.
830 // NOTE: The environment is assumed not frozen, so no need to use
831 // %BindParameterChecked.
832 BindParameter(ctx.GetRecordPtr(), NPL::Deref(p_formals), term);
833 #if NPL_Impl_NPLA1_TraceVauCall
834 ctx.Trace.Log(Debug, [&]{
835 return sfmt<string>("Function called, with %ld shared term(s), %ld"
836 " %s shared static environment(s), %zu parameter(s).",
837 p_eval_struct.use_count(), parent.GetPtr().use_count(),
838 p_static ? "owning" : "nonowning", p_formals->size());
839 });
840 #endif
841 // NOTE: The static environment is bound as the base of the local
842 // environment by setting the parent environment pointer.
843 ctx.GetRecordRef().Parent = parent;
844 #if NPL_Impl_NPLA1_Enable_TCO
845 // XXX: Assume the last function is this object.
846 // TODO: Avoid TCO when the static environment has something with side
847 // effects on destruction.
848 if(move)
849 {
850 TermNode eval_struct(std::move(Deref(p_eval_struct)));
851 auto& act(RefTCOAction(ctx));
852
853 if(p_static && p_static.use_count() == 1)
854 act.RecordList.emplace_front(ContextHandler(),
855 std::move(p_static));
856
857 const bool no_lifting(NoLifting);
858
859 // XXX: This would make '*this' invalid.
860 yunused(act.MoveFunction());
861 // XXX: The evaluation structure does not need to be saved, since it
862 // would be used immediately in %RelayForCall. The pointer is moved
863 // to indicate the error condition when it is called again.
864 LiftOther(term, eval_struct);
865 return RelayForCall(ctx, term, std::move(gd), no_lifting);
866 }
867 else
868 term.SetContent(Deref(p_eval_struct));
869 #else
870 // XXX: Ditto.
871 LiftOtherOrCopy(term, Deref(p_eval_struct), move);
872 #endif
873 return RelayForCall(ctx, term, std::move(gd), NoLifting);
874 }
876 };
877
878
880 YB_FLATTEN void
881 MakeValueListOrMove(TermNode& term, TermNode& nd,
882 ResolvedTermReferencePtr p_ref)
883 {
884 MakeValueOrMove(p_ref, [&]{
885 for(const auto& sub : nd)
886 term.Add(sub);
887 }, [&]{
888 // XXX: No cyclic reference check.
889 term.GetContainerRef().splice(term.end(),
890 std::move(nd.GetContainerRef()));
891 });
892 }
893
895
896 YB_NORETURN void
897 ThrowConsError(TermNode& nd, ResolvedTermReferencePtr p_ref)
898 {
899 throw ListTypeError(ystdex::sfmt(
900 "Expected a list for the 2nd argument, got '%s'.",
901 TermToStringWithReferenceMark(nd, p_ref).c_str()));
902 }
903
904 void
905 ConsItem(TermNode& term, TermNode& y)
906 {
907 ResolveTerm([&](TermNode& nd_y, ResolvedTermReferencePtr p_ref){
908 if(IsList(nd_y))
909 MakeValueListOrMove(term, nd_y, p_ref);
910 else
911 ThrowConsError(nd_y, p_ref);
912 }, y);
913 }
914
915 void
916 ConsImpl(TermNode& term)
917 {
918 RetainN(term, 2);
919
920 const auto i(std::next(term.begin(), 2));
921
922 ConsItem(term, *i);
923 term.erase(i);
924 RemoveHead(term);
925 }
927
928
930
931 YB_NORETURN ReductionStatus
932 ThrowForUnwrappingFailure(const ContextHandler& h)
933 {
934 throw TypeError(ystdex::sfmt("Unwrapping failed with type '%s'.",
935 h.target_type().name()));
936 }
937
938 ReductionStatus
939 UnwrapResolved(TermNode& term, ContextNode& ctx, FormContextHandler& fch,
940 ResolvedTermReferencePtr p_ref)
941 {
942 if(fch.Wrapping != 0)
943 {
944 return MakeValueOrMove(p_ref, [&]{
945 return ReduceForCombinerRef(term, ctx, NPL::Deref(p_ref),
946 fch.Handler, fch.Wrapping - 1);
947 }, [&]{
948 --fch.Wrapping;
949 term.Value = ContextHandler(std::move(fch));
950 return ReductionStatus::Clean;
951 });
952 }
953 throw TypeError("Unwrapping failed on an operative argument.");
954 }
955
956 template<typename _func, typename _func2>
957 ReductionStatus
958 DispatchContextHandler(ContextHandler& h, ResolvedTermReferencePtr p_ref,
959 _func f, _func2 f2)
960 {
961 if(const auto p = h.target<FormContextHandler>())
962 return f(*p, p_ref);
963 return ystdex::expand_proxy<ReductionStatus(ContextHandler&,
964 const ResolvedTermReferencePtr&)>::call(f2, h, p_ref);
965 }
966
967 template<typename _func, typename _func2>
968 ReductionStatus
969 WrapUnwrapResolve(TermNode& term, _func f, _func2 f2)
970 {
971 return NPL::ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
972 return DispatchContextHandler(
973 NPL::AccessRegular<ContextHandler>(nd, p_ref), p_ref, f, f2);
974 }, term);
975 }
977
978
980 #if false
981 template<typename... _tParams>
982 TermNode&
983 AddTrailingTemporary(TermNode& term, _tParams&&... args)
984 {
985 return *term.emplace(yforward(args)...);
986 }
987 #endif
988
990
991 // NOTE: The bound term can be reused later because no referent can be
992 // invalidated unless %mv writes %o.
993 template<typename _fMove>
994 void
995 BindMoveLocalObject(TermNode& o, _fMove mv)
996 {
997 // NOTE: Simplified from 'sigil == '&' and 'can_modify && temp' branch in
998 // %BindParameterObject::operator().
999 if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
1000 // NOTE: Reference collapsed by move.
1001 mv(std::move(o.GetContainerRef()),
1002 TermReference(BindReferenceTags(*p), std::move(*p)));
1003 else
1004 // NOTE: As %MarkTemporaryTerm in %NPLA1.
1005 (mv(std::move(o.GetContainerRef()),
1006 std::move(o.Value))).get().Tags |= TermTags::Temporary;
1007 }
1008
1009 void
1010 BindMoveLocalObjectInPlace(TermNode& o)
1011 {
1012 // NOTE: Simplified from 'sigil == '&' and 'can_modify && temp' branch in
1013 // %BindParameterObject::operator().
1014 if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
1015 // NOTE: Reference collapsed by move.
1016 p->SetTags(BindReferenceTags(*p));
1017 else
1018 // NOTE: As %MarkTemporaryTerm in %NPLA1.
1019 o.Tags |= TermTags::Temporary;
1020 }
1021
1022 void
1023 BindMoveNextNLocalSubobjectInPlace(TNIter i, size_t n)
1024 {
1025 while(n-- != 0)
1026 BindMoveLocalObjectInPlace(*++i);
1027 }
1028
1029 // NOTE: The bound term cannot be reused later because %o can be the referent.
1030 // Neither %o can be overwritten by %mv.
1031 template<typename _fMove>
1032 void
1033 BindLocalReference(TermTags o_tags, TermNode& o, _fMove mv,
1034 const EnvironmentReference& r_env)
1035 {
1036 // NOTE: Simplified from '&' and not 'can_modify && temp' branch in
1037 // %BindParameterObject::operator().
1038 mv(TermNode::Container(o.GetContainer()), [&]() -> TermReference{
1039 if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
1040 return TermReference(BindReferenceTags(*p), *p);
1041 return TermReference(GetLValueTagsOf(o.Tags | o_tags), o, r_env);
1042 }());
1043 }
1044
1045 YB_ATTR_nodiscard YB_ATTR(always_inline) inline TermNode
1046 EvaluateToLValueReference(TermNode& term, const shared_ptr<Environment>& p_env)
1047 {
1048 return NPL::AsTermNode(term.get_allocator(), EnsureLValueReference(
1049 TermReference(term.Tags, term, NPL::Nonnull(p_env))));
1050 }
1052
1053 #if false
1054 // NOTE: The bound term cannot be reused later because %term can be the
1055 // referent.
1057 YB_ATTR_nodiscard TermNode
1058 EvaluateBoundLValue(TermNode& term, const shared_ptr<Environment>& p_env)
1059 {
1060 if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
1061 return TermNode(std::allocator_arg, term.get_allocator(),
1062 term.GetContainer(), EnsureLValueReference(*p));
1063 return EvaluateToLValueReference(term, p_env);
1064 }
1065
1067
1068 // NOTE: The bound term cannot be reused later because %term can be the
1069 // referent.
1070 YB_ATTR_nodiscard TermNode
1071 EvaluateBoundLValueMoved(TermNode& term, const shared_ptr<Environment>& p_env)
1072 {
1073 if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
1074 {
1075 *p = EnsureLValueReference(std::move(*p));
1076 return std::move(term);
1077 }
1078 return EvaluateToLValueReference(term, p_env);
1079 }
1080 #endif
1081
1082 // NOTE: See %BindMoveLocalObjectInPlace and %EvaluateBoundLValue.
1084 YB_ATTR_nodiscard TermNode
1085 EvaluateLocalObject(TermNode& o, const shared_ptr<Environment>& p_env)
1086 {
1087 // NOTE: Make unique reference as bound temporary object.
1088 if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
1089 {
1090 p->SetTags(BindReferenceTags(*p));
1091 return TermNode(std::allocator_arg, o.get_allocator(),
1092 o.GetContainer(), EnsureLValueReference(*p));
1093 }
1094 o.Tags |= TermTags::Temporary;
1095 return EvaluateToLValueReference(o, p_env);
1096 }
1097
1098 // NOTE: See %BindMoveLocalObjectInPlace and %EvaluateBoundLValueMoved.
1099 YB_ATTR_nodiscard TermNode
1100 EvaluateLocalObjectMoved(TermNode& o, const shared_ptr<Environment>& p_env)
1101 {
1102 // NOTE: Make unique reference as bound temporary object.
1103 if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
1104 {
1105 // NOTE: See also %EnsureLValueReference.
1106 *p = TermReference(BindReferenceTags(*p) & ~TermTags::Unique,
1107 std::move(*p));
1108 return std::move(o);
1109 }
1110 o.Tags |= TermTags::Temporary;
1111 return EvaluateToLValueReference(o, p_env);
1112 }
1113
1114 void
1115 ForwardToUnwrapped(TermNode& comb, ContextNode& ctx)
1116 {
1117 using namespace std::placeholders;
1118
1119 RegularizeTerm(comb, WrapUnwrapResolve(comb, std::bind(UnwrapResolved,
1120 std::ref(comb), std::ref(ctx), _1, _2), ThrowForUnwrappingFailure));
1121 }
1122
1124
1125 // XXX: Preserving %con is better for performance, at least in code generation
1126 //`by x86_64-pc-linux G++ 10.2.
1127 YB_ATTR_nodiscard TermNode
1128 EvaluateBoundUnwrappedLValueDispatch(TermNode::allocator_type a,
1129 const TermNode::Container& con, TermReference ref, ContextNode& ctx,
1130 TermNode& nd)
1131 {
1132 auto& h(NPL::AccessRegular<ContextHandler>(nd, true));
1133
1134 if(const auto p = h.target<FormContextHandler>())
1135 {
1136 auto& fch(*p);
1137
1138 if(fch.Wrapping != 0)
1139 {
1140 TermNode term(std::allocator_arg, a, con);
1141
1142 ReduceForCombinerRef(term, ctx, ref, fch.Handler, fch.Wrapping - 1);
1143 return term;
1144 }
1145 throw TypeError("Unwrapping failed on an operative argument.");
1146 }
1147 ThrowForUnwrappingFailure(h);
1148 }
1149
1150 // NOTE: As %EvaluateBoundLValue and %ForwardToUnwrapped.
1151 YB_ATTR_nodiscard TermNode
1152 EvaluateBoundLValueUnwrapped(TermNode& term, ContextNode& ctx,
1153 const shared_ptr<Environment>& p_env)
1154 {
1155 if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
1156 return EvaluateBoundUnwrappedLValueDispatch(
1157 term.get_allocator(), term.GetContainer(), *p, ctx, p->get());
1158 return EvaluateBoundUnwrappedLValueDispatch(term.get_allocator(),
1159 {}, TermReference(term.Tags, term, NPL::Nonnull(p_env)), ctx, term);
1160 }
1162
1164
1165 // NOTE: As %ReduceSubsequent.
1166 // NOTE: This does not guarantee PTC.
1167 template<typename _fCurrent>
1168 ReductionStatus
1169 ReduceCallSubsequent(TermNode& term, ContextNode& ctx,
1170 shared_ptr<Environment> p_env, _fCurrent&& next)
1171 {
1172 using namespace std::placeholders;
1173
1174 // TODO: Blocked. Use C++14 lambda initializers to simplify the
1175 // implementation.
1176 return A1::ReduceCurrentNext(term, ctx,
1177 std::bind([](shared_ptr<Environment>& p_e, TermNode& t, ContextNode& c){
1178 #if true
1179 // NOTE: This does not rely on the existence of the %TCOAction, as it
1180 // will call %EnsureTCOAction. Since the call would rely on %TCOAction,
1181 // anyway, creating the TCO action here instead of a new action
1182 // to restore the environment is more efficient.
1183 SetupTailContext(c, t);
1184 return RelayCombinedTail(c, t, std::move(p_e));
1185 #else
1186 return RelayCombined(c, t, std::move(p_e));
1187 #endif
1188 }, std::move(p_env), _1, _2), yforward(next));
1189 }
1190
1191 #if false
1192 template<typename _fCurrent>
1194 ReductionStatus
1195 ReduceCallSubsequentTail(TermNode& term, ContextNode& ctx,
1196 shared_ptr<Environment> p_env, _fCurrent&& next)
1197 {
1198 using namespace std::placeholders;
1199
1200 // TODO: Blocked. Use C++14 lambda initializers to simplify the
1201 // implementation.
1202 return A1::ReduceCurrentNext(term, ctx,
1203 std::bind([](shared_ptr<Environment>& p_e, TermNode& t, ContextNode& c){
1204 // NOTE: This does not calls %EnsureTCOAction, so an %TCOAction shall be
1205 // already existed in the context.
1206 return RelayCombinedTail(c, t, std::move(p_e));
1207 }, std::move(p_env), _1, _2), yforward(next));
1208 }
1209 #endif
1210
1211
1213 template<typename _func>
1214 YB_FLATTEN ReductionStatus
1215 FirstOrVal(TermNode& term, _func f)
1216 {
1217 return CallResolvedUnary([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
1218 if(IsBranchedList(nd))
1219 return f(AccessFirstSubterm(nd), p_ref);
1220 ThrowInsufficientTermsError();
1221 }, term);
1222 }
1224
1226 void
1227 CheckResolvedListReference(TermNode& nd, bool has_ref)
1228 {
1229 if(has_ref)
1230 {
1231 if(YB_UNLIKELY(!IsBranchedList(nd)))
1232 throw ListTypeError(ystdex::sfmt(
1233 "Expected a non-empty list for the 1st argument, got '%s'.",
1234 TermToStringWithReferenceMark(nd, true).c_str()));
1235 }
1236 else
1237 ThrowValueCategoryErrorForFirstArgument(nd);
1238 }
1239
1241 template<typename _func>
1242 YB_FLATTEN ReductionStatus
1243 FirstAtRef(TermNode& term, _func f)
1244 {
1245 return CallResolvedUnary([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
1246 CheckResolvedListReference(nd, p_ref);
1247 // XXX: This should be safe, since the parent list is guaranteed an
1248 // lvalue by %CheckResolvedListReference.
1249 return f(term, AccessFirstSubterm(nd), p_ref);
1250 }, term);
1251 }
1252
1254 template<typename _func>
1255 void
1256 SetFirstRest(_func f, TermNode& term)
1257 {
1258 RetainN(term, 2);
1259
1260 auto i(term.begin());
1261
1262 ResolveTerm([&](TermNode& nd_x, bool has_ref){
1263 CheckResolvedListReference(nd_x, has_ref);
1264 return f(nd_x, *++i);
1265 }, *++i);
1266 term.Value = ValueToken::Unspecified;
1267 }
1268
1270 template<typename _func>
1271 void
1272 DoSetFirst(TermNode& term, _func f)
1273 {
1274 SetFirstRest([f](TermNode& nd_x, TermNode& y){
1275 auto& dst(AccessFirstSubterm(nd_x));
1276
1277 if(const auto p = NPL::TryAccessLeaf<TermReference>(y))
1278 f(dst, y, *p);
1279 else
1280 LiftTerm(dst, y);
1281 }, term);
1282 }
1283
1285 void
1286 LiftNoOp(TermNode&) ynothrow
1287 {}
1288
1290 void
1291 SetRestImpl(TermNode& term, void(&lift)(TermNode&))
1292 {
1293 SetFirstRest([&lift](TermNode& nd_x, TermNode& y){
1294 ResolveTerm([&](TermNode& nd_y, ResolvedTermReferencePtr p_ref_y){
1295 // XXX: How to simplify? Merge with %BindParameterObject?
1296 if(IsList(nd_y))
1297 {
1298 const auto a(nd_x.get_allocator());
1299 TermNode nd_new(std::allocator_arg, a, {TermNode(a)});
1300
1301 MakeValueListOrMove(nd_new, nd_y, p_ref_y);
1302 lift(nd_new);
1303 // XXX: The order is significant.
1304 AccessFirstSubterm(nd_new) = MoveFirstSubterm(nd_x);
1305 swap(nd_x, nd_new);
1306 }
1307 else
1308 throw ListTypeError(ystdex::sfmt("Expected a list for"
1309 " the 2nd argument, got '%s'.",
1310 TermToStringWithReferenceMark(nd_y, p_ref_y).c_str()));
1311 }, y);
1312 }, term);
1313 }
1314
1315
1317 pair<lref<Environment>, lref<const TokenValue>>
1318 CheckToUndefine(TermNode& term, ContextNode& ctx)
1319 {
1320 Retain(term);
1321 if(term.size() == 2)
1322 {
1323 const auto&
1324 n(NPL::ResolveRegular<const TokenValue>(*std::next(term.begin())));
1325
1326 if(IsNPLASymbol(n))
1327 {
1328 auto& env(ctx.GetRecordRef());
1329
1330 if(!env.Frozen)
1331 return {env, n};
1332 throw
1333 TypeError("Cannot remove a variable in a frozen environment.");
1334 }
1335 else
1336 ThrowInvalidSyntaxError(ystdex::sfmt("Invalid token '%s' found as"
1337 " name to be undefined.", n.c_str()));
1338 }
1339 else
1340 ThrowInvalidSyntaxError(
1341 "Expected exact one term as name to be undefined.");
1342 }
1343
1345 template<typename _func>
1346 inline auto
1347 CheckFunctionCreation(_func f) -> decltype(f())
1348 {
1349 TryRet(f())
1350 CatchExpr(..., std::throw_with_nested(MakeFunctionAbstractionError()))
1351 }
1352
1354
1355 template<typename _func>
1356 ReductionStatus
1357 CreateFunction(TermNode& term, _func f, size_t n)
1358 {
1359 Retain(term);
1360 if(term.size() > n)
1361 return f();
1362 ThrowInsufficientTermsErrorFor(MakeFunctionAbstractionError());
1363 }
1364
1365 ReductionStatus
1366 LambdaImpl(TermNode& term, ContextNode& ctx, bool no_lift)
1367 {
1368 return CreateFunction(term, [&, no_lift]{
1369 term.Value = CheckFunctionCreation([&]() -> ContextHandler{
1370 // NOTE: Protect the reference count of the environment at first.
1371 auto p_env(ctx.ShareRecord());
1372 auto i(term.begin());
1373 auto formals(ShareMoveTerm(NPL::Deref(++i)));
1374
1375 term.erase(term.begin(), ++i);
1376 // NOTE: The wrapping count 1 implies strict evaluation of arguments
1377 // in %FormContextHandler::operator().
1378 return FormContextHandler(VauHandler({},
1379 std::move(formals), std::move(p_env), {}, term, no_lift), 1);
1380 });
1381 return ReductionStatus::Clean;
1382 }, 1);
1383 }
1384
1386 ContextHandler
1387 CreateVau(TermNode& term, bool no_lift, TNIter i,
1388 shared_ptr<Environment>&& p_env, bool owning)
1389 {
1390 auto formals(ShareMoveTerm(NPL::Deref(++i)));
1391 auto eformal(CheckEnvFormal(NPL::Deref(++i)));
1392
1393 term.erase(term.begin(), ++i);
1394 return FormContextHandler(VauHandler(std::move(eformal), std::move(formals),
1395 std::move(p_env), owning, term, no_lift));
1396 }
1397
1398 ReductionStatus
1399 VauImpl(TermNode& term, ContextNode& ctx, bool no_lift)
1400 {
1401 return CreateFunction(term, [&, no_lift]{
1402 term.Value = CheckFunctionCreation([&]{
1403 return
1404 CreateVau(term, no_lift, term.begin(), ctx.ShareRecord(), {});
1405 });
1406 return ReductionStatus::Clean;
1407 }, 2);
1408 }
1409
1410 ReductionStatus
1411 VauWithEnvironmentImpl(TermNode& term, ContextNode& ctx, bool no_lift)
1412 {
1413 return CreateFunction(term, [&, no_lift]{
1414 auto i(term.begin());
1415 auto& tm(NPL::Deref(++i));
1416
1417 return ReduceSubsequent(tm, ctx,
1418 A1::NameTypedReducerHandler([&, i, no_lift]{
1419 term.Value = CheckFunctionCreation([&]{
1420 // XXX: List components are ignored.
1421 auto p_env_pr(ResolveEnvironment(tm));
1422
1423 return CreateVau(term, no_lift, i, std::move(p_env_pr.first),
1424 p_env_pr.second);
1425 });
1426 return ReductionStatus::Clean;
1427 }, "eval-vau"));
1428 }, 3);
1429 }
1431
1432
1434
1435 size_t
1436 AddWrapperCount(size_t n)
1437 {
1438 ++n;
1439 if(n != 0)
1440 return n;
1441 throw NPLException("Wrapping count overflow detected.");
1442 }
1443
1444 YB_NORETURN ReductionStatus
1445 ThrowForWrappingFailure(const ystdex::type_info& tp)
1446 {
1447 throw TypeError(ystdex::sfmt("Wrapping failed with type '%s'.", tp.name()));
1448 }
1449
1450 ReductionStatus
1451 WrapH(TermNode& term, ContextHandler h)
1452 {
1453 // XXX: Allocators are not used here for performance in most cases.
1454 term.Value = std::move(h);
1455 return ReductionStatus::Clean;
1456 }
1457
1458 ReductionStatus
1459 WrapN(TermNode& term, ContextNode&, ResolvedTermReferencePtr p_ref,
1460 FormContextHandler& fch, size_t n)
1461 {
1462 return WrapH(term, MakeValueOrMove(p_ref, [&]{
1463 return FormContextHandler(fch.Handler, n);
1464 }, [&]{
1465 return
1466 FormContextHandler(std::move(fch.Handler), n);
1467 }));
1468 }
1469
1470 ReductionStatus
1471 WrapRefN(TermNode& term, ContextNode& ctx, ResolvedTermReferencePtr p_ref,
1472 FormContextHandler& fch, size_t n)
1473 {
1474 if(p_ref)
1475 return ReduceForCombinerRef(term, ctx, *p_ref, fch.Handler, n);
1476 term.Value = ContextHandler(FormContextHandler(std::move(fch.Handler), n));
1477 return ReductionStatus::Clean;
1478 }
1479
1480 template<typename _func, typename _func2>
1481 YB_FLATTEN ReductionStatus
1482 WrapUnwrap(TermNode& term, _func f, _func2 f2)
1483 {
1484 return CallRegularUnaryAs<ContextHandler>(
1485 [&](ContextHandler& h, ResolvedTermReferencePtr p_ref){
1486 return DispatchContextHandler(h, p_ref, f, f2);
1487 }, term);
1488 }
1489
1490 template<typename _func>
1491 ReductionStatus
1492 WrapOrRef(TermNode& term, ContextNode& ctx, ReductionStatus
1493 (&fwrap)(TermNode&, ContextNode&, ResolvedTermReferencePtr,
1494 FormContextHandler&, size_t), _func f)
1495 {
1496 return WrapUnwrap(term,
1497 [&](FormContextHandler& fch, ResolvedTermReferencePtr p_ref){
1498 return fwrap(term, ctx, p_ref, fch, AddWrapperCount(fch.Wrapping));
1499 }, f);
1500 }
1501
1502 ReductionStatus
1503 WrapOnceOrOnceRef(TermNode& term, ContextNode& ctx, ReductionStatus
1504 (&fwrap)(TermNode&, ContextNode&, ResolvedTermReferencePtr,
1505 FormContextHandler&, size_t))
1506 {
1507 return WrapUnwrap(term,
1508 [&](FormContextHandler& fch, ResolvedTermReferencePtr p_ref){
1509 return fch.Wrapping == 0 ? fwrap(term, ctx, p_ref, fch, 1)
1510 : ThrowForWrappingFailure(
1511 ystdex::type_id<FormContextHandler>());
1512 }, [](const ContextHandler& h) YB_ATTR_LAMBDA(noreturn) -> ReductionStatus{
1513 ThrowForWrappingFailure(h.target_type());
1514 });
1515 }
1517
1518
1520
1521 class EncapsulationBase
1522 {
1523 private:
1524 // XXX: Is it possible to support %TermReference safety check here with
1525 // anchors?
1526 // TODO: Add naming scheme and persistence interoperations?
1527 shared_ptr<void> p_type;
1528
1529 public:
1531 EncapsulationBase(shared_ptr<void> p) ynothrow
1532 : p_type(std::move(p))
1533 {}
1534 DefDeCopyMoveCtorAssignment(EncapsulationBase)
1535
1536 YB_ATTR_nodiscard YB_PURE friend PDefHOp(bool, ==,
1537 const EncapsulationBase& x, const EncapsulationBase& y) ynothrow
1538 ImplRet(x.p_type == y.p_type)
1539
1540 DefGetter(const ynothrow, const EncapsulationBase&, , *this)
1541 DefGetter(ynothrow, EncapsulationBase&, Ref, *this)
1542 DefGetter(const ynothrow, const shared_ptr<void>&, Type, p_type)
1543 };
1544
1545
1546 class Encapsulation final : private EncapsulationBase
1547 {
1548 public:
1549 mutable TermNode TermRef;
1550
1551 Encapsulation(shared_ptr<void> p, TermNode term)
1552 : EncapsulationBase(std::move(p)), TermRef(std::move(term))
1553 {}
1554 DefDeCopyMoveCtorAssignment(Encapsulation)
1555
1556 YB_ATTR_nodiscard YB_PURE friend PDefHOp(bool, ==,
1557 const Encapsulation& x, const Encapsulation& y) ynothrow
1558 ImplRet(x.Get() == y.Get())
1559
1560 using EncapsulationBase::Get;
1561 using EncapsulationBase::GetType;
1562 };
1563
1564
1565 class Encapsulate final : private EncapsulationBase
1566 {
1567 public:
1568 Encapsulate(shared_ptr<void> p)
1569 : EncapsulationBase(std::move(p))
1570 {}
1571 DefDeCopyMoveCtorAssignment(Encapsulate)
1572
1573 YB_ATTR_nodiscard YB_PURE friend PDefHOp(bool, ==,
1574 const Encapsulate& x, const Encapsulate& y) ynothrow
1575 ImplRet(x.Get() == y.Get())
1576
1577 void
1578 operator()(TermNode& term) const
1579 {
1580 CallUnary([this](TermNode& tm) YB_PURE{
1581 return Encapsulation(GetType(), ystdex::invoke_value_or(
1582 &TermReference::get, NPL::TryAccessReferencedLeaf<
1583 const TermReference>(tm), std::move(tm)));
1584 }, term);
1585 }
1586 };
1587
1588
1589 class Encapsulated final : private EncapsulationBase
1590 {
1591 public:
1592 Encapsulated(shared_ptr<void> p)
1593 : EncapsulationBase(std::move(p))
1594 {}
1595 DefDeCopyMoveCtorAssignment(Encapsulated)
1596
1597 YB_ATTR_nodiscard YB_PURE friend
1598 PDefHOp(bool, ==, const Encapsulated& x, const Encapsulated& y) ynothrow
1599 ImplRet(x.Get() == y.Get())
1600
1601 void
1602 operator()(TermNode& term) const
1603 {
1604 CallUnary([this](TermNode& tm) YB_ATTR_LAMBDA(pure) -> bool{
1605 return ystdex::call_value_or([this](const Encapsulation& enc)
1606 YB_ATTR_LAMBDA_QUAL(ynothrow, YB_PURE){
1607 return Get() == enc.Get();
1608 }, NPL::TryAccessReferencedTerm<Encapsulation>(tm));
1609 }, term);
1610 }
1611 };
1612
1613
1614 class Decapsulate final : private EncapsulationBase
1615 {
1616 public:
1617 Decapsulate(shared_ptr<void> p)
1618 : EncapsulationBase(std::move(p))
1619 {}
1620 DefDeCopyMoveCtorAssignment(Decapsulate)
1621
1622 YB_ATTR_nodiscard YB_PURE friend
1623 PDefHOp(bool, ==, const Decapsulate& x, const Decapsulate& y) ynothrow
1624 ImplRet(x.Get() == y.Get())
1625
1626
1627 ReductionStatus
1628 operator()(TermNode& term, ContextNode& ctx) const
1629 {
1630 return CallRegularUnaryAs<const Encapsulation>(
1631 [&](const Encapsulation& enc, ResolvedTermReferencePtr p_ref){
1632 if(Get() == enc.Get())
1633 {
1634 auto& tm(enc.TermRef);
1635
1636 return MakeValueOrMove(p_ref, [&]() -> ReductionStatus{
1637 // NOTE: As an lvalue reference, the object in %tm cannot be
1638 // destroyed.
1639 if(const auto p
1640 = NPL::TryAccessLeaf<const TermReference>(tm))
1641 term.SetContent(tm.GetContainer(), *p);
1642 else
1643 {
1644 // XXX: Subterms cleanup is deferred.
1645 // XXX: Allocators are not used here for performance in
1646 // most cases.
1647 term.Value = TermReference(tm,
1648 FetchTailEnvironmentReference(*p_ref, ctx));
1649 return ReductionStatus::Clean;
1650 }
1651 return ReductionStatus::Retained;
1652 }, [&]{
1653 LiftTerm(term, tm);
1654 return ReductionStatus::Retained;
1655 });
1656 }
1657 throw TypeError("Mismatched encapsulation type found.");
1658 }, term);
1659 }
1660 };
1662
1663
1665 ReductionStatus
1666 ApplyImpl(TermNode& term, ContextNode& ctx, shared_ptr<Environment> p_env)
1667 {
1668 auto i(term.begin());
1669 auto& comb(NPL::Deref(++i));
1670
1671 ForwardToUnwrapped(comb, ctx);
1672
1673 TermNode expr(std::allocator_arg, term.get_allocator(), {std::move(comb)});
1674
1675 ConsItem(expr, NPL::Deref(++i));
1676 term = std::move(expr);
1677 return RelayCombinedTail(ctx, term, std::move(p_env));
1678 }
1679
1681 void
1682 ListAsteriskImpl(TermNode& term)
1683 {
1684 Retain(term);
1685
1686 auto i(std::next(term.begin()));
1687
1688 if(i != term.end())
1689 {
1690 auto& head(NPL::Deref(i));
1691
1692 if(++i != term.end())
1693 {
1694 const auto last(std::prev(term.end()));
1695
1696 ConsItem(term, Deref(last));
1697 term.erase(last),
1698 RemoveHead(term);
1699 }
1700 else
1701 LiftOther(term, head);
1702 }
1703 else
1704 ThrowInsufficientTermsError();
1705 }
1706
1708
1709 template<typename _func>
1710 YB_FLATTEN ReductionStatus
1711 AccImpl(_func f, TermNode& term, ContextNode& ctx)
1712 {
1713 YAssert(FetchArgumentN(term) == 8, "Invalid recursive call found.");
1714
1715 auto i(term.begin());
1716 auto& l(*++i);
1717 auto& pred(*++i);
1718 const auto& d(ctx.GetRecordPtr());
1719 auto lv_pred(EvaluateBoundLValueUnwrapped(pred, ctx, d));
1720 auto& con(term.GetContainerRef());
1721 auto& nterm(con.back());
1722 auto& lv_l(*++con.rbegin());
1723
1724 lv_l = EvaluateLocalObject(l, d);
1725 nterm
1726 = TermNode::Container({std::move(lv_pred), lv_l}, term.get_allocator());
1727 // TODO: Blocked. Use C++14 lambda initializers to simplify the
1728 // implementation.
1729 return ReduceCallSubsequent(nterm, ctx, d, A1::NameTypedReducerHandler(
1730 std::bind([&, d, f](TNIter& i_0) -> ReductionStatus{
1731 auto& base(*++i_0);
1732
1733 if(!ExtractBool(nterm))
1734 {
1735 auto& head(*++i_0);
1736 auto lv_head(EvaluateBoundLValueUnwrapped(head, ctx, d));
1737
1738 nterm.GetContainerRef() = {std::move(lv_head), lv_l};
1739 nterm.Value.Clear();
1740 return ReduceCallSubsequent(nterm, ctx, d,
1741 A1::NameTypedReducerHandler(
1742 std::bind([&, d, f](TNIter& i_1){
1743 return f(l, base, lv_l, nterm, d, i_1);
1744 }, std::move(i_0)), "eval-acc-head-next"));
1745 }
1746 else
1747 {
1748 LiftOther(term, base);
1749 return ReductionStatus::Retained;
1750 }
1751 }, std::move(i)), "eval-acc-nested"));
1752 }
1753
1754 YB_FLATTEN ReductionStatus
1755 AccLImpl(TermNode& term, ContextNode& ctx)
1756 {
1757 return AccImpl([&](TermNode& l, TermNode& base, TermNode& lv_l, TermNode&
1758 nterm, const shared_ptr<Environment>& d, TNIter& i) YB_FLATTEN{
1759 auto& tail(*++i);
1760 auto lv_sum(EvaluateBoundLValueUnwrapped(*++i, ctx, d));
1761
1762 base.GetContainerRef() = TermNode::Container({std::move(lv_sum),
1763 std::move(nterm), std::move(base)}, term.get_allocator());
1764 return ReduceCallSubsequent(base, ctx, d,
1765 A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
1766 auto lv_tail(EvaluateBoundLValueUnwrapped(tail, ctx, d));
1767
1768 nterm.GetContainerRef() = {std::move(lv_tail), std::move(lv_l)};
1769 return ReduceCallSubsequent(nterm, ctx, d,
1770 A1::NameTypedReducerHandler([&]() YB_FLATTEN{
1771 l = std::move(nterm);
1772 return AccLImpl(term, ctx);
1773 }, "eval-accl-accl"));
1774 }, "eval-accl-tail"));
1775 }, term, ctx);
1776 }
1777
1778 YB_FLATTEN ReductionStatus
1779 AccRImpl(TermNode& term, ContextNode& ctx, TermNode& sum)
1780 {
1781 return AccImpl([&](TermNode& l, TermNode&, TermNode& lv_l, TermNode& nterm,
1782 const shared_ptr<Environment>& d, TNIter& i) YB_FLATTEN{
1783 auto& con(term.GetContainerRef());
1784 const auto a(term.get_allocator());
1785 auto& n2term(*std::next(con.rbegin(), 2));
1786 auto lv_tail(EvaluateBoundLValueUnwrapped(*++i, ctx, d));
1787
1788 n2term.GetContainerRef()
1789 = TermNode::Container({std::move(lv_tail), std::move(lv_l)}, a);
1790 return ReduceCallSubsequent(n2term, ctx, d,
1791 A1::NameTypedReducerHandler([&, a, d]() YB_FLATTEN{
1792 l = std::move(n2term);
1793
1794 auto lv_sum(EvaluateBoundLValueUnwrapped(sum, ctx, d));
1795 auto& rterm(*term.emplace(ystdex::exchange(con, TermNode::Container(
1796 {std::move(lv_sum), std::move(nterm)}, a))));
1797
1798 RelaySwitched(ctx, A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
1799 SetupTailContext(ctx, term);
1800 return RelayCombinedTail(ctx, term, d);
1801 }, "eval-accr-sum"));
1802 return AccRImpl(rterm, ctx, sum);
1803 }, "eval-accr-accr"));
1804 }, term, ctx);
1805 }
1807
1809
1810 void
1811 LiftFirst(TermNode& term, TermNode& tm, bool move)
1812 {
1813 if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
1814 {
1815 if(!p->IsReferencedLValue())
1816 {
1817 LiftMovedOther(term, *p, p->IsMovable());
1818 return;
1819 }
1820 }
1821 // XXX: Term tags are currently not respected in prvalues.
1822 LiftOtherOrCopy(term, tm, move);
1823 }
1824
1825 YB_FLATTEN TermNode&
1826 FoldRMap1Impl(TermNode& term, TermNode& nd, ResolvedTermReferencePtr p_ref,
1827 TermNode& l)
1828 {
1829 auto& con(term.GetContainerRef());
1830 auto& nterm(con.back());
1831 if(IsBranchedList(nd))
1832 {
1833 auto& tm_first(AccessFirstSubterm(nd));
1834
1835 YAssert(nterm.empty(), "Invalid term found.");
1836 if(NPL::Deref(p_ref).IsReferencedLValue())
1837 {
1838 if(const auto p
1839 = NPL::TryAccessLeaf<const TermReference>(tm_first))
1840 nterm.SetContent(tm_first);
1841 else
1842 ReduceToReferenceAt(nterm, tm_first, p_ref);
1843
1844 const auto a(nd.get_allocator());
1845 TermNode::Container ncon(a);
1846 auto j(nd.begin());
1847
1848 while(++j != nd.end())
1849 {
1850 auto& tm(*j);
1851
1852 if(IsReferenceTerm(tm))
1853 ncon.emplace_back(tm);
1854 else
1855 // XXX: Same to %ReduceToReferenceAt.
1856 ncon.emplace_back(NPL::AsTermNode(TermReference(
1857 tm.Tags, tm,
1858 NPL::Deref(p_ref).GetEnvironmentReference())));
1859 }
1860 l.Value.Clear();
1861 l.GetContainerRef() = std::move(ncon);
1862 }
1863 else
1864 {
1865 LiftFirst(nterm, tm_first, !p_ref || p_ref->IsModifiable());
1866 nd.GetContainerRef().pop_front();
1867 }
1868 return nterm;
1869 }
1870 else
1871 ThrowInsufficientTermsError();
1872 }
1873
1874 YB_FLATTEN ReductionStatus
1875 FoldR1Impl(TermNode& term, ContextNode& ctx, TermNode& kons)
1876 {
1877 YAssert(FetchArgumentN(term) == 4, "Invalid recursive call found.");
1878
1879 auto i(term.begin());
1880 auto& knil(*++(++i));
1881 auto& l(*++i);
1882 const auto& d(ctx.GetRecordPtr());
1883 auto lv_l(EvaluateLocalObject(l, d));
1884
1885 // XXX: Keep %lv_l is a slightly more efficient.
1886 return NPL::ResolveTerm(
1887 [&, d](TermNode& nd, ResolvedTermReferencePtr p_ref) -> ReductionStatus{
1888 if(!IsEmpty(nd))
1889 {
1890 auto& nterm(FoldRMap1Impl(term, nd, p_ref, l));
1891 auto lv_kons(EvaluateBoundLValueUnwrapped(kons, ctx, d));
1892 auto& rterm(*term.emplace(ystdex::exchange(term.GetContainerRef(),
1893 TermNode::Container({std::move(lv_kons), std::move(nterm)},
1894 term.get_allocator()))));
1895
1896 RelaySwitched(ctx, A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
1897 SetupTailContext(ctx, term);
1898 return RelayCombinedTail(ctx, term, d);
1899 }, "eval-foldr1-kons"));
1900 nterm.ClearContainer();
1901 return RelaySwitched(ctx, [&]{
1902 return FoldR1Impl(rterm, ctx, kons);
1903 });
1904 }
1905 LiftOther(term, knil);
1906 return ReductionStatus::Retained;
1907 }, lv_l);
1908 }
1909
1910 YB_FLATTEN ReductionStatus
1911 Map1Impl(TermNode& term, ContextNode& ctx, TermNode& appv)
1912 {
1913 YAssert(FetchArgumentN(term) == 3, "Invalid recursive call found.");
1914
1915 auto i(term.begin());
1916 auto& l(*++(++i));
1917 const auto& d(ctx.GetRecordPtr());
1918 auto lv_l(EvaluateLocalObject(l, d));
1919
1920 // XXX: Keep %lv_l is a slightly more efficient.
1921 return NPL::ResolveTerm(
1922 [&, d](TermNode& nd, ResolvedTermReferencePtr p_ref) -> ReductionStatus{
1923 if(!IsEmpty(nd))
1924 {
1925 auto& nterm(FoldRMap1Impl(term, nd, p_ref, l));
1926 auto lv_appv(EvaluateBoundLValueUnwrapped(appv, ctx, d));
1927 const auto a(term.get_allocator());
1928 auto& rterm(*term.emplace(ystdex::exchange(term.GetContainerRef(),
1929 TermNode::Container({TermNode({std::move(lv_appv),
1930 std::move(nterm)}, a)}, a))));
1931
1932 RelaySwitched(ctx, A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
1933 return ReduceCallSubsequent(*term.begin(), ctx, d,
1934 A1::NameTypedReducerHandler([&]() YB_FLATTEN{
1935 auto i_term(term.begin());
1936
1937 ConsItem(term, NPL::Deref(++i_term));
1938 term.erase(i_term);
1939 return ReductionStatus::Retained;
1940 }, "eval-map1-cons"));
1941 }, "eval-map1-appv"));
1942 nterm.ClearContainer();
1943 return RelaySwitched(ctx, [&]{
1944 return Map1Impl(rterm, ctx, appv);
1945 });
1946 }
1947 term.Clear();
1948 return ReductionStatus::Regular;
1949 }, lv_l);
1950 }
1951
1952 YB_FLATTEN void
1953 AccFoldR1(TermNode& term, ContextNode& ctx, TermNode& rterm, ptrdiff_t n)
1954 {
1955 auto& sum(*std::next(rterm.begin(), n));
1956
1957 term.emplace(std::move(sum));
1958 sum.Value.Clear();
1959 rterm.GetContainerRef().emplace_back();
1960 RelaySwitched(ctx, [&]{
1961 LiftOther(term, rterm);
1962 return ctx.LastStatus;
1963 });
1964 }
1965
1966 template<typename _func>
1967 YB_FLATTEN ReductionStatus
1968 DoFoldRMap1(TermNode& term, ContextNode& ctx, _func f)
1969 {
1970 auto& con(term.GetContainerRef());
1971 auto& rterm(*term.emplace(ystdex::exchange(con,
1972 TermNode::Container(term.get_allocator()))));
1973
1974 AccFoldR1(term, ctx, rterm, 1);
1975 return f(rterm, ctx, con.back());
1976 }
1978
1979 } // unnamed namespace;
1980
1981
1982 namespace Forms
1983 {
1984
1985 bool
1986 IsSymbol(const string& id) ynothrow
1987 {
1988 return IsNPLASymbol(id);
1989 }
1990
1991 TokenValue
1992 StringToSymbol(const string& s)
1993 {
1994 // XXX: Allocators are not used here for performance in most cases.
1995 return TokenValue(s);
1996 }
1997 TokenValue
1998 StringToSymbol(string&& s)
1999 {
2000 // XXX: Ditto.
2001 return TokenValue(std::move(s));
2002 }
2003
2004 const string&
2005 SymbolToString(const TokenValue& s) ynothrow
2006 {
2007 return s;
2008 }
2009
2010 size_t
2011 RetainN(const TermNode& term, size_t m)
2012 {
2013 const auto n(FetchArgumentN(term));
2014
2015 if(n == m)
2016 return n;
2017 throw ArityMismatch(m, n);
2018 }
2019
2020
2021 void
2022 Equal(TermNode& term)
2023 {
2024 EqualTermReference(term, YSLib::HoldSame);
2025 }
2026
2027 void
2028 EqualLeaf(TermNode& term)
2029 {
2030 EqualTermValue(term, ystdex::equal_to<>());
2031 }
2032
2033 void
2034 EqualReference(TermNode& term)
2035 {
2036 EqualTermValue(term, YSLib::HoldSame);
2037 }
2038
2039 void
2040 EqualValue(TermNode& term)
2041 {
2042 EqualTermReference(term, ystdex::equal_to<>());
2043 }
2044
2045
2046 ReductionStatus
2047 If(TermNode& term, ContextNode& ctx)
2048 {
2049 Retain(term);
2050
2051 const auto size(term.size());
2052
2053 if(size == 3 || size == 4)
2054 {
2055 auto i(std::next(term.begin()));
2056
2057 // XXX: Use captured %ctx seems more efficient here.
2058 return ReduceSubsequent(*i, ctx, A1::NameTypedReducerHandler([&, i]{
2059 auto j(i);
2060
2061 if(!ExtractBool(*j))
2062 ++j;
2063 return ++j != term.end() ? ReduceOnceLifted(term, ctx, *j)
2064 : ReduceReturnUnspecified(term);
2065 }, "select-clause"));
2066 }
2067 else
2068 ThrowInvalidSyntaxError("Syntax error in conditional form.");
2069 }
2070
2071 ReductionStatus
2072 Cond(TermNode& term, ContextNode& ctx)
2073 {
2074 Retain(term);
2075 RemoveHead(term);
2076 #if NPL_Impl_NPLA1_Enable_Thunked
2077 return CondImpl(term, ctx, term.begin());
2078 #else
2079 for(auto i(term.begin()); i != term.end(); ++i)
2080 {
2081 auto& clause(Deref(i));
2082 auto j(CondClauseCheck(clause));
2083
2084 ReduceOnce(Deref(j), ctx);
2085 if(CondTest(clause, j))
2086 return ReduceOnceLifted(term, ctx, clause);
2087 }
2088 return ReduceReturnUnspecified(term);
2089 #endif
2090 }
2091
2092 ReductionStatus
2093 When(TermNode& term, ContextNode& ctx)
2094 {
2095 return WhenUnless(term, ctx, true);
2096 }
2097
2098 ReductionStatus
2099 Unless(TermNode& term, ContextNode& ctx)
2100 {
2101 return WhenUnless(term, ctx, {});
2102 }
2103
2104 bool
2105 Not(TermNode& term)
2106 {
2107 auto& tm(NPL::ReferenceTerm(term));
2108
2109 return IsLeaf(tm) && tm.Value == false;
2110 }
2111
2112 ReductionStatus
2113 And(TermNode& term, ContextNode& ctx)
2114 {
2115 return AndOr(term, ctx, And2);
2116 }
2117
2118 ReductionStatus
2119 Or(TermNode& term, ContextNode& ctx)
2120 {
2121 return AndOr(term, ctx, Or2);
2122 }
2123
2124
2125 ReductionStatus
2126 Cons(TermNode& term)
2127 {
2128 ConsImpl(term);
2129 LiftSubtermsToReturn(term);
2130 return ReductionStatus::Retained;
2131 }
2132
2133 ReductionStatus
2134 ConsRef(TermNode& term)
2135 {
2136 ConsImpl(term);
2137 return ReductionStatus::Retained;
2138 }
2139
2140 ReductionStatus
2141 ForwardListFirst(TermNode& term, ContextNode& ctx)
2142 {
2143 RetainN(term, 3);
2144
2145 auto i(term.begin());
2146 auto& op(*i);
2147 const auto i_list_app(++i);
2148 auto& app(*++i);
2149 auto& l(*++i);
2150 const auto a(term.get_allocator());
2151 const auto& d(ctx.GetRecordPtr());
2152 TermNode::Container con({EvaluateLocalObjectMoved(l, d)}, a);
2153
2154 ForwardToUnwrapped(*i_list_app, ctx);
2155 con.splice(con.cbegin(), term.GetContainerRef(), i_list_app);
2156 op = TermNode(std::allocator_arg, a, std::move(con));
2157 // TODO: Blocked. Use C++14 lambda initializers to simplify the
2158 // implementation.
2159 return ReduceCallSubsequent(op, ctx, d, A1::NameTypedReducerHandler(
2160 std::bind([&, d](shared_ptr<Environment>& p_e0) YB_FLATTEN{
2161 return NPL::ResolveTerm(
2162 [&](TermNode& nd, ResolvedTermReferencePtr p_ref) YB_FLATTEN{
2163 if(IsBranchedList(nd))
2164 {
2165 const auto assign_term(
2166 [&](TermNode::Container&& c, ValueObject&& vo) YB_FLATTEN{
2167 // XXX: The term %l is reused as a shared bound operand as
2168 // the referent.
2169 l = TermNode(std::allocator_arg, term.get_allocator(),
2170 std::move(c), std::move(vo));
2171 return std::ref(l);
2172 });
2173 auto& x(AccessFirstSubterm(nd));
2174
2175 if(p_ref)
2176 BindLocalReference(p_ref->GetTags()
2177 & (TermTags::Unique | TermTags::Nonmodifying), x,
2178 assign_term, p_ref->GetEnvironmentReference());
2179 else
2180 BindMoveLocalObject(x, assign_term);
2181 ForwardToUnwrapped(app, ctx);
2182 #if true
2183 // XXX: This is more efficient.
2184 term.GetContainerRef() = {std::move(app), std::move(l)};
2185 #else
2186 term.GetContainerRef().pop_front();
2187 #endif
2188 return RelayCombinedTail(ctx, term, std::move(p_e0));
2189 }
2190 else
2191 ThrowInsufficientTermsError();
2192 }, op);
2193 }, d), "eval-forward-list-first"));
2194 }
2195
2196 ReductionStatus
2197 First(TermNode& term)
2198 {
2199 return FirstOrVal(term,
2200 [&](TermNode& tm, ResolvedTermReferencePtr p_ref) -> ReductionStatus{
2201 #if true
2202 // XXX: This is verbose but likely more efficient with %YB_FLATTEN.
2203 const bool list_not_move(p_ref && p_ref->IsReferencedLValue());
2204
2205 if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
2206 {
2207 if(list_not_move)
2208 {
2209 term.SetContent(tm);
2210 return ReductionStatus::Retained;
2211 }
2212 if(!p->IsReferencedLValue())
2213 {
2214 LiftMovedOther(term, *p, p->IsMovable());
2215 return ReductionStatus::Retained;
2216 }
2217 }
2218 else if(list_not_move)
2219 return ReduceToReferenceAt(term, tm, p_ref);
2220 // XXX: Term tags are currently not respected in prvalues.
2221 LiftOtherOrCopy(term, tm, !p_ref || p_ref->IsModifiable());
2222 return ReductionStatus::Retained;
2223 #else
2224 // NOTE: For exposition only. The optimized implemenation shall be
2225 // equivalent to this.
2226 // XXX: This should be safe, since the parent list is guaranteed an
2227 // lvalue by the false result of the call to %NPL::IsMovable.
2228 if(!(p_ref && p_ref->IsReferencedLValue()))
2229 {
2230 if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
2231 {
2232 if(!p->IsReferencedLValue())
2233 {
2234 LiftMovedOther(term, *p, p->IsMovable());
2235 return ReductionStatus::Retained;
2236 }
2237 }
2238 // XXX: Term tags are currently not respected in prvalues.
2239 LiftOtherOrCopy(term, tm, !p_ref || p_ref->IsModifiable());
2240 return ReductionStatus::Retained;
2241 }
2242 return ReduceToReference(term, tm, p_ref);
2243 #endif
2244 });
2245 }
2246
2247 ReductionStatus
2248 FirstAt(TermNode& term)
2249 {
2250 return FirstAtRef(term, ReduceToReferenceAt);
2251 }
2252
2253 ReductionStatus
2254 FirstRef(TermNode& term)
2255 {
2256 return FirstAtRef(term, ReduceToReference);
2257 }
2258
2259 ReductionStatus
2260 FirstVal(TermNode& term)
2261 {
2262 return FirstOrVal(term, [&](TermNode& tm, bool has_ref){
2263 // XXX: Simple 'ReduceToValue(term, tm)' is wrong because it may
2264 // move non-unqiue reference object away.
2265 if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
2266 LiftMovedOther(term, *p, !has_ref && p->IsMovable());
2267 else
2268 // XXX: Term tags are currently not respected in prvalues.
2269 LiftOtherOrCopy(term, tm, !has_ref);
2270 return ReductionStatus::Retained;
2271 });
2272 }
2273
2274 void
2275 SetFirst(TermNode& term)
2276 {
2277 DoSetFirst(term, [](TermNode& dst, TermNode&, const TermReference& ref){
2278 LiftMovedOther(dst, ref, ref.IsMovable());
2279 });
2280 }
2281
2282 void
2283 SetFirstAt(TermNode& term)
2284 {
2285 DoSetFirst(term, [](TermNode& dst, TermNode& y, const TermReference&){
2286 LiftOther(dst, y);
2287 });
2288 }
2289
2290 void
2291 SetFirstRef(TermNode& term)
2292 {
2293 DoSetFirst(term, [](TermNode& dst, TermNode& y, TermReference& ref){
2294 // XXX: No cyclic reference check except for self assignment.
2295 LiftCollapsed(dst, y, std::move(ref));
2296 });
2297 }
2298
2299 void
2300 SetRest(TermNode& term)
2301 {
2302 SetRestImpl(term, LiftSubtermsToReturn);
2303 }
2304
2305 void
2306 SetRestRef(TermNode& term)
2307 {
2308 SetRestImpl(term, LiftNoOp);
2309 }
2310
2311
2312 ReductionStatus
2313 Eval(TermNode& term, ContextNode& ctx)
2314 {
2315 return EvalImpl(term, ctx, {});
2316 }
2317
2318 ReductionStatus
2319 EvalRef(TermNode& term, ContextNode& ctx)
2320 {
2321 return EvalImpl(term, ctx, true);
2322 }
2323
2324 ReductionStatus
2325 EvalString(TermNode& term, ContextNode& ctx)
2326 {
2327 return EvalStringImpl(term, ctx, {});
2328 }
2329
2330 ReductionStatus
2331 EvalStringRef(TermNode& term, ContextNode& ctx)
2332 {
2333 return EvalStringImpl(term, ctx, true);
2334 }
2335
2336 ReductionStatus
2337 EvalUnit(TermNode& term)
2338 {
2339 CallBinaryAs<const string, REPLContext>(
2340 [&](const string& unit, REPLContext& rctx){
2341 term.SetContent(rctx.Perform(unit));
2342 }, term);
2343 return ReductionStatus::Retained;
2344 }
2345
2346
2347 void
2348 MakeEnvironment(TermNode& term)
2349 {
2350 Retain(term);
2351
2352 const auto a(term.get_allocator());
2353
2354 if(term.size() > 1)
2355 {
2356 const auto tr([&](TNIter iter){
2357 return ystdex::make_transform(iter, [&](TNIter i) -> ValueObject{
2358 // XXX: Like %LiftToReturn, but for %Value only.
2359 if(const auto p = NPL::TryAccessLeaf<const TermReference>(*i))
2360 {
2361 if(!p->IsMovable())
2362 return p->get().Value;
2363 return std::move(p->get().Value);
2364 }
2365 return std::move(i->Value);
2366 });
2367 });
2368 #if true
2369 // XXX: This is slightly more efficient.
2370 ValueObject parent;
2371
2372 parent.emplace<EnvironmentList>(tr(std::next(term.begin())),
2373 tr(term.end()), a);
2374 term.Value = NPL::AllocateEnvironment(a, std::move(parent));
2375 #else
2376 term.Value = NPL::AllocateEnvironment(a, ValueObject(std::allocator_arg,
2377 a, in_place_type<EnvironmentList>, tr(std::next(term.begin())),
2378 tr(term.end()), a));
2379 #endif
2380 }
2381 else
2382 term.Value = NPL::AllocateEnvironment(a);
2383 }
2384
2385 void
2386 GetCurrentEnvironment(TermNode& term, ContextNode& ctx)
2387 {
2388 RetainN(term, 0);
2389 term.Value = ValueObject(ctx.WeakenRecord());
2390 }
2391
2392 void
2393 LockCurrentEnvironment(TermNode& term, ContextNode& ctx)
2394 {
2395 RetainN(term, 0);
2396 term.Value = ValueObject(ctx.ShareRecord());
2397 }
2398
2399 ReductionStatus
2400 ValueOf(TermNode& term, const ContextNode& ctx)
2401 {
2402 RetainN(term);
2403 if(const auto p_id = NPL::TryAccessTerm<const string>(
2404 ReferenceTerm(*std::next(term.begin()))))
2405 {
2406 // XXX: This is needed since %EvaluateIdentifier assumes regularized
2407 // term and it would not return %ReductionStatus::Clean to ensure
2408 // additional regularzation.
2409 term.ClearContainer();
2410 TryRet(EvaluateIdentifier(term, ctx, *p_id))
2411 CatchIgnore(BadIdentifier&)
2412 }
2413 term.Value = ValueToken::Null;
2414 return ReductionStatus::Clean;
2415 }
2416
2417
2418 ReductionStatus
2419 DefineLazy(TermNode& term, ContextNode& ctx)
2420 {
2421 DoDefine(term, std::bind(BindParameterChecked, ctx.GetRecordPtr(),
2422 std::placeholders::_1, std::ref(term)));
2423 return ReduceReturnUnspecified(term);
2424 }
2425
2426 ReductionStatus
2427 DefineWithNoRecursion(TermNode& term, ContextNode& ctx)
2428 {
2429 return DoDefine(term, DefineOrSetDispatcher<>{term, ctx});
2430 }
2431
2432 ReductionStatus
2433 DefineWithRecursion(TermNode& term, ContextNode& ctx)
2434 {
2435 return DoDefine(term, DefineOrSetDispatcher<true>{term, ctx});
2436 }
2437
2438 ReductionStatus
2439 SetWithNoRecursion(TermNode& term, ContextNode& ctx)
2440 {
2441 return DoSet(term, ctx, DefineOrSetDispatcher<>{term, ctx});
2442 }
2443
2444 ReductionStatus
2445 SetWithRecursion(TermNode& term, ContextNode& ctx)
2446 {
2447 return DoSet(term, ctx, DefineOrSetDispatcher<true>{term, ctx});
2448 }
2449
2450 void
2451 Undefine(TermNode& term, ContextNode& ctx)
2452 {
2453 const auto pr(CheckToUndefine(term, ctx));
2454
2455 term.Value = pr.first.get().Remove(pr.second.get());
2456 }
2457
2458 void
2459 UndefineChecked(TermNode& term, ContextNode& ctx)
2460 {
2461 const auto pr(CheckToUndefine(term, ctx));
2462
2463 pr.first.get().RemoveChecked(pr.second.get());
2464 }
2465
2466
2467 ReductionStatus
2468 Lambda(TermNode& term, ContextNode& ctx)
2469 {
2470 return LambdaImpl(term, ctx, {});
2471 }
2472
2473 ReductionStatus
2474 LambdaRef(TermNode& term, ContextNode& ctx)
2475 {
2476 return LambdaImpl(term, ctx, true);
2477 }
2478
2479 ReductionStatus
2480 Vau(TermNode& term, ContextNode& ctx)
2481 {
2482 return VauImpl(term, ctx, {});
2483 }
2484
2485 ReductionStatus
2486 VauRef(TermNode& term, ContextNode& ctx)
2487 {
2488 return VauImpl(term, ctx, true);
2489 }
2490
2491 ReductionStatus
2492 VauWithEnvironment(TermNode& term, ContextNode& ctx)
2493 {
2494 return VauWithEnvironmentImpl(term, ctx, {});
2495 }
2496
2497 ReductionStatus
2498 VauWithEnvironmentRef(TermNode& term, ContextNode& ctx)
2499 {
2500 return VauWithEnvironmentImpl(term, ctx, true);
2501 }
2502
2503
2504 ReductionStatus
2505 Wrap(TermNode& term, ContextNode& ctx)
2506 {
2507 return WrapOrRef(term, ctx, WrapN,
2508 [&](ContextHandler& h, ResolvedTermReferencePtr p_ref){
2509 return WrapH(term, MakeValueOrMove(p_ref, [&]{
2510 return FormContextHandler(h, 1);
2511 }, [&]{
2512 return FormContextHandler(std::move(h), 1);
2513 }));
2514 });
2515 }
2516
2517 ReductionStatus
2518 WrapRef(TermNode& term, ContextNode& ctx)
2519 {
2520 return WrapOrRef(term, ctx, WrapRefN,
2521 [&](ContextHandler& h, ResolvedTermReferencePtr p_ref){
2522 return p_ref ? ReduceForCombinerRef(term, ctx, *p_ref, h, 1)
2523 : WrapH(term, FormContextHandler(std::move(std::move(h)), 1));
2524 });
2525 }
2526
2527 ReductionStatus
2528 WrapOnce(TermNode& term, ContextNode& ctx)
2529 {
2530 return WrapOnceOrOnceRef(term, ctx, WrapN);
2531 }
2532
2533 ReductionStatus
2534 WrapOnceRef(TermNode& term, ContextNode& ctx)
2535 {
2536 return WrapOnceOrOnceRef(term, ctx, WrapRefN);
2537 }
2538
2539 ReductionStatus
2540 Unwrap(TermNode& term, ContextNode& ctx)
2541 {
2542 using namespace std::placeholders;
2543
2544 return WrapUnwrap(term, std::bind(UnwrapResolved, std::ref(term),
2545 std::ref(ctx), _1, _2), ThrowForUnwrappingFailure);
2546 }
2547
2548
2549 ReductionStatus
2550 CheckEnvironment(TermNode& term)
2551 {
2552 RetainN(term);
2553
2554 auto& tm(*std::next(term.begin()));
2555
2556 Environment::EnsureValid(ResolveEnvironment(tm).first);
2557 MoveRValueToReturn(term, tm);
2558 return ReductionStatus::Regular;
2559 }
2560
2561 ReductionStatus
2562 CheckListReference(TermNode& term)
2563 {
2564 return CallResolvedUnary([&](TermNode& nd, bool has_ref){
2565 CheckResolvedListReference(nd, has_ref);
2566 // XXX: Similar to %DoIdFunc in %NPL.Dependency.
2567 LiftTerm(term, NPL::Deref(std::next(term.begin())));
2568 return ReductionStatus::Regular;
2569 }, term);
2570 }
2571
2572
2573 ReductionStatus
2574 MakeEncapsulationType(TermNode& term)
2575 {
2576 const auto tag(in_place_type<ContextHandler>);
2577 const auto a(term.get_allocator());
2578 // NOTE: The %p_type handle can be extended to point to a metadata block.
2579 #if true
2580 shared_ptr<void> p_type(new yimpl(byte));
2581
2582 term.GetContainerRef() = {NPL::AsTermNode(a, tag, std::allocator_arg, a,
2583 FormContextHandler(Encapsulate(p_type), 1)),
2584 NPL::AsTermNode(a, tag, std::allocator_arg, a,
2585 FormContextHandler(Encapsulated(p_type), 1)),
2586 NPL::AsTermNode(a, tag, std::allocator_arg, a,
2587 FormContextHandler(Decapsulate(p_type), 1))};
2588 #else
2589 // XXX: Mixing the %p_type above to following assignment code can be worse
2590 // in performance.
2591 shared_ptr<void> p_type(YSLib::allocate_shared<yimpl(byte)>(a));
2592
2593 term.GetContainerRef() = {NPL::AsTermNode(a, std::allocator_arg, a, tag,
2594 std::allocator_arg, a, FormContextHandler(Encapsulate(p_type), 1)),
2595 NPL::AsTermNode(a, std::allocator_arg, a, tag,
2596 std::allocator_arg, a, FormContextHandler(Encapsulated(p_type), 1)),
2597 NPL::AsTermNode(a, std::allocator_arg, a, tag,
2598 std::allocator_arg, a, FormContextHandler(Decapsulate(p_type), 1))};
2599 #endif
2600 return ReductionStatus::Retained;
2601 }
2602
2603
2604 ReductionStatus
2605 Sequence(TermNode& term, ContextNode& ctx)
2606 {
2607 Retain(term);
2608 RemoveHead(term);
2609 return ReduceOrdered(term, ctx);
2610 }
2611
2612 ReductionStatus
2613 Apply(TermNode& term, ContextNode& ctx)
2614 {
2615 Retain(term);
2616
2617 const auto size(term.size());
2618
2619 if(size == 3)
2620 return ApplyImpl(term, ctx,
2621 NPL::AllocateEnvironment(term.get_allocator()));
2622 if(size == 4)
2623 return ApplyImpl(term, ctx,
2624 ResolveEnvironment(*std::next(term.begin(), 3)).first);
2625 ThrowInvalidSyntaxError("Syntax error in applying form.");
2626 }
2627
2628 ReductionStatus
2629 ListAsterisk(TermNode& term)
2630 {
2631 ListAsteriskImpl(term);
2632 LiftSubtermsToReturn(term);
2633 return ReductionStatus::Retained;
2634 }
2635
2636 ReductionStatus
2637 ListAsteriskRef(TermNode& term)
2638 {
2639 ListAsteriskImpl(term);
2640 return ReductionStatus::Retained;
2641 }
2642
2643 ReductionStatus
2644 AccL(TermNode& term, ContextNode& ctx)
2645 {
2646 RetainN(term, 6);
2647 // XXX: This preprocessing binds all arguments but the abstract list object.
2648 // It is necessary for recursive calls, but redundant for the non-recursive
2649 // case. Implement it here for better overall performance as non-recursive
2650 // cases are relatively rare.
2651 BindMoveNextNLocalSubobjectInPlace(std::next(term.begin()), 5);
2652
2653 auto& con(term.GetContainerRef());
2654
2655 con.emplace_back();
2656 con.emplace_back();
2657 return AccLImpl(term, ctx);
2658 }
2659
2660 ReductionStatus
2661 AccR(TermNode& term, ContextNode& ctx)
2662 {
2663 RetainN(term, 6);
2664 // XXX: Ditto.
2665 BindMoveNextNLocalSubobjectInPlace(std::next(term.begin()), 5);
2666
2667 auto& con(term.GetContainerRef());
2668 auto& rterm(*term.emplace(ystdex::exchange(con,
2669 TermNode::Container(term.get_allocator()))));
2670
2671 rterm.GetContainerRef().emplace_back();
2672 AccFoldR1(term, ctx, rterm, 6);
2673 return AccRImpl(rterm, ctx, con.back());
2674 }
2675
2676 ReductionStatus
2677 FoldR1(TermNode& term, ContextNode& ctx)
2678 {
2679 RetainN(term, 3);
2680 // XXX: Like %AccL.
2681 BindMoveNextNLocalSubobjectInPlace(term.begin(), 2);
2682 return DoFoldRMap1(term, ctx, FoldR1Impl);
2683 }
2684
2685 ReductionStatus
2686 Map1(TermNode& term, ContextNode& ctx)
2687 {
2688 RetainN(term, 2);
2689 // XXX: Like %AccL.
2690 BindMoveNextNLocalSubobjectInPlace(term.begin(), 2);
2691 return DoFoldRMap1(term, ctx, Map1Impl);
2692 }
2693
2694
2695 void
2696 CallSystem(TermNode& term)
2697 {
2698 CallUnaryAs<const string>(
2699 ystdex::compose(usystem, std::mem_fn(&string::c_str)), term);
2700 }
2701
2702 } // namespace Forms;
2703
2704 } // namesapce A1;
2705
2706 } // namespace NPL;
2707
NPL::A1::Forms::Apply
YF_API ReductionStatus Apply(TermNode &, ContextNode &)
函数应用：应用参数指定的函数和作为函数参数的列表。
Definition: NPLA1Forms.cpp:2613
NPL::A1::Forms::MakeEnvironment
YF_API void MakeEnvironment(TermNode &)
创建以参数指定的环境列表作为父环境的新环境。
Definition: NPLA1Forms.cpp:2348
NPL::A1::Internals::RelayCurrentNext
YB_FLATTEN ReductionStatus RelayCurrentNext(TermNode &term, ContextNode &ctx, _fCurrent &&cur, _fNext &&next)
Definition: NPLA1Internals.h:620
YSLib::Environment
应用程序环境。
Definition: Environment.h:63
NPL::A1::Forms::LambdaRef
YF_API ReductionStatus LambdaRef(TermNode &, ContextNode &)
Definition: NPLA1Forms.cpp:2474
NPL::A1::ThrowValueCategoryErrorForFirstArgument
void ThrowValueCategoryErrorForFirstArgument(const TermNode &term)
Definition: NPLA1.cpp:790
YB_ATTR_nodiscard
#define YB_ATTR_nodiscard
标记返回值不被忽略的属性。
Definition: ydef.h:715
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:112
NPL::TermReference
项引用。
Definition: NPLA.h:1068
x
const EncapsulationBase & x
Definition: NPLA1Forms.cpp:1536
YSLib::swap
void swap(ValueNode &x, ValueNode &y) ynothrowv
Definition: ValueNode.cpp:95
platform::Nonnull
YB_PURE _type && Nonnull(_type &&p) ynothrowv
断言并返回非空参数。
Definition: Debug.h:518
NPL::A1::Forms::CallResolvedUnary
auto CallResolvedUnary(_func &&f, TermNode &term) -> yimpl(decltype(NPL::ResolveTerm(yforward(f), term)))
解析节点的子节点并调用一元函数。
Definition: NPLA1Forms.h:148
size
size_t size
Definition: memory_resource.cpp:295
NPL::A1::Forms::ConsRef
YF_API ReductionStatus ConsRef(TermNode &)
Definition: NPLA1Forms.cpp:2134
NPL::A1::EvaluateIdentifier
YF_API ReductionStatus EvaluateIdentifier(TermNode &, const ContextNode &, string_view)
求值标识符。
Definition: NPLA1.cpp:1232
NPL::A1::Forms::EvalString
YF_API ReductionStatus EvalString(TermNode &, ContextNode &)
在参数指定的环境中求值作为外部表示的字符串。
Definition: NPLA1Forms.cpp:2325
store
unordered_map< string, shared_ptr_t > store
Definition: NPLA1Forms.cpp:256
NPL::A1::Forms::ValueOf
YF_API ReductionStatus ValueOf(TermNode &, const ContextNode &)
求值标识符得到指称的实体。
Definition: NPLA1Forms.cpp:2400
NPL::A1::ThrowInsufficientTermsError
YB_NORETURN YF_API void ThrowInsufficientTermsError()
抛出缺少项的异常。
Definition: NPLA1.cpp:759
NPL::A1::Forms::If
YF_API ReductionStatus If(TermNode &, ContextNode &)
分支判断：根据求值的条件选取表达式求值。
Definition: NPLA1Forms.cpp:2047
CatchIgnore
#define CatchIgnore(_ex)
指定异常处理器忽略指定异常。
Definition: YBaseMacro.h:133
NPL::A1::Forms::VauRef
YF_API ReductionStatus VauRef(TermNode &, ContextNode &)
Definition: NPLA1Forms.cpp:2486
NPL::A1::Forms::ListAsteriskRef
YF_API ReductionStatus ListAsteriskRef(TermNode &)
Definition: NPLA1Forms.cpp:2637
NPL::A1::Forms::ListAsterisk
YF_API ReductionStatus ListAsterisk(TermNode &)
使用可选的参数指定的不定数量的元素和结尾列表构造新列表。
Definition: NPLA1Forms.cpp:2629
CHRLib::c
c
Definition: CharacterProcessing.h:84
NPL::A1::Forms::RetainN
ReductionStatus::Retained YF_API size_t RetainN(const TermNode &, size_t=1)
保留经检查确保具有指定个数参数的项：保留求值。
Definition: NPLA1Forms.cpp:2011
ystdex::lref
左值引用包装。
Definition: ref.hpp:61
NPL::A1::Forms::EqualValue
YF_API void EqualValue(TermNode &)
比较两个子项表示的值相等。
Definition: NPLA1Forms.cpp:2040
NPL::A1::Forms::CallRegularUnaryAs
auto CallRegularUnaryAs(_func &&f, TermNode &term, _tParams &&... args) -> yimpl(decltype(ystdex::expand_proxy< void(_type &, const ResolvedTermReferencePtr &, _tParams &&...)>::call(f, NPL::Access< _type >(term), ResolvedTermReferencePtr(), std::forward< _tParams >(args)...)))
Definition: NPLA1Forms.h:188
YB_PURE
#define YB_PURE
指示函数或函数模板实例为纯函数。
Definition: ydef.h:919
NPL::IsEmpty
YB_ATTR_nodiscard YB_PURE const TermNode &term ynothrow IsEmpty
Definition: SContext.h:524
platform::usystem
YF_API int usystem(const char *)
执行 UTF-8 字符串的环境命令。
Definition: YCommon.cpp:91
YB_ATTR_LAMBDA_QUAL
#define YB_ATTR_LAMBDA_QUAL(_q,...)
允许在 lambda 表达式的参数列表后和限定符共用的属性。
Definition: ydef.h:619
NPL::RelaySwitched
ReductionStatus RelaySwitched(ContextNode &ctx, _fCurrent &&cur)
异步规约指定动作和上下文中的当前动作。
Definition: NPLA.h:3101
NPL::BadIdentifier
标识符错误。
Definition: NPLA.h:626
NPL::A1::Internals::term
_fCurrent TermNode &decltype(cur(term, ctx)) term
Definition: NPLA1Internals.h:593
NPL::A1::Forms::CallSystem
YF_API void CallSystem(TermNode &)
调用 UTF-8 字符串的系统命令，并保存 int 类型的结果到项的值中。
Definition: NPLA1Forms.cpp:2696
NPL::A1::Forms::LockCurrentEnvironment
YF_API void LockCurrentEnvironment(TermNode &, ContextNode &)
锁定当前环境的引用。
Definition: NPLA1Forms.cpp:2393
DefDeMoveCtor
#define DefDeMoveCtor(_t)
Definition: YBaseMacro.h:167
NPL::A1::Forms::FirstVal
YF_API ReductionStatus FirstVal(TermNode &)
Definition: NPLA1Forms.cpp:2260
NPL::A1::BindParameter
YF_API void BindParameter(const shared_ptr< Environment > &, const TermNode &, TermNode &)
使用操作数结构化匹配并绑定参数。
Definition: NPLA1.cpp:1463
ystdex::dep_ops::equality_comparable
_t< details::ops_seq< _type, _type2, _tOpt, cond_t< is_same< _type, _type2 >, index_sequence< 7 >, index_sequence< 6, 7, 8 > >> > equality_comparable
Definition: operators.hpp:265
NPL::A1::Forms::AccL
YF_API ReductionStatus AccL(TermNode &, ContextNode &)
在抽象列表元素上应用左结合的二元操作。
Definition: NPLA1Forms.cpp:2644
YB_FLATTEN
#define YB_FLATTEN
标记函数尽可能内联定义内的调用。
Definition: ydef.h:843
TermTags
TermTags
标签：表示引用元数据的位。
Definition: SContext.h:108
NPL::A1::Internals::ReduceForCombinerRef
ReductionStatus ReduceForCombinerRef(TermNode &term, ContextNode &ctx, const TermReference &ref, const ContextHandler &h, size_t n)
Definition: NPLA1Internals.cpp:186
NPL::A1::Forms::Or
YF_API ReductionStatus Or(TermNode &, ContextNode &)
支持短路求值的逻辑或。
Definition: NPLA1Forms.cpp:2119
YSLib::operator==
bool operator==(const shared_ptr< _type > &sp, _type *p)
比较： shared_ptr 和内建指针类型的相等关系。
Definition: YShellDefinition.h:62
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
CHRLib::d
_tDst * d
Definition: CharacterProcessing.h:142
NPL::A1::Forms::Equal
YF_API void Equal(TermNode &)
比较两个子项表示的值引用相同的对象。
Definition: NPLA1Forms.cpp:2022
NPL::AllocateEnvironment
shared_ptr< Environment > AllocateEnvironment(ContextNode &ctx, _tParams &&... args)
Definition: NPLA.h:2917
NPL::TermToNamePtr
YB_ATTR_nodiscard YB_PURE observer_ptr< const TokenValue > TermToNamePtr(const TermNode &)
访问项的值作为记号。
NPL::A1::Forms::When
YF_API ReductionStatus When(TermNode &, ContextNode &)
条件顺序求值：预期条件成立。
Definition: NPLA1Forms.cpp:2093
Type
const EncapsulationBase const EncapsulationBase &y ynothrow const EncapsulationBase *this const shared_ptr< void > Type
Definition: NPLA1Forms.cpp:1542
NPL::A1::Forms::AccR
YF_API ReductionStatus AccR(TermNode &, ContextNode &)
在抽象列表元素上应用右结合的二元操作。
Definition: NPLA1Forms.cpp:2661
YF_API
#define YF_API
Definition: Platform.h:56
TermRef
lref< const TermNode > TermRef
Definition: NPLA1Forms.cpp:262
NPL::A1::Forms::Undefine
YF_API void Undefine(TermNode &, ContextNode &)
移除定义引入的绑定。
Definition: NPLA1Forms.cpp:2451
NPL::A1::Forms::Unwrap
YF_API ReductionStatus Unwrap(TermNode &, ContextNode &)
解包装应用子为合并子。
Definition: NPLA1Forms.cpp:2540
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::ReduceToReferenceAt
PDefH(ReductionStatus, ReduceToList, TermNode &term) ynothrow ImplRet(IsBranchedList(term) ? ReduceBranchToList(term) YF_API ReductionStatus ReduceToReferenceAt(TermNode &, TermNode &, ResolvedTermReferencePtr)
规约为列表：对分支列表节点移除第一个子项，保留余下的子项作为列表。
Definition: NPLA.h:1932
ystdex::expand_proxy
Definition: functional.hpp:471
NPL::A1::Forms::SetFirst
YF_API void SetFirst(TermNode &)
修改第一参数指定的列表以第二参数作为第一个元素。
Definition: NPLA1Forms.cpp:2275
platform_ex::Windows::Invalid
@ Invalid
Definition: Win32/include/YCLib/MinGW32.h:485
NPL::A1::Forms::Cond
YF_API ReductionStatus Cond(TermNode &, ContextNode &)
条件分支选择：根据条件列表顺序选取第一个符合其中条件对应的表达式求值。
Definition: NPLA1Forms.cpp:2072
NPLA1Internals.h
NPLA1 内部接口。
NPL::A1::Forms::StringToSymbol
YB_ATTR_nodiscard YF_API YB_PURE TokenValue StringToSymbol(const string &)
创建等于指定字符串值的记号值。
Definition: NPLA1Forms.cpp:1992
ystdex::invoke_value_or
auto invoke_value_or(_func f, _type &&p) -> decay_t< decltype(ystdex::invoke(f, *std::forward< decltype(p)>(p)))>
使用 invoke 调用非空值或取默认值。
Definition: invoke.hpp:588
CHRLib::f
f(d, s)
YSLib::Drawing::g
The boundary is out of the const Graphics & g
Definition: YDraw.h:161
p_type
shared_ptr< void > p_type
Definition: NPLA1Forms.cpp:1527
act
Action act
Definition: NPLA1.cpp:580
NPL::tm
tm
Definition: NPLA.h:1941
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::Forms::Wrap
YF_API ReductionStatus Wrap(TermNode &, ContextNode &)
包装合并子为应用子。
Definition: NPLA1Forms.cpp:2505
NPL::A1::EnvironmentGuard
ystdex::guard< EnvironmentSwitcher > EnvironmentGuard
求值环境守卫。
Definition: NPLA1.h:1221
NPL::MoveRValueToReturn
YF_API void MoveRValueToReturn(TermNode &, TermNode &)
提升第二参数指定的右值项作为第一参数指定项中的返回值。
Definition: NPLA.cpp:801
NPL::A1::Forms::Unless
YF_API ReductionStatus Unless(TermNode &, ContextNode &)
条件顺序求值：预期条件不成立。
Definition: NPLA1Forms.cpp:2099
platform::Descriptions::Alert
@ Alert
Definition: YCommon.h:180
NPL::A1::Forms::CallUnary
void CallUnary(_func &&f, TermNode &term, _tParams &&... args)
访问节点并调用一元函数。
Definition: NPLA1Forms.h:228
YModules.h
NPL 库模块配置文件。
TNIter
TermNode::iterator TNIter
Definition: SContext.h:501
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
YSLib::LoggedEvent
记录日志的异常事件类。
Definition: YException.h:51
NPL::A1::Forms::SetRestRef
YF_API void SetRestRef(TermNode &)
Definition: NPLA1Forms.cpp:2306
YSLib::RemoveHead
YF_API void RemoveHead(ValueNode::Container &) ynothrowv
移除第一个子节点。
Definition: ValueNode.cpp:186
YB_NORETURN
#define YB_NORETURN
指定无返回值函数。
Definition: ydef.h:877
NPL::A1::Forms::FirstRef
YF_API ReductionStatus FirstRef(TermNode &)
Definition: NPLA1Forms.cpp:2254
NPL::A1::Forms::FoldR1
YF_API ReductionStatus FoldR1(TermNode &, ContextNode &)
在列表元素上应用右结合的二元操作。
Definition: NPLA1Forms.cpp:2677
NPL::A1::Forms::UndefineChecked
YF_API void UndefineChecked(TermNode &, ContextNode &)
检查并移除名称绑定。
Definition: NPLA1Forms.cpp:2459
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
NPL::ContextNode::WeakenRecord
const ynothrow ynothrow WeakenRecord
Definition: NPLA.h:2873
NPL::A1::Forms::FirstAt
YF_API ReductionStatus FirstAt(TermNode &)
Definition: NPLA1Forms.cpp:2248
NPL::A1::Forms::GetCurrentEnvironment
YF_API void GetCurrentEnvironment(TermNode &, ContextNode &)
取当前环境的引用。
Definition: NPLA1Forms.cpp:2386
NPL::A1::Forms::Eval
YF_API ReductionStatus Eval(TermNode &, ContextNode &)
对指定项以指定的环境求值。
Definition: NPLA1Forms.cpp:2313
YSLib::GHEvent< ReductionStatus(TermNode &, ContextNode &)>
NPL::A1::REPLContext
Definition: NPLA1.h:1554
NPL::A1::REPLContext::Perform
TermNode Perform(_tParams &&... args)
执行循环：从指定参数指定的来源读取并翻译源代码，并返回处理结果。
Definition: NPLA1.h:1722
NPL::IsLeaf
YB_ATTR_nodiscard YB_PURE const TermNode &term ynothrow const TermNode &term ynothrow const TermNode &term ynothrow IsLeaf
Definition: SContext.h:537
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
NPL::A1::Forms::DefineWithNoRecursion
YF_API ReductionStatus DefineWithNoRecursion(TermNode &, ContextNode &)
不带递归匹配的定义。
Definition: NPLA1Forms.cpp:2427
NPL::A1::Forms::EvalRef
YF_API ReductionStatus EvalRef(TermNode &, ContextNode &)
Definition: NPLA1Forms.cpp:2319
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
YSLib::yimpl
YF_API yimpl(GUIApplication &) FetchGlobalInstance()
取全局应用程序实例。
NPL::A1::Forms::WrapOnce
YF_API ReductionStatus WrapOnce(TermNode &, ContextNode &)
包装操作子为应用子。
Definition: NPLA1Forms.cpp:2528
YSLib::i
return i
Definition: YCoreUtilities.h:177
NPL::A1::Forms::SetWithNoRecursion
YF_API ReductionStatus SetWithNoRecursion(TermNode &, ContextNode &)
修改指定环境的绑定，不带递归匹配。
Definition: NPLA1Forms.cpp:2439
NPL::LiftCollapsed
YF_API void LiftCollapsed(TermNode &, TermNode &, TermReference)
提升折叠后的项引用到指定的项。
Definition: NPLA.cpp:729
ystdex::type_id
const type_info & type_id()
Definition: typeinfo.h:149
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1535
NPL::A1::Forms::VauWithEnvironment
YF_API ReductionStatus VauWithEnvironment(TermNode &, ContextNode &)
带环境的 vau 抽象：求值为一个捕获当前上下文的非严格求值的函数。
Definition: NPLA1Forms.cpp:2492
NPL::A1::SetupTailContext
YF_API void SetupTailContext(ContextNode &, TermNode &)
设置参数指定的上下文为尾上下文。
Definition: NPLA1.cpp:1594
NPL::ArityMismatch
元数不匹配。
Definition: NPLA.h:595
NPL::A1::Forms::And
YF_API ReductionStatus And(TermNode &, ContextNode &)
支持短路求值的逻辑与。
Definition: NPLA1Forms.cpp:2113
NPL::A1::Forms::SymbolToString
YB_ATTR_nodiscard YF_API YB_STATELESS const string & SymbolToString(const TokenValue &) ynothrow
取符号对应的名称字符串。
Definition: NPLA1Forms.cpp:2005
NPL::A1::Forms::IsSymbol
YB_ATTR_nodiscard YF_API YB_PURE bool IsSymbol(const string &) ynothrow
判断字符串值是否可构成符号。
Definition: NPLA1Forms.cpp:1986
NPL
Definition: NPL/Configuration.h:35
YSLib::UI::y
SPos SPos y
Definition: YWidget.cpp:44
NPL::TryAccessReferencedLeaf
YB_ATTR_nodiscard YB_PURE observer_ptr< _type > TryAccessReferencedLeaf(TermNode &term)
尝试访问解析 TermReference 后的项的指定类型对象指针。
Definition: NPLA.h:1319
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::Forms::Not
YF_API YB_PURE bool Not(TermNode &)
逻辑非。
Definition: NPLA1Forms.cpp:2105
CatchExpr
#define CatchExpr(_ex,...)
指定表达式作为异常处理器。
Definition: YBaseMacro.h:129
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
ystdex::cpp2017::empty
auto empty(const _tRange &c) -> decltype(c.empty())
Definition: range.hpp:562
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:46
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:143
head
link_ptr head
Definition: memory_resource.cpp:232
NPL::A1::NameTypedReducerHandler
YB_ATTR_nodiscard YB_PURE _fCallable NameTypedReducerHandler(_fCallable &&x, string_view desc)
初始化作为规约器处理器的全局类型名称表项并转发参数。
Definition: NPLA1.h:1481
NPL::TermToStringWithReferenceMark
YB_ATTR_nodiscard YF_API YB_PURE string TermToStringWithReferenceMark(const TermNode &, bool)
访问项的值并转换为可选带有引用标记的字符串形式。
Definition: NPLA.cpp:567
YSLib::ynothrow
YB_PURE const _type size_t n ynothrow
Definition: YCoreUtilities.h:169
Context
ContextNode & Context
Definition: NPLA1Forms.cpp:488
NPL::A1::Forms::Vau
YF_API ReductionStatus Vau(TermNode &, ContextNode &)
vau 抽象：求值为一个捕获当前上下文的非严格求值的函数。
Definition: NPLA1Forms.cpp:2480
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::ReduceToReference
ReductionStatus ReduceToReference(TermNode &term, TermNode &tm, ResolvedTermReferencePtr p_ref)
Definition: NPLA.cpp:839
platform::Deref
YB_PURE yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:547
NPL::A1::FormContextHandler
形式上下文处理器。
Definition: NPLA1.h:919
platform::tail
_tString ystdex::string_traits< _tString >::const_pointer tail
Definition: YCLib/FileSystem.h:465
YSLib::ImplRet
ImplRet(FetchGlobalInstance().GetGUIHostRef()) YF_API void Execute(GUIApplication &
执行程序主消息循环。
NPL::A1::Forms::SetRest
YF_API void SetRest(TermNode &)
修改第一参数指定的列表以第二参数作为第一个元素外的列表。
Definition: NPLA1Forms.cpp:2300
NPL::A1::Forms::Cons
YF_API ReductionStatus Cons(TermNode &)
接受两个参数，返回以第一参数作为第一个元素插入第二参数创建的新的列表。
Definition: NPLA1Forms.cpp:2126
ystdex
<memory> 特性测试宏。
Definition: ydef.h:1262
NPL::A1::Forms::First
YF_API ReductionStatus First(TermNode &)
取参数指定的列表中的第一元素的引用值。
Definition: NPLA1Forms.cpp:2197
NPL::IsMovable
YB_ATTR_nodiscard YB_PURE PDefH(TermNode &, ReferenceTerm, TermNode &term) ynoexcept_spec(std YB_ATTR_nodiscard YB_PURE yconstfn IsMovable
Definition: NPLA.h:1295
NPL::ContextNode::ShareRecord
ShareRecord
Definition: NPLA.h:2861
NPL::A1::Forms::EqualLeaf
YF_API void EqualLeaf(TermNode &)
比较两个子项的值相等。
Definition: NPLA1Forms.cpp:2028
RecordPtr
shared_ptr< Environment > RecordPtr
Definition: NPLA1Forms.cpp:260
YSLib::_tParams
YB_ATTR_nodiscard YB_PURE typename _tParams
Definition: ValueNode.h:1294
YSLib::YB_NONNULL
YB_ATTR_nodiscard YF_API YB_NONNULL(1, 2) ValueNode LoadNPLA1File(const char *disp
载入 NPLA1 配置文件。
ystdex::cpp2017::in_place_type
uniformed_tags::in_place_tag in_place_type(empty_base< _type >)
Definition: placement.hpp:255
NPL::c_str
YF_API const char src c_str())) YF_API void InstallDirectory(const string &
安装目录：复制目录树。
Definition: Dependency.h:140
NPL::LiftOtherOrCopy
void LiftOtherOrCopy(TermNode &term, TermNode &tm, bool move)
Definition: NPLA.cpp:696
NPL::A1::Forms::EvalStringRef
YF_API ReductionStatus EvalStringRef(TermNode &, ContextNode &)
在参数指定的环境中求值作为外部表示的字符串。
Definition: NPLA1Forms.cpp:2331
NPL::A1::Forms::Map1
YF_API ReductionStatus Map1(TermNode &, ContextNode &)
单列表映射操作。
Definition: NPLA1Forms.cpp:2686
NPL::A1::Internals::RelayForEvalOrDirect
ReductionStatus RelayForEvalOrDirect(ContextNode &ctx, TermNode &term, EnvironmentGuard &&gd, bool no_lift, _fNext &&next)
Definition: NPLA1Internals.h:655
NPL::A1::Forms::Lambda
YF_API ReductionStatus Lambda(TermNode &, ContextNode &)
λ 抽象：求值为一个捕获当前上下文的严格求值的函数。
Definition: NPLA1Forms.cpp:2468
ystdex::value_or
auto value_or(_type &&p) -> decay_t< decltype(*std::forward< decltype(p)>(p))>
取非空值或默认值。
Definition: deref_op.hpp:128
DefGetter
#define DefGetter(_q, _t, _n,...)
Definition: YBaseMacro.h:241
NPL::A1::Forms::EqualReference
YF_API void EqualReference(TermNode &)
比较两个子项的值引用相同的对象。
Definition: NPLA1Forms.cpp:2034
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
CHRLib::enc
enc
Definition: CharacterProcessing.h:84
NPL::A1::Forms::DefineLazy
YF_API ReductionStatus DefineLazy(TermNode &, ContextNode &)
以惰性求值的表达式定义值。
Definition: NPLA1Forms.cpp:2419
ystdex::nullptr
const class ystdex::nullptr_t nullptr
ystdex::cpp2014::exchange
_type exchange(_type &obj, _type2 &&new_val)
交换值并返回旧值。
Definition: swap.hpp:535
YB_UNLIKELY
#define YB_UNLIKELY(_expr)
分支预测提示。
Definition: ydef.h:828
platform::p
return p p
Definition: YCLib/FileSystem.h:209
NPL::A1::Forms::CheckEnvironment
YF_API ReductionStatus CheckEnvironment(TermNode &)
检查参数指定的项表示环境。
Definition: NPLA1Forms.cpp:2550
NPL::A1::ReduceOrdered
ReductionStatus ReduceOrdered(TermNode &term, ContextNode &ctx)
Definition: NPLA1.cpp:965
NPL::A1::Forms::ForwardListFirst
YF_API ReductionStatus ForwardListFirst(TermNode &, ContextNode &)
取列表的第一元素并转发给指定的应用子。
Definition: NPLA1Forms.cpp:2141
ystdex::function
function_base< function_traits< _fSig, empty_function_policy::throwing >, _fSig > function
函数包装类模板。
Definition: function.hpp:900
const
const Decapsulate const Decapsulate &y ynothrow ContextNode &ctx const
Definition: NPLA1Forms.cpp:1629
ystdex::compose
auto compose(_func f, _func2 g, _func3 h, _funcs... args) -> decltype(ystdex::compose(ystdex::compose(f, g), h, args...))
Definition: functional.hpp:124
NPL::A1::Forms::WrapOnceRef
YF_API ReductionStatus WrapOnceRef(TermNode &, ContextNode &)
包装操作子为应用子。
Definition: NPLA1Forms.cpp:2534
NPL::dst
YF_API const char src const string const char * dst
Definition: Dependency.h:96
DefDeMoveAssignment
#define DefDeMoveAssignment(_t)
Definition: YBaseMacro.h:191
NPL::A1::Forms::WrapRef
YF_API ReductionStatus WrapRef(TermNode &, ContextNode &)
包装合并子为应用子。
Definition: NPLA1Forms.cpp:2518
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
ystdex::any_ops::use_holder
const struct ystdex::any_ops::use_holder_t use_holder
NPL::A1::Internals::ReduceSubsequent
ReductionStatus ReduceSubsequent(TermNode &term, ContextNode &ctx, _fNext &&next)
Definition: NPLA1Internals.h:699
NPL::A1::ReduceOnce
YF_API ReductionStatus ReduceOnce(TermNode &, ContextNode &)
NPLA1 表达式节点一次规约：转发调用到 NPLA1 表达式节点一次规约续延并调用。
Definition: NPLA1.cpp:959
NPL::A1::Forms::SetFirstAt
YF_API void SetFirstAt(TermNode &)
Definition: NPLA1Forms.cpp:2283
YSLib::vo
vo
Definition: YApplication.h:231
TryRet
#define TryRet(...)
指定表达式在 try 块中求值并返回。
Definition: YBaseMacro.h:124
NPL::A1::Forms::CheckListReference
YF_API ReductionStatus CheckListReference(TermNode &)
检查参数指定的项表示非空列表的引用。
Definition: NPLA1Forms.cpp:2562
TryExpr
#define TryExpr(...)
指定表达式在 try 块中求值。
Definition: YBaseMacro.h:120
NPL::A1::Forms::SetFirstRef
YF_API void SetFirstRef(TermNode &)
Definition: NPLA1Forms.cpp:2291
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:1458
YSLib::args
YB_ATTR_nodiscard YB_PURE typename _tParams && args
Definition: ValueNode.h:1299
ystdex::path_category::parent
@ parent
NPL::A1::Forms::VauWithEnvironmentRef
YF_API ReductionStatus VauWithEnvironmentRef(TermNode &, ContextNode &)
Definition: NPLA1Forms.cpp:2498
NPL::get
PDefH(void, LiftTermRef, TermNode &term, const TermNode &tm) ImplExpr(NPL ref get()
Definition: NPLA.h:1737
ystdex::allocate_shared
std::shared_ptr< _type > allocate_shared(const _tAlloc &alloc, _tParams &&... args)
使用分配器创建 std::shared_ptr 。
Definition: allocator.hpp:949
ystdex::ref
void ref(const _type &&)=delete
YB_ATTR_LAMBDA
#define YB_ATTR_LAMBDA(...)
允许在 lambda 表达式的参数列表后使用的属性。
Definition: ydef.h:581
NPL::A1::Forms::MakeEncapsulationType
YF_API ReductionStatus MakeEncapsulationType(TermNode &)
创建封装类型。
Definition: NPLA1Forms.cpp:2574
YSLib::PDefH
PDefH(Environment &, FetchEnvironment,) ImplRet(FetchGlobalInstance().GetEnvironmentRef()) inline PDefH(GUIHost &
取单一环境对象引用。
NPL::IsReferenceTerm
YB_ATTR_nodiscard YF_API YB_PURE bool IsReferenceTerm(const TermNode &)
判断项（的值数据成员）是否为引用项。
Definition: NPLA.cpp:636
NPL::SContext::Analyze
void Analyze(TermNode &root, const _tParseResult &parse_result)
分析指定源，取抽象语法树储存至指定值类型节点。
Definition: SContext.h:1127
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::sfmt< string >
template string sfmt< string >(const char *,...)
显式实例化：以 C 标准输出格式的输出 string 对象。
YSLib::a
YB_PURE const _type * a
Definition: YCoreUtilities.h:168
NPL::A1::Forms::EvalUnit
YF_API ReductionStatus EvalUnit(TermNode &)
在参数指定的 REPL 环境中规约字符串表示的翻译单元以求值。
Definition: NPLA1Forms.cpp:2337
platform::l
return l
Definition: YCLib/FileSystem.h:402
NPL::ResolveEnvironment
YB_ATTR_nodiscard YF_API pair< shared_ptr< Environment >, bool > ResolveEnvironment(const ValueObject &)
解析环境。
Definition: NPLA.cpp:1224
platform::Descriptions::Debug
@ Debug
Definition: YCommon.h:186
NPL::A1::Forms::SetWithRecursion
YF_API ReductionStatus SetWithRecursion(TermNode &, ContextNode &)
修改指定环境的绑定，带递归匹配。
Definition: NPLA1Forms.cpp:2445
NPL::A1::Forms::DefineWithRecursion
YF_API ReductionStatus DefineWithRecursion(TermNode &, ContextNode &)
带递归匹配的定义。
Definition: NPLA1Forms.cpp:2433