• R/O
  • SSH

YSLib: Commit

The YSLib project - main repository


Commit MetaInfo

Revision220a0255d5fc7690b2b52ea03b38c446ef091989 (tree)
Time2022-06-15 02:36:26
AuthorFrankHB <frankhb1989@gmai...>
CommiterFrankHB

Log Message

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

Change Summary

    Incremental Difference

    diff -r 9e7268439539 -r 220a0255d5fc Tools/Scripts/SHBuild-BuildApp.txt
    --- a/Tools/Scripts/SHBuild-BuildApp.txt Sun Jun 05 02:23:03 2022 +0800
    +++ b/Tools/Scripts/SHBuild-BuildApp.txt Wed Jun 15 01:36:26 2022 +0800
    @@ -154,8 +154,8 @@
    154154 putss "Found SHBuild build directory \"" SHBuild_BuildDir "\".";
    155155 $env-de! SHBuild ++ SR_Bin_ "/SHBuild";
    156156 $assert-nonempty SHBuild;
    157- build-with-conf-opt (++ SHBuild_BuildDir "." SHBuild_Conf) host-os debug
    158- dynamic "" #t ($if debug ld-ext-noadjust_
    157+ build-with-conf-opt (++ SHBuild_BuildDir "." SHBuild_Conf) host-arch host-os
    158+ debug dynamic "" #t ($if debug ld-ext-noadjust_
    159159 ld-ext-adjust_win32_subsystem_) ($lambda (#ignore CXXFLAGS SHBOPT .)
    160160 (
    161161 "TODO", "Support precompiled headers?";
    diff -r 9e7268439539 -r 220a0255d5fc Tools/Scripts/SHBuild-YSLib-build.txt
    --- a/Tools/Scripts/SHBuild-YSLib-build.txt Sun Jun 05 02:23:03 2022 +0800
    +++ b/Tools/Scripts/SHBuild-YSLib-build.txt Wed Jun 15 01:36:26 2022 +0800
    @@ -104,6 +104,11 @@
    104104 ++ SHBuild_BuildDir "/.shbuild" ($if dynamic "-dll" "")
    105105 ($if debug "-debug" "");
    106106
    107+$defl! host-build-with-conf-opt_
    108+ (outdir debug dynamic shbopt-ext app do-ld-ext do-build)
    109+ build-with-conf-opt outdir host-arch host-os debug dynamic shbopt-ext app
    110+ do-ld-ext do-build;
    111+
    107112 SHBuild_EnsureDirectory_ SHBuild_BuildDir;
    108113 $defl! skip-or-build_ (nskip dynamic debug) $let
    109114 (
    @@ -142,7 +147,7 @@
    142147 "XXX", "No need to set %LDFLAGS, since it is always set in the",
    143148 " call to 'build-with-conf-opt' for dynamic libraries.";
    144149 $if dynamic (safeenv-restore "LIBS");
    145- build-with-conf-opt outdir host-os debug dynamic
    150+ host-build-with-conf-opt_ outdir debug dynamic
    146151 "-xid,alternative -xid,data -xid,include -xid,Android" #f
    147152 ld-ext-noadjust_ ($lambda (CXX CXXFLAGS SHBOPT LIBPFX)
    148153 (
    @@ -336,8 +341,8 @@
    336341 putss "Building " target-name " ...";
    337342 $assert-absolute-path src-dir;
    338343 "XXX", "Extra options for SHBOPT are always empty now.";
    339- build-with-conf-opt SR_SHBuild_ host-os #f #t "" #t ld-ext-noadjust_
    340- ($lambda (CXX CXXFLAGS SHBOPT LIBPFX)
    344+ host-build-with-conf-opt_ SR_SHBuild_ #f #t "" #t
    345+ ld-ext-noadjust_ ($lambda (CXX CXXFLAGS SHBOPT LIBPFX)
    341346 system-check (apply cons-cmd (append (list e_S1_SHBuild_
    342347 src-dir SHBOPT) extra-opts (list CXXFLAGS INCLUDES_))));
    343348 putss "Finished building " target-name "."
    @@ -366,7 +371,7 @@
    366371 $def! tools-list list "RevisionPatcher" "SXML2XML" "ProjectGenerator";
    367372 "XXX", "'SHBuild_BaseDir' is fixed in parallel to these directories of",
    368373 " these tools, while 'SHBuild_ToolDir' is expected more portable.";
    369- build-with-conf-opt SR_SHBuild_ host-os #f #t "" #t
    374+ host-build-with-conf-opt_ SR_SHBuild_ #f #t "" #t
    370375 ld-ext-noadjust_ ($lambda (CXX CXXFLAGS SHBOPT LIBPFX)
    371376 for-each-ltr ($lambda (name)
    372377 system-check (apply cons-cmd (append
    diff -r 9e7268439539 -r 220a0255d5fc Tools/Scripts/SHBuild-YSLib-common.txt
    --- a/Tools/Scripts/SHBuild-YSLib-common.txt Sun Jun 05 02:23:03 2022 +0800
    +++ b/Tools/Scripts/SHBuild-YSLib-common.txt Wed Jun 15 01:36:26 2022 +0800
    @@ -382,8 +382,8 @@
    382382 $defl! use-ubsan? (opt) use-fsanitize? "undefined" opt;
    383383 $defl! use-lsan? (opt) use-fsanitize? "leak" opt;
    384384
    385-$defl! build-with-conf-opt (outdir host-os debug dynamic shbopt-ext app
    386- do-ld-ext do-build)
    385+$defl! build-with-conf-opt (outdir host-arch host-os debug dynamic shbopt-ext
    386+ app do-ld-ext do-build)
    387387 (
    388388 $import! std.strings string->symbol,
    389389 $import! std.promises $lazy force,
    @@ -464,18 +464,19 @@
    464464 "CXXFLAGS_IMPL_WARNING" cons-cmd
    465465 "-Wconditionally-supported" "-Wno-noexcept-type"
    466466 "-Wstrict-null-sentinel" "-Wzero-as-null-pointer-constant";
    467+ $def! LTO_ $if ($and (win32? host-os) (eqv? host-arch "i686"))
    468+ "-flto=jobserver" "-flto=auto";
    467469 $redef! prom_CXXFLAGS_IMPL_OPT $lazy-env-val "CXXFLAGS_IMPL_OPT"
    468- cons-cmd "-fexpensive-optimizations"
    469- ($if (win32? host-os) "-flto=auto" "-flto=jobserver")
    470+ cons-cmd "-fexpensive-optimizations" LTO_
    470471 "-fno-enforce-eh-specs";
    471472 $if use-ld
    472473 (
    473- "XXX", "Workaround for LTO bug on MinGW. See https://sourceware.org/bugzilla/show_bug.cgi?id=12762.";
    474+ "XXX", "Workaround for LTO bug on MinGW. See",
    475+ " https://sourceware.org/bugzilla/show_bug.cgi?id=12762.";
    474476 $redef! prom_LDFLAGS_IMPL_OPT $lazy-env-val "LDFLAGS_IMPL_OPT"
    475- $if (win32? host-os)
    476- (++ "-fexpensive-optimizations -flto=jobserver"
    477- " -Wl,-allow-multiple-definition")
    478- "-fexpensive-optimizations -flto=auto"
    477+ (++ "-fexpensive-optimizations " LTO_
    478+ ($if (win32? host-os) " -Wl,-allow-multiple-definition"
    479+ ""))
    479480 )
    480481 ));
    481482 $def! prom_CFLAGS_STD $lazy-env-val "CFLAGS_STD" "-std=c11";
    diff -r 9e7268439539 -r 220a0255d5fc Tools/Scripts/SHBuild-build.sh
    --- a/Tools/Scripts/SHBuild-build.sh Sun Jun 05 02:23:03 2022 +0800
    +++ b/Tools/Scripts/SHBuild-build.sh Wed Jun 15 01:36:26 2022 +0800
    @@ -1,5 +1,5 @@
    11 #!/usr/bin/env bash
    2-# (C) 2014-2018, 2020-2021 FrankHB.
    2+# (C) 2014-2018, 2020-2022 FrankHB.
    33 # Build script for SHBuild.
    44
    55 set -e
    @@ -33,19 +33,28 @@
    3333
    3434 : "${SHBuild_Output:=SHBuild}"
    3535
    36-# XXX: After MSYS2 enables ASLR by default, x86_64 binutils with g++ is buggy.
    36+# XXX: After MSYS2 enabling ASLR by default, x86_64 binutils with g++ is buggy.
    3737 # See https://www.msys2.org/news/#2021-01-31-aslr-enabled-by-default,
    3838 # https://github.com/msys2/MINGW-packages/issues/6986,
    3939 # https://github.com/msys2/MINGW-packages/issues/7023,
    4040 # and https://sourceware.org/bugzilla/show_bug.cgi?id=26659. Here is a
    4141 # workaround to the issue.
    42+# XXX: This is now fixed by https://github.com/msys2/MINGW-packages/pull/8259.
    43+# TODO: Detect precise version?
    44+# XXX: There are some other bugs not resolved for ld.bfd on PE targets:
    45+# https://sourceware.org/bugzilla/show_bug.cgi?id=11539,
    46+# https://sourceware.org/bugzilla/show_bug.cgi?id=19803.
    4247 if [[ "$SHBuild_Host_OS" == 'Win32' && "$SHBuild_Host_Arch" == 'x86_64' \
    4348 && "$SHBuild_CXX_Style_" == 'G++' ]]; then
    44- LDFLAGS_LOWBASE_="$(SHBuild_CheckCompiler "$CXX" \
    45- 'int main(){}' -Wl,--default-image-base-low '' \
    46- -xc++ -Wl,--default-image-base-low)"
    49+# LDFLAGS_WKRD_="$(SHBuild_CheckCompiler "$CXX" \
    50+# 'int main(){}' -Wl,--default-image-base-low '' \
    51+# -xc++ -Wl,--default-image-base-low)"
    52+ # XXX: The linker (ld) from mingw-w64-x86_64-binutils 2.38-3 versions does
    53+ # not work otherwise. And mingw-w64-x86_64-lld-14.0.4-1 does not work with
    54+ # LTO here.
    55+ LDFLAGS_WKRD_='-fuse-ld=lld'
    4756 else
    48- LDFLAGS_LOWBASE_=
    57+ LDFLAGS_WKRD_=
    4958 fi
    5059
    5160 SHBuild_Pushd .
    @@ -71,11 +80,11 @@
    7180 # XXX: Value of several variables may contain whitespaces.
    7281 # shellcheck disable=2086
    7382 SHBuild_Puts "$CXX" Main.cpp -o"$SHBuild_Output" $CXXFLAGS $LDFLAGS \
    74- $LDFLAGS_LOWBASE_ $SHBuild_IncPCH $INCLUDES $LIBS
    83+ $LDFLAGS_WKRD_ $SHBuild_IncPCH $INCLUDES $LIBS
    7584 fi
    7685 # XXX: Value of several variables may contain whitespaces.
    7786 # shellcheck disable=2086
    78-"$CXX" Main.cpp -o"$SHBuild_Output" $CXXFLAGS $LDFLAGS $LDFLAGS_LOWBASE_ \
    87+"$CXX" Main.cpp -o"$SHBuild_Output" $CXXFLAGS $LDFLAGS $LDFLAGS_WKRD_ \
    7988 $SHBuild_IncPCH $INCLUDES $LIBS
    8089
    8190 SHBuild_Popd
    diff -r 9e7268439539 -r 220a0255d5fc Tools/Scripts/SHBuild-common-options.sh
    --- a/Tools/Scripts/SHBuild-common-options.sh Sun Jun 05 02:23:03 2022 +0800
    +++ b/Tools/Scripts/SHBuild-common-options.sh Wed Jun 15 01:36:26 2022 +0800
    @@ -115,7 +115,8 @@
    115115 # LDFLAGS_IMPL_USE_LLD_=true
    116116 #: "${CXXFLAGS_IMPL_OPT:=-flto}"
    117117 #: "${LDFLAGS_IMPL_OPT:=-flto}"
    118- # XXX: LTO is disabled by default for compatibility to the prebuilt binaries.
    118+ # XXX: LTO is disabled by default for compatibility to the prebuilt
    119+ # binaries (by G++).
    119120 elif [[ $SHBuild_CXX_Style_ == "G++" ]]; then
    120121 : "${C_CXXFLAGS_IMPL_WARNING:="-Wdouble-promotion \
    121122 -Wlogical-op \
    @@ -129,23 +130,27 @@
    129130 -Wsuggest-final-types \
    130131 -Wsuggest-final-methods \
    131132 -Wzero-as-null-pointer-constant"}"
    132- if [[ "$SHBuild_Host_OS" == 'Win32' ]]; then
    133- : "${CXXFLAGS_IMPL_OPT:="-fexpensive-optimizations \
    134--flto=jobserver \
    135--fno-enforce-eh-specs"}"
    133+ # XXX: %SHBuild_Host_OS and %SHBuild_host_Arch are external.
    134+ # shellcheck disable=2154
    135+ # XXX: Only i686 MinGW32 uses old GCC not supporting -flto=auto now.
    136+ if [[ "$SHBuild_Host_OS" == 'Win32' && "$SHBuild_Host_Arch" == 'i686' ]]; \
    137+then
    138+ LTO_=-flto=jobserver
    136139 else
    137- : "${CXXFLAGS_IMPL_OPT:="-fexpensive-optimizations \
    138--flto=auto \
    140+ LTO_=-flto=auto
    141+ fi
    142+ : "${CXXFLAGS_IMPL_OPT:="-fexpensive-optimizations \
    143+$LTO_ \
    139144 -fno-enforce-eh-specs"}"
    140- fi
    141- # XXX: Workarond for LTO bug on MinGW. See https://sourceware.org/bugzilla/show_bug.cgi?id=12762.
    142145 # XXX: %SHBuild_Host_OS is external.
    143146 # shellcheck disable=2154
    144147 if [[ "$SHBuild_Host_OS" == 'Win32' ]]; then
    145- : "${LDFLAGS_IMPL_OPT:="-fexpensive-optimizations -flto=jobserver \
    148+ # XXX: Workarond for LTO bug on MinGW. See
    149+ # https://sourceware.org/bugzilla/show_bug.cgi?id=12762.
    150+ : "${LDFLAGS_IMPL_OPT:="-fexpensive-optimizations $LTO_ \
    146151 -Wl,-allow-multiple-definition"}"
    147152 else
    148- : "${LDFLAGS_IMPL_OPT:=-fexpensive-optimizations -flto=auto}"
    153+ : "${LDFLAGS_IMPL_OPT:=-fexpensive-optimizations $LTO_}"
    149154 fi
    150155 fi
    151156
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/include/NPL/NPLA.h
    --- a/YFramework/include/NPL/NPLA.h Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/include/NPL/NPLA.h Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA.h
    1212 \ingroup NPL
    1313 \brief NPLA 公共接口。
    14-\version r9468
    14+\version r9543
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 663
    1717 \par 创建时间:
    1818 2016-01-07 10:32:34 +0800
    1919 \par 修改时间:
    20- 2022-05-08 16:16 +0800
    20+ 2022-06-14 18:41 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -36,16 +36,16 @@
    3636 // ystdex::is_nothrow_copy_constructible, ystdex::is_nothrow_copy_assignable,
    3737 // ystdex::is_nothrow_move_constructible, ystdex::is_nothrow_move_assignable,
    3838 // EnsureValueTags, AssertValueTags, IsTyped, ThrowListTypeErrorForInvalidType,
    39-// observer_ptr, TryAccessValue, IsLeaf, ystdex::equality_comparable, weak_ptr,
    40-// lref, ystdex::get_equal_to, NPL::IsMovable, pair, ystdex::invoke_value_or,
    41-// ystdex::expand_proxy, NPL::Access, ystdex::ref_eq, ValueObject,
    42-// NPL::SetContentWith, std::for_each, AccessFirstSubterm, AssertBranch,
    43-// NPL::Deref, YSLib::EmplaceCallResult, ystdex::less, YSLib::map, pmr,
    44-// ystdex::copy_and_swap, NoContainer, ystdex::try_emplace,
    45-// ystdex::try_emplace_hint, ystdex::insert_or_assign, type_info,
    46-// ystdex::expanded_function, ystdex::enable_if_same_param_t,
    39+// observer_ptr, TryAccessValue, IsAtom, IsLeaf, ystdex::equality_comparable,
    40+// weak_ptr, lref, AssertReferentTags, ystdex::get_equal_to, NPL::IsMovable,
    41+// pair, std::declval, ystdex::invoke_value_or, ystdex::expand_proxy,
    42+// Access, ystdex::ref_eq, ValueObject, NPL::SetContentWith, std::for_each,
    43+// AccessFirstSubterm, AssertBranch, NPL::Deref, YSLib::EmplaceCallResult,
    44+// ystdex::less, YSLib::map, pmr, ystdex::copy_and_swap, NoContainer,
    45+// ystdex::try_emplace, ystdex::try_emplace_hint, ystdex::insert_or_assign,
    46+// type_info, ystdex::expanded_function, ystdex::enable_if_same_param_t,
    4747 // ystdex::exclude_self_t, ystdex::make_obj_using_allocator,
    48-// YSLib::forward_list, ystdex::swap_dependent, NPL::make_observer,
    48+// YSLib::forward_list, ystdex::swap_dependent, make_observer,
    4949 // YSLib::allocate_shared, YSLib::Logger, trivial_swap, ystdex::exchange,
    5050 // NPL::AsTermNode, ystdex::is_bitwise_swappable;
    5151 #include <ystdex/base.h> // for ystdex::derived_entity;
    @@ -112,7 +112,7 @@
    112112 /*!
    113113 \brief 转义 NPLA 节点字面量。
    114114 \return 调用 EscapeLiteral 转义访问字符串的结果。
    115-\exception bad_any_cast 异常中立:由 NPL::Access 抛出。
    115+\exception bad_any_cast 异常中立:由 Access 抛出。
    116116 \since build 597
    117117 */
    118118 YB_ATTR_nodiscard YF_API YB_PURE string
    @@ -498,15 +498,15 @@
    498498 \note 第一参数是可能带有 const 的左值的 TermNode 或转换为 TermNode 的类型。
    499499 \sa ThrowListTypeErrorForInvalidType
    500500
    501-以 NPL::Access 访问调用 NPL::CheckRegular 检查后的项。
    501+以 Access 访问调用 NPL::CheckRegular 检查后的项。
    502502 */
    503503 template<typename _type, class _tTerm>
    504504 YB_ATTR_nodiscard YB_PURE inline auto
    505505 AccessRegular(_tTerm& term, bool has_ref)
    506- -> yimpl(decltype(NPL::Access<_type>(term)))
    506+ -> yimpl(decltype(Access<_type>(term)))
    507507 {
    508508 NPL::CheckRegular<_type>(term, has_ref);
    509- return NPL::Access<_type>(term);
    509+ return Access<_type>(term);
    510510 }
    511511 //@}
    512512
    @@ -541,10 +541,33 @@
    541541 //@}
    542542
    543543 /*!
    544+\brief 尝试访问不构成有序对的节点的指定类型对象指针。
    545+\sa IsAtom
    546+\sa TryAccessLeafAtom
    547+\since build 947
    548+
    549+尝试排除有序对并访问作为叶节点的 TermNode 。
    550+*/
    551+//@{
    552+template<typename _type>
    553+YB_ATTR_nodiscard YB_PURE inline observer_ptr<_type>
    554+TryAccessLeafAtom(TermNode& term)
    555+{
    556+ return IsAtom(term) ? TryAccessLeaf<_type>(term) : nullptr;
    557+}
    558+template<typename _type>
    559+YB_ATTR_nodiscard YB_PURE inline observer_ptr<const _type>
    560+TryAccessLeafAtom(const TermNode& term)
    561+{
    562+ return IsAtom(term) ? TryAccessLeaf<_type>(term) : nullptr;
    563+}
    564+//@}
    565+
    566+/*!
    544567 \brief 尝试访问项的指定类型叶节点对象指针。
    545568
    546569 尝试访问 TermNode 。
    547-类似 NPL::TryAccessLeaf ,但先使用 NPL::IsLeaf 判断叶节点,
    570+类似 TryAccessLeaf ,但先使用 NPL::IsLeaf 判断叶节点,
    548571 对非叶节点直接返回空指针。
    549572 */
    550573 //@{
    @@ -552,13 +575,13 @@
    552575 YB_ATTR_nodiscard YB_PURE inline observer_ptr<_type>
    553576 TryAccessTerm(TermNode& term)
    554577 {
    555- return IsLeaf(term) ? NPL::TryAccessLeaf<_type>(term) : nullptr;
    578+ return IsLeaf(term) ? TryAccessLeaf<_type>(term) : nullptr;
    556579 }
    557580 template<typename _type>
    558581 YB_ATTR_nodiscard YB_PURE inline observer_ptr<const _type>
    559582 TryAccessTerm(const TermNode& term)
    560583 {
    561- return IsLeaf(term) ? NPL::TryAccessLeaf<_type>(term) : nullptr;
    584+ return IsLeaf(term) ? TryAccessLeaf<_type>(term) : nullptr;
    562585 }
    563586 //@}
    564587 //@}
    @@ -571,7 +594,7 @@
    571594 */
    572595 YB_ATTR_nodiscard YB_PURE inline
    573596 PDefH(observer_ptr<const TokenValue>, TermToNamePtr, const TermNode& term)
    574- ImplRet(NPL::TryAccessTerm<TokenValue>(term))
    597+ ImplRet(TryAccessTerm<TokenValue>(term))
    575598
    576599 /*!
    577600 \return 转换得到的字符串。
    @@ -600,9 +623,11 @@
    600623
    601624 /*!
    602625 \brief 访问项初始化标签。
    603-\since build 857
    626+\pre 参数的标签可表示被引用对象。
    627+\sa AssertReferentTags
    604628 \sa GetLValueTagsOf
    605629 \sa TermTags
    630+\since build 857
    606631
    607632 若项表示引用值,使用引用值排除 TermTags::Temporary 后的标签;
    608633 否则,使用项的标签。
    @@ -796,6 +821,7 @@
    796821 lref<TermNode> term_ref;
    797822 /*!
    798823 \brief 引用标签。
    824+ \invariant \c IsReferentTags(tags) 。
    799825 \since build 857
    800826 */
    801827 TermTags tags = TermTags::Unqualified;
    @@ -816,6 +842,8 @@
    816842 : TermReference(TermToTags(term), term, yforward(arg),
    817843 yforward(args)...)
    818844 {}
    845+ //! \pre 第一参数可表示被引用对象。
    846+ //@{
    819847 /*!
    820848 \brief 构造:使用参数指定的标签及引用。
    821849 \since build 894
    @@ -824,7 +852,7 @@
    824852 inline
    825853 TermReference(TermTags t, TermNode& term, _tParam&& arg, _tParams&&... args)
    826854 ynothrow
    827- : term_ref(term), tags(t),
    855+ : term_ref(term), tags((AssertReferentTags(t), t)),
    828856 r_env(yforward(arg), yforward(args)...)
    829857 {}
    830858 /*!
    @@ -833,12 +861,15 @@
    833861 */
    834862 //@{
    835863 TermReference(TermTags t, const TermReference& ref) ynothrow
    836- : term_ref(ref.term_ref), tags(t), r_env(ref.r_env)
    864+ : term_ref(ref.term_ref), tags((AssertReferentTags(t), t)),
    865+ r_env(ref.r_env)
    837866 {}
    838867 TermReference(TermTags t, TermReference&& ref) ynothrow
    839- : term_ref(ref.term_ref), tags(t), r_env(std::move(ref.r_env))
    868+ : term_ref(ref.term_ref), tags((AssertReferentTags(t), t)),
    869+ r_env(std::move(ref.r_env))
    840870 {}
    841871 //@}
    872+ //@}
    842873 //! \since build 855
    843874 DefDeCopyMoveCtorAssignment(TermReference)
    844875
    @@ -990,18 +1021,19 @@
    9901021 \brief 访问项并取解析 TermReference 间接值后的引用。
    9911022 \return 若项的 Value 数据成员为 TermReference 则为其中的引用,否则为参数。
    9921023 \sa TermReference
    1024+\sa TryAccessLeafAtom
    9931025 \since build 854
    9941026 */
    9951027 YB_ATTR_nodiscard YB_PURE inline
    9961028 PDefH(TermNode&, ReferenceTerm, TermNode& term)
    9971029 ynoexcept_spec(std::declval<TermReference>().get())
    9981030 ImplRet(ystdex::invoke_value_or(&TermReference::get,
    999- NPL::TryAccessLeaf<const TermReference>(term), term))
    1031+ TryAccessLeafAtom<TermReference>(term), term))
    10001032 YB_ATTR_nodiscard YB_PURE inline
    10011033 PDefH(const TermNode&, ReferenceTerm, const TermNode& term)
    1002- ynoexcept_spec(std::declval<TermReference>().get())
    1034+ ynoexcept_spec(std::declval<const TermReference>().get())
    10031035 ImplRet(ystdex::invoke_value_or(&TermReference::get,
    1004- NPL::TryAccessLeaf<const TermReference>(term), term))
    1036+ TryAccessLeafAtom<const TermReference>(term), term))
    10051037
    10061038 /*!
    10071039 \ingroup functors
    @@ -1098,7 +1130,7 @@
    10981130 //@{
    10991131 /*!
    11001132 \sa NPL::ReferenceTerm
    1101-\sa NPL::TryAccessLeaf
    1133+\sa TryAccessLeaf
    11021134 \since build 854
    11031135 */
    11041136 //@{
    @@ -1106,18 +1138,18 @@
    11061138 YB_ATTR_nodiscard YB_PURE inline observer_ptr<_type>
    11071139 TryAccessReferencedLeaf(TermNode& term)
    11081140 {
    1109- return NPL::TryAccessLeaf<_type>(ReferenceTerm(term));
    1141+ return TryAccessLeafAtom<_type>(ReferenceTerm(term));
    11101142 }
    11111143 template<typename _type>
    11121144 YB_ATTR_nodiscard YB_PURE inline observer_ptr<const _type>
    11131145 TryAccessReferencedLeaf(const TermNode& term)
    11141146 {
    1115- return NPL::TryAccessLeaf<_type>(ReferenceTerm(term));
    1147+ return TryAccessLeafAtom<_type>(ReferenceTerm(term));
    11161148 }
    11171149 //@}
    11181150
    11191151 /*!
    1120-\sa NPL::TryAccessTerm
    1152+\sa TryAccessTerm
    11211153 \since build 858
    11221154 */
    11231155 //@{
    @@ -1125,18 +1157,18 @@
    11251157 YB_ATTR_nodiscard YB_PURE inline observer_ptr<_type>
    11261158 TryAccessReferencedTerm(TermNode& term)
    11271159 {
    1128- return NPL::TryAccessTerm<_type>(ReferenceTerm(term));
    1160+ return TryAccessTerm<_type>(ReferenceTerm(term));
    11291161 }
    11301162 template<typename _type>
    11311163 YB_ATTR_nodiscard YB_PURE inline observer_ptr<const _type>
    11321164 TryAccessReferencedTerm(const TermNode& term)
    11331165 {
    1134- return NPL::TryAccessTerm<_type>(ReferenceTerm(term));
    1166+ return TryAccessTerm<_type>(ReferenceTerm(term));
    11351167 }
    11361168 //@}
    11371169 //@}
    11381170
    1139-//! \note 使用 NPL::TryAccessLeaf 访问。
    1171+//! \note 使用 TryAccessLeaf 访问。
    11401172 //@{
    11411173 /*!
    11421174 \brief 判断项(的值数据成员)是否为引用项。
    @@ -1196,6 +1228,7 @@
    11961228 \sa ResolveTermHandler
    11971229 \sa ResolvedTermReferencePtr
    11981230 \sa TermReference
    1231+\sa TryAccessLeafAtom
    11991232
    12001233 接受指定解析实现的函数和被解析的项作为参数,尝试访问其中是否具有引用值。
    12011234 若确定是引用值,则被引用的项是被引用值引用的项;否则,被引用的项是第二参数指定的项。
    @@ -1219,9 +1252,11 @@
    12191252 using handler_t = yimpl(void)(_tTerm&&, ResolvedTermReferencePtr);
    12201253
    12211254 // XXX: Assume value representation of %term is not trivially regular.
    1222- if(const auto p = NPL::TryAccessLeaf<const TermReference>(term))
    1255+ if(const auto p = TryAccessLeafAtom<const TermReference>(term))
    1256+ {
    12231257 return ystdex::expand_proxy<handler_t>::call(do_resolve, p->get(),
    12241258 NPL::ResolveToTermReferencePtr(p));
    1259+ }
    12251260 return ystdex::expand_proxy<handler_t>::call(do_resolve,
    12261261 yforward(term), ResolvedTermReferencePtr());
    12271262 }
    @@ -1230,10 +1265,10 @@
    12301265 \brief 访问一次解析引用值后的项的指定类型正规值。
    12311266 \exception ListTypeError 异常中立:项为列表项。
    12321267 \exception bad_any_cast 异常中立:非列表项类型检查失败。
    1233-\sa NPL::AccessRegular
    1268+\sa AccessRegular
    12341269 \sa NPL::ResolveTerm
    12351270
    1236-以 NPL::AccessRegular 访问调用 NPL::ResolveTerm 解析引用值得到的项。
    1271+以 AccessRegular 访问调用 NPL::ResolveTerm 解析引用值得到的项。
    12371272 若遇到正规值为引用值,则进行解引用后继续访问。解引用至多一次。
    12381273 和 YSLib::Access 访问 ValueNode 类似,但调用 NPL::ResolveTerm
    12391274 解析引用重定向到目标,且首先对检查项,若项为列表项使用
    @@ -1241,11 +1276,11 @@
    12411276 */
    12421277 template<typename _type, class _tTerm>
    12431278 YB_ATTR_nodiscard YB_PURE inline auto
    1244-ResolveRegular(_tTerm& term) -> yimpl(decltype(NPL::Access<_type>(term)))
    1279+ResolveRegular(_tTerm& term) -> yimpl(decltype(Access<_type>(term)))
    12451280 {
    12461281 return NPL::ResolveTerm([&](_tTerm& nd, bool has_ref)
    1247- -> yimpl(decltype(NPL::Access<_type>(term))){
    1248- return NPL::AccessRegular<_type>(nd, has_ref);
    1282+ -> yimpl(decltype(Access<_type>(term))){
    1283+ return AccessRegular<_type>(nd, has_ref);
    12491284 }, term);
    12501285 }
    12511286 //@}
    @@ -1273,7 +1308,7 @@
    12731308 template<class _tTerm>
    12741309 YB_ATTR_nodiscard YB_PURE inline auto
    12751310 operator()(_tTerm& term) const
    1276- -> yimpl(decltype(NPL::Access<_type>(term)))
    1311+ -> yimpl(decltype(Access<_type>(term)))
    12771312 {
    12781313 return NPL::ResolveRegular<_type>(term);
    12791314 }
    @@ -1332,7 +1367,7 @@
    13321367 {
    13331368 return NPL::ResolveTerm([](_tTerm& nd, ResolvedTermReferencePtr p_ref){
    13341369 return ResolvedArg<_type>(
    1335- NPL::AccessRegular<_type>(nd, p_ref), p_ref);
    1370+ AccessRegular<_type>(nd, p_ref), p_ref);
    13361371 }, term);
    13371372 }
    13381373 };
    @@ -2408,6 +2443,8 @@
    24082443 void
    24092444 clear() ynothrow
    24102445 {
    2446+ // XXX: There is generally no more efficient implementation using
    2447+ // iterator explicitly for %forward_list.
    24112448 while(!empty())
    24122449 pop_front();
    24132450 }
    @@ -2437,7 +2474,7 @@
    24372474
    24382475 public:
    24392476 ReductionGuard(ContextNode& ctx) ynothrow
    2440- : p_ctx(NPL::make_observer(&ctx)), i_stacked(ctx.stacked.cbegin())
    2477+ : p_ctx(make_observer(&ctx)), i_stacked(ctx.stacked.cbegin())
    24412478 {
    24422479 ctx.stacked.splice_after(ctx.stacked.cbefore_begin(),
    24432480 ctx.current);
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/include/NPL/NPLA1.h
    --- a/YFramework/include/NPL/NPLA1.h Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/include/NPL/NPLA1.h Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA1.h
    1212 \ingroup NPL
    1313 \brief NPLA1 公共接口。
    14-\version r9469
    14+\version r9480
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 472
    1717 \par 创建时间:
    1818 2014-02-02 17:58:24 +0800
    1919 \par 修改时间:
    20- 2022-05-30 18:54 +0800
    20+ 2022-06-14 18:41 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -32,7 +32,7 @@
    3232 #include YFM_NPL_NPLA // for NPLATag, TermNode, ContextNode,
    3333 // ystdex::equality_comparable, std::declval, ystdex::exclude_self_t,
    3434 // trivial_swap_t, trivial_swap, ystdex::ref_eq, string_view,
    35-// CombineReductionResult, pmr::memory_resource, NPL::make_observer,
    35+// CombineReductionResult, pmr::memory_resource, make_observer,
    3636 // AssertMatchedAllocators, TNIter, LiftOtherValue, ValueNode, NPL::Deref,
    3737 // NPL::AsTermNode, std::make_move_iterator, std::next, ystdex::retry_on_cond,
    3838 // std::find_if, ystdex::exclude_self_params_t, YSLib::AreEqualHeld,
    @@ -388,14 +388,14 @@
    388388 \since build 895
    389389 */
    390390 PDefH(void, SetCombiningTermRef, TermNode& term) ynothrow
    391- ImplExpr(combining_term_ptr = NPL::make_observer(&term))
    391+ ImplExpr(combining_term_ptr = make_observer(&term))
    392392 /*!
    393393 \brief 设置下一求值项引用。
    394394 \sa next_term_ptr
    395395 \since build 883
    396396 */
    397397 PDefH(void, SetNextTermRef, TermNode& term) ynothrow
    398- ImplExpr(next_term_ptr = NPL::make_observer(&term))
    398+ ImplExpr(next_term_ptr = make_observer(&term))
    399399
    400400 /*!
    401401 \brief 清除规约合并项指针。
    @@ -1371,7 +1371,7 @@
    13711371 // NOTE: This is optional, as it is not guaranteed to be saved as
    13721372 // %ContextHandler in %ReduceCombined.
    13731373 ImplExpr([&]{
    1374- if(const auto p_handler = NPL::TryAccessTerm<const LiteralHandler>(tm))
    1374+ if(const auto p_handler = TryAccessTerm<const LiteralHandler>(tm))
    13751375 RegularizeTerm(term, (*p_handler)(ctx));
    13761376 }())
    13771377
    @@ -1800,10 +1800,10 @@
    18001800 \note 当参数指定 TCO 时且保存记号值时保存的值即为名称,否则名称不存在。
    18011801 \return 若存在名称则为内部保存的名称字符串,否则是数据指针为空的结果。
    18021802 \note 仅在 TCO 动作存在时支持。
    1803-\since build 896
    1803+\since build 947
    18041804 */
    18051805 YB_ATTR_nodiscard YF_API observer_ptr<const ValueObject>
    1806-QueryTailOperatorName(const Reducer&);
    1806+QueryTailOperatorName(const Reducer&) ynothrow;
    18071807
    18081808 /*!
    18091809 \brief 查询全局类型名称表。
    @@ -1817,13 +1817,13 @@
    18171817 \return 是否成功。
    18181818 \warning 若不满足上下文状态类型要求,行为未定义。
    18191819 \sa ContextState::GetCombiningTermPtr
    1820-\since build 896
    1820+\since build 947
    18211821
    18221822 检查第一参数指定的项是否同第二参数保存的规约合并项的第一项,若成功视为操作符项,
    18231823 并转移操作符项的值数据成员到规约合并项。
    18241824 */
    1825-YF_API bool
    1826-SetupTailOperatorName(TermNode&, const ContextNode&);
    1825+bool
    1826+SetupTailOperatorName(TermNode&, const ContextNode&) ynothrow;
    18271827
    18281828 /*!
    18291829 \brief 追踪记录 NPL 续延。
    @@ -2234,7 +2234,9 @@
    22342234 \brief 尝试加载源代码。
    22352235 \exception NPLException 嵌套异常:加载失败。
    22362236 \note 第二参数表示来源,仅用于诊断消息。
    2237+\note 不使用可能自定义的 REPLContext::Load 。
    22372238 \relates REPLContext
    2239+\sa REPLContext::LoadFrom
    22382240 \since build 838
    22392241 */
    22402242 template<typename... _tParams>
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/include/NPL/NPLA1Forms.h
    --- a/YFramework/include/NPL/NPLA1Forms.h Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/include/NPL/NPLA1Forms.h Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA1Forms.h
    1212 \ingroup NPL
    1313 \brief NPLA1 语法形式。
    14-\version r8723
    14+\version r8742
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 882
    1717 \par 创建时间:
    1818 2020-02-15 11:19:21 +0800
    1919 \par 修改时间:
    20- 2022-04-25 18:07 +0800
    20+ 2022-06-14 18:32 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -31,11 +31,10 @@
    3131 #include "YModules.h"
    3232 #include YFM_NPL_NPLA1 // for shared_ptr, TermNode, ReductionStatus, string,
    3333 // TokenValue, AssertBranch, ystdex::exclude_self_t, ystdex::expand_proxy,
    34-// NPL::ResolveTerm, std::next, NPL::Access, NPL::Deref,
    35-// Forms::CallResolvedUnary, ResolvedTermReferencePtr, NPL::AccessRegular,
    36-// ystdex::make_expanded, std::ref, ystdex::invoke_nonvoid, TNIter,
    37-// NPL::AccessTypedValue, ystdex::make_transform, std::accumulate,
    38-// std::placeholders::_2, ystdex::bind1, ContextNode,
    34+// NPL::ResolveTerm, std::next, Access, NPL::Deref, Forms::CallResolvedUnary,
    35+// ResolvedTermReferencePtr, AccessRegular, ystdex::make_expanded, std::ref,
    36+// ystdex::invoke_nonvoid, TNIter, AccessTypedValue, ystdex::make_transform,
    37+// std::accumulate, std::placeholders::_2, ystdex::bind1, ContextNode,
    3938 // ystdex::equality_comparable, ystdex::exclude_self_params_t,
    4039 // ystdex::examiners::equal_examiner, trivial_swap_t, trivial_swap,
    4140 // Environment, ystdex::is_bitwise_swappable, ystdex::true_;
    @@ -53,7 +52,7 @@
    5352 \sa Continuation
    5453 \since build 943
    5554
    56-若定义为 true ,则在续延调用时断言被捕获的帧在当前动作序列中存在。
    55+若定义为 true ,则在续延调用时断言被捕获的帧在当前动作序列中存在且满足实现约束。
    5756 */
    5857 #ifndef NPL_NPLA1Forms_CheckContinuationFrames
    5958 # ifndef NDEBUG
    @@ -302,7 +301,7 @@
    302301 inline auto
    303302 CallResolvedUnaryAs(_func&& f, TermNode& term, _tParams&&... args)
    304303 -> yimpl(decltype(ystdex::expand_proxy<void(_type&, const
    305- ResolvedTermReferencePtr&, _tParams&&...)>::call(f, NPL::Access<_type>(
    304+ ResolvedTermReferencePtr&, _tParams&&...)>::call(f, Access<_type>(
    306305 term), ResolvedTermReferencePtr(), std::forward<_tParams>(args)...)))
    307306 {
    308307 using handler_t
    @@ -314,21 +313,21 @@
    314313 -> decltype(ystdex::expand_proxy<handler_t>::call(f,
    315314 std::declval<_type&>(), p_ref)){
    316315 // XXX: Blocked. 'yforward' cause G++ 7.1.0 failed silently.
    317- return ystdex::expand_proxy<handler_t>::call(f, NPL::Access<_type>(nd),
    316+ return ystdex::expand_proxy<handler_t>::call(f, Access<_type>(nd),
    318317 p_ref, std::forward<_tParams>(args)...);
    319318 }, term);
    320319 }
    321320
    322321 /*!
    323322 \note 访问节点的子节点,以正规值调用一元函数。
    324-\sa NPL::AccessRegular
    323+\sa AccessRegular
    325324 \exception ListTypeError 异常中立:项为列表项。
    326325 */
    327326 template<typename _type, typename _func, typename... _tParams>
    328327 inline auto
    329328 CallRegularUnaryAs(_func&& f, TermNode& term, _tParams&&... args)
    330329 -> yimpl(decltype(ystdex::expand_proxy<void(_type&, const
    331- ResolvedTermReferencePtr&, _tParams&&...)>::call(f, NPL::Access<_type>(
    330+ ResolvedTermReferencePtr&, _tParams&&...)>::call(f, Access<_type>(
    332331 term), ResolvedTermReferencePtr(), std::forward<_tParams>(args)...)))
    333332 {
    334333 using handler_t
    @@ -340,7 +339,7 @@
    340339 -> decltype(ystdex::expand_proxy<handler_t>::call(f,
    341340 std::declval<_type&>(), p_ref)){
    342341 // XXX: Blocked. 'yforward' cause G++ 7.1.0 failed silently.
    343- return ystdex::expand_proxy<handler_t>::call(f, NPL::AccessRegular<
    342+ return ystdex::expand_proxy<handler_t>::call(f, AccessRegular<
    344343 _type>(nd, p_ref), p_ref, std::forward<_tParams>(args)...);
    345344 }, term);
    346345 }
    @@ -381,8 +380,8 @@
    381380 // XXX: This is a bit more efficient than directly use of
    382381 // %ystdex::expand_proxy for G++.
    383382 return ystdex::make_expanded<void(decltype(
    384- NPL::AccessTypedValue<_type>(tm)), _tParams&&...)>(std::ref(f))(
    385- NPL::AccessTypedValue<_type>(tm), std::forward<_tParams>(args)...);
    383+ AccessTypedValue<_type>(tm)), _tParams&&...)>(std::ref(f))(
    384+ AccessTypedValue<_type>(tm), std::forward<_tParams>(args)...);
    386385 }, term);
    387386 }
    388387 //@}
    @@ -410,12 +409,12 @@
    410409 RetainN(term, 2);
    411410
    412411 auto i(term.begin());
    413- auto&& x(NPL::AccessTypedValue<_type>(NPL::Deref(++i)));
    412+ auto&& x(AccessTypedValue<_type>(NPL::Deref(++i)));
    414413
    415414 return NPL::EmplaceCallResultOrReturn(term, ystdex::invoke_nonvoid(
    416415 ystdex::make_expanded<void(decltype(x), decltype(
    417- NPL::AccessTypedValue<_type2>(*i)), _tParams&&...)>(std::ref(f)),
    418- yforward(x), NPL::AccessTypedValue<_type2>(NPL::Deref(++i)),
    416+ AccessTypedValue<_type2>(*i)), _tParams&&...)>(std::ref(f)),
    417+ yforward(x), AccessTypedValue<_type2>(NPL::Deref(++i)),
    419418 yforward(args)...));
    420419 }
    421420 //@}
    @@ -432,7 +431,7 @@
    432431 const auto n(FetchArgumentN(term));
    433432 auto i(term.begin());
    434433 const auto j(ystdex::make_transform(++i, [](TNIter it){
    435- return NPL::AccessTypedValue<_type>(NPL::Deref(it));
    434+ return AccessTypedValue<_type>(NPL::Deref(it));
    436435 }));
    437436
    438437 return NPL::EmplaceCallResultOrReturn(term, std::accumulate(j, std::next(
    @@ -856,7 +855,6 @@
    856855 \since build 779
    857856
    858857 按值传递返回值。构造的对象中的元素转换为右值。
    859-替代引用值通过 NPL::LiftSubtermsToReturn(@6.6.2) 提升求值后的项的每个子项实现。
    860858
    861859 参考调用文法:
    862860 <pre>cons \<object> \<list></pre>
    @@ -1035,7 +1033,6 @@
    10351033 \sa LiftSubtermsToReturn
    10361034
    10371035 第二参数的元素转换为右值。
    1038-替代引用值通过 LiftSubtermsToReturn 插入第一个元素前的每个子项实现。
    10391036
    10401037 参考调用文法:
    10411038 <pre>set-rest! \<list> \<object></pre>
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/include/NPL/SContext.h
    --- a/YFramework/include/NPL/SContext.h Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/include/NPL/SContext.h Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file SContext.h
    1212 \ingroup NPL
    1313 \brief S 表达式上下文。
    14-\version r4233
    14+\version r4421
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 304
    1717 \par 创建时间:
    1818 2012-08-03 19:55:41 +0800
    1919 \par 修改时间:
    20- 2022-04-28 03:46 +0800
    20+ 2022-06-13 18:16 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -97,15 +97,34 @@
    9797 using YSLib::weak_ptr;
    9898
    9999
    100+/*!
    101+\brief 压缩项标签。
    102+\since build 947
    103+
    104+若定义为 true ,则特定的项标签复用其它项标签的位。
    105+因为这些标签预期不会在表示一等对象中出现,非一等对象的表示可复用相同的位置。
    106+公开接口中使用的对象表示的这些标签是否复用这些位在是未指定的。
    107+为避免依赖实现配置,判断对应的标签是否存在时,
    108+ 应使用 API 而不是直接依赖标签的数值的操作(例如比较和位运算)。
    109+*/
    110+#ifndef NPL_SContext_CompressTermTags
    111+# define NPL_SContext_CompressTermTags true
    112+#endif
    113+
    100114 //! \since build 857
    101115 //@{
    102116 //! \brief 项标签索引:指定项标签元数据掩码的位。
    103117 enum TermTagIndices : size_t
    104118 {
    105- UnqualifiedIndex = 0,
    106119 UniqueIndex,
    107120 NonmodifyingIndex,
    108- TemporaryIndex
    121+ TemporaryIndex,
    122+ StickyIndex
    123+#if NPL_SContext_CompressTermTags
    124+ // NOTE: This can be any other index except %UnqualifiedIndex, because
    125+ // all other indices do not qualify subobjects.
    126+ = yimpl(NonmodifyingIndex)
    127+#endif
    109128 };
    110129
    111130 /*!
    @@ -122,7 +141,7 @@
    122141 指定默认情形的对象或对象引用。
    123142 当前用于实现对象语言的被绑定的对象或消亡值以外的表达式。
    124143 */
    125- Unqualified = 1 << UnqualifiedIndex,
    144+ Unqualified = 0,
    126145 /*!
    127146 \brief 唯一引用。
    128147
    @@ -151,7 +170,19 @@
    151170 而不引入项引用。
    152171 不取得范式的项中,派生语言可指定指示被绑定对象以外的语义。
    153172 */
    154- Temporary = 1 << TemporaryIndex
    173+ Temporary = 1 << TemporaryIndex,
    174+ /*!
    175+ \brief 粘滞项。
    176+
    177+ 指定非平凡非正规表示中的第一个不作为一等对象的子项。
    178+ 在非平凡非正规表示的项的子项以外的其它项的标签中不具有这个标签值,
    179+ 但数值相等的其它标签值可在项引用中使用。
    180+ 若这个标签值在第一个子项的标签设置,则包含这个子项的整个项不是非真列表。
    181+ 在这个标签值不在第一个子项的标签设置时,非平凡非正规表示的项表示非真列表:
    182+ 在第一个具有这个标签值的子项前的子项表示 cons 对的第二个元素以外的列表元素;
    183+ 其它子项和值数据成员表示最后的 cons 对的第二个元素。
    184+ */
    185+ Sticky = 1 << StickyIndex
    155186 };
    156187
    157188 //! \relates TermTags
    @@ -168,6 +199,24 @@
    168199 == TermTags::Unique)
    169200
    170201 /*!
    202+\brief 判断标签可表示被引用对象。
    203+\note 一等对象的表示的标签可表示被引用对象。
    204+\since build 947
    205+*/
    206+YB_ATTR_nodiscard YB_STATELESS yconstfn
    207+ PDefH(bool, IsReferentTags, TermTags tags) ynothrow
    208+ ImplRet((tags & (TermTags::Unique | TermTags::Nonmodifying
    209+ | TermTags::Temporary)) == tags)
    210+
    211+/*!
    212+\brief 判断标签具有粘滞位。
    213+\since build 947
    214+*/
    215+YB_ATTR_nodiscard YB_STATELESS yconstfn
    216+ PDefH(bool, IsSticky, TermTags tags) ynothrow
    217+ ImplRet(bool(tags & TermTags::Sticky))
    218+
    219+/*!
    171220 \brief 取转发推断为左值表达式时保留的标签。
    172221 \sa TermTags::Temporary
    173222
    @@ -255,12 +304,29 @@
    255304 TermNode(allocator_type a)
    256305 : container(a)
    257306 {}
    307+ //! \since build 947
    308+ explicit
    309+ TermNode(TermTags tags)
    310+ : Tags(tags)
    311+ {}
    312+ //! \since build 947
    313+ TermNode(TermTags tags, allocator_type a)
    314+ : container(a), Tags(tags)
    315+ {}
    258316 TermNode(const Container& con)
    259- : TermNode(con, con.get_allocator())
    317+ : TermNode(TermTags::Unqualified, con)
    260318 {}
    261319 TermNode(Container&& con)
    262320 : container(std::move(con))
    263321 {}
    322+ //! \since build 947
    323+ TermNode(TermTags tags, const Container& con)
    324+ : TermNode(std::allocator_arg, con.get_allocator(), tags, con)
    325+ {}
    326+ //! \since build 947
    327+ TermNode(TermTags tags, Container&& con)
    328+ : container(std::move(con)), Tags(tags)
    329+ {}
    264330 /*!
    265331 \note 除非 Value 的构造非嵌套调用安全,支持构造任意子节点时的嵌套调用安全。
    266332 \since build 853
    @@ -283,6 +349,26 @@
    283349 TermNode(Container&& con, _tParams&&... args)
    284350 : container(std::move(con)), Value(yforward(args)...)
    285351 {}
    352+ //! \since build 947
    353+ //@{
    354+ template<typename... _tParams,
    355+ yimpl(typename = enable_value_constructible_t<_tParams...>)>
    356+ inline
    357+ TermNode(TermTags tags, NoContainerTag, _tParams&&... args)
    358+ : Value(yforward(args)...), Tags(tags)
    359+ {}
    360+ template<typename... _tParams,
    361+ yimpl(typename = enable_value_constructible_t<_tParams...>)>
    362+ TermNode(TermTags tags, const Container& con, _tParams&&... args)
    363+ : TermNode(std::allocator_arg, con.get_allocator(), tags, con,
    364+ yforward(args)...)
    365+ {}
    366+ template<typename... _tParams,
    367+ yimpl(typename = enable_value_constructible_t<_tParams...>)>
    368+ TermNode(TermTags tags, Container&& con, _tParams&&... args)
    369+ : container(std::move(con)), Value(yforward(args)...), Tags(tags)
    370+ {}
    371+ //@}
    286372 template<typename... _tParams,
    287373 yimpl(typename = enable_value_constructible_t<_tParams...>)>
    288374 inline
    @@ -304,21 +390,60 @@
    304390 _tParams&&... args)
    305391 : container(std::move(con), a), Value(yforward(args)...)
    306392 {}
    393+ //! \since build 947
    394+ //@{
    395+ template<typename... _tParams,
    396+ yimpl(typename = enable_value_constructible_t<_tParams...>)>
    397+ inline
    398+ TermNode(std::allocator_arg_t, allocator_type a, TermTags tags,
    399+ NoContainerTag, _tParams&&... args)
    400+ : container(a), Value(yforward(args)...), Tags(tags)
    401+ {}
    402+ template<typename... _tParams,
    403+ yimpl(typename = enable_value_constructible_t<_tParams...>)>
    404+ inline
    405+ TermNode(std::allocator_arg_t, allocator_type a, TermTags tags,
    406+ const Container& con, _tParams&&... args)
    407+ : container(ConSub(con, a)), Value(yforward(args)...), Tags(tags)
    408+ {}
    409+ template<typename... _tParams,
    410+ yimpl(typename = enable_value_constructible_t<_tParams...>)>
    411+ inline
    412+ TermNode(std::allocator_arg_t, allocator_type a, TermTags tags,
    413+ Container&& con, _tParams&&... args)
    414+ : container(std::move(con), a), Value(yforward(args)...), Tags(tags)
    415+ {}
    416+ //@}
    307417 //@}
    308418 //! \warning 不保证嵌套调用安全。
    419+ //@{
    420+ explicit
    421+ TermNode(const ValueNode& nd)
    422+ : container(ConCons(nd.GetContainer())), Value(nd.Value)
    423+ {}
    309424 TermNode(const ValueNode& nd, allocator_type a)
    310425 : container(ConCons(nd.GetContainer(), a)), Value(nd.Value)
    311426 {}
    312- //! \warning 不保证嵌套调用安全。
    427+ explicit
    428+ TermNode(ValueNode&& nd)
    429+ : container(ConCons(std::move(nd.GetContainerRef()))),
    430+ Value(std::move(nd.Value))
    431+ {}
    313432 TermNode(ValueNode&& nd, allocator_type a)
    314433 : container(ConCons(std::move(nd.GetContainerRef()), a)),
    315434 Value(std::move(nd.Value))
    316435 {}
    317436 //@}
    437+ //@}
    318438 // XXX: This needs tag to avoid clash with other constructors.
    319439 TermNode(YSLib::ListContainerTag, std::initializer_list<TermNode> il)
    320440 : container(il)
    321441 {}
    442+ //! \since build 947
    443+ TermNode(TermTags tags, std::initializer_list<TermNode> il,
    444+ allocator_type a = {})
    445+ : container(il, a), Tags(tags)
    446+ {}
    322447 TermNode(std::initializer_list<TermNode> il, allocator_type a)
    323448 : container(il, a)
    324449 {}
    @@ -330,16 +455,14 @@
    330455 std::initializer_list<TermNode> il, _tParams&&... args)
    331456 : TermNode(std::allocator_arg, a, Container(il, a), yforward(args)...)
    332457 {}
    333- //! \warning 不保证嵌套调用安全。
    334- explicit
    335- TermNode(const ValueNode& nd)
    336- : container(ConCons(nd.GetContainer())), Value(nd.Value)
    337- {}
    338- //! \warning 不保证嵌套调用安全。
    339- explicit
    340- TermNode(ValueNode&& nd)
    341- : container(ConCons(std::move(nd.GetContainer()))),
    342- Value(std::move(nd.Value))
    458+ //! \since build 947
    459+ template<typename... _tParams,
    460+ yimpl(typename = enable_value_constructible_t<_tParams...>)>
    461+ inline
    462+ TermNode(std::allocator_arg_t, allocator_type a, TermTags tags,
    463+ std::initializer_list<TermNode> il, _tParams&&... args)
    464+ : TermNode(std::allocator_arg, a, tags, Container(il, a),
    465+ yforward(args)...)
    343466 {}
    344467 //! \note 除非 Value 的构造非嵌套调用安全,支持构造任意子节点时的嵌套调用安全。
    345468 //@{
    @@ -424,14 +547,15 @@
    424547 PDefH(void, SetContent, TermNode&& nd)
    425548 ImplExpr(SwapContainer(nd), Value = std::move(nd.Value), Tags = nd.Tags)
    426549 //@}
    427- //! \since build 918
    428- //@{
    550+ //! \since build 947
    429551 template<typename _tParam>
    430552 inline yimpl(ystdex::enable_if_same_param_t<ValueObject, _tParam>)
    431- SetValue(_tParam&& arg) ynoexcept_spec(yforward(arg))
    553+ SetValue(_tParam&& arg) ynoexcept_spec(Value = yforward(arg))
    432554 {
    433555 Value = yforward(arg);
    434556 }
    557+ //! \since build 918
    558+ //@{
    435559 template<typename _tParam, typename... _tParams,
    436560 yimpl(ystdex::enable_if_t<sizeof...(_tParams) != 0
    437561 || !ystdex::is_same_param<ValueObject, _tParam>::value, int> = 0,
    @@ -508,14 +632,10 @@
    508632 private:
    509633 //! \warning 不保证嵌套调用安全。
    510634 //@{
    511- YB_ATTR_nodiscard YB_PURE static TermNode::Container
    512- ConCons(const ValueNode::Container&);
    513- YB_ATTR_nodiscard YB_PURE static TermNode::Container
    514- ConCons(ValueNode::Container&&);
    515- YB_ATTR_nodiscard YB_PURE static TermNode::Container
    516- ConCons(const ValueNode::Container&, allocator_type);
    517- YB_ATTR_nodiscard YB_PURE static TermNode::Container
    518- ConCons(ValueNode::Container&&, allocator_type);
    635+ YB_ATTR_nodiscard YB_FLATTEN YB_PURE static TermNode::Container
    636+ ConCons(const ValueNode::Container&, allocator_type = {});
    637+ YB_ATTR_nodiscard YB_FLATTEN YB_PURE static TermNode::Container
    638+ ConCons(ValueNode::Container&&, allocator_type = {});
    519639 //@}
    520640
    521641 //! \since build 934
    @@ -725,6 +845,16 @@
    725845 YB_ATTR_nodiscard YB_PURE inline
    726846 PDefH(bool, IsRegular, const TermNode& nd) ynothrow
    727847 ImplRet(IsLeaf(nd) || IsList(nd))
    848+
    849+//! \brief 判断项是否为原子节点:不能表示为一等对象的有序对的节点。
    850+YB_ATTR_nodiscard YB_PURE inline
    851+ PDefH(bool, IsAtom, const TermNode& nd) ynothrow
    852+ ImplRet(IsLeaf(nd) || IsSticky(nd.begin()->Tags))
    853+
    854+//! \brief 判断项是否为有序对节点。
    855+YB_ATTR_nodiscard YB_PURE inline
    856+ PDefH(bool, IsPair, const TermNode& nd) ynothrow
    857+ ImplRet(!IsAtom(nd))
    728858 //@}
    729859
    730860 //! \since build 928
    @@ -815,6 +945,23 @@
    815945 ImplExpr(yunused(nd), yunused(msg), YAssert(IsBranchedList(nd), msg))
    816946
    817947 /*!
    948+\brief 断言具有可表示被引用对象的标签节点。
    949+\pre 断言:参数的标签可表示被引用对象的值。
    950+\sa IsReferentTags
    951+\since build 947
    952+*/
    953+//@{
    954+YB_NONNULL(2) inline
    955+ PDefH(void, AssertReferentTags, TermTags tags, const char* msg
    956+ = "Invalid term of referent found.") ynothrowv
    957+ ImplExpr(yunused(tags), yunused(msg), YAssert(IsReferentTags(tags), msg))
    958+YB_NONNULL(2) inline
    959+ PDefH(void, AssertReferentTags, const TermNode& nd, const char* msg
    960+ = "Invalid term of referent found.") ynothrowv
    961+ ImplExpr(AssertReferentTags(nd.Tags, msg))
    962+//@}
    963+
    964+/*!
    818965 \brief 断言具有可表示一等对象的值的标签节点。
    819966 \pre 断言:参数的标签可表示一等对象的值。
    820967 \note 较 EnsureValueTags 更严格,对不符合要求的项总是断言失败。
    @@ -845,6 +992,24 @@
    845992 {
    846993 return TermNode(std::allocator_arg, a, NoContainer, yforward(args)...);
    847994 }
    995+
    996+//! \since build 947
    997+template<typename... _tParam, typename... _tParams>
    998+YB_ATTR_nodiscard YB_PURE inline
    999+yimpl(ystdex::enable_if_inconvertible_t)<ystdex::head_of_t<_tParams...>,
    1000+ TermNode::allocator_type, TermNode>
    1001+AsTermNodeTagged(TermTags tags, _tParams&&... args)
    1002+{
    1003+ return TermNode(tags, NoContainer, yforward(args)...);
    1004+}
    1005+//! \since build 947
    1006+template<typename... _tParams>
    1007+YB_ATTR_nodiscard YB_PURE inline TermNode
    1008+AsTermNodeTagged(TermNode::allocator_type a, TermTags tags, _tParams&&... args)
    1009+{
    1010+ return
    1011+ TermNode(std::allocator_arg, a, tags, NoContainer, yforward(args)...);
    1012+}
    8481013 //@}
    8491014
    8501015 //! \since build 852
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/source/NPL/Dependency.cpp
    --- a/YFramework/source/NPL/Dependency.cpp Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/source/NPL/Dependency.cpp Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file Dependency.cpp
    1212 \ingroup NPL
    1313 \brief 依赖管理。
    14-\version r6902
    14+\version r6958
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 623
    1717 \par 创建时间:
    1818 2015-08-09 22:14:45 +0800
    1919 \par 修改时间:
    20- 2022-04-25 18:07 +0800
    20+ 2022-06-14 18:33 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -29,11 +29,11 @@
    2929 #include YFM_NPL_Dependency // for set, string, UnescapeContext, string_view,
    3030 // ystdex::isspace, std::istream, YSLib::unique_ptr, std::throw_with_nested,
    3131 // std::invalid_argument, ystdex::sfmt, YSLib::share_move, REPLContext,
    32-// RetainN, NPL::ResolveRegular, NPL::Deref, RelaySwitched, trivial_swap,
    33-// A1::NameTypedReducerHandler, std::bind, std::ref, Forms::CallResolvedUnary,
    34-// EnsureValueTags, ResolvedTermReferencePtr, NPL::TryAccessLeaf,
    35-// TermReference, LiftTerm, MoveResolved, Environment,
    36-// NPL::AllocateEnvironment, function, ValueObject, NPL::AccessPtr,
    32+// RelaySwitched, trivial_swap, std::bind, SourceName, RetainN,
    33+// NPL::ResolveRegular, NPL::Deref, A1::NameTypedReducerHandler, std::ref,
    34+// Forms::CallResolvedUnary, EnsureValueTags, ResolvedTermReferencePtr,
    35+// TryAccessLeafAtom, TermReference, LiftTerm, MoveResolved, Environment,
    36+// NPL::AllocateEnvironment, function, ValueObject, AccessPtr,
    3737 // EnvironmentReference, shared_ptr, std::piecewise_construct,
    3838 // NPL::forward_as_tuple, LiftOther, ThrowNonmodifiableErrorForAssignee,
    3939 // ThrowValueCategoryError, ValueToken, ResolveTerm, TokenValue,
    @@ -47,7 +47,7 @@
    4747 // AccessFirstSubterm, ThrowInsufficientTermsError, AssertValueTags, Retain,
    4848 // RemoveHead, ClearCombiningTags, EmplaceCallResultOrReturn, NPL::AsTermNode,
    4949 // ReferenceTerm, ResolveName, ystdex::fast_any_of, Ensigil, YSLib::ufexists,
    50-// YSLib::to_std_string, EmplaceCallResultOrReturn, NPL::TryAccessTerm,
    50+// YSLib::to_std_string, EmplaceCallResultOrReturn, TryAccessTerm,
    5151 // ystdex::plus, ystdex::tolower, YSLib::OwnershipTag, YSLib::IO::StreamPut,
    5252 // YSLib::FetchEnvironmentVariable, YSLib::SetEnvironmentVariable, NPL::tuple,
    5353 // YSLib::IO::UniqueFile, YSLib::uremove, YSLib::allocate_shared,
    @@ -212,7 +212,8 @@
    212212 {
    213213 auto p_is(A1::OpenFile(filename.c_str()));
    214214
    215- // NOTE: Swap guard for %Context.CurrentSource is not used to support PTC.
    215+ // NOTE: Swap guard for %Context.CurrentSource is not used. It is up to the
    216+ // caller to support PTC or not.
    216217 context.CurrentSource = YSLib::share_move(filename);
    217218 return p_is;
    218219 }
    @@ -233,10 +234,31 @@
    233234 ReduceToLoadFile(TermNode& term, ContextNode& ctx, REPLContext& context,
    234235 string filename)
    235236 {
    236- term = context.Load(context, ctx, std::move(filename));
    237237 // NOTE: This is explicitly not same to klisp. This is also friendly to PTC.
    238238 // XXX: Same to %A1::ReduceOnce, without setup the next term.
    239+#if NPL_Impl_NPLA1_Enable_Thunked
    240+# if NPL_Impl_NPLA1_Enable_TCO
    241+ RefTCOAction(ctx).SaveTailSourceName(context.CurrentSource,
    242+ std::move(context.CurrentSource));
    243+# else
    244+ RelaySwitched(ctx, trivial_swap,
    245+ A1::NameTypedReducerHandler(std::bind([&](SourceName& saved_src){
    246+ context.CurrentSource = std::move(saved_src);
    247+ return ctx.LastStatus;
    248+ }, std::move(context.CurrentSource)), "recover-source-name"));
    249+# endif
    250+ term = context.Load(context, ctx, std::move(filename));
    239251 return ContextState::Access(ctx).ReduceOnce.Handler(term, ctx);
    252+#else
    253+ auto saved_src(std::move(context.CurrentSource));
    254+
    255+ term = context.Load(context, ctx, std::move(filename));
    256+
    257+ const auto res(ContextState::Access(ctx).ReduceOnce.Handler(term, ctx));
    258+
    259+ context.CurrentSource = std::move(saved_src);
    260+ return res;
    261+#endif
    240262 }
    241263
    242264 } // unnamed namespace;
    @@ -284,7 +306,7 @@
    284306 Qualify(TermNode& term, TermTags tag_add)
    285307 {
    286308 return Forms::CallRawUnary([&](TermNode& tm){
    287- if(const auto p = NPL::TryAccessLeaf<TermReference>(tm))
    309+ if(const auto p = TryAccessLeafAtom<TermReference>(tm))
    288310 p->AddTags(tag_add);
    289311 LiftTerm(term, tm);
    290312 return ReductionStatus::Retained;
    @@ -308,14 +330,14 @@
    308330 });
    309331 const auto copy_parent_ptr(
    310332 [&](function<Environment&()> mdst, const ValueObject& vo) -> bool{
    311- if(const auto p = NPL::AccessPtr<EnvironmentReference>(vo))
    333+ if(const auto p = AccessPtr<EnvironmentReference>(vo))
    312334 {
    313335 if(const auto p_parent = p->Lock())
    314336 copy_parent(mdst(), *p_parent);
    315337 // XXX: Failure of locking is ignored.
    316338 return true;
    317339 }
    318- else if(const auto p_e = NPL::AccessPtr<shared_ptr<Environment>>(vo))
    340+ else if(const auto p_e = AccessPtr<shared_ptr<Environment>>(vo))
    319341 {
    320342 if(const auto p_parent = *p_e)
    321343 copy_parent(mdst(), *p_parent);
    @@ -567,7 +589,7 @@
    567589 RegisterUnary(ctx, "uncollapsed?", IsUncollapsedTerm);
    568590 RegisterStrict(ctx, "deshare", [](TermNode& term){
    569591 return CallRawUnary([&](TermNode& tm){
    570- if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
    592+ if(const auto p = TryAccessLeafAtom<const TermReference>(tm))
    571593 LiftTermRef(tm, p->get());
    572594 NPL::SetContentWith(term, std::move(tm),
    573595 &ValueObject::MakeMoveCopy);
    @@ -770,7 +792,7 @@
    770792 auto& tm(*pr.first);
    771793
    772794 if(const auto p
    773- = NPL::TryAccessLeaf<const TermReference>(tm))
    795+ = TryAccessLeafAtom<const TermReference>(tm))
    774796 return p->IsReferencedLValue();
    775797 return !(bool(tm.Tags & TermTags::Unique)
    776798 || bool(tm.Tags & TermTags::Temporary));
    @@ -915,7 +937,7 @@
    915937 // implementation.
    916938 ystdex::bind1([](TermNode& term, const EnvironmentReference& ce){
    917939 RetainN(term, 0);
    918- term.Value = CreateEnvironmentWithParent(term.get_allocator(), ce);
    940+ term.SetValue(CreateEnvironmentWithParent(term.get_allocator(), ce));
    919941 }, context.Root.WeakenRecord()));
    920942 RegisterStrict(renv, "derive-current-environment",
    921943 [] YB_LAMBDA_ANNOTATE((TermNode& term, ContextNode& ctx), , flatten){
    @@ -1532,7 +1554,7 @@
    15321554 // is trustable to have only the tags of modifiable first-class object.
    15331555 const bool list_not_move(!NPL::IsMovable(p_ref) || p_back);
    15341556
    1535- if(const auto p = NPL::TryAccessLeaf<const TermReference>(nd))
    1557+ if(const auto p = TryAccessLeafAtom<const TermReference>(nd))
    15361558 {
    15371559 if(list_not_move)
    15381560 {
    @@ -1548,7 +1570,7 @@
    15481570 else if(list_not_move)
    15491571 {
    15501572 // XXX: Allocators are not used here for performance.
    1551- term.Value.assign(in_place_type<TermReference>, nd.Tags, nd,
    1573+ term.SetValue(in_place_type<TermReference>, nd.Tags, nd,
    15521574 p_ref ? p_ref->GetEnvironmentReference() : r_env);
    15531575 return ReductionStatus::Clean;
    15541576 }
    @@ -1629,7 +1651,7 @@
    16291651 // the recursive call to %ForcePromise also reuses %nterm to hold the
    16301652 // old %nprom for nested promise evaluation, so lifetimes of %prom and
    16311653 // %nprom should not overlap.
    1632- auto& nprom(NPL::AccessRegular<Promise>(nd, p_ref));
    1654+ auto& nprom(AccessRegular<Promise>(nd, p_ref));
    16331655
    16341656 // NOTE: This is necessary to handle the promise forced during the
    16351657 // evaluation on %nterm, see [RnRK].
    @@ -1880,8 +1902,8 @@
    18801902 "string<-", [](ResolvedArg<>&& x, ResolvedArg<>&& y){
    18811903 if(x.IsModifiable())
    18821904 {
    1883- auto& str_x(NPL::AccessRegular<string>(x.get(), x.second));
    1884- auto& str_y(NPL::AccessRegular<string>(y.get(), y.second));
    1905+ auto& str_x(AccessRegular<string>(x.get(), x.second));
    1906+ auto& str_y(AccessRegular<string>(y.get(), y.second));
    18851907
    18861908 if(y.IsMovable())
    18871909 str_x = std::move(str_y);
    @@ -2001,22 +2023,13 @@
    20012023 $defl! puts (&s) $sequence (put s) (() newline);
    20022024 )NPL");
    20032025 #endif
    2004-#if true
    20052026 RegisterStrict(renv, "load", trivial_swap,
    20062027 [&](TermNode& term, ContextNode& ctx){
    2028+ // NOTE: Since %load requires no additional barrier of catching the
    2029+ // inner exceptions and the reset of the source name, %TryLoadSource or
    2030+ // %PreloadExternal is not applicable here.
    20072031 return ReduceToLoadExternal(term, ctx, context);
    20082032 });
    2009-#else
    2010- RegisterUnary<Strict, string>(renv, "load", [&](string& filename){
    2011- // NOTE: This is not applicable since %load has no additional barrier
    2012- // here.
    2013- // XXX: As %PreloadExternal.
    2014- const auto p_is(OpenUnique(context, std::move(filename)));
    2015-
    2016- TryLoadSource(context, context.CurrentSource->c_str(), *p_is);
    2017- return ValueToken::Unspecified;
    2018- });
    2019-#endif
    20202033 #if NPL_Impl_NPLA1_Native_Forms
    20212034 RegisterStrict(renv, "get-module", trivial_swap,
    20222035 ystdex::bind1([&](TermNode& term, ContextNode& ctx,
    @@ -2048,7 +2061,7 @@
    20482061 # if NPL_Impl_NPLA1_Enable_Thunked
    20492062 RelaySwitched(ctx, trivial_swap, A1::NameTypedReducerHandler(
    20502063 std::bind([&](shared_ptr<Environment> p_res){
    2051- term.Value = std::move(p_res);
    2064+ term.SetValue(std::move(p_res));
    20522065 return ReductionStatus::Clean;
    20532066 }, p_env), "get-module-return"));
    20542067 return ReduceToLoadGuarded(term, ctx, context, std::move(p_env),
    @@ -2056,7 +2069,7 @@
    20562069 # else
    20572070 ReduceToLoadGuarded(term, ctx, context, std::move(p_env),
    20582071 ReduceToLoadExternal);
    2059- term.Value = std::move(p_env);
    2072+ term.SetValue(std::move(p_env));
    20602073 return ReductionStatus::Clean;
    20612074 # endif
    20622075 }
    @@ -2087,7 +2100,7 @@
    20872100 RegisterStrict(renv, "get-current-repl", trivial_swap,
    20882101 [&](TermNode& term){
    20892102 RetainN(term, 0);
    2090- term.Value = ValueObject(context, YSLib::OwnershipTag<>());
    2103+ term.Value.assign(context, YSLib::OwnershipTag<>());
    20912104 });
    20922105 RegisterStrict(renv, "eval-string", EvalString);
    20932106 RegisterStrict(renv, "eval-string%", EvalStringRef);
    @@ -2245,15 +2258,15 @@
    22452258 // XXX: As %ReduceToReference for modifiable lvalues (with default
    22462259 // tags).
    22472260 AssertValueTags(tm);
    2248- if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
    2261+ if(const auto p = TryAccessLeafAtom<const TermReference>(tm))
    22492262 {
    22502263 // XXX: Since %tm is not shared with %term, it is safe to use
    22512264 // %TermNode::SetContent instead of %TermNode::CopyContent.
    22522265 term.SetContent(tm);
    22532266 return ReductionStatus::Retained;
    22542267 }
    2255- term.Value
    2256- = TermReference(TermTags::Unqualified, tm, ctx.WeakenRecord());
    2268+ term.SetValue(in_place_type<TermReference>, TermTags::Unqualified,
    2269+ tm, ctx.WeakenRecord());
    22572270 return ReductionStatus::Clean;
    22582271 });
    22592272
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/source/NPL/NPLA.cpp
    --- a/YFramework/source/NPL/NPLA.cpp Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/source/NPL/NPLA.cpp Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA.cpp
    1212 \ingroup NPL
    1313 \brief NPLA 公共接口。
    14-\version r4016
    14+\version r4055
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 663
    1717 \par 创建时间:
    1818 2016-01-07 10:32:45 +0800
    1919 \par 修改时间:
    20- 2022-05-29 08:09 +0800
    20+ 2022-06-14 18:41 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -28,18 +28,17 @@
    2828 #include "NPL/YModules.h"
    2929 #include YFM_NPL_NPLA // for YSLib::Warning, YSLib::Err, YSLib::RecordLevel,
    3030 // string, YSLib::make_string_view, std::to_string, YSLib::DecodeIndex,
    31-// std::invalid_argument, ValueNode, NPL::Access, EscapeLiteral, Literalize,
    32-// NPL::AccessPtr, ystdex::value_or, ystdex::write, std::bind,
    33-// TraverseSubnodes, bad_any_cast, std::allocator_arg, YSLib::NodeSequence,
    34-// ystdex::begins_with, ystdex::sfmt, observer_ptr,
    35-// ystdex::make_obj_using_allocator, trivial_swap, NPL::make_observer,
    36-// TermTags, NPL::TryAccessLeaf, NPL::Deref, YSLib::sfmt,
    37-// ystdex::call_value_or, IsTyped, ystdex::compose, GetLValueTagsOf,
    38-// std::mem_fn, ystdex::invoke_value_or, ystdex::ref, PropagateTo,
    39-// NPL::IsMovable, AccessFirstSubterm, YSLib::FilterExceptions, type_id,
    40-// ystdex::addrof, ystdex::second_of, type_info, std::current_exception,
    41-// std::rethrow_exception, std::throw_with_nested, ystdex::retry_on_cond,
    42-// ystdex::id, pair, YSLib::ExtractException;
    31+// std::invalid_argument, ValueNode, Access, EscapeLiteral, Literalize,
    32+// AccessPtr, ystdex::value_or, ystdex::write, std::bind, TraverseSubnodes,
    33+// bad_any_cast, std::allocator_arg, YSLib::NodeSequence, ystdex::begins_with,
    34+// ystdex::sfmt, observer_ptr, ystdex::make_obj_using_allocator, trivial_swap,
    35+// make_observer, TermTags, TryAccessLeafAtom, NPL::Deref, YSLib::sfmt,
    36+// AssertReferentTags, ystdex::call_value_or, ystdex::compose, GetLValueTagsOf,
    37+// std::mem_fn, IsTyped, ystdex::invoke_value_or, ystdex::ref, PropagateTo,
    38+// NPL::IsMovable, TryAccessLeaf, AccessFirstSubterm, YSLib::FilterExceptions,
    39+// type_id, ystdex::addrof, ystdex::second_of, type_info,
    40+// std::current_exception, std::rethrow_exception, std::throw_with_nested,
    41+// ystdex::retry_on_cond, ystdex::id, pair, YSLib::ExtractException;
    4342 #include <ystdex/function.hpp> // for ystdex::unchecked_function;
    4443
    4544 //! \since build 903
    @@ -71,7 +70,7 @@
    7170 string
    7271 EscapeNodeLiteral(const ValueNode& node)
    7372 {
    74- return EscapeLiteral(NPL::Access<string>(node));
    73+ return EscapeLiteral(Access<string>(node));
    7574 }
    7675
    7776 string
    @@ -83,7 +82,7 @@
    8382 string
    8483 ParseNPLANodeString(const ValueNode& node)
    8584 {
    86- return ystdex::value_or(NPL::AccessPtr<string>(node));
    85+ return ystdex::value_or(AccessPtr<string>(node));
    8786 }
    8887
    8988
    @@ -140,7 +139,7 @@
    140139 string
    141140 ParseNPLATermString(const TermNode& term)
    142141 {
    143- return ystdex::value_or(NPL::AccessPtr<string>(term));
    142+ return ystdex::value_or(AccessPtr<string>(term));
    144143 }
    145144
    146145 ValueNode
    @@ -162,7 +161,7 @@
    162161
    163162 if(node.empty())
    164163 {
    165- if(const auto p = NPL::AccessPtr<YSLib::NodeSequence>(node))
    164+ if(const auto p = AccessPtr<YSLib::NodeSequence>(node))
    166165 for(auto& nd : *p)
    167166 nested_call(nd);
    168167 else
    @@ -226,7 +225,7 @@
    226225 cont = std::move(c);
    227226 return RedirectEnvironmentList(a, cont, i, last);
    228227 }, std::next(first), std::move(cont)));
    229- return NPL::make_observer(&*first);
    228+ return make_observer(&*first);
    230229 }
    231230 return {};
    232231 }
    @@ -246,7 +245,7 @@
    246245 AssertValueTags(tm);
    247246 // XXX: Term tags are currently not respected in prvalues. However, this
    248247 // should be neutral here due to copy elision in the object language.
    249- if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
    248+ if(const auto p = TryAccessLeafAtom<const TermReference>(tm))
    250249 {
    251250 if(!p->IsReferencedLValue())
    252251 return LiftMovedOther(term, *p, ((*p).*pm)());
    @@ -376,9 +375,10 @@
    376375 TermTags
    377376 TermToTags(TermNode& term)
    378377 {
    378+ AssertReferentTags(term);
    379379 return ystdex::call_value_or(ystdex::compose(GetLValueTagsOf,
    380380 std::mem_fn(&TermReference::GetTags)),
    381- NPL::TryAccessLeaf<const TermReference>(term), term.Tags);
    381+ TryAccessLeafAtom<const TermReference>(term), term.Tags);
    382382 }
    383383
    384384 void
    @@ -386,7 +386,7 @@
    386386 {
    387387 for(auto& child : term)
    388388 TokenizeTerm(child);
    389- if(const auto p = NPL::AccessPtr<string>(term))
    389+ if(const auto p = AccessPtr<string>(term))
    390390 term.Value.emplace<TokenValue>(std::move(*p));
    391391 }
    392392
    @@ -406,7 +406,7 @@
    406406 pair<TermReference, bool>
    407407 Collapse(TermReference ref)
    408408 {
    409- if(const auto p = NPL::TryAccessLeaf<TermReference>(ref.get()))
    409+ if(const auto p = TryAccessLeafAtom<TermReference>(ref.get()))
    410410 {
    411411 // XXX: Term tags on prvalues are reserved and should be ignored
    412412 // normally except for future internal use. The only case making the
    @@ -433,21 +433,21 @@
    433433 bool
    434434 IsReferenceTerm(const TermNode& term)
    435435 {
    436- return bool(NPL::TryAccessLeaf<const TermReference>(term));
    436+ return bool(TryAccessLeafAtom<const TermReference>(term));
    437437 }
    438438
    439439 bool
    440440 IsUniqueTerm(const TermNode& term)
    441441 {
    442442 return ystdex::invoke_value_or(&TermReference::IsUnique,
    443- NPL::TryAccessLeaf<const TermReference>(term), true);
    443+ TryAccessLeafAtom<const TermReference>(term), true);
    444444 }
    445445
    446446 bool
    447447 IsModifiableTerm(const TermNode& term)
    448448 {
    449449 return ystdex::invoke_value_or(&TermReference::IsModifiable,
    450- NPL::TryAccessLeaf<const TermReference>(term),
    450+ TryAccessLeafAtom<const TermReference>(term),
    451451 !bool(term.Tags & TermTags::Nonmodifying));
    452452 }
    453453
    @@ -455,7 +455,7 @@
    455455 IsTemporaryTerm(const TermNode& term)
    456456 {
    457457 return ystdex::invoke_value_or(&TermReference::IsTemporary,
    458- NPL::TryAccessLeaf<const TermReference>(term),
    458+ TryAccessLeafAtom<const TermReference>(term),
    459459 bool(term.Tags & TermTags::Temporary));
    460460 }
    461461
    @@ -463,7 +463,7 @@
    463463 IsBoundLValueTerm(const TermNode& term)
    464464 {
    465465 return ystdex::invoke_value_or(&TermReference::IsReferencedLValue,
    466- NPL::TryAccessLeaf<const TermReference>(term));
    466+ TryAccessLeafAtom<const TermReference>(term));
    467467 }
    468468
    469469 bool
    @@ -471,7 +471,7 @@
    471471 {
    472472 return ystdex::call_value_or(ystdex::compose(IsReferenceTerm,
    473473 std::mem_fn(&TermReference::get)),
    474- NPL::TryAccessLeaf<const TermReference>(term));
    474+ TryAccessLeafAtom<const TermReference>(term));
    475475 }
    476476
    477477
    @@ -529,7 +529,7 @@
    529529 void
    530530 MoveCollapsed(TermNode& term, TermNode& tm)
    531531 {
    532- if(const auto p = NPL::TryAccessLeaf<TermReference>(tm))
    532+ if(const auto p = TryAccessLeafAtom<TermReference>(tm))
    533533 term.SetContent(TermNode(std::move(tm.GetContainerRef()),
    534534 Collapse(std::move(*p)).first));
    535535 else
    @@ -567,9 +567,8 @@
    567567 else if(tm.Value.OwnsCount() > 1)
    568568 // XXX: This is unsafe and not checkable because the anchor is not
    569569 // referenced.
    570- // XXX: Allocators are not used here for performance.
    571- term.Value = TermReference(TermTags::Unqualified, tm,
    572- EnvironmentReference());
    570+ term.SetValue(in_place_type<TermReference>, TermTags::Unqualified,
    571+ tm, EnvironmentReference());
    573572 else
    574573 throw InvalidReference(
    575574 "Value of a temporary shall not be referenced.");
    @@ -585,7 +584,7 @@
    585584 // should be neutral here due to copy elision in the object language. Note
    586585 // the operation here is idempotent for qualified expressions.
    587586 // TODO: Detect lifetime escape to perform copy elision?
    588- if(const auto p = NPL::TryAccessLeaf<const TermReference>(term))
    587+ if(const auto p = TryAccessLeafAtom<const TermReference>(term))
    589588 // XXX: Using %LiftMovedOther instead of %LiftMoved is safe, because the
    590589 // referent is not allowed to be same to %term in NPLA.
    591590 LiftMovedOther(term, *p, p->IsMovable());
    @@ -603,7 +602,7 @@
    603602 LiftOtherValue(term, tm);
    604603 if(!IsBoundLValueTerm(term))
    605604 {
    606- if(const auto p = NPL::TryAccessLeaf<const TermReference>(term))
    605+ if(const auto p = TryAccessLeafAtom<const TermReference>(term))
    607606 LiftMovedOther(term, *p, p->IsModifiable());
    608607 }
    609608 #endif
    @@ -682,7 +681,7 @@
    682681 ReductionStatus
    683682 ReduceToReference(TermNode& term, TermNode& tm, ResolvedTermReferencePtr p_ref)
    684683 {
    685- if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
    684+ if(const auto p = TryAccessLeafAtom<const TermReference>(tm))
    686685 {
    687686 AssertValueTags(tm);
    688687 // NOTE: Reference collapsed.
    @@ -708,9 +707,8 @@
    708707 // XXX: Term tags on prvalues are reserved and should be ignored normally
    709708 // except for future internal use. Since %tm is a term,
    710709 // %TermTags::Temporary is not expected, %GetLValueTagsOf is also not used.
    711- // XXX: Allocators are not used here for performance.
    712- term.Value = TermReference(PropagateTo(tm.Tags, p_ref->GetTags()), tm,
    713- NPL::Deref(p_ref).GetEnvironmentReference());
    710+ term.SetValue(in_place_type<TermReference>, PropagateTo(tm.Tags,
    711+ p_ref->GetTags()), tm, NPL::Deref(p_ref).GetEnvironmentReference());
    714712 return ReductionStatus::Clean;
    715713 }
    716714
    @@ -834,7 +832,7 @@
    834832 Environment::LookupName(string_view id) const
    835833 {
    836834 YAssertNonnull(id.data());
    837- return NPL::make_observer(ystdex::call_value_or<BindingMap::mapped_type*>(
    835+ return make_observer(ystdex::call_value_or<BindingMap::mapped_type*>(
    838836 ystdex::compose(ystdex::addrof<>(), ystdex::second_of<>()),
    839837 Bindings.find(id), {}, Bindings.cend()));
    840838 }
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/source/NPL/NPLA1.cpp
    --- a/YFramework/source/NPL/NPLA1.cpp Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/source/NPL/NPLA1.cpp Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA1.cpp
    1212 \ingroup NPL
    1313 \brief NPLA1 公共接口。
    14-\version r22377
    14+\version r22423
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 472
    1717 \par 创建时间:
    1818 2014-02-02 18:02:47 +0800
    1919 \par 修改时间:
    20- 2022-05-20 18:06 +0800
    20+ 2022-06-14 18:22 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -29,23 +29,23 @@
    2929 #include YFM_NPL_NPLA1Forms // for NPL, EvaluationPasses, lref, ContextHandler,
    3030 // RelaySwitched, trivial_swap, type_index, string_view, std::hash,
    3131 // ystdex::equal_to, YSLib::unordered_map, std::piecewise_construct,
    32-// YSLib::lock_guard, YSLib::mutex, type_id, NPL::make_observer, IsBranch,
    32+// YSLib::lock_guard, YSLib::mutex, type_id, make_observer, IsBranch,
    3333 // CheckReducible, IsNPLAExtendedLiteralNonDigitPrefix, IsAllSignLexeme,
    3434 // AllocatorHolder, ystdex::ref, YSLib::IValueHolder,
    3535 // YSLib::AllocatedHolderOperations, any, ystdex::as_const,
    3636 // NPL::forward_as_tuple, uintmax_t, ystdex::bind1, TokenValue,
    3737 // Forms::Sequence, std::allocator_arg, ReduceBranchToList, YSLib::stack,
    3838 // YSLib::vector, TermTags, function, TermReference, GetLValueTagsOf,
    39-// NPL::TryAccessLeaf, ListReductionFailure, ystdex::sfmt, PropagateTo,
    40-// NPL::IsMovable, in_place_type, InvalidReference, NPL::Deref, IsLeaf,
    41-// ResolveTerm, ThrowInsufficientTermsError, ThrowListTypeErrorForNonlist,
    42-// ystdex::update_thunk, Environment, shared_ptr, NPL::AsTermNode, IsTyped,
    43-// ystdex::retry_on_cond, AccessFirstSubterm, ystdex::make_transform,
    44-// IsBranchedList, std::placeholders, NoContainer, ystdex::try_emplace,
    45-// NPL::Access, YSLib::Informative, ystdex::unique_guard,
    46-// CategorizeBasicLexeme, DeliteralizeUnchecked, Deliteralize,
    47-// ystdex::isdigit, INT_MAX, ystdex::ref_eq, NPL::TryAccessTerm,
    48-// YSLib::share_move, ystdex::call_value_or, std::to_string, YSLib::Notice,
    39+// TryAccessLeaf, ListReductionFailure, ystdex::sfmt, TryAccessLeafAtom,
    40+// PropagateTo, NPL::IsMovable, in_place_type, InvalidReference, NPL::Deref,
    41+// IsLeaf, ResolveTerm, ThrowInsufficientTermsError,
    42+// ThrowListTypeErrorForNonlist, ystdex::update_thunk, Environment, shared_ptr,
    43+// NPL::AsTermNode, IsTyped, ystdex::retry_on_cond, AccessFirstSubterm,
    44+// ystdex::make_transform, IsBranchedList, std::placeholders, NoContainer,
    45+// ystdex::try_emplace, Access, YSLib::Informative, ystdex::unique_guard,
    46+// CategorizeBasicLexeme, DeliteralizeUnchecked, Deliteralize, ystdex::isdigit,
    47+// INT_MAX, ystdex::ref_eq, TryAccessTerm, YSLib::share_move,
    48+// ystdex::call_value_or, std::to_string, YSLib::Notice,
    4949 // YSLib::FilterException, Session;
    5050 #include "NPLA1Internals.h" // for A1::Internals API;
    5151 #include YFM_NPL_NPLAMath // for ReadDecimal;
    @@ -241,6 +241,7 @@
    241241 term.Value.Clear();
    242242
    243243 auto gd(ystdex::unique_guard([&]() ynothrow{
    244+ // XXX: This term is fixed, as in the term cleanup in %TCOAction.
    244245 term.Clear();
    245246 }));
    246247 # if NPL_Impl_NPLA1_Enable_Thunked
    @@ -276,7 +277,7 @@
    276277 string name(term.get_allocator());
    277278
    278279 // XXX: As %TermToNamePtr.
    279- if(const auto p = NPL::TryAccessLeaf<TokenValue>(term))
    280+ if(const auto p = TryAccessLeaf<TokenValue>(term))
    280281 {
    281282 name = std::move(*p);
    282283 name += ": ";
    @@ -483,7 +484,7 @@
    483484 # if NPL_Impl_NPLA1_Enable_ThunkedThreshold == 0
    484485 YAssert(!remained.empty(), "Invalid state found.");
    485486 // XXX: For some reason, 'while' here is more efficient than 'do' in the
    486- // generated code with x86_64-pc-linux G++ 11.1.0.
    487+ // generated code with x86_64-pc-linux G++ 11.1.
    487488 # endif
    488489 while(!remained.empty())
    489490 {
    @@ -586,7 +587,7 @@
    586587
    587588 // NOTE: Subterms in arguments retained are also transferred for
    588589 // values.
    589- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    590+ if(const auto p = TryAccessLeafAtom<TermReference>(o))
    590591 {
    591592 if(sigil != char())
    592593 {
    @@ -839,7 +840,8 @@
    839840 // here.
    840841 if(IsLeaf(back))
    841842 {
    842- if(const auto p = NPL::TryAccessLeaf<TokenValue>(back))
    843+ if(const auto p
    844+ = TryAccessLeafAtom<TokenValue>(back))
    843845 {
    844846 if(!p->empty() && p->front() == '.')
    845847 --last;
    @@ -907,7 +909,7 @@
    907909 has_ref).c_str()));
    908910 }, o);
    909911 }
    910- else if(const auto p_t = NPL::TryAccessLeaf<const TermReference>(t))
    912+ else if(const auto p_t = TryAccessLeafAtom<const TermReference>(t))
    911913 {
    912914 auto& nd(p_t->get());
    913915
    @@ -1153,13 +1155,15 @@
    11531155 {
    11541156 AssertValueTags(term);
    11551157
    1158+ // NOTE: For efficiency, only quite a few kinds of terms would be reduced
    1159+ // here. More specific handling can be implemented by context handlers or
    1160+ // replacement of %ContextState::DefaultReduceOnce.
    11561161 auto& cs(ContextState::Access(ctx));
    11571162 const bool non_list(!IsList(term));
    11581163
    11591164 // NOTE: Empty list or special value token has no-op to do with.
    11601165 if(non_list)
    11611166 {
    1162- // XXX: Add logic to directly handle special value tokens here?
    11631167 // NOTE: The reduction relies on proper handling of reduction status and
    11641168 // proper tail action for the thunked implementations.
    11651169 if(!IsTyped<ValueToken>(term))
    @@ -1360,7 +1364,7 @@
    13601364
    13611365 // XXX: As %BindParameter.
    13621366 for(auto& o : nd)
    1363- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    1367+ if(const auto p = TryAccessLeafAtom<TermReference>(o))
    13641368 EmplaceReference(con, o, *p, !p_ref);
    13651369 else if(p_ref)
    13661370 con.emplace_back(TermNode::Container(o.get_allocator()),
    @@ -1397,13 +1401,13 @@
    13971401 const auto add_tags(p_ref->GetTags() | TermTags::Unique);
    13981402
    13991403 for(auto& o : nd)
    1400- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    1404+ if(const auto p = TryAccessLeafAtom<TermReference>(o))
    14011405 EmplaceReference(con, o, *p, {});
    14021406 else
    14031407 con.emplace_back(TermNode::Container(o.get_allocator()),
    1404- ValueObject(std::allocator_arg, a, in_place_type<
    1405- TermReference>, o.Tags | add_tags, o,
    1406- p_ref->GetEnvironmentReference()));
    1408+ std::allocator_arg, a, in_place_type<TermReference>,
    1409+ o.Tags | add_tags, o,
    1410+ p_ref->GetEnvironmentReference());
    14071411 con.swap(term.GetContainerRef());
    14081412 }
    14091413 else
    @@ -1431,7 +1435,7 @@
    14311435 if(const auto p = p_e->LookupName(name))
    14321436 {
    14331437 using ystdex::pvoid;
    1434- auto& depth(NPL::Access<size_t>(*p));
    1438+ auto& depth(Access<size_t>(*p));
    14351439
    14361440 yunused(term), yunused(ctx);
    14371441 YTraceDe(YSLib::Informative, "Depth = %zu, context = %p, semantics"
    @@ -1495,6 +1499,8 @@
    14951499 ParseLeaf(TermNode& term, string_view id)
    14961500 {
    14971501 YAssertNonnull(id.data());
    1502+ // NOTE: The lexeme shall not be empty, although the code literal '' can be
    1503+ // converted to an empty symbol after the processing here.
    14981504 YAssert(!id.empty(), "Invalid leaf token found.");
    14991505 switch(CategorizeBasicLexeme(id))
    15001506 {
    @@ -1527,8 +1533,7 @@
    15271533 // NOTE: Most are same to %ParseLeaf, except for additional source
    15281534 // information mixed into the values of %TokenValue.
    15291535 YAssertNonnull(id.data());
    1530- // NOTE: The lexeme shall not be empty, although the code literal '' can be
    1531- // converted to an empty symbol after the processing here.
    1536+ // NOTE: Ditto.
    15321537 YAssert(!id.empty(), "Invalid leaf token found.");
    15331538 switch(CategorizeBasicLexeme(id))
    15341539 {
    @@ -1582,7 +1587,7 @@
    15821587 YAssert(!t.empty(), "Invalid term found.");
    15831588 ReduceChildrenOrderedAsyncUnchecked(std::next(t.begin()), t.end(), c);
    15841589 return ReductionStatus::Partial;
    1585- }, trivial_swap, A1::NameTypedReducerHandler([&, n](ContextNode& c){
    1590+ }, trivial_swap, NameTypedReducerHandler([&, n](ContextNode& c){
    15861591 SetupNextTerm(c, term);
    15871592 return CallN(n - 1, term, c);
    15881593 }, "eval-combine-operator"));
    @@ -1782,7 +1787,7 @@
    17821787 // XXX: Allocators are not used here on %TermReference to avoid G++ from
    17831788 // folding code with other basic blocks with more inefficient
    17841789 // implementations.
    1785- if(const auto p = NPL::TryAccessLeaf<const TermReference>(bound))
    1790+ if(const auto p = TryAccessLeafAtom<const TermReference>(bound))
    17861791 {
    17871792 p_rterm = &p->get();
    17881793 // NOTE: If the bound object is a term reference, referencing it
    @@ -1835,7 +1840,7 @@
    18351840 YAssert(IsCombiningTerm(term), "Invalid term found for combined term.");
    18361841
    18371842 auto& fm(AccessFirstSubterm(term));
    1838- const auto p_ref_fm(NPL::TryAccessLeaf<const TermReference>(fm));
    1843+ const auto p_ref_fm(TryAccessLeafAtom<const TermReference>(fm));
    18391844
    18401845 // NOTE: If this call returns normally, the combiner object implied by %fm
    18411846 // is not owned by %term.
    @@ -1866,7 +1871,7 @@
    18661871 // in %ReduceForCombinerRef.
    18671872 const auto& referenced(p_ref_fm->get());
    18681873
    1869- YAssert(ystdex::ref_eq<>()(NPL::Deref(NPL::Access<
    1874+ YAssert(ystdex::ref_eq<>()(NPL::Deref(Access<
    18701875 shared_ptr<TermNode>>(*fm.begin())), referenced),
    18711876 "Invalid subobject reference found.");
    18721877 // XXX: Explicit copy is necessary as in the implementation of
    @@ -1879,7 +1884,7 @@
    18791884 #endif
    18801885 // NOTE: The combiner object is in an lvalue. It is not saved by %term.
    18811886 if(const auto p_handler
    1882- = NPL::TryAccessLeaf<const ContextHandler>(p_ref_fm->get()))
    1887+ = TryAccessLeafAtom<const ContextHandler>(p_ref_fm->get()))
    18831888 // NOTE: This is neutral to %NPL_Impl_NPLA1_Enable_Thunked.
    18841889 return CombinerReturnThunk(*p_handler, term, ctx);
    18851890 }
    @@ -1891,7 +1896,7 @@
    18911896 // XXX: Converted terms (if used, see above) are also handled here as in
    18921897 // prvalues.
    18931898 // NOTE: To allow being moved, %p_handler is not qualified by 'const'.
    1894- if(const auto p_handler = NPL::TryAccessTerm<ContextHandler>(fm))
    1899+ if(const auto p_handler = TryAccessTerm<ContextHandler>(fm))
    18951900 #if NPL_Impl_NPLA1_Enable_TCO
    18961901 return
    18971902 CombinerReturnThunk(*p_handler, term, ctx, std::move(*p_handler));
    @@ -1919,7 +1924,7 @@
    19191924 YAssert(IsCombiningTerm(term), "Invalid term found for combined term.");
    19201925 // XXX: %SetupNextTerm is to be called in %CombinerReturnThunk.
    19211926 ClearCombiningTags(term);
    1922- if(const auto p_handler = NPL::TryAccessLeaf<const ContextHandler>(fm))
    1927+ if(const auto p_handler = TryAccessLeafAtom<const ContextHandler>(fm))
    19231928 return CombinerReturnThunk(*p_handler, term, ctx);
    19241929 return ThrowCombiningFailure(term, fm, true);
    19251930 }
    @@ -2157,12 +2162,12 @@
    21572162 YB_STATELESS
    21582163 #endif
    21592164 observer_ptr<const ValueObject>
    2160-QueryTailOperatorName(const Reducer& act)
    2165+QueryTailOperatorName(const Reducer& act) ynothrow
    21612166 {
    21622167 #if NPL_Impl_NPLA1_Enable_TCO
    21632168 if(const auto p_act = act.target<TCOAction>())
    21642169 if(p_act->OperatorName.type() == type_id<TokenValue>())
    2165- return NPL::make_observer(&p_act->OperatorName);
    2170+ return make_observer(&p_act->OperatorName);
    21662171 #else
    21672172 yunused(act);
    21682173 #endif
    @@ -2182,7 +2187,7 @@
    21822187 }
    21832188
    21842189 bool
    2185-SetupTailOperatorName(TermNode& term, const ContextNode& ctx)
    2190+SetupTailOperatorName(TermNode& term, const ContextNode& ctx) ynothrow
    21862191 {
    21872192 if(const auto p_combining = ContextState::Access(ctx).GetCombiningTermPtr())
    21882193 {
    @@ -2210,16 +2215,16 @@
    22102215 {
    22112216 const auto name(QueryContinuationName(act));
    22122217 const auto p(name.data() ? name.data() :
    2213-# if NDEBUG
    2218+#if NDEBUG
    22142219 "?"
    2215-# else
    2220+#else
    22162221 // XXX: This is enabled for debugging only because the name
    22172222 // is not guaranteed steady.
    22182223 ystdex::call_value_or([](const Continuation& cont)
    22192224 -> const type_info&{
    22202225 return cont.Handler.target_type();
    22212226 }, act.target<Continuation>(), act.target_type()).name()
    2222-# endif
    2227+#endif
    22232228 );
    22242229 const auto p_opn_vo(QueryTailOperatorName(act));
    22252230 // XXX: No %NPL::TryAccessValue is needed, since %p_opn_vo comes
    @@ -2231,14 +2236,14 @@
    22312236 {
    22322237 // XXX: This clause relies on the source information for
    22332238 // meaningful output. Assume it is used.
    2234-# if true
    2239+#if true
    22352240 if(const auto p_si = QuerySourceInformation(*p_opn_vo))
    22362241 trace.TraceFormat(Notice, "#[continuation: %s (%s) @"
    22372242 " %s (line %zu, column %zu)]", p_o, p,
    22382243 p_si->first ? p_si->first->c_str() : "<unknown>",
    22392244 p_si->second.Line + 1, p_si->second.Column + 1);
    22402245 else
    2241-# endif
    2246+#endif
    22422247 trace.TraceFormat(Notice, "#[continuation: %s (%s)]",
    22432248 p_o, p);
    22442249 }
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/source/NPL/NPLA1Forms.cpp
    --- a/YFramework/source/NPL/NPLA1Forms.cpp Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/source/NPL/NPLA1Forms.cpp Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA1Forms.cpp
    1212 \ingroup NPL
    1313 \brief NPLA1 语法形式。
    14-\version r27233
    14+\version r27377
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 882
    1717 \par 创建时间:
    1818 2014-02-15 11:19:51 +0800
    1919 \par 修改时间:
    20- 2022-05-29 08:09 +0800
    20+ 2022-06-14 18:34 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -27,7 +27,7 @@
    2727
    2828 #include "NPL/YModules.h"
    2929 #include YFM_NPL_NPLA1Forms // for YSLib, std::next, ReduceOnceLifted,
    30-// ResolvedTermReferencePtr, NPL::IsMovable, NPL::TryAccessReferencedTerm,
    30+// ResolvedTermReferencePtr, NPL::IsMovable, TryAccessReferencedTerm,
    3131 // ystdex::value_or, ThrowInsufficientTermsError, NPL::Deref,
    3232 // A1::NameTypedReducerHandler, ReduceReturnUnspecified, RemoveHead, IsBranch,
    3333 // AccessFirstSubterm, ReduceSubsequent, ReduceCombinedBranch,
    @@ -39,17 +39,17 @@
    3939 // ResolveEnvironment, ShareMoveTerm, BindParameterWellFormed, ystdex::sfmt,
    4040 // TermToStringWithReferenceMark, ResolveTerm, LiftOtherOrCopy,
    4141 // ClearCombiningTags, SContext::Analyze, std::allocator_arg,
    42-// NPL::ResolveRegular, ystdex::make_transform, NPL::TryAccessLeaf,
    43-// TermReference, EnvironmentList, NPL::AllocateEnvironment,
    44-// ystdex::equality_comparable, CheckParameterTree, AssertValueTags,
    45-// NPL::AsTermNode, ystdex::exchange, NPLException, GuardFreshEnvironment,
    46-// TermTags, YSLib::Debug, YSLib::sfmt, A1::MakeForm, ystdex::expand_proxy,
    47-// NPL::AccessRegular, GetLValueTagsOf, RegularizeTerm, IsBranchedList,
    48-// LiftMovedOther, LiftOtherValue, ThrowValueCategoryError, std::mem_fn,
    49-// ThrowListTypeErrorForNonlist, ThrowInvalidSyntaxError,
    50-// CheckEnvironmentFormal, type_id, ystdex::update_thunk, IsTyped,
    51-// EnvironmentGuard, BindSymbol, A1::AsForm, ystdex::bind1, IsNPLASymbol,
    52-// ystdex::fast_all_of, ystdex::call_value_or, LiftCollapsed, YSLib::usystem;
    42+// NPL::ResolveRegular, ystdex::make_transform, TryAccessLeaf, TermReference,
    43+// EnvironmentList, NPL::AllocateEnvironment, ystdex::equality_comparable,
    44+// CheckParameterTree, AssertValueTags, NPL::AsTermNode, ystdex::exchange,
    45+// NPLException, GuardFreshEnvironment, TermTags, YSLib::Debug, YSLib::sfmt,
    46+// A1::MakeForm, ystdex::expand_proxy, AccessRegular, GetLValueTagsOf,
    47+// RegularizeTerm, IsBranchedList, LiftMovedOther, LiftOtherValue,
    48+// ThrowValueCategoryError, std::mem_fn, ThrowListTypeErrorForNonlist,
    49+// ThrowInvalidSyntaxError, CheckEnvironmentFormal, type_id,
    50+// ystdex::update_thunk, IsTyped, EnvironmentGuard, BindSymbol, A1::AsForm,
    51+// ystdex::bind1, IsNPLASymbol, ystdex::fast_all_of, ystdex::call_value_or,
    52+// LiftCollapsed, YSLib::usystem;
    5353 #include "NPLA1Internals.h" // for A1::Internals API;
    5454 #include YFM_NPL_SContext // for Session;
    5555 #include <ystdex/functor.hpp> // for ystdex::id;
    @@ -116,7 +116,7 @@
    116116 YB_ATTR_nodiscard YB_PURE bool
    117117 ExtractBool(const TermNode& term)
    118118 {
    119- return ystdex::value_or(NPL::TryAccessReferencedTerm<bool>(term), true);
    119+ return ystdex::value_or(TryAccessReferencedTerm<bool>(term), true);
    120120 }
    121121
    122122 //! \since build 860
    @@ -695,7 +695,7 @@
    695695 return ystdex::make_transform(iter, [&](TNIter i) -> ValueObject{
    696696 // XXX: Like %LiftToReturn, but for %Value only.
    697697 if(const auto p
    698- = NPL::TryAccessLeaf<const TermReference>(NPL::Deref(i)))
    698+ = TryAccessLeafAtom<const TermReference>(NPL::Deref(i)))
    699699 {
    700700 if(nonmodifying || !p->IsMovable())
    701701 return p->get().Value;
    @@ -994,46 +994,44 @@
    994994 };
    995995
    996996
    997-//! \since build 944
    997+//! \since build 947
    998+//@{
    999+template<typename... _tParams>
    9981000 void
    999-MakeValueListOrMove(TermNode::Container& con, TermNode& nd,
    1000- ResolvedTermReferencePtr p_ref)
    1001-{
    1002- MakeValueOrMove(p_ref, [&]{
    1003- for(const auto& sub : nd)
    1004- con.push_back(sub);
    1005- }, [&]{
    1006- // XXX: No cyclic reference check.
    1007- con.splice(con.end(), nd.GetContainerRef());
    1008- });
    1009-}
    1010-
    1011-//! \since build 859
    1012-YB_NORETURN void
    1013-ThrowConsError(TermNode& nd, ResolvedTermReferencePtr p_ref)
    1014-{
    1015- throw ListTypeError(ystdex::sfmt(
    1016- "Expected a list for the 2nd argument, got '%s'.",
    1017- TermToStringWithReferenceMark(nd, p_ref).c_str()));
    1018-}
    1019-
    1020-//! \since build 944
    1021-void
    1022-ConsItem(TermNode::Container& con, TermNode& y)
    1023-{
    1024- ResolveTerm([&](TermNode& nd_y, ResolvedTermReferencePtr p_ref){
    1001+ConsSplice(TermNode tm, TermNode& nd, _tParams&&... args)
    1002+{
    1003+ auto& tcon(tm.GetContainerRef());
    1004+ auto& con(nd.GetContainerRef());
    1005+
    1006+ // XXX: No other cyclic reference check.
    1007+ YAssert(!ystdex::ref_eq<>()(con, tcon), "Invalid self move found.");
    1008+ tcon.splice(tcon.begin(), con, con.begin(), yforward(args)...);
    1009+ tcon.swap(con);
    1010+}
    1011+
    1012+// XXX: Returning term instead of the container allows to pass improper lists,
    1013+// also perserves the allocator on
    1014+// copy.
    1015+YB_ATTR_nodiscard TermNode
    1016+ConsItem(TermNode& y)
    1017+{
    1018+ return ResolveTerm([&](TermNode& nd_y, ResolvedTermReferencePtr p_ref_y){
    10251019 if(IsList(nd_y))
    1026- MakeValueListOrMove(con, nd_y, p_ref);
    1020+ // TODO: Use %LiftOtherOrCopy?
    1021+ return MakeValueOrMove(p_ref_y, [&]{
    1022+ // XXX: The order is significant for the exception safety
    1023+ // guarantee.
    1024+ return nd_y;
    1025+ }, [&]{
    1026+ // NOTE: This is necessary because %con can be moved to its
    1027+ // ancestors.
    1028+ return std::move(nd_y);
    1029+ });
    10271030 else
    1028- ThrowConsError(nd_y, p_ref);
    1031+ ThrowListTypeErrorForNonlist(nd_y, p_ref_y);
    10291032 }, y);
    10301033 }
    1031-//! \since build 859
    1032-void
    1033-ConsItem(TermNode& term, TermNode& y)
    1034-{
    1035- ConsItem(term.GetContainerRef(), y);
    1036-}
    1034+//@}
    10371035
    10381036 //! \since build 912
    10391037 ReductionStatus
    @@ -1044,9 +1042,7 @@
    10441042
    10451043 auto i(term.begin());
    10461044
    1047- ++i;
    1048- ConsItem(term, NPL::Deref(i));
    1049- term.erase(i);
    1045+ ConsSplice(ConsItem(NPL::Deref(++i)), term);
    10501046 return ReductionStatus::Retained;
    10511047 }
    10521048
    @@ -1133,7 +1129,7 @@
    11331129 {
    11341130 return NPL::ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
    11351131 return DispatchContextHandler(
    1136- NPL::AccessRegular<ContextHandler>(nd, p_ref), p_ref, f, f2);
    1132+ AccessRegular<ContextHandler>(nd, p_ref), p_ref, f, f2);
    11371133 }, term);
    11381134 }
    11391135 //@}
    @@ -1160,7 +1156,7 @@
    11601156 // NOTE: Simplified from 'sigil == '&' and 'can_modify && temp' branch in
    11611157 // %BindParameterObject::operator(), except that %TermTags::Temporary is
    11621158 // not set as %MarkTemporaryTerm in NPLA1.cpp.
    1163- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    1159+ if(const auto p = TryAccessLeafAtom<TermReference>(o))
    11641160 // NOTE: Reference collapsed by move.
    11651161 mv(std::move(o.GetContainerRef()),
    11661162 TermReference(BindReferenceTags(*p), std::move(*p)));
    @@ -1174,7 +1170,7 @@
    11741170 // NOTE: Simplified from 'sigil == '&' and 'can_modify && temp' branch in
    11751171 // %BindParameterObject::operator(), except that %TermTags::Temporary is
    11761172 // not set as %MarkTemporaryTerm in NPLA1.cpp.
    1177- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    1173+ if(const auto p = TryAccessLeafAtom<TermReference>(o))
    11781174 // NOTE: Reference collapsed by move.
    11791175 p->SetTags(BindReferenceTags(*p));
    11801176 }
    @@ -1196,7 +1192,7 @@
    11961192 // NOTE: Simplified from '&' and not 'can_modify && temp' branch in
    11971193 // %BindParameterObject::operator().
    11981194 mv(TermNode::Container(o.GetContainer()), [&]() -> TermReference{
    1199- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    1195+ if(const auto p = TryAccessLeafAtom<TermReference>(o))
    12001196 return TermReference(BindReferenceTags(*p), *p);
    12011197 return TermReference(GetLValueTagsOf(o.Tags | o_tags), o, r_env);
    12021198 }());
    @@ -1217,7 +1213,7 @@
    12171213 YB_ATTR_nodiscard TermNode
    12181214 EvaluateBoundLValue(TermNode& term, const shared_ptr<Environment>& p_env)
    12191215 {
    1220- if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
    1216+ if(const auto p = TryAccessLeafAtom<TermReference>(term))
    12211217 return TermNode(std::allocator_arg, term.get_allocator(),
    12221218 term.GetContainer(), EnsureLValueReference(*p));
    12231219 return EvaluateToLValueReference(term, p_env);
    @@ -1229,7 +1225,7 @@
    12291225 YB_ATTR_nodiscard TermNode
    12301226 EvaluateBoundLValueMoved(TermNode& term, const shared_ptr<Environment>& p_env)
    12311227 {
    1232- if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
    1228+ if(const auto p = TryAccessLeafAtom<TermReference>(term))
    12331229 {
    12341230 *p = EnsureLValueReference(std::move(*p));
    12351231 return std::move(term);
    @@ -1245,7 +1241,7 @@
    12451241 EvaluateLocalObject(TermNode& o, const shared_ptr<Environment>& p_env)
    12461242 {
    12471243 // NOTE: Make unique reference as a bound temporary object.
    1248- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    1244+ if(const auto p = TryAccessLeafAtom<TermReference>(o))
    12491245 {
    12501246 p->SetTags(BindReferenceTags(*p));
    12511247 return TermNode(std::allocator_arg, o.get_allocator(),
    @@ -1264,7 +1260,7 @@
    12641260 EvaluateLocalObjectMoved(TermNode& o, const shared_ptr<Environment>& p_env)
    12651261 {
    12661262 // NOTE: Make unique reference as a bound temporary object.
    1267- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    1263+ if(const auto p = TryAccessLeafAtom<TermReference>(o))
    12681264 {
    12691265 // NOTE: See also %EnsureLValueReference.
    12701266 *p = TermReference(BindReferenceTags(*p) & ~TermTags::Unique,
    @@ -1296,7 +1292,7 @@
    12961292 const TermNode::Container& con, TermReference ref,
    12971293 TermNode& nd)
    12981294 {
    1299- auto& h(NPL::AccessRegular<ContextHandler>(nd, true));
    1295+ auto& h(AccessRegular<ContextHandler>(nd, true));
    13001296
    13011297 if(const auto p = h.target<FormContextHandler>())
    13021298 {
    @@ -1320,7 +1316,7 @@
    13201316 EvaluateBoundLValueUnwrapped(TermNode& term,
    13211317 const shared_ptr<Environment>& p_env)
    13221318 {
    1323- if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
    1319+ if(const auto p = TryAccessLeafAtom<TermReference>(term))
    13241320 return EvaluateBoundUnwrappedLValueDispatch(
    13251321 term.get_allocator(), term.GetContainer(), *p, p->get());
    13261322 return EvaluateBoundUnwrappedLValueDispatch(term.get_allocator(),
    @@ -1347,7 +1343,7 @@
    13471343 // XXX: Similar to the implementation of %ReduceToReference in NPLA.cpp.
    13481344 term.CopyContent(tm);
    13491345 // NOTE: Propagate tags if it is a term reference.
    1350- if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
    1346+ if(const auto p = TryAccessLeafAtom<TermReference>(term))
    13511347 p->PropagateFrom(tags);
    13521348 // XXX: Term tags are currently not respected in prvalues.
    13531349 }
    @@ -1389,7 +1385,7 @@
    13891385 // however, not x86_64-pc-linux G++ 11.1.
    13901386 const bool list_not_move(!NPL::IsMovable(p_ref));
    13911387
    1392- if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
    1388+ if(const auto p = TryAccessLeafAtom<const TermReference>(tm))
    13931389 {
    13941390 if(list_not_move)
    13951391 LiftPropagatedReference(term, tm, p_ref->GetTags());
    @@ -1432,7 +1428,7 @@
    14321428 auto& tm(AccessFirstSubterm(nd));
    14331429 const bool move(NPL::IsMovable(tags));
    14341430
    1435- if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
    1431+ if(const auto p = TryAccessLeafAtom<const TermReference>(tm))
    14361432 {
    14371433 if(move)
    14381434 {
    @@ -1456,9 +1452,8 @@
    14561452 // not unique due to 2-pass iterations (e.g. it may be also used in
    14571453 // a interleaved call to %BranchRestFwdReferenced with unspecified
    14581454 // order to this call).
    1459- term.Value = ValueObject(std::allocator_arg, term.get_allocator(),
    1460- in_place_type<TermReference>, PropagateTo(tm.Tags, tags), tm,
    1461- r_env);
    1455+ term.SetValue(in_place_type<TermReference>, PropagateTo(tm.Tags, tags),
    1456+ tm, r_env);
    14621457 // NOTE: No %TermNode::ClearContainer is here because %term is expected
    14631458 // newly created.
    14641459 YAssert(IsLeaf(term), "Invalid term found");
    @@ -1504,7 +1499,7 @@
    15041499 {
    15051500 // XXX: Simple 'ReduceToValue(term, tm)' is wrong because it may move
    15061501 // non-unqiue reference object away.
    1507- if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
    1502+ if(const auto p = TryAccessLeafAtom<const TermReference>(tm))
    15081503 LiftMovedOther(term, *p, move && p->IsMovable());
    15091504 else
    15101505 // XXX: Term tags are currently not respected in prvalues.
    @@ -1583,7 +1578,7 @@
    15831578 SetFirstRest([f](TermNode& nd_x, TermNode& y){
    15841579 auto& dst(AccessFirstSubterm(nd_x));
    15851580
    1586- if(const auto p = NPL::TryAccessLeaf<TermReference>(y))
    1581+ if(const auto p = TryAccessLeafAtom<TermReference>(y))
    15871582 f(dst, y, *p);
    15881583 else
    15891584 LiftTerm(dst, y);
    @@ -1605,24 +1600,16 @@
    16051600 SetRestImpl(TermNode& term)
    16061601 {
    16071602 SetFirstRest([](TermNode& nd_x, TermNode& y){
    1608- ResolveTerm([&](TermNode& nd_y, ResolvedTermReferencePtr p_ref_y){
    1609- // XXX: How to simplify? Merge with %BindParameterObject?
    1610- if(IsList(nd_y))
    1611- {
    1612- const auto a(nd_x.get_allocator());
    1613- TermNode::Container con_new(a);
    1614-
    1615- con_new.emplace_back();
    1616- MakeValueListOrMove(con_new, nd_y, p_ref_y);
    1617- _rLift(con_new);
    1618- // XXX: The order is significant.
    1619- con_new.front() = MoveFirstSubterm(nd_x);
    1620- swap(nd_x.GetContainerRef(), con_new);
    1621- nd_x.Value.Clear();
    1622- }
    1623- else
    1624- ThrowListTypeErrorForNonlist(nd_y, p_ref_y);
    1625- }, y);
    1603+ auto tcon(ConsItem(y));
    1604+
    1605+ ConsSplice(tcon, nd_x);
    1606+ // XXX: Assume the call to %_rLift does not throw, so it can be
    1607+ // reordered here.
    1608+ // TODO: What to do on %nd_x.Value if lifting is requested?
    1609+ _rLift(nd_x.GetContainerRef());
    1610+ // XXX: The order is significant for the exception safety
    1611+ // guarantee.
    1612+ nd_x.Value.Clear();
    16261613 }, term);
    16271614 }
    16281615
    @@ -1739,7 +1726,7 @@
    17391726 auto& tm(NPL::Deref(++i));
    17401727
    17411728 return ReduceSubsequent(tm, ctx,
    1742- A1::NameTypedReducerHandler([&, i, wrap, no_lift]{
    1729+ NameTypedReducerHandler([&, i, wrap, no_lift]{
    17431730 return ReduceCreateFunction(term, [&]{
    17441731 // XXX: Keep %ResolveParentFrom in lambda-expression is a bit more
    17451732 // efficient for x86_64-pc-linux G++ 12.1.
    @@ -1918,13 +1905,11 @@
    19181905
    19191906 ForwardToUnwrapped(comb);
    19201907 {
    1921- TermNode::Container tcon(term.get_allocator());
    1922-
    1923- tcon.push_back(std::move(comb));
    1924- ConsItem(tcon, NPL::Deref(++i));
    1925- tcon.swap(term.GetContainerRef());
    1908+ auto t(ConsItem(NPL::Deref(++i)));
    1909+
    1910+ t.GetContainerRef().push_front(std::move(comb));
    1911+ swap(t, term);
    19261912 }
    1927- ClearCombiningTags(term);
    19281913 // NOTE: The precondition is same to the last call in %EvalImplUnchecked.
    19291914 // See also the precondition of %Combine<TailCall>::RelayEnvSwitch.
    19301915 return Combine<TailCall>::RelayEnvSwitch(ctx, term, std::move(p_env));
    @@ -1943,9 +1928,8 @@
    19431928 {
    19441929 const auto last(std::prev(term.end()));
    19451930
    1946- ConsItem(term, Deref(last));
    1947- term.erase(last),
    19481931 RemoveHead(term);
    1932+ ConsSplice(ConsItem(NPL::Deref(last)), term, last);
    19491933 }
    19501934 else
    19511935 LiftOther(term, head);
    @@ -1956,15 +1940,16 @@
    19561940 using TermPrefixGuard = decltype(ystdex::unique_guard(ystdex::prefix_eraser<
    19571941 TermNode::Container>(std::declval<TermNode::Container&>())));
    19581942
    1959-TermPrefixGuard
    1943+YB_ATTR_nodiscard inline TermPrefixGuard
    19601944 GuardTermPrefix(TermNode::Container& con) ynothrow
    19611945 {
    19621946 return
    19631947 ystdex::unique_guard(ystdex::prefix_eraser<TermNode::Container>(con));
    19641948 }
    19651949
    1950+//! \since build 947
    19661951 void
    1967-RemoveTermPostfix(TermPrefixGuard& gd) ynothrow
    1952+RemoveTermSuffix(TermPrefixGuard& gd) ynothrow
    19681953 {
    19691954 auto& eraser(gd.func.func);
    19701955 auto& tcon(eraser.container);
    @@ -1984,7 +1969,7 @@
    19841969
    19851970 con.insert(con.insert(con.begin(), yforward(lv_l)),
    19861971 EvaluateBoundLValueUnwrapped(tail, d));
    1987- RemoveTermPostfix(gd);
    1972+ RemoveTermSuffix(gd);
    19881973 }
    19891974 term.Value.Clear();
    19901975 // XXX: No %ClearCombiningTags is called, as it would be determined later
    @@ -2116,6 +2101,8 @@
    21162101 }, term, ctx);
    21172102 }
    21182103
    2104+// XXX: Direct assignment of %TermRange to %ValueObject is likely more efficient
    2105+// than %SetValue.
    21192106 //! \since build 916
    21202107 struct TermRange final
    21212108 {
    @@ -2164,7 +2151,7 @@
    21642151 if(p_ref->IsMovable())
    21652152 {
    21662153 LiftOther(term, nd);
    2167- term.SetValue(TermRange(term));
    2154+ term.Value = TermRange(term);
    21682155 }
    21692156 else
    21702157 // NOTE: Encode the value category information of the list.
    @@ -2177,11 +2164,11 @@
    21772164 // shall be copied on the element accesses later. This is
    21782165 // comsumed by %IsExpiredRange, only used to provide the
    21792166 // 3rd argument to the call to %ExtractRangeFirstOrCopy.
    2180- term.Tags |= TermTags::Nonmodifying,
    2181- term.SetValue(TermRange(nd, p_ref->GetTags()));
    2167+ yunseq(term.Tags |= TermTags::Nonmodifying,
    2168+ term.Value = TermRange(nd, p_ref->GetTags()));
    21822169 }
    21832170 else
    2184- term.SetValue(TermRange(term));
    2171+ term.Value = TermRange(term);
    21852172 }
    21862173 else
    21872174 // NOTE: Always treat the list as an lvalue as in the derivation.
    @@ -2376,7 +2363,7 @@
    23762363 auto& nterm(tcon.emplace_back());
    23772364 auto& o(NPL::Deref(tr.First));
    23782365
    2379- if(const auto p = NPL::TryAccessLeaf<const TermReference>(o))
    2366+ if(const auto p = TryAccessLeafAtom<const TermReference>(o))
    23802367 {
    23812368 // NOTE: The tags of the term range shall be prepared in the
    23822369 // call to %PrepareFoldRList or similar functions. The nonmodifying
    @@ -2417,7 +2404,7 @@
    24172404 const bool move(NPL::IsMovable(o_tags));
    24182405
    24192406 #if false
    2420- if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
    2407+ if(const auto p = TryAccessLeafAtom<const TermReference>(tm))
    24212408 {
    24222409 LiftOtherOrCopy(nterm, p->get(), move ? p->IsMovable()
    24232410 : NPL::IsMovable(PropagateTo(p->GetTags(), o_tags)));
    @@ -2897,18 +2884,17 @@
    28972884
    28982885 for(auto& o : nd)
    28992886 {
    2900- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
    2901- con.emplace_back(o.GetContainer(), ValueObject(
    2902- std::allocator_arg, a, in_place_type<TermReference>, *p));
    2887+ if(const auto p = TryAccessLeafAtom<TermReference>(o))
    2888+ con.emplace_back(o.GetContainer(), std::allocator_arg, a,
    2889+ in_place_type<TermReference>, *p);
    29032890 else
    29042891 con.emplace_back(TermNode::Container(o.get_allocator()),
    2905- ValueObject(std::allocator_arg, a, in_place_type<
    2906- TermReference>, GetLValueTagsOf(o.Tags | o_tags)
    2907- | TermTags::Unique, o, r_env));
    2892+ std::allocator_arg, a, in_place_type<TermReference>,
    2893+ GetLValueTagsOf(o.Tags | o_tags) | TermTags::Unique, o, r_env);
    29082894 }
    29092895 con.swap(term.GetContainerRef());
    29102896 // NOTE: As %PrepareFoldRList.
    2911- term.SetValue(TermRange(term, TermTags::Temporary));
    2897+ term.Value = TermRange(term, TermTags::Temporary);
    29122898 }
    29132899
    29142900 //! \since build 918
    @@ -2942,7 +2928,7 @@
    29422928 // NOTE: Optimize by the fast path for cases of zero arguments.
    29432929 if(IsEmpty(bindings))
    29442930 return LetEmptyNoEnv(term, ctx, no_lift);
    2945- if(const auto p = NPL::TryAccessLeaf<TermReference>(bindings))
    2931+ if(const auto p = TryAccessLeafAtom<TermReference>(bindings))
    29462932 {
    29472933 auto& nd(p->get());
    29482934
    @@ -2961,7 +2947,7 @@
    29612947 else if(IsList(nd))
    29622948 {
    29632949 bindings.ClearContainer(),
    2964- bindings.SetValue(TermRange(nd, p->GetTags()));
    2950+ bindings.Value = TermRange(nd, p->GetTags());
    29652951 con.push_front(nd.GetContainer().front());
    29662952 ++bindings.Value.GetObject<TermRange>().First;
    29672953 }
    @@ -2969,7 +2955,7 @@
    29692955 ThrowInsufficientTermsError(nd, true);
    29702956 }
    29712957 // NOTE: The %TermRange is from the converted result above.
    2972- else if(const auto p_tr = NPL::TryAccessLeaf<TermRange>(bindings))
    2958+ else if(const auto p_tr = TryAccessLeaf<TermRange>(bindings))
    29732959 {
    29742960 // XXX: Empty ranges shall not be converted to %TermRange above; they
    29752961 // are from the handling of other non-empty %TermRange values.
    @@ -3040,7 +3026,7 @@
    30403026 ContextState::Access(ctx).ClearCombiningTerm();
    30413027 term.Value.Clear();
    30423028 // XXX: The nested 'combine-return' continuations in
    3043- // %ReduceCombined are omitteed even when TCO is not available,
    3029+ // %ReduceCombined are omitted even when TCO is not available,
    30443030 // since they are still idempotent in the tail context
    30453031 // (guaranteed by the semantics of the derivation in the
    30463032 // operation). The enclosing call initialiating %LetAsterisk or
    @@ -3064,7 +3050,7 @@
    30643050 // XXX: The call to %GetLValueTagsOf on the tag argument for
    30653051 // %BranchFirstReferenced is unnecessary. See the comments in
    30663052 // %ListRangeExtract.
    3067- if(const auto p = NPL::TryAccessLeaf<TermReference>(extracted))
    3053+ if(const auto p = TryAccessLeafAtom<TermReference>(extracted))
    30683054 {
    30693055 auto& nd(p->get());
    30703056
    @@ -3085,7 +3071,7 @@
    30853071 auto& nterm(*con.emplace_front().emplace());
    30863072 auto& tm(AccessFirstSubterm(extracted));
    30873073
    3088- if(const auto p_ref = NPL::TryAccessLeaf<const TermReference>(tm))
    3074+ if(const auto p_ref = TryAccessLeafAtom<const TermReference>(tm))
    30893075 {
    30903076 if(!p_ref->IsReferencedLValue())
    30913077 LiftMovedOther(nterm, *p_ref, p_ref->IsMovable());
    @@ -3120,7 +3106,7 @@
    31203106 ThrowInsufficientTermsError(nd, true);
    31213107 });
    31223108
    3123- if(const auto p = NPL::TryAccessLeaf<TermReference>(extracted))
    3109+ if(const auto p = TryAccessLeafAtom<TermReference>(extracted))
    31243110 return letc(p->get(), p->GetEnvironmentReference(), p->GetTags(),
    31253111 p->IsMovable());
    31263112 return letc(extracted, ctx.GetRecordPtr(),
    @@ -3159,7 +3145,7 @@
    31593145 // NOTE: Optimize by the fast path for cases of zero arguments.
    31603146 if(IsEmpty(bindings))
    31613147 return LetEmpty(term, ctx, no_lift, with_env);
    3162- if(const auto p = NPL::TryAccessLeaf<TermReference>(bindings))
    3148+ if(const auto p = TryAccessLeafAtom<TermReference>(bindings))
    31633149 {
    31643150 auto& nd(p->get());
    31653151
    @@ -3174,8 +3160,8 @@
    31743160 p->GetTags());
    31753161 else if(IsList(nd))
    31763162 // NOTE: As %PrepareFoldRList.
    3177- forwarded.SetValue(TermRange(nd, p->GetTags())),
    3178- forwarded.Tags = TermTags::Nonmodifying;
    3163+ yunseq(forwarded.Value = TermRange(nd, p->GetTags()),
    3164+ forwarded.Tags = TermTags::Nonmodifying);
    31793165 else
    31803166 ThrowInsufficientTermsError(nd, true);
    31813167 }
    @@ -3254,7 +3240,7 @@
    32543240 for(auto& x : term)
    32553241 // NOTE: As %MoveRValueToForward, but with same term to
    32563242 // be lifted.
    3257- if(const auto p = NPL::TryAccessLeaf<const TermReference>(x))
    3243+ if(const auto p = TryAccessLeafAtom<const TermReference>(x))
    32583244 if(!p->IsReferencedLValue())
    32593245 LiftOtherOrCopy(x, p->get(), p->IsModifiable());
    32603246 }
    @@ -3332,7 +3318,7 @@
    33323318 // not used of operator, so %SetupTailOperatorName is not
    33333319 // called.
    33343320 if(const auto p
    3335- = NPL::TryAccessLeaf<const TermReference>(bound))
    3321+ = TryAccessLeafAtom<const TermReference>(bound))
    33363322 {
    33373323 if(p->IsTemporary())
    33383324 LiftOtherOrCopy(nterm, p->get(), p->IsModifiable());
    @@ -3594,7 +3580,7 @@
    35943580 return bool(ystdex::call_value_or([this] YB_LAMBDA_ANNOTATE(
    35953581 (const Encapsulation& enc), ynothrow, pure){
    35963582 return Get() == enc.Get();
    3597- }, NPL::TryAccessReferencedTerm<Encapsulation>(tm)));
    3583+ }, TryAccessReferencedTerm<Encapsulation>(tm)));
    35983584 }, term);
    35993585 }
    36003586
    @@ -3612,13 +3598,13 @@
    36123598 // NOTE: As an lvalue reference, the object in %tm cannot be
    36133599 // destroyed.
    36143600 if(const auto p
    3615- = NPL::TryAccessLeaf<const TermReference>(tm))
    3601+ = TryAccessLeafAtom<const TermReference>(tm))
    36163602 term.SetContent(tm.GetContainer(), *p);
    36173603 else
    36183604 {
    36193605 // XXX: Subterms cleanup is deferred.
    36203606 // XXX: Allocators are not used here for performance.
    3621- term.Value.assign(in_place_type<TermReference>, tm,
    3607+ term.SetValue(in_place_type<TermReference>, tm,
    36223608 p_ref->GetEnvironmentReference());
    36233609 return ReductionStatus::Clean;
    36243610 }
    @@ -3695,7 +3681,7 @@
    36953681 auto i(std::next(term.begin()));
    36963682
    36973683 // XXX: Use captured %ctx seems more efficient here.
    3698- return ReduceSubsequent(*i, ctx, A1::NameTypedReducerHandler([&, i]{
    3684+ return ReduceSubsequent(*i, ctx, NameTypedReducerHandler([&, i]{
    36993685 auto j(i);
    37003686
    37013687 if(!ExtractBool(*j))
    @@ -4446,7 +4432,7 @@
    44464432 auto& x(*++i);
    44474433
    44484434 if(const auto p
    4449- = NPL::TryAccessLeaf<const TermReference>(x))
    4435+ = TryAccessLeafAtom<const TermReference>(x))
    44504436 {
    44514437 if(!p->IsReferencedLValue())
    44524438 LiftMovedOther(x, *p, p->IsMovable());
    @@ -4649,7 +4635,7 @@
    46494635
    46504636 // TODO: Optimize the case of empty binding lists, as %LetEmpty.
    46514637 // NOTE: As %LetOrRecImpl.
    4652- if(const auto p = NPL::TryAccessLeaf<TermReference>(bindings))
    4638+ if(const auto p = TryAccessLeafAtom<TermReference>(bindings))
    46534639 {
    46544640 auto& nd(p->get());
    46554641
    @@ -4657,8 +4643,8 @@
    46574643 LetExpireChecked(forwarded, nd, p->GetEnvironmentReference(),
    46584644 p->GetTags());
    46594645 else if(IsList(nd))
    4660- forwarded.SetValue(TermRange(nd, p->GetTags())),
    4661- forwarded.Tags = TermTags::Nonmodifying;
    4646+ yunseq(forwarded.Value = TermRange(nd, p->GetTags()),
    4647+ forwarded.Tags = TermTags::Nonmodifying);
    46624648 else
    46634649 ThrowInsufficientTermsError(nd, true);
    46644650 }
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/source/NPL/NPLA1Internals.cpp
    --- a/YFramework/source/NPL/NPLA1Internals.cpp Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/source/NPL/NPLA1Internals.cpp Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA1Internals.cpp
    1212 \ingroup NPL
    1313 \brief NPLA1 内部接口。
    14-\version r20628
    14+\version r20644
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 473
    1717 \par 创建时间:
    1818 2020-02-15 13:20:08 +0800
    1919 \par 修改时间:
    20- 2022-06-05 01:26 +0800
    20+ 2022-06-13 23:54 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 非公开模块名称:
    @@ -256,19 +256,20 @@
    256256
    257257 // NOTE: Irregular representation is constructed for the subobject
    258258 // reference.
    259- const auto a(term.get_allocator());
    260- auto& sub(NPL::Deref(p_sub));
    259+ auto& con(term.GetContainerRef());
    260+ auto i(con.begin());
    261261
    262-#if true
    263- TermNode tm(std::allocator_arg, a, {NPL::AsTermNode(a, std::move(p_sub))},
    264- std::allocator_arg, a, TermReference(sub, r_env));
    265-
    266- term.SetContent(std::move(tm));
    267-#else
    268- term = TermNode(std::allocator_arg, a,
    269- {NPL::AsTermNode(a, std::move(p_sub))},
    270- std::allocator_arg, a, TermReference(sub, r_env));
    271-#endif
    262+ // XXX: Set %Value first. Although this is not strongly exception-safe,
    263+ // it guarantees no unexpected copies of user-defined objects remained even
    264+ // if the following operations exit via exception. The order of setting of
    265+ // %Tags is insignificant, though.
    266+ term.SetValue(TermReference(NPL::Deref(p_sub), r_env)),
    267+ term.Tags = TermTags::Unqualified;
    268+ // XXX: Not using %ystdex::prefix_eraser because there is known 1 subterm to
    269+ // be inserted.
    270+ con.insert(i, NPL::AsTermNodeTagged(con.get_allocator(), TermTags::Sticky,
    271+ std::move(p_sub)));
    272+ con.erase(i, con.end());
    272273 return ReductionStatus::Retained;
    273274 }
    274275
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/source/NPL/NPLA1Internals.h
    --- a/YFramework/source/NPL/NPLA1Internals.h Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/source/NPL/NPLA1Internals.h Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLA1Internals.h
    1212 \ingroup NPL
    1313 \brief NPLA1 内部接口。
    14-\version r22245
    14+\version r22378
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 882
    1717 \par 创建时间:
    1818 2020-02-15 13:20:08 +0800
    1919 \par 修改时间:
    20- 2022-06-05 01:26 +0800
    20+ 2022-06-14 18:24 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 非公开模块名称:
    @@ -32,10 +32,10 @@
    3232 #include YFM_NPL_NPLA1 // for shared_ptr, ContextNode, NPL::Deref, NPLException,
    3333 // TermNode, ReductionStatus, Reducer, YSLib::map, lref, Environment, set,
    3434 // IsTyped, EnvironmentList, EnvironmentReference, pair, YSLib::forward_list,
    35-// size_t, list, std::declval, EnvironmentGuard, MoveKeptGuard,
    35+// size_t, tuple, std::declval, EnvironmentGuard, MoveKeptGuard,
    3636 // A1::NameTypedContextHandler, TermReference, ThrowTypeErrorForInvalidType,
    37-// NPL::TryAccessLeaf, type_id, TermToNamePtr, IsIgnore,
    38-// ystdex::exclude_self_t, ParameterMismatch;
    37+// TryAccessLeafAtom, type_id, TermToNamePtr, IsIgnore, ystdex::exclude_self_t,
    38+// ParameterMismatch;
    3939 #include <ystdex/compose.hpp> // for ystdex::get_less;
    4040 #include <ystdex/scope_guard.hpp> // for ystdex::unique_guard;
    4141 #include <ystdex/optional.h> // for ystdex::optional;
    @@ -97,7 +97,33 @@
    9797 ImplExpr(ContextState::Access(ctx).SetNextTermRef(term))
    9898
    9999 // NOTE: See $2018-09 @ %Documentation::Workflow for rationale of the
    100-// implementation.
    100+// implementation of PTC.
    101+
    102+/*!
    103+\brief 源代码名称恢复器。
    104+\since build 947
    105+*/
    106+class SourceNameRecoverer final
    107+{
    108+private:
    109+ observer_ptr<SourceName> p_current{};
    110+ SourceName Saved{};
    111+
    112+public:
    113+ DefDeCtor(SourceNameRecoverer)
    114+ SourceNameRecoverer(SourceName& cur, SourceName name)
    115+ : p_current(&cur), Saved(name)
    116+ {}
    117+ DefDeCopyMoveCtorAssignment(SourceNameRecoverer)
    118+
    119+ void
    120+ operator()() const ynothrow
    121+ {
    122+ if(p_current)
    123+ *p_current = std::move(Saved);
    124+ }
    125+};
    126+
    101127 // XXX: First-class continuations are not implemented completely yet, due to
    102128 // lack of term replacement mechanism in captured continuation. Kernel-style
    103129 // continuation interception is also unsupported because no reference for
    @@ -116,6 +142,8 @@
    116142 OneShotChecker(ContextNode& ctx)
    117143 : p_shot(YSLib::allocate_shared<bool>(ctx.get_allocator()))
    118144 {}
    145+ //! \since build 947
    146+ DefDeCopyMoveCtorAssignment(OneShotChecker)
    119147
    120148 void
    121149 operator()() const ynothrow
    @@ -305,7 +333,7 @@
    305333 public:
    306334 #if YB_IMPL_CLANGPP || YB_IMPL_GNUCPP >= 100000
    307335 // XXX: See ContextNode::ReducerSequence.
    308- FrameRecordList() ynoexcept_spec(FrameRecordList())
    336+ FrameRecordList() ynoexcept_spec(Base())
    309337 : Base()
    310338 {}
    311339 #elif __cpp_inheriting_constructors < 201511L
    @@ -358,6 +386,27 @@
    358386 PDefHOp(void, (), ) const ynothrow
    359387 ImplExpr(TermRef.get().Clear())
    360388 };
    389+ //! \since build 947
    390+ //@{
    391+ /*!
    392+ \brief 附加信息索引。
    393+ \note 顺序保持和 ExtraInfo 的元素对应一致。
    394+ */
    395+ enum ExtraInfoIndex : size_t
    396+ {
    397+ RecoverSourceName,
    398+ CheckOneShot
    399+ };
    400+
    401+ /*!
    402+ \brief 帧记录。
    403+ \note 成员顺序和 RecordFrameIndex 中的项对应。
    404+ \note 成员析构的顺序是未指定的。
    405+ \sa RecordFrameIndex
    406+ */
    407+ using ExtraInfo = tuple<ystdex::guard<SourceNameRecoverer>,
    408+ ystdex::optional<ystdex::guard<OneShotChecker>>>;
    409+ //@}
    361410
    362411 //! \since build 910
    363412 mutable size_t req_lift_result = 0;
    @@ -376,10 +425,10 @@
    376425
    377426 private:
    378427 /*!
    379- \brief 一次调用检查守卫。
    380- \since build 943
    428+ \brief 可选的附加信息。
    429+ \since build 947
    381430 */
    382- mutable ystdex::optional<ystdex::guard<OneShotChecker>> one_shot_guard{};
    431+ mutable ystdex::optional<ExtraInfo> opt_extra_info{};
    383432
    384433 public:
    385434 //! \since build 819
    @@ -407,10 +456,7 @@
    407456 // object always live longer than the older one.
    408457 : req_lift_result(a.req_lift_result),
    409458 env_guard(std::move(a.env_guard)), term_guard(std::move(a.term_guard))
    410- {
    411- if(a.one_shot_guard)
    412- one_shot_guard.emplace(a.one_shot_guard->func);
    413- }
    459+ {}
    414460 DefDeMoveCtor(TCOAction)
    415461 // XXX: Out-of-line destructor here is inefficient.
    416462
    @@ -420,6 +466,17 @@
    420466 ReductionStatus
    421467 operator()(ContextNode&) const;
    422468
    469+private:
    470+ //! \since build 947
    471+ YB_ATTR_nodiscard ExtraInfo&
    472+ GetExtraInfoRef()
    473+ {
    474+ if(!opt_extra_info)
    475+ opt_extra_info.emplace();
    476+ return *opt_extra_info;
    477+ }
    478+
    479+public:
    423480 //! \since build 913
    424481 DefGetter(const ynothrow, TermNode&, TermRef, term_guard.func.func.TermRef)
    425482
    @@ -474,13 +531,15 @@
    474531 {
    475532 CompressForContext(ctx);
    476533 // NOTE: The temporary function and the environment are saved in
    477- // the frame record list as a new entry if necessary.
    534+ // the frame record list as a new entry if necessary. The
    535+ // existence of the entry shall be checked because it may be
    536+ // missing for function lvalues or calls not from a combiner
    537+ // (e.g. by 'eval').
    478538 if(!record_list.empty() && !record_list.front().second)
    479539 record_list.front().second = std::move(p_saved);
    480540 else
    481541 record_list.emplace_front(ContextHandler(),
    482542 std::move(p_saved));
    483- return;
    484543 }
    485544 // XXX: Normally this should not occur, but this is allowed by the
    486545 // interface (for an object %EnvironmentSwitcher initialized
    @@ -497,6 +556,8 @@
    497556 YB_ATTR_nodiscard OneShotChecker
    498557 MakeOneShotChecker()
    499558 {
    559+ auto& one_shot_guard(NPL::get<CheckOneShot>(GetExtraInfoRef()));
    560+
    500561 if(!one_shot_guard)
    501562 // XXX: The context is only used to determine the allocator, which
    502563 // is an implementation detail. Usually the context in caller
    @@ -518,16 +579,29 @@
    518579 }
    519580
    520581 /*!
    521- \pre \c one_shot_guard 。
    582+ \pre \c NPL::get<CheckOneShot>(GetExtraInfoRef()) 。
    522583 \since build 945
    523584 */
    524585 void
    525586 ReleaseOneShotGuard()
    526587 {
    588+ auto& one_shot_guard(NPL::get<CheckOneShot>(GetExtraInfoRef()));
    589+
    527590 YAssert(one_shot_guard, "One-shot guard is not initialized properly.");
    528591 return one_shot_guard.reset();
    529592 }
    530593
    594+ /*!
    595+ \brief 保存尾上下文中的源代码名称。
    596+ \since build 947
    597+ */
    598+ void
    599+ SaveTailSourceName(SourceName& cur, SourceName name)
    600+ {
    601+ NPL::get<RecoverSourceName>(GetExtraInfoRef())
    602+ = SourceNameRecoverer(cur, std::move(name));
    603+ }
    604+
    531605 //! \since build 911
    532606 //@{
    533607 //! \brief 设置提升请求。
    @@ -589,6 +663,10 @@
    589663 ImplExpr(SetupTailAction(ctx, TCOAction(ctx, term, lift)))
    590664
    591665
    666+// XXX: It is accidentally close to ECMAScript 6's %PrepareForTailCall in both
    667+// name and semantics, but actually independent. In particular, ES6's "pop"
    668+// wording indicates it only operate on one side of the activation records in
    669+// relavant contexts, which differs than the %TCOAction here.
    592670 /*!
    593671 \brief 准备 TCO 求值。
    594672 \param ctx 规约上下文。
    @@ -915,6 +993,30 @@
    915993 //@{
    916994 struct NonTailCall final
    917995 {
    996+#if NPL_Impl_NPLA1_Enable_Thunked
    997+ //! \since build 947
    998+ YB_ATTR_nodiscard YB_FLATTEN static Reducer
    999+ MakeLiftResult(TermNode& term, ContextNode& ctx)
    1000+ {
    1001+ // NOTE: The term to be lifted is fixed regardless of continuation
    1002+ // capture, so this needs no setup of the next term and the reducer
    1003+ // does not need to be a %Continuation.
    1004+ // XXX: However, %Containuation is actually more efficient. Whether
    1005+ // %Continuation is used, %NPL::ToReducer here would be a bit
    1006+ // inefficient.
    1007+#if true
    1008+ return Continuation(NameTypedContextHandler([&]{
    1009+ return ReduceForLiftedResult(term);
    1010+ }, "eval-lift-result"), ctx);
    1011+#else
    1012+ yunused(ctx);
    1013+ return NameTypedContextHandler([&]{
    1014+ return ReduceForLiftedResult(term);
    1015+ }, "eval-lift-result");
    1016+#endif
    1017+ }
    1018+#endif
    1019+
    9181020 //! \pre 最后一个参数的类型退化后可平凡交换。
    9191021 //@{
    9201022 template<typename _fCurrent>
    @@ -940,27 +1042,20 @@
    9401042 }
    9411043
    9421044 template<typename _fCurrent>
    943- YB_FLATTEN static inline ReductionStatus
    1045+ static inline ReductionStatus
    9441046 RelayNextGuardedLifted(ContextNode& ctx, TermNode& term,
    9451047 EnvironmentGuard&& gd, _fCurrent&& cur)
    9461048 {
    9471049 // XXX: See %RelayNextGuarded.
    9481050 #if NPL_Impl_NPLA1_Enable_Thunked
    9491051 auto act(MoveKeptGuard(gd));
    950- // TODO: Blocked. Use C++14 lambda initializers to simplify the
    951- // implementation.
    952- // XXX: Term reused. Call of %SetupNextTerm is not needed as the next
    953- // term is guaranteed not changed when %cur is a continuation.
    954- Continuation cont(A1::NameTypedContextHandler([&]{
    955- // TODO: Avoid fixed continuation parameter.
    956- return ReduceForLiftedResult(term);
    957- }, "eval-lift-result"), ctx);
    9581052
    1053+ // XXX: Call of %SetupNextTerm is not needed because the next term is
    1054+ // guaranteed not changed whether %cur is a continuation.
    9591055 RelaySwitched(ctx, trivial_swap, std::move(act));
    960- // XXX: %Continuation is specialized enough without
    961- // %trivial_swap.
    1056+ // XXX: %Reducer is specialized enough without %trivial_swap.
    9621057 return A1::RelayCurrentNext(ctx, term, trivial_swap, yforward(cur),
    963- std::move(cont));
    1058+ MakeLiftResult(term, ctx));
    9641059 #else
    9651060 yunused(gd);
    9661061 RelayDirect(ctx, cur, term);
    @@ -981,18 +1076,11 @@
    9811076
    9821077 if(lift)
    9831078 {
    984- // XXX: Term reused. Call of %SetupNextTerm is not needed as the
    985- // next term is guaranteed not changed when %cur is a continuation.
    986- Continuation cont(A1::NameTypedContextHandler([&]{
    987- // TODO: Avoid fixed continuation parameter.
    988- return ReduceForLiftedResult(term);
    989- }, "eval-lift-result"), ctx);
    990-
    1079+ // XXX: As %RelayNextGuardedLifted.
    9911080 RelaySwitched(ctx, trivial_swap, std::move(act));
    992- // XXX: %Continuation is specialized enough without
    993- // %trivial_swap.
    994- return A1::RelayCurrentNext(ctx, term, trivial_swap,
    995- yforward(cur), std::move(cont));
    1081+ // XXX: As %RelayNextGuardedLifted.
    1082+ return A1::RelayCurrentNext(ctx, term, trivial_swap, yforward(cur),
    1083+ MakeLiftResult(term, ctx));
    9961084 }
    9971085 return A1::RelayCurrentNext(ctx, term, trivial_swap, yforward(cur),
    9981086 trivial_swap, std::move(act));
    @@ -1183,7 +1271,7 @@
    11831271 const TermReference& ref)
    11841272 // XXX: It is assumed that %term is not an ancestor of %bound. The source
    11851273 // term tags are ignored.
    1186- ImplExpr(YAssert(NPL::TryAccessLeaf<const TermReference>(bound).get()
    1274+ ImplExpr(YAssert(TryAccessLeafAtom<const TermReference>(bound).get()
    11871275 == &ref, "Invalid term or reference value found."), term.SetContent(
    11881276 bound.GetContainer(), EnsureLValueReference(TermReference(ref))))
    11891277
    @@ -1274,7 +1362,7 @@
    12741362 if(IsBranch(t))
    12751363 MatchSubterms(t.begin(), t.end());
    12761364 }
    1277- else if(const auto p_t = NPL::TryAccessLeaf<const TermReference>(t))
    1365+ else if(const auto p_t = TryAccessLeafAtom<const TermReference>(t))
    12781366 {
    12791367 auto& nd(p_t->get());
    12801368
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/source/NPL/NPLAMath.cpp
    --- a/YFramework/source/NPL/NPLAMath.cpp Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/source/NPL/NPLAMath.cpp Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file NPLAMath.cpp
    1212 \ingroup NPL
    1313 \brief NPLA 数学功能。
    14-\version r28330
    14+\version r28361
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 930
    1717 \par 创建时间:
    1818 2021-11-03 12:50:49 +0800
    1919 \par 修改时间:
    20- 2022-02-08 19:39 +0800
    20+ 2022-06-14 18:30 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -28,7 +28,7 @@
    2828 #include "NPL/YModules.h"
    2929 #include YFM_NPL_NPLAMath // for ValueObject, ResolvedArg, size_t, type_info,
    3030 // TermNode, ystdex::identity, ystdex::conditional_t, std::is_signed,
    31-// ystdex::_t, NPL::TryAccessValue, YAssert, TypeError, ystdex::sfmt,
    31+// ystdex::_t, TryAccessValue, YAssert, TypeError, ystdex::sfmt,
    3232 // NPL::Nonnull, std::string, ystdex::enable_if_t, std::is_floating_point,
    3333 // NPL::Deref, std::isfinite, std::nearbyint, ystdex::exclude_self_t,
    3434 // std::fmod, ystdex::and_, std::is_unsigned, std::abs, std::floor, std::trunc,
    @@ -288,32 +288,32 @@
    288288 YB_ATTR_nodiscard _type
    289289 DoNumLeaf(_tValue& x, _func f)
    290290 {
    291- if(const auto p_i = NPL::TryAccessValue<int>(x))
    291+ if(const auto p_i = TryAccessValue<int>(x))
    292292 return f(*p_i);
    293- if(const auto p_u = NPL::TryAccessValue<unsigned>(x))
    293+ if(const auto p_u = TryAccessValue<unsigned>(x))
    294294 return f(*p_u);
    295- if(const auto p_ll = NPL::TryAccessValue<long long>(x))
    295+ if(const auto p_ll = TryAccessValue<long long>(x))
    296296 return f(*p_ll);
    297- if(const auto p_ull = NPL::TryAccessValue<unsigned long long>(x))
    297+ if(const auto p_ull = TryAccessValue<unsigned long long>(x))
    298298 return f(*p_ull);
    299- if(const auto p_d = NPL::TryAccessValue<double>(x))
    299+ if(const auto p_d = TryAccessValue<double>(x))
    300300 return f(*p_d);
    301301 // TODO: Support bigint.
    302- if(const auto p_l = NPL::TryAccessValue<long>(x))
    302+ if(const auto p_l = TryAccessValue<long>(x))
    303303 return f(*p_l);
    304- if(const auto p_ul = NPL::TryAccessValue<unsigned long>(x))
    304+ if(const auto p_ul = TryAccessValue<unsigned long>(x))
    305305 return f(*p_ul);
    306- if(const auto p_s = NPL::TryAccessValue<short>(x))
    306+ if(const auto p_s = TryAccessValue<short>(x))
    307307 return f(*p_s);
    308- if(const auto p_us = NPL::TryAccessValue<unsigned short>(x))
    308+ if(const auto p_us = TryAccessValue<unsigned short>(x))
    309309 return f(*p_us);
    310- if(const auto p_sc = NPL::TryAccessValue<signed char>(x))
    310+ if(const auto p_sc = TryAccessValue<signed char>(x))
    311311 return f(*p_sc);
    312- if(const auto p_uc = NPL::TryAccessValue<unsigned char>(x))
    312+ if(const auto p_uc = TryAccessValue<unsigned char>(x))
    313313 return f(*p_uc);
    314- if(const auto p_f = NPL::TryAccessValue<float>(x))
    314+ if(const auto p_f = TryAccessValue<float>(x))
    315315 return f(*p_f);
    316- if(const auto p_ld = NPL::TryAccessValue<long double>(x))
    316+ if(const auto p_ld = TryAccessValue<long double>(x))
    317317 return f(*p_ld);
    318318 return f(x);
    319319 }
    @@ -780,7 +780,7 @@
    780780 ++x;
    781781 else
    782782 // TODO: Support bigint with allocator?
    783- Result.get() = ValueObject(MakeExtType<_type>(x) + 1);
    783+ Result.get().assign(MakeExtType<_type>(x) + 1);
    784784 }
    785785 };
    786786
    @@ -811,7 +811,7 @@
    811811 --x;
    812812 else
    813813 // TODO: Support bigint with allocator?
    814- Result.get() = ValueObject(MakeNExtType<_type>(x) - 1);
    814+ Result.get().assign(ValueObject(MakeNExtType<_type>(x) - 1));
    815815 }
    816816 };
    817817
    @@ -3563,11 +3563,11 @@
    35633563 bool
    35643564 IsRationalValue(const ValueObject& vo) ynothrow
    35653565 {
    3566- if(const auto p_d = NPL::TryAccessValue<double>(vo))
    3566+ if(const auto p_d = TryAccessValue<double>(vo))
    35673567 return std::isfinite(*p_d);
    3568- if(const auto p_f = NPL::TryAccessValue<float>(vo))
    3568+ if(const auto p_f = TryAccessValue<float>(vo))
    35693569 return std::isfinite(*p_f);
    3570- if(const auto p_ld = NPL::TryAccessValue<long double>(vo))
    3570+ if(const auto p_ld = TryAccessValue<long double>(vo))
    35713571 return std::isfinite(*p_ld);
    35723572 return IsExactValue(vo);
    35733573 }
    @@ -3575,11 +3575,11 @@
    35753575 bool
    35763576 IsIntegerValue(const ValueObject& vo) ynothrow
    35773577 {
    3578- if(const auto p_d = NPL::TryAccessValue<double>(vo))
    3578+ if(const auto p_d = TryAccessValue<double>(vo))
    35793579 return FloatIsInteger(*p_d);
    3580- if(const auto p_f = NPL::TryAccessValue<float>(vo))
    3580+ if(const auto p_f = TryAccessValue<float>(vo))
    35813581 return FloatIsInteger(*p_f);
    3582- if(const auto p_ld = NPL::TryAccessValue<long double>(vo))
    3582+ if(const auto p_ld = TryAccessValue<long double>(vo))
    35833583 return FloatIsInteger(*p_ld);
    35843584 return IsExactValue(vo);
    35853585 }
    @@ -3588,11 +3588,11 @@
    35883588 bool
    35893589 IsFinite(const ValueObject& x) ynothrowv
    35903590 {
    3591- if(const auto p_d = NPL::TryAccessValue<double>(x))
    3591+ if(const auto p_d = TryAccessValue<double>(x))
    35923592 return std::isfinite(*p_d);
    3593- if(const auto p_f = NPL::TryAccessValue<float>(x))
    3593+ if(const auto p_f = TryAccessValue<float>(x))
    35943594 return std::isfinite(*p_f);
    3595- if(const auto p_ld = NPL::TryAccessValue<long double>(x))
    3595+ if(const auto p_ld = TryAccessValue<long double>(x))
    35963596 return std::isfinite(*p_ld);
    35973597 return true;
    35983598 }
    @@ -3600,11 +3600,11 @@
    36003600 bool
    36013601 IsInfinite(const ValueObject& x) ynothrowv
    36023602 {
    3603- if(const auto p_d = NPL::TryAccessValue<double>(x))
    3603+ if(const auto p_d = TryAccessValue<double>(x))
    36043604 return std::isinf(*p_d);
    3605- if(const auto p_f = NPL::TryAccessValue<float>(x))
    3605+ if(const auto p_f = TryAccessValue<float>(x))
    36063606 return std::isinf(*p_f);
    3607- if(const auto p_ld = NPL::TryAccessValue<long double>(x))
    3607+ if(const auto p_ld = TryAccessValue<long double>(x))
    36083608 return std::isinf(*p_ld);
    36093609 return {};
    36103610 }
    @@ -3612,11 +3612,11 @@
    36123612 bool
    36133613 IsNaN(const ValueObject& x) ynothrowv
    36143614 {
    3615- if(const auto p_d = NPL::TryAccessValue<double>(x))
    3615+ if(const auto p_d = TryAccessValue<double>(x))
    36163616 return std::isnan(*p_d);
    3617- if(const auto p_f = NPL::TryAccessValue<float>(x))
    3617+ if(const auto p_f = TryAccessValue<float>(x))
    36183618 return std::isnan(*p_f);
    3619- if(const auto p_ld = NPL::TryAccessValue<long double>(x))
    3619+ if(const auto p_ld = TryAccessValue<long double>(x))
    36203620 return std::isnan(*p_ld);
    36213621 return {};
    36223622 }
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/source/NPL/SContext.cpp
    --- a/YFramework/source/NPL/SContext.cpp Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/source/NPL/SContext.cpp Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file SContext.cpp
    1212 \ingroup NPL
    1313 \brief S 表达式上下文。
    14-\version r2292
    14+\version r2314
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 329
    1717 \par 创建时间:
    1818 2012-08-03 19:55:59 +0800
    1919 \par 修改时间:
    20- 2022-04-29 18:57 +0800
    20+ 2022-06-13 01:32 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -150,7 +150,7 @@
    150150 }
    151151
    152152 // XXX: Making it a separate definition slightly improves the generated code
    153- // quality with x86_64-pc-linux G++ 11.1.0.
    153+ // quality with x86_64-pc-linux G++ 11.1.
    154154 void
    155155 UpdateCopyValueAndTags(TermNode& dst, const TermNode& src) const
    156156 {
    @@ -198,41 +198,22 @@
    198198 }
    199199
    200200 // XXX: Simplify with %CreateRecursively?
    201-TermNode::Container
    202-TermNode::ConCons(const ValueNode::Container& con)
    203-{
    204- Container res;
    205-
    206- for(const auto& item : con)
    207- res.emplace_back(ConCons(item.GetContainer()), item.Value);
    208- return res;
    209-}
    210-TermNode::Container
    211-TermNode::ConCons(ValueNode::Container&& con)
    212-{
    213- Container res;
    214-
    215- for(auto& item : con)
    216- res.emplace_back(ConCons(std::move(item.GetContainerRef())),
    217- std::move(item.Value));
    218- return res;
    219-}
    220-TermNode::Container
    201+YB_FLATTEN TermNode::Container
    221202 TermNode::ConCons(const ValueNode::Container& con, allocator_type a)
    222203 {
    223204 Container res(a);
    224205
    225206 for(const auto& item : con)
    226- res.emplace_back(ConCons(item.GetContainer()), item.Value);
    207+ res.emplace_back(ConCons(item.GetContainer(), a), item.Value);
    227208 return res;
    228209 }
    229-TermNode::Container
    210+YB_FLATTEN TermNode::Container
    230211 TermNode::ConCons(ValueNode::Container&& con, allocator_type a)
    231212 {
    232213 Container res(a);
    233214
    234215 for(auto& item : con)
    235- res.emplace_back(ConCons(std::move(item.GetContainerRef())),
    216+ res.emplace_back(ConCons(std::move(item.GetContainerRef()), a),
    236217 std::move(item.Value));
    237218 return res;
    238219 }
    diff -r 9e7268439539 -r 220a0255d5fc YFramework/source/NPL/SXML.cpp
    --- a/YFramework/source/NPL/SXML.cpp Sun Jun 05 02:23:03 2022 +0800
    +++ b/YFramework/source/NPL/SXML.cpp Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file SXML.cpp
    1212 \ingroup NPL
    1313 \brief NPL SXML 实现。
    14-\version r4729
    14+\version r4735
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 936
    1717 \par 创建时间:
    1818 2022-01-20 17:41:15 +0800
    1919 \par 修改时间:
    20- 2022-01-21 02:03 +0800
    20+ 2022-06-14 18:34 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -26,7 +26,7 @@
    2626
    2727
    2828 #include "NPL/YModules.h"
    29-#include YFM_NPL_SXML // for YSLib::Warning, NPL::Access, string, NPL::Deref,
    29+#include YFM_NPL_SXML // for YSLib::Warning, Access, string, NPL::Deref,
    3030 // ystdex::write, AccessFirstSubterm, ystdex::unimplemented, IsTyped,
    3131 // bad_any_cast, ystdex::quote, ystdex::call_value_or;
    3232
    @@ -50,13 +50,13 @@
    5050 case 2:
    5151 {
    5252 auto i(term.begin());
    53- const auto& n(NPL::Access<string>(NPL::Deref(i)));
    53+ const auto& n(Access<string>(NPL::Deref(i)));
    5454
    55- return n + '=' + NPL::Access<string>(NPL::Deref(++i));
    55+ return n + '=' + Access<string>(NPL::Deref(++i));
    5656 }
    5757 YB_ATTR_fallthrough;
    5858 case 1:
    59- return NPL::Access<string>(AccessFirstSubterm(term));
    59+ return Access<string>(AccessFirstSubterm(term));
    6060 case 0:
    6161 break;
    6262 }
    @@ -79,7 +79,7 @@
    7979 try
    8080 {
    8181 auto i(term.begin());
    82- const auto& str(NPL::Access<string>(NPL::Deref(i)));
    82+ const auto& str(Access<string>(NPL::Deref(i)));
    8383
    8484 ++i;
    8585 if(str == "@")
    @@ -167,7 +167,7 @@
    167167 string
    168168 ConvertStringNode(const TermNode& term)
    169169 {
    170- return ystdex::call_value_or(EscapeXML, NPL::AccessPtr<string>(term));
    170+ return ystdex::call_value_or(EscapeXML, AccessPtr<string>(term));
    171171 }
    172172
    173173 void
    diff -r 9e7268439539 -r 220a0255d5fc doc/ChangeLog.V0.9.txt
    --- a/doc/ChangeLog.V0.9.txt Sun Jun 05 02:23:03 2022 +0800
    +++ b/doc/ChangeLog.V0.9.txt Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file ChangeLog.V0.9.txt
    1212 \ingroup Documentation
    1313 \brief 版本更新历史记录 - V0.9 。
    14-\version r9480
    14+\version r9726
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 800
    1717 \par 创建时间:
    1818 2020-10-12 17:19:23 +0800
    1919 \par 修改时间:
    20- 2022-06-05 02:22 +0800
    20+ 2022-06-15 01:04 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -32,6 +32,241 @@
    3232
    3333 $now
    3434 (
    35+ (
    36+ / DLP "updated platform %MinGW64 toolchain"
    37+ $dep_to "MinGW64 toolchain update";
    38+ / $re_ex(b900) $forced "rebuilt library %FreeImage"
    39+ ),
    40+ / $build %Tools $=
    41+ (
    42+ / @ "%SHbuild-build.sh" $=
    43+ (
    44+ / DLI "%LDFLAGS_LOWBASE_" => "%LDFLAGS_WKRD_",
    45+ / "disabled workaround" @ "platform %MinGW64",
    46+ + $forced "workaround for mingw-w64-x86_64-binutils 2.38-3"
    47+ ^ '-fuse-ld=lld' $dep_from "MinGW64 toolchain update"
    48+ // This is also faster.
    49+ ),
    50+ + "selected '-flto=jobserver' over '-flto=auto' for G++ only on \
    51+ platform %MinGW32" @ "%SHBuild-common-options.sh",
    52+ // Now only MinGW32 uses '-flto=jobserver'.
    53+ / @ "applicative %build-with-conf-opt"
    54+ @ "%SHBuild-YSLib-common.txt" $=
    55+ (
    56+ + "2nd argument 'host-arch'"
    57+ $dep_to "passing host architecture to build";
    58+ + "selected '-flto=jobserver' over '-flto=auto' for G++ only on \
    59+ platform %MinGW32"
    60+ // Ditto.
    61+ ),
    62+ / $forced "%SHBuild-YSLib-build.txt"
    63+ $dep_from "passing host architecture to build"
    64+ ),
    65+ / %YFramework.NPL $=
    66+ (
    67+ + 'ynothrow' @ "function %(QueryTailOperatorName, \
    68+ SetupTailOperatorName)" @ %NPLA1,
    69+ - "unnecessary 'A1::' before 'NameTypedReducerHandler'"
    70+ $effective @ "%(NPLA1, NPLA1Internals, NPLA1Forms)",
    71+ / DLI "simplified term value setting with a single value of types \
    72+ except environment references" ^ '=' ~ "%TermValue::SetValue"
    73+ $effective %(NPLAMath, NPLA1Forms),
    74+ // In %NPLA1Forms, all modified instances are for %TermRange. It \
    75+ is a bit more efficient to use assignment directly in this case.
    76+ / %Dependency $=
    77+ (
    78+ * "missing source name recovery" @ (("functions \
    79+ %(ReduceToLoadExternal, RelayToLoadExternal)",
    80+ "applicative %load" @ "function %LoadModule_std_io")
    81+ $since b899, "native implementation" @ "applicative %require"
    82+ @ "function %LoadModule_std_modules" $since b923)
    83+ $= (/ $impl ^ $dep_from
    84+ ("%TCOAction::SaveTailSourceName" @ %NPLA1Internals)),
    85+ / DLDI "simplified native implementation" @ "applicative %force"
    86+ @ "function %LoadModule_std_promises"
    87+ ^ "%TermNode::SetValue" ~ "%ValueObject::assign",
    88+ / DLI ("applicative 'make-standard-environment'" @ "funciton \
    89+ %LoadGroundContext", "native implementation"
    90+ @ "applicative 'get-module'" @ "function \
    91+ %LoadModule_std_modules") ^ "%TermNode::SetValue" ~ '.Value =',
    92+ // To be consistent to other modificiation of environments.
    93+ / DLI "applicative 'get-current-repl'" @ "%function \
    94+ %LoadModule_std_system" ^ "%TermNode::Value::assign" ~ '='
    95+ ),
    96+ / DLI "all term value assignment from %TermReference"
    97+ ^ "%(SetValue, in_place_type<TermReference>)" $effective
    98+ @ %(NPLA, Dependency)
    99+ // It is a bit more efficient with the tag argument.
    100+ / DLDI "simplified term container construction" $effective
    101+ @ ("functions %(ReduceToReferenceList, ReduceToReferenceUList)"
    102+ @ %NPLA1, "functions %Forms::(Let, LetRef, LetWithEnvironment, \
    103+ LetWithEnvironmentRef, LetRec, LetRecRef, \
    104+ BindingsWithParentToEnvironment, BindingsToEnvironment, ProvideLet)"
    105+ !^ "explicit %ValueObject initialization" @ %NPLA1Forms),
    106+ / @ %NPLA1Internals $=
    107+ (
    108+ + 'DefDeCopyMoveCtorAssignment(OneShotChecker)'
    109+ @ "class %OneShotChecker",
    110+ + "class %SourceNameRecovery"
    111+ / @ "class %TCOAction" $=
    112+ (
    113+ / DLDI "simplified function %CompressForGuard",
    114+ / DLDI "simplified copy constructior",
    115+ (
    116+ / DLDI "functions %(MakeOneShotChecker, ReleaseOneShotGuard)";
    117+ + "support of source name guard" @ "data members"
    118+ ^ $dep_from "%SourceNameRecovery";
    119+ + "function %SaveTailSourceName"
    120+ )
    121+ ),
    122+ / @ 'NPL_Impl_NPLA1_Enable_Thunked' @ "class %NonTailCall" $=
    123+ (
    124+ - DLDI 'YB_FLATTEN' @ "static function %RelayNextGuardedLifted",
    125+ (
    126+ + "static function %MakeLiftResult";
    127+ / DLI "simplified static function templates \
    128+ %(RelayNextGuardedLifted, RelayNextGuardedProbe)"
    129+ )
    130+ ),
    131+ * "exception specification" @ "constructor %FrameRecordList"
    132+ $since b946,
    133+ // Also to eliminate Clang++ error. This is related to CWG \
    134+ 1330. The original code is really not wanted here. \
    135+ (Clang++ does have other related bugs as in \
    136+ https://stackoverflow.com/questions/48340412.)
    137+ / @ "function %ReduceAsSubobjectReference" $=
    138+ (
    139+ / DLI "avoided redundant term container copy",
    140+ / "tagged for irregular representation" ^ $dep_from
    141+ ("%(TermTags::Sticky, NPL::AsTermNodeTagged)" @ %SContext)
    142+ )
    143+ ),
    144+ / %SContext $=
    145+ (
    146+ (
    147+ / $src "initializer" @ "enumerator %Unqualified"
    148+ @ "enum class %TermTags" -> '0' ~ '1 << UnqualifiedIndex';
    149+ // Actually the non-zero value is not expected at the very \
    150+ beginning of the design. However, no other code relies on \
    151+ the fact previously, so this is not a bug.
    152+ (
    153+ - "enumerator %UnqualifiedIndex" @ "enum %TermTagIndices";
    154+ / $comp $src "underlying values" @ "all enumerators"
    155+ @ "enum %TermTags"
    156+ ),
    157+ * "exception specification"
    158+ @ "member function template % TermNode::SetValue#1" $since b918,
    159+ (
    160+ + "function %IsReferentTags";
    161+ // To be simpler, this relies on the change of \
    162+ %TermTags::Unqualified above.
    163+ + "2 functions %AssertReferentTags"
    164+ )
    165+ ),
    166+ / @ "constructors %TermNode" $=
    167+ (
    168+ / DLDI "reordered and simplified with %ValueNode::Container \
    169+ parameter",
    170+ (
    171+ + "12 overloads with %TermTags parameter"
    172+ $dep_to "tagged term constructor";
    173+ * "allocator used to initialize %Value instead of the container"
    174+ @ "overload with 'const Container&' parameter" $since b944
    175+ ),
    176+ (
    177+ * "copy" @ "overload with single 'ValueNode&&' parameter"
    178+ $since b853
    179+ $= (/ $impl ^ "%GetContainerRef" ~ "%GetContainer"),
    180+ * "missing propagating allocator to subterms"
    181+ @ "all 2 overloads with single %ValueNode reference and \
    182+ allocator parameters" $since b853,
    183+ )
    184+ ),
    185+ + "2 function templates %AsTermNodeTagged"
    186+ $dep_from "tagged term constructor",
    187+ (
    188+ + "macro %NPL_SContext_CompressTermTags";
    189+ + "enumerator %StickyIndex" @ "enum %TermTagIndices";
    190+ + "enumerator %Sticky" @ "enum class %TermTags";
    191+ + "functions %(IsPair; IsAtom)"
    192+ )
    193+ ),
    194+ / %NPLA $=
    195+ (
    196+ + DLI "invariant, precondition and check" @ "constuctors \
    197+ %TermReference" ^ $dep_from "%AssertReferentTags#1",
    198+ + DLI "precondition and check" @ "function %TermToTags"
    199+ ^ $dep_from "%AssertReferentTags#2",
    200+ + "2 function templates %TryAccessLeafAtom"
    201+ ^ $dep_from ("%IsAtom" @ %SContext),
    202+ + DLDI 'const' @ "operand" @ "exception specification"
    203+ @ "function template %ReferenceTerm#2",
    204+ + "function %LiftElementsToReturn"
    205+ ),
    206+ / "distinguished pairs from leaf values for first-class object accesses"
    207+ $effective @ (("function template %ResolveTerm", ("all 2 functions \
    208+ %ReferenceTerm"; $comp "functor %ReferenceTermOp"), "all 2 \
    209+ function templates %TryAccessReferencedLeaf", "functions \
    210+ %(Collapse, MoveCollapsed, TermToTags, IsReferenceTerm, \
    211+ IsUniqueTerm, IsModifiableTerm, IsTemporaryTerm, \
    212+ IsBoundLValueTerm, IsUncollapsedTerm, LiftToReturn, \
    213+ MoveRValueToForward, MoveRValueToReturn, ReduceToReference)")
    214+ @ %NPLA, "functions %(EvaluateIdentifier, ReduceCombinedBranch, \
    215+ ReduceCombinedReferent, MatchParameter, BindParameter, \
    216+ BindParameterWellFormed, BindSymbol, ReduceToReferenceList, \
    217+ ReduceToReferenceUList)" @ %NPLA1, ("function \
    218+ %SetEvaluatedReference", "class template %GParameterValueMatcher")
    219+ @ %NPLA1Internals, ("function %Decapsulate::operator()",
    220+ ("all functions with prefix 'Lambda', 'Vau', 'WVau', 'SetFirst', \
    221+ 'Acc', 'Let', 'Bindings', 'ListExtract', 'Import' or 'Ass'",
    222+ "functions %(MakeEnvironment, CheckParent, ForwardFirst, First, \
    223+ FirstFwd, FirstVal, RestFwd, RestVal, FoldR1, Map1, ListConcat, \
    224+ Append, SymbolsToImports, ProvideLet, ListPushFront)")
    225+ @ "namespace %Forms") @ %NPLA1Forms, ("combiners ('as-const', \
    226+ %(expire, deshare), '$lvalue-identifier?')" @ "function \
    227+ %LoadGroundContext", "native implementation" @ ("applicative \
    228+ %force" @ "function %LoadModule_std_promises", "applicative \
    229+ %require" @ "function %LoadModule_std_modules")) @ %Dependency)
    230+ // These include almost all call sites of %TryAccessLeaf \
    231+ except a few exceptions: the implementation of \
    232+ %(TryAccessLeafAtom, TryAccessTerm), the internal \
    233+ exception throwing in %ReduceCombinedBranch and %TermRange \
    234+ accesses. Also 'GetObject<TermReference>()' calls in \
    235+ %LiftPropagatedReference would be protected by these changes.
    236+ $= (/ $impl
    237+ ^ ($dep_from "%TryAccessLeafAtom" ~ "%TryAccessLeaf") @ %NPLA),
    238+ / @ "namespace %Forms" @ %NPLA1Forms $=
    239+ (
    240+ + DLDI 'YB_ATTR_nodiscard' @ "internal implemenation"
    241+ @ "%(AccL, AccR)",
    242+ / DLDI "simplified member function %Decapsulate::operator()"
    243+ ^ "%TermNode::SetValue" ~ "%ValueObject::assign",
    244+ / DLDI "simplified explicit %ValueObject with allocator \
    245+ assignment" ^ "%TermNode::SetValue" ~ '.Value =',
    246+ / @ "functions %(Cons, ConsRef, SetRest, SetRestRef, \
    247+ ListAsterisk, ListAsteriskRef, Apply)" $=
    248+ (
    249+ / DLDI "simplified by transferring 1st subterm from the \
    250+ operand instead of the rest";
    251+ + DLDI "assertion to check against self move"
    252+ ^ "%ystdex::ref_eq",
    253+ (
    254+ / DLDI "throwing exception" ^ "%ThrowListTypeErrorForNonlist";
    255+ // This changes the exception message a bit.
    256+ / "merged error handling"
    257+ )
    258+ )
    259+ ),
    260+ - DLDI "all 'NPL::' prefix" @ "calls to function templates with \
    261+ prefix 'Access' or 'TryAccess', or name %make_observer"
    262+ $effective @ %(NPLA, NPLAMath, NPLA1, NPLA1Forms, NPLA1Internals,
    263+ Dependency, SXML)
    264+ // See $2022-06 @ %Documentation::Workflow.
    265+ )
    266+),
    267+
    268+b946
    269+(
    35270 / %YFramework.NPL $=
    36271 (
    37272 / DLI "enabled conditinoal inclusion for different G++ versions"
    @@ -129,6 +364,10 @@
    129364 "%SHBuild-YSLib-common.txt") @ %Scripts, %ProjectGenerator.Main)
    130365 // Ditto.
    131366 ),
    367+ + $lib $impl 'YB_ATTR(optimize("Os"))' @ "member function \
    368+ %resource_pool::deallocate" @ %YBase.YStandardEx.MemoryResource,
    369+ // GCC 12.1 does not generate optimal code as before without this \
    370+ attribute. See also $2022-05 @ %Documentation::Workflow.
    132371 / %YFramework.NPL $=
    133372 (
    134373 / DLI @ "static member function %ContextNode::DefaultResolve" @ %NPLA $=
    @@ -773,6 +1012,8 @@
    7731012 ),
    7741013 / %NPLAMath $=
    7751014 (
    1015+ / $re_add(b940) DLDI "header inclusion %Functional"
    1016+ -> %(ExpandedFunction, Functor),
    7761017 / DLDI "simplified internal static assertions" ^ '()'
    7771018 ~ '::value',
    7781019 / $re_add(b941) DLDI "all member type %traits"
    @@ -1106,7 +1347,7 @@
    11061347 // They should be same to implicily declared ones, hence \
    11071348 redundant.
    11081349 (
    1109- / "header inclusion %Placement" -> "%ComporessedPair",
    1350+ / "inclusion %Placement" -> "%ComporessedPair",
    11101351 / DLDI "function %get_allocator"
    11111352 @ "class templates %(allocator_guard_delete, allocator_delete)"
    11121353 !^ "using-declaration",
    @@ -1725,7 +1966,7 @@
    17251966 ),
    17261967 / %TypeInspection $=
    17271968 (
    1728- / "header inclusion %CStandardDefinition" -> "%IntegralConstant"
    1969+ / "inclusion %CStandardDefinition" -> "%IntegralConstant"
    17291970 $dep_to "collapsed type inspection header inclusion",
    17301971 + "conditionally defined macro %__cpp_lib_is_final";
    17311972 + "unary type trait %is_final" @ "inline namespace %cpp2014"
    @@ -2138,7 +2379,7 @@
    21382379 (
    21392380 / DLDI "simplified constructor template" @ "class %enum_union"
    21402381 ^ "%empty_base" ~ "%std::tuple";
    2141- / DLDI "header inclusion %Tuple" -> "%Variadic"
    2382+ / DLDI "inclusion %Tuple" -> "%Variadic"
    21422383 ),
    21432384 + "function template %to_underlying"
    21442385 ),
    @@ -2759,8 +3000,8 @@
    27593000 / "functions %((is_power_of_2; is_power_of_2_positive), ceiling_lb, \
    27603001 floor_lb)" -> "function templates with 'YB_ATTR_always_inline'"
    27613002 @ %Bits;
    2762- - DLDI "header inclusion %CStandardInteger" @ %MemoryResource,
    2763- - ("header inclusion %CStandardInteger" -> "%IteratorOperation")
    3003+ - DLDI "inclusion %CStandardInteger" @ %MemoryResource,
    3004+ / ("header inclusion %CStandardInteger" -> "%IteratorOperation")
    27643005 @ %Placement,
    27653006 + $dev $lib 'YB_ATTR_always_inline'
    27663007 @ "functions %(is_power_of_2, is_power_of_2_positive)"
    @@ -5594,7 +5835,7 @@
    55945835 for GCC 9.0.x.
    55955836 + "macro %YB_LAMBDA_ANNOTATE"
    55965837 ),
    5597- + $lib $impl "support of extra attributes powered by 'YB_ATTR_LAMBDA_PFRX'"
    5838+ / $lib $impl "supported of extra attributes powered by 'YB_ATTR_LAMBDA_PFX'"
    55985839 @ "all non-standard attributes" @ "lambda-expression" ^ $dep_from
    55995840 ('YB_LAMBDA_ANNOTATE' @ %YBase.YDefinition) ~ ("'YB_*' attributes",
    56005841 'YB_LAMBDA_QUAL') $effective @ ("function %main" @ %SHBuild.Main,
    diff -r 9e7268439539 -r 220a0255d5fc doc/Definitions.txt
    --- a/doc/Definitions.txt Sun Jun 05 02:23:03 2022 +0800
    +++ b/doc/Definitions.txt Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file Definitions.txt
    1212 \ingroup Documentation
    1313 \brief 方法和公共域定义与说明。
    14-\version r14458
    14+\version r14459
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since 早于 build 132
    1717 \par 创建时间:
    1818 2010-01-26 19:34:51 +0800
    1919 \par 修改时间:
    20- 2022-05-24 18:20 +0800
    20+ 2022-06-11 03:26 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -526,6 +526,7 @@
    526526 {
    527527 $unit SContext
    528528 {
    529+#NPL_SContext_CompressTermTags
    529530 NPL_Impl_SContext_Enable_ThunkedActions
    530531 #NPL_Impl_SContext_Enable_ThunkedThreshold
    531532 }
    diff -r 9e7268439539 -r 220a0255d5fc doc/Dependencies.txt
    --- a/doc/Dependencies.txt Sun Jun 05 02:23:03 2022 +0800
    +++ b/doc/Dependencies.txt Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file Dependencies.txt
    1212 \ingroup Documentation
    1313 \brief 依赖说明。
    14-\version r1680
    14+\version r1690
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 519
    1717 \par 创建时间:
    1818 2014-07-15 03:14:24 +0800
    1919 \par 修改时间:
    20- 2022-05-17 18:01 +0800
    20+ 2022-06-10 18:43 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -66,9 +66,10 @@
    6666 @1.1.2 非支持实现的已知问题:
    6767 本节问题不提供变通。
    6868 G++ 11.1.0 之后 12.1.0 前 LTO 因编译器内部错误不被支持。
    69+部分 x86_64 GNU binutils 的 ld 链接 stage 1 SHBuild 时因不明原因无法解析符号,但 -fuse-ld=lld 可用,在此情形下(构建 stage 1 时)ld 不被支持。
    6970
    7071 @1.1.2.1 历史版本的实现的问题:
    71-已知以下历史问题:
    72+已知以下历史问题,不再适用于当前被支持的语言实现:
    7273 G++ 4.8.2(4.8.2-17ubuntu1) :
    7374 在启用 -flto 时,仅使用 std::thread 而不显式使用 pthread 的代码无法链接 pthread 导致运行时出错。
    7475 链接器命令行使用 -lpthread -Wl,--no-as-needed ,参见 http://stackoverflow.com/questions/19463602/compiling-multithread-code-with-g 。
    @@ -78,7 +79,7 @@
    7879
    7980 @1.1.2.2 构建系统兼容性问题:
    8081 已知以下问题可能通过构建系统提供通用的自动检测机制而避免,但当前没有实现:
    81-MinGW 平台输出可执行文件的后缀默认不为 .exe(如某些版本的 Clang++ )。
    82+特定工具链输出非预期文件名(如 MinGW 平台中某些版本的 Clang++ 输出的可执行文件后缀默认不为 .exe )。
    8283
    8384 @1.1.3 正式支持变更记录:
    8485 YSLib 整体正式支持编译器版本要求变更如下:
    @@ -431,6 +432,13 @@
    431432 升级包 mingw64/mingw-w64-x86_64-winpthreads-git 和 mingw64/mingw-w64-x86_64-libwinpthread-git 版本 8.0.0.6001.98dad1fe-3 。
    432433 升级包 mingw64/mingw-w64-x86_64-binutils 版本 2.35.1-2 。
    433434 升级包 mingw64/mingw-w64-x86_64-freetype 2.10.2-2 。
    435+2022-06-10(build 947) 起:
    436+升级包 mingw64/mingw-w64-x86_64-gcc 和 mingw64/mingw-w64-x86_64-gcc-libs 版本 12.1.0-2 。
    437+升级包 mingw64/mingw-w64-x86_64-headers-git 和 mingw64/mingw-w64-x86_64-crt-git 版本 10.0.0.r32.g89bacd2be-1 。
    438+升级包 mingw64/mingw-w64-x86_64-winpthreads-git 和 mingw64/mingw-w64-x86_64-libwinpthread-git 版本 10.0.0.r32.g89bacd2be-1 。
    439+升级包 mingw64/mingw-w64-x86_64-binutils 版本 2.38-3 。
    440+升级包 mingw64/mingw-w64-x86_64-freetype 2.12.1-1 。
    441+使用包 mingw64/mingw-w64-x86_64-lld-14.0.4-1 。
    434442
    435443 @1.7.1 MinGW64 库部署:
    436444 同 MinGW32 库部署(@1.5.1) 的方式。
    diff -r 9e7268439539 -r 220a0255d5fc doc/Workflow.txt
    --- a/doc/Workflow.txt Sun Jun 05 02:23:03 2022 +0800
    +++ b/doc/Workflow.txt Wed Jun 15 01:36:26 2022 +0800
    @@ -11,13 +11,13 @@
    1111 /*! \file Workflow.txt
    1212 \ingroup Documentation
    1313 \brief 工作流汇总报告。
    14-\version r4943
    14+\version r4958
    1515 \author FrankHB <frankhb1989@gmail.com>
    1616 \since build 433
    1717 \par 创建时间:
    1818 2013-07-31 01:27:41 +0800
    1919 \par 修改时间:
    20- 2022-06-05 02:19 +0800
    20+ 2022-06-14 18:57 +0800
    2121 \par 文本编码:
    2222 UTF-8
    2323 \par 模块名称:
    @@ -2590,7 +2590,7 @@
    25902590 This would cause undefined behavior with environment locking, e.g. in evaluation of expression '$let/e (() make-environment) () 42'.
    25912591 The resolution of the bug also relies on removing the hack of collecting function prvalues (see below).
    25922592 Now hack of prvalue function collection is also removed.
    2593- It seems at current it does not effect PTC typically.
    2593+ It seems at current it does not affect PTC typically.
    25942594 See $2018-06 for descriptions of original design.
    25952595
    25962596 $2018-10:
    @@ -4821,7 +4821,7 @@
    48214821 The saved value is then never used.
    48224822 This is generated for 'ystdex::tidy_ptr' copy constructor.
    48234823 OTOH, x86_64-pc-linux Clang++ 13.0.1 always move the 'free_count' value from and to the memory in the call to 'add_free'.
    4824- The code generated is not changed by 'YB_ATTR(optimize("Os"))'.
    4824+ The code generated is not changed by 'YB_ATTR(optimize("Os"))' (actually ignored).
    48254825 Different to 'resource_pool::allocate', there is less chances to predicate the branches correctly, so more compact CMOVcc instructions can be a win. (And actually it generate worse code using '-Os' on 'resouce_pool::allocate'.
    48264826 Note plain branch instructions can still be more compact in binary representations (and the compiler does not necessarily correctly figure that out), e.g. see https://bugs.llvm.org/show_bug.cgi?id=33013#c8.
    48274827 This does not makes any differences with x86_64-pc-linux Clang++ 13.0.1, though.
    @@ -4879,6 +4879,19 @@
    48794879 This sequence is precisely implied by the destructor, as well as the the suffix except the returning value in 'operator()'.
    48804880 By the call to 'dismiss' of the term guard in 'operator()' before the sequence, it remains compatible to both normal ('operator()') and abnormal (destructor entered by exception) returning.
    48814881 Based on the fact that 'operator()' does not have custom actions relying on the program of the object language, the common sequence of the operation is deferred to the modification of 'ContextNode::TailAction' in 'ContextNode::ApplyTail'.
    4882+Some calls to qualified functions are cleanup.
    4883+ For calls with all function arguments of known types not being template specializations, ADL is not performed or has the results same to the unqualified name lookup.
    4884+ In such cases, the prefix (with '::') can be safely omitted without side effects, except there can be a bit worse compilation performance (usually ignored).
    4885+ It is now clear 'TermNode' and some other types defined as classes in namespace 'NPL' are the instances conform to the descriptions above.
    4886+ Notably, there are many calls to function templates named with prefix 'TryAccess'.
    4887+ Some other function templates named with prefix 'Access' and with the name 'TryAccessValue' are from namespace 'YSLib' by using declarations.
    4888+ Nevertheless, the only supported arguments 'ValueObject' is also introduced from 'YSLib' by same way.
    4889+ Additionally, function template 'NPL::make_observer' from 'YSLib' only accept built-in pointers, which have no associated namespaces respected to ADL.
    4890+ So it is also safe to remove the 'NPL::' prefix here.
    4891+ On the other hand, some calls to functions like 'TermToNamePtr', 'AccessFirstSubterm' and 'IsBranch' already has no 'NPL::' prefix.
    4892+ The changed calls would be more consistent to these calls.
    4893+ Similar calls out of the NPL implementation and calls like 'YSLib::make_observer' are also subjected to the cleanup.
    4894+ To make the changes in the current revision neat, the changes are planned in future.
    48824895
    48834896 ////
    48844897
    Show on old repository browser