• R/O
  • SSH

YSLib: Commit

The YSLib project - main repository


Commit MetaInfo

Revision37835df0ac3b86b8a993936e2aedab678c1f3ccc (tree)
Time2021-03-26 23:43:02
AuthorFrankHB <frankhb1989@gmai...>
CommiterFrankHB

Log Message

更新主分支版本: build 915 rev 10 。

Change Summary

    Incremental Difference

    diff -r 92d04ed3856a -r 37835df0ac3b YFramework/include/NPL/NPLA1.h
    --- a/YFramework/include/NPL/NPLA1.h Sat Mar 13 14:46:42 2021 +0800
    +++ b/YFramework/include/NPL/NPLA1.h Fri Mar 26 22:43:02 2021 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA1.h
    1212 \ingroup NPL
    1313 \brief NPLA1 公共接口。
    14-\version r8529
    14+\version r8550
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 472
    1717 \par 创建时间:
    1818 2014-02-02 17:58:24 +0800
    1919 \par 修改时间:
    20- 2021-03-12 18:01 +0800
    20+ 2021-03-17 04:45 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -611,21 +611,36 @@
    611611 //@}
    612612
    613613 /*!
    614-\brief 规约到引用列表。
    615614 \note 不访问项的值数据成员。若需返回值正确地反映规约状态,需确保为空。
    616615 \return ReductionStatus::Retained
    616+
    617+检查最后一个参数指定的项表示的对象语言中的列表或列表的引用值,
    618+ 处理其中的元素构造列表到第一参数中的子项。
    619+结果中的列表元素是对应源列表的元素。
    620+最后一个参数指定的源列表可能被第一参数所有。
    621+*/
    622+//@{
    623+/*!
    624+\brief 规约到引用列表。
    617625 \since build 913
    618626
    619-检查第三参数指定的项表示的对象语言中的列表或列表的引用值,
    620- 处理其中的元素构造列表到第一参数中的子项。
    621-结果中的列表元素是对应源列表的元素。
    622627 若源列表为左值,则结果中的列表元素是对应的左值引用值;
    623628 否则,结果中的列表元素从源列表中的元素复制初始化(按标签可发生转移)。
    624-第三参数指定的源列表可能被第一参数所有。
    625629 */
    626630 YF_API ReductionStatus
    627631 ReduceToReferenceList(TermNode&, ContextNode&, TermNode&);
    628632
    633+/*!
    634+\brief 规约到可带有唯一引用标签的引用列表。
    635+\since build 915
    636+
    637+若源列表为左值,则结果中的列表元素是对应的左值引用值;
    638+否则,结果中的列表元素是源列表中的元素的唯一引用。
    639+*/
    640+YF_API ReductionStatus
    641+ReduceToReferenceUList(TermNode&, TermNode&);
    642+//@}
    643+
    629644
    630645 /*!
    631646 \brief 规约至确定的未指定值。
    @@ -1461,7 +1476,8 @@
    14611476 {
    14621477 static_assert(std::is_constructible<_tTarget, _fCallable>(),
    14631478 "Invalid callable type found.");
    1464- using expanded_t = ystdex::expanded_caller<_func, _fCallable>;
    1479+ using expanded_t
    1480+ = ystdex::expanded_caller<_func, ystdex::remove_cvref_t<_fCallable>>;
    14651481
    14661482 A1::InitializeTypeNameTableEntry<ystdex::cond_t<ystdex::and_<
    14671483 ystdex::not_<std::is_constructible<function<_func>, _fCallable>>,
    diff -r 92d04ed3856a -r 37835df0ac3b YFramework/include/NPL/SContext.h
    --- a/YFramework/include/NPL/SContext.h Sat Mar 13 14:46:42 2021 +0800
    +++ b/YFramework/include/NPL/SContext.h Fri Mar 26 22:43:02 2021 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file SContext.h
    1212 \ingroup NPL
    1313 \brief S 表达式上下文。
    14-\version r3866
    14+\version r3968
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 304
    1717 \par 创建时间:
    1818 2012-08-03 19:55:41 +0800
    1919 \par 修改时间:
    20- 2021-03-12 18:01 +0800
    20+ 2021-03-19 23:15 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -138,11 +138,7 @@
    138138 通常在派生实现绑定特定引用且指定被引用的对象是右值时使用。
    139139 取得范式的项中,临时对象标签指示被绑定对象或其引用的绑定的是临时对象,
    140140 类似宿主语言中声明的右值引用变量,但实际作用在被引用的对象的项,
    141- 而不引入引用项。
    142- 范式中来自绑定的临时对象外的标签在对象语言中完全通过表达式的值类别决定。
    143- 排除临时对象标签的项,在特定上下文中被推断为左值,仍保留剩余的标签;
    144- 在这些上下文中,临时对象标签使推断结果为右值。
    145- 和宿主语言的 std::forward 不同,此处推断的右值除了是消亡值外,也可以是纯右值。
    141+ 而不引入项引用。
    146142 不取得范式的项中,派生语言可指定指示被绑定对象以外的语义。
    147143 */
    148144 Temporary = 1 << TemporaryIndex
    @@ -153,14 +149,28 @@
    153149 DefBitmaskEnum(TermTags)
    154150
    155151 /*!
    156-\brief 取推断为左值表达式时保留的标签。
    152+\brief 取转发推断为左值表达式时保留的标签。
    157153 \sa TermTags::Temporary
    158154
    159-取推断为左值表达式的标签,即除临时对象以外的标签。
    155+取按对象语言引用推断规则转发操作数时,允许使实际参数被推断为左值表达式的标签。
    156+当前设计中,即除临时对象以外的标签。
    160157 */
    161158 YB_ATTR_nodiscard YB_STATELESS yconstfn
    162159 PDefH(TermTags, GetLValueTagsOf, const TermTags& tags) ynothrow
    163160 ImplRet(tags & ~TermTags::Temporary)
    161+
    162+/*!
    163+\brief 传播标签。
    164+\since build 915
    165+
    166+向指定的标签添加可向被引用对象传播的标签。
    167+传播的标签实现引用值上的限定符向列表引用子对象的传播或者间接引用的合并。
    168+适用的范围类似宿主语言引用的限定符的传播。
    169+当前可传播的标签只有实现限定符的 TermTags::Nonmodifying 。
    170+*/
    171+YB_ATTR_nodiscard YB_STATELESS yconstfn
    172+ PDefH(TermTags, PropagateTo, TermTags dst, TermTags tags) ynothrow
    173+ ImplRet(dst | (tags & TermTags::Nonmodifying))
    164174 //@}
    165175 //@}
    166176
    @@ -294,24 +304,24 @@
    294304 \brief 复制构造:使用参数和参数指定的分配器。
    295305 \since build 879
    296306 */
    297- TermNode(const TermNode& tm)
    298- : TermNode(tm, tm.get_allocator())
    307+ TermNode(const TermNode& nd)
    308+ : TermNode(nd, nd.get_allocator())
    299309 {}
    300- TermNode(const TermNode& tm, allocator_type a)
    301- : container(tm.container, a), Value(tm.Value), Tags(tm.Tags)
    310+ TermNode(const TermNode& nd, allocator_type a)
    311+ : container(nd.container, a), Value(nd.Value), Tags(nd.Tags)
    302312 {}
    303313 DefDeMoveCtor(TermNode)
    304- TermNode(TermNode&& tm, allocator_type a)
    305- : container(std::move(tm.container), a), Value(std::move(tm.Value)),
    306- Tags(tm.Tags)
    314+ TermNode(TermNode&& nd, allocator_type a)
    315+ : container(std::move(nd.container), a), Value(std::move(nd.Value)),
    316+ Tags(nd.Tags)
    307317 {}
    308318
    309319 /*!
    310320 \brief 复制赋值:使用参数副本和交换操作。
    311321 \since build 879
    312322 */
    313- PDefHOp(TermNode&, =, const TermNode& tm)
    314- ImplRet(ystdex::copy_and_swap(*this, tm))
    323+ PDefHOp(TermNode&, =, const TermNode& nd)
    324+ ImplRet(ystdex::copy_and_swap(*this, nd))
    315325 /*!
    316326 \pre 被转移的参数不是被子节点容器直接或间接所有的其它节点。
    317327 \warning 违反前置条件的转移可能引起循环引用。
    @@ -337,11 +347,11 @@
    337347 container = yforward(con);
    338348 Value = yforward(val);
    339349 }
    340- PDefH(void, SetContent, const TermNode& term)
    341- ImplExpr(SetContent(term.container, term.Value))
    342- PDefH(void, SetContent, TermNode&& term)
    343- ImplExpr(SetContent(std::move(term.container), std::move(term.Value)),
    344- Tags = term.Tags)
    350+ PDefH(void, SetContent, const TermNode& nd)
    351+ ImplExpr(SetContent(nd.container, nd.Value))
    352+ PDefH(void, SetContent, TermNode&& nd)
    353+ ImplExpr(SetContent(std::move(nd.container), std::move(nd.Value)),
    354+ Tags = nd.Tags)
    345355 //@}
    346356
    347357 //! \since build 853
    @@ -378,14 +388,14 @@
    378388 \since build 913
    379389 */
    380390 //@{
    381- PDefH(void, CopyContainer, const TermNode& node)
    382- ImplExpr(GetContainerRef() = Container(node.GetContainer()))
    391+ PDefH(void, CopyContainer, const TermNode& nd)
    392+ ImplExpr(GetContainerRef() = Container(nd.GetContainer()))
    383393
    384- PDefH(void, CopyContent, const TermNode& node)
    385- ImplExpr(SetContent(TermNode(node)))
    394+ PDefH(void, CopyContent, const TermNode& nd)
    395+ ImplExpr(SetContent(TermNode(nd)))
    386396
    387- PDefH(void, CopyValue, const TermNode& node)
    388- ImplExpr(Value = ValueObject(node.Value))
    397+ PDefH(void, CopyValue, const TermNode& nd)
    398+ ImplExpr(Value = ValueObject(nd.Value))
    389399 //@}
    390400
    391401 private:
    @@ -407,10 +417,10 @@
    407417 {
    408418 Container res(con.get_allocator());
    409419
    410- for(auto&& tm : con)
    420+ for(auto&& nd : con)
    411421 res.emplace_back(CreateRecursively(
    412- ystdex::forward_like<_tCon>(tm.container), f),
    413- ystdex::invoke(f, ystdex::forward_like<_tCon>(tm.Value)));
    422+ ystdex::forward_like<_tCon>(nd.container), f),
    423+ ystdex::invoke(f, ystdex::forward_like<_tCon>(nd.Value)));
    414424 return res;
    415425 }
    416426 //@}
    @@ -550,43 +560,43 @@
    550560 */
    551561 //@{
    552562 //! \brief 判断项是否为枝节点。
    553-YB_ATTR_nodiscard YB_PURE inline PDefH(bool, IsBranch, const TermNode& term)
    554- ynothrow
    555- ImplRet(!term.empty())
    563+YB_ATTR_nodiscard YB_PURE inline
    564+ PDefH(bool, IsBranch, const TermNode& nd) ynothrow
    565+ ImplRet(!nd.empty())
    556566
    557567 /*!
    558568 \brief 判断项是否为分支列表节点。
    559569 \since build 858
    560570 */
    561-YB_ATTR_nodiscard YB_PURE inline PDefH(bool, IsBranchedList,
    562- const TermNode& term) ynothrow
    563- ImplRet(!(term.empty() || term.Value))
    571+YB_ATTR_nodiscard YB_PURE inline
    572+ PDefH(bool, IsBranchedList, const TermNode& nd) ynothrow
    573+ ImplRet(!(nd.empty() || nd.Value))
    564574
    565575 //! \brief 判断项是否为空节点。
    566-YB_ATTR_nodiscard YB_PURE inline PDefH(bool, IsEmpty, const TermNode& term)
    567- ynothrow
    568- ImplRet(!term)
    576+YB_ATTR_nodiscard YB_PURE inline
    577+ PDefH(bool, IsEmpty, const TermNode& nd) ynothrow
    578+ ImplRet(!nd)
    569579
    570580 /*!
    571581 \brief 判断项是否为扩展列表节点。
    572582 \since build 858
    573583 */
    574-YB_ATTR_nodiscard YB_PURE inline PDefH(bool, IsExtendedList,
    575- const TermNode& term) ynothrow
    576- ImplRet(!(term.empty() && term.Value))
    584+YB_ATTR_nodiscard YB_PURE inline
    585+ PDefH(bool, IsExtendedList, const TermNode& nd) ynothrow
    586+ ImplRet(!(nd.empty() && nd.Value))
    577587
    578588 //! \brief 判断项是否为叶节点。
    579-YB_ATTR_nodiscard YB_PURE inline PDefH(bool, IsLeaf, const TermNode& term)
    580- ynothrow
    581- ImplRet(term.empty())
    589+YB_ATTR_nodiscard YB_PURE inline
    590+ PDefH(bool, IsLeaf, const TermNode& nd) ynothrow
    591+ ImplRet(nd.empty())
    582592
    583593 /*!
    584594 \brief 判断项是否为列表节点。
    585595 \since build 774
    586596 */
    587-YB_ATTR_nodiscard YB_PURE inline PDefH(bool, IsList, const TermNode& term)
    588- ynothrow
    589- ImplRet(!term.Value)
    597+YB_ATTR_nodiscard YB_PURE inline
    598+ PDefH(bool, IsList, const TermNode& nd) ynothrow
    599+ ImplRet(!nd.Value)
    590600 //@}
    591601
    592602 //! \since build 853
    @@ -594,16 +604,16 @@
    594604 //! \since build 854
    595605 template<typename _type>
    596606 YB_ATTR_nodiscard YB_PURE inline _type&
    597-Access(TermNode& term)
    607+Access(TermNode& nd)
    598608 {
    599- return term.Value.Access<_type>();
    609+ return nd.Value.Access<_type>();
    600610 }
    601611 //! \since build 854
    602612 template<typename _type>
    603613 YB_ATTR_nodiscard YB_PURE inline const _type&
    604-Access(const TermNode& term)
    614+Access(const TermNode& nd)
    605615 {
    606- return term.Value.Access<_type>();
    616+ return nd.Value.Access<_type>();
    607617 }
    608618
    609619 //! \since build 853
    @@ -611,16 +621,16 @@
    611621 //! \since build 852
    612622 template<typename _type>
    613623 YB_ATTR_nodiscard YB_PURE inline observer_ptr<_type>
    614-AccessPtr(TermNode& term) ynothrow
    624+AccessPtr(TermNode& nd) ynothrow
    615625 {
    616- return term.Value.AccessPtr<_type>();
    626+ return nd.Value.AccessPtr<_type>();
    617627 }
    618628 //! \since build 852
    619629 template<typename _type>
    620630 YB_ATTR_nodiscard YB_PURE inline observer_ptr<const _type>
    621-AccessPtr(const TermNode& term) ynothrow
    631+AccessPtr(const TermNode& nd) ynothrow
    622632 {
    623- return term.Value.AccessPtr<_type>();
    633+ return nd.Value.AccessPtr<_type>();
    624634 }
    625635
    626636 /*!
    @@ -628,9 +638,9 @@
    628638 \pre 断言:参数指定的项是枝节点。
    629639 \since build 761
    630640 */
    631-inline PDefH(void, AssertBranch, const TermNode& term,
    641+inline PDefH(void, AssertBranch, const TermNode& nd,
    632642 const char* msg = "Invalid term found.") ynothrowv
    633- ImplExpr(yunused(term), yunused(msg), YAssert(IsBranch(term), msg))
    643+ ImplExpr(yunused(nd), yunused(msg), YAssert(IsBranch(nd), msg))
    634644
    635645 //! \brief 创建项节点。
    636646 //@{
    @@ -658,18 +668,17 @@
    658668 // NOTE: Like %YSLib::GetValueOf.
    659669 YB_ATTR_nodiscard YB_PURE inline
    660670 PDefH(ValueObject, GetValueOf, observer_ptr<const TermNode> p_term)
    661- ImplRet(ystdex::call_value_or(
    662- [](const TermNode& term) -> const ValueObject&{
    663- return term.Value;
    671+ ImplRet(ystdex::call_value_or([](const TermNode& nd) -> const ValueObject&{
    672+ return nd.Value;
    664673 }, p_term))
    665674
    666675 // NOTE: Like %YSLib::GetValuePtrOf.
    667676 YB_ATTR_nodiscard YB_PURE inline PDefH(observer_ptr<const ValueObject>,
    668677 GetValuePtrOf, observer_ptr<const TermNode> p_term)
    669- ImplRet(ystdex::call_value_or(ystdex::compose(make_observer<const
    670- ValueObject>, ystdex::addrof<>(),
    671- [](const TermNode& term) -> const ValueObject&{
    672- return term.Value;
    678+ ImplRet(ystdex::call_value_or(
    679+ ystdex::compose(make_observer<const ValueObject>, ystdex::addrof<>(),
    680+ [](const TermNode& nd) -> const ValueObject&{
    681+ return nd.Value;
    673682 }), p_term))
    674683
    675684 //! \since build 872
    @@ -677,29 +686,29 @@
    677686 //! \pre 断言:参数指定的项是枝节点。
    678687 //@{
    679688 YB_ATTR_nodiscard YB_PURE inline
    680- PDefH(TermNode&, AccessFirstSubterm, TermNode& term)
    681- ImplRet(AssertBranch(term), NPL::Deref(term.begin()))
    689+ PDefH(TermNode&, AccessFirstSubterm, TermNode& nd)
    690+ ImplRet(AssertBranch(nd), NPL::Deref(nd.begin()))
    682691 YB_ATTR_nodiscard YB_PURE inline
    683- PDefH(const TermNode&, AccessFirstSubterm, const TermNode& term)
    684- ImplRet(AssertBranch(term), NPL::Deref(term.begin()))
    692+ PDefH(const TermNode&, AccessFirstSubterm, const TermNode& nd)
    693+ ImplRet(AssertBranch(nd), NPL::Deref(nd.begin()))
    685694
    686695 YB_ATTR_nodiscard YB_PURE inline
    687- PDefH(TermNode&&, MoveFirstSubterm, TermNode& term)
    688- ImplRet(std::move(AccessFirstSubterm(term)))
    696+ PDefH(TermNode&&, MoveFirstSubterm, TermNode& nd)
    697+ ImplRet(std::move(AccessFirstSubterm(nd)))
    689698 //@}
    690699
    691700 YB_ATTR_nodiscard inline
    692- PDefH(shared_ptr<TermNode>, ShareMoveTerm, TermNode& term)
    693- ImplRet(YSLib::share_move(term.get_allocator(), term))
    701+ PDefH(shared_ptr<TermNode>, ShareMoveTerm, TermNode& nd)
    702+ ImplRet(YSLib::share_move(nd.get_allocator(), nd))
    694703 YB_ATTR_nodiscard inline
    695- PDefH(shared_ptr<TermNode>, ShareMoveTerm, TermNode&& term)
    696- ImplRet(YSLib::share_move(term.get_allocator(), term))
    704+ PDefH(shared_ptr<TermNode>, ShareMoveTerm, TermNode&& nd)
    705+ ImplRet(YSLib::share_move(nd.get_allocator(), nd))
    697706 //@}
    698707
    699708 //! \pre 断言:项节点容器非空。
    700-inline PDefH(void, RemoveHead, TermNode& term) ynothrowv
    701- ImplExpr(YAssert(!term.empty(), "Empty term container found."),
    702- term.erase(term.begin()))
    709+inline PDefH(void, RemoveHead, TermNode& nd) ynothrowv
    710+ ImplExpr(YAssert(!nd.empty(), "Empty term container found."),
    711+ nd.erase(nd.begin()))
    703712
    704713 /*!
    705714 \brief 根据节点和节点容器创建操作设置目标节点的值或子节点。
    @@ -708,11 +717,11 @@
    708717 */
    709718 template<typename _fCallable, class _tNode>
    710719 void
    711-SetContentWith(TermNode& dst, _tNode&& node, _fCallable f)
    720+SetContentWith(TermNode& dst, _tNode&& nd, _fCallable f)
    712721 {
    713722 // NOTE: Similar to %YSLib::SetContentWith.
    714- auto con(yforward(node).CreateWith(f));
    715- auto vo(ystdex::invoke(f, yforward(node).Value));
    723+ auto con(yforward(nd).CreateWith(f));
    724+ auto vo(ystdex::invoke(f, yforward(nd).Value));
    716725
    717726 dst.SetContent(std::move(con), std::move(vo));
    718727 }
    @@ -724,9 +733,9 @@
    724733 */
    725734 template<typename _type>
    726735 YB_ATTR_nodiscard YB_PURE inline bool
    727-HasValue(const TermNode& term, const _type& x)
    736+HasValue(const TermNode& nd, const _type& x)
    728737 {
    729- return term.Value == x;
    738+ return nd.Value == x;
    730739 }
    731740 //@}
    732741
    @@ -740,15 +749,15 @@
    740749 */
    741750 template<typename _fCallable, class _tNode>
    742751 void
    743-TraverseSubnodes(_fCallable f, const _tNode& node)
    752+TraverseSubnodes(_fCallable f, const _tNode& nd)
    744753 {
    745754 // TODO: Null coalescing or variant value?
    746- if(const auto p = AccessPtr<YSLib::NodeSequence>(node))
    747- for(const auto& nd : *p)
    748- ystdex::invoke(f, _tNode(nd));
    755+ if(const auto p = AccessPtr<YSLib::NodeSequence>(nd))
    756+ for(const auto& sub : *p)
    757+ ystdex::invoke(f, _tNode(sub));
    749758 else
    750- for(const auto& nd : node)
    751- ystdex::invoke(f, nd);
    759+ for(const auto& sub : nd)
    760+ ystdex::invoke(f, sub);
    752761 }
    753762
    754763
    @@ -1127,7 +1136,7 @@
    11271136 tms.push(std::move(term));
    11281137 for(; first != last; ++first)
    11291138 if(ToLexeme(*first) == "(")
    1130- tms.push(NPL::AsTermNode(a));
    1139+ tms.push(TermNode(a));
    11311140 else if(ToLexeme(*first) != ")")
    11321141 {
    11331142 YAssert(!tms.empty(), "Invalid state found.");
    diff -r 92d04ed3856a -r 37835df0ac3b YFramework/source/NPL/Dependency.cpp
    --- a/YFramework/source/NPL/Dependency.cpp Sat Mar 13 14:46:42 2021 +0800
    +++ b/YFramework/source/NPL/Dependency.cpp Fri Mar 26 22:43:02 2021 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file Dependency.cpp
    1212 \ingroup NPL
    1313 \brief 依赖管理。
    14-\version r4480
    14+\version r4599
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 623
    1717 \par 创建时间:
    1818 2015-08-09 22:14:45 +0800
    1919 \par 修改时间:
    20- 2021-03-13 01:42 +0800
    20+ 2021-03-26 12:10 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -650,21 +650,6 @@
    650650 });
    651651 RegisterStrict(renv, "idv", idv);
    652652 RegisterStrict(renv, "list", ReduceBranchToListValue);
    653- RegisterStrict(renv, "list%", ReduceBranchToList);
    654- RegisterStrict(renv, "rlist", [](TermNode& term, ContextNode& ctx){
    655- return Forms::CallRawUnary([&](TermNode& tm){
    656- return ReduceToReferenceList(term, ctx, tm);
    657- }, term);
    658- });
    659- // NOTE: Lazy form '$deflazy!' is the basic operation, which may bind
    660- // parameter as unevaluated operands.
    661- RegisterForm(renv, "$deflazy!", DefineLazy);
    662- RegisterForm(renv, "$set!", SetWithNoRecursion);
    663- RegisterForm(renv, "$setrec!", SetWithRecursion);
    664- RegisterForm(renv, "$lambda", Lambda);
    665- RegisterForm(renv, "$lambda%", LambdaRef);
    666- // NOTE: The sequence operator is also available as infix ';' syntax sugar.
    667- RegisterForm(renv, "$sequence", Sequence);
    668653 RegisterForm(renv, "$lvalue-identifier?",
    669654 [](TermNode& term, ContextNode& ctx){
    670655 Forms::CallRegularUnaryAs<const TokenValue>([&](string_view id){
    @@ -685,6 +670,27 @@
    685670 });
    686671 }, term);
    687672 });
    673+ RegisterStrict(renv, "forward!", [](TermNode& term){
    674+ return Forms::CallRawUnary([&](TermNode& tm){
    675+ MoveRValueToForward(term, tm);
    676+ return ReductionStatus::Retained;
    677+ }, term);
    678+ });
    679+ RegisterStrict(renv, "list%", ReduceBranchToList);
    680+ RegisterStrict(renv, "rlist", [](TermNode& term, ContextNode& ctx){
    681+ return Forms::CallRawUnary([&](TermNode& tm){
    682+ return ReduceToReferenceList(term, ctx, tm);
    683+ }, term);
    684+ });
    685+ // NOTE: Lazy form '$deflazy!' is the basic operation, which may bind
    686+ // parameter as unevaluated operands.
    687+ RegisterForm(renv, "$deflazy!", DefineLazy);
    688+ RegisterForm(renv, "$set!", SetWithNoRecursion);
    689+ RegisterForm(renv, "$setrec!", SetWithRecursion);
    690+ RegisterForm(renv, "$lambda", Lambda);
    691+ RegisterForm(renv, "$lambda%", LambdaRef);
    692+ // NOTE: The sequence operator is also available as infix ';' syntax sugar.
    693+ RegisterForm(renv, "$sequence", Sequence);
    688694 RegisterStrict(renv, "collapse", [](TermNode& term){
    689695 return Forms::CallRawUnary([&](TermNode& tm){
    690696 MoveCollapsed(term, tm);
    @@ -695,12 +701,6 @@
    695701 return Forms::CallRawUnary(std::bind(ReduceToValue, std::ref(term),
    696702 std::placeholders::_1), term);
    697703 });
    698- RegisterStrict(renv, "forward!", [](TermNode& term){
    699- return Forms::CallRawUnary([&](TermNode& tm){
    700- MoveRValueToForward(term, tm);
    701- return ReductionStatus::Retained;
    702- }, term);
    703- });
    704704 RegisterBinary<>(renv, "assign%!", [](TermNode& x, TermNode& y){
    705705 return DoAssign(ystdex::bind1(MoveCollapsed, std::ref(y)), x);
    706706 });
    @@ -753,6 +753,11 @@
    753753 ThrowInsufficientTermsError(nd, p_ref);
    754754 }, x);
    755755 });
    756+ RegisterStrict(renv, "rulist", [](TermNode& term){
    757+ return Forms::CallRawUnary([&](TermNode& tm){
    758+ return ReduceToReferenceUList(term, tm);
    759+ }, term);
    760+ });
    756761 RegisterStrict(renv, "list-concat", ListConcat);
    757762 RegisterStrict(renv, "append", Append);
    758763 RegisterStrict(renv, "list-extract%", ListExtract);
    @@ -809,9 +814,8 @@
    809814 $def! lock-current-environment (wrap ($vau () d lock-environment d));
    810815 )NPL"
    811816 # endif
    812- // XXX: The operative '$set!' is same to following derivations.
    813817 R"NPL(
    814- $def! $quote $vau (&x) #ignore x;
    818+ $def! $quote $vau% (x) #ignore $move-resolved! x;
    815819 )NPL"
    816820 // NOTE: The function 'id' does not initialize new objects from the operand.
    817821 // XXX: The implementation of 'id' relies on the fact that an object other
    @@ -831,8 +835,6 @@
    831835 $def! id wrap ($vau% (%x) #ignore $move-resolved! x);
    832836 $def! idv wrap $quote;
    833837 $def! list wrap ($vau (.x) #ignore move! x);
    834- $def! list% wrap ($vau &x #ignore x);
    835- $def! rlist wrap ($vau ((.&x)) #ignore move! x);
    836838 )NPL"
    837839 # else
    838840 );
    @@ -841,9 +843,25 @@
    841843 context.ShareCurrentSource("<root:basic-derived-1>");
    842844 context.Perform(R"NPL(
    843845 $def! id $lambda% (%x) $move-resolved! x;
    844- $def! idv $lambda (&x) x;
    846+ $def! idv $lambda% (x) $move-resolved! x;
    845847 $def! list $lambda (.x) move! x;
    846- $def! list% $lambda &x x;
    848+ )NPL"
    849+# endif
    850+ R"NPL(
    851+ $def! $lvalue-identifier? $vau (&s) d
    852+ eval (list bound-lvalue? (list $resolve-identifier s)) d;
    853+ )NPL"
    854+# if NPL_Impl_NPLA1_Use_Id_Vau
    855+ R"NPL(
    856+ $def! forward! wrap
    857+ ($vau% (%x) #ignore $if ($lvalue-identifier? x) x (move! x));
    858+ $def! list% wrap ($vau &x #ignore forward! x);
    859+ $def! rlist wrap ($vau ((.&x)) #ignore move! x);
    860+ )NPL"
    861+# else
    862+ R"NPL(
    863+ $def! forward! $lambda% (%x) $if ($lvalue-identifier? x) x (move! x);
    864+ $def! list% $lambda &x forward! x;
    847865 $def! rlist $lambda ((.&x)) move! x;
    848866 )NPL"
    849867 # endif
    @@ -861,10 +879,11 @@
    861879 )NPL"
    862880 # if NPL_Impl_NPLA1_Use_Id_Vau
    863881 R"NPL(
    864- $defv! $lambda (&formals .&body) d wrap
    865- (eval (cons $vau (cons formals (cons ignore (move! body)))) d);
    866- $defv! $lambda% (&formals .&body) d wrap
    867- (eval (cons $vau% (cons formals (cons ignore (move! body)))) d);
    882+ $defv! $lambda (&formals .&body) d
    883+ wrap (eval (cons $vau (cons formals (cons ignore (move! body)))) d);
    884+ $defv! $lambda% (&formals .&body) d
    885+ wrap
    886+ (eval (cons $vau% (cons formals (cons ignore (move! body)))) d);
    868887 )NPL"
    869888 # endif
    870889 // XXX: The operatives '$defl!', '$defl%!', '$defw%!', '$defv%!',
    @@ -878,20 +897,18 @@
    878897 (eval% (cons% $aux (move! exprseq)) d))
    879898 ($set! se $aux
    880899 $vau/e% (weaken-environment se) (&head .&tail) d
    881- $if (null? tail) (eval% head d)
    900+ $if (null? tail) (eval% (forward! head) d)
    882901 (($vau% (&t) e ($lambda% #ignore eval% t e)
    883- (eval% head d)) (eval% (cons% $aux tail) d))))
    902+ (eval% (forward! head) d))
    903+ (eval% (cons% $aux (move! tail)) d))))
    884904 (make-environment (() get-current-environment));
    885905 $defv! $defl! (&f &formals .&body) d
    886906 eval (list $set! d f $lambda formals (move! body)) d;
    887907 $defv! $defl%! (&f &formals .&body) d
    888908 eval (list $set! d f $lambda% formals (move! body)) d;
    889- $defv! $lvalue-identifier? (&s) d
    890- eval (list bound-lvalue? (list $resolve-identifier s)) d;
    891909 $defl%! collapse (%x)
    892910 $if (uncollapsed? ($resolve-identifier x)) (idv x) x;
    893911 $defl%! forward (%x) $if ($lvalue-identifier? x) x (idv x);
    894- $defl%! forward! (%x) $if ($lvalue-identifier? x) x (move! x);
    895912 $defl! assign! (&x &y) assign@! (forward! x) (idv (collapse y));
    896913 $defl! assign%! (&x &y) assign@! (forward! x) (forward! (collapse y));
    897914 $defl%! apply (&appv &arg .&opt)
    @@ -902,9 +919,11 @@
    902919 (raise-invalid-syntax-error
    903920 "Syntax error in applying form.")) opt));
    904921 $defl! list* (&head .&tail)
    905- $if (null? tail) head (cons head (apply list* tail));
    906- $defl%! list*% (&head .&tail) $if (null? tail) (forward! head)
    907- (cons% (forward! head) (apply list*% tail));
    922+ $if (null? tail) (forward! head)
    923+ (cons (forward! head) (apply list* (move! tail)));
    924+ $defl%! list*% (&head .&tail)
    925+ $if (null? tail) (forward! head)
    926+ (cons% (forward! head) (apply list*% tail));
    908927 $defv! $defw%! (&f &formals &ef .&body) d
    909928 eval (list $set! d f wrap (list* $vau% formals ef (move! body))) d;
    910929 $defw%! forward-first% (&appv (&x .)) d
    @@ -915,47 +934,53 @@
    915934 $defl%! first@ (&l)
    916935 ($lambda% ((@x .)) x) (check-list-reference (forward! l));
    917936 $defl%! first% (%l)
    918- ($lambda% (fwd (@x .)) idv (fwd x))
    937+ ($lambda (fwd (@x .)) fwd x)
    919938 ($if ($lvalue-identifier? l) id expire) l;
    920939 $defl%! first& (&l)
    921940 ($lambda% ((&x .)) x) (check-list-reference (forward! l));
    922941 $defl! firstv ((&x .)) x;
    923- $defl! rest% ((#ignore .%x)) move! x;
    942+ $defl! rest% ((#ignore .%xs)) move! xs;
    924943 $defl%! rest& (&l)
    925- ($lambda% ((#ignore .&x)) x) (check-list-reference (forward! l));
    926- $defl! restv ((#ignore .x)) move! x;
    944+ ($lambda% ((#ignore .&xs)) xs) (check-list-reference (forward! l));
    945+ $defl! restv ((#ignore .xs)) move! xs;
    927946 $defl! set-first! (&l x) assign@! (first@ (forward! l)) (move! x);
    928947 $defl! set-first@! (&l &x) assign@! (first@ (forward! l)) (forward! x);
    929948 $defl! set-first%! (&l &x) assign%! (first@ (forward! l)) (forward! x);
    930- $defl! equal? (&x &y) $if ($if (branch? x) (branch? y) #f)
    931- ($if (equal? (first& x) (first& y)) (equal? (rest& x) (rest& y)) #f)
    932- (eqv? x y);
    949+ $defl! equal? (&x &y)
    950+ $if ($if (branch? x) (branch? y) #f)
    951+ ($if (equal? (first& x) (first& y))
    952+ (equal? (rest& x) (rest& y)) #f)
    953+ (eqv? x y);
    933954 $defl%! check-environment (&e)
    934955 $sequence (eval% #ignore e) (forward! e);
    935956 $defl%! check-parent (&e)
    936957 $sequence ($vau/e% e . #ignore) (forward! e);
    937958 $defv! $defv%! (&$f &formals &ef .&body) d
    938959 eval (list $set! d $f $vau% formals ef (move! body)) d;
    939- $defv%! $cond &clauses d $if (null? clauses) #inert
    940- (apply ($lambda% ((&test .&body) .&clauses)
    941- $if (eval test d) (eval% (move! body) d)
    942- (apply (wrap $cond) (move! clauses) d)) (move! clauses));
    960+ $defv%! $cond &clauses d
    961+ $if (null? clauses) #inert
    962+ (apply ($lambda% ((&test .&body) .&clauses)
    963+ $if (eval test d) (eval% (move! body) d)
    964+ (apply (wrap $cond) (move! clauses) d))
    965+ (move! clauses));
    943966 $defv%! $when (&test .&exprseq) d
    944- $if (eval test d) (eval% (list () $sequence (move! exprseq)) d);
    967+ $if (eval test d) (eval% (list* () $sequence (move! exprseq)) d);
    945968 $defv%! $unless (&test .&exprseq) d
    946969 $if (eval test d) #inert
    947- (eval% (list () $sequence (move! exprseq)) d);
    970+ (eval% (list* () $sequence (move! exprseq)) d);
    948971 $defl! not? (&x) eqv? x #f;
    949- $defv%! $and? &x d $cond
    950- ((null? x) #t)
    951- ((null? (rest& x)) eval% (first (forward! x)) d)
    952- ((eval% (first& x) d) apply (wrap $and?) (rest% (forward! x)) d)
    953- (#t #f);
    954- $defv%! $or? &x d $cond
    955- ((null? x) #f)
    956- ((null? (rest& x)) eval% (first (forward! x)) d)
    957- (#t ($lambda% (&r) $if r (forward! r) (apply (wrap $or?)
    958- (rest% (forward! x)) d)) (eval% (move! (first& x)) d));
    972+ $defv%! $and? &x d
    973+ $cond
    974+ ((null? x) #t)
    975+ ((null? (rest& x)) eval% (first (forward! x)) d)
    976+ ((eval% (first& x) d) apply (wrap $and?) (rest% (forward! x)) d)
    977+ (#t #f);
    978+ $defv%! $or? &x d
    979+ $cond
    980+ ((null? x) #f)
    981+ ((null? (rest& x)) eval% (first (forward! x)) d)
    982+ (#t ($lambda% (&r) $if r (forward! r) (apply (wrap $or?)
    983+ (rest% (forward! x)) d)) (eval% (move! (first& x)) d));
    959984 $defw%! accl (&l &pred? &base &head &tail &sum) d
    960985 $if (apply pred? (list% l) d) (forward! base)
    961986 (apply accl (list% (apply tail (list% l) d) pred?
    @@ -971,8 +996,16 @@
    971996 (list% (forward! l) null? (forward! knil) first% rest% kons) d;
    972997 $defw%! map1 (&appv &l) d
    973998 foldr1 ($lambda (&x &xs) cons%
    974- (apply appv (list% (forward! x)) d) xs) () (forward! l);
    999+ (apply appv (list% (forward! x)) d) (move! xs)) () (forward! l);
    9751000 $defl! first-null? (&l) null? (first l);
    1001+ $defl%! rulist (&l)
    1002+ $if ($lvalue-identifier? l)
    1003+ (accr (($lambda ((.@xs)) xs) l) null? ()
    1004+ ($lambda% (%l) $sequence ($def! %x idv (first@ l))
    1005+ (($if (uncollapsed? x) idv expire) x)) rest%
    1006+ ($lambda (&x &xs)
    1007+ (cons% ($resolve-identifier x) (move! xs))))
    1008+ (rlist (forward! l));
    9761009 $defl! list-concat (&x &y) foldr1 cons% (forward! y) (forward! x);
    9771010 $defl! append (.&ls) foldr1 list-concat () (move! ls);
    9781011 $defw%! list-extract% (&l &extr) d
    @@ -1121,8 +1154,7 @@
    11211154 (
    11221155 $defv%! $lqual (&ls) d
    11231156 $if (eval (list $lvalue-identifier? ls) d)
    1124- (eval% (list as-const ls) d)
    1125- (($lambda% (&l) map1 expire (rlist l)) (eval% ls d));
    1157+ (eval% (list as-const ls) d) (rulist (eval% ls d));
    11261158 $defv%! $lqual* (&x) d
    11271159 ($if (eval (list $lvalue-identifier? x) d) as-const expire)
    11281160 (eval% x d);
    @@ -1156,8 +1188,7 @@
    11561188 (
    11571189 $defv%! $lqual (&ls) d
    11581190 $if (eval (list $lvalue-identifier? ls) d)
    1159- (eval% (list as-const ls) d)
    1160- (($lambda% (&l) map1 expire (rlist l)) (eval% ls d));
    1191+ (eval% (list as-const ls) d) (rulist (eval% ls d));
    11611192 $defv%! $lqual* (&x) d
    11621193 ($if (eval (list $lvalue-identifier? x) d) as-const expire)
    11631194 (eval% x d);
    @@ -1315,15 +1346,18 @@
    13151346 $defl%! force-promise (&x) $let ((((&o &env)) x))
    13161347 $if (null? env) (forward! o)
    13171348 (
    1318- $let% ((&y eval% o env)) $cond
    1319- ((null? (first (rest& (first& x)))) first& (first& x))
    1320- ((promise? y) $sequence
    1321- (set-first%! x (first (decapsulate (forward! y))))
    1322- (force-promise x))
    1323- (#t $sequence
    1324- ($let (((&o &e) first& x))
    1325- list% (assign! o y) (assign@! e ()))
    1326- (forward! y))
    1349+ $let% ((&y eval% o env))
    1350+ $cond
    1351+ ((null? (first (rest& (first& x))))
    1352+ first& (first& x))
    1353+ ((promise? y) $sequence
    1354+ (set-first%! x
    1355+ (first (decapsulate (forward! y))))
    1356+ (force-promise x))
    1357+ (#t $sequence
    1358+ ($let (((&o &e) first& x))
    1359+ list% (assign! o y) (assign@! e ()))
    1360+ (forward! y))
    13271361 )
    13281362 )))
    13291363 (
    diff -r 92d04ed3856a -r 37835df0ac3b YFramework/source/NPL/NPLA.cpp
    --- a/YFramework/source/NPL/NPLA.cpp Sat Mar 13 14:46:42 2021 +0800
    +++ b/YFramework/source/NPL/NPLA.cpp Fri Mar 26 22:43:02 2021 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA.cpp
    1212 \ingroup NPL
    1313 \brief NPLA 公共接口。
    14-\version r3520
    14+\version r3542
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 663
    1717 \par 创建时间:
    1818 2016-01-07 10:32:45 +0800
    1919 \par 修改时间:
    20- 2021-03-06 23:23 +0800
    20+ 2021-03-26 03:29 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -35,8 +35,8 @@
    3535 // ystdex::call_value_or, ystdex::begins_with, ystdex::sfmt,
    3636 // NPL::make_observer, YSLib::sfmt, GetLValueTagsOf, std::mem_fn,
    3737 // ystdex::compose, ystdex::invoke_value_or, NPL::TryAccessLeaf,
    38-// NPL::IsMovable, ystdex::ref, YSLib::FilterExceptions, ystdex::id,
    39-// ystdex::retry_on_cond, ystdex::type_info, pair, ystdex::addrof,
    38+// NPL::IsMovable, ystdex::ref, PropagateTo, YSLib::FilterExceptions,
    39+// ystdex::id, ystdex::retry_on_cond, ystdex::type_info, pair, ystdex::addrof,
    4040 // ystdex::second_of, std::rethrow_exception, std::throw_with_nested,
    4141 // YSLib::ExtractException;
    4242 #include YFM_NPL_SContext
    @@ -886,7 +886,27 @@
    886886 if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
    887887 {
    888888 // NOTE: Reference collapsed.
    889- LiftOtherOrCopy(term, tm, !p_ref);
    889+ // XXX: As %LiftOtherOrCopy, except that tags spcfified %p_ref are also
    890+ // Propagated.
    891+ if(!p_ref)
    892+ LiftOther(term, tm);
    893+ else
    894+ {
    895+ // XXX: Both can be even more efficient than %LiftOtherOrCopy.
    896+#if true
    897+ // XXX: As %LiftTermOtherOrCopy.
    898+ term.CopyContent(tm);
    899+
    900+ auto& ref(term.Value.GetObject<TermReference>());
    901+
    902+ ref.SetTags(PropagateTo(ref.GetTags(), p_ref->GetTags()));
    903+#else
    904+ term.CopyContainer(tm);
    905+ term.Value = TermReference(PropagateTo(p->GetTags(),
    906+ p_ref->GetTags()), p->get(),
    907+ NPL::Deref(p_ref).GetEnvironmentReference());
    908+#endif
    909+ }
    890910 // XXX: The resulted representation can be irregular.
    891911 return ReductionStatus::Retained;
    892912 }
    @@ -901,7 +921,7 @@
    901921 // except for future internal use. Since %term is a term, %Tags::Temporary
    902922 // is not expected, the %GetLValueTagsOf is also not used.
    903923 // XXX: Allocators are not used here for performance in most cases.
    904- term.Value = TermReference(tm.Tags, tm,
    924+ term.Value = TermReference(PropagateTo(tm.Tags, p_ref->GetTags()), tm,
    905925 NPL::Deref(p_ref).GetEnvironmentReference());
    906926 return ReductionStatus::Clean;
    907927 }
    diff -r 92d04ed3856a -r 37835df0ac3b YFramework/source/NPL/NPLA1.cpp
    --- a/YFramework/source/NPL/NPLA1.cpp Sat Mar 13 14:46:42 2021 +0800
    +++ b/YFramework/source/NPL/NPLA1.cpp Fri Mar 26 22:43:02 2021 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA1.cpp
    1212 \ingroup NPL
    1313 \brief NPLA1 公共接口。
    14-\version r20407
    14+\version r20493
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 473
    1717 \par 创建时间:
    1818 2014-02-02 18:02:47 +0800
    1919 \par 修改时间:
    20- 2021-03-01 19:58 +0800
    20+ 2021-03-26 02:47 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -33,7 +33,7 @@
    3333 // YSLib::IValueHolder, YSLib::AllocatedHolderOperations, any,
    3434 // ystdex::as_const, NPL::forward_as_tuple, uintmax_t, TokenValue, Forms,
    3535 // std::allocator_arg, YSLib::stack, YSLib::vector, std::find_if, TermTags,
    36-// function, TermReference, GetLValueTagsOf, NPL::TryAccessLeaf,
    36+// function, TermReference, GetLValueTagsOf, NPL::TryAccessLeaf, PropagateTo,
    3737 // NPL::IsMovable, in_place_type, InvalidReference, NPL::Deref, IsLeaf,
    3838 // ResolveTerm, ThrowInsufficientTermsError, ThrowListTypeErrorForNonlist,
    3939 // ystdex::update_thunk, NPL::Access, ystdex::retry_on_cond,
    @@ -223,8 +223,10 @@
    223223 yunseq(0, (lf = NPL::make_observer(
    224224 &act.AttachFunction(std::forward<_tParams>(args)).get()), 0)...);
    225225 SetupNextTerm(ctx, term);
    226- // XXX: %A1::RelayCurrentOrDirect is not used to allow the underlying
    227- // handler optimized with %NPL_Impl_NPLA1_Enable_InlineDirect.
    226+ // XXX: %A1::RelayCurrentOrDirect is not used to allow the call to the
    227+ // underlying handler implementation (e.g. %FormContextHandler::CallN)
    228+ // optimized with %NPL_Impl_NPLA1_Enable_InlineDirect remaining the nested
    229+ // call safety.
    228230 return RelaySwitched(ctx, Continuation(std::ref(lf ? *lf : h), ctx));
    229231 #else
    230232
    @@ -317,6 +319,21 @@
    317319 }
    318320 #endif
    319321
    322+//! \since build 915
    323+void
    324+EmplaceReference(TermNode::Container& con, TermNode& o, TermReference& ref,
    325+ bool move)
    326+{
    327+ if(move)
    328+ con.emplace_back(std::move(o.GetContainerRef()),
    329+ ValueObject(std::allocator_arg, con.get_allocator(),
    330+ in_place_type<TermReference>, std::move(ref)));
    331+ else
    332+ con.emplace_back(o.GetContainer(), ValueObject(
    333+ std::allocator_arg, con.get_allocator(), in_place_type<
    334+ TermReference>, BindReferenceTags(ref), ref));
    335+}
    336+
    320337
    321338 //! \since build 891
    322339 //@{
    @@ -508,8 +525,8 @@
    508525 {
    509526 if(sigil != char())
    510527 {
    511- const auto ref_tags(sigil == '&' ? BindReferenceTags(*p)
    512- : p->GetTags());
    528+ const auto ref_tags(PropagateTo(sigil == '&'
    529+ ? BindReferenceTags(*p) : p->GetTags(), o_tags));
    513530
    514531 // XXX: Allocators are not used here on %TermReference for
    515532 // performance in most cases.
    @@ -655,7 +672,8 @@
    655672
    656673 if(n_p > 0)
    657674 {
    658- const auto& back(NPL::Deref(std::prev(last)));
    675+ const auto&
    676+ back(ReferenceTerm(NPL::Deref(std::prev(last))));
    659677
    660678 // NOTE: Empty list lvalue arguments shall not be matched
    661679 // here.
    @@ -694,10 +712,15 @@
    694712 {
    695713 const auto ref_tags(p_ref->GetTags());
    696714
    715+ // NOTE: Drop the temporary tag unconditionally.
    716+ // Even a list is a prvalue, its element cannot
    717+ // be a prvalue being matched.
    697718 tags = (tags
    698719 & ~(TermTags::Unique | TermTags::Temporary))
    699720 | (ref_tags & TermTags::Unique);
    700- tags |= ref_tags & TermTags::Nonmodifying;
    721+ // NOTE: Propagate %TermTags::Nonmodifying to
    722+ // the referent.
    723+ tags = PropagateTo(tags, ref_tags);
    701724 }
    702725 MatchSubterms(t.begin(), last, nd, nd.begin(), tags,
    703726 p_ref ? p_ref->GetEnvironmentReference()
    @@ -889,7 +912,7 @@
    889912 return DoAdministratives(cs.EvaluateList, term, ctx);
    890913
    891914 // XXX: This may be slightly more efficient, and more importantly,
    892- // respecting to nested call safety on %ReduceOnce for the thunked
    915+ // respecting to the nested call safety on %ReduceOnce for the thunked
    893916 // implementation well by only allow one level of direct recursion.
    894917 auto term_ref(ystdex::ref(term));
    895918
    @@ -1035,7 +1058,6 @@
    10351058 return ReduceOnce(term, ctx);
    10361059 }
    10371060
    1038-
    10391061 ReductionStatus
    10401062 ReduceToReferenceList(TermNode& term, ContextNode& ctx, TermNode& tm)
    10411063 {
    @@ -1044,50 +1066,69 @@
    10441066 if(IsList(nd))
    10451067 {
    10461068 // XXX: As %BindParameterObject.
    1047- const bool temp(!p_ref || p_ref->IsTemporary());
    1048-
    1049- if(temp || p_ref->IsMovable())
    1069+ if(!p_ref || p_ref->IsMovable())
    10501070 // NOTE: This allows %nd owned by %term.
    10511071 term.MoveContainer(std::move(nd));
    10521072 else
    10531073 {
    10541074 const auto a(term.get_allocator());
    10551075 TermNode::Container con(a);
    1056- const bool can_modify(!p_ref || p_ref->IsModifiable());
    10571076 const auto& r_env(p_ref ? p_ref->GetEnvironmentReference()
    10581077 : ctx.WeakenRecord());
    1059- auto o_tags(p_ref ? p_ref->GetTags()
    1060- & (TermTags::Unique | TermTags::Nonmodifying)
    1061- : TermTags::Temporary);
    1078+ const auto o_tags(p_ref ? p_ref->GetTags() & (TermTags::Unique
    1079+ | TermTags::Nonmodifying) : TermTags::Temporary);
    10621080
    10631081 // XXX: As %BindParameter.
    10641082 for(auto& o : nd)
    1065- {
    10661083 if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    1067- {
    1068- if(can_modify && temp)
    1069- con.emplace_back(std::move(o.GetContainerRef()),
    1070- ValueObject(std::allocator_arg, a,
    1071- in_place_type<TermReference>, std::move(*p)));
    1072- else
    1073- con.emplace_back(o.GetContainer(), ValueObject(
    1074- std::allocator_arg, a, in_place_type<
    1075- TermReference>, BindReferenceTags(*p), *p));
    1076- }
    1077- else if(can_modify && temp)
    1084+ EmplaceReference(con, o, *p, !p_ref);
    1085+ else if(p_ref)
    1086+ con.emplace_back(TermNode::Container(o.get_allocator()),
    1087+ ValueObject(std::allocator_arg, a,
    1088+ in_place_type<TermReference>,
    1089+ GetLValueTagsOf(o.Tags | o_tags), o, r_env));
    1090+ else
    10781091 {
    10791092 con.emplace_back(std::move(o.GetContainerRef()),
    10801093 std::move(o.Value));
    10811094 con.back().Tags |= TermTags::Temporary;
    10821095 }
    1096+ con.swap(term.GetContainerRef());
    1097+ }
    1098+ return ReductionStatus::Retained;
    1099+ }
    1100+ else
    1101+ ThrowListTypeErrorForNonlist(nd, p_ref);
    1102+ }, tm);
    1103+}
    1104+
    1105+ReductionStatus
    1106+ReduceToReferenceUList(TermNode& term, TermNode& tm)
    1107+{
    1108+ // XXX: As %ReduceToReferenceList.
    1109+ return ResolveTerm(
    1110+ [&](TermNode& nd, ResolvedTermReferencePtr p_ref) YB_FLATTEN{
    1111+ if(IsList(nd))
    1112+ {
    1113+ if(p_ref)
    1114+ {
    1115+ const auto a(term.get_allocator());
    1116+ TermNode::Container con(a);
    1117+ const auto add_tags(p_ref->GetTags() | TermTags::Unique
    1118+ | TermTags::Temporary);
    1119+
    1120+ for(auto& o : nd)
    1121+ if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    1122+ EmplaceReference(con, o, *p, {});
    10831123 else
    10841124 con.emplace_back(TermNode::Container(o.get_allocator()),
    1085- ValueObject(std::allocator_arg, a,
    1086- in_place_type<TermReference>,
    1087- GetLValueTagsOf(o.Tags | o_tags), o, r_env));
    1088- }
    1125+ ValueObject(std::allocator_arg, a, in_place_type<
    1126+ TermReference>, o.Tags | add_tags, o,
    1127+ p_ref->GetEnvironmentReference()));
    10891128 con.swap(term.GetContainerRef());
    10901129 }
    1130+ else
    1131+ term.MoveContainer(std::move(nd));
    10911132 return ReductionStatus::Retained;
    10921133 }
    10931134 else
    @@ -1175,7 +1216,7 @@
    11751216 {
    11761217 YAssertNonnull(id.data());
    11771218
    1178- auto term(NPL::AsTermNode(a));
    1219+ TermNode term(a);
    11791220
    11801221 if(!id.empty())
    11811222 switch(CategorizeBasicLexeme(id))
    @@ -1214,7 +1255,7 @@
    12141255 // information mixed into the values of %TokenValue.
    12151256 YAssertNonnull(id.data());
    12161257
    1217- auto term(NPL::AsTermNode(a));
    1258+ TermNode term(a);
    12181259
    12191260 if(!id.empty())
    12201261 switch(CategorizeBasicLexeme(id))
    @@ -1255,7 +1296,7 @@
    12551296 return RelayCurrentOrDirect(ctx, Continuation(std::ref(Handler), ctx),
    12561297 term);
    12571298 return A1::RelayCurrentNext(ctx, term,
    1258- Continuation([&](TermNode& t, ContextNode& c){
    1299+ Continuation([](TermNode& t, ContextNode& c){
    12591300 YAssert(!t.empty(), "Invalid term found.");
    12601301 ReduceChildrenOrderedAsyncUnchecked(std::next(t.begin()), t.end(), c);
    12611302 return ReductionStatus::Partial;
    @@ -1363,7 +1404,8 @@
    13631404 if(const auto p = NPL::TryAccessLeaf<const TermReference>(bound))
    13641405 {
    13651406 p_rterm = &p->get();
    1366- // XXX: It is assumed that %term is not an ancestor of %bound.
    1407+ // XXX: It is assumed that %term is not an ancestor of %bound. The
    1408+ // source term tags are ignored.
    13671409 term.SetContent(bound.GetContainer(),
    13681410 EnsureLValueReference(TermReference(*p)));
    13691411 }
    diff -r 92d04ed3856a -r 37835df0ac3b YFramework/source/NPL/NPLA1Forms.cpp
    --- a/YFramework/source/NPL/NPLA1Forms.cpp Sat Mar 13 14:46:42 2021 +0800
    +++ b/YFramework/source/NPL/NPLA1Forms.cpp Fri Mar 26 22:43:02 2021 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA1Forms.cpp
    1212 \ingroup NPL
    1313 \brief NPLA1 语法形式。
    14-\version r21603
    14+\version r21958
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 882
    1717 \par 创建时间:
    1818 2014-02-15 11:19:51 +0800
    1919 \par 修改时间:
    20- 2021-03-13 14:15 +0800
    20+ 2021-03-26 03:34 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -608,11 +608,11 @@
    608608
    609609 //! \since build 781
    610610 YB_ATTR_nodiscard YB_PURE string
    611-CheckEnvFormal(const TermNode& eterm)
    611+CheckEnvFormal(const TermNode& term)
    612612 {
    613- const auto& term(ReferenceTerm(eterm));
    614-
    615- if(const auto p = TermToNamePtr(term))
    613+ const auto& nd(ReferenceTerm(term));
    614+
    615+ if(const auto p = TermToNamePtr(nd))
    616616 {
    617617 if(!IsIgnore(*p))
    618618 {
    @@ -622,7 +622,7 @@
    622622 }
    623623 }
    624624 else
    625- ThrowInvalidSymbolType(term, "environment formal parameter");
    625+ ThrowInvalidSymbolType(nd, "environment formal parameter");
    626626 return {};
    627627 }
    628628
    @@ -751,13 +751,6 @@
    751751 \since build 909
    752752 */
    753753 ReductionStatus(&call)(const VauHandler&, TermNode&, ContextNode&);
    754-#if NPL_Impl_NPLA1_Enable_TCO
    755- /*!
    756- \brief 保存环境例程。
    757- \since build 909
    758- */
    759- void(&save)(const VauHandler&, TCOAction&);
    760-#endif
    761754
    762755 public:
    763756 //! \brief 返回时不提升项以允许返回引用。
    @@ -776,9 +769,6 @@
    776769 p_eval_struct(ShareMoveTerm(ystdex::exchange(term,
    777770 NPL::AsTermNode(term.get_allocator())))),
    778771 call(eformal.empty() ? CallStatic : CallDynamic),
    779-#if NPL_Impl_NPLA1_Enable_TCO
    780- save(owning ? SaveOwning : SaveNothing),
    781-#endif
    782772 NoLifting(nl)
    783773 {}
    784774 //! \since build 909
    @@ -791,10 +781,6 @@
    791781 p_eval_struct(ShareMoveTerm(ystdex::exchange(term,
    792782 NPL::AsTermNode(term.get_allocator())))),
    793783 call(eformal.empty() ? CallStatic : CallDynamic),
    794-#if NPL_Impl_NPLA1_Enable_TCO
    795- // TODO: Optimize?
    796- save(SaveList),
    797-#endif
    798784 NoLifting(nl)
    799785 {}
    800786
    @@ -871,15 +857,17 @@
    871857 static void
    872858 CheckParameterTree(const TermNode& term)
    873859 {
    874- for(const auto& child : term)
    860+ auto& nd(ReferenceTerm(term));
    861+
    862+ for(const auto& child : nd)
    875863 CheckParameterTree(child);
    876- if(term.Value)
    864+ if(nd.Value)
    877865 {
    878- if(const auto p = TermToNamePtr(term))
    866+ if(const auto p = TermToNamePtr(nd))
    879867 CheckVauSymbol(*p, "parameter in a parameter tree",
    880868 IsIgnoreOrNPLASymbol(*p));
    881869 else
    882- ThrowInvalidSymbolType(term, "parameter tree node");
    870+ ThrowInvalidSymbolType(nd, "parameter tree node");
    883871 }
    884872 }
    885873
    @@ -901,9 +889,6 @@
    901889 // NOTE: Forming beta-reducible terms using parameter binding, to
    902890 // substitute them as arguments for later closure reduction.
    903891 // XXX: Do not lift terms if provable to be safe?
    904- // NOTE: Since now binding does not rely on temporaries stored elsewhere
    905- // (by using %TermTags::Temporary instead), this should be safe even
    906- // with TCO.
    907892 // NOTE: The environment is assumed not frozen, so no need to use
    908893 // %BindParameterChecked.
    909894 BindParameter(ctx.GetRecordPtr(), NPL::Deref(p_formals), term);
    @@ -914,15 +899,16 @@
    914899 p_formals->size());
    915900 });
    916901 #endif
    917- // NOTE: The static environment is bound as the base of the local
    918- // environment by setting the parent environment pointer.
    919- ctx.GetRecordRef().Parent = parent;
    920902 AssertNextTerm(ctx, term);
    921903
    922904 // NOTE: Saved the no lift flag here to avoid branching in the
    923905 // following implementation.
    924906 const bool no_lift(NoLifting);
    925907
    908+ // NOTE: Since now binding does not rely on temporary objects stored
    909+ // elsewhere (by using %TermTags::Temporary instead), setting %term
    910+ // immediately after the call to %BindParameter should be safe even
    911+ // with TCO.
    926912 // NOTE: Because the only possible (non-administrative) owner of the
    927913 // evaluation structure visible in the object language is the combiner
    928914 // object which is not possible here in the %term, the evaluation
    @@ -931,9 +917,11 @@
    931917 // instead of %LiftOther. See %ReduceCombinedBranch in NPLA1.cpp for
    932918 // details.
    933919 // XXX: Using %LiftOtherOrCopy is less efficient.
    934- // XXX: Assume the last function is this object.
    935920 if(move)
    936921 {
    922+ // NOTE: The static environment is bound as the base of the local
    923+ // environment by setting the parent environment pointer.
    924+ ctx.GetRecordRef().Parent = std::move(parent);
    937925 // NOTE: The evaluation structure does not need to be saved to the
    938926 // continuation, since it would be used immediately in
    939927 // the call to %RelayForCall.
    @@ -942,19 +930,23 @@
    942930
    943931 auto& act(RefTCOAction(ctx));
    944932
    945- save(*this, act);
    946- // XXX: This would make '*this' invalid.
    933+ // XXX: Assume the last function being handled in %TCOAction is this
    934+ // object. This would make '*this' invalid.
    947935 yunused(act.MoveFunction());
    948936 #endif
    949937 }
    950938 else
    939+ {
    940+ ctx.GetRecordRef().Parent = parent;
    951941 term.SetContent(Deref(p_eval_struct));
    942+ }
    952943 // NOTE: The precondition is same to the last call in
    953944 // %EvalImplUnchecked.
    954945 return RelayForCall(ctx, term, std::move(gd), no_lift);
    955946 }
    956947
    957- //! \since build 909
    948+public:
    949+ //! \since build 915
    958950 YB_ATTR_nodiscard YB_PURE static ValueObject
    959951 MakeParentSingle(const shared_ptr<Environment>& p_env, bool owning)
    960952 {
    @@ -964,35 +956,6 @@
    964956 return p_env;
    965957 return EnvironmentReference(p_env);
    966958 }
    967-
    968-#if NPL_Impl_NPLA1_Enable_TCO
    969- static void
    970- SaveNothing(const VauHandler&, TCOAction&)
    971- {}
    972-
    973- static void
    974- SaveList(const VauHandler& vau, TCOAction& act)
    975- {
    976- for(auto& vo : vau.parent.GetObject<EnvironmentList>())
    977- {
    978- if(const auto p = vo.AccessPtr<shared_ptr<Environment>>())
    979- SaveOwningPtr(*p, act);
    980- }
    981- }
    982-
    983- static void
    984- SaveOwning(const VauHandler& vau, TCOAction& act)
    985- {
    986- SaveOwningPtr(vau.parent.GetObject<shared_ptr<Environment>>(), act);
    987- }
    988-
    989- static void
    990- SaveOwningPtr(shared_ptr<Environment>& p_static, TCOAction& act)
    991- {
    992- if(p_static.use_count() == 1)
    993- act.RecordList.emplace_front(ContextHandler(), std::move(p_static));
    994- }
    995-#endif
    996959 };
    997960
    998961
    @@ -1344,6 +1307,36 @@
    13441307 }, term);
    13451308 }
    13461309
    1310+//! \since build 915
    1311+void
    1312+LiftCopyPropagate(TermNode& term, TermNode& tm, const TermReference& ref)
    1313+{
    1314+ // XXX: Similar to the implementation of %ReduceToReference in NPLA.cpp.
    1315+ term.CopyContent(tm);
    1316+ // NOTE: Propagate tags if it is a term reference.
    1317+ if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
    1318+ p->SetTags(PropagateTo(p->GetTags(), ref.GetTags()));
    1319+ // XXX: Term tags are currently not respected in prvalues.
    1320+}
    1321+
    1322+//! \since build 915
    1323+void
    1324+LiftOtherOrCopyPropagate(TermNode& term, TermNode& tm,
    1325+ ResolvedTermReferencePtr p_ref)
    1326+{
    1327+ if(NPL::IsMovable(p_ref))
    1328+ // XXX: Using %LiftOther (from %LiftOtherOrCopy) instead of
    1329+ // %LiftTermOrCopy is safe, because the referent is not allowed to have
    1330+ // cyclic reference to %term. And %LiftTermOrCopy is in that case is
    1331+ // still inapproiate anyway because copy should be elided in a
    1332+ // forwarding operation.
    1333+ LiftOther(term, tm);
    1334+ else
    1335+ // XXX: The call to %NPL::IsMovable has guarantees %p_ref is nonnull
    1336+ // here.
    1337+ LiftCopyPropagate(term, tm, NPL::Deref(p_ref));
    1338+}
    1339+
    13471340 //! \since build 914
    13481341 ReductionStatus
    13491342 ReduceToFirst(TermNode& term, TermNode& tm, ResolvedTermReferencePtr p_ref)
    @@ -1356,8 +1349,7 @@
    13561349 {
    13571350 if(list_not_move)
    13581351 {
    1359- // NOTE: As %LiftOtherOrCopy.
    1360- term.CopyContent(tm);
    1352+ LiftCopyPropagate(term, tm, NPL::Deref(p_ref));
    13611353 return ReductionStatus::Retained;
    13621354 }
    13631355 if(!p->IsReferencedLValue())
    @@ -1563,6 +1555,41 @@
    15631555 "Expected exact one term as name to be undefined.");
    15641556 }
    15651557
    1558+//! \since build 915
    1559+//@{
    1560+template<typename... _tParams>
    1561+YB_ATTR_nodiscard YB_PURE inline ContextHandler
    1562+MakeForm(TermNode::allocator_type a, _tParams&&... args)
    1563+{
    1564+ return ContextHandler(std::allocator_arg, a,
    1565+ FormContextHandler(yforward(args)...));
    1566+}
    1567+template<typename... _tParams>
    1568+YB_ATTR_nodiscard YB_PURE inline ContextHandler
    1569+MakeForm(TermNode& term, _tParams&&... args)
    1570+{
    1571+ return MakeForm(term.get_allocator(), yforward(args)...);
    1572+}
    1573+
    1574+template<typename... _tParams>
    1575+YB_ATTR_nodiscard YB_PURE inline TermNode
    1576+AsForm(TermNode::allocator_type a, _tParams&&... args)
    1577+{
    1578+ // XXX: Allocators are not used on %FormContextHandler for performance in
    1579+ // most cases.
    1580+#if true
    1581+ return NPL::AsTermNode(a, std::allocator_arg, a,
    1582+ in_place_type<ContextHandler>, std::allocator_arg, a,
    1583+ FormContextHandler(yforward(args)...));
    1584+#elif true
    1585+ return NPL::AsTermNode(a, in_place_type<ContextHandler>, std::allocator_arg,
    1586+ a, FormContextHandler(yforward(args)...));
    1587+#else
    1588+ return NPL::AsTermNode(a, MakeForm(a, yforward(args)...));
    1589+#endif
    1590+}
    1591+//@}
    1592+
    15661593 //! \since build 888
    15671594 template<typename _func>
    15681595 inline auto
    @@ -1588,7 +1615,7 @@
    15881615 LambdaImpl(TermNode& term, ContextNode& ctx, bool no_lift)
    15891616 {
    15901617 return CreateFunction(term, [&, no_lift]{
    1591- term.Value = CheckFunctionCreation([&]() -> ContextHandler{
    1618+ term.Value = CheckFunctionCreation([&]{
    15921619 // NOTE: Protect the reference count of the environment at first.
    15931620 auto p_env(ctx.ShareRecord());
    15941621 auto i(term.begin());
    @@ -1597,15 +1624,15 @@
    15971624 term.erase(term.begin(), ++i);
    15981625 // NOTE: The wrapping count 1 implies strict evaluation of arguments
    15991626 // in %FormContextHandler::operator().
    1600- return FormContextHandler(VauHandler({},
    1601- std::move(formals), std::move(p_env), {}, term, no_lift), 1);
    1627+ return MakeForm(term, VauHandler({}, std::move(formals),
    1628+ std::move(p_env), {}, term, no_lift), 1U);
    16021629 });
    16031630 return ReductionStatus::Clean;
    16041631 }, 1);
    16051632 }
    16061633
    1607-//! \since build 842
    1608-YB_ATTR_nodiscard ContextHandler
    1634+//! \since build 915
    1635+YB_ATTR_nodiscard VauHandler
    16091636 CreateVau(TermNode& term, bool no_lift, TNIter i,
    16101637 shared_ptr<Environment>&& p_env, bool owning)
    16111638 {
    @@ -1615,22 +1642,8 @@
    16151642 term.erase(term.begin(), ++i);
    16161643 // XXX: Allocators are not used on %FormContextHandler for performance in
    16171644 // most cases.
    1618- return FormContextHandler(VauHandler(std::move(eformal), std::move(formals),
    1619- std::move(p_env), owning, term, no_lift));
    1620-}
    1621-
    1622-//! \since build 909
    1623-YB_ATTR_nodiscard ContextHandler
    1624-CreateVauWithParent(TermNode& term, bool no_lift, TNIter i,
    1625- ValueObject&& parent)
    1626-{
    1627- auto formals(ShareMoveTerm(NPL::Deref(++i)));
    1628- auto eformal(CheckEnvFormal(NPL::Deref(++i)));
    1629-
    1630- term.erase(term.begin(), ++i);
    1631- // XXX: Ditto.
    1632- return FormContextHandler(VauHandler(0, std::move(eformal),
    1633- std::move(formals), std::move(parent), term, no_lift));
    1645+ return VauHandler(std::move(eformal), std::move(formals),
    1646+ std::move(p_env), owning, term, no_lift);
    16341647 }
    16351648
    16361649 ReductionStatus
    @@ -1638,8 +1651,8 @@
    16381651 {
    16391652 return CreateFunction(term, [&, no_lift]{
    16401653 term.Value = CheckFunctionCreation([&]{
    1641- return
    1642- CreateVau(term, no_lift, term.begin(), ctx.ShareRecord(), {});
    1654+ return MakeForm(term,
    1655+ CreateVau(term, no_lift, term.begin(), ctx.ShareRecord(), {}));
    16431656 });
    16441657 return ReductionStatus::Clean;
    16451658 }, 2);
    @@ -1654,10 +1667,26 @@
    16541667
    16551668 return ReduceSubsequent(tm, ctx,
    16561669 A1::NameTypedReducerHandler([&, i, no_lift]{
    1657- term.Value = CheckFunctionCreation([&]{
    1658- return ResolveTerm([&](TermNode& nd,
    1659- ResolvedTermReferencePtr p_ref) -> ContextHandler{
    1660- if(!IsExtendedList(nd))
    1670+ term.Value = CheckFunctionCreation([&]() YB_FLATTEN{
    1671+ return MakeForm(term, ResolveTerm([&](TermNode& nd,
    1672+ ResolvedTermReferencePtr p_ref) -> VauHandler{
    1673+ if(IsList(nd))
    1674+ {
    1675+ // NOTE: The parent check is implied in the constructor
    1676+ // of %VauHandler.
    1677+ auto parent(MakeEnvironmentParent(nd.begin(), nd.end(),
    1678+ nd.get_allocator(), !NPL::IsMovable(p_ref)));
    1679+ auto j(i);
    1680+ // XXX: As %CreateVau.
    1681+ auto formals(ShareMoveTerm(NPL::Deref(++j)));
    1682+ auto eformal(CheckEnvFormal(NPL::Deref(++j)));
    1683+
    1684+ term.erase(term.begin(), ++j);
    1685+ return VauHandler(0, std::move(eformal),
    1686+ std::move(formals), std::move(parent), term,
    1687+ no_lift);
    1688+ }
    1689+ if(IsLeaf(nd))
    16611690 {
    16621691 // NOTE: The environment check is used as the parent
    16631692 // check when the parent is an environment.
    @@ -1668,18 +1697,11 @@
    16681697 return CreateVau(term, no_lift, i,
    16691698 std::move(p_env_pr.first), p_env_pr.second);
    16701699 }
    1671- if(IsList(nd))
    1672- // NOTE: The parent check is implied in the constructor
    1673- // of %VauHandler.
    1674- return CreateVauWithParent(term, no_lift, i,
    1675- MakeEnvironmentParent(nd.begin(),
    1676- nd.end(), nd.get_allocator(),
    1677- !NPL::IsMovable(p_ref)));
    16781700 ThrowInvalidEnvironmentType(nd, p_ref);
    1679- }, tm);
    1701+ }, tm));
    16801702 });
    16811703 return ReductionStatus::Clean;
    1682- }, "eval-vau"));
    1704+ }, "eval-vau-parent"));
    16831705 }, 3);
    16841706 }
    16851707 //@}
    @@ -1702,11 +1724,13 @@
    17021724 throw TypeError(ystdex::sfmt("Wrapping failed with type '%s'.", tp.name()));
    17031725 }
    17041726
    1727+//! \since build 915
    17051728 ReductionStatus
    1706-WrapH(TermNode& term, ContextHandler h)
    1729+WrapH(TermNode& term, FormContextHandler h)
    17071730 {
    17081731 // XXX: Allocators are not used here for performance in most cases.
    1709- term.Value = std::move(h);
    1732+ term.Value = ContextHandler(std::allocator_arg, term.get_allocator(),
    1733+ std::move(h));
    17101734 return ReductionStatus::Clean;
    17111735 }
    17121736
    @@ -1733,9 +1757,7 @@
    17331757 if(p_ref)
    17341758 return ReduceForCombinerRef(term, *p_ref, fch.Handler, n);
    17351759 // XXX: Ditto.
    1736- term.Value = ContextHandler(std::allocator_arg, term.get_allocator(),
    1737- FormContextHandler(std::move(fch.Handler), n));
    1738- return ReductionStatus::Clean;
    1760+ return WrapH(term, FormContextHandler(std::move(fch.Handler), n));
    17391761 }
    17401762
    17411763 template<typename _func, typename _func2>
    @@ -2531,6 +2553,7 @@
    25312553 });
    25322554 }
    25332555
    2556+
    25342557 ReductionStatus
    25352558 LetCore(TermNode& term, ContextNode& ctx, bool no_lift, bool with_env)
    25362559 {
    @@ -2552,7 +2575,7 @@
    25522575 if(with_env)
    25532576 ++i;
    25542577 ++i;
    2555- return Combine<NonTailCall>::ReduceCallSubsequent(*term.emplace([&]{
    2578+ return A1::ReduceCurrentNext(*term.emplace([&]{
    25562579 const auto a(term.get_allocator());
    25572580 TermNode::Container tcon(a);
    25582581
    @@ -2561,78 +2584,156 @@
    25612584 // NOTE: Now subterms are 'bindings', optional 'e',
    25622585 // originally bound 'bindings', 'body'.
    25632586 tcon.clear();
    2564- tcon.push_back(NPL::AsTermNode(a, ContextHandler(std::allocator_arg, a,
    2565- FormContextHandler(Forms::ListExtractFirst))));
    2587+ tcon.emplace_back();
    25662588 tcon.push_back(nterm);
    2589+ PrepareFoldRList(tcon.back());
    25672590 return tcon;
    2568- }()), ctx, d, A1::NameTypedReducerHandler([&, d, no_lift, with_env]{
    2591+ }()), ctx, DoListExtractFirst,
    2592+ A1::NameTypedReducerHandler([&, d, no_lift, with_env]{
    25692593 // NOTE: Now subterms are 'bindings', optional 'e', originally bound
    25702594 // 'bindings', 'body', extracted 'formals' for the lambda abstraction.
    25712595 const auto a(nterm.get_allocator());
    25722596
    2597+ PrepareFoldRList(nterm);
    25732598 // NOTE: Replace 'bindings' (%nterm) directly to the call expression, as
    25742599 // 'bindings' is not needed after this call. Note %nterm.Tags is
    25752600 // uninterested.
    25762601 nterm.emplace(ystdex::exchange(nterm, TermNode(a)));
    2577- nterm.GetContainerRef().push_front(NPL::AsTermNode(a,
    2578- ContextHandler(std::allocator_arg, a,
    2579- FormContextHandler(Forms::ListExtractRestFwd))));
    2580- return Combine<NonTailCall>::ReduceCallSubsequent(nterm, ctx, d,
    2581- A1::NameTypedReducerHandler([&, d, no_lift, with_env]{
    2602+ nterm.GetContainerRef().emplace_front();
    2603+ // TODO: Blocked. Use C++14 lambda initializers to simplify the
    2604+ // implementation.
    2605+ return A1::ReduceCurrentNext(nterm, ctx, DoListExtractRestFwd,
    2606+ A1::NameTypedReducerHandler([&, no_lift, with_env]() YB_FLATTEN{
    25822607 // NOTE: Now subterms are extracted arguments for the call,
    25832608 // optional 'e', originally bound 'bindings', 'body',
    25842609 // extracted 'formals' for the lambda abstraction.
    2610+ const auto call_next([&, no_lift]{
    2611+ // NOTE: Now subterms are extracted arguments for the call plus
    2612+ // the parent in %Value, unused 'bindings', 'body', extracted
    2613+ // 'formals' for the lambda abstraction.
    2614+ YAssert(term.size() == 4, "Invalid term found.");
    2615+ VauHandler::CheckParameterTree(con.back());
    2616+ return A1::RelayCurrentNext(ctx, con.front(),
    2617+ Continuation([](TermNode& t, ContextNode& c) YB_FLATTEN{
    2618+ ReduceChildren(t, c);
    2619+ return ReductionStatus::Partial;
    2620+ }, ctx), NPL::ToReducer(ctx.get_allocator(),
    2621+ A1::NameTypedReducerHandler([&, no_lift]() YB_FLATTEN{
    2622+ const auto let_call([&]{
    2623+ EnvironmentGuard
    2624+ egd(ctx, NPL::SwitchToFreshEnvironment(ctx));
    2625+ auto j(con.begin());
    2626+ auto& operand(*j);
    2627+
    2628+ ++j;
    2629+
    2630+ auto& body(*++j);
    2631+
    2632+ ctx.GetRecordRef().Parent = std::move(operand.Value);
    2633+ operand.Value.Clear();
    2634+ BindParameter(ctx.GetRecordPtr(), *++j, operand);
    2635+ // NOTE: Set 'body'.
    2636+ LiftOther(term, body);
    2637+#if NPL_Impl_NPLA1_Enable_Thunked
    2638+ SetupNextTerm(ctx, term);
    2639+#endif
    2640+ return RelayForCall(ctx, term, std::move(egd), no_lift);
    2641+ });
    2642+#if !NPL_Impl_NPLA1_Enable_TCO
    2643+ auto gd(ystdex::unique_guard([&]() ynothrow{
    2644+ term.Clear();
    2645+ }));
    2646+#endif
    2647+#if NPL_Impl_NPLA1_Enable_Thunked
    2648+# if !NPL_Impl_NPLA1_Enable_TCO
    2649+
    2650+ RelaySwitched(ctx, A1::NameTypedReducerHandler(
    2651+ std::bind([&](decltype(gd)& g){
    2652+ ystdex::dismiss(g);
    2653+ return RegularizeTerm(term, ctx.LastStatus);
    2654+ }, std::move(gd)), "eval-let-combine-return"));
    2655+# endif
    2656+ return let_call();
    2657+#else
    2658+ const auto res(RegularizeTerm(term, let_call()));
    2659+
    2660+ ystdex::dismiss(gd);
    2661+ return res;
    2662+#endif
    2663+ }, "eval-let-combine-operator")));
    2664+ });
    2665+
    25852666 auto j(term.begin());
    2586-
    2587- if(with_env)
    2588- ++j;
    2589- // NOTE: The original bound 'bindings' is not needed now.
    2590- j = con.erase(++j);
    2591-
    2592- auto& body(*j);
    2593- auto& body_con(body.GetContainerRef());
    2594- const auto ab(body_con.get_allocator());
    2595-
    2596- if(with_env)
    2667+ // NOTE: The original bound 'bindings' is not needed now. However,
    2668+ // it is not reused to avoid redundant branch check of %with_env.
    2669+ // Instead, the %Value in the 1st subterm is reused.
    2670+ auto& parent(j->Value);
    2671+
    2672+ YAssert(!parent, "Invalid value found in list result.");
    2673+ if(!with_env)
    25972674 {
    2598- body_con.push_front(NPL::AsTermNode(ab, TokenValue("#ignore")));
    2599- body_con.splice(body_con.begin(), con, ++j);
    2600- j = term.begin();
    2601- body_con.splice(body_con.begin(), con, ++j);
    2602- body_con.push_front(NPL::AsTermNode(ab,
    2603- ContextHandler(std::allocator_arg, ab, FormContextHandler(
    2604- no_lift ? Forms::VauWithEnvironmentRef
    2605- : Forms::VauWithEnvironment))));
    2606- body.emplace(ystdex::exchange(body, TermNode(ab)));
    2607- body_con.push_front(NPL::AsTermNode(ab,
    2608- ContextHandler(std::allocator_arg, ab,
    2609- FormContextHandler(Forms::Wrap, 1))));
    2675+ parent = ctx.ShareRecord();
    2676+ return call_next();
    26102677 }
    2611- else
    2612- {
    2613- body_con.splice(body_con.begin(), con, ++j);
    2614- body_con.push_front(NPL::AsTermNode(ab,
    2615- ContextHandler(std::allocator_arg, ab, FormContextHandler(
    2616- no_lift ? Forms::LambdaRef : Forms::Lambda))));
    2617- }
    2618- return Combine<NonTailCall>::ReduceCallSubsequent(body, ctx, d,
    2619- A1::NameTypedReducerHandler([&]{
    2620- // NOTE: Now subterms are extracted arguments for the call,
    2621- // the constructed lambda abstraction.
    2622- YAssert(term.size() == 2, "Invalid term found.");
    2623- con.splice(con.end(), con.front().GetContainerRef());
    2624- // NOTE: The head term is needed if there is no argument.
    2625- con.front().Clear();
    2626- SetupNextTerm(ctx, term);
    2627- // XXX: As %RelayForCall without guard switch. This also
    2628- // requires that %no_lift handled by the inner abstraction.
    2629- return A1::RelayCurrentOrDirect(ctx,
    2630- std::ref(ContextState::Access(ctx).ReduceOnce), term);
    2631- }, "eval-let-call"));
    2678+ ++j;
    2679+ return ReduceSubsequent(NPL::Deref(j), ctx,
    2680+ A1::NameTypedReducerHandler([&, j, call_next]() YB_FLATTEN{
    2681+ // XXX: As %VauWithEnvironmentImpl.
    2682+ ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
    2683+ if(IsList(nd))
    2684+ parent = MakeEnvironmentParent(nd.begin(), nd.end(),
    2685+ nd.get_allocator(), !NPL::IsMovable(p_ref));
    2686+ else if(IsLeaf(nd))
    2687+ {
    2688+ auto p_env_pr(ResolveEnvironment(nd.Value,
    2689+ NPL::IsMovable(p_ref)));
    2690+
    2691+ Environment::EnsureValid(p_env_pr.first);
    2692+ parent = std::move(p_env_pr.first);
    2693+ }
    2694+ else
    2695+ ThrowInvalidEnvironmentType(nd, p_ref);
    2696+ }, *j);
    2697+ con.erase(j);
    2698+ return call_next();
    2699+ }, "eval-let-parent"));
    26322700 }, "eval-let-make-combiner"));
    26332701 }, "eval-let-extract-arguments"));
    26342702 }
    26352703
    2704+//! \since build 915
    2705+void
    2706+ExpireReferenceListLV(TermNode& term, TermNode& nd, const TermReference& ref)
    2707+{
    2708+ if(IsList(nd))
    2709+ {
    2710+ // XXX: As %ReduceToReferenceUList for lvalues in terms of
    2711+ // %BindParameterObject in NPLA1.cpp.
    2712+ const auto a(term.get_allocator());
    2713+ TermNode::Container con(a);
    2714+ const auto& r_env(ref.GetEnvironmentReference());
    2715+ auto o_tags(ref.GetTags() & TermTags::Nonmodifying);
    2716+
    2717+ for(auto& o : nd)
    2718+ {
    2719+ if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    2720+ con.emplace_back(o.GetContainer(), ValueObject(
    2721+ std::allocator_arg, a, in_place_type<TermReference>,
    2722+ BindReferenceTags(*p), *p));
    2723+ else
    2724+ con.emplace_back(TermNode::Container(o.get_allocator()),
    2725+ ValueObject(std::allocator_arg, a, in_place_type<
    2726+ TermReference>, GetLValueTagsOf(o.Tags | o_tags)
    2727+ | TermTags::Unique, o, r_env));
    2728+ }
    2729+ con.swap(term.GetContainerRef());
    2730+ }
    2731+ else
    2732+ ThrowListTypeErrorForNonlist(nd, true);
    2733+ term.Value.Clear(),
    2734+ term.Tags = TermTags::Temporary;
    2735+}
    2736+
    26362737 ReductionStatus
    26372738 LetImpl(TermNode& term, ContextNode& ctx, bool no_lift, bool with_env = {})
    26382739 {
    @@ -2640,6 +2741,7 @@
    26402741 if(FetchArgumentN(term) > (with_env ? 1 : 0))
    26412742 {
    26422743 auto i(term.begin());
    2744+ // NOTE: This is to be the initial content of %nterm in %LetCore.
    26432745 auto& forwarded(*i);
    26442746
    26452747 if(with_env)
    @@ -2657,28 +2759,15 @@
    26572759 return LetCore(term, ctx, no_lift, with_env);
    26582760 }
    26592761 else
    2660- {
    2661- // NOTE: This shall behave as an lvalue.
    2662- p->RemoveTags(TermTags::Unique | TermTags::Temporary);
    2663- // XXX: Assume synchrounous.
    2664- ReduceToReferenceList(forwarded, ctx, bindings);
    2665- }
    2762+ ExpireReferenceListLV(forwarded, p->get(), *p);
    26662763 }
    26672764 else
    26682765 {
    2669- // NOTE: Ditto.
    26702766 forwarded.Value = TermReference(GetLValueTagsOf(bindings.Tags)
    26712767 & ~TermTags::Unique, bindings, ctx.GetRecordPtr());
    2672- // NOTE: Ditto.
    2673- ReduceToReferenceList(forwarded, ctx, forwarded);
    2768+ ExpireReferenceListLV(forwarded, bindings,
    2769+ forwarded.Value.GetObject<const TermReference>());
    26742770 }
    2675- for(auto& x : forwarded.GetContainerRef())
    2676- // NOTE: The element 'x' should always owns a %Value of
    2677- // %TermReference.
    2678- NPL::Deref(
    2679- NPL::TryAccessLeaf<TermReference>(x)).AddTags(TermTags::Unique);
    2680- forwarded.Tags = TermTags::Temporary,
    2681- forwarded.Value.Clear();
    26822771 return LetCore(term, ctx, no_lift, with_env);
    26832772 }
    26842773 else
    @@ -2883,8 +2972,6 @@
    28832972 auto& op(*i);
    28842973 auto& appv(*++i);
    28852974
    2886- // TODO: Blocked. Use C++14 lambda initializers to simplify the
    2887- // implementation.
    28882975 return NPL::ResolveTerm(
    28892976 [&](TermNode& nd, ResolvedTermReferencePtr p_ref) YB_FLATTEN{
    28902977 if(IsBranchedList(nd))
    @@ -2944,12 +3031,7 @@
    29443031 FirstFwd(TermNode& term)
    29453032 {
    29463033 return FirstOrVal(term, [&](TermNode& tm, ResolvedTermReferencePtr p_ref){
    2947- // XXX: Using %LiftOtherOrCopy instead of %LiftTermOrCopy is safe,
    2948- // because the referent is not allowed to have cyclic reference to
    2949- // %term. And %LiftTermOrCopy is in that case is still inapproiate
    2950- // anyway because copy should be elided in a forwarding operation.
    2951- // XXX: Term tags are currently not respected in prvalues.
    2952- LiftOtherOrCopy(term, tm, NPL::IsMovable(p_ref));
    3034+ LiftOtherOrCopyPropagate(term, tm, p_ref);
    29533035 return ReductionStatus::Retained;
    29543036 });
    29553037 }
    @@ -2974,7 +3056,7 @@
    29743056 {
    29753057 return RestOrVal(term, [](TermNode&) ynothrow{},
    29763058 [&](TermNode& dst, TermNode& tm, ResolvedTermReferencePtr p_ref){
    2977- LiftOtherOrCopy(dst, tm, NPL::IsMovable(p_ref));
    3059+ LiftOtherOrCopyPropagate(dst, tm, p_ref);
    29783060 });
    29793061 }
    29803062
    @@ -3308,7 +3390,6 @@
    33083390 ReductionStatus
    33093391 MakeEncapsulationType(TermNode& term)
    33103392 {
    3311- const auto tag(in_place_type<ContextHandler>);
    33123393 const auto a(term.get_allocator());
    33133394 // NOTE: The %p_type handle can be extended to point to a metadata block.
    33143395 term.GetContainerRef() = [&]{
    @@ -3317,26 +3398,9 @@
    33173398 shared_ptr<void> p_type(new yimpl(byte));
    33183399 // shared_ptr<void> p_type(YSLib::allocate_shared<yimpl(byte)>(a));
    33193400
    3320- // XXX: Allocators are not used on %FormContextHandler for performance
    3321- // in most cases.
    3322-#if true
    3323- tcon.push_back(NPL::AsTermNode(a, tag, std::allocator_arg, a,
    3324- FormContextHandler(Encapsulate(p_type), 1)));
    3325- tcon.push_back(NPL::AsTermNode(a, tag, std::allocator_arg, a,
    3326- FormContextHandler(Encapsulated(p_type), 1)));
    3327- tcon.push_back(NPL::AsTermNode(a, tag, std::allocator_arg, a,
    3328- FormContextHandler(Decapsulate(p_type), 1)));
    3329-#else
    3330- // XXX: Mixing the %p_type above to following assignment code can be
    3331- // worse in performance.
    3332- tcon.push_back(NPL::AsTermNode(a, std::allocator_arg, a, tag,
    3333- std::allocator_arg, a, FormContextHandler(Encapsulate(p_type), 1)));
    3334- tcon.push_back(NPL::AsTermNode(a, std::allocator_arg, a, tag,
    3335- std::allocator_arg, a,
    3336- FormContextHandler(Encapsulated(p_type), 1)));
    3337- tcon.push_back(NPL::AsTermNode(a, std::allocator_arg, a, tag,
    3338- std::allocator_arg, a, FormContextHandler(Decapsulate(p_type), 1)));
    3339-#endif
    3401+ tcon.push_back(AsForm(a, Encapsulate(p_type), 1U));
    3402+ tcon.push_back(AsForm(a, Encapsulated(p_type), 1U));
    3403+ tcon.push_back(AsForm(a, Decapsulate(p_type), 1U));
    33403404 return tcon;
    33413405 }();
    33423406 return ReductionStatus::Retained;
    diff -r 92d04ed3856a -r 37835df0ac3b doc/ChangeLog.PreAlpha5.txt
    --- a/doc/ChangeLog.PreAlpha5.txt Sat Mar 13 14:46:42 2021 +0800
    +++ b/doc/ChangeLog.PreAlpha5.txt Fri Mar 26 22:43:02 2021 +0800
    @@ -1,5 +1,5 @@
    11 /*
    2- © 2014-2020 FrankHB.
    2+ © 2014-2021 FrankHB.
    33
    44 This file is part of the YSLib project, and may only be used,
    55 modified, and distributed under the terms of the YSLib project
    @@ -11,13 +11,13 @@
    1111 /*! \file ChangeLog.PreAlpha5.txt
    1212 \ingroup Documentation
    1313 \brief 版本更新历史记录 - PreAlpha5 。
    14-\version r15447
    14+\version r15467
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 500
    1717 \par 创建时间:
    1818 2014-05-29 19:30:47 +0800
    1919 \par 修改时间:
    20- 2020-01-12 18:19 +0800
    20+ 2021-03-26 22:08 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -2383,9 +2383,9 @@
    23832383 ),
    23842384 (
    23852385 + %Ref;
    2386- / "class template %lref, function templates %(ref, cref, unref), unary \
    2387- type trait %wrapped_traits, alias template %wrapped_traits_t"
    2388- @ %Functional >> %Ref,
    2386+ / ("class template %lref", "function templates %(ref, cref, unref)",
    2387+ "unary type trait %wrapped_traits",
    2388+ "alias template %wrapped_traits_t") @ %Functional >> %Ref,
    23892389 / "class %void_ref" @ %Any >> %Ref
    23902390 ),
    23912391 (
    @@ -5771,9 +5771,9 @@
    57715771 @ "platforms %(MinGW32, Android)" @ "Code::Blocks projects",
    57725772 // Note that for %Android it is not actually effective.
    57735773 + $repo "pattern 'Tools/SHBuild/stdinc.h.gch'" @ "file %.hgignore",
    5774- / $dev $repo $re_add(b563) "all edited file with module name not the same \
    5774+ / $dev $repo $re_add(b563) "all edited files with module name not the same \
    57755775 as base filename" @ !%YBase ^ 'hg mv' $effective @ ("%yadaptor.h"
    5776- => "%YAdaptor.h" @ %YFramework.YSLib.Adaptor.YGDIBase)
    5776+ => "%YAdaptor.h" @ %YFramework.YSLib.Adaptor)
    57775777 ),
    57785778
    57795779 b563
    @@ -5939,8 +5939,7 @@
    59395939 + "variable %EXESFX with default variable '.exe'"
    59405940 @ "platform %Win32" @ "%SHBuild-common-options.sh",
    59415941 * $re_ex(b434) "wrong '-Wl,--dn' option" @ "debug dynamic libraries"
    5942- @ "%SHBuild-YSLib.debug.sh" $since b429,
    5943-
    5942+ @ "%SHBuild-YSLib.debug.sh" $since b429
    59445943 ),
    59455944 / "normalized bash condition use" $=
    59465945 (
    @@ -6063,7 +6062,7 @@
    60636062 / @ "%install-sysroot.sh" $=
    60646063 (
    60656064 + "support for installing on UNIX-like targets",
    6066- + "variable %$SHBuild_Env_Arch" $dep_from
    6065+ + "variable %SHBuild_Env_Arch" $dep_from
    60676066 ("%SHBuild-common.sh" @ %Scripts);
    60686067 / "3rd party library directory now would be determinate by \
    60696068 %(SHBuild_YSLib_Platform, $SHBuild_Env_Arch)";
    @@ -7748,8 +7747,8 @@
    77487747 ),
    77497748 / $build "makefile" @ "platform %Android" @ %YReader $=
    77507749 (
    7751- / $re_ex(b518) 'ANDROID_SDKVER := 21.0.0'
    7752- -> 'ANDROID_SDKVER := 21.1.1',
    7750+ / $re_ex(b518) "updated value" @ "variable %ANDROID_SDKVER" -> '21.1.1'
    7751+ ~ '20.0.0',
    77537752 - DLD "redundant '-shared'" @ "%LDFLAGS"
    77547753 ),
    77557754 / $build @ "all 3 makefiles" @ "platform %Android" $=
    @@ -8285,8 +8284,9 @@
    82858284
    82868285 b550
    82878286 (
    8288- / $doc "updated Doxygen file" $=
    8289- (
    8287+ / $doc @ "%Doxyfile" $=
    8288+ (
    8289+ / $deploy "updated PROJECT_NUMBER",
    82908290 + "ignored path 'sysroot'",
    82918291 (
    82928292 / "value of %HTML_FILE_EXTENSION" -> '.xhtml' ~ "default '.html'";
    @@ -12049,7 +12049,7 @@
    1204912049 / $doc "updated build notice" @ "%Readme.zh-CN.txt",
    1205012050 / $dev $build "makefile" @ "platform %Android" $=
    1205112051 (
    12052- / 'ANDROID_SDKVER := 20.0.0' -> 'ANDROID_SDKVER := 19.0.3',
    12052+ / "updated value" @ "variable %ANDROID_SDKVER" -> '20.0.0' ~ '19.0.3',
    1205312053 // This is the Android SDK Build-tools version.
    1205412054 / "updated zipalign path" @ "target $(OUTPUT_FINAL)"
    1205512055 // The new SDK moved zipalign to the Build-tools.
    @@ -12511,7 +12511,7 @@
    1251112511 / %YReader $=
    1251212512 (
    1251312513 ^ "%IsPrintf" ~ "%std::iswprint" @ %DSReader $dep_from
    12514- %YFramework.YAdaptor.YTextBase,
    12514+ %YFramework.Adaptor.YTextBase,
    1251512515 + "function %FetchDefaultShellDirectory;
    1251612516 / "default argument" @ "class %ShlExplorer"
    1251712517 -> 'FetchDefaultShellDirectory()'
    @@ -13316,14 +13316,15 @@
    1331613316 + "function %AddButtonTabBar" @ %Shells,
    1331713317 + "rearranged setting UI in 3 tab pages" @ %ReaderSettingUI
    1331813318 ),
    13319- / $doc "updated Doxygen file" $=
    13320- (
    13321- ^ "Doxygen 1.8.7" ~ "Doxygen 1.8.2",
    13319+ / $doc @ "%Doxyfile" $=
    13320+ (
    13321+ / $deploy "updated PROJECT_NUMBER",
    1332213322 / 'YFramework/include/freetype YFramework/include/ft2build.h'
    1332313323 @ "%EXCLUDE" -> '.git Data Tools',
    13324- / "set %SHORT_NAMES" -> 'YES' ~ 'NO'
    13324+ / "set %SHORT_NAMES" -> 'YES' ~ 'NO';
    1332513325 // Workaround of error: 'could not open file for writing' with a \
    1332613326 name containing a tab.
    13327+ ^ $re_ex(b366) "Doxygen 1.8.7" ~ "Doxygen 1.8.2"
    1332713328 )
    1332813329 );
    1332913330
    diff -r 92d04ed3856a -r 37835df0ac3b doc/ChangeLog.V0.9.txt
    --- a/doc/ChangeLog.V0.9.txt Sat Mar 13 14:46:42 2021 +0800
    +++ b/doc/ChangeLog.V0.9.txt Fri Mar 26 22:43:02 2021 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file ChangeLog.V0.9.txt
    1212 \ingroup Documentation
    1313 \brief 版本更新历史记录 - V0.9 。
    14-\version r3098
    14+\version r3284
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 800
    1717 \par 创建时间:
    1818 2020-10-12 17:19:23 +0800
    1919 \par 修改时间:
    20- 2021-03-13 14:20 +0800
    20+ 2021-03-26 22:13 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -32,6 +32,189 @@
    3232
    3333 $now
    3434 (
    35+ / %YFramework.NPL $=
    36+ (
    37+ / DLDI "simplified all calls to construct %TermNode with a sole \
    38+ allocator argument" ^ "%TermNode" ~ "%NPL::AsTermNode"
    39+ $effective @ %(SContext, NPLA1),
    40+ / %SContext $=
    41+ (
    42+ / DLDI "all %TermNode argument ('node', 'term', 'tm') to be \
    43+ accessed directly" => 'nd',
    44+ // The direct accesses include member functions and some other \
    45+ related functions.
    46+ + "function %PropagateTo"
    47+ )
    48+ / %NPLA1 $=
    49+ (
    50+ * "missing support for term references" @ "trailing \
    51+ parameter term" @ "functions %(BindParameter, MatchParameter)"
    52+ @ %NPLA1 $since b800
    53+ $= (/ $impl ^ "%ReferenceTerm")
    54+ // The term tree matching for other leaf symbols has supported \
    55+ term references since b855. The implementation here uses \
    56+ %ReferenceTerm rather than %ResolveTerm for simplicity.
    57+ + "function %ReduceToReferenceWithUniqueList",
    58+ * "wrong handler type derived for lvalue callers"
    59+ @ ("function template %NameExpandedHandler";
    60+ $comp "function template %NameTypedReducerHandler") $since b896
    61+ $= (/ $impl ^ "%ystdex::remove_cvref_t"),
    62+ / DLDI "removed unused capture '&'" @ "function %operator()"
    63+ @ "class %FormContextHandler",
    64+ / DLDI "simplified functions %(BindParameter, MatchParameter)"
    65+ ^ $dep_from ("%PropagateTo" @ %SContext)
    66+ ),
    67+ / @ "namespace %Forms" @ %NPLA1Forms $=
    68+ (
    69+ * $re_add(b803) "missing support for term references"
    70+ @ "formal parameter tree check" @ "vau handler" $since b800
    71+ $= (/ $impl ^ "%ReferenceTerm"),
    72+ // The check for the dynamic environment term has already \
    73+ supported term references since b803. This should also \
    74+ have been done for the parameter tree.
    75+ * "wrong handling for reference terms with temporary tag"
    76+ @ "function %ReduceToReferenceList" $since b913
    77+ // This did not have effects on the derivations because the \
    78+ only use was 'map1 expire (rlist l)' which always behaves \
    79+ the same regardless of the temporar tag on the operand.
    80+ / @ "functions %(Let, LetRef, LetWithEnvironment, \
    81+ LetWithEnvironmentRef)" $=
    82+ (
    83+ (
    84+ * $comp "wrong handling for reference subterms in bindings"
    85+ $dep_from "%ReduceToReferenceList";
    86+ / DLI "optimized bindings forwarding"
    87+ !^ $dep_from "%ReduceToReferenceList"
    88+ ),
    89+ / DLI "ompimized abstraction construction"
    90+ $dep_from ("%NameTypedReducerHandler" @ %NPLA1)
    91+ ),
    92+ / $re_add(b912) DLI ^ "allocator" @ "initialization of \
    93+ %ContextHandler" @ "%(Lambda, LambdaRef, Vau, VauRef, \
    94+ VauWithEnvironment, VauWithEnvironmentRef, Wrap, WrapN, \
    95+ WrapOnce, WrapOnceRef)",
    96+ / DLDI "simplified function %MakeEncapsulationType",
    97+ / DLI @ "functions %(VauWithEnvironment, VauWithEnvironmentRef)" $=
    98+ (
    99+ / "renamed reducer name for parent environment evaluation",
    100+ / "simplified" ^ "%IsLeaf" ~ "%IsExtendedList"
    101+ ),
    102+ / DLI "%operator()" @ "vau handler" $=
    103+ (
    104+ / "avoided redundant copy of the parent environment object for \
    105+ combiner prvalues",
    106+ / "removed redundant enviroment saving for combiner prvalues"
    107+ @ 'NPL_Impl_NPLA1_Enable_TCO'
    108+ // This is actually already saved in the parent.
    109+ )
    110+ ),
    111+ * "missing propogation of the nonmodifying tag on reference \
    112+ passing" $effective @ ("function %BindParameter" @ %NPLA1
    113+ $since b856, ("function %ReduceToReferenceAt",
    114+ "function %ReduceToReference") @ %NPLA $since b871,
    115+ "functions %Forms::(FirstFwd, RestFwd)" @ %NPLA1Forms $since b913)
    116+ ^ $dep_from ("%PropagateTo" @ %SContext)
    117+ $dep_to "missing tags propogation on reference passing",
    118+ / %Dependency $=
    119+ (
    120+ / @ "function %LoadGroundContext" $=
    121+ (
    122+ (
    123+ * "unexpected internal argument copy" @ "alternative derivation"
    124+ @ ("applicative 'list*'" $since b789,
    125+ "'operative $sequence'" $since b828)
    126+ // Operative '$sequence' support move-only type since \
    127+ b828, and it is known unable to support it before then.
    128+ $= (/ $impl ^ ('forward!', 'move!')),
    129+ (
    130+ * "unexpected copy" @ "alternative derivations"
    131+ @ ("applicative %idv" $since b828,
    132+ "operative '$quote'" $since b799) $=
    133+ (
    134+ / "converted argument to rvalue" @ "parameter tree" ^ !'&',
    135+ * "missing parameter forwarding";
    136+ $= (/ $impl ^ '$move-resolved!');
    137+ // This relies on the parameters passed by value.
    138+ * "unexpected result copy"
    139+ / $= ($impl ^ ('$lambda%', '$vau%')
    140+ ~ ('$lambda', '$vau'))
    141+ // This relies on forwarding' to ensure memory safety.
    142+ );
    143+ (
    144+ / DLDI "reordered derivation" @ "applicatives %(id, idv, list)";
    145+ / DLDI "alternative derivation"
    146+ @ "operative '$lvalue-identifier?'"
    147+ ^ ('$def!', '$vau', 'cons') ~ ('$defv!', 'list');
    148+ / DLDI "reordered derviations of operative \
    149+ '$lvalue-identifier?' and applicative 'forward!'";
    150+ / DLDI "alternative derivation of applicative 'forward!'"
    151+ ^ ('$def!', '$vau%', 'wrap') ~ '$defl%!';
    152+ * "missing parameter forwarding" @ "alternative derivations"
    153+ @ "applicative 'list%'" $since b828
    154+ $= (/ $impl ^ 'forward!')
    155+ ),
    156+ / "alternative derivation" @ ($comp "applicative 'first%'"
    157+ $comp "applicative %(foldr1; map1)")
    158+ $since b913
    159+ // This differs to the native implementations.
    160+ );
    161+ * $comp "unexpected copy of initializers on calls"
    162+ @ "non-native derivations" @ "operatives named with '$let' \
    163+ prefix" $since b914
    164+ // For '$let' and '$let%', this has been fixed with native \
    165+ implementations since b914. The derivations of '$let' \
    166+ and '$let%' does not need the fixes of other combiners \
    167+ than 'list*'. However, '$let*' and '$let*%' need 'idv' \
    168+ and '$quote' fixes; '$letrec' and '$letrec%' further \
    169+ need '$sequence' and 'map1' fixes above.
    170+ ),
    171+ + DLI "alternative derviation" @ "applicative 'forward!'"
    172+ @ 'NPL_Impl_NPLA1_Use_Id_Vau' ^ 'lambda%',
    173+ / DLDI "simplified alternative derivation"
    174+ @ "applicative 'first%'"
    175+ $= (/ $impl ^ 'lambda' @ 'first%' ~ ('$lambda%', 'idv')),
    176+ // This can fix the wrong behavior without touching \
    177+ '$quote' or 'idv', but it does not fix the root cause. \
    178+ Anyway, this is still more succinct.
    179+ * $re_add(b874) "unexpected internal argument copy"
    180+ @ "alternative derivation" @ "applicative 'map1'"
    181+ $since b829
    182+ $= (/ $impl ^ 'move!'),
    183+ // The applicative added b791 has nothing support of \
    184+ forwarding. It was partially fixed by adding \
    185+ 'forward!' to the 1st argument of 'cons%' call, but \
    186+ not the trailing list argument.
    187+ / DLDI "trailing parameter 'x'" => 'xs'
    188+ $effective @ "alternative derivations"
    189+ @ "applicatives ('rest%', 'rest&', %restv)",
    190+ + "applicative %rulist"
    191+ ^ $dep_from ("%ReduceToReferenceWithUniqueList" @ %NPLA1),
    192+ * "lvalues in bindings moved unexpectedly" @ "operatives named \
    193+ with '$let' prefix" $since b914 $=
    194+ (
    195+ / "alternative derivations" ^ $dep_from "%rulist"
    196+ ~ "%(map1, expire, rlist)",
    197+ / $comp "native implementations" $dep_from ("%(Let, \
    198+ LetRef, LetWithEnvironment, LetWithEnvironmentRef)"
    199+ @ %NPLA1Forms)
    200+ ),
    201+ / DLDI "qualified broken" @ "term accessor functions on \
    202+ reference passing" $since b856
    203+ $dep_from "missing tags propogation on reference passing",
    204+ * "alternative derivation" @ "operatives ('$when', '$unless')"
    205+ $since b908
    206+ $= (/ $impl ^ 'list*' ~ 'list'),
    207+ ),
    208+ / DLDI "broke down multiline definitions after the formal \
    209+ parameter and the dynamic environment (if any)" $effective
    210+ @ "functions %(LoadGroundContext, LoadModule_std_promises)"
    211+ // This is more consistent.
    212+ )
    213+ )
    214+),
    215+
    216+b914
    217+(
    35218 * $revert(b909) DD "wrong 1st parameter type"
    36219 @ "operatives ('$set!', '$setrec!')" @ %Documentation.NPL $since b909,
    37220 / %YFramework.NPL $=
    @@ -128,7 +311,7 @@
    128311 ^ $dep_from ("%TermReference::AddTags" @ %NPLA),
    129312 + "applicative 'as-const'"
    130313 ^ $dep_from ("%TermReference::AddTags" @ %NPLA),
    131- * "unexpected copy on calls"
    314+ * "unexpected copy of initializers on calls"
    132315 @ "operatives named with '$let' prefix" $since b791
    133316 ),
    134317 / $lib "added native derivation enabled by default"
    @@ -437,9 +620,9 @@
    437620 // This get less one line.
    438621 ),
    439622 / DLI ^ "allocator" @ "initialization of %ContextHandler"
    440- $effective @ ("functions %Forms::(WrapRef, WrapOnceRef, \
    441- Unwrap, Apply, ForwardFirst)" @ %NPLA1Forms,
    442- "function %ReduceForCombinerRef" @ %NPLA1Internals)
    623+ @ ("functions %Forms::(WrapRef, WrapOnceRef, Unwrap, Apply, \
    624+ ForwardFirst)" @ %NPLA1Forms, "function %ReduceForCombinerRef"
    625+ @ %NPLA1Internals)
    443626 ),
    444627 - DLDI "unused lambda-capture" @ "member function %ValueObject::Query"
    445628 @ %YSLib.Core.YObject,
    diff -r 92d04ed3856a -r 37835df0ac3b doc/NPL.txt
    --- a/doc/NPL.txt Sat Mar 13 14:46:42 2021 +0800
    +++ b/doc/NPL.txt Fri Mar 26 22:43:02 2021 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPL.txt
    1212 \ingroup Documentation
    1313 \brief NPL 规范和实现规格说明。
    14-\version r22087
    14+\version r22172
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 304
    1717 \par 创建时间:
    1818 2012-04-25 10:34:20 +0800
    1919 \par 修改时间:
    20- 2021-03-13 02:07 +0800
    20+ 2021-03-26 12:17 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -1257,7 +1257,10 @@
    12571257 过程中和过程外的计算的组合满足因果性(causality) :
    12581258 以求值描述的过程中的计算整体非后序(@4.4.1) 于引起过程中计算的外部环境的计算;
    12591259 以求值描述的过程中的任意计算非后序(@4.4.1) 于对应计算结果的值的计算,即值的计算结果是决定值的计算的依赖(dependency) 。
    1260-主调函数(caller function) 等调用者(caller) 或其它引起过程中的计算的实体进入(enter) 过程,转移控制(control) 到过程中的计算。
    1260+主调函数(caller function) 等调用者(caller) 或其它引起过程中的计算的实体转移控制(control) 到过程中的计算而使之进入(enter) 过程。
    1261+过程调用时控制可能通过调用被再次转移,即嵌套调用。
    1262+一些被调用的过程可能被多次进入,即重入(reenter) 。
    1263+通过嵌套调用直接(总是以自身作为调用者)或间接(通过其它调用者转移控制)的重入是递归调用(recursive call) 。
    12611264 过程可以返回(return) 改变控制状态(@4.1) ,影响之后的计算。
    12621265 具体实现中的过程按计算的顺序约束和默认返回控制的方式,可能有不同的形式:
    12631266 例程(routine) 的求值不交叉(interleave) ,即例程中的计算和之外的计算非决定性有序(@4.4.1) ;
    @@ -1281,7 +1284,7 @@
    12811284 除 E1 外表达式的剩余子项 E2 是操作数(@4.4.3.1),在 E 被求值时以操作数决定的值等效替换(substitute) 函数的形式参数(@4.5.2) 。
    12821285 替换形式参数的值是实际参数(actual argument, argument) 。
    12831286 函数合并的求值是替换规则(@4.4) 的非平凡形式。
    1284-若替换操作数 E2 可被求值,函数合并 E 是函数应用表达式,简称函数应用。
    1287+若替换操作数 E2 在合并中被求值,函数合并 E 是函数应用表达式,简称函数应用。
    12851288 若操作符是 λ 抽象,E2 视为一个整体,则函数应用替换规则对应 λ 演算的 β-规约(beta-reduction) 规则。
    12861289 其它函数合并使用的替换规则由派生实现指定。
    12871290 派生实现应指定函数合并规约(@4.1) 的结果是规范形式(@4.5.2),它对应的值是函数合并的求值结果(@4.1) ,称为函数值。
    @@ -1290,7 +1293,7 @@
    12901293 伴随参数匹配,实现可引入其它必要的操作(如为匹配分配资源和确定上述对应关系)。这些操作可具有和确定参数对应关系的匹配之间非决定性有序(@4.4.1) 的副作用。
    12911294 仅当上述必要操作及所有实际参数的匹配成功,替换 E1 决定的某个关联表达式中和形式参数(@4.5.2) 结构一致的子表达式为实际参数(@4.5.2) 。替换参数的结构一致性是等价关系。
    12921295 表达式相等蕴含参数匹配一致性和替换结构一致性。实现可分别定义其它规则扩充这些等价关系的外延。
    1293-替换参数的值蕴含对实际参数的值的计算的依赖,即参数的值的计算先序(@4.4.1) 函数应用的求值;但其它求值顺序没有保证。
    1296+替换参数的值蕴含对实际参数的计算的依赖,即参数的值的计算先序(@4.4.1) 函数应用的求值;但其它求值顺序没有保证。
    12941297
    12951298 @4.5.3.1 函数调用(call) :
    12961299 求值函数合并包含子表达式的求值:总是求值操作符,并可能求值操作数。若这些求值都没有退出,则函数被调用。
    @@ -1299,7 +1302,7 @@
    12991302 绑定的实际参数和对应的形式参数作为不同的实体时,作为伴随参数匹配的必要操作的一部分,发生参数传递(parameter passing) 。参数传递使形式参数具有作为实际参数值的副本。参数传递可能使和实际参数相关的资源被复制或转移。
    13001303 实现在函数合并的求值中应提供函数调用的支持。
    13011304 函数调用确定副作用的边界:保证参数表达式在函数应用被求值之前被求值。
    1302-在控制返回(@4.5.2.1) 主调函数(@4.5.2.1) 时,函数调用内部确定的函数值最终替换被求值的函数调用(@4.5.3.1) ,即为返回值(return value) 。
    1305+在控制返回(@4.5.2.1) 主调函数(@4.5.2.1) 时,函数调用内部确定的函数值最终替换被求值的函数合并表达式,即为返回值(return value) 。
    13031306 典型实现的函数指称过程(@4.5.2.1) ,函数调用为过程调用(procedure call) 。
    13041307 若一个函数的调用仍待返回,则该函数调用是活动的(active) 。
    13051308 一般地,被调用的函数及函数调用的作用的等价性通常不能被确定。一个重要的子类是不能确定具体表示的合并子的情形(@4.4.3.1) ,参见 @4.5.3.2 。其它函数一般也有类似限制。
    @@ -1687,6 +1690,11 @@
    16871690 右值(rvalue) 是消亡值或纯右值。
    16881691 求值涉及表达式的值类别仅在必要时约定。
    16891692 值类别根据是否只关心表达式关联的(对象的或非对象的)值,在需要对象时提供区分两类一等对象(@4.2) 的机制,同时避免在仅需要表达式关联的值时引入不必要的其它对象。
    1693+和 ISO C++ 类似,表达式的值类别是上下文相关的,相同表达式构造在不同的上下文可能具有不同的值类别。
    1694+和 ISO C++ 不同,NPLA 表达式允许在源语言语法之外的形式被间接构造,这些表达式同样具有值类别。
    1695+求值规约(@4.4) 可能重写一个表达式为具有不同值类别的其它形式的表达式。
    1696+和 ISO C++ 不同,一般地,NPLA 的表达式不限定从源代码(@4.1.1) 的翻译(@2.4.1) 确定,且一个表达式的求值结果不排除继续构成表达式而被求值,因此表达式的值也普遍具有值类别。
    1697+除非另行指定,若一个 NPLA 表达式没有指定未被求值,则其值类别是其求值结果(@4.1) 的值类别。
    16901698 另见引用(@4.2.3) 对一等状态(@4.2.2.1) 的支持(@4.2.3.3.2) 。
    16911699
    16921700 @5.8.1.1 类型系统和表示:
    @@ -1707,6 +1715,14 @@
    17071715 第三条性质保证表达式的作用(@2.3.4) 是可组合的并允许求值表达为树规约(@6.2) ,还保证能总是通过子表达式的值类别决定表达式的值类别。因为被求值的表达式是有限的,判定过程是总是能终止,即便求值不满足强规范化性质(@4.4.3) 。
    17081716 第四条性质要求提供泛左值总是能作为纯右值使用的机制和通过纯右值引入对象的机制,详见值类别转换(@5.8.4) 。
    17091717 第五条性质要求在表达式之外不存在地位相同的对象的存储资源(@5.6) 的所有者,限定了被决定同一性的对象的外延;存储由环境提供(@5.6) ,其中不需要保存对象的引用。
    1718+不像 ISO C++ 一样仅限于静态类型系统范畴,NPLA 值类别的作用机制和 ISO C++ 存在一些明确的不同:
    1719+ 对 C++ ,表达式求值规约的重写(如 ISO C++ 的左值到右值转换)是静态的文法构造确定的;
    1720+ 但对 NPLA ,这种重写的存在性可依赖程序运行时的状态。
    1721+基于求值结果约定可能被求值的表达式的值类别是自然的,因为:
    1722+ 值类别通常影响值的使用,若一个表达式预期被求值,对应求值结果以外的值类别通常不被关心。
    1723+ 尽管允许取得构造关联的表达式副本时,值类别可能因其被用于其它求值而在求值前被关心。
    1724+ 这也和 ISO C++ 更加一致,尽管后者因为上下文被静态地确定(排除 ISO C++ 未求值操作数(unevaluated operand) )而可以直接只讨论被求值的情形,而不需要这种约定。
    1725+ 注意此时表达式的值可能是左值,因此表达式的“值”与“右值”不等价,这与 ISO C 的一般约定不同。
    17101726
    17111727 @5.8.2 初始化:
    17121728 部分创建对象的表达式引入对象的初始化(initialization) 。
    @@ -2085,6 +2101,10 @@
    20852101 和 ISO C++ 核心语言(但不是 [res.on.arguments] 中的标准库绑定到右值引用实际参数的约定)的右值引用类似,唯一引用不总是表示被引用对象非共享。接受唯一引用的操作可能只假定被引用对象的子对象是不被共享,也可能完全不做假定,这依赖具体操作的语义。若需要和具体操作无关的无条件非共享假定,使用纯右值(@5.8.1) 而非作为左值的唯一引用。
    20862102 若实质化转换上下文(@5.8.5.1) 支持绑定临时对象,按引用绑定的对象具有临时对象标签(@6.2.2) 。引入引用值的形式参数的具体形式由派生实现指定。
    20872103 类似地,和宿主语言不同,违反不可修改标签引入的假定不引起未定义行为。
    2104+因为 NPLA 使用潜在类型(@5.2.3) ,表达式不保证提供静态类型(@4.6.2) 能编码值类别和类型信息;作为替代,这些信息通过规约范式中的项的标签保存。其中:
    2105+TermTags::Unique 指定特定的值类别(消亡值(@5.8.1) );
    2106+TermTags::Nonmodifying 指定特定的限定类型;
    2107+TermTags::Temporary 指定具有特定的值类别(纯右值)的引用值,或引用这些临时对象的项引用。
    20882108
    20892109 @6.2.3 项节点访问:
    20902110 模块 SContext 提供访问项节点的 API 。
    @@ -2395,7 +2415,7 @@
    23952415
    23962416 @6.6.3.3 项引用(term reference) :
    23972417 宿主语言中的 NPL::TermReference 是项引用。
    2398-NPL::TermReference 和所在的项中可能包含的子对象是引用值的宿主值(@6.3) 类型。
    2418+项引用是泛左值(即临时对象引用以外的引用值)的内部表示的值类型对象的宿主值(@6.3) 。
    23992419 其中,子项只被子对象引用(@6.6.3.3.5) 的情形使用。
    24002420 子对象引用使用的这种形式的表示通常因为需要更多的操作比其它引用值的类似操作低效,但这种表示可避免依赖宿主语言中的本机对象内部表示(如成员布局)的依赖。
    24012421 一般地,在 C++ 的意义上不存在能满足语义的更有效的可移植表示,所以这种表示在和宿主语言的互操作(@5.3) 上是必要的。
    @@ -2689,7 +2709,7 @@
    26892709 满足上述约定的求值结果的表示(@6.3) 是正规(regular) 表示;否则,求值结果的表示是非正规(irregular) 表示。
    26902710 表达式具有正规表示。
    26912711 空求值(@4.4.2) 不改变表示的正规性。
    2692-平凡(trivial) 非正规表示保证可被(此次规约中剩余的操作)安全忽略而不改变规约的语义。
    2712+平凡(trivial) 非正规表示保证可被(此次规约中剩余的步骤)安全忽略而不改变规约的语义。
    26932713 对被求值项(@6.3) 的任一遍(@6.7.4) 规约都可引入非正规表示,但应满足取得范式的要求:
    26942714 被求值项取得平凡非正规以外的表示是取得范式(@6.7.3) 的必要非充分条件。
    26952715 为取得范式,可能需要继续进行规范化规约(@4.4.3) 。
    @@ -3402,13 +3422,13 @@
    34023422
    34033423 @7.7.3 绑定操作:
    34043424 绑定操作决定符号或具有符号的数据结构与项的对应关系,并初始化被绑定对象(@6.8.1) 而引入变量(@4.1) 。
    3405-作为函数语法的扩展,前者和后者分别是绑定操作使用形式参数(@4.5.2) 和操作数(@4.4.3.1) 。
    3425+作为函数语法的推广,两者分别由绑定操作使用形式参数(@4.5.2) 和操作数(@4.4.3.1) 指定。
    34063426 作为 TermNode ,操作数(@4.4.3.1) 的表示具有树的构造,即操作数树(@4.4.3.1) ,它可以具有子项。
    34073427 匹配的形式参数和操作数树对应也可具有树的构造,即形式参数树(formal parameter tree) 。
    34083428 绑定操作初始化的变量的名称和值分别由形式参数树和操作数树决定。
    34093429 绑定操作匹配待绑定的形式参数和操作数或它们的子项。
    34103430 成功的匹配决定形式参数对应的操作数或其子项,作为其实际参数(@4.5.3) 。这种对应关系是单射但不一定是满射,即匹配成功后,每个参数总存在对应的操作数或其子项,而操作数和子项允许不对应形式参数而被忽略。
    3411-NPLA 操作数树的叶节点为符号(@6.6.3.1) 或其引用值(@6.3.4) 。
    3431+NPLA 形式参数树的叶节点为符号(@6.6.3.1) 或其引用值(@6.3.4) 。不符合要求的对象构造形式参数树时可引起(@2.5.2) 错误。
    34123432 被绑定的项的操作数是待匹配的项的子项(而不会是此项自身,满足 @6.7.6 )。
    34133433 被绑定的参数可以作为函数的形式参数(@4.5.2) ,也可以其它初始化变量的语法构造的基础。
    34143434 和 Kernel 类似,形式参数树是 DAG ,但通过真列表(@6.2.1) 的性质蕴含而不需要另行限制。形式参数树中的节点在匹配时被视为右值。
    @@ -3422,16 +3442,22 @@
    34223442 若形式参数可能由求值得到,需在匹配前另行处理。
    34233443
    34243444 @7.7.3.2 绑定临时对象(@5.8.5.1) 标签:
    3425-绑定临时对象时设置对象上的 TermTags::Temporary 标签(@6.2.2) ,以实现区分通过引用绑定延长生存期的临时对象和非引用绑定的对象(@5.8.5.3) 。
    3445+绑定临时对象时设置对象上的 TermTags::Temporary 标签(@6.2.2) ,以允许区分通过引用绑定延长生存期的临时对象和非引用绑定的对象(@5.8.5.3) 。
    34263446 一般地,表达式中的纯右值(非引用值)被绑定为临时对象,被绑定的对象在初始化后具有 TermTags::Temporary 。
    34273447 这对应宿主语言中的转发引用(forwarding reference) 参数中的情形:
    34283448 若模板参数 P 对应转发引用函数参数 P&& ,其中 P 是右值引用类型,保留从实际参数推断但不是实际参数类型的信息;
    34293449 没有绑定临时对象标签的对象则同一般的非引用类型的对象类型参数(非转发引用)。
    3430-A1::EvaluateIdentifier(@7.6.4) 保证被绑定的对象名称解析的引用标签不包含 TermTags::Unique(@6.2.2) ,但不清除绑定临时对象引入的 TermTags::Temporary 。
    3431-这允许 TermTags::Temporary 在作为返回值的名称表达式中直接被跨过程传递(若不经过返回值转换(@6.4.6.4) 或其它操作)。
    3450+注意 P 在宿主语言中通过值类别推断,但不表示值类别。而 TermTags::Temporary 在绑定特定形式的参数时具有和 P 编码的附加信息类似的作用:
    3451+不具有 TermTags::Temporary 的项引用表示的引用值作为表达式,在初始化临时对象的引用时被视为左值(不被影响其余标签);
    3452+其它表达式的推断结果为右值。
    3453+类似宿主语言,这种以操作数表达式的值类别以外的形式是一种推断。因为推断规则和宿主语言的相似,这种上下文可支持类似宿主语言的参数转发。
    3454+和宿主语言的 std::forward 不同,此处推断的右值除了是消亡值外,也可以是纯右值。
    3455+A1::EvaluateIdentifier(@7.6.4) 保证求值标识符的结果是左值引用(@7.1.3) ,即被绑定的对象名称解析最终得到的引用值的标签不包含 TermTags::Unique(@6.2.2) 。
    3456+与此不同,这不清除绑定临时对象引入到表示被绑定对象的项或项引用中的 TermTags::Temporary 。
    3457+TermTags::Temporary 在作为返回值的名称表达式保持不变,且可被跨过程传递(若不经过返回值转换(@6.4.6.4) 或其它操作)。
    34323458 被传递标签类似宿主语言的 std::forward 的模板参数中指定转发引用参数类型(因为宿主语言的引用折叠,此处 P 和 P&& 一致)。
    34333459 跨过程传递实质上并不被宿主语言支持(因为 P 表示的静态类型信息不在函数外可用),因此一般仅限为了实现类似宿主语言的根据值类别和类型转发参数的转发上下文(forwarding context) 中使用。
    3434-使用引用标记字符(@7.7.3.4) 可保留来自引用值实际参数的绑定临时对象标签。
    3460+使用引用标记字符(@7.7.3.4) 可保留来自引用值实际参数的绑定临时对象标签及启用转发推断值类别。
    34353461
    34363462 @7.7.3.3 绑定匹配:
    34373463 数据结构和匹配算法类似 Kernel 中用于 $define! 和 $vau 等操作子(@4.5.3.2) 的机制,但有以下不同(另见 @9.9.5 ):
    @@ -3450,12 +3476,15 @@
    34503476
    34513477 @7.7.3.4 引用标记字符:
    34523478 应用在形式参数树叶节点的前缀 % 、& 或 @ 为标记字符表示名称绑定的可按需引入引用,称为引用标记字符。
    3453-没有标记字符时,指示绑定的默认行为。
    3479+绑定引用时,可使用引用推断规则:引用值按值传递(@4.4.4.5) 给形式参数,非引用值按引用传递(@4.4.4.5) 给形式参数(@7.7.3.3) ;
    3480+否则,操作数按值传递给形式参数。
    34543481 标记字符引起的绑定的差异为:
    3455-没有标记字符则对操作数按值绑定,实际参数值传递给对应的形式参数,若为 NPL::TermReference 则发生左值到右值转换(@6.4.6.1) ;
    3456-有标记字符 % 或 & 按引用推断规则直接绑定或转发操作数(当操作数为引用时;属于引用折叠(@6.6.3.3.2) );
    3457-有标记字符 @ 则绑定操作数的引用,不论操作数的类型和值类别(不进行引用折叠)。
    3458-使用引用推断规则绑定引用时,操作数按引用传递(@4.4.4.5) 给形式参数(@7.7.3.3) ;否则,操作数按值传递(@4.4.4.5) 给形式参数。
    3482+ 没有标记字符生效时,对操作数按值绑定,实际参数值传递给对应的形式参数。
    3483+ 若实际参数是泛左值(@5.8.1) ,则实际参数上首先隐含左值到右值转换(@6.4.6.1) 。
    3484+ 标记字符 % 或 & 生效时,按引用推断规则直接绑定或转发操作数。
    3485+ 当实际参数是引用值时,隐含一次引用折叠(@6.6.3.3.2) 。
    3486+ 标记字符 @ 生效时,绑定以实际参数作为被引用对象的引用值,不论操作数的类型和值类别。
    3487+ 初始化引用值时,没有引用折叠。
    34593488
    34603489 @7.7.3.5 非递归绑定:
    34613490 非递归绑定在一次匹配之后创建对应的变量绑定。
    @@ -4265,16 +4294,18 @@
    42654294 eval-booleans
    42664295 eval-cond-list
    42674296 eval-foldr1-kons
    4268-eval-let-call
    4297+eval-let-combine-operator
    4298+eval-let-combine-return
    42694299 eval-let-extract-arguments
    42704300 eval-let-make-combiner
    4301+eval-let-parent
    42714302 eval-lift-sum
    42724303 eval-list-concat-cons
    42734304 eval-list-extract-cons
    42744305 eval-list-extract-next
    42754306 eval-map1-appv
    42764307 eval-map1-cons
    4277-eval-vau
    4308+eval-vau-parent
    42784309 match-ptree
    42794310 match-ptree-recursive
    42804311 select-clause
    @@ -4298,9 +4329,11 @@
    42984329 eval-combine-return :非 TCO 的规约合并求值(@7.6.4.2) 实现中设置规约合并最后的返回结果。
    42994330 eval-foldr1-kons :Forms::FoldR1(@8.4.9) 应用子调用。
    43004331 eval-guard :非 TCO 的求值实现重置守卫的附加动作帧(@6.9.6)。
    4301-eval-let-call :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef(@8.4.9) 中从绑定列表中调用。
    4332+eval-let-combine-operator :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef(@8.4.9) 中合并创建的合并子和初值符构成的操作数。
    4333+eval-let-combine-return :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef 中设置最后的返回结果。
    43024334 eval-let-extract-arguments :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef 中从绑定列表中取形式实际参数。
    43034335 eval-let-make-combiner :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef 中从绑定列表中创建合并子。
    4336+eval-let-parent :Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef 中求值过程抽象(@8.4.5) 的父环境的表达式。
    43044337 eval-lift-result :非 TCO 的求值实现调用 NPL::ReduceForLiftedResult(@6.7.12.1) 提升返回结果。
    43054338 eval-lift-sum :Forms::AccR、Forms::FoldR1 和 Forms::Map1(@8.4.9) 公共的部分和提升调用。
    43064339 eval-list-concat-cons :Forms::ListConcat(@8.4.9) 列表构造调用。
    @@ -4310,7 +4343,7 @@
    43104343 eval-map1-cons :Forms::Map1 列表构造调用。
    43114344 eval-sequence-return :非 TCO 的 A1::ReduceOrdered(@7.4.6) 实现中设置规约合并最后的返回结果。
    43124345 eval-tail :TCO 动作尾上下文求值(和 klisp 不同,不依赖 GC(@5.6.4) 而在 TCO 动作单独保存资源(@7.10.5.1) )。
    4313-eval-vau :求值过程抽象(@8.4.5) 在带环境的函数构造器中作为续延。
    4346+eval-vau-parent :合并子构造时求值过程抽象的父环境的表达式。
    43144347 注意 klisp 的 $vau 不具有应保证被求值的实际参数,不需要异步调用,没有对应的续延。
    43154348 load-external :A1::RelayToLoadExternal(@8.5.2) 加载外部翻译单元。
    43164349 match-ptree-recursive :支持延迟递归绑定( Forms::DefineWithRecursion 和 Forms::SetWithRecursion(@8.4.4.3) )。
    @@ -4785,7 +4818,7 @@
    47854818 例如 NPLA1 参考实现环境(@10) 下求值以下表达式:
    47864819 $let ((nenv () make-environment)) $set! nenv self nenv
    47874820 可引起被捕获的环境中存储的对象无法释放。
    4788-能同时保证避免资源泄漏的实现引起一般意义上更根本的设计限制,因此不被使用。详见 @4.2.4 。
    4821+能同时保证避免资源泄漏的实现引起一般意义上更根本的设计限制,因此不被使用。详见自引用数据结构和循环引用(@4.2.4) 。
    47894822 此外,为了避免 $lambda 等引起不经意的循环引用误用,根据易预测性原则(@1.4.5.2) ,这些组合子的构造器默认不使用强引用(@6.8.1) 作为静态环境。
    47904823 若需保持静态环境的所有权,使用显式指定静态环境的构造器(如 $lambda/e ) 和 lock-current-environment 等。
    47914824 否则,容易引起循环引用,如以下表达式:
    @@ -4800,7 +4833,8 @@
    48004833
    48014834 @9.9.1.2 自引用(self-referencing) 数据结构:
    48024835 因为不支持循环引用(@9.9.1.1) ,不支持引用自身的自引用数据结构。
    4803-详见 @4.2.4 。
    4836+详见自引用数据结构和循环引用(@4.2.4) 。
    4837+另见列表(@9.9.4) 。
    48044838
    48054839 @9.9.2 符号(@2.3.4) :
    48064840 在求值算法(@9.7.1) 中,求值符号依赖环境(@9.9.3) 进行名称解析(@4.3.3) ,求值为引用(@9.9.1) 。
    @@ -4881,7 +4915,8 @@
    48814915 若提供其它由派生实现定义的方法(附加初始化或提供本机实现操作)撤销冻结而使上述调用的安全性失效,这种方法应由派生实现定义。
    48824916
    48834917 @9.9.4 列表:
    4884-和 Scheme 及 Kernel 不同,基于 @4.2.4 的理由,NPLA 支持的列表都是真列表(@6.2.1) ,元素有限且不存在环。
    4918+和 Scheme 及 Kernel 不同,基于关于自引用数据结构和循环引用的分析(@4.2.4) 的理由,NPLA 支持的列表都是真列表(@6.2.1) ,元素有限且不存在环。
    4919+列表上的引用也应不构成环(@9.9.1.1) 。这使处理列表的操作不需要考虑一些复杂的自引用(@9.9.1.2) 情形。
    48854920 作为真列表,列表直接被表示为子项元素的列表节点的序列,其宿主类型为 TermNode(@6.2) 。
    48864921 利用 TermNode 中可选的值数据成员(@6.2) ,列表节点可以退化为非列表的值的表示;列表自身也可作为其它列表的节点。列表节点的实现的表示详见 @6.2.1 。
    48874922 由 TermNode 的性质,列表的元素是列表的子对象,列表对作为元素的节点具有所有权。同一个列表的元素节点之间没有所有权关系。
    @@ -5641,7 +5676,8 @@
    56415676 cons <object> <list> :构造两个元素的列表。
    56425677 和 Kernel 不同,NPL 不支持列表中存在环,因此第二个操作数应为列表,否则引起错误(@9.5.1) 。
    56435678 cons% <object> <list> :构造两个元素的列表,保留引用值。
    5644-同 cons ,但允许子项中有引用而不复制(@8.4.5.4) 子项的值。
    5679+同 cons ,但 <object> 是引用值时,直接以其值作为列表元素的值,而不以其被引用对象的值作为列表元素的值。
    5680+这允许被构造的列表中存在和 <object> 相等的引用值,而非其被引用对象的副本。
    56455681 set-rest! <list> <object> :修改列表的第一个以外的元素。
    56465682 和 Kernel 的 set-cdr! 类似,但检查列表是左值,且不保留被添加元素中的引用值。
    56475683 set-rest%! <list> <object> :同 set-rest! 但保留引用值。
    @@ -5774,6 +5810,14 @@
    57745810 idv <object> :同 id ,但结果为返回值转换(@6.4.6.4) 后的值。
    57755811 使用 idv 可指定在返回值中保留引用值的不安全操作(@10.8.1) 的个别操作数不再保留引用值。
    57765812 list <object>... :创建列表(类型为 <list> )对象。
    5813+$lvalue-identifier? <symbol>
    5814+解析当前环境中的标识符(同 $resolve-identifier(@11.3.7) )并判断是否为左值(同 bound-lvalue?(@11.3.4) )。
    5815+forward! <object> :转发(@10.5.4) 可能是引用的值(@11.2.2.4) 。
    5816+转移可修改的右值操作数(包括消亡值和临时对象)。
    5817+其中,需转移时,使用使用项的转移(@6.3.2) 。这和对象的转移(@5.8.2.3) 不同,不保证调用宿主实现的转移构造函数。
    5818+本机实现使用 NPL::MoveRValueToForward(@6.6.7.3) 可简化操作。
    5819+这个函数类似宿主语言以对象类型参数和推断的函数参数类型作为模板参数调用 std::forward ,但若需转移,直接转移而非如 expire(@11.3.2) 返回指定结果是消亡值(@5.8.1) 的唯一引用(@6.2.2) 。
    5820+和宿主语言不同,直接转移允许区分消亡值和纯右值,同等地作为一等对象(如作为列表的元素)。
    57775821 list% <object>... :同 list ,但每个参数都不隐含左值到右值转换,在结果保留引用值。
    57785822 rlist <list> :转换参数为引用列表元素的列表。
    57795823 若参数是左值,则结果是参数的元素的引用构成的列表;否则,结果同 idv 。
    @@ -5794,19 +5838,13 @@
    57945838 操作数非空时结果是最后的参数,可能是引用值。
    57955839 类似 Kernel 的同名操作。
    57965840 求值每个 <object> 的副作用包括其中临时对象(@5.8.5) 的销毁都被顺序限制,类似宿主语言的语句而不是保证子表达式中的临时对象的生存期延迟到完全表达式求值结束的逗号表达式。这也允许实现和 [RnRK] 同名操作类似的 PTC 要求。
    5797-$lvalue-identifier? <symbol>
    5798-解析当前环境中的标识符(同 $resolve-identifier(@11.3.7) )并判断是否为左值(同 bound-lvalue?(@11.3.4) )。
    57995841 collapse <object> :折叠可能是引用的值。
    5800-forward <object> :转发(@10.5.4) 可能是引用的值(@11.2.2.4) 。
    5842+forward <object> :转发可能是引用的非临时对象的值。
    5843+同 forward! ,但不转移(使用复制代替)可修改的临时对象操作数。
    58015844 按在所在的环境中解析的操作数的类型可选地提升项(@6.6.7) 作为结果,其作用 id 或 idv 之一。
    58025845 被转发的值若是形式参数树(@7.7.3) 中的变量,一般应以带有标记字符 & 的形式绑定(@7.7.3.5) ;否则,转发的不是对应的实际参数,而可能是其按值绑定的副本。
    58035846 转移(而不是复制)可修改的右值操作数。注意若右值操作数不可修改(如本机实现引入带有 TermTags::Nonmodifying 标签(@6.2.2) 的引用操作数),复制不可复制构造的宿主对象会失败。
    58045847 本机实现使用 NPL::MoveRValueToReturn(@6.6.7.3) 可简化操作。
    5805-forward! <object> :同 forward ,但除转移右值操作数外,也转移(而不是复制)可修改的临时对象操作数。
    5806-其中,需转移时,使用使用项的转移(@6.3.2) 。这和对象的转移(@5.8.2.3) 不同,不保证调用宿主实现的转移构造函数。
    5807-本机实现使用 NPL::MoveRValueToForward(@6.6.7.3) 可简化操作。
    5808-这个函数类似宿主语言以对象类型参数和推断的函数参数类型作为模板参数调用 std::forward ,但若需转移,直接转移而非如 expire(@11.3.2) 返回指定结果是消亡值(@5.8.1) 的唯一引用(@6.2.2) 。
    5809-和宿主语言不同,直接转移允许区分消亡值和纯右值,同等地作为一等对象(如作为列表的元素)。
    58105848 apply <applicative> <object> <environment> :在指定环境中应用。
    58115849 和 Kernel 的参考派生不同,检查 <environment> 确保为一个对象。
    58125850 apply <applicative> <object> :在新环境(@9.9.3) 中应用。
    @@ -5833,13 +5871,13 @@
    58335871 当 <list> 是左值时结果是折叠的引用值,否则结果是返回值转换(@6.4.6.4) 后的值。
    58345872 first@ <list> :同 first ,但结果总是未折叠的引用值。
    58355873 first% <list> :同 first ,但结果总是转发的值。
    5836-转发的值是经过折叠但没有返回值转换的值,无论参数是否为左值。
    5874+转发的值是经过折叠但没有返回值转换的列表元素的值,无论参数是否为引用值。
    58375875 first& <list> :同 first ,但结果总是折叠的引用值。
    5838-首先调用 check-list-reference(@11.3.9) 检查参数是列表引用,对右值的抛出异常。
    5876+首先调用 check-list-reference(@11.3.9) 检查参数是列表引用,对右值抛出异常。
    58395877 firstv <list> :同 first ,但结果总是返回值转换后的值。
    58405878 rest% <list> :取列表第一个元素以外的元素值经过转发的值构成的列表。
    58415879 rest& <list> :取列表第一个元素以外的元素值的引用值构成的列表的子对象引用(@11.2.4) 。
    5842-首先调用 check-list-reference 检查参数是列表引用,对右值的抛出异常。
    5880+首先调用 check-list-reference 检查参数是列表引用,对右值抛出异常。
    58435881 restv <list> :取列表第一个元素以外的元素值构成的列表。
    58445882 equal? <object> <object> :一般相等关系。类似 eqv?(@11.3.2) ,但同时支持表示中具有子项作为子对象(@9.8.2) 的对象。
    58455883 相等定义为:
    @@ -5876,20 +5914,26 @@
    58765914 对 <object1> 指定的抽象列表进行处理,取得部分和。
    58775915 当谓词 <predicate> 成立时结果为 <object2> ,否则继续处理抽象列表中余下的元素。
    58785916 处理抽象的列表的操作通过余下的应用子分别定义:取列表头、取列表尾和部分和的二元合并操作。
    5917+参数 <applicative1> 和参数参数 <applicative2> 应接受两个参数,否则引起错误(@9.5.1) 。
    5918+参数 <applicative3> 应接受两个参数,否则引起错误。
    58795919 调用参数中的应用子的 <object1> 实际参数在不同的应用子调用中可能同一(@9.8.1) 。
    58805920 调用参数中的应用子的底层合并子的当前环境同调用 accl 的动态环境。
    58815921 accr <object1> <predicate> <object2> <applicative1> <applicative2> <applicative3> :在抽象列表的元素上应用右结合的二元操作。
    58825922 操作方式同 accl 。
    58835923 和 accl 不同,可保证合并操作是尾调用;相应地,递归调用不是尾上下文而无法确保 PTC(@9.7.4.1) 。
    58845924 foldr1 <applicative> <object> <list> :同 accr ,但指定谓词为 null? ,应用子分别为 first% 和 rest% 。
    5925+参数 <applicative> 同 accr 的参数 <applicative3> 。
    58855926 同 SRFI-1 的 fold-right ,但只接受一个真列表(@9.9.4) 。
    58865927 名称中的 1 指 <list> 参数的个数。
    58875928 map1 <applicative> <list> :单列表映射操作:使用指定应用子对列表中每个参数进行调用,结果为调用结果的列表。
    5888-参数 <applicative> 应接受一个参数,否则引起错误(@9.5.1) 。
    5929+参数 <applicative> 应接受一个参数,否则引起错误。
    58895930 任意两个 <applicative> 调用的求值及列表构造操作的相对顺序未指定。
    58905931 类似 Kernel 的 map ,但只接受一个真列表(@9.9.4) 。
    58915932 first-null? <list> :复合 first 和 null? 操作。
    5892-可用于实现 nonfoldable? 的检查中的单个项。
    5933+可用于实现 nonfoldable?(@11.4.3) 的检查中的单个项。
    5934+rulist <list> :转换参数为可带有唯一引用的引用列表元素的列表。
    5935+同 rlist ,但在参数是右值时,参数中的列表元素非引用值转换为结果中的列表元素的唯一引用。
    5936+注意消亡值处理和 rlist 不同。
    58935937 list-concat <list1> <list2> :顺序连接两个列表。
    58945938 append <list>... :顺序连接零个或多个列表。
    58955939 若没有参数,结果为空列表。
    @@ -5906,10 +5950,10 @@
    59065950 创建的环境同合并子的局部环境(@8.4.5) 。
    59075951 $let% <bindings> <body> :同 $let ,但保留引用值。
    59085952 $let/e <parent> <bindings> <body> :指定静态环境并局部绑定求值。
    5909-类似 Kernel 的 $let-redirect ,但使用 $lambda/e 而不是 eval 和 $lambda 实现且支持 <parent> ,并返回非引用值。
    5953+类似 Kernel 的 $let-redirect ,但使用 $lambda/e(@11.4.3) 而不是 eval 和 $lambda 实现且支持 <parent> ,并返回非引用值。
    59105954 这允许传递引用值并保证环境的宿主值类型(包含所有权)被正确传递作为求值的父环境,而无需支持扩展 <parent> 中的环境为右值时其中的环境临时对象的生存期。
    59115955 注意此时 <parent> 中的环境中创建的环境对象在表达式求值后仍会因为 $lambda/e% 引入的合并子生存期结束而被销毁。
    5912-$let/e% <parent> <bindings> <body> :同 $let/e ,但使用 $lambda/e% 而不是 $lambda/e 实现,保留引用值。
    5956+$let/e% <parent> <bindings> <body> :同 $let/e ,但使用 $lambda/e%(@11.4.3) 而不是 $lambda/e 实现,保留引用值。
    59135957 derive-current-environment <environment>... :创建当前环境的派生环境:以参数指定的环境和当前环境为父环境的空环境。
    59145958 当前环境以外的父环境顺序同参数顺序。当前环境是最后一个父环境。
    59155959 () make-standard-environment :创建标准环境(standard environment) :以基础环境(@10.1) 为父环境的空环境。
    diff -r 92d04ed3856a -r 37835df0ac3b doc/ProjectRules.txt
    --- a/doc/ProjectRules.txt Sat Mar 13 14:46:42 2021 +0800
    +++ b/doc/ProjectRules.txt Fri Mar 26 22:43:02 2021 +0800
    @@ -1,5 +1,5 @@
    11 /*
    2- © 2013-2020 FrankHB.
    2+ © 2013-2021 FrankHB.
    33
    44 This file is part of the YSLib project, and may only be used,
    55 modified, and distributed under the terms of the YSLib project
    @@ -11,13 +11,13 @@
    1111 /*! \file ProjectRules.txt
    1212 \ingroup Documentation
    1313 \brief 项目组织和管理规则。
    14-\version r1185
    14+\version r1202
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 381
    1717 \par 创建时间:
    1818 2013-02-14 17:59:49 +0800
    1919 \par 修改时间:
    20- 2020-12-07 22:17 +0800
    20+ 2021-03-26 22:05 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -358,12 +358,12 @@
    358358 对宏,对象宏/函数宏之间的变更以及参数列表变更非闭合。
    359359 仅包含替换列表外空白符变更的宏定义是闭合的。
    360360 typedef 名称和别名声明中被声明标识符以外的变更是闭合的;别名模板除了模板参数列表的部分中,被声明标识符以外的变更是闭合的。
    361-对所有被声明的实体,不等价的类型(定义参见 ISO C++ [temps.type] ,另见 [Documentation::LanguageConvention @@5.12.1] )和存储类限定符( static 、 extern 、 mutable 等)变更非闭合。
    361+对所有被声明的实体,不等价的类型(定义参见 ISO C++ [temps.type] ,另见 [Documentation::LanguageConvention @@5.12.1] )和存储类限定符( static 、extern 、mutable 等)变更非闭合。
    362362 推论:对同标记的类类型, struct 与 class 的变更闭合,但 struct 或 class 与 union 之间的变更非闭合。
    363363 推论:对同标记的枚举, enum struct 与 enum class 的变更闭合,但 enum struct 或 enum class 与 enum 之间的变更非闭合。
    364364 对相同类型的特殊成员函数,任意声明仅显式使用或不使用 = default 而不导致其它非平凡变更的变更是闭合的;此外,对函数、函数模板和函数模板特化,闭合变更仅包括:
    365365 在声明的记号序列差异仅包含等价名称变换时,仅由 typedef 名称和别名声明中名称以外部分的变更导致的间接变更;
    366- 函数限定符( inline 、 virtual 、explicit )和 constexpr 的变更;
    366+ 函数限定符( inline 、virtual 、explicit )和 constexpr 的变更;
    367367 显式指定的异常规范中,通过语言规则能保证修改在相同语言规范版本的任何配置下(对模板,包括考虑 [LWG 1330] 修订的规则后任意的实例化上下文和顺序)总是等价的变更;
    368368 推论:对函数、函数模板和函数模板特化,非闭合变更包括:
    369369 是否在任意声明上使用或不使用 = delete ;
    @@ -535,7 +535,7 @@
    535535 module-namespace-name
    536536 nested-module-name
    537537 identifier 规则同 ISO C++ 标识符。
    538-:: 、 ( 和 ) 两边的空白仅作区分记号的示意,实际使用时和标识符之间不保留空格。
    538+:: 、( 和 ) 两边的空白仅作区分记号的示意,实际使用时和标识符之间不保留空格。
    539539 此处语法使用 :: 而不使用 . 或其它分隔符并非语义上必要,而是为了便于和一般文件名相区分。
    540540
    541541 @3.2.1 简单模块名称约定:
    @@ -577,11 +577,11 @@
    577577 考虑可移植性,在每一个目录下,保证其中所有文件名和目录名中的所有字符在默认区域下使用 std::tolower 转换后得到的文件名不重复。
    578578
    579579 @3.4.2 可包含字符例外:
    580-除了 YBase([Documentation::YBase]) ,在文件名(但对存在扩展名的文件名,不包含扩展名部分)和目录名中允许使用大写字母。
    580+除 YBase([Documentation::YBase]) ,在文件名(但对存在扩展名的文件名,不包含扩展名部分)和目录名中允许使用大写字母。
    581581
    582582 @3.4.3 包含源文件扩展名:
    583583 被包含的源文件作为头文件(@2.2.9) ,一般使用 h ;但设计时即确定不需要作为独立单元(@3.1) 的实现文件(如仅包含模板的实现或元编程设施)的头文件使用 hpp 。
    584-扩展名 h 表示 header 。尽管标准库不保证 header 是文件,但此处可移植的实现要求为文件。扩展名为 h 的头文件可能被 C 、 C++ 、汇编或其它源文件(如 IDL 和资源编辑器)使用。
    584+扩展名 h 表示 header 。尽管标准库不保证 header 是文件,但此处可移植的实现要求为文件。扩展名为 h 的头文件可能被 C 、C++ 、汇编或其它源文件(如 IDL 和资源编辑器)使用。
    585585 扩展名 hpp 表示 C++ only header 。扩展名为 hpp 的头文件仅被 C++ 单元包含使用;翻译时,逻辑上可理解为 h 和 cpp 为扩展名的源文件的组合,即 hpp 文件可单独构成单元(@3.1) 。
    586586 使用 cpp 作为默认编译单元的源文件扩展名(@3.1) 和以上约定协调。
    587587 使用 hh/hxx 和 cc/cxx 等作为扩展名也可对应头文件和源文件。除非另行指定,这种形式保留给源代码生成或不被本项目直接管理的模块(@3.2) 使用。
    @@ -602,6 +602,19 @@
    602602 除非另行指定(如 [Documentation::YBase @@2.5.7.3] ),禁止显式重复包含同一文件或循环依赖;头文件应具有守卫宏(@2.2.9) 。
    603603 实现源文件依赖同名头文件,应保证包含此头文件,但不重复包含此头文件已经包含的其它头文件。
    604604
    605+@3.4.6 外部依赖项文件名:
    606+外部依赖项相关的文件名应使用官方或权威文档的唯一形式。
    607+在一些无法实现的情形(如文件名实际可不唯一),可另行约定使用方式。
    608+对文件名大小写敏感的文件系统中使用和大小写不符合实际文件的文件名可导致构建失败。
    609+指定库的构建系统命令行使用小写的库名称。
    610+
    611+@3.4.6.1 Windows SDK :
    612+注意 Windows SDK 文件名大小写可随不同版本变化而不唯一。
    613+对 #include 预处理命令中包含的 Windows SDK 头,
    614+一般地,具有 Windows. 前缀外的头文件使用字母全为小写的文件名;这在大多数情形下兼容当前版本的文档 https://docs.microsoft.com/windows/win32/api 。
    615+注意使用官方 Windows SDK 实现中实际分发的文件名可能与之不同。
    616+需兼容现代的 MinGW-w64(这是最常用的交叉构建 Windows 应用程序的环境)时,总是使用小写的名称。对不使用小写文件名的例外,需在构建环境中自行确保环境中具有适当的布局(如符号链接)以引用正确的头文件。
    617+
    605618 @3.5 命名空间:
    606619 库和用户程序的代码在逻辑上最终属于一定的命名空间([Documentation::NPL @@4.3.4]) ,对应 C++ 等语言的命名空间特性。(对没有命名空间特性的语言如 C ,则相当于使用全局命名空间,或另行指定以标识符中的前缀等方式作为替代)。
    607620 语言支持的命名空间特性通常具有单一根(一般称为全局命名空间)的树形层次体系。直接从属于全局命名空间的子命名空间称为顶层命名空间。
    Show on old repository browser