• R/O
  • SSH

YSLib: Commit

The YSLib project - main repository


Commit MetaInfo

Revision2d5fea7ba0cd0fac01231c4782660cbf25d6f093 (tree)
Time2021-01-30 15:55:15
AuthorFrankHB <frankhb1989@gmai...>
CommiterFrankHB

Log Message

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

Change Summary

Incremental Difference

diff -r 6ad22b72cee3 -r 2d5fea7ba0cd Tools/Scripts/SHBuild-YSLib-common.txt
--- a/Tools/Scripts/SHBuild-YSLib-common.txt Sat Jan 23 17:00:30 2021 +0800
+++ b/Tools/Scripts/SHBuild-YSLib-common.txt Sat Jan 30 14:55:15 2021 +0800
@@ -8,24 +8,28 @@
88 " or dangerous to environments except 'move!', 'assign!' and",
99 " 'lock-current-environment' are poisoned.";
1010 $provide! (assign%! assign@! copy-environment lock-environment
11- $defrec! $setrec! make-standard-environment)
11+ $defrec! $setrec! make-standard-environment derive-environment)
1212 (
1313 $import! std.strings string->symbol symbol->string;
1414
1515 $def! fns (unwrap list) move! assign%! assign@! copy-environment
1616 lock-environment $defrec! $setrec!;
17- $defl/e! raise-error (make-environment env_SHBuild_ std.strings) (&fn)
17+ $defl/e! raise-error (make-environment env_SHBuild_ std.strings) (&n)
1818 SHBuild_RaiseError_
19- (++ "ERROR: Use of unsafe function '" fn "' is not allowed.");
19+ (++ "ERROR: Use of unsafe function '" n "' is not allowed.");
2020 $defl! poison-fn (&fn &env)
21- eval (list $defl/e! fn (() make-standard-environment)
22- (string->symbol ".") raise-error (symbol->string fn)) env;
21+ eval (list $defl/e! (ensigil fn)
22+ (() make-standard-environment) (string->symbol ".") raise-error
23+ (symbol->string fn)) env;
2324 $defw! poison (fns) d for-each-ltr ($lambda (fn) poison-fn fn d) fns;
2425 poison fns;
2526 $def! nstd (() make-standard-environment);
26-
2727 eval (list poison (list $quote fns)) nstd;
28- $defl/e! make-standard-environment nstd () () lock-current-environment
28+ $defl/e! &make-standard-environment nstd () () lock-current-environment,
29+ $def! &derive-environment
30+ ($lambda/e nstd (&e) $lambda/e (() lock-current-environment) (.&envs)
31+ () ($lambda/e (append envs (list e)) ()
32+ () lock-current-environment)) (weaken-environment nstd)
2933 );
3034
3135 $def! $redef! $def!;
@@ -70,10 +74,10 @@
7074 $set! mods $assert $assert;
7175
7276 "TODO", "Use 'string?'.";
73- $defv/e! $assert-nonempty mods (&var) d
77+ $defv/e! &$assert-nonempty mods (&var) d
7478 eval (list $assert var ($lambda (str) not? (string-empty? str))
75- "be a string of nonempty value") d;
76- $defv/e! $assert-absolute-path mods (&var) d
79+ "be a string of nonempty value") d,
80+ $defv/e! &$assert-absolute-path mods (&var) d
7781 eval (list $assert var SHBuild_String_absolute_path?_
7882 "be a string of absolute path") d
7983 );
@@ -97,12 +101,12 @@
97101 ($lambda .));
98102
99103 "TODO", "Optimize with continuations.";
100- $defl/e! safeenv-get mods (name)
104+ $defl/e! &safeenv-get mods (name)
101105 $letrec ((sym string->symbol name) (denv () get-current-environment))
102106 $if (eval (list $binds1? emap sym) denv)
103107 (eval (list sym) emap)
104108 ($def! v env-get name; eval (list $set! emap sym v) denv; v),
105- $defl/e! safeenv-set mods (name val)
109+ $defl/e! &safeenv-set mods (name val)
106110 (
107111 $letrec ((sym string->symbol name) (denv () get-current-environment))
108112 $unless (eval (list $binds1? emap sym) denv)
@@ -110,14 +114,14 @@
110114 log-set name val;
111115 env-set name val
112116 ),
113- $defl/e! ss-verbose-puts mods (str) $if SS_Verbose (puts str)
117+ $defl/e! &ss-verbose-puts mods (str) $if SS_Verbose (puts str)
114118 );
115119 $provide! (safeenv-empty? safeenv-restore)
116120 (
117121 $def! mods derive-environment std.strings;
118122 $set! mods (safeenv-get safeenv-set) list safeenv-get safeenv-set;
119- $defl/e! safeenv-empty? mods (&n) string-empty? (safeenv-get n),
120- $defl/e! safeenv-restore mods (&n) safeenv-set n (safeenv-get n)
123+ $defl/e! &safeenv-empty? mods (&n) string-empty? (safeenv-get n),
124+ $defl/e! &safeenv-restore mods (&n) safeenv-set n (safeenv-get n)
121125 );
122126 $provide!
123127 (
@@ -129,12 +133,12 @@
129133 std.system env_SHBuild_;
130134 $set! mods safeenv-get safeenv-get;
131135
132- $defv/e! $lazy-env-val mods (&name .&body) d
136+ $defv/e! &$lazy-env-val mods (&name .&body) d
133137 $lazy/e (() lock-current-environment)
134138 $let ((t safeenv-get name)) $if (string-empty? t)
135- (eval (move! body) d) t;
136- $defv/e! $env-de! mods (&var .&body) d
137- $let ((t safeenv-get (symbol->string var)))
139+ (eval (move! body) d) t,
140+ $defv/e! &$env-de! mods (&var .&body) d
141+ $let ((t safeenv-get (symbol->string (desigil var))))
138142 eval (list $def! var
139143 ($if (string-empty? t)
140144 (list (unwrap eval) (move! body) d) t)) d;
@@ -154,9 +158,9 @@
154158 (#t "unknown");
155159
156160 "XXX", "'SHBuild_CheckUName_*' depend on the external command 'uname'";
157- $env-de! SHBuild_Env_OS ($set-system-var! SHBuild_Env_uname "uname";
161+ $env-de! &SHBuild_Env_OS ($set-system-var! SHBuild_Env_uname "uname";
158162 SHBuild_CheckUName_Case_ SHBuild_Env_uname),
159- $env-de! SHBuild_Env_Arch ($set-system-var! SHBuild_Env_uname_m "uname -m";
163+ $env-de! &SHBuild_Env_Arch ($set-system-var! SHBuild_Env_uname_m "uname -m";
160164 SHBuild_CheckUNameM_Case_ SHBuild_Env_uname_m);
161165 );
162166 $defl! SHBuild_GetPlatformStrings ()
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd YFramework/include/NPL/NPLA.h
--- a/YFramework/include/NPL/NPLA.h Sat Jan 23 17:00:30 2021 +0800
+++ b/YFramework/include/NPL/NPLA.h Sat Jan 30 14:55:15 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2014-2020 FrankHB.
2+ © 2014-2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file NPLA.h
1212 \ingroup NPL
1313 \brief NPLA 公共接口。
14-\version r8005
14+\version r8045
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 663
1717 \par 创建时间:
1818 2016-01-07 10:32:34 +0800
1919 \par 修改时间:
20- 2020-12-23 19:48 +0800
20+ 2021-01-27 18:14 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -947,7 +947,7 @@
947947
948948 若定义为 true ,则在 Environment 和 EnvironmentReference 启用引用计数检查支持。
949949 检查在 Environment 的析构函数进行,通过对锚对象剩余引用计数的来源计数判断正常状态。
950-若引用计数来源都是 Environment 、 EnvironmentReference 或 TermReference ,
950+若引用计数来源都是 Environment 、EnvironmentReference 或 TermReference ,
951951 则表示正常;否则,使用 YTraceDe 输出错误消息。
952952 注意绑定析构顺序不确定,可能导致依赖不确定而误报。
953953 因对性能有影响,默认仅调试配置下启用。
@@ -967,9 +967,11 @@
967967 //@{
968968 /*!
969969 \brief 父环境访问检查支持。
970+\sa ContextNode::DefaultResolve
970971 \sa Environment
971-
972-若定义为 true ,则在默认解析父环境时,检查环境引用是否存在。
972+\sa Environment::CheckParent
973+
974+若定义为 true ,则在默认解析和检查父环境时,检查环境引用是否存在。
973975 */
974976 #ifndef NPL_NPLA_CheckParentEnvironment
975977 # ifndef NDEBUG
@@ -1187,6 +1189,11 @@
11871189 !(bool(tags & TermTags::Unique) || bool(tags & TermTags::Temporary)))
11881190 //@}
11891191 /*!
1192+ \brief 判断被引用的对象是否指定临时值。
1193+ \since build 909
1194+ */
1195+ DefPred(const ynothrow, Temporary, bool(tags & TermTags::Temporary))
1196+ /*!
11901197 \brief 判断被引用的对象是否指定唯一。
11911198 \since build 856
11921199 */
@@ -1402,6 +1409,23 @@
14021409 */
14031410 YB_ATTR_nodiscard YF_API YB_PURE bool
14041411 IsUniqueTerm(const TermNode&);
1412+
1413+//! \since build 909
1414+//@{
1415+/*!
1416+\brief 判断项(的值数据成员)是否表示可修改的对象或可修改的引用值。
1417+\sa TermReference::IsModifiable
1418+*/
1419+YB_ATTR_nodiscard YF_API YB_PURE bool
1420+IsModifiableTerm(const TermNode&);
1421+
1422+/*!
1423+\brief 判断项(的值数据成员)是否表示临时对象或临时对象的引用值。
1424+\sa TermReference::IsTemporary
1425+*/
1426+YB_ATTR_nodiscard YF_API YB_PURE bool
1427+IsTemporaryTerm(const TermNode&);
1428+//@}
14051429 //@}
14061430
14071431 //! \since build 859
@@ -2251,6 +2275,7 @@
22512275 /*!
22522276 \brief 确保环境指针有效。
22532277 \exception std::invalid_argument 异常中立:由 ThrowForInvalidType 抛出。
2278+ \note 只检查互操作意义上的有效,即非空值。
22542279 \sa ThrowForInvalidType
22552280 \since build 872
22562281 */
@@ -2840,7 +2865,7 @@
28402865 }
28412866
28422867 /*!
2843- \brief 转移当第二参数指定的位置之前的当前动作序列的动作到第一参数。
2868+ \brief 转移第二参数指定的位置之前的当前动作序列的动作到第一参数。
28442869 \since build 895
28452870 */
28462871 PDefH(void, Shift, ReducerSequence& rs, ReducerSequence::const_iterator i)
@@ -3068,13 +3093,24 @@
30683093 YB_ATTR_nodiscard YF_API pair<shared_ptr<Environment>, bool>
30693094 ResolveEnvironment(const ValueObject&);
30703095 /*!
3096+\note 第二参数指定是否转移。
3097+\since build 909
3098+*/
3099+YB_ATTR_nodiscard YF_API pair<shared_ptr<Environment>, bool>
3100+ResolveEnvironment(ValueObject&, bool);
3101+/*!
30713102 \throw ListTypeError 参数是列表节点。
30723103 \note 当前使用和 TermToStringWithReferenceMark 相同的方式在异常消息中表示引用项。
30733104 \sa TermToStringWithReferenceMark
3074-\since build 840
30753105 */
3106+//@{
3107+//! \since build 840
30763108 YB_ATTR_nodiscard YF_API pair<shared_ptr<Environment>, bool>
30773109 ResolveEnvironment(const TermNode& term);
3110+//! \since build 909
3111+YB_ATTR_nodiscard YF_API pair<shared_ptr<Environment>, bool>
3112+ResolveEnvironment(TermNode& term);
3113+//@}
30783114 //@}
30793115
30803116
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd YFramework/include/NPL/NPLA1.h
--- a/YFramework/include/NPL/NPLA1.h Sat Jan 23 17:00:30 2021 +0800
+++ b/YFramework/include/NPL/NPLA1.h Sat Jan 30 14:55:15 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1.h
1212 \ingroup NPL
1313 \brief NPLA1 公共接口。
14-\version r8475
14+\version r8493
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 472
1717 \par 创建时间:
1818 2014-02-02 17:58:24 +0800
1919 \par 修改时间:
20- 2021-01-20 06:06 +0800
20+ 2021-01-28 22:40 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -295,6 +295,8 @@
295295 \brief NPLA1 表达式节点一次规约续延。
296296 \pre 规约函数第二参数引用的对象是 NPLA1 上下文状态或 public 继承的派生类。
297297 \pre 若修改规约函数实现,应和 DefaultReduceOnce 具有相同的求值语义。
298+ \pre 若可能在实现中调用续延,调用时应确保下一求值项被正确设置。
299+ \sa SetNextTermRef
298300 \since build 877
299301 */
300302 Continuation ReduceOnce{DefaultReduceOnce, *this};
@@ -1175,15 +1177,6 @@
11751177 ReduceCombinedBranch(TermNode&, ContextNode&);
11761178
11771179 /*!
1178-\brief 规约列表合并项:同 ReduceCombinedBranch ,但先设置 NPLA1 上下文的下一项。
1179-\pre 间接断言:项满足 IsCombiningTerm 。
1180-\since build 884
1181-*/
1182-YB_FLATTEN inline PDefH(ReductionStatus, ReduceNextCombinedBranch,
1183- TermNode& term, ContextState& cs)
1184- ImplRet(cs.SetNextTermRef(term), ReduceCombinedBranch(term, cs))
1185-
1186-/*!
11871180 \brief 规约列表合并项:同 ReduceCombined ,但使用第三参数指定的值。
11881181 \note 若第三参数不表示上下文处理器的宿主值,抛出的异常消息指定其为引用项。
11891182 \since build 883
@@ -1541,7 +1534,16 @@
15411534 \sa QueryContinuationName
15421535 \sa QuerySourceInformation
15431536 \sa QueryTailOperatorName
1537+\see $2021-01 @ %Documentation::Workflow.
15441538 \since build 903
1539+
1540+追踪第一参数指定的动作序列记录的 NPL 续延并清除其中的动作。
1541+追踪每一个动作以未指定的格式打印特定的文本。
1542+清除动作可具有副作用。
1543+以下约定的作用外的顺序未指定:
1544+追踪任意动作和清除任意动作之间非决定性有序;
1545+追踪动作先序清楚同一个动作;
1546+追踪的动作之间的顺序同 ContextNode::ReducerSequence::clear 清除项的顺序。
15451547 */
15461548 YF_API void
15471549 TraceBacktrace(ContextNode::ReducerSequence&, YSLib::Logger&);
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd YFramework/include/NPL/NPLA1Forms.h
--- a/YFramework/include/NPL/NPLA1Forms.h Sat Jan 23 17:00:30 2021 +0800
+++ b/YFramework/include/NPL/NPLA1Forms.h Sat Jan 30 14:55:15 2021 +0800
@@ -8,16 +8,16 @@
88 understand and accept it fully.
99 */
1010
11-/*! \file NPLA1.h
11+/*! \file NPLA1Forms.h
1212 \ingroup NPL
1313 \brief NPLA1 语法形式。
14-\version r7741
14+\version r7761
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2020-02-15 11:19:21 +0800
1919 \par 修改时间:
20- 2021-01-08 19:22 +0800
20+ 2021-01-25 01:05 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -1241,18 +1241,18 @@
12411241
12421242
12431243 /*!
1244+\return ReductionStatus::Regular 。
1245+\note 对参数指定的项进行检查,接受对象语言的一个参数。
12441246 \since build 859
1245-\return ReductionStatus::Regular 。
12461247 */
12471248 //@{
12481249 /*!
12491250 \brief 检查参数指定的项表示环境。
12501251 \exception TypeError 检查失败:参数指定的项不表示环境。
12511252 \exception ListTypeError 检查失败:参数指定的项表示列表。
1253+\sa ResolveEnvironment
12521254
1253-对参数指定的项进行检查。
1254-接受对象语言的一个参数。若这个参数不表示环境,抛出异常;
1255- 否则,对象语言中返回为参数指定的值。
1255+若接受的对象语言参数不表示环境,抛出异常;否则,对象语言中返回为参数指定的值。
12561256
12571257 参考调用文法:
12581258 <pre>check-environment \<object></pre>
@@ -1261,12 +1261,26 @@
12611261 CheckEnvironment(TermNode&);
12621262
12631263 /*!
1264+\brief 检查参数指定的项表示适合作为父环境的环境或环境列表。
1265+\exception TypeError 检查失败:参数指定的项不表示环境。
1266+\exception ListTypeError 检查失败:参数指定的项表示列表。
1267+\since build 909
1268+
1269+若接受的对象语言参数不表示适合作为父环境的环境或环境列表,抛出异常;
1270+ 否则,对象语言中返回为参数指定的值。
1271+
1272+参考调用文法:
1273+<pre>check-parent \<object></pre>
1274+*/
1275+YF_API ReductionStatus
1276+CheckParent(TermNode&);
1277+
1278+/*!
12641279 \brief 检查参数指定的项表示非空列表的引用。
12651280 \exception ListTypeError 检查失败:参数指定的项不表示非空列表。
12661281 \since build 857
12671282
1268-对参数指定的项进行检查。
1269-接受对象语言的一个参数。若这个参数不表示非空列表引用值,抛出异常;
1283+若接受的对象语言参数不表示非空列表引用值,抛出异常;
12701284 否则,对象语言中返回为参数指定的值。
12711285
12721286 参考调用文法:
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd YFramework/source/NPL/Dependency.cpp
--- a/YFramework/source/NPL/Dependency.cpp Sat Jan 23 17:00:30 2021 +0800
+++ b/YFramework/source/NPL/Dependency.cpp Sat Jan 30 14:55:15 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file Dependency.cpp
1212 \ingroup NPL
1313 \brief 依赖管理。
14-\version r3996
14+\version r4120
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 623
1717 \par 创建时间:
1818 2015-08-09 22:14:45 +0800
1919 \par 修改时间:
20- 2021-01-23 16:25 +0800
20+ 2021-01-27 01:33 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -28,16 +28,21 @@
2828 #include "NPL/YModules.h"
2929 #include YFM_NPL_Dependency // for set, string, UnescapeContext, string_view,
3030 // ystdex::isspace, std::istream, YSLib::unique_ptr, YSLib::share_move,
31-// A1::NameTypedReducerHandler, std::ref, RelaySwitched,
32-// ThrowNonmodifiableErrorForAssignee, ThrowValueCategoryError, TokenValue,
33-// ystdex::bind1, ValueObject, NPL::AllocateEnvironment,
34-// std::piecewise_construct, NPL::forward_as_tuple, LiftOther, Collapse,
35-// LiftOtherOrCopy, NPL::IsMovable, LiftTermOrCopy, ResolveTerm,
36-// LiftTermValueOrCopy, MoveResolved, ResolveIdentifier, ystdex::plus,
37-// std::placeholders, NPL::ResolveRegular, ystdex::tolower,
38-// FetchEnvironmentVariable, ystdex::swap_dependent, LiftTermRef, LiftTerm,
39-// NPL::Deref, YSLib::IO::StreamPut, YSLib::IO::omode_convb, YSLib::uremove,
40-// ystdex::throw_error;
31+// A1::NameTypedReducerHandler, std::ref, RelaySwitched, NPL::Deref,
32+// NPL::ResolveRegular, A1::ReduceOnce, ResolvedTermReferencePtr,
33+// Forms::CallResolvedUnary, NPL::AllocateEnvironment, function, ValueObject,
34+// EnvironmentReference, std::piecewise_construct, NPL::forward_as_tuple,
35+// LiftOther, ThrowNonmodifiableErrorForAssignee, ThrowValueCategoryError,
36+// ResolveTerm, TokenValue, IsEmpty, ComposeReferencedTermOp, IsBranch,
37+// IsReferenceTerm, IsBoundLValueTerm, IsUncollapsedTerm, IsUniqueTerm,
38+// IsModifiableTerm, IsTemporaryTerm, NPL::TryAccessLeaf, LiftTermRef,
39+// NPL::SetContentWith, Forms::CallRawUnary, LiftTerm, LiftOtherOrCopy,
40+// std::placeholders, LiftTermValueOrCopy, ystdex::bind1, MoveResolved,
41+// ResolveIdentifier, Collapse, NPL::IsMovable, LiftTermOrCopy, IsBranchedList,
42+// AccessFirstSubterm, ReferenceTerm, ThrowInsufficientTermsError,
43+// ystdex::plus, ystdex::tolower, FetchEnvironmentVariable,
44+// ystdex::swap_dependent, YSLib::IO::StreamPut, YSLib::IO::omode_convb,
45+// YSLib::uremove, ystdex::throw_error;
4146 #include YFM_NPL_NPLA1Forms // for NPL::Forms functions;
4247 #include YFM_YSLib_Service_FileSystem // for YSLib::IO::Path;
4348 #include <ystdex/iterator.hpp> // for std::istreambuf_iterator,
@@ -445,6 +450,8 @@
445450 RegisterUnary<>(ctx, "bound-lvalue?", IsBoundLValueTerm);
446451 RegisterUnary<>(ctx, "uncollapsed?", IsUncollapsedTerm);
447452 RegisterUnary<>(ctx, "unique?", IsUniqueTerm);
453+ RegisterUnary<>(ctx, "modifiable?", IsModifiableTerm);
454+ RegisterUnary<>(ctx, "temporary?", IsTemporaryTerm);
448455 RegisterStrict(ctx, "deshare", [](TermNode& term){
449456 return Forms::CallRawUnary([&](TermNode& tm){
450457 if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
@@ -599,9 +606,9 @@
599606 namespace Derived
600607 {
601608
602-//! \since build 855
609+//! \since build 909
603610 void
604-LoadGroundedDerived(REPLContext& context)
611+LoadBasicDerived(REPLContext& context)
605612 {
606613 auto& renv(context.Root.GetRecordRef());
607614
@@ -682,6 +689,7 @@
682689 RegisterStrict(renv, "set-first%!", SetFirstRef);
683690 RegisterStrict(renv, "equal?", EqualTermValue);
684691 RegisterStrict(renv, "check-environment", CheckEnvironment);
692+ RegisterStrict(renv, "check-parent", CheckParent);
685693 RegisterForm(renv, "$cond", Cond);
686694 RegisterForm(renv, "$when", When);
687695 RegisterForm(renv, "$unless", Unless);
@@ -693,24 +701,26 @@
693701 RegisterStrict(renv, "foldr1", FoldR1);
694702 RegisterStrict(renv, "map1", Map1);
695703 #else
704+ context.ShareCurrentSource("<root:basic-derived>");
705+ context.Perform(
696706 # if NPL_Impl_NPLA1_Native_EnvironmentPrimitives
697- context.Perform(R"NPL(
707+ R"NPL(
698708 $def! $vau $vau/e (() get-current-environment) (&formals &ef .&body) d
699709 eval (cons $vau/e (cons d (cons formals (cons ef (move! body))))) d;
700710 $def! $vau% $vau (&formals &ef .&body) d
701711 eval (cons $vau/e% (cons d (cons formals (cons ef (move! body)))))
702712 d;
703- )NPL");
713+ )NPL"
704714 # else
705- context.Perform(R"NPL(
715+ R"NPL(
706716 $def! get-current-environment (wrap ($vau () d d));
707717 $def! lock-current-environment (wrap ($vau () d lock-environment d));
708- )NPL");
718+ )NPL"
709719 # endif
710720 // XXX: The operative '$set!' is same to following derivations.
711- context.Perform(R"NPL(
721+ R"NPL(
712722 $def! $quote $vau (&x) #ignore x;
713- )NPL");
723+ )NPL"
714724 // NOTE: The function 'id' does not initialize new objects from the operand.
715725 // XXX: The implementation of 'id' relies on the fact that an object other
716726 // than a reference (i.e. represented by a prvalue) cannot have qualifiers
@@ -725,25 +735,27 @@
725735 // This is not the same in Kernel as it does not differentiate lvalues
726736 // (first-class referents) from prvalues and all terms can be accessed as
727737 // objects with arbitrary longer lifetime.
728- context.Perform(R"NPL(
738+ R"NPL(
729739 $def! id wrap ($vau% (%x) #ignore $if (bound-lvalue? x) x (move! x));
730740 $def! idv wrap $quote;
731741 $def! list wrap ($vau (.x) #ignore x);
732742 $def! list% wrap ($vau &x #ignore x);
733- )NPL");
743+ )NPL"
734744 # else
745+ );
735746 RegisterForm(renv, "$lambda", Lambda);
736747 RegisterForm(renv, "$lambda%", LambdaRef);
748+ context.ShareCurrentSource("<root:basic-derived-1>");
737749 context.Perform(R"NPL(
738750 $def! id $lambda% (%x) $if (bound-lvalue? x) x (move! x);
739751 $def! idv $lambda (&x) x;
740752 $def! list $lambda (.x) x;
741753 $def! list% $lambda &x x;
742- )NPL");
754+ )NPL"
743755 # endif
744756 // XXX: The operative '$defv!' is same to following derivations in
745757 // %LoadCore.
746- context.Perform(R"NPL(
758+ R"NPL(
747759 $def! $deflazy! $vau (&definiend .&expr) d
748760 eval (list $def! definiend $quote expr) d;
749761 $def! $set! $vau (&e &formals .&expr) d
@@ -752,20 +764,20 @@
752764 eval (list $set! d $f $vau formals ef (move! body)) d;
753765 $defv! $setrec! (&e &formals .&expr) d
754766 eval (list $defrec! formals (unwrap eval%) expr d) (eval e d);
755- )NPL");
767+ )NPL"
756768 # if NPL_Impl_NPLA1_Use_Id_Vau
757- context.Perform(R"NPL(
769+ R"NPL(
758770 $defv! $lambda (&formals .&body) d wrap
759771 (eval (cons $vau (cons formals (cons ignore (move! body)))) d);
760772 $defv! $lambda% (&formals .&body) d wrap
761773 (eval (cons $vau% (cons formals (cons ignore (move! body)))) d);
762- )NPL");
774+ )NPL"
763775 # endif
764776 // XXX: The operatives '$defl!', '$defl%!', '$defw%!', and '$defv%!', as
765777 // well as the applicatives 'rest&' and 'rest%' are same to following
766778 // derivations in %LoadCore.
767779 // NOTE: Use of 'eqv?' is more efficient than '$if'.
768- context.Perform(R"NPL(
780+ R"NPL(
769781 $def! $sequence
770782 ($lambda (&se)
771783 ($lambda #ignore $vau/e% se &exprseq d
@@ -824,6 +836,8 @@
824836 ($if (equal? (first& x) (first& y)) (equal? (rest& x) (rest& y)) #f)
825837 (eqv? x y);
826838 $defl%! check-environment (&e)
839+ $sequence (eval% #ignore e) (forward! e);
840+ $defl%! check-parent (&e)
827841 $sequence ($vau/e% e . #ignore) (forward! e);
828842 $defv! $defv%! (&$f &formals &ef .&body) d
829843 eval (list $set! d $f $vau% formals ef (move! body)) d;
@@ -867,11 +881,47 @@
867881 #endif
868882 }
869883
884+//! \since build 909
885+void
886+LoadStandardDerived(REPLContext& context)
887+{
888+#if NPL_Impl_NPLA1_Native_Forms
889+ auto& renv(context.Root.GetRecordRef());
890+
891+ RegisterUnary<Strict, const TokenValue>(renv, "ensigil",
892+ [](TokenValue s) -> TokenValue{
893+ if(!s.empty() && s.front() != '&')
894+ {
895+ if(s.front() != '%')
896+ return '&' + s;
897+ s.front() = '&';
898+ }
899+ return s;
900+ });
901+#else
902+ // XXX: %ensigil depends on %std.strings but not some core functions, to
903+ // avoid cyclic dependencies.
904+ context.ShareCurrentSource("<root:standard-derived>");
905+ context.Perform(R"NPL(
906+ $def! ensigil $lambda (&s)
907+ $let/e (derive-current-environment std.strings)
908+ ()
909+ $let ((&str symbol->string s))
910+ $if (string-empty? str) s
911+ (string->symbol (++ "&" (symbol->string (desigil s))));
912+ )NPL");
913+#endif
914+}
915+
870916 //! \since build 839
871917 //@{
872918 void
873919 LoadCore(REPLContext& context)
874920 {
921+ // XXX: Call multiple %context.Perform in different places. Different to
922+ // %LoadBasicDerived, this way is a slightly more efficient whether
923+ // %NPL_Impl_NPLA1_Native_Forms is set.
924+ context.ShareCurrentSource("<root:core>");
875925 context.Perform(R"NPL(
876926 $def! $defv! $vau (&$f &formals &ef .&body) d
877927 eval (list $set! d $f $vau formals ef (move! body)) d;
@@ -903,26 +953,31 @@
903953 eval (list $set! d f $lambda/e e formals (move! body)) d;
904954 $defv! $defl/e%! (&f &e &formals .&body) d
905955 eval (list $set! d f $lambda/e% e formals (move! body)) d;
906- $defl! restv ((#ignore .x)) x;
956+ $defl! restv ((#ignore .x)) move! x;
907957 $defl! rest& (&l) ($lambda ((#ignore .&x)) x) (check-list-reference l);
908- $defl! rest% ((#ignore .%x)) x;
958+ $defl! rest% ((#ignore .%x)) move! x;
909959 )NPL");
960+ // XXX: Keep %ContextNode::Perform calls here. This does not benefit from
961+ // the removal of the calls (tested with G++ 10.2 in x86_64-pc-linux),
962+ // whether %NPL_Impl_NPLA1_Native_Forms is set. However, the code below for
963+ // 'derive-environment' is not the same.
964+ context.Perform(
910965 #if NPL_Impl_NPLA1_Use_LockEnvironment
911- context.Perform(R"NPL(
966+ R"NPL(
912967 $defl! make-standard-environment () () lock-current-environment;
913- )NPL");
968+ )NPL"
914969 #else
915970 // XXX: Ground environment is passed by 'ce'.
916- context.Perform(R"NPL(
971+ R"NPL(
917972 $def! make-standard-environment
918973 ($lambda (&se &e)
919974 ($lambda #ignore $lambda/e se () make-environment ce)
920975 ($set! se ce e))
921976 (make-environment (() get-current-environment))
922977 (() get-current-environment);
923- )NPL");
978+ )NPL"
924979 #endif
925- context.Perform(R"NPL(
980+ R"NPL(
926981 $def! (box% box? unbox) () make-encapsulation-type;
927982 $defl! box (&x) box% x;
928983 $defl! first-null? (&l) null? (first l);
@@ -934,6 +989,26 @@
934989 (#t assv (forward! x) (rest% alist));
935990 $defw! derive-current-environment (.&envs) d
936991 apply make-environment (append envs (list d)) d;
992+ )NPL"
993+#if NPL_Impl_NPLA1_Use_LockEnvironment
994+# if true
995+ R"NPL(
996+ $def! derive-environment ()
997+ ($vau () d $lambda/e (() lock-current-environment) (.&envs)
998+ () ($lambda/e (append envs (list d)) ()
999+ () lock-current-environment));
1000+ )NPL"
1001+# else
1002+ // XXX: This is also correct, but less efficient.
1003+ R"NPL(
1004+ $def! derive-environment ()
1005+ ($vau () d eval (list $lambda/e (() lock-current-environment)
1006+ ((unwrap list) .&envs) () (list $lambda/e ((unwrap list) append
1007+ envs (list d)) () () lock-current-environment)) d);
1008+ )NPL"
1009+# endif
1010+#else
1011+ R"NPL(
9371012 $def! derive-environment
9381013 ($lambda (&se &e)
9391014 ($lambda #ignore
@@ -942,6 +1017,9 @@
9421017 ($set! se ce e))
9431018 (make-environment (() get-current-environment))
9441019 (() get-current-environment);
1020+ )NPL"
1021+#endif
1022+ R"NPL(
9451023 $defv! $as-environment (.&body) d
9461024 eval (list $let () (list $sequence (move! body)
9471025 (list () lock-current-environment))) d;
@@ -980,7 +1058,7 @@
9801058 $defv! $bindings->environment (.&bindings) d
9811059 eval (list* $bindings/p->environment () bindings) d;
9821060 $defl! symbols->imports (&symbols)
983- list* () list
1061+ list* () list%
9841062 (map1 ($lambda (&s) list forward! (desigil s)) symbols);
9851063 $defv! $provide/let! (&symbols &bindings .&body) d
9861064 $sequence (eval% (list $def! symbols (list $let bindings $sequence
@@ -991,6 +1069,9 @@
9911069 eval (list* $provide/let! (forward! symbols) () (move! body)) d;
9921070 $defv! $import! (&e .&symbols) d
9931071 eval% (list $set! d symbols (symbols->imports symbols)) (eval e d);
1072+ $defv! $import&! (&e .&symbols) d
1073+ eval% (list $set! d (map1 ensigil symbols)
1074+ (symbols->imports symbols)) (eval e d);
9941075 $defl! nonfoldable? (&l)
9951076 $if (null? l) #f ($if (first-null? l) #t (nonfoldable? (rest& l)));
9961077 $defl%! list-extract (&l &extr)
@@ -1011,7 +1092,8 @@
10111092 void
10121093 Load(REPLContext& context)
10131094 {
1014- LoadGroundedDerived(context);
1095+ LoadBasicDerived(context);
1096+ LoadStandardDerived(context);
10151097 LoadCore(context);
10161098 }
10171099 //@}
@@ -1056,6 +1138,7 @@
10561138 return bool(ResolveName(ctx, id).first);
10571139 });
10581140 });
1141+ context.ShareCurrentSource("<lib:std.environments>");
10591142 context.Perform(R"NPL(
10601143 $defv/e! $binds1? (derive-current-environment std.strings) (&e &s) d
10611144 eval (list (unwrap bound?) (symbol->string s)) (eval e d);
@@ -1075,6 +1158,7 @@
10751158 {
10761159 // NOTE: Call of 'set-first%!' does not check cyclic references. This is
10771160 // kept safe since it can occur only with NPLA1 undefined behavior.
1161+ context.ShareCurrentSource("<lib:std.promises>");
10781162 context.Perform(R"NPL(
10791163 $provide/let! (promise? memoize $lazy $lazy/e force)
10801164 ((mods $as-environment (
@@ -1095,15 +1179,16 @@
10951179 )
10961180 )))
10971181 (
1098- $import! mods promise?;
1099- $defl/e%! memoize mods (&x)
1182+ $import! mods &promise?;
1183+
1184+ $defl/e%! &memoize mods (&x)
11001185 encapsulate% (list (list% (forward! x) ())),
1101- $defv/e%! $lazy mods (.&body) d
1186+ $defv/e%! &$lazy mods (.&body) d
11021187 encapsulate% (list (list (move! body) d)),
1103- $defv/e%! $lazy/e mods (&e .&body) d
1188+ $defv/e%! &$lazy/e mods (&e .&body) d
11041189 encapsulate%
1105- (list (list (move! body) (check-environment (eval e d)))),
1106- $defl/e%! force mods (&x)
1190+ (list (list (move! body) (check-parent (eval e d)))),
1191+ $defl/e%! &force mods (&x)
11071192 $if (promise? x) (force-promise (decapsulate x)) (forward! x)
11081193 );
11091194 )NPL");
@@ -1242,6 +1327,7 @@
12421327 [&](const string& var, const string& val){
12431328 SetEnvironmentVariable(var.c_str(), val.c_str());
12441329 });
1330+ context.ShareCurrentSource("<lib:std.system>");
12451331 context.Perform(R"NPL(
12461332 $defl/e! env-empty? (derive-current-environment std.strings) (&n)
12471333 string-empty? (env-get n);
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd YFramework/source/NPL/NPLA.cpp
--- a/YFramework/source/NPL/NPLA.cpp Sat Jan 23 17:00:30 2021 +0800
+++ b/YFramework/source/NPL/NPLA.cpp Sat Jan 30 14:55:15 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA.cpp
1212 \ingroup NPL
1313 \brief NPLA 公共接口。
14-\version r3428
14+\version r3477
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 663
1717 \par 创建时间:
1818 2016-01-07 10:32:45 +0800
1919 \par 修改时间:
20- 2021-01-11 06:28 +0800
20+ 2021-01-25 22:33 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -682,6 +682,22 @@
682682 NPL::TryAccessLeaf<const TermReference>(term), true);
683683 }
684684
685+bool
686+IsModifiableTerm(const TermNode& term)
687+{
688+ return ystdex::invoke_value_or(&TermReference::IsModifiable,
689+ NPL::TryAccessLeaf<const TermReference>(term),
690+ !bool(term.Tags & TermTags::Nonmodifying));
691+}
692+
693+bool
694+IsTemporaryTerm(const TermNode& term)
695+{
696+ return ystdex::invoke_value_or(&TermReference::IsTemporary,
697+ NPL::TryAccessLeaf<const TermReference>(term),
698+ bool(term.Tags & TermTags::Temporary));
699+}
700+
685701
686702 bool
687703 CheckReducible(ReductionStatus status)
@@ -943,6 +959,18 @@
943959 && tp != ystdex::type_id<EnvironmentReference>()
944960 && tp != ystdex::type_id<shared_ptr<Environment>>()))
945961 ThrowForInvalidType(tp);
962+#if NPL_NPLA_CheckParentEnvironment
963+ if(tp == ystdex::type_id<observer_ptr<const Environment>>())
964+ {
965+ if(YB_UNLIKELY(!vo.GetObject<observer_ptr<const Environment>>()))
966+ // NOTE: See %EnsureValid.
967+ ThrowForInvalidValue();
968+ }
969+ else if(tp == ystdex::type_id<EnvironmentReference>())
970+ EnsureValid(vo.GetObject<EnvironmentReference>().Lock());
971+ else if(tp == ystdex::type_id<shared_ptr<Environment>>())
972+ EnsureValid(vo.GetObject<shared_ptr<Environment>>());
973+#endif
946974 }
947975
948976 bool
@@ -978,7 +1006,7 @@
9781006 {
9791007 if(p_env)
9801008 return *p_env;
981- Environment::ThrowForInvalidValue();
1009+ ThrowForInvalidValue();
9821010 }
9831011
9841012 AnchorPtr
@@ -1254,6 +1282,17 @@
12541282 Environment::ThrowForInvalidType(vo.type());
12551283 }
12561284 pair<shared_ptr<Environment>, bool>
1285+ResolveEnvironment(ValueObject& vo, bool move)
1286+{
1287+ // XXX: Ditto.
1288+ if(const auto p = vo.AccessPtr<const EnvironmentReference>())
1289+ return {p->Lock(), {}};
1290+ if(const auto p = vo.AccessPtr<shared_ptr<Environment>>())
1291+ return {move ? std::move(*p) : *p, true};
1292+ // TODO: Ditto.
1293+ Environment::ThrowForInvalidType(vo.type());
1294+}
1295+pair<shared_ptr<Environment>, bool>
12571296 ResolveEnvironment(const TermNode& term)
12581297 {
12591298 return ResolveTerm([&](const TermNode& nd, bool has_ref){
@@ -1264,6 +1303,17 @@
12641303 TermToStringWithReferenceMark(nd, has_ref).c_str()));
12651304 }, term);
12661305 }
1306+pair<shared_ptr<Environment>, bool>
1307+ResolveEnvironment(TermNode& term)
1308+{
1309+ return ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
1310+ if(!IsExtendedList(nd))
1311+ return ResolveEnvironment(nd.Value, NPL::IsMovable(p_ref));
1312+ throw ListTypeError(
1313+ ystdex::sfmt("Invalid environment formed from list '%s' found.",
1314+ TermToStringWithReferenceMark(nd, p_ref).c_str()));
1315+ }, term);
1316+}
12671317
12681318
12691319 void
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd YFramework/source/NPL/NPLA1.cpp
--- a/YFramework/source/NPL/NPLA1.cpp Sat Jan 23 17:00:30 2021 +0800
+++ b/YFramework/source/NPL/NPLA1.cpp Sat Jan 30 14:55:15 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1.cpp
1212 \ingroup NPL
1313 \brief NPLA1 公共接口。
14-\version r20247
14+\version r20275
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 473
1717 \par 创建时间:
1818 2014-02-02 18:02:47 +0800
1919 \par 修改时间:
20- 2021-01-21 06:41 +0800
20+ 2021-01-30 13:47 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -117,7 +117,14 @@
117117 const auto& f(first->second);
118118
119119 ++first;
120- SetupNextTerm(ctx, term);
120+ // XXX: By convention, no %SetupNextTerm call is needed here. Any
121+ // necessary next term setup is in the concrete action handler.
122+ // This avoids redundant calls if the action actually does know the
123+ // current term in from the argument is correct (e.g. the 1st
124+ // action initialized by the call of
125+ // %ContextState::DefaultReduceOnce) or all previous actions are
126+ // known not to change the next term in the context. See
127+ // %SetupDefaultInterpretation for example.
121128 RelaySwitched(ctx, PushedAction{first, last, f, term, ctx});
122129 }
123130 }
@@ -245,6 +252,9 @@
245252 ContextNode& ctx)
246253 {
247254 #if NPL_Impl_NPLA1_Enable_Thunked
255+ // XXX: No %SetupNextTerm call is needed here because it should have been
256+ // called before entering %ContextState::DefaultReduceOnce.
257+ AssertNextTerm(ctx, term);
248258 // XXX: Be cautious with overflow risks in call of %ContextNode::ApplyTail
249259 // when TCO is not enabled.
250260 ctx.LastStatus = ReductionStatus::Neutral;
@@ -969,6 +979,10 @@
969979 ReductionStatus
970980 ReduceOnce(TermNode& term, ContextNode& ctx)
971981 {
982+ // NOTE: See $2021-01 @ %Documentation::Workflow.
983+#if NPL_Impl_NPLA1_Enable_Thunked
984+ SetupNextTerm(ctx, term);
985+#endif
972986 return A1::RelayDirect(ctx, ContextState::Access(ctx).ReduceOnce, term);
973987 }
974988
@@ -982,7 +996,8 @@
982996 term.Value = ValueToken::Unspecified;
983997 return ReductionStatus::Retained;
984998 # else
985- return A1::ReduceCurrentNext(term, ctx, Continuation(
999+ AssertNextTerm(ctx, term);
1000+ return A1::RelayCurrentNext(term, ctx, Continuation(
9861001 static_cast<ReductionStatus(&)(TermNode&, ContextNode&)>(
9871002 ReduceChildrenOrdered), ctx), A1::NameTypedReducerHandler([&]{
9881003 ReduceOrderedResult(term);
@@ -1156,12 +1171,15 @@
11561171 // NOTE: This implementes arguments evaluation in applicative order when
11571172 // %Wrapping is not zero.
11581173 #if NPL_Impl_NPLA1_Enable_Thunked
1174+ // XXX: No %SetupNextTerm call is needed because it should have been called
1175+ // in %CombinerReturnThunk.
1176+ AssertNextTerm(ctx, term);
11591177 // NOTE: Optimize for cases with no argument.
11601178 if(n == 0 || term.size() <= 1)
11611179 // XXX: Assume the term has been setup by the caller.
11621180 return RelayCurrentOrDirect(ctx, Continuation(std::ref(Handler), ctx),
11631181 term);
1164- return A1::ReduceCurrentNext(term, ctx,
1182+ return A1::RelayCurrentNext(term, ctx,
11651183 Continuation([&](TermNode& t, ContextNode& c){
11661184 YAssert(!t.empty(), "Invalid term found.");
11671185 ReduceChildrenOrderedAsyncUnchecked(std::next(t.begin()), t.end(), c);
@@ -1326,11 +1344,10 @@
13261344 {
13271345 YAssert(IsCombiningTerm(term), "Invalid term found for combined term.");
13281346
1329- SetupNextTerm(ctx, term);
1330-
13311347 auto& fm(AccessFirstSubterm(term));
13321348 const auto p_ref_fm(NPL::TryAccessLeaf<const TermReference>(fm));
13331349
1350+ // XXX: %SetupNextTerm is to be called in %CombinerReturnThunk.
13341351 // NOTE: The tag is intended to be consumed by %VauHandler in %NPLA1Forms.
13351352 // As the irregular representation has a handler of %RefContextHandler,
13361353 // the tag is consumed only by the underlying handler, so the irregular
@@ -1409,7 +1426,7 @@
14091426 ReductionStatus
14101427 ReduceCombinedReferent(TermNode& term, ContextNode& ctx, const TermNode& fm)
14111428 {
1412- SetupNextTerm(ctx, term);
1429+ // XXX: %SetupNextTerm is to be called in %CombinerReturnThunk.
14131430 term.Tags &= ~TermTags::Temporary;
14141431 if(const auto p_handler = NPL::TryAccessLeaf<const ContextHandler>(fm))
14151432 return CombinerReturnThunk(*p_handler, term, ctx);
@@ -1442,8 +1459,9 @@
14421459 bool no_lift, Continuation next)
14431460 {
14441461 // XXX: For thunked code, %next shall be a continuation before being
1445- // captured and it is not capturable here. No %SetupNextTerm needs to be
1446- // called in the caller.
1462+ // captured and it is not capturable here.
1463+ // XXX: No %SetupNextTerm call is needed because it should have been called
1464+ // in the caller.
14471465 return RelayForEvalOrDirect(ctx, term, std::move(gd), no_lift,
14481466 std::move(next));
14491467 }
@@ -1454,6 +1472,8 @@
14541472 {
14551473 // NOTE: With TCO, the operand temporary is been indicated by
14561474 // %TermTags::Temporary, no lifetime extension needs to be cared here.
1475+ // XXX: No %SetupNextTerm call is needed because it should have been called
1476+ // in the caller.
14571477 return RelayForEvalOrDirect(ctx, term, std::move(gd), no_lift,
14581478 std::ref(ContextState::Access(ctx).ReduceOnce));
14591479 }
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd YFramework/source/NPL/NPLA1Forms.cpp
--- a/YFramework/source/NPL/NPLA1Forms.cpp Sat Jan 23 17:00:30 2021 +0800
+++ b/YFramework/source/NPL/NPLA1Forms.cpp Sat Jan 30 14:55:15 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Forms.cpp
1212 \ingroup NPL
1313 \brief NPLA1 语法形式。
14-\version r19731
14+\version r19959
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2014-02-15 11:19:51 +0800
1919 \par 修改时间:
20- 2021-01-23 15:43 +0800
20+ 2021-01-27 13:30 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -30,15 +30,15 @@
3030 // NPL::IsMovable, function, NPL::TryAccessReferencedTerm, ystdex::value_or,
3131 // ThrowInsufficientTermsError, NPL::Deref, A1::NameTypedReducerHandler,
3232 // ReduceReturnUnspecified, RemoveHead, IsBranch, AccessFirstSubterm,
33-// ReduceNextCombinedBranch, std::placeholders, ystdex::as_const, IsLeaf,
34-// ystdex::ref_eq, RelaySwitched, ContextHandler, shared_ptr, string,
33+// ReduceSubsequent, ReduceCombinedBranch, std::placeholders, ystdex::as_const,
34+// IsLeaf, ystdex::ref_eq, RelaySwitched, ContextHandler, shared_ptr, string,
3535 // unordered_map, Environment, lref, list, IsBranchedList, TokenValue,
3636 // NPL::TryAccessLeaf, ValueObject, weak_ptr, any_ops::use_holder,
3737 // in_place_type, ystdex::type_id, YSLib::allocate_shared, InvalidReference,
3838 // MoveFirstSubterm, ShareMoveTerm, ThrowInvalidSyntaxError,
39-// ReduceCombinedBranch, ResolvedTermReferencePtr, LiftOtherOrCopy,
40-// ResolveTerm, ystdex::equality_comparable, std::allocator_arg,
41-// NPL::AsTermNode, ystdex::exchange, NPL::SwitchToFreshEnvironment, TermTags,
39+// ResolvedTermReferencePtr, LiftOtherOrCopy, ResolveTerm,
40+// ystdex::equality_comparable, std::allocator_arg, NPL::AsTermNode,
41+// ystdex::exchange, NPL::SwitchToFreshEnvironment, TermTags,
4242 // ystdex::expand_proxy, NPL::AccessRegular, TermReference, GetLValueTagsOf,
4343 // RegularizeTerm, ThrowValueCategoryError, ThrowListTypeErrorForNonlist,
4444 // ystdex::update_thunk, NPL::TryAccessReferencedLeaf, ystdex::invoke_value_or,
@@ -172,7 +172,7 @@
172172 if(ExtractBool(NPL::Deref(i)))
173173 {
174174 term.Remove(i);
175- return ReduceNextCombinedBranch(term, ContextState::Access(ctx));
175+ return ReduceCombinedBranch(term, ctx);
176176 }
177177 term.Value = false;
178178 return ReductionStatus::Clean;
@@ -186,7 +186,7 @@
186186 if(!ExtractBool(tm))
187187 {
188188 term.Remove(i);
189- return ReduceNextCombinedBranch(term, ContextState::Access(ctx));
189+ return ReduceCombinedBranch(term, ctx);
190190 }
191191 LiftOther(term, tm);
192192 return ReductionStatus::Retained;
@@ -277,21 +277,22 @@
277277 yunseq(++first1, ++first2);
278278 // XXX: The continuations in the middle are not required to be
279279 // preserved.
280- RelaySwitched(ctx, [&, first1, first2, last1]{
280+ RelaySwitched(ctx,
281+ A1::NameTypedReducerHandler([&, first1, first2, last1]{
281282 // XXX: This is not effective if the result is known to be false.
282283 return r ? EqualSubterm(r, ctx, {}, first1, first2, last1)
283284 : ReductionStatus::Neutral;
284- });
285- return RelaySwitched(ctx, [&]{
285+ }, "equal-siblings"));
286+ return RelaySwitched(ctx, A1::NameTypedReducerHandler([&]{
286287 return
287288 EqualSubterm(r, ctx, {}, x.begin(), y.begin(), x.end());
288- });
289+ }, "equal-subterm"));
289290 }
290291 return orig ? ReductionStatus::Clean : ReductionStatus::Partial;
291292 }
292293 #else
293294 //! \since build 908
294-bool
295+YB_ATTR_nodiscard YB_PURE bool
295296 EqualSubterm(TNCIter first1, TNCIter first2, TNCIter last1)
296297 {
297298 if(first1 != last1)
@@ -614,6 +615,14 @@
614615 return {};
615616 }
616617
618+//! \since build 909
619+YB_NORETURN void
620+ThrowInvalidEnvironmentType(const TermNode& term, bool has_ref)
621+{
622+ throw TypeError(ystdex::sfmt("Invalid environment formed from object '%s'"
623+ " found.", TermToStringWithReferenceMark(term, has_ref).c_str()));
624+}
625+
617626
618627 //! \since build 898
619628 //@{
@@ -693,6 +702,8 @@
693702 ReductionStatus
694703 EvalImplUnchecked(TermNode& term, ContextNode& ctx, bool no_lift)
695704 {
705+ AssertNextTerm(ctx, term);
706+
696707 const auto i(std::next(term.begin()));
697708 auto p_env(ResolveEnvironment(NPL::Deref(std::next(i))).first);
698709
@@ -728,6 +739,36 @@
728739 //@}
729740
730741
742+//! \since build 909
743+YB_ATTR_nodiscard ValueObject
744+MakeEnvironmentParent(TNIter first, TNIter last,
745+ const TermNode::allocator_type& a, bool nonmodifying)
746+{
747+ const auto tr([&](TNIter iter){
748+ return ystdex::make_transform(iter, [&](TNIter i) -> ValueObject{
749+ // XXX: Like %LiftToReturn, but for %Value only.
750+ if(const auto p = NPL::TryAccessLeaf<const TermReference>(*i))
751+ {
752+ if(nonmodifying || !p->IsMovable())
753+ return p->get().Value;
754+ return std::move(p->get().Value);
755+ }
756+ return std::move(i->Value);
757+ });
758+ });
759+#if true
760+ // XXX: This is slightly more efficient.
761+ ValueObject parent;
762+
763+ parent.emplace<EnvironmentList>(tr(first), tr(last), a);
764+ return parent;
765+#else
766+ return ValueObject(std::allocator_arg, a, in_place_type<EnvironmentList>,
767+ tr(first), tr(last), a);
768+#endif
769+}
770+
771+
731772 //! \since build 897
732773 YB_ATTR_nodiscard YB_PURE inline
733774 PDefH(InvalidSyntax, MakeFunctionAbstractionError, ) ynothrow
@@ -750,26 +791,29 @@
750791 */
751792 shared_ptr<TermNode> p_formals;
752793 /*!
753- \brief 捕获静态环境作为父环境的引用,包含引入抽象时的静态环境。
794+ \brief 父环境。
795+ \note 包含引入抽象时的静态环境。
754796 \note 共享所有权用于检查循环引用。
755- \since build 823
797+ \since build 909
756798 */
757- EnvironmentReference parent;
758- /*!
759- \brief 可选保持所有权的静态环境指针。
760- \since build 861
761- */
762- mutable shared_ptr<Environment> p_static;
799+ mutable ValueObject parent;
763800 /*!
764801 \brief 求值结构。
765802 \since build 861
766803 */
767804 mutable shared_ptr<TermNode> p_eval_struct;
768805 /*!
769- \brief 调用指针。
770- \since build 847
806+ \brief 调用例程。
807+ \since build 909
771808 */
772- ReductionStatus(VauHandler::*p_call)(TermNode&, ContextNode&) const;
809+ ReductionStatus(&call)(const VauHandler&, TermNode&, ContextNode&);
810+#if NPL_Impl_NPLA1_Enable_TCO
811+ /*!
812+ \brief 保存环境例程。
813+ \since build 909
814+ */
815+ void(&save)(const VauHandler&, TCOAction&);
816+#endif
773817
774818 public:
775819 //! \brief 返回时不提升项以允许返回引用。
@@ -782,12 +826,32 @@
782826 VauHandler(string&& ename, shared_ptr<TermNode>&& p_fm,
783827 shared_ptr<Environment>&& p_env, bool owning, TermNode& term, bool nl)
784828 : eformal(std::move(ename)), p_formals((CheckParameterTree(Deref(p_fm)),
785- std::move(p_fm))), parent((Environment::EnsureValid(p_env), p_env)),
786- // XXX: Optimize with region inference?
787- p_static(owning ? std::move(p_env) : nullptr),
829+ // XXX: The parent check is not needed, since %p_env is an environment
830+ // checked before (by %ResolveEnvironment, etc.).
831+ std::move(p_fm))), parent(MakeParentSingle(p_env, owning)),
788832 p_eval_struct(ShareMoveTerm(ystdex::exchange(term,
789- NPL::AsTermNode(term.get_allocator())))), p_call(eformal.empty()
790- ? &VauHandler::CallStatic : &VauHandler::CallDynamic), NoLifting(nl)
833+ NPL::AsTermNode(term.get_allocator())))),
834+ call(eformal.empty() ? CallStatic : CallDynamic),
835+#if NPL_Impl_NPLA1_Enable_TCO
836+ save(owning ? SaveOwning : SaveNothing),
837+#endif
838+ NoLifting(nl)
839+ {}
840+ //! \since build 909
841+ VauHandler(int, string&& ename, shared_ptr<TermNode>&& p_fm,
842+ ValueObject&& vo, TermNode& term, bool nl)
843+ : eformal(std::move(ename)),
844+ p_formals((CheckParameterTree(Deref(p_fm)), std::move(p_fm))),
845+ // XXX: Refine the allocator in %vo?
846+ parent((Environment::CheckParent(vo), std::move(vo))),
847+ p_eval_struct(ShareMoveTerm(ystdex::exchange(term,
848+ NPL::AsTermNode(term.get_allocator())))),
849+ call(eformal.empty() ? CallStatic : CallDynamic),
850+#if NPL_Impl_NPLA1_Enable_TCO
851+ // TODO: Optimize?
852+ save(SaveList),
853+#endif
854+ NoLifting(nl)
791855 {}
792856
793857 //! \since build 824
@@ -795,8 +859,7 @@
795859 operator==(const VauHandler& x, const VauHandler& y)
796860 {
797861 return x.eformal == y.eformal && x.p_formals == y.p_formals
798- && x.parent == y.parent && x.p_static == y.p_static
799- && x.NoLifting == y.NoLifting;
862+ && x.parent == y.parent && x.NoLifting == y.NoLifting;
800863 }
801864
802865 //! \since build 772
@@ -806,7 +869,7 @@
806869 if(IsBranchedList(term))
807870 {
808871 if(p_eval_struct)
809- return (this->*p_call)(term, ctx);
872+ return call(*this, term, ctx);
810873 // XXX: The call has been performed on the handler, see the notes in
811874 // %DoCall.
812875 throw NPLException("Invalid handler of call found.");
@@ -816,7 +879,6 @@
816879
817880 private:
818881 //! \since build 847
819- //@{
820882 void
821883 BindEnvironment(ContextNode& ctx, ValueObject&& vo) const
822884 {
@@ -828,8 +890,9 @@
828890 // is no need to treat as root.
829891 }
830892
831- ReductionStatus
832- CallDynamic(TermNode& term, ContextNode& ctx) const
893+ //! \since build 909
894+ static ReductionStatus
895+ CallDynamic(const VauHandler& vau, TermNode& term, ContextNode& ctx)
833896 {
834897 // NOTE: Evaluation in the local context: using the activation
835898 // record frame with outer scope bindings.
@@ -840,22 +903,23 @@
840903 // environments.
841904 EnvironmentGuard gd(ctx, NPL::SwitchToFreshEnvironment(ctx));
842905
843- BindEnvironment(ctx, std::move(wenv));
906+ vau.BindEnvironment(ctx, std::move(wenv));
844907 // XXX: Referencing escaped variables (now only parameters need to be
845908 // cared) form the context would cause undefined behavior (e.g.
846909 // returning a reference to automatic object in the host language). The
847910 // lifting of call result is enabled to prevent this, unless
848911 // %NoLifting is %true. See also %BindParameter.
849- return DoCall(term, ctx, gd);
912+ return vau.DoCall(term, ctx, gd);
850913 }
851914
852- ReductionStatus
853- CallStatic(TermNode& term, ContextNode& ctx) const
915+ //! \since build 909
916+ static ReductionStatus
917+ CallStatic(const VauHandler& vau, TermNode& term, ContextNode& ctx)
854918 {
855919 // NOTE: See above.
856920 EnvironmentGuard gd(ctx, NPL::SwitchToFreshEnvironment(ctx));
857921
858- return DoCall(term, ctx, gd);
922+ return vau.DoCall(term, ctx, gd);
859923 }
860924
861925 public:
@@ -876,6 +940,7 @@
876940 }
877941
878942 private:
943+ //! \since build 847
879944 ReductionStatus
880945 DoCall(TermNode& term, ContextNode& ctx, EnvironmentGuard& gd) const
881946 {
@@ -898,15 +963,15 @@
898963 BindParameter(ctx.GetRecordPtr(), NPL::Deref(p_formals), term);
899964 #if NPL_Impl_NPLA1_TraceVauCall
900965 ctx.Trace.Log(Debug, [&]{
901- return sfmt<string>("Function called, with %ld shared term(s), %ld"
902- " %s shared static environment(s), %zu parameter(s).",
903- p_eval_struct.use_count(), parent.GetPtr().use_count(),
904- p_static ? "owning" : "nonowning", p_formals->size());
966+ return sfmt<string>("Function called, with %ld shared term(s),"
967+ " %zu parameter(s).", p_eval_struct.use_count(),
968+ p_formals->size());
905969 });
906970 #endif
907971 // NOTE: The static environment is bound as the base of the local
908972 // environment by setting the parent environment pointer.
909973 ctx.GetRecordRef().Parent = parent;
974+ AssertNextTerm(ctx, term);
910975 #if NPL_Impl_NPLA1_Enable_TCO
911976 // XXX: Assume the last function is this object.
912977 // TODO: Avoid TCO when the static environment has something with side
@@ -915,13 +980,9 @@
915980 {
916981 TermNode eval_struct(std::move(Deref(p_eval_struct)));
917982 auto& act(RefTCOAction(ctx));
918-
919- if(p_static && p_static.use_count() == 1)
920- act.RecordList.emplace_front(ContextHandler(),
921- std::move(p_static));
922-
923983 const bool no_lifting(NoLifting);
924984
985+ save(*this, act);
925986 // XXX: This would make '*this' invalid.
926987 yunused(act.MoveFunction());
927988 // XXX: The evaluation structure does not need to be saved, since it
@@ -938,7 +999,47 @@
938999 #endif
9391000 return RelayForCall(ctx, term, std::move(gd), NoLifting);
9401001 }
941- //@}
1002+
1003+ //! \since build 909
1004+ YB_ATTR_nodiscard YB_PURE static ValueObject
1005+ MakeParentSingle(const shared_ptr<Environment>& p_env, bool owning)
1006+ {
1007+ // TODO: Use allocator?
1008+ Environment::EnsureValid(p_env);
1009+ if(owning)
1010+ return p_env;
1011+ return EnvironmentReference(p_env);
1012+ }
1013+
1014+#if NPL_Impl_NPLA1_Enable_TCO
1015+ static void
1016+ SaveNothing(const VauHandler&, TCOAction&)
1017+ {}
1018+
1019+ static void
1020+ SaveList(const VauHandler& vau, TCOAction& act)
1021+ {
1022+ for(auto& vo : vau.parent.GetObject<EnvironmentList>())
1023+ {
1024+ if(const auto p = vo.AccessPtr<shared_ptr<Environment>>())
1025+ SaveOwningPtr(*p, act);
1026+ }
1027+ }
1028+
1029+ static void
1030+ SaveOwning(const VauHandler& vau, TCOAction& act)
1031+ {
1032+ SaveOwningPtr(vau.parent.GetObject<shared_ptr<Environment>>(), act);
1033+ }
1034+
1035+ static void
1036+ SaveOwningPtr(shared_ptr<Environment>& p_static, TCOAction& act)
1037+ {
1038+ if(p_static.use_count() == 1)
1039+ act.RecordList.emplace_front(ContextHandler(),
1040+ std::move(p_static));
1041+ }
1042+#endif
9421043 };
9431044
9441045
@@ -1447,7 +1548,7 @@
14471548 }
14481549
14491550 //! \since build 842
1450-ContextHandler
1551+YB_ATTR_nodiscard ContextHandler
14511552 CreateVau(TermNode& term, bool no_lift, TNIter i,
14521553 shared_ptr<Environment>&& p_env, bool owning)
14531554 {
@@ -1459,6 +1560,19 @@
14591560 std::move(p_env), owning, term, no_lift));
14601561 }
14611562
1563+//! \since build 909
1564+YB_ATTR_nodiscard ContextHandler
1565+CreateVauWithParent(TermNode& term, bool no_lift, TNIter i,
1566+ ValueObject&& parent)
1567+{
1568+ auto formals(ShareMoveTerm(NPL::Deref(++i)));
1569+ auto eformal(CheckEnvFormal(NPL::Deref(++i)));
1570+
1571+ term.erase(term.begin(), ++i);
1572+ return FormContextHandler(VauHandler(0, std::move(eformal),
1573+ std::move(formals), std::move(parent), term, no_lift));
1574+}
1575+
14621576 ReductionStatus
14631577 VauImpl(TermNode& term, ContextNode& ctx, bool no_lift)
14641578 {
@@ -1481,11 +1595,28 @@
14811595 return ReduceSubsequent(tm, ctx,
14821596 A1::NameTypedReducerHandler([&, i, no_lift]{
14831597 term.Value = CheckFunctionCreation([&]{
1484- // XXX: List components are ignored.
1485- auto p_env_pr(ResolveEnvironment(tm));
1486-
1487- return CreateVau(term, no_lift, i, std::move(p_env_pr.first),
1488- p_env_pr.second);
1598+ return ResolveTerm([&](TermNode& nd,
1599+ ResolvedTermReferencePtr p_ref) -> ContextHandler{
1600+ if(!IsExtendedList(nd))
1601+ {
1602+ // NOTE: The environment check is used as the parent
1603+ // check when the parent is an environment.
1604+ auto p_env_pr(ResolveEnvironment(nd.Value,
1605+ NPL::IsMovable(p_ref)));
1606+
1607+ Environment::EnsureValid(p_env_pr.first);
1608+ return CreateVau(term, no_lift, i,
1609+ std::move(p_env_pr.first), p_env_pr.second);
1610+ }
1611+ if(IsList(nd))
1612+ // NOTE: The parent check is implied in the constructor
1613+ // of %VauHandler.
1614+ return CreateVauWithParent(term, no_lift, i,
1615+ MakeEnvironmentParent(nd.begin(),
1616+ nd.end(), nd.get_allocator(),
1617+ !NPL::IsMovable(p_ref)));
1618+ ThrowInvalidEnvironmentType(nd, p_ref);
1619+ }, tm);
14891620 });
14901621 return ReductionStatus::Clean;
14911622 }, "eval-vau"));
@@ -2192,10 +2323,12 @@
21922323 return ReductionStatus::Clean;
21932324 }
21942325 #if NPL_Impl_NPLA1_Enable_Thunked
2326+ yunused(ctx);
21952327 term.Value = true;
21962328 return EqualSubterm(term.Value.GetObject<bool>(), ctx, true, x.begin(),
21972329 y.begin(), x.end());
21982330 #else
2331+ yunused(ctx);
21992332 term.Value = EqualSubterm(x.begin(), y.begin(), x.end());
22002333 return ReductionStatus::Clean;
22012334 #endif
@@ -2511,35 +2644,10 @@
25112644
25122645 const auto a(term.get_allocator());
25132646
2514- if(term.size() > 1)
2515- {
2516- const auto tr([&](TNIter iter){
2517- return ystdex::make_transform(iter, [&](TNIter i) -> ValueObject{
2518- // XXX: Like %LiftToReturn, but for %Value only.
2519- if(const auto p = NPL::TryAccessLeaf<const TermReference>(*i))
2520- {
2521- if(!p->IsMovable())
2522- return p->get().Value;
2523- return std::move(p->get().Value);
2524- }
2525- return std::move(i->Value);
2526- });
2527- });
2528-#if true
2529- // XXX: This is slightly more efficient.
2530- ValueObject parent;
2531-
2532- parent.emplace<EnvironmentList>(tr(std::next(term.begin())),
2533- tr(term.end()), a);
2534- term.Value = NPL::AllocateEnvironment(a, std::move(parent));
2535-#else
2536- term.Value = NPL::AllocateEnvironment(a, ValueObject(std::allocator_arg,
2537- a, in_place_type<EnvironmentList>, tr(std::next(term.begin())),
2538- tr(term.end()), a));
2539-#endif
2540- }
2541- else
2542- term.Value = NPL::AllocateEnvironment(a);
2647+ // NOTE: The parent check is implied in the constructor of %Environment.
2648+ term.Value = term.size() > 1 ? NPL::AllocateEnvironment(a,
2649+ MakeEnvironmentParent(std::next(term.begin()), term.end(), a, {}))
2650+ : NPL::AllocateEnvironment(a);
25432651 }
25442652
25452653 void
@@ -2719,6 +2827,30 @@
27192827 }
27202828
27212829 ReductionStatus
2830+CheckParent(TermNode& term)
2831+{
2832+ RetainN(term);
2833+
2834+ auto& tm(*std::next(term.begin()));
2835+
2836+ CheckFunctionCreation([&]{
2837+ ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
2838+ if(!IsExtendedList(nd))
2839+ // XXX: The call of %as_const is needed to prevent modification.
2840+ Environment::EnsureValid(
2841+ ResolveEnvironment(ystdex::as_const(nd)).first);
2842+ else if(IsList(nd))
2843+ Environment::CheckParent(MakeEnvironmentParent(nd.begin(),
2844+ nd.end(), nd.get_allocator(), true));
2845+ else
2846+ ThrowInvalidEnvironmentType(nd, p_ref);
2847+ }, tm);
2848+ });
2849+ MoveRValueToReturn(term, tm);
2850+ return ReductionStatus::Regular;
2851+}
2852+
2853+ReductionStatus
27222854 CheckListReference(TermNode& term)
27232855 {
27242856 return CallResolvedUnary([&](TermNode& nd, bool has_ref){
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd YFramework/source/NPL/NPLA1Internals.h
--- a/YFramework/source/NPL/NPLA1Internals.h Sat Jan 23 17:00:30 2021 +0800
+++ b/YFramework/source/NPL/NPLA1Internals.h Sat Jan 30 14:55:15 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2017-2020 FrankHB.
2+ © 2017-2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Internals.h
1212 \ingroup NPL
1313 \brief NPLA1 内部接口。
14-\version r20213
14+\version r20236
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2020-02-15 13:20:08 +0800
1919 \par 修改时间:
20- 2020-10-06 21:22 +0800
20+ 2021-01-30 13:45 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 非公开模块名称:
@@ -220,8 +220,8 @@
220220 {
221221 // NOTE: This implies the call of %RegularizeTerm before lifting. Since
222222 // the call of %RegularizeTerm is idempotent without term modification
223- // before the next reduction of the term or some other term, there is
224- // no need to call %RegularizeTerm if the lift is not needed.
223+ // before the next reduction of term, there is no need to call
224+ // %RegularizeTerm if the lift is not needed.
225225 if(req_lift_result)
226226 {
227227 // NOTE: The call of %RegularizeTerm is for the previous reduction.
@@ -229,6 +229,11 @@
229229 RegularizeTerm(term, ctx.LastStatus);
230230 return ReduceForLiftedResult(term);
231231 }
232+ // NOTE: This is only needed on a real call from the evaluation is
233+ // reentered. Currently, other evaluations (e.g. for continuation are
234+ // all administrative) and expected not reentered with unbound number
235+ // of times when no lifting is required.
236+ // TODO: Prepare for invocation of first-class continuations?
232237 if(req_combined)
233238 RegularizeTerm(term, ctx.LastStatus);
234239 return ctx.LastStatus;
@@ -527,6 +532,19 @@
527532 #endif
528533
529534
535+//! \since build 909
536+inline void
537+AssertNextTerm(ContextNode& ctx, TermNode& term)
538+{
539+ yunused(ctx),
540+ yunused(term);
541+#if NPL_Impl_NPLA1_Enable_Thunked
542+ YAssert(ystdex::ref_eq<>()(term, ContextState::Access(
543+ ctx).GetNextTermRef()), "Invalid current term found.");
544+#endif
545+}
546+
547+
530548 //! \since build 879
531549 //@{
532550 #if NPL_Impl_NPLA1_Enable_Thunked && !NPL_Impl_NPLA1_Enable_InlineDirect
@@ -662,7 +680,6 @@
662680 // in direct calls instead of the setup next term, while they shall be
663681 // equivalent.
664682 #if NPL_Impl_NPLA1_Enable_TCO
665- SetupNextTerm(ctx, term);
666683 SetupTCOLift(PrepareTCOEvaluation(ctx, term, std::move(gd)), no_lift);
667684 return A1::RelayCurrentOrDirect(ctx, yforward(next), term);
668685 #elif NPL_Impl_NPLA1_Enable_Thunked
@@ -671,7 +688,7 @@
671688 auto act(MakeMoveGuard(gd));
672689
673690 if(no_lift)
674- return ReduceCurrentNext(term, ctx, yforward(next), std::move(act));
691+ return A1::RelayCurrentNext(term, ctx, yforward(next), std::move(act));
675692
676693 // XXX: Term reused. Call of %SetupNextTerm is not needed as the next
677694 // term is guaranteed not changed when %next is a continuation.
@@ -681,10 +698,9 @@
681698 }, "eval-lift-result"), ctx);
682699
683700 RelaySwitched(ctx, std::move(act));
684- return ReduceCurrentNext(term, ctx, yforward(next), std::move(cont));
701+ return A1::RelayCurrentNext(term, ctx, yforward(next), std::move(cont));
685702 #else
686703 yunused(gd);
687- SetupNextTerm(ctx, term);
688704
689705 const auto res(RelayDirect(ctx, next, term));
690706
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd doc/ChangeLog.V0.9.txt
--- a/doc/ChangeLog.V0.9.txt Sat Jan 23 17:00:30 2021 +0800
+++ b/doc/ChangeLog.V0.9.txt Sat Jan 30 14:55:15 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file ChangeLog.V0.9.txt
1212 \ingroup Documentation
1313 \brief 版本更新历史记录 - V0.9 。
14-\version r2129
14+\version r2324
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 800
1717 \par 创建时间:
1818 2020-10-12 17:19:23 +0800
1919 \par 修改时间:
20- 2021-01-23 16:59 +0800
20+ 2021-01-30 14:48 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -32,6 +32,202 @@
3232
3333 $now
3434 (
35+ / %YFramework.NPL $=
36+ (
37+ / %NPLA $=
38+ (
39+ / @ "class %Environment" $=
40+ (
41+ / DLDI "simplified function %EnsureValid",
42+ + "check to ensure nonnull parent environment pointer"
43+ @ "function %CheckParent"
44+ @ 'NPL_NPLA_CheckParentEnvironment',
45+ // As %EnsreValid.
46+ + "function %IsTemporary"
47+ ),
48+ + "function %IsTemporaryTerm"
49+ ^ $dep_from "%Environment::IsTemporary",
50+ + "function %IsModifiableTerm",
51+ / @ "functions %ResolveEnvironment" $=
52+ (
53+ + "overload with parameter of type 'ValueObject&' and \
54+ additional parameter to specify the move operation";
55+ + "overload with type 'TermNode&' to support environment move"
56+ )
57+ ),
58+ / @ "namespace %Forms" @ %NPLA1Forms $=
59+ (
60+ / @ 'NPL_Impl_NPLA1_Enable_Thunked' @ "function %EqualTermValue" $=
61+ (
62+ / DLDI "%EqualTermValue" @ 'NPL_Impl_NPLA1_Enable_Thunked',
63+ // To eliminate G++ warnings: [-Wunused], \
64+ [-Wsuggest-attribute=pure].
65+ + "reducer names"
66+ ),
67+ / DLDI "%MakeEnvironment",
68+ / "vau handler" $=
69+ (
70+ / DLI "dispatched call" ^ "reference" ~ "pointer to member",
71+ (
72+ (
73+ - "log information for parents" @ 'NPL_Impl_NPLA1_TraceVauCall',
74+ - DLDI "parent comparation" @ "friend %operator==",
75+ (
76+ / DLI "dispatched saving check on moving for owning static \
77+ environments" @ 'NPL_Impl_NPLA1_Enable_TCO',
78+ / DLI "parent pointer" -> "parent object";
79+ );
80+ - DLI "static parent pointer"
81+ // See $2021-01 @ %Documentation::Workflow.
82+ );
83+ + "constructor to support explicit parent object"
84+ $dep_to "direct vau parent"
85+ )
86+ ),
87+ / @ "functions %(VauWithEnvironment, VauWithEnvironmentRef)" $=
88+ (
89+ / "supported environment list as the vau parent"
90+ $dep_from ("%MakeEnvironment", "direct vau parent"),
91+ + "environment check" ^ "%Environment::EnsureValid",
92+ // This is more consistent to %CheckEnvironment.
93+ / "supported move the environment argument"
94+ ^ $dep_from ("%ResolveEnvironment with parameter of \
95+ 'ValueObject&'" @ %NPLA)
96+ ),
97+ + "function %CheckParent",
98+ // The behavior is more consistent to the combiner creation \
99+ now (e.g. with nested exception thrown).
100+ / $comp DLI "supported move the environment argument"
101+ @ "functions %(SetWithNoRecursion, SetWithRecursion, Eval, \
102+ EvalRef, EvalString, EvalStringRef, Apply)"
103+ $dep_from ("%ResolveEnvironment" @ %NPLA)
104+ ),
105+ (
106+ / DLI "all calls to %ReduceNextCombinedBranch"
107+ -> "calls to %ReduceCombinedBranch"
108+ $effective @ ("functions %(And, Or)" @ %NPLA1Forms);
109+ // Setting the next term is redundant due to the change to \
110+ %ReduceCombinedBranch since b898.
111+ - $revert(b882) "function %ReduceNextCombinedBranch" @ %NPLA1
112+ ),
113+ (
114+ + "function %AssertNextTerm" @ %NPLA1Internals;
115+ + "assertion to ensure no %SetupNextTerm call is needed for NPLA1 \
116+ reduction functions" $effective @ (("member functions \
117+ %(ContextState::DefaultReduceOnce, FormContextHandler::operator())"
118+ 'NPL_Impl_NPLA1_Thunked && !NPL_Impl_NPLA1_Enable_TCO'
119+ @ "function %ReduceOrdered") @ %NPLA1,
120+ ("functions %Forms::(Eval, EvalRef, EvalString, \
121+ EvalStringRef)", "%operator()" @ "vau handler") @ %NPLA1Forms)
122+ ^ ("%AssertNextTerm" @ %NPLA1Internals)
123+ ),
124+ / $dev %NPLA1 $=
125+ (
126+ (
127+ / DLDI "setup next term" @ 'NPL_Impl_NPLA1_Enable_Thunked'
128+ @ "function %ReduceOnce",
129+ // See $2021-01 @ %Documentation::Workflow.
130+ + DD "'\pre' command to ensure proper next term set"
131+ @ "Doxygen comment" @ "member object %ContextState::ReduceOnce";
132+ - DLI "redundant %SetupNextTerm call" @ "functions \
133+ %(ContextState::DefaultReduceOnce, ReduceCombinedBranch, \
134+ ReduceCombinedReferent, FormContextHandler::operator())"
135+ @ 'NPL_Impl_NPLA1_Enable_Thunked'
136+ // This is redundat due to change to the reducing functions \
137+ used in %SetupDefaultInterpretation (including \
138+ %ReduceCombinedBranch) for since b898.
139+ ),
140+ - DLI "simplified to avoid redundant %SetupNextTerm call"
141+ @ "functions %(RelayForCall, RelayForEval)",
142+ / DLI "simplified" @ 'NPL_Impl_NPLA1_Enable_Thunked'
143+ @ "member function %FormContextHandler::operator()"
144+ ^ "%A1::RelayCurrentNext" ~ "%A1::ReduceCurrentNext"
145+ / DLI "simplified"
146+ @ 'NPL_Impl_NPLA1_Enable_Thunked && !NPL_Impl_NPLA1_Enable_TCO'
147+ @ "function %ReduceOrdered"
148+ ^ "%A1::RelayCurrentNext" ~ "%A1::ReduceCurrentNext",
149+ / "support destroying temporary objects on exception"
150+ @ "functions %(ReduceCombinedBranch, ReduceCombinedReferent)"
151+ $dep_from ("TCO term cleanup" @ %NPLA1Interals)
152+ ),
153+ / %Dependency $=
154+ (
155+ / $comp "supported parent environment lists" @ "functions with \
156+ '/e' in the name" $dep_from
157+ ("%(VauWithEnvironment, VauWithEnvironmentRef)" @ %NPLA1Forms)
158+ $dep_to "parent environment lists support",
159+ / @ "function %LoadGroundContext" $=
160+ (
161+ + "applicative %ensigil",
162+ * "missing preserving reference on generated initializers"
163+ @ "applicative 'symbols->ipmorts'" $since b908
164+ $= (/ $impl "combining" ^ 'list' ~ 'list%');
165+ (
166+ * $comp "missing preserving reference on initializers"
167+ @ "operatives (('$provide/let!'; '$provide!'), \
168+ '$import!')" $since b908,
169+ // The bug would make it impossible to bind \
170+ nonmodifying references even with '&'.
171+ + "operative '$import&!'" ^ $dep_from "%ensigil"
172+ ),
173+ (
174+ + "applicative 'check-parent'"
175+ ^ $dep_from ("%CheckParent" @ %NPLA1Forms);
176+ / $forced "all uses of applicative 'check-environment' for \
177+ applicative derivation of function name with '/e'"
178+ -> 'check-parent' $dep_from ("%(VauWithEnvironment, \
179+ VauWithEnvironmentRef)" @ %NPLA1Forms)
180+ ),
181+ / $forced "alternative derivation" @ "applicative \
182+ 'check-environment'" $dep_from ("%(VauWithEnvironment, \
183+ VauWithEnvironmentRef)" @ %NPLA1Forms)
184+ $= (/ $impl ^ 'eval%' ~ '$vau/e%'),
185+ / "simplified derivation" @ "applicative 'derive-environment'"
186+ @ 'NPL_Impl_NPLA1_Use_LockEnvironment'
187+ $dep_from "parent environment lists support",
188+ + "applicative 'modifiable?'"
189+ ^ $dep_from ("%IsModifiableTerm" @ %NPLA),
190+ + "applicative 'tempoary?'"
191+ ^ $dep_from ("%IsTemporaryTerm" @ %NPLA),
192+ / $comp DLI "supported move the environment argument"
193+ @ "applicative 'freeze-environment!'"
194+ $dep_from ("%ResolveEnvironment" @ %NPLA),
195+ / "avoided redundant copies" @ "applicatives ('restv', 'rest%')"
196+ ^ 'move!'
197+ ),
198+ / DLI "optimized variables to be provided" ^ "sigil"
199+ $effective @ "function %LoadModule_std_promises",
200+ // Since '$lambda/e' and '$lambda/e%' have no native \
201+ implementations currently and all such functions \
202+ derivable are derived from the vau abstractions, all \
203+ functions are effected uniformly.
204+ - DLI "reduced number of %ContextNode::Perform calls in the same \
205+ function" @ "basic derivations" @ "function %LoadGroundContext",
206+ // See comment in the code.
207+ / "set source names before calls to %ContextNode::Perform"
208+ ^ "%REPLContext::ShareCurrentSource"
209+ )
210+ ),
211+ / @ "%SHBuild-YSLib-common.txt" @ %Tools.Scripts $=
212+ (
213+ / @ "prelude" $=
214+ (
215+ / "overrode applicative 'derive-environment' for poisoned functions"
216+ $dep_from "parent environment lists support",
217+ / DLI "optimized poisoning functions" ^ ('ensigil'
218+ @ "%LoadGroundContext" @ %YFramework.NPL.Dependency)
219+ ),
220+ (
221+ / "supported sigil" @ "operative '$env-de!'" ^ 'desigil';
222+ / DLI "defined provided functions with '&' to enable forwarding"
223+ $dep_from
224+ ('$provide!' @ "%LoadGroundContext" @ %YFramework.NPL.Dependency)
225+ )
226+ )
227+),
228+
229+b908
230+(
35231 / %Tools.Scripts $=
36232 (
37233 / DLDI "simplified '$lambda'" @ "development tools build calls",
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd doc/NPL.txt
--- a/doc/NPL.txt Sat Jan 23 17:00:30 2021 +0800
+++ b/doc/NPL.txt Sat Jan 30 14:55:15 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPL.txt
1212 \ingroup Documentation
1313 \brief NPL 规范和实现规格说明。
14-\version r19248
14+\version r19454
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 304
1717 \par 创建时间:
1818 2012-04-25 10:34:20 +0800
1919 \par 修改时间:
20- 2021-01-23 16:54 +0800
20+ 2021-01-30 14:24 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -656,11 +656,12 @@
656656 @4.1.1 表示:
657657 表示用于表现演绎实例、具体实现及其中一部分实体(如某个值)的状态。
658658 注意变量不一定是可变状态的表示。
659-外部表示和内部表示是相对的。不同外部环境可以有不同的外部表示,这些外部表示相对其它外部环境而言可以不是外部表示。
659+外部表示(@2.3.2) 和内部表示(@2.3.2) 是相对的。不同外部环境可以有不同的外部表示,这些外部表示相对其它外部环境而言可以不是外部表示。
660660 外部表示可能被读取(read) 处理为内部表示。内部表示可能被写入(write) 处理为外部表示。
661661 读取和写入操作的副作用分别是输入(input) 和输出(output) 。
662662 外部表示为元素序列时,读取和写入是非特定格式数据和元素序列之间的转换,若不含其它作用(@2.3.4) ,其操作是进行反序列化(deserialize) 和序列化(serialize) 。
663663 内部表示为对象时,读取和写入包含对象和非特定格式数据之间的转换,其操作是进行列集(marshall) 和散集(unmarshall) 。
664+除非另行指定,不要求对象语言提供内部表示到外部表示的转换。
664665 文法(@3) 约定基准的表示作为翻译(@2.3.4) 的输入。这种表示是翻译所在外部环境的外部表示,称为源代码(source code) ;翻译结果为对象语言代码,简称对象代码(object code) ,可以是另外的外部表示。
665666 翻译单元(@3.1) 是这里翻译的外部表示。
666667 由基本文法(@3) ,空白符参与表示,不一一对应。为便于输出标准化,NPL 约定以下规范(canonical) 外部表示:
@@ -785,7 +786,7 @@
785786 一等实体的普遍支持体现在:
786787 在一般的一等实体上引入可变状态,实质上提供了一等副作用(first-class side effect) ,而不把可修改性(@4.1.4.2) 限于特定的数据结构(如求值环境(@4.6.1.1) );
787788 允许以一致的方式和实现的外部环境进行互操作(@2.3.3) ,特别地,允许物理上提供状态抽象的设备实体的状态直接映射为一等对象。
788-普遍的一等实体支持使一等实体的访问不依赖非一等的实体(@4.2.3.5) 。
789+普遍的一等实体支持使一等实体的访问不依赖非一等的实体而避免一些问题(@4.2.3.5) 。
789790
790791 @4.2.1.3 Kernel 中的一等对象:
791792 尽管没有显式指出一等实体和一等对象的区别,在 [RnRK] 中的一等对象和此处的一等实体在目的上一致。因为 Kernel 不直接支持区分对象同一性,一等实体退化为一等对象。
@@ -1105,6 +1106,7 @@
11051106 描述操作语义或实现可使用的求值规约以外的规约称为管理(administrative) 规约。
11061107 管理规约可以是求值规约的一部分,或者和求值规约的步骤没有交集。
11071108 系统的规约规则即表达式的求值规约规则和管理规约规则的并集。
1109+表示非一等对象(@4.1) 的项的规约总是管理规约。
11081110 抽象求值(@4.1) 中不在对象语言求值结果(@4.1) 中可表达的中间规约是管理规约实现。
11091111 求值的基本操作以满足特定规则的替换(substituion) 规则或其组合表示。
11101112 除非另行指定,以下讨论的排除求值副作用的重写系统具有汇聚性(@4.1.2) 。
@@ -1557,27 +1559,30 @@
15571559 @5.2.4 存储和对象模型:
15581560 NPLA 使用统一的模型对存储和对象进行抽象,并提供若干保证。
15591561 对象语言的存储被视为资源进行管理,称为存储资源(memory resource) 。
1562+除非另行指定,对象是由对象语言构造的一等对象(@4.1) ,且其它明确的非一等对象遵循相同的规则。
15601563
15611564 @5.2.4.1 基本模型:
15621565 因需提供宿主语言互操作(@5.2.1) 支持,除不支持静态(static) 存储和没有提供支持的存储操作外,NPLA 的基础存储模型和对象模型和 ISO C++11 相同。
15631566 当前不支持的存储操作包括分配函数(allocation function) 取得的存储和线程局部(thread-local) 存储。
15641567 NPLA 还允许类似对象具有未指定的存储或不需要存储的实体,以使一等实体(@4.2) 可涵盖宿主语言在功能上等价的非对象类型(如 C++ 的引用)。这些实体若被支持,其存储实现和互操作接口由派生实现定义。
1565-保证存储性质的差异不被依赖时,一等实体可按一等对象相同的方式实现。
1568+NPLA 中不是一等对象的一等实体(@4.2.1) 仅由派生实现定义。
1569+保证存储性质的差异不被依赖时,不区分一等实体和一等对象的实现方式。
15661570 在此情况下对象都是固定(pinned) 的,即对象在存储期(storage duration) 内具有宿主语言意义上的确定不变的地址。派生实现可约定扩展作为例外。
1567-和宿主语言类似,对象的生存期是存储期的子集。创建对象基于已确保可访问的存储;销毁对象结束后释放存储。
1571+推论:若一等实体不是一等对象,存储可能和一等对象的存储方式不同。派生实现可在必要时约定与其它一等实体存储的差异。
1572+和宿主语言类似,对象的生存期(@4.1) 是存储期的子集。创建对象基于已确保可访问的存储;销毁对象结束后释放存储。
15681573 基于宿主操作等意义,作为一等对象相同方式传递的一等实体都在此都视为一等对象;仅当不依赖一等对象的性质时,实现以非一等对象的方式实现一等实体的操作。
15691574
15701575 @5.2.4.2 求值和对象所有权:
15711576 被求值的表达式的内部表示即项(@5.5) 或环境(@5.4.3) 中的对象具有 NPLA 对象的所有权。
1572-所有权可被前者独占的 NPLA 对象是临时对象(temporary object) 。关于引入临时对象,参见 @5.5.6 。
1573-和宿主语言类似,NPLA 临时对象的存储未指定。对名义上被项所有的临时对象,必要时实现可分配内部存储转移项(包括在环境中分配),以满足附加要求(如 @5.2.5 )。
1577+和宿主语言类似,NPLA 临时对象(@5.5.6) 的存储未指定,但部分临时对象被项所有。
1578+对名义上被项所有的临时对象,必要时实现可分配内部存储转移项(包括在环境中分配),以满足附加要求(如 @5.2.5 )。
15741579 和宿主语言类似,对象的所有权随可随对象被转移,且被转移对象后的项具有有效但未指定(valid but unspecified) 的状态,参见 @5.5.2.3 和 @5.5.3 。
15751580 环境对绑定具有的所有权是独占的。绑定对其中的对象可具有独占或共享的所有权。因此,环境可对绑定中的对象具有独占或共享的所有权。
15761581 求值结果(@4.1) 可包含一等对象(@4.1) ,称为结果对象(result object) 。结果对象和 ISO C++17(由提案 [WG21 P0135R1] 引入)中的概念对应。
1577-函数调用(@4.5.3.1) 时以活动记录(@4.5.3.4) 保持被引用对象(@4.2.3) 的所有权。活动记录及其帧的具体结构、维护方式和生存期由派生实现定义。
1578-除非另行指定,NPLA 只有一种作用域(@4.6.1.1.2) 。
1582+函数调用(@4.5.3.1) 时以活动记录(@4.5.3.4) 保持被引用对象的所有权。活动记录及其帧的具体结构、维护方式和生存期由派生实现定义。
1583+除非另行指定,NPLA 只有一种作用域(@4.6.1.1.2) ,这种作用域中的名称由环境提供。
15791584 因为宿主语言函数调用实现(典型地,调用栈(call stack) 及其中的栈帧)不提供可移植的互操作(@5.2.1) ,除非另行指定,NPLA 的活动记录设计不需要保证直接对应关系。
1580-环境对象之间共享所有权(@5.4.3) ,按值传递环境不引起其中所有的对象被复制。
1585+作为非一等对象的环境对象之间共享所有权,以作为一等对象的环境引用访问(@5.4.3) 。按值传递(@4.4.4.5) 环境引用不引起其中所有的对象被复制。
15811586
15821587 @5.2.4.3 内存安全(memory safety) :
15831588 (非并发)内存安全是存储资源避免特定类型不可预测错误使用的性质。
@@ -1639,9 +1644,9 @@
16391644
16401645 @5.2.5 生存期附加约定:
16411646 和宿主语言不同,NPLA 子表达式的求值顺序可被不同的函数(特别允许显式指定对特定操作数(@4.4.3.1) 求值的操作子(@4.5.3.2) )中的求值调整,不需要特别约定。
1642-NPLA 不存在宿主意义上的完全表达式(@4.4.4.2) ,但在按宿主语言规则判断生存期时,使用本机实现(@5.2.1) 的函数合并(@4.5.3.2) 视同宿主语言的完全表达式,其本机函数调用不引起函数内创建的对象的生存期被延长。
1643-临时对象(@5.2.4.2) 的生存期(@5.2.4.1) 同时约束隐含的隐式宿主函数调用(如复制构造)。
1644-为保证求值表达式取得的临时对象(@5.2.4.2) 的内存安全(@5.2.4.3) ,函数合并同时满足以下规则:
1647+NPLA 不存在宿主语言意义上的完全表达式(@4.4.4.2) ,但在按宿主语言规则判断生存期时,使用本机实现(@5.2.1) 的函数合并(@4.5.3.2) 视同宿主语言的完全表达式,其本机函数调用不引起函数内创建的对象的生存期被延长。
1648+临时对象(@5.5.6) 的生存期(@5.2.4.1) 同时约束隐含的隐式宿主函数调用(如复制构造)。
1649+为保证求值表达式取得的临时对象的内存安全(@5.2.4.3) ,函数合并同时满足以下规则:
16451650 操作符(@4.4.3.1) 和未被求值的操作数的直接或间接子表达式关联的对象以及求值操作数的子表达式引入的临时对象的生存期结束的作用应不后序(@4.4.1) 于活动调用(@4.5.3.1) 结束。
16461651 这同时确保引入临时对象时,其生存期不会任意地被延长(超过函数合并表达式的求值)。
16471652 具体操作可在以上约束下指定被求值的操作数可能引入的临时对象的生存期。
@@ -1664,7 +1669,7 @@
16641669 PTC 确保仅有一个活动(@4.5.3.1) 的调用。不满足 PTC 的情形下,语言没有提供用户访问非活动记录帧(@4.5.3.4) 资源的手段,因此可以认为是资源泄漏。但为简化语义规则,NPLA 不要求避免相关的弱内存泄漏(5.2.2.2) 。
16651670 NPL 不保证一般对象存在引用(@4.2.3) ,NPLA 也不添加保证活动记录的帧(@4.5.3.4) 中保存引用,销毁活动记录的帧可能影响环境中的变量生存期而改变语义;因此 NPLA 不保证 PTC 支持,实现一般的 PTC 依赖派生实现定义的附加规则。
16661671 为满足 PTC ,在 @5.2.5 的基础上,尾上下文内的可以确定(@5.2.5) 并调整对象生存期结束时机:
1667-作为临时对象(@5.2.4.2) 的合并子及其参数可以延长生存期至多到尾上下文结束;
1672+作为临时对象(@5.5.6) 的合并子及其参数可以延长生存期至多到尾上下文结束;
16681673 被证明不再需要之后引用的对象,或未被绑定到活动记录上的项中的对象,可以缩短生存期;
16691674 被延长生存期的对象生存期起始和结束的相对顺序保持不变;
16701675 被缩短生存期的不同对象生存期结束的相对顺序保持不变。
@@ -1803,7 +1808,7 @@
18031808 @5.4.1 类型映射(@5.2.3) 实现:
18041809 类型映射使用的 C++ 类型在 namespace NPL 中声明,从 namespace YSLib 引入。
18051810 一些类型如 string 、ValueNode 和 ValueObject 在词法分析(@5.3.1) 和语法分析(@5.3.2) API 中引入,被以下章节的实现使用,成为实际的映射目标。
1806-以下章节 @5.4.2 和 @5.6 提供的节点或中间值(@4.4.4.2) 类型(thunk type) 是类型映射的目标(@5.4.1) 。
1811+以下章节中,IR 节点数据结构(@5.4.2) 和 NPLA 中间值(@5.6) 提供的节点或中间值(@4.4.4.2) 类型(thunk type) 是类型映射的目标(@5.4.1) 。
18071812
18081813 @5.4.2 IR 节点数据结构:
18091814 NPLA 实现使用节点(node) 数据结构表示实现使用的 IR 中间表示递归的构造,如 SContext 产生的 AST 的节点和语义分析使用的项。
@@ -1853,7 +1858,7 @@
18531858 Unqualified :非限定对象。默认值。
18541859 Unique :唯一引用。
18551860 Nonmodifying :不可修改。
1856-Temporary :临时对象。
1861+Temporary :临时对象(@5.5.6) 。
18571862 默认值外仅用于 NPLA 项引用(@5.6.3) 及其元数据(@5.6.3.1) 和派生实现。
18581863 在 TermTagIndices 中的枚举项带有 Index 后缀,和这些枚举项一一对应。
18591864 项的标签指定通过和标签关联的值访问的对象假定允许具有的性质。除非派生实现另行指定,违反这些假定不引起 NPLA 未定义行为(@5.2.2) 。
@@ -1917,6 +1922,7 @@
19171922 求值结果可以是具有 TermNode 子项的列表(@5.4.2.1) 数据结构,详见 @5.9 。
19181923 TermNode 还可能表示求值的中间结果(即求值规约中取得对象语言表达式的值之前出现的值),如表示某些中间值(@5.6) 的情形。
19191924 除非中间值也作为一等对象的表示(@2.3.4) ,NPLA 的规约范式(@5.8.4) 不会使用这些形式表示。
1925+NPLA 允许(但不要求对象语言支持)以一等对象作为表达式的表示并被求值。
19201926 表达式、表达式在求值过程中的中间表示(如中间值(@4.4.4.2) )和求值结果的表示统称规约表示。
19211927 在规约时,上下文(@4.6.1) 指定当前被求值项,确定当前被规约的 TermNode 。
19221928 表示值的 TermNode 是宿主语言对象具有的特定动态类型(@4.6.2) 的值是宿主值(hosted value) ,具有不固定的宿主类型(@5.2.3) 。
@@ -1929,7 +1935,7 @@
19291935 @5.5.1 值类别(@4.2.2.1) :
19301936 和 ISO C++17 (由提案 [WG21 P0135R1] 引入的特性)类似,表达式项(@5.5) 及在表达式求值的规约中得到的项具有以下值类别之一:
19311937 泛左值(glvalue) :求值用于决定被表示的对象的同一性(@4.1) 的项;
1932-纯右值(prvalue) :求值不用于决定对象同一性(而仅用于初始化(@5.5.2) 临时对象(@5.2.4.2) 或计算对象中存储的值)的项。
1938+纯右值(prvalue) :求值不用于决定对象同一性(而仅用于初始化(@5.5.2) 临时对象(@5.5.6) 或计算对象中存储的值)的项。
19331939 一个项可能被标记为消亡值(xvalue) 或附加其它元数据(如通过间接的引用(@4.2.3.3.1) ),以提供基于不同的所有权的行为。
19341940 左值(lvalue) 是除了消亡值外的泛左值。
19351941 右值(rvalue) 是消亡值或纯右值。
@@ -2010,7 +2016,9 @@
20102016 其中,前者是值数据成员为项引用(@5.6.3) 对象的项。
20112017 引用项(@5.5.4) 中的项引用对象引用一个(其它的)项,用于在必要时引入可被引用的一个项而不在 TermNode 中直接储存这个项的值。
20122018 对实现作为一等对象(@4.1) 的列表(@5.4.2.1) 的引用(@4.2.3) ,支持引用整个项的中间值是必要的;但项引用也支持引用非列表项。
2013-临时对象(@5.5.6) 可初始化引用值。和非临时对象的引用值不同,临时对象初始化的引用值和关联的被引用对象之间不需要区分同一性,因此使用被引用对象添加 TermTags::Temporary(@5.4.2.2) 标签表示。
2019+临时对象(@5.5.6) 可作为引用值的被引用对象。
2020+因为临时对象不是一等对象(@5.5.6) ,临时对象的引用值可代替关联的被引用对象使之作为一等对象被访问,因此使用被引用对象添加 TermTags::Temporary(@5.4.2.2) 标签表示。
2021+与此不同,非临时对象的引用值可作为一等对象而总是需要区分作为不同对象的同一性(@4.1) 。
20142022 引用值可能是左值引用(lvalue reference) 或右值引用(rvalue reference) 。
20152023 前者是排除引用项表示且不是唯一引用(@5.4.2.2) 的引用值;后者是以引用项表示的唯一引用或临时对象初始化的非引用项的引用值。
20162024 左值引用和左值引用与宿主语言中的对象类型的左值引用与右值引用分别类似。
@@ -2027,7 +2035,7 @@
20272035 @5.5.5 值类别转换:
20282036 和宿主语言类似,具有特定值类别的表达式可转换为不同值类别的表达式:
20292037 除非另行指定,泛左值总是允许作为纯右值使用,称为左值到右值转换(lvalue-to-rvalue conversion) ;
2030-从纯右值初始化(@5.5.2) 可被对象语言作为一等对象(@4.1) 使用的临时对象作为消亡值(@5.5.1) ,称为临时对象实质化转换(temporary materialization conversion) 。
2038+从纯右值初始化(@5.5.2) 可被对象语言作为一等对象(@4.1) 使用的临时对象(@5.5.6) 作为消亡值(@5.5.1) ,称为临时对象实质化转换(temporary materialization conversion) 。
20312039 左值到右值转换没有副作用(@4.2.2.1) 。临时对象实质化转换没有副作用,当且仅当其中初始化临时对象时没有副作用。
20322040 临时对象实质化转换中,纯右值被实质化(materialized) 。
20332041 在求值子表达式时,按表达式具有的语义,必要时(如按 @5.5.1.1 判断上下文的值类别)进行值类别转换。
@@ -2051,22 +2059,30 @@
20512059 返回值转换(return value conversion) 用于在对象语言中确定函数调用的返回值(@5.2.1) 可包含函数体(@4.5.2) 的求值结果到返回值的转换。
20522060 返回值转换的应用参见 @7.1.4.2 。
20532061
2054-@5.5.6 临时对象的引入:
2055-和宿主语言的临时对象的使用方式类似,NPLA 的临时对象在特定的上下文中被引入。
2056-为简化规约和互操作(@5.2.1) 机制的设计,和 ISO C++17 不同,临时对象仅在转换为消亡值(@5.5.1) 时的临时对象实质化转换(@5.5.5) 引入,而不包括延迟初始化或异常对象的创建。
2057-临时对象实质化转换引入临时对象的规则和 ISO C++17 不同:
2058-不论表达式是否作为子表达式使其值被使用(未使用的情形对应 ISO C++ 中的 discarded-value expression ),都允许存在临时对象;
2062+@5.5.6 临时对象(temporary object) :
2063+特定的 NPLA 非一等对象(@4.1) 是临时对象(@5.5.6) ,包括:
2064+所有权可被项独占(@5.7.5) 而不能作为一等对象访问的对象;
2065+内部表示具有临时对象标签(@5.4.2.2) 的引用对象(@5.5.4) 关联的被引用对象(@4.2.3) 。
2066+其中,直接构成项的对象可以是通过外部表示(@4.1.1) 通过翻译(@2.4.1) 变换得到的具有内部表示的数据结构(@5.4.2) 的非一等对象。
2067+NPLA 允许(但不要求对象语言支持)一等对象通过特定的求值,在中间结果中蕴含这种非一等对象。
2068+和宿主语言类似,NPLA 对象语言在特定的上下文引入其它临时对象,包括:
2069+实质化转换上下文(@5.5.6.1) ;
2070+返回值转换上下文(@5.5.6.2) 。
2071+关于临时对象的存储和所有权,参见求值和对象所有权(@5.2.4.2) 。
2072+为简化规约和互操作(@5.2.1) 机制的设计,和 ISO C++17 不同,引入临时对象不包括延迟初始化或异常对象的创建。
20592073 关于避免特定相关对象的初始化(@5.5.2) 的要求,参见复制消除(@5.5.6.3) 。
20602074
20612075 @5.5.6.1 实质化转换上下文:
20622076 可要求临时对象实质化转换的上下文包括:
20632077 使用纯右值初始化按引用绑定的变量(如函数的引用类型的形式参数(@4.5.2) );
20642078 求值函数调用以初始化返回值对象。
2065-其中,按引用绑定的变量被可选地支持;若被支持,引入引用值的形式参数的具体形式由派生实现指定。
2079+其中,按引用绑定的变量被可选地支持;若被支持,按引用绑定的对象具有临时对象标签(@5.4.2.2) ,引入引用值的形式参数的具体形式由派生实现指定。
20662080 一般地,按引用绑定的变量在活动调用(@4.5.3.1) 关联的环境分配临时对象。此时,对象被调用表达式的项独占所有权,同时被绑定的环境独占资源所有权。
2081+临时对象实质化转换引入临时对象的规则和 ISO C++17 不同:
2082+不论表达式是否作为子表达式使其值被使用(未使用的情形对应 ISO C++ 中的 discarded-value expression ),都允许存在临时对象;
20672083
20682084 @5.5.6.2 返回值转换上下文:
2069-返回值转换(@5.5.5.2) 可引入实质化的临时对象,其中可能转移求值的中间结果(@5.5)(条件参见 @5.6.3.4 );否则,对象被复制。
2085+返回值转换(@5.5.5.2) 可引入实质化的临时对象,其中可能转移求值的中间结果(条件参见 @5.6.3.4 );否则,对象被复制。
20702086 此处被转移对象符合求值和对象所有权(@5.2.4.2) 规则中的临时对象的定义,但除非另行指定,被转移的对象不在对象语言中可被访问。
20712087 此处的转移引起宿主对象转移消除(@5.5.3.1) 。
20722088 仅在对象被复制且复制具有副作用时,返回值转换具有等价复制的副作用。
@@ -2230,7 +2246,7 @@
22302246 使用 ValueObject 的特定持有者或约定特定的中间值(@5.6) 实现间接值允许和所有权分离的其它形式的表示,提供和非间接值不同的对象所有权和附加操作。
22312247 间接值的实例总是具有关联对象。间接值可间接访问关联对象。
22322248 对作为对象语言中的一等对象的间接值,允许复制或转移关联的对象以恢复对应的非间接值作为一等对象直接访问。
2233-间接值可用于代替非间接值,避免求值时改变环境(@5.4.3) 所有的非临时对象(@5.2.4.2) 的所有权。
2249+间接值可用于代替非间接值,避免求值时改变环境(@5.4.3) 所有的非临时对象的所有权(@5.2.4.2) 。
22342250 间接值可实现和 C++ 引用类型表达式类似的行为。
22352251 NPLA 提供引入间接值的 API ,参见 @6.6.2 。
22362252 实现通过值数据成员以外的机制也可隐含固定(不通过用户代码修改定制)的所有权关系,如上下文(@5.4.4) 和环境(@5.4.3) 。
@@ -2334,7 +2350,7 @@
23342350 对临时对象分配资源可能转移表示临时对象的项,但不影响其子项的稳定性。
23352351
23362352 @5.7.8 项修改限制:
2337-若规约需调整项的结构以便使用特定 API ,可使用 TermNode& 作为参数的规约函数(@5.8.5)(另见 @6.5.3 );
2353+若规约需调整项的结构以便使用特定 API ,可使用 TermNode& 作为参数的规约函数(@5.8.5)(另见规约函数形式约定(@6.5.3) );
23382354 如不可行,一般需转移到新创建的项上进行调用,以免改变现有的项导致无法使用项独占所有权的资源(如 @5.7.7.1 的状态)。
23392355 单独转移可能具有宿主类型对象的子项会违反固定对象的约定(@5.7.7) ,因此除非确保子项不被引用,不单独转移或销毁可能带有宿主对象(@5.5) 的子项(包括引起子项对象被销毁的删除操作)。
23402356 若规约内部确定符合内存安全(@5.2.4.3) 或派生实现指定的假定满足的条件(至少应满足 @5.7 中的资源管理要求),子项可被转移或销毁。这些操作包括:
@@ -2345,7 +2361,10 @@
23452361
23462362 @5.8 规约约定:
23472363 NPLA 规约 API(@6.5) 约定默认使用 TermNode 和 ContextNode 类型的引用作为参数类型,分别表示被规约项(@5.4.2) 和使用的上下文(@4.6.1) 。
2348-其中其它变体参见 @6.5.3 。
2364+更具体的其它约定参见规约函数形式约定(@6.5.3) 。
2365+一次规约局限在当前被规约项(一个 TermNode 对象)进行修改(@5.7.8) ,这个被规约项称为此次规约的当前项(current term) 。
2366+表达式求值起始时,当前项是当前被求值项(@5.5) 。
2367+规约 API 的 TermNode 参数指定当前项。必要时,当前项可被其它方式指定。
23492368 NPLA 约定列表表达式(@3.4.2.3) 子项作为被规约项需进行递归的树规约(@5.4.2) 。
23502369
23512370 @5.8.1 规约结果:
@@ -2354,8 +2373,8 @@
23542373 中立规约(neutral reduction) :规约成功终止(@4.4.3) ,且未指定是否需要保留子项。
23552374 纯值规约:规约成功终止,且不需要保留子项。
23562375 非纯值规约:规约成功终止,且需要保留子项。
2357-重规约:所在的列表表达式需要以相同的参数重新调用进行进一步规约,而需要跳过当前被规约项(一个 TermNode 对象)的剩余的规约动作(@5.4.4) 。
2358-取得重规约外的规约结果时,被规约项表示求值结果(@4.1) 。关于使用规约实现表达式求值,另见 @5.5 。
2376+重规约:所在的列表表达式需要以相同的参数重新调用进行进一步规约,而需要跳过当前项的剩余的规约动作(@5.4.4) 。
2377+取得重规约外的规约结果时,被规约项表示求值结果(@4.1) 。另见关于使用规约实现表达式求值(@5.5) 。
23592378 纯值规约的求值结果总是由值数据成员(@5.4.2) 决定。
23602379 非纯值规约为纯列表规约,当且仅当求值结果仅由子项决定而不需要访问值数据成员。
23612380 除不指定要求保留子项,中立规约和非纯值规约的作用相同,仅影响 @5.8.3 中的处理。
@@ -2372,7 +2391,7 @@
23722391 @5.8.2.1 子项的清理(cleanup) :
23732392 纯值规约(@5.8.1) 要求清理操作,即移除不被需要(@5.8.1) 的子项。
23742393 清理时子项所有的对象被销毁,可具有副作用(@2.3.4) 。
2375-子项的清理属于 @5.7.8 中约定的删除子项的操作。
2394+子项的清理属于删除子项的操作(@5.7.8) 。
23762395
23772396 @5.8.3 规约迭代:
23782397 对项的一次规约可分解为若干个对这个项的分步规约的有序的迭代过程,每个过程称为一个遍(pass) ;另见 @6.8 。
@@ -2513,6 +2532,10 @@
25132532 这种方式支持嵌套调用安全(@5.2.7) 。其它方式实现可能具有更好的性能,但存在限制而不被使用,如:
25142533 依赖不可移植的宿主语言扩展及实现假定,
25152534 对对象语言源代码中使用的语言构造(特别是影响控制流的合并子(@4.5.3.2) )进行限制,使用单独的阶段进行抽象求值(@4.1) 。(这允许使用静态 TCO (@5.2.6.4.2) 所需的变换。)
2535+异步规约动作不需要接受以宿主语言 API 的参数传递的当前项(@5.8) 。
2536+必要时,由上下文或异步规约操作内部捕获保存的值确定当前项。
2537+起始求值规约(@4.4) 的规约动作是异步求值规约动作。
2538+异步求值规约动作应及时以当前被求值项(@5.5) 更新保存在上下文中保存的项,使之后新的表达式求值的动作可确定正确的表达式。
25162539
25172540 @5.10.2 异步规约操作流程:
25182541 调用当前动作(@5.4.4) 引导若干操作(可包括后继的动作对当前动作的更新)组成一个异步操作序列实现对一个项的规约,这和对应的同步操作的树规约(@5.4.2) 保证 CPS 等价:
@@ -2527,7 +2550,7 @@
25272550 因为不再通过宿主的活动记录保留同步操作对应的项,当明确异步动作及对应的项时,规约函数返回的规约结果(@6.5.1) 和对应同步操作不再具有一一对应关系;上述外层循环的循环条件仅考虑当前动作的有效性,具体同 ContextNode::Rewrite(@6.9.4) 的约定。
25282551 当前动作对应单一项的到当前被求值项(@5.5) 的有界续延(delimited continuation) 。后继动作(@5.4.4) 是这个边界外的被定界的续延。
25292552 实现过程调用(@4.5.3.1) 时,设置子项的当前动作前保存当前动作,和同步操作时保存活动记录帧(@4.5.3.4) 等价。保存当前动作的方式(具体调用的 API )由调用方的实现指定。
2530-异步规约所在的重写循环(@5.10.1) 中,每个动作返回的规约状态的含义不变;除被规约的项(若保持副作用顺序,也包括每个子项)上最后一步外,使用当前动作实现一个项内非最终步骤的异步操作,都为部分规约(@5.8.1) ,规约函数返回值应为 ReductionStatus::Partial 。
2553+异步规约所在的重写循环(@5.10.1) 中,每个动作返回的规约状态的含义不变;除当前项(@5.8)(若保持副作用顺序,也包括每个子项)上最后一步外,使用当前动作实现一个项内非最终步骤的异步操作,都为部分规约(@5.8.1) ,规约函数返回值应为 ReductionStatus::Partial 。
25312554 因为不记录规约的具体项,求值遍(@7.4.1.2) 中的动作序列在需要重规约时无法判断是否保留剩余的规约动作(@5.8.1) 。
25322555 是否继续需要剩余规约动作,由规约函数自行判断:
25332556 异步规约的实现通过重规约指定跳过剩余的规约动作;
@@ -2560,9 +2583,10 @@
25602583
25612584 @5.11.1 NPLA1 约定:
25622585 NPLA1 仅使用宿主语言的类型和值作为状态。
2586+在 NPLA 的基础上,NPLA1 要求对象语言支持以一等对象作为表达式并被求值(@5.5) 。
25632587 类型等价性基于类型映射(@5.2.3) 及其实现(@5.4.1) ,由 C++ 的语义规则定义。
25642588 值等价性由宿主实现的 == 表达式的结果定义。
2565-除非另行指定,所有类型的外部表示都是同宿主类型的空字符结尾的字符串( C++ NTCTS )。
2589+除非另行指定,所有类型的外部表示(@4.1.1) 都是允许从作为内部表示的项节点结构确定的同宿主类型的空字符结尾的字符串(即 ISO C++ 的 NTCTS )。
25662590
25672591 @5.11.1.1 附加规则:
25682592 当前仅支持标识符(@3.3.1) 作为名称。
@@ -2706,7 +2730,9 @@
27062730 NPL::IsReferenceTerm
27072731 NPL::IsBoundLValueTerm
27082732 NPL::IsUncollapsedTerm
2733+NPL::IsModifiableTerm
27092734 NPL::IsUniqueTerm
2735+NPL::IsTemporaryTerm
27102736 NPL::ResolveTerm 解析并间接引用处理可能是引用值(@5.5.4) 的项,其中尝试解析使用 NPL::TryAccessLeaf 。
27112737 NPL::CheckRegular 指定函数访问检查项后的指定类型正规值(@5.9) ,即按模板参数指定的类型访问解析后的正规值。
27122738 NPL::AccessRegular
@@ -2806,7 +2832,7 @@
28062832 引用值通过参数指定的值对象(@5.4.2) 上创建得到。
28072833 函数 NPL::LiftToReference 提升项对象为引用。
28082834 若项对象表示引用值则提升项,否则对 ValueObject 进行基于所有权的生存期检查并取引用这个项的引用值。
2809-运行时进行的检查类似于强制 C++ 的一元 & 对表达式值类别(另见 @4.2.3 )的要求但更严格(尽管仍然不能保证避免未定义行为),避免临时对象(@5.2.4.2) 被保存为引用值。
2835+运行时进行的检查类似于强制 C++ 的一元 & 对表达式值类别(另见 @4.2.3 )的要求但更严格(尽管仍然不能保证避免未定义行为),避免临时对象(@5.5.6) 被保存为引用值。
28102836
28112837 @6.6.3 消除中间值的提升操作:
28122838 函数 NPL::LiftMoved
@@ -2999,7 +3025,7 @@
29993025
30003026 @7.1 NPLA1 一般约定:
30013027 在 NPLA 的一般约定(@5.2) 外,本节概述不通过具体 API 指定的一般特性。
3002-参见存储和对象模型(@5.2.4)(包括临时对象(@5.2.4.2) 和内存安全(@5.2.4.3) )的基本规则。
3028+参见存储和对象模型(@5.2.4)(包括临时对象生存期(@5.2.4.2) 和内存安全(@5.2.4.3) )的基本规则。
30033029 另见作为具体实现的 NPLA 间接值(@5.7) 使用规则(@7.1.4) 。
30043030 关于所有权和生存期,参见 NPLA1 间接值的有关规则和求值对应的 API(@7.6.4) 。
30053031 类似 NPLA(@6.10) ,NPLA1 实现可在实现中提供构建时确定的实现选项,以宿主语言的宏定义等方式启用。
@@ -3073,8 +3099,8 @@
30733099 规约实现需满足被规约项稳定性(@5.7.7) 。
30743100 在 @5.7.7.1 决定操作状态的资源包含当前使用的遍处理器中的目标对象(@6.8.1) 。
30753101 规约前被规约项的第一个子项具有遍处理器的所有权,也对目标对象具有所有权。
3076-假定满足 @5.7.8 的要求而允许删除子项的情形包括:
3077-主规约函数(@6.5.3.3) 和 @8 支持的本机函数(@5.2.1) 的实现可假定被在调用处理器前会转移子项的处理器调用;
3102+假定满足限制而允许删除子项的情形(@5.7.8) 包括:
3103+主规约函数(@6.5.3.3) 和 NPLA1 扩展实现(@8) 支持的本机函数(@5.2.1) 的实现可假定被在调用处理器前会转移子项的处理器调用;
30783104 通过处理 WHNF 的调用遍处理器的 A1::ReduceCombined(@7.6.4.2) 在调用处理器前会转移子项,可保证调用时生存期不会因为直接清理第一个子项而结束,因此处理器可清理第一个子项。
30793105
30803106 @7.2.2 节点记号:
@@ -3086,7 +3112,7 @@
30863112 注意当前 A1::Reduce 规约时不对空节点(表示空列表)和 A1::ValueToken 类型的值进行操作。
30873113
30883114 @7.2.3 NPLA1 续延(@4.5.2.1) :
3089-续延是依赖上下文状态(@7.4.3) 的一等中间值(@5.6.1) ,参见 @7.4.2 。
3115+续延是依赖上下文状态(@7.4.3) 的一等中间值(@5.6.1) ,参见合并遍(@7.4.2) 。
30903116
30913117 @7.3 错误处理例程:
30923118 除非另行指定,NPLA1 实现优先使用以下包装 NPLA 异常(@6.3) 的错误处理 API :
@@ -3099,14 +3125,15 @@
30993125 @7.4 规约实现:
31003126 NPLA1 在 NPL::A1 中提供不同粒度的规约和求值实现 API 。
31013127 由于实现 NPLA 的宿主语言不支持 TCO(@5.2.6.4.1) ,在实现时显式使用尾调用(@5.2.6) 形式才能支持空间复杂度和规约调用的嵌套深度无关;详见 @7.10 。
3102-命名空间 A1 中使用上下文参数的规约函数(参见 @7.4.4 和 @7.4.6 )要求 ContextNode& 类型的参数引用的对象是 NPLA1 上下文状态或 public 继承的派生类,否则行为未定义。
3128+命名空间 A1 中使用上下文参数的规约函数(参见 NPLA1 主规约函数(@7.4.4) 和一般规约函数(@7.4.6) )要求 ContextNode& 类型的参数引用的对象是 NPLA1 上下文状态或 public 继承的派生类,否则行为未定义。
31033129
31043130 @7.4.1 遍类型:
31053131 基于 YSLib 事件( YSLib::GEvent 的实例),NPLA1 提供若干的遍类型。
3106-基于 NPLA 公共实现,NPLA1 使用上下文提供的可配置的公共遍(@7.4.3) ,其 API 详见 @7.4.3 。
3132+基于 NPLA 公共实现,NPLA1 使用上下文提供的可配置的公共遍(@7.4.3) ,其 API 详见 NPLA1 上下文状态(@7.4.3) 。
31073133
31083134 @7.4.1.1 遍合并器(pass combiner) :
3109-忽略部分规约(@5.8.1) 的多个遍的调用结果被实现为遍合并器 A1::PassesCombiner 定义的逻辑合并。合并时使用的判断条件参见 @6.8.2 。
3135+忽略部分规约(@5.8.1) 的多个遍的调用结果被实现为遍合并器 A1::PassesCombiner 定义的逻辑合并。
3136+合并时使用的判断条件参见遍合并(@6.8.2) 。
31103137 遍合并器依次调用事件处理器,合并调用的结果为表示是否需要重规约(@5.8.1) 的值。当发现调用的结果对应遍的规约结果需要重规约时,调用停止。
31113138 遍合并器被 YSLib::GEvent 的模板参数依赖,可简化不使用异步规约(@5.10.1) 的同步实现。
31123139
@@ -3134,20 +3161,35 @@
31343161 遍的调用不一定需要维护共享状态,也因此一般多个遍被调用时不保证求值的强异常安全;其它情形仍然遵守一般约定([Documentation::YFramework @@3.2]) 。
31353162 除 A1::ReduceCombined(@7.6.4.2) ,NPLA1 规约实现不保证进行正规化操作(@5.9.2) :
31363163 在正规化操作不保证存在时,实现列表遍的用户代码需注意清理(@5.8.2.1) 不需要的子项。
3137-关于规约函数(@5.8.5) 的基本约定,参见 @6.5.3 。
3138-NPLA1 中名称以 Reduce 起始的规约函数(@6.5.3) 若不排除 TermNode& 参数的项在其实现中被规约同时其子项待规约,确保设置上下文状态中的下一求值项(@7.4.3) 为 TermNode& 参数指定的项。
3164+
3165+@7.4.1.5 规约函数实现约定:
3166+关于规约函数(@5.8.5) 的基本约定,参见规约函数形式约定(@6.5.3) 。
3167+对 NPLA1 使用的规约函数(@7.4.6)(不含 NPLA 中引入的规约函数(@5.8.5) ,下同),约定以下可被实现假定的使用要求:
3168+ 若具有上下文参数,则上下文的动态类型是 A1::ContextState(@7.4.3) 或其 public 派生类。
3169+若规约函数包含异步求值规约且不排除可能调用续延,规约函数还应满足:
3170+ 若可能通过调用 A1::ContextState::ReduceOnce 调用续延(@7.4.2) ,应确保调用时下一求值项(@7.4.3) 被正确设置。
3171+ 以下情形要求规约函数具有指定 NPLA1 上下文的参数,以此和被规约项作为参数调用 ContextState::SetNextTermRef 更新 NPLA1 上下文中保存的下一求值项:
3172+ 对主规约函数(@7.4.4) 及名称包含通配符模式 Reduce*Subsequent 或 RewriteTerm 起始的规约函数,首先以 TermNode& 参数指定的当前项(@5.8) 更新下一求值项。
3173+ 发生和当前项不同的被规约项(通常表示子表达式)的规约,首先以新的被规约项更新下一求值项。
3174+ 除以上要求以当前项更新下一求值项的函数,调用函数的当前项应和下一求值项相同。
3175+使用不符合以上要求的实现的程序行为未定义。
31393176
31403177 @7.4.2 NPLA1 续延:
31413178 类 A1::Continuation 表示 NPLA1 的一等续延,即作为一等对象(@4.1) 的续延。
3142-一等续延依赖 NPLA1 上下文状态(@7.4.3) 。
31433179 一等续延当前未完全在对象语言中被支持。
3180+续延同时在规约中作为非一等对象使用,以支持异步规约(@5.10) 。
3181+续延依赖 NPLA1 上下文状态(@7.4.3) 。
3182+A1::Continuation 对象保存 A1::ContextHandler(@7.6.1) 对象实现具体操作。
3183+A1::Continuation::operator() 以 ContextNode& 参数直接调用续延。
31443184 注意 NPLA 上下文中的续延由 NPL::ReducerSequence(@6.9.4) 表示,提供续延捕获直接支持(参见 @5.10.4),而 NPLA1 续延是这个机制上的扩充。
31453185 NPLA1 续延的必要性体现为的状态支持下一求值项(@7.4.3) 的支持(这隐含运行时对上下文状态类型的要求)。
3186+调用续延要求上下文对象的动态类型包含 NPLA1 上下文,取其中的下一求值项作为当前项(@5.8) 。
31463187 此外,也可存在其它续延的对象。例如,Forms::Sequence(@8.4.9) 中的内部续延不支持访问(因此不依赖)下一求值项,而不需要实现为 A1::Continuation 。
31473188 另见动作帧(@5.10.6) 。
31483189
31493190 @7.4.3 NPLA1 上下文状态:
31503191 类 A1::ContextState 是 ContextNode 的 public 派生类,其对象表示 NPLA1 上下文状态,包含 NPLA 上下文的状态(@5.4.4) 。
3192+A1::ContextState 包含作为之后的异步求值规约动作(@5.10.1) 使用的当前项(@5.8) 的下一求值项。
31513193 NPLA1 上下文状态提供以下的供迭代的公共遍:
31523194 守卫遍(guard pass) ,类型是一个 GuardPasses(@7.4.1.3) ,用于提供调试回调等。
31533195 叶遍(leaf pass) ,类型是一个 EvaluationPasses(@7.4.1.2) ,用于实现叶节点(@5.4.2.1) 对应表达式的求值。
@@ -3175,9 +3217,9 @@
31753217 A1::Reduce 是 A1::ReduceOnce 的包装,最终调用后者以支持异步规约(@7.9) 。
31763218 @7.4 及以下各节中对 A1::ReduceOnce 的行为描述默认由 A1::ContextState::DefaultReduceOnce(@7.4.3) 实现。替换的实现应保持的要求相同。
31773219 A1::ReduceOnce 的规约对列表和非列表分别进行处理,实现求值算法(@6.5.3.3) ,要求单一子项的项规约为其子项,而其它列表或非列表项的规约操作由遍(@7.4.1) 提供。其中,列表被先匹配。
3178-A1::ReduceOnce 中的处理器(@7.2.1) 应符合 @7.2.1.1 的约定。
3179-若实现中使用的处理器不符合约定,可能不满足 @5.7.7.1 并可能引起未定义行为。
3180-对支持异步规约的实现(@7.9.2) ,还应符合 @7.9.1 。
3220+注意 A1::ReduceOnce 中的处理器(@7.2.1) 作为应符合关于中间值的使用约束(@7.2.1.1) 。
3221+若实现中使用的处理器不符合约束,可能不满足 @5.7.7.1 并可能引起未定义行为。
3222+对支持异步规约的实现(@7.9.2) ,上述处理器还应符合和同步规约实现兼容性(@7.9.1) 中的规则。
31813223 A1::ReduceOnce 和辅助规约函数(@6.7) 类似,能处理一般的项,没有前置条件。参数中 TermNode(@5.4.2) 表示的表达式语法意义(@3.4.2) 上非空,但没有实现限制(即不附加检查)。
31823224 A1::ReduceOnce 循环调用遍(@7.4.1) 进行必要的重规约,即迭代规约;通过 NPL::CheckReducible(@6.5.2) 判断是否需要重规约。
31833225 A1::ReduceOnce 的实现中不直接指定需要重规约;所有 ReductionStatus::Retrying 都来自遍(@7.4.1) 的调用。
@@ -3363,7 +3405,7 @@
33633405 函数 A1::RelayForEval 直接求值(@4.1) 规约:规约并传递求值的结果。
33643406 函数 A1::RelayForCall 函数调用规约( β 规约(@4.5.3) ):规约并传递词法闭包规则(@4.6.1.1.2) 下求值的结果。
33653407 使用合并动作 API ,可定义依赖这些合并动作的求值规约操作,附加相同的约束。
3366-为确保嵌套函数调用时允许引用绑定到非直接主调函数的临时对象(@5.2.4.2) 形式参数,已被匹配作为绑定目标的项所在的不表示操作数的项(参见 @7.7.3 )可能被转移以保证其子项生存期足够长。
3408+为确保嵌套函数调用时允许引用绑定到非直接主调函数的临时对象(@5.5.6) 形式参数,已被匹配作为绑定目标的项所在的不表示操作数的项(参见 @7.7.3 )可能被转移以保证其子项生存期足够长。
33673409 按 @5.7.7.2 ,此时被作为绑定目标的子项不需被修改(因此自动符合 @5.7.8 的要求)。
33683410 间接调用 A1::RelayForEval 或 A1::RelayForCall 的操作是求值规约操作。
33693411 间接调用 A1::RelayForEval 的求值规约操作包括:
@@ -3406,7 +3448,7 @@
34063448 绑定时不对形式参数对应的函数参数进行修改,所以不对形式参数除访问引用值外的间接处理。
34073449 若形式参数可能由求值得到,需在匹配前另行处理。
34083450
3409-@7.7.3.2 绑定临时对象(@5.2.4.2) 标签:
3451+@7.7.3.2 绑定临时对象(@5.5.6.1) 标签:
34103452 绑定临时对象时设置对象上的 TermTags::Temporary 标签(@5.4.2.2) ,以实现区分通过引用绑定延长生存期的临时对象和非引用绑定的对象(@5.5.6.3) 。
34113453 一般地,表达式中的纯右值(非引用值)被绑定为临时对象,被绑定的对象在初始化后具有 TermTags::Temporary 。
34123454 这对应宿主语言中的转发引用(forwarding reference) 参数中的情形:
@@ -3630,7 +3672,7 @@
36303672 非 NPLA1 API 若支持异步规约,可能以关联的上下文中的当前动作为空作为前置条件以允许直接调用 ContextNode::SetupTail(@6.9.4) 等设置当前动作。
36313673 对具有前置条件的 API ,调用者应按需在其他操作前保存当前动作以维护符合预期的作用顺序。
36323674
3633-@7.9.3 临时对象(@5.2.4.2) 管理:
3675+@7.9.3 临时对象(@5.5.6) 管理:
36343676 规约时,对象语言的函数右值和操作数右值需要被保存以避免引起宿主语言的未定义行为(@5.2.2) 。
36353677 特别地,对象语言语法意义上的嵌套函数调用应能引用外层对象(例如,通过绑定引用参数(@7.7.3.4) )而不引起宿主语言的未定义行为(@5.2.2) 。
36363678 A1::ReduceCombined 在同步规约时通过宿主语言的规则自然地实现此要求,转移子项(@7.2.1.1) 时只需以宿主语言的自动对象作为新建的项。
@@ -3661,12 +3703,12 @@
36613703 基于异步规约 API(@7.9.2) ,使用重写规则(直接通过现有 API 支持的即重规约(@7.4.4) )代替直接使用宿主语言的递归形式可实现目标 TCO(@5.2.6.4.2) ;
36623704 动态 TCO(@5.2.6.4.2) ,具体机制详见操作压缩(@7.10.3.2) 。
36633705 NPLA 除个别例外(@6.1) 均支持宿主 TCO ,不需要其它形式的静态 TCO(@5.2.6.4.2) 。
3664-在此基础上,NPLA1 通过允许和动态 TCO 互操作的异步重规约的方式支持目标 TCO ,详见 @7.10.6 ;但当前 NPLA1 部分 API 不保证支持宿主 TCO ,这可能在以后完善。
3706+在此基础上,NPLA1 通过允许和动态 TCO 互操作的异步重规约的方式支持目标 TCO(@7.10.6) ;但当前 NPLA1 部分 API 不保证支持宿主 TCO(@6.1) ,这可能在以后完善。
36653707 NPLA1 支持的动态 TCO 按实现策略即 TCM(@5.2.6.4.2) 。
36663708 综上,使用 NPLA1 的 PTC 有三类实现策略:
36673709 通过直接重写宿主语言的实现(使用循环代替部分递归)提供宿主 TCO ;
36683710 通过 TCO 动作(@7.10.3) 提供动态 TCO ;
3669-基于异步重规约和 TCO 的互操作(@7.10.6) 提供目标 TCO 。
3711+基于异步重规约和 TCO 的互操作提供目标 TCO 。
36703712
36713713 @7.10.2 整体设计约束:
36723714 TCO 要求尾上下文(@4.4.7) 的续延(@4.5.2.1) 保持等效。考虑到计算资源的限制,排除构造相同的外部的求值环境(@4.6.1.1.2) 的实现方式,这蕴含同一性。
@@ -3704,7 +3746,7 @@
37043746 @7.10.3.2.1 非幂等操作:
37053747 非幂等的操作和生存期相关,包括:
37063748 设置环境时,确保被设置环境的父环境(@5.4.3) 的生存期;
3707-分配临时对象(@5.2.4.2) 时,确保临时对象最终能被及时释放;
3749+分配临时对象(@5.5.6) 时,确保临时对象最终能被及时释放;
37083750 每次调用的调用结果都适用的附加的状态维护操作(@7.10.3.3) ,包括对调用结果的正规化操作(@5.9.2) 和提升项(@6.6) 。
37093751 这些操作可能有多个实例,因为以下几个原因而无法合并:
37103752 存储模型和对象模型(@5.2.4) 要求生存期开始和结束的顺序;
@@ -3763,7 +3805,7 @@
37633805 被从 TCO 对象中移除的环境对象是没有 NPL::TermReference 引用其锚对象的对象。当强引用计数为 1 时,压缩后最终会被清除而释放,持有的对应资源被回收。
37643806 这一过程在局部上类似基于引用计数的 GC(@5.2.4.4) 机制。
37653807
3766-@7.10.5 TCO 临时对象(@5.2.4.2) 管理:
3808+@7.10.5 TCO 临时对象(@5.5.6) 管理:
37673809 一般机制参见临时对象管理(@7.9.3) 和 TCO 资源管理(@7.10.4) 。
37683810 TCO 异步规约对临时对象的管理基本策略同 @7.9.3 ,但因为操作压缩(@7.10.3.2) 具有更多的变化和限制,所以实现较复杂。
37693811 和非 TCO 异步规约的实现相比,临时对象不仅因为引用绑定子项需保证子项的生存期足够长(@7.7.2) 的原因,还可因为操作压缩的需要,而可被转移。后者的情形应符合 @5.7.8 中取得求值结果后不被引用的项修改限制条件。
@@ -3857,7 +3899,7 @@
38573899
38583900 @7.11.5 TCO 动作(@7.10.3) 实现和限制:
38593901 因为维护资源(@7.10.4) 的需要,规范求值算法(@7.8.2) 不处理 WHNF 以外的操作数且允许宿主类型的调用(@7.6.1.2) 处理 WHNF 的第一项。
3860-当前在 TCO 动作中被分配的临时对象(@5.2.4.2) 的操作都针对作为 WHNF 的第一项的合并子,其中合并子相等性由 @8.4.5.5 或其它宿主实现提供的 == 操作确定。
3902+当前在 TCO 动作中被分配的临时对象(@5.5.6) 的操作都针对作为 WHNF 的第一项的合并子,其中合并子相等性由 @8.4.5.5 或其它宿主实现提供的 == 操作确定。
38613903 由 @8.4.5.5 ,捕获不同环境的 vau 合并子不相等;不论是否具有相等的外部表示(@2.3.4) 和来源,其右值不会被直接操作压缩(@7.10.3.2) 避免多次添加而被 TCO ;若其嵌套调用因为捕获不同的存在引用关系的环境,不支持其它形式的 TCO ;因此,不支持 PTC 。
38623904 注意上述情形在其它语言中因为可达性分析等可能具有实现缺陷也不会释放存储,如 Kernel 程序 ($sequence ($define! f ($lambda (n) ((($vau (x y) e (eval ($sequence x y) e)) n (f n))))) (f 1)) 在 klisp 中实测不支持 PTC 。
38633905 当前 TCO 操作压缩不支持回收非 #ignore 的动态环境。这实际上较 [RnRK] 的保证弱。但 klisp 同样没有很好地支持此特性,如 Kernel 程序 ($sequence ($define! $f ($vau () #ignore (($f)))) ($f)) 在 klisp 中实测不支持 PTC 。
@@ -3871,19 +3913,20 @@
38713913 当前实现并没有显式支持 evlis tail recursion(@5.2.6.3) ,但因为调用前切换环境时已提前进行了收集,所以以 TCO 动作为边界,保存的帧应与之等效。
38723914 尽管可能有更优的渐进复杂度,所需空间的大小仍取决 TCO 活动记录最终保留帧前分配对象和碎片所占空间大小之和的最大值;实现应该不依赖这项特性。
38733915 回收使函数对象在表达式求值外完毕之前结束,这仍然符合 @5.2.6 的要求。
3874-当前 NPL::LiftToReturn(@6.6.3) 的调用非嵌套调用安全(参见 @6.1 )。在项的嵌套深度依赖调用深度时,不满足 PTC 。
3916+当前 NPL::LiftToReturn(@6.6.3) 的调用非嵌套调用安全(@6.1) 。在项的嵌套深度依赖调用深度时,不满足 PTC 。
38753917
38763918 @7.11.6 元数据:
38773919 模块 NPL::NPLA1 提供特定可由函数 A1::QueryContinuationName 查询得到。
38783920 其中查询结果的名称和 A1::Continuation::Handler 或 Reducer 的特定目标类型关联。
38793921 除非另行指定,关联的类型是非公开的内部类型。这些名称包括:
38803922 conditional-eval-sequence
3923+equal-subterm
3924+equal-siblings
38813925 eval-acc-head-next
38823926 eval-acc-nested
38833927 eval-accl-accl
38843928 eval-accl-tail
38853929 eval-accr-accr
3886-eval-accr-foldr
38873930 eval-accr-sum
38883931 eval-argument-list
38893932 eval-booleans
@@ -3895,6 +3938,7 @@
38953938 eval-forward-list-first
38963939 eval-guard
38973940 eval-lift-result
3941+eval-lift-sum
38983942 eval-map1-appv
38993943 eval-map1-cons
39003944 eval-sequence
@@ -3908,6 +3952,9 @@
39083952 若特定对象语言操作使用非本机实现(@5.2.1) ,可使用其它续延。
39093953 上述名称中部分名称和 klisp 0.3 中作用近似的续延的名称一致,功能近似。
39103954 不一致的名称包括:
3955+equal-subterm :Forms::EqualTermValue(@8.4.1) 比较直接子项。
3956+equal-siblings :Forms::EqualTermValue 比较同一个项中的剩余其它子项。
3957+因为 klisp 的 equal? 直接使用自动机实现,在比较操作中没有对应的续延。
39113958 eval-acc-head-next :Forms::AccL 和 Forms::AccR(@8.4.9) 公共操作后分派的不同操作。
39123959 eval-acc-nested :Forms::AccL 和 Forms::AccR(@8.4.9) 嵌套调用抽象列表余下的元素的公共操作。
39133960 eval-accl-accl :Forms::AccL 递归调用。
@@ -3925,7 +3972,7 @@
39253972 eval-sequence-return :非 TCO 的 A1::ReduceOrdered(@7.4.6) 实现中设置规约合并最后的返回结果。
39263973 eval-tail :TCO 动作尾上下文求值(和 klisp 不同,不依赖 GC(@5.2.4.4) 而在 TCO 动作单独保存资源(@7.10.4.1) )。
39273974 eval-vau :求值过程抽象(@8.4.5) 在带环境的函数构造器中作为续延。
3928-注意 klisp 的 $vau 不含保证被求值的操作数,不需要异步调用,没有对应的续延。
3975+注意 klisp 的 $vau 不具有应保证被求值的实际参数,不需要异步调用,没有对应的续延。
39293976 load-external :A1::RelayToLoadExternal(@8.5.2) 加载外部翻译单元。
39303977 match-ptree-recursive :支持延迟递归绑定( Forms::DefineWithRecursion 和 Forms::SetWithRecursion(@8.4.4.3) )。
39313978
@@ -4014,9 +4061,16 @@
40144061 这些操作中的一部分可能通过不同的顺序和依赖关系在非本机实现中派生。
40154062
40164063 @8.4.1 内建谓词:
4017-函数 Forms::EqualLeaf 比较项中的值数据成员(@5.4.2) 相等。
4018-函数 Forms::EqualReference 和 Forms::EqualValue 分别支持通过引用和值分别比较。前者对引用值的判断满足 @4.2.3 的相等关系,其结果是准确的。除此之外,两者的语义接近 [RnRS] 的 eq? 和 eqv? 。
4019-基于 YSLib::GHEvent ,上下文处理器(@7.6.1) 对未支持 == 比较的函数对象提供默认的相等实现,相同类型的函数对象的值视为恒等。
4064+Forms 提供以下实现谓词(@4.1.4) 的函数:
4065+Forms::EqLeaf :比较项中的值数据成员(@5.4.2) 相等。
4066+Forms::EqReference
4067+对引用值的判断满足引用(@4.2.3) 的相等关系,其结果是准确的。
4068+语义接近 [RnRS] 的 eq? 。
4069+Forms::EqValue
4070+语义接近 [RnRS] 的 eqv? 。
4071+Forms::EqualTermValue
4072+以上通过值的比较基于 YSLib::GHEvent 的相等。
4073+上下文处理器(@7.6.1) 对未支持 == 比较的函数对象提供默认的相等实现,相同类型的函数对象的值视为恒等。
40204074 若需改变行为,需补充 operator== 。
40214075
40224076 @8.4.2 分支和逻辑操作:
@@ -4038,6 +4092,7 @@
40384092 Forms::FirstAt
40394093 Forms::FirstRef
40404094 Forms::FirstVal
4095+Forms::RestVal
40414096 Forms::SetFirst
40424097 Forms::SetFirstAt
40434098 Forms::SetFirstRef
@@ -4048,7 +4103,7 @@
40484103 Forms 提供环境相关的操作,以支持对象语言中的环境(参见 @9.9.3 )。
40494104
40504105 @8.4.4.1 求值操作:
4051-Forms 提供以下函数实现对象语言中的求值:
4106+Forms 提供以下函数实现对象语言中的求值(@5.11.1) :
40524107 Forms::Eval
40534108 Forms::EvalRef
40544109 Forms::EvalString
@@ -4140,6 +4195,7 @@
41404195 @8.4.7 错误检查:
41414196 Forms 提供以下可能抛出异常的错误检查函数:
41424197 Forms::CheckEnvironment
4198+Forms::CheckParent
41434199 Forms::CheckListReference
41444200
41454201 @8.4.8 封装类型操作:
@@ -4304,6 +4360,7 @@
43044360 <applicative> :应用子(@4.5.3.2) 。
43054361 <predicate> :谓词,是应用操作数的求值结果的值为 <test> 的 <applicative> 。通常实现结果为 <bool> 的纯求值(@4.4.2) 。
43064362 <environment> :一等环境(@9.9.3) 。
4363+<parent> :指定环境的父环境(@5.4.3) 的值,包括 <environment> 或元素为 <environment> 的 <list> 。
43074364 <string> :字符串,宿主值类型为 string(@5.6.1) 。
43084365 字符串(包括字符串字面量求值的结果)以 string 类型表示,编码和表示要求同 YFramework 默认约定([Documentation::YFramework @@3.3.1]) 。
43094366
@@ -4316,6 +4373,7 @@
43164373 针对这个假设,派生实现可进行附加的语义检查。在 NPLA1 的当前实现(特别地,使用绑定支持 API(@7.7.4) )中,没有这样的检查。
43174374 这实质等价使用 [Shu09] 中的记法,即 <formals> 用于除和 [Shu09] 的 $define! 类似外的所有操作(包括 $set! 和 $let 等,而不论是否对应 <body> )。这些上下文中总是隐含了上述的可派生实现的要求。
43184375 和 [RnRK] 不同,<body> 不蕴含顺序求值子项。
4376+为对 <environment> 和 <parent> 进行类型检查(@9.5.4.1) 取得环境强引用(@5.4.3) 时,可附带进行内部的检查(@9.5.4) 确保 shared_ptr<Environment>(@5.6.2) 类型的宿主值非空。
43194377
43204378 @9.3 对象语言语法:
43214379 基于 NPLA 基本语法约定参见 NPLA 约定(@5.2) 。
@@ -4403,7 +4461,7 @@
44034461 保留可能无效的间接值(@9.4.4) :
44044462 保留可能无效的引用值(@9.4.3.2) ;
44054463 保留可能无效的环境引用。
4406-可能因为操作环境强引用而引入循环引用(@9.9.1.1) ;
4464+可能因为操作环境强引用(@5.4.3) 而引入循环引用(@9.9.1.1) ;
44074465 可能引入数据竞争(@5.2.4.3) ;
44084466 是其它另行指定的可能引入未定义行为的操作。
44094467 当前对象语言不支持并发访问对象。数据竞争仅可由和宿主语言的互操作(@5.2.4) 引入。
@@ -4477,7 +4535,7 @@
44774535 部分实体从属于其它实体类型而构成子类型(subtyping) 关系;部分的规约操作取得求值结果保证结果中的值可能具有的特定类型集合,这些类型也一并在以下描述中给出;其它情形不指定类型。
44784536 规约预期符合约束。若违反由项的值对应的动态类型(@5.5) 不匹配导致,则求值失败;否则,行为未指定。
44794537 除非另行指定,不同类型检查的作用的顺序未指定。
4480-类型检查失败引发错误(@9.5.1) ,称为类型错误(type error) 。
4538+类型检查失败引发错误对象(@9.5.1) ,称为类型错误(type error) 。
44814539
44824540 @9.6 外部表示:
44834541 同 @4.1.1 ,外部表示由派生实现约定。
@@ -4553,7 +4611,7 @@
45534611 由 <test>(@9.2.2.1) 控制或连续求值多个表达式中最后被求值的子表达式求值,包括 $if(@11.3.3) 、$sequence(@11.4.1) 、$and?(@11.4.1) 和 $or?(@11.4.1) ;
45544612 函数 eval(@11.3.7) 、eval%(@11.3.7) 、$quote(@11.4.1) 、id(@11.4.1) 、idv(@11.4.1) 、eval-string(@12.1) 和 eval-string%(@12.1) 对 <expression> 的求值或替换;
45554613 函数 apply(@11.4.1) 对 <applicative> 和 <object> 在 <environment> 或默认的动态环境中的应用;
4556-函数 accl(@11.4.1) 、map-reverse(@11.4.2) 和 for-each-ltr(@11.4.2) 蕴含的尾上下文的递归调用。
4614+函数 accl(@11.4.1) 、map-reverse(@11.4.3) 和 for-each-ltr(@11.4.3) 蕴含的尾上下文的递归调用。
45574615
45584616 @9.7.4.2 支持 PTC 的非调用尾上下文:
45594617 通过环境(@9.9.3) 支持的名称解析(@5.4.3) 的实现在符合嵌套调用安全的约定(@6.1) 。
@@ -4565,7 +4623,7 @@
45654623 当前通过参考实现环境(@10) 引入的合并子已经支持了保存操作数,但若互操作(@5.2.1) 没有保存操作数,则可能产生问题。
45664624 应注意合并子的参数绑定引用值(@7.7.3) 在同一个尾上下文求值引起清理导致悬空引用(@9.4.3.2) 破坏内存安全(@9.4) 。
45674625 这里的求值典型地可通过显式求值引入。具体地,这主要包含使用引用值作为函数 eval 或 eval%(@11.3.7) 的参数的进行函数应用表达式求值的方式。
4568-对合并子的直接的函数调用求值较不容易引起这种情形,因为 <body> 内使用的参数是被绑定的,其中临时对象(@5.2.4.2) 即便传递引用也会被转移值(@7.7.3) 。悬空引用通过其它方式(如在合并子的动态环境内显式求值)才被直接引入。
4626+对合并子的直接的函数调用求值较不容易引起这种情形,因为 <body> 内使用的参数是被绑定的,其中临时对象(@5.5.6) 即便传递引用也会被转移值(@7.7.3) 。悬空引用通过其它方式(如在合并子的动态环境内显式求值)才被直接引入。
45694627 考虑在调用前使用总是不保留引用值(@10.4.3) 的 list 和 list* 而不是保留引用值(@10.4.3) 的 list% 和 list*%(@11.4.1) ,或单独调用 idv(@11.4.1) 提升被传递项中的值避免此类问题。
45704628
45714629 @9.7.4.4 限制影响:
@@ -4639,7 +4697,7 @@
46394697 @9.8.7 类型分类:
46404698 和 Kernel 不同,NPLA1 不要求支持任意类型的不相交集合即分区(partition) 。
46414699 这避免假定类型全集,并开放类型映射(@5.2.3) 。但基于实体文法(@9.2.2) 引入的类型仍被分区。
4642-和 Kernel 不同,NPLA1 的类型判断谓词是一元谓词,只接受一个参数(@4.6.2.5) ,以强调语言提供的接口的正交性(@1.4.2.4) 。这也避免对 map(@11.4.2) 等库函数的依赖。
4700+和 Kernel 不同,NPLA1 的类型判断谓词是一元谓词,只接受一个参数(@4.6.2.5) ,以强调语言提供的接口的正交性(@1.4.2.4) 。这也避免对 map(@11.4.3) 等库函数的依赖。
46434701 和 Kernel 不同,列表类型只包括真列表(@9.9.4) 。列表节点的实现的表示详见 @5.4.2.1 。
46444702
46454703 @9.9 对象语言数据结构:
@@ -4650,7 +4708,7 @@
46504708 @9.9.1 引用:
46514709 NPLA1 基于 NPLA 项的引用(@5.6.3) 支持实体的左值引用(@5.7.6.1) ,和 Kernel 等的引用概念类似。
46524710 NPLA1 语义中对广义实体(@2.3.4) 的构成依赖的使用也被称为引用,这不限被对象语言中的引用值表达。另见环境引用(@5.4.3) 。
4653-和 Kernel 不同,NPLA1 明确允许不通过对象的引用保存对象(参见 @9.9.3 ),但是也允许使用对象引用;即对象和对象的引用都是一等对象(@4.1) 。详见 @4.2 。这也允许子对象直接被所在的对象蕴含。
4711+和 Kernel 不同,NPLA1 明确允许不通过对象的引用保存对象(参见 @9.9.3 ),但是也允许使用对象引用;即对象和对象的引用都可作为一等对象(@4.1) 。详见 @4.2 。这也允许子对象直接被所在的对象蕴含。
46544712 使用项引用(宿主类型为 NPL::TermReference )表示(使用 TermNode 表示的)其它对象的引用,即引用值(@5.5.4) 。
46554713 按 NPL::TermReference 初始化时保存的引用来源可区分被引用的对象是否是左值。
46564714 左值(@5.5.1) 都通过引用值(参见 @5.7.6.1 ;另见 @4.1 和 @5.2.4 )表示。
@@ -4781,7 +4839,7 @@
47814839
47824840 @9.9.6 数值:
47834841 NPLA1 不要求支持数值计算。数值类型和相关的操作由派生类型提供。
4784-和 Kernel 不同,NPL 不提供依赖数值的接口(用于描述列表长度等);核心库函数(@11.4.2) 的实现也不需要依赖数值。
4842+和 Kernel 不同,NPL 不提供依赖数值的接口(用于描述列表长度等);核心库函数(@11.4.3) 的实现也不需要依赖数值。
47854843
47864844 @9.10 实现注记:
47874845 NPLA1 中提供的一些名称以及实现架构和 klisp 相似,且都为 AST 解释器,但实现方式略不同。
@@ -4934,7 +4992,7 @@
49344992 @10.5.4 函数值转发:
49354993 一些其它保留引用值的操作中,引用值来自参数,且难以通过自身的逻辑单独决定可否安全地直接返回引用值。
49364994 此时,在返回之前根据特定参数是否为引用值,可选地转换结果以确定是否保留引用值,即进行转发。
4937-显式转发临时对象(@5.2.4.2) 的引用值(@5.5.4) 使临时对象被转移,以转发的值作为返回值,可不同于使用返回值转换(@5.7.6.4) :
4995+显式转发临时对象(@5.5.6) 的引用值(@5.5.4) 使临时对象被转移,以转发的值作为返回值,可不同于使用返回值转换(@5.7.6.4) :
49384996 同返回值转换,转发转移右值,复制左值;但当转发临时对象可确定唯一使用时,也转移临时对象(实现参见 @5.6.3.4 )。
49394997 确定是否保留引用值的机制类似 ISO C++14 中从没有括号的 id-expression 上推断返回 decltype(auto) 类型是否为引用类型。
49404998 函数值转发使某些操作在默认情况下满足间接值生存期规则而保持内存安全,符合适用性原则(@1.4.5.2) 。
@@ -4979,6 +5037,7 @@
49795037 除非另行指定,若函数合并(@4.5.3) 指定的操作的约束(@9.2) 或要求检查(@9.5.4) 的条件不被满足,引起错误(@9.5.1) 。
49805038 除非另行指定,引起错误抛出异常(@9.5.2) 。
49815039 求值时引起的错误使求值中断可产生副作用,这样的副作用总是后序(@4.4.1) 于已被求值的表达式中产生的副作用。
5040+被错误处理和检查的函数不修改参数或者函数调用外创建的对象。
49825041
49835042 @10.6.5 非常规函数:
49845043 不符合常规函数约定的例外的一个例子是续延(@4.5.2.1) 。非常规函数归类为对象而非操作(@10.3.1) ,但调用时候错误处理同常规函数(@10.6.4) 。
@@ -5084,7 +5143,7 @@
50845143 可保留参数中的引用值(@9.4.4) 并在返回值中保留;
50855144 不提供避免保留值的对应操作,或仅在此基础上提供总是包含等价返回值转换(@10.4.2) 的对应操作。
50865145 否则,这些操作不返回引用值。
5087-这些操作不会使用临时对象(@5.2.4.2) 作为环境,所以不需要使用以引用标记字符结尾的变体要求注意区分返回引用值而避免误用。
5146+这些操作不会使用临时对象(@5.5.6) 作为环境,所以不需要使用以引用标记字符结尾的变体要求注意区分返回引用值而避免误用。
50885147 因此,不提供区分涉及引用的变体,这也使接口设计更清晰。
50895148 这些操作包括以下小节的情形。
50905149 部分操作涉及参数转发(@10.5.2) 和函数值转发(@10.5.4) 。这些操作不包含可提供以引用标记字符结尾变体的操作中的个别变体(@10.7.2) 。
@@ -5194,7 +5253,7 @@
51945253 除非是语义蕴含的操作结果或另行指定,所有作为函数值的操作(@10.3.1) 的结果(@4.4.3.1) 是未指定值(@7.2.2) 。另见函数名称约定(@10.7) 。
51955254 未指定值可等于 #inert(@9.3.1) 或其它值,但满足忽略值时不引起可观察行为(@4.1.3) 的改变(这排除了引入 volatile 类型或非平凡析构的宿主值)。
51965255 若操作(@10.3.1) 在 Kernel 或 klisp 中存在结果为 #inert 的对应的操作,且未指定作为函数值的结果,则返回等于 #inert 的右值。
5197-除非显式指定,空环境没有父环境。
5256+除非显式指定,空环境没有父环境(@9.9.3) 。
51985257 约定的接口通过绑定在根环境中的名称提供,参见以下各节。
51995258 这些名称可能是本机实现(@5.2.1) ,即直接调用 NPLA 或 NPLA1 API(参见 @6 、@7 和 @8 )绑定定义;也可能是非本机的派生的(derive) 实现,即通过在当前的基础上求值特定的对象语言代码引入(其实现最终依赖本机实现)。
52005259 变量的绑定(@4.1) 的引入是否由本机实现未指定。
@@ -5206,7 +5265,7 @@
52065265
52075266 @10.9.1 函数实现约定:
52085267 名称使用 $def 起始的函数用于在当前环境引入绑定。
5209-需引入绑定时,优先使用核心库(@11.4.2) 中的函数;当使用这些函数并不能简化实现时,使用 $def!(@11.3.7) 。
5268+需引入绑定时,优先使用核心库(@11.4.3) 中的函数;当使用这些函数并不能简化实现时,使用 $def!(@11.3.7) 。
52105269 除以下例外,优先使用函数名中不带有 % 及 %! 结尾的函数:
52115270 当实现操作的语义要求时;
52125271 调用的结果明确是非引用值(此时是否使用带有 % 的函数的效果应一致)。
@@ -5221,6 +5280,7 @@
52215280 @10.9.3 操作实现注记:
52225281 派生实现不依赖非真合并子(@9.9.5) ,因此以合并子实现操作时,其中不使用分隔符(@9.7.1) ,也不需要实现在初始化(@10.1.1) 时支持中缀变换(@7.5.2) 。
52235282 但是,不同操作之间的定义可能使用分隔符。因为不需依赖 $sequence(@11.4.1) ,这种实现也更简单。
5283+除非另行指定,当前实现中,操作引发错误对象(@9.5.2) 以抛出异常实现(@10.6.4) ,涉及具体的异常类型未指定。
52245284
52255285 @11 NPLA1 根环境特性(@10.2) :
52265286 本章指定在根环境(@10.1) 提供的 NPLA1 标准库特性(@10.3.3) 。
@@ -5238,12 +5298,12 @@
52385298 @11.1.1 在返回值中保留环境引用的操作(@10.8.2) :
52395299 包括基本操作(@11.3.7) :
52405300 make-environment
5241-包括派生操作(@11.4.1) :
5242-make-standard-environment
5243-derive-current-environment
5244-derive-environment
5245-$provide!
5246-$provide/let!
5301+包括派生操作:
5302+make-standard-environment(@11.4.1) :
5303+derive-current-environment(@11.4.3)
5304+derive-environment(@11.4.3)
5305+$provide!(@11.4.3)
5306+$provide/let!(@11.4.3)
52475307
52485308 @11.1.2 在返回值中保留其它间接值的操作(@10.8.3) :
52495309 包括:
@@ -5291,21 +5351,21 @@
52915351 list%(@11.4.1)
52925352 list*(@11.4.1)
52935353 list*%(@11.4.1)
5294-box(@11.4.2)
5295-box%(@11.4.2)
5354+box(@11.4.3)
5355+box%(@11.4.3)
52965356
52975357 @11.2.1.2 可能使结果包含引用值的容器元素访问器(@10.7.2.2) :
52985358 包括:
52995359 first(@11.4.1)
53005360 first&(@11.4.1)
53015361 first@(@11.4.1)
5302-restv(@11.4.2)
5303-rest&(@11.4.2)
5304-rest%(@11.4.2)
5362+restv(@11.4.3)
5363+rest&(@11.4.3)
5364+rest%(@11.4.3)
53055365 因为正规表示(@5.9.4) 的限制,restv 、rest& 和 rest% 重新构造列表,并不直接返回子对象(@9.8.2) ;其它访问器若带有引用标记字符,可直接返回引用值。
53065366 此外,@11.2.2.4 中部分函数也符合容器元素访问器的要求,但当前不提供带有后缀标记字符的变体。这些函数包括:
53075367 unwrap(@11.3.8)
5308-unbox(@11.4.2)
5368+unbox(@11.4.3)
53095369
53105370 @11.2.1.3 可能使对象中包含引用值的修改操作(@10.7.2.3) :
53115371 简单赋值,包括:
@@ -5322,9 +5382,9 @@
53225382 @11.2.1.4 可能间接保留引用值的操作(@10.7.2.4) :
53235383 以求值 <body> 作为尾上下文的操作,包括:
53245384 结果是合并子或用于在环境中绑定合并子的构造器操作;
5325-以及核心库函数(@11.4.2) 中的绑定操作;
5385+以及核心库函数(@11.4.3) 中的绑定操作;
53265386 以求值 <expression> 作为尾上下文的函数,包括 eval 和 eval%(@11.3.7) 。
5327-参见环境基本操作(@11.3.7) 和核心库(@11.4.2) 。
5387+参见环境基本操作(@11.3.7) 和核心库(@11.4.3) 。
53285388 以上操作中的求值符合词法闭包(@4.6.1.1.2) 规则,可使用 A1::RelayForEval 或 A1::RelayForCall(@7.7.2) 实现。
53295389
53305390 @11.2.2 不提供结尾 % 或 & 对应变体(@10.7.3) 的函数:
@@ -5341,8 +5401,8 @@
53415401 $or?(@11.4.1)
53425402
53435403 @11.2.2.2 返回非引用值的操作(@10.7.3.2) :
5344-这些返回值总是按值传递的操作涉及的容器包括列表、箱(@11.4.2) 或其它的封装类型(@11.3.10) 对象。
5345-包括核心库函数(@11.4.2) :
5404+这些返回值总是按值传递的操作涉及的容器包括列表、箱(@11.4.3) 或其它的封装类型(@11.3.10) 对象。
5405+包括核心库函数(@11.4.3) :
53465406 map1
53475407 list-concat
53485408 append
@@ -5350,12 +5410,12 @@
53505410 @11.2.2.3 直接参数转发操作(@10.7.3.3) :
53515411 包括合并子基本操作(@11.3.8) :
53525412 unwrap
5353-包括核心库函数(@11.4.2) :
5413+包括核心库函数(@11.4.3) :
53545414 accl
53555415 accr
53565416 foldr1
53575417 map1
5358-核心库函数(@11.4.2) 中的绑定操作的非 <environment> 的形式参数支持转发。
5418+核心库函数(@11.4.3) 中的绑定操作的非 <environment> 的形式参数支持转发。
53595419 注意 map1 同时返回非引用值(@11.2.2.2) 。
53605420 参数形式上被转发但操作的语义并非总是转发到其它操作的操作不使用本节的名称约定,如以下仅有第二参数支持转发的操作是提供结尾 % 或 & 对应名称的函数(@11.2.1) ,有对象基本操作(@11.3.4) 中的:
53615421 assign%!
@@ -5366,7 +5426,7 @@
53665426 unwrap(@11.3.8)
53675427 id(@11.4.1)
53685428 forward(@11.4.1)
5369-unbox(@11.4.2)
5429+unbox(@11.4.3)
53705430 基本操作(@11.3) 的不具有名称的相关操作中参数和函数值原生支持的转发操作包括:
53715431 使用 make-encapsulation-type(@11.3.10) 返回的访问器合并子。
53725432
@@ -5465,10 +5525,12 @@
54655525 reference? <object> :判断操作数是否为引用值。
54665526 uncollapsed? <object> :判断操作数是否为未折叠的引用值。
54675527 bound-lvalue? <object> :判断操作数是否为被引用的被绑定对象左值。
5468-绑定临时对象(@5.2.4.2) 的引用类型的参数不被视为左值引用。
5528+绑定临时对象(@5.5.6) 的引用类型的参数不被视为左值引用。
54695529 配合 $resolve-identifier(@11.3.7) 和 % 引用标记(@7.7.3.4) 绑定的变量,可确定实际参数是否为左值。
54705530 单独使用 bound-lvalue? 和 & 引用标记字符(@7.7.3.4) 绑定的变量,可确定实际参数是否为引用。
54715531 unique? <object> :判断操作数是否为唯一引用(@5.4.2.2) 。
5532+modifiable? <object> :判断操作数是否为可修改对象或可修改对象的引用值。
5533+temporary? <object> :判断操作数是否为临时对象或临时对象的引用值。
54725534 deshare <object> :取指定对象取消共享的值。
54735535 同 idv(@11.4.1) ,但显式提升操作数中具有共享持有者的值数据成员(@5.4.2) ,且不转移宿主值。
54745536 因为提供在返回值中保留其它间接值的操作(@11.1.2) ,这个区别是必要的。否则,使用 idv 替代应不影响可观察行为(@4.1.3) 。
@@ -5527,7 +5589,7 @@
55275589 和 $resolve-identifier 类似,但直接取被绑定的对象并从环境中转移。
55285590 若环境被冻,则复制绑定的对象所在的项;否则,直接转移对象的项(@5.5.3) 。
55295591 一般应仅用于被绑定的对象不需要再被使用时。
5530-() copy-environment :递归复制当前环境。当前忽略父环境中的环境列表(@5.4.3) 。
5592+() copy-environment :递归复制当前环境。当前忽略父环境(@9.9.3) 中的环境列表(@5.4.3) 。
55315593 结果为新创建的环境,具有宿主值类型 shared_ptr<Environment> 。
55325594 使用类似 @5.4.3 的 DFS 搜索操作数的父环境和绑定的对象,若非环境则直接复制值,否则创建环境并递归使用 DFS 复制值。
55335595 当前只支持复制具有 shared_ptr<Environment> 和 EnvrionmentReference 的宿主值的环境,其它对象直接视为非环境对象。
@@ -5568,13 +5630,12 @@
55685630 @11.3.8 合并子:
55695631 和 Scheme 及 Kernel 不同,<body> 可以是多个项,而不在派生另外的变体支持顺序求值。
55705632 引入合并子的操作子不求值 <body> ,后者在被调用时替换操作数以后被求值。这允许安全地使用 $def! 而不需要 $defrec! 进行递归绑定(@11.3.7) 。
5571-创建合并子时对参数指定的求值环境 <environment> 进行类型检查(@9.5.4.1) 外,还进行内部的检查确保宿主值非空。
55725633 检查失败的错误(@9.5.1) 是(可能依赖(@9.5.1) 类型错误(@9.5.4.1) 的)语法错误(@9.5.1) 。
5573-$vau/e <environment> <formals> <eformal> <body> :创建指定静态环境的 vau 抽象(@4.5.2.3) 。
5634+$vau/e <parent> <formals> <eformal> <body> :创建指定静态环境的 vau 抽象(@4.5.2.3) 。
55745635 创建的对象是操作子(@7.6.1.1) 。
55755636 和 Kernel 不同,因为支持保存环境的所有权,$vau/e 被设计为比 $vau 更基本的操作。
55765637 不考虑所有权时,eval(@11.3.7) 和 $vau 可派生 $vau/e 。
5577-$vau/e% <environment> <formals> <eformal> <body> :同 $vau/e ,但保留引用值。
5638+$vau/e% <parent> <formals> <eformal> <body> :同 $vau/e ,但保留引用值。
55785639 wrap <combiner> :包装(@4.5.3.2) 合并子为应用子(@7.6.1.1) 。
55795640 包装应用子可能符合包装数溢出的错误条件(@9.9.5) 。
55805641 wrap% <combiner> :同 wrap ,但参数不隐含左值到右值转换,在结果保留引用值。
@@ -5583,9 +5644,9 @@
55835644
55845645 @11.3.9 错误处理和检查:
55855646 raise-invalid-syntax-error <string> :引发包含参数指定的字符串内容的语法错误(@9.5.1) 。
5586-当前实现中引发的错误对象以抛出异常实现,其中异常对象类型具有 public 基类 NPL::InvalidSyntax 。
5647+实现引发错误对象(@10.9.3) 的异常对象类型具有 public 基类 NPL::InvalidSyntax 。
55875648 check-list-reference <object> :检查对象是否是列表引用,若检查通过返回参数,否则引发错误对象(@9.5.1) 。
5588-当前实现中引发错误对象以抛出异常实现,其中异常对象类型是 NPL::ListTypeError(@6.3) 或 NPL::ValueCategoryMismatch(@6.3) 。
5649+实现引发错误对象的异常对象类型是 NPL::ListTypeError(@6.3) 或 NPL::ValueCategoryMismatch(@6.3) 。
55895650
55905651 @11.3.10 封装:
55915652 () make-encapsulation-type :创建封装类型。
@@ -5616,7 +5677,7 @@
56165677 @11.4.1 基本派生特性(basic derived feature) :
56175678 引入合并子的操作子对 <body> 的约定同 @11.3.8 。
56185679 因互相依赖,一些操作实现为派生操作时,不能用于直接派生特定一些其它操作。
5619-和 $vau/e 或 $vau/e%(@11.3.8) 以及 $lambda/e 或 $lambda/e%(@11.4.2) 不同,不指定静态环境的合并子构造器隐含总是使用环境弱引用(@5.4.3) 形式的静态环境,以避免过于容易引入循环引用(@9.9.1.1) 。另见环境数据结构(@5.4.3) 。
5680+和 $vau/e 或 $vau/e%(@11.3.8) 以及 $lambda/e 或 $lambda/e%(@11.4.3) 不同,不指定静态环境的合并子构造器隐含总是使用环境弱引用(@5.4.3) 形式的静态环境,以避免过于容易引入循环引用(@9.9.1.1) 。另见环境数据结构(@5.4.3) 。
56205681 () get-current-environment :取当前环境:取当前环境的环境弱引用。
56215682 结果具有宿主值类型 NPL::EnvironmentReference 。派生需要非派生实现的 vau/e 。
56225683 () lock-current-environment :锁定当前环境:取当前环境的环境强引用。
@@ -5636,21 +5697,21 @@
56365697 list% <object>... :同 list ,但每个参数都不隐含左值到右值转换,在结果保留引用值。
56375698 $deflazy! <definiend> <body> :修改绑定。
56385699 同 $def! ,但不求值参数;在添加绑定前仍对冻结环境进行检查(@11.3.7) 。
5639-$set! <environment> <formals> <body> :修改指定环境的变量绑定。
5700+$set! <parent> <formals> <body> :修改指定环境的变量绑定。
56405701 在当前环境求值 <environment> 和 <body> ,再以后者的求值结果修改前者的求值结果指定的环境中的绑定。绑定效果同使用 $def!(@11.3.7) 。
56415702 类似 Kernel 的 $set! 。注意 <body> 的形式不同。允许的递归操作参见 $def! 。
56425703 和 Kernel 不同而和 NPLA1 的 $def! 等类似,在修改绑定前对冻结环境进行检查。
5643-$setrec! <environment> <formals> <body> :修改指定环境的绑定,绑定效果同使用 $defrec!(@11.3.7) 。
5704+$setrec! <parent> <formals> <body> :修改指定环境的绑定,绑定效果同使用 $defrec!(@11.3.7) 。
56445705 同 $set! ,但允许不同的递归操作,参见 $defrec! 。
56455706 $lambda <formals> <body> :创建 λ 抽象(@4.5.2.2) 。
56465707 和创建 vau 抽象类似,但创建的是调用时对操作数的元素求值一次的应用子(@7.6.1.1) ,且忽略动态环境。
5647-可通过 vau 抽象或 $lambda/e(@11.4.2) 和(非派生的)get-current-environment 派生。
5708+可通过 vau 抽象或 $lambda/e(@11.4.3) 和(非派生的)get-current-environment 派生。
56485709 表达式项的用法和 vau 抽象类似。
56495710 $lambda% <formals> <body> :同 $lambda ,但允许函数体求值返回引用值。
56505711 $sequence <expression-sequence> :顺序求值。
56515712 操作数非空时结果是最后的参数,可能是引用值。
56525713 类似 Kernel 的同名操作。
5653-求值每个 <object> 的副作用包括其中临时对象(@5.2.4.2) 的销毁都被顺序限制,类似宿主语言的语句而不是保证子表达式中的临时对象的生存期延迟到完全表达式求值结束的逗号表达式。这也允许实现和 [RnRK] 同名操作类似的 PTC 要求。
5714+求值每个 <object> 的副作用包括其中临时对象(@5.5.6) 的销毁都被顺序限制,类似宿主语言的语句而不是保证子表达式中的临时对象的生存期延迟到完全表达式求值结束的逗号表达式。这也允许实现和 [RnRK] 同名操作类似的 PTC 要求。
56545715 collapse <object> :折叠可能是引用的值。
56555716 forward <object> :转发(@10.5.4) 可能是引用的值(@11.2.2.4) 。
56565717 按在所在的环境中解析的操作数的类型可选地提升项(@6.6) 作为结果,其作用 id 或 idv 之一。
@@ -5694,10 +5755,14 @@
56945755 否则,同 eqv? 且每个子节点对应满足 eqv?(蕴含节点数量相等)。
56955756 类似 Kernel 和 Scheme 的 equal? 的二元谓词,但在此保证可通过 eqv? 直接构造。:
56965757 因为列表的性质(@9.9.4) ,不需要支持循环引用(@9.9.1.1) ,可以直接派生。后者被视为基本的抽象而非实现细节。
5697-check-environment <environment> :检查环境。
5758+check-environment <object> :检查环境(@9.9.3) 。
5759+若参数是 <environment> 则检查通过,结果是转发的参数;
5760+否则,引发错误对象。
5761+check-parent <object> :检查作为环境的父环境(@9.9.3) 的对象。
5762+若参数是可以作为合并子环境的 <parent> 则检查通过,结果是转发的参数;
5763+否则,引发错误对象。
56985764 检查环境通过的条件同创建合并子时的检查(@11.3.8) 。
5699-若检查通过,返回转发的参数,否则引发错误(@9.5.1)。
5700-引发的错误对象和创建合并子时环境检查失败引发的错误对象,或其依赖(@9.5.1) 的错误对象(后者保证不是语法错误(@7.8.2) )。
5765+引发的错误对象(@9.5.2) 同创建合并子时环境检查失败引发的错误对象,或其依赖(@9.5.1) 的错误对象(后者保证不是语法错误(@7.8.2) )。
57015766 $cond <clauses> :条件选择。
57025767 类似 Kernel 的同名操作,但 <test> 的判断条件和 <body> 形式不同。
57035768 $when <test> <expression-sequence> :条件成立时顺序求值。
@@ -5729,8 +5794,16 @@
57295794 参数 <applicative> 应接受一个参数,否则引起错误(@9.5.1) 。
57305795 任意两个调用之间的相对求值顺序未指定。
57315796 类似 Kernel 的 map ,但只接受一个真列表(@9.9.4) 。
5732-
5733-@11.4.2 核心库(core library) :
5797+first-null? <list> :复合 first 和 null? 操作。可用于实现 nonfoldable? 的检查中的单个项。
5798+() make-standard-environment :创建标准环境:创建没有基础环境绑定外其它绑定的环境。
5799+新创建环境的唯一父环境是基础环境(@10.1) 。类似 Kernel 的 make-standard-kernel-environment 。
5800+
5801+@11.4.2 标准派生特性(standard derived feature) :
5802+同基本派生特性(@11.4.1) ,但其派生依赖标准库其它模块(@11) 。
5803+ensigil <symbol> :向非空的没有 & 前缀的符号添加 & 引用标记字符。
5804+结果为添加字符作为前缀的参数。
5805+
5806+@11.4.3 核心库(core library) :
57345807 本节约定以下求值得到的操作数:
57355808 <box> :箱(@4.2.3.5.3) 。
57365809 核心库提供以下操作,即核心库函数:
@@ -5738,21 +5811,19 @@
57385811 $defl%! <variable> <formals> <body> :绑定 λ 抽象,等价 $def! <variable> $lambda% <formals> <body> 。
57395812 $defv! <variable> <formals> <eformal> <body> :绑定 vau 抽象,等价 $def! <variable> $vau <formals> <eformal> <body> 。
57405813 $defv%! <variable> <formals> <eformal> <body> :绑定 vau 抽象,等价 $def! <variable> $vau% <formals> <eformal> <body> 。
5741-$defv/e! <variable> <environment> <formals> <eformal> <body> :绑定指定静态环境的 vau 抽象,等价 $def! <variable> $vau/e <environment> <formals> <eformal> <body> 。
5742-$defv/e%! <variable> <environment> <formals> <eformal> <body> :绑定指定静态环境的 vau 抽象,等价 $def! <variable> $vau/e% <environment> <formals> <eformal> <body> 。
5814+$defv/e! <variable> <parent> <formals> <eformal> <body> :绑定指定静态环境的 vau 抽象,等价 $def! <variable> $vau/e <parent> <formals> <eformal> <body> 。
5815+$defv/e%! <variable> <parent> <formals> <eformal> <body> :绑定指定静态环境的 vau 抽象,等价 $def! <variable> $vau/e% <parent> <formals> <eformal> <body> 。
57435816 $defw! <variable> <formals> <eformal> <body> :绑定 wrap 的 vau 抽象,等价 $def! <variable> wrap ($vau <formals> <eformal> <body>) 。
57445817 $defw%! <variable> <formals> <eformal> <body> :绑定 wrap 的 vau 抽象,等价 $def! <variable> wrap ($vau% <formals> <eformal> <body>) 。
5745-$defw/e! <variable> <environment> <formals> <eformal> <body> :绑定 wrap 的指定静态环境的 vau 抽象,等价 $def! <variable> wrap ($vau/e <environment> <formals> <eformal> <body>) 。
5746-$defw/e%! <variable> <environment> <formals> <eformal> <body> :绑定 wrap 的指定静态环境的 vau 抽象,等价 $def! <variable> wrap ($vau/e% <environment> <formals> <eformal> <body>) 。
5747-$lambda/e <environment> <formals> <body> :同 $lambda ,但支持显式指定的求值环境作为静态环境。
5748-$lambda/e% <environment> <formals> <body> :同 $lambda/e ,但保留引用值。
5749-$defl/e! <variable> <environment> <formals> <body> :绑定指定静态环境的 λ 抽象,等价 $def! <variable> $lambda/e <environment> <formals> <body> 。
5750-$defl/e%! <variable> <environment> <formals> <body> :绑定指定静态环境的 λ 抽象,等价 $def! <variable> $lambda/e% <environment> <formals> <body> 。
5818+$defw/e! <variable> <parent> <formals> <eformal> <body> :绑定 wrap 的指定静态环境的 vau 抽象,等价 $def! <variable> wrap ($vau/e <parent> <formals> <eformal> <body>) 。
5819+$defw/e%! <variable> <parent> <formals> <eformal> <body> :绑定 wrap 的指定静态环境的 vau 抽象,等价 $def! <variable> wrap ($vau/e% <parent> <formals> <eformal> <body>) 。
5820+$lambda/e <parent> <formals> <body> :同 $lambda ,但支持显式指定的求值环境作为静态环境。
5821+$lambda/e% <parent> <formals> <body> :同 $lambda/e ,但保留引用值。
5822+$defl/e! <variable> <parent> <formals> <body> :绑定指定静态环境的 λ 抽象,等价 $def! <variable> $lambda/e <parent> <formals> <body> 。
5823+$defl/e%! <variable> <parent> <formals> <body> :绑定指定静态环境的 λ 抽象,等价 $def! <variable> $lambda/e% <parent> <formals> <body> 。
57515824 restv <list> :取列表第一个元素以外的元素值构成的列表。
57525825 rest& <list> :同 rest ,但在返回的列表值中的元素是引用值,且首先调用 check-list-reference 检查参数是列表引用,对右值的抛出异常。
57535826 rest% <list> :同 rest ,但在返回的列表值中的元素可能是传递的引用值。
5754-() make-standard-environment 创建标准环境:创建没有基础环境绑定外其它绑定的环境。
5755-新创建环境的唯一父环境是基础环境(@10.1) 。类似 Kernel 的 make-standard-kernel-environment 。
57565827 box <object> 装箱:构造箱(类型为 <box> 的对象)。
57575828 box% <object> 同 box ,但参数不隐含左值到右值转换,在结果保留引用值。
57585829 box? <object> 判断是否为 <box> 类型的对象。
@@ -5763,7 +5834,6 @@
57635834 和 http://community.schemewiki.org/?scheme-faq-language 关于装箱的描述不同,这样的代替不一定保证有更好的性能。
57645835 以上这些函数可使用 make-encapsulation-type(@11.3.10) 实现。
57655836 和 Scheme 等不同,箱具有被装箱对象的所有权,因此使用 box% 和 unbox 时,需注意保存被构造的箱或被箱中引用值引用的对象。
5766-first-null? <list> :复合 first 和 null? 操作。可用于实现 nonfoldable? 的检查中的单个项。
57675837 list-rest% <list> :复合 list% 和 rest% 操作。可用于解析 <bindings> ,去除其中每个元素的符号项构成新的列表。
57685838 list-concat <list1> <list2> :取顺序连接的列表。
57695839 append <list>... :顺序拼接列表。
@@ -5778,7 +5848,7 @@
57785848 derive-environment <environment>... :创建基础环境的派生环境。
57795849 创建参数指定的环境和基础环境作为父环境的空环境。
57805850 父环境顺序同参数顺序。基础环境是最后一个父环境。
5781-类似 make-standard-environment ,但具有参数指定的环境作为其它的父环境。
5851+类似 make-standard-environment(@11.4.1) ,但具有参数指定的环境作为其它的父环境。
57825852 $as-environment <body> :求值表达式构造环境。
57835853 创建以动态环境为父环境的空环境,并在其中求值参数指定的表达式。
57845854 结果是创建的环境强引用。
@@ -5787,11 +5857,11 @@
57875857 创建的环境同合并子的局部环境(@8.4.5) 。
57885858 $let% <bindings> <body> :同 $let ,但保留引用值。
57895859 当前派生使用 $lambda% 而不是 $lambda 实现。
5790-$let/e <environment> <bindings> <body> :指定静态环境并局部绑定求值。
5791-类似 Kernel 的 $let-redirect ,但使用 $lambda/e 而不是 eval 和 $lambda 实现,并返回非引用值。
5792-这允许传递引用值并保证环境的宿主值类型(包含所有权)被正确传递作为求值的父环境,而无需支持扩展 <environment> 为右值时其中的环境临时对象的生存期。
5793-注意此时 <environment> 中创建的环境对象在表达式求值后仍会因为 $lambda/e% 引入的合并子生存期结束而被销毁。
5794-$let/e% <environment> <bindings> <body> :同 $let/e ,但使用 $lambda/e% 而不是 $lambda/e 实现,保留引用值。
5860+$let/e <parent> <bindings> <body> :指定静态环境并局部绑定求值。
5861+类似 Kernel 的 $let-redirect ,但使用 $lambda/e 而不是 eval 和 $lambda 实现且支持 <parent> ,并返回非引用值。
5862+这允许传递引用值并保证环境的宿主值类型(包含所有权)被正确传递作为求值的父环境,而无需支持扩展 <parent> 中的环境为右值时其中的环境临时对象的生存期。
5863+注意此时 <parent> 中的环境中创建的环境对象在表达式求值后仍会因为 $lambda/e% 引入的合并子生存期结束而被销毁。
5864+$let/e% <parent> <bindings> <body> :同 $let/e ,但使用 $lambda/e% 而不是 $lambda/e 实现,保留引用值。
57955865 $let* <bindings> <body> :顺序局部绑定求值。
57965866 同 $let ,但 <bindings> 中的被用于绑定的表达式从左到右顺序求值,被用于初始化变量的表达式在求值时可访问 <bindings> 中之前绑定的符号。
57975867 类似 Kernel 的同名操作。
@@ -5811,7 +5881,7 @@
58115881 类似 Kernel 的 $provide! 和 $import! 提供符号列表的方式,但有以下不同:
58125882 支持移除引用标记字符;
58135883 支持转发参数;
5814-不带有引用标记字符和符号指称的对象不是临时对象(@5.2.4.2) 的默认情形复制值而不是初始化引用。
5884+不带有引用标记字符和符号指称的对象不是临时对象(@5.5.6) 的默认情形复制值而不是初始化引用。
58155885 $provide/let! <symbols> <bindings> <body> :在当前环境中提供绑定:蕴含 $let <bindings> <body> ,在求值 <body> 后以结果作为操作数绑定到 <symbols> 的符号。
58165886 <symbols> 应能被作为 <defindend> 使用。
58175887 结果是对这些绑定具有所有权的环境强引用。
@@ -5821,6 +5891,8 @@
58215891 类似 Kernel 的同名操作,但结果是创建的环境的强引用,且以同 symbols->imports! 的方式确定初值符。
58225892 $import! <environment> <symbols> :从第一参数指定的环境导入第二参数指定的符号。
58235893 类似 Kernel 的同名操作,但以同 symbols->imports! 的方式确定初值符。
5894+$import&! <environment> <symbols> :从第一参数指定的环境以引用绑定导入第二参数指定的符号。
5895+同 $import! ,但以 ensigil(@11.4.2) 的方式指定绑定的符号。
58245896 nonfoldable? <list> :判断参数是否不可被继续折叠映射:存在空列表。
58255897 输入类似 Kernel map 操作可接受的列表参数或空列表。若输入是空列表,结果为 #f 。
58265898 list-extract <list> <applicative> :以指定应用子在指定列表中选取并合并内容为新的列表。
@@ -5874,7 +5946,7 @@
58745946 promise? <object> :判断是否为 <promise> 类型的对象。
58755947 memoize <object> :记忆化求值。
58765948 $lazy <body> :创建求值代理对象,延迟求值。
5877-$lazy/e <environment> <body> :同 $lazy ,但以指定环境替代动态环境。
5949+$lazy/e <parent> <body> :同 $lazy ,但以指定环境替代动态环境。
58785950 force <promise> :立即求值指定的 promise 对象。
58795951
58805952 @12.3 字符串:
@@ -5981,7 +6053,9 @@
59816053 lock-environment(@11.3.7)
59826054 $defrec!(@11.3.7)
59836055 $setrec!(@11.4.1)
5984-函数 make-standard-environment(@11.4.2) 被重新定义返回禁用了上述操作的环境。
6056+创建以基础环境为父环境(@9.9.3) 的环境的以下函数被重新定义返回禁用了上述操作的环境:
6057+make-standard-environment(@11.4.1)
6058+derive-environment(@11.4.3)
59856059 注意派生这些不安全的操作的操作如 lock-current-environment 未被禁用。
59866060
59876061 @13.2.2 简单扩展接口:
@@ -6035,6 +6109,7 @@
60356109 $env-de! <variable> <body> :按环境变量定义变量的值。
60366110 使用 $def!(@11.3.7) 定义第一参数指定的变量绑定。
60376111 若变量同名的环境变量具有非空值,则定义的变量的值为等于这个值的字符串;否则,求值 <body> 并定义变量的值为求值结果。
6112+定义变量使用的绑定的初值符是以 desigil(@11.3.6) 的方式移除标记字符(@9.2.2.4) 后的参数。
60386113
60396114 @13.2.5 其它 SHBuild 派生特性:
60406115 变量 SHBuild_Env_OS :参见用户文档。
diff -r 6ad22b72cee3 -r 2d5fea7ba0cd doc/Workflow.txt
--- a/doc/Workflow.txt Sat Jan 23 17:00:30 2021 +0800
+++ b/doc/Workflow.txt Sat Jan 30 14:55:15 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file Workflow.txt
1212 \ingroup Documentation
1313 \brief 工作流汇总报告。
14-\version r4098
14+\version r4157
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 433
1717 \par 创建时间:
1818 2013-07-31 01:27:41 +0800
1919 \par 修改时间:
20- 2021-01-23 15:52 +0800
20+ 2021-01-30 14:36 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -4057,42 +4057,71 @@
40574057 $2021-01:
40584058
40594059 report.impl:
4060-NPLA1 interface for local bindings and modules are revised.
4061- The operative '$provide/d!', '$let/d' and '$let/d%' are removed.
4062- The dynamic environment denoted by the environment formal parameter is generally discouraged, because the dynamic environment may have other bindings initialized later, and relying on such bindings is often error-prone, esp. for long bodies.
4063- Using of the statically derived environments (e.g. the standard enviornment) instead as the static environment of the exported functions in the body is generally more encouraged.
4064- If the dynamic environment is needed indeed, it can be easily worked around.
4065- Since the environment is local to the binding clauses and the bound expressions in the clauses will be always evaluated, it is easy to specify the dynamic environment in the bindings clause.
4066- For example, a '() get-current-environment' should generally be enough.
4067- This is different to operative constructors like '$vau'.
4068- Dynamic environment is necessary to operatives in general, even though the caveats on the use of the dynamic environments still apply.
4069- It is not optional for all such operative constructors.
4070- There should be some place to get the binding of the dynamic environment in some operative contructors.
4071- Operatives cannot rely on the dynamic environment available from the evaluation by the operative calls.
4072- That is, operand like '() get-current-environment' cannot be in the parameter tree, because it will remain unevaluated if the operative is not wrapped.
4073- Obviously it cannot be in the body, either.
4074- There is no other room for such an operand to go, so the environment formal parameter is eventually needed.
4060+Several NPLA1 improvements are made.
4061+ Interface for local bindings and modules are revised.
4062+ The operative '$provide/d!', '$let/d' and '$let/d%' are removed.
4063+ The dynamic environment denoted by the environment formal parameter is generally discouraged, because the dynamic environment may have other bindings initialized later, and relying on such bindings is often error-prone, esp. for long bodies.
4064+ Using of the statically derived environments (e.g. the standard enviornment) instead as the static environment of the exported functions in the body is generally more encouraged.
4065+ If the dynamic environment is needed indeed, it can be easily worked around.
4066+ Since the environment is local to the binding clauses and the bound expressions in the clauses will be always evaluated, it is easy to specify the dynamic environment in the bindings clause.
4067+ For example, a '() get-current-environment' should generally be enough.
4068+ This is different to operative constructors like '$vau'.
4069+ Dynamic environment is necessary to operatives in general, even though the caveats on the use of the dynamic environments still apply.
4070+ It is not optional for all such operative constructors.
4071+ There should be some place to get the binding of the dynamic environment in some operative contructors.
4072+ Operatives cannot rely on the dynamic environment available from the evaluation by the operative calls.
4073+ That is, operand like '() get-current-environment' cannot be in the parameter tree, because it will remain unevaluated if the operative is not wrapped.
4074+ Obviously it cannot be in the body, either.
4075+ There is no other room for such an operand to go, so the environment formal parameter is eventually needed.
4076+ A bug of wrong parent environment used in the constructed environment is fixed in the core library operative '$bindings->environment'.
4077+ The operative now correctly used the fresh environment without parents instead.
4078+ This is also consistent to the environments vs. modules definitions (requires a standard environment for the latter ones).
40754079 Mapping between modules and environments for loaded modules has been clearified.
40764080 There is no guarantee of one-to-one mapping, even though it often is the case.
40774081 The stability of the environments for loaded modules is now explicitly required.
40784082 This is in alignment to the applicative 'get-module' in [RnRK],
40794083 The stability in 'get-module' is get by a fresh environment made by 'make-kernel-standard-environment' as the parent.
40804084 This is also similar to '$let-safe' in [RnRK], though '$let-safe' is not specific to module interface.
4081- A bug of wrong parent environment used in the constructed environment is fixed in the core library operative '$bindings->environment'.
4082- The operative now correctly used the fresh environment without parents instead.
4083- This is also consistent to the environments vs. modules definitions (requires a standard environment for the latter ones).
4084-The synchronous (non-thunked) implementation of NPLA1 has been reviewed and several bug has been fixed.
4085- The bugs in the native implementations of sequence algorithms ('AccR', 'FoldR1' and 'Map1' in namespace 'NPL::Forms' has been fixed).
4086- One of the bug is the wrong use of 'RelaySwitched'.
4087- This should not be used by the synchronous implementation.
4088- It would cause invalid results and invalid memory accesses eventually becuase of the unexpected early return.
4089- The other is the wrong treatment of the call result. That is, 'ContextNode::LastResult' should not be used.
4090- Without the previous bug, this bug would lead to wrong combiner call results determine by previous reductions.
4091- For instance, '$let' would sometimes make no bindings by accident, since 'map1' results are empty lists (unless all of 'accr', 'foldr1' and 'map1' are derived rather than implemented natively).
4092- An alternative implementation of 'A1::SetupDefaultInterpretation' is fixed.
4093- The implementation was buggy because it missed the reduction result in the step to conditionally setup combining term reference.
4094- The reduction result was implicitly 'ReductionStatus::Clean'.
4095- This was wrong for the synchronous implementation because the implicit reduction status could override the reduction status from other handlers unexpectedly.
4085+ The synchronous (non-thunked) implementation has been reviewed and several bug has been fixed.
4086+ The bugs in the native implementations of sequence algorithms ('AccR', 'FoldR1' and 'Map1' in namespace 'NPL::Forms' has been fixed).
4087+ One of the bug is the wrong use of 'RelaySwitched'.
4088+ This should not be used by the synchronous implementation.
4089+ It would cause invalid results and invalid memory accesses eventually becuase of the unexpected early return.
4090+ The other is the wrong treatment of the call result. That is, 'ContextNode::LastResult' should not be used.
4091+ Without the previous bug, this bug would lead to wrong combiner call results determine by previous reductions.
4092+ For instance, '$let' would sometimes make no bindings by accident, since 'map1' results are empty lists (unless all of 'accr', 'foldr1' and 'map1' are derived rather than implemented natively).
4093+ An alternative implementation of 'A1::SetupDefaultInterpretation' is fixed.
4094+ The implementation was buggy because it missed the reduction result in the step to conditionally setup combining term reference.
4095+ The reduction result was implicitly 'ReductionStatus::Clean'.
4096+ This was wrong for the synchronous implementation because the implicit reduction status could override the reduction status from other handlers unexpectedly.
4097+ Implementaton of the vau handler is changed.
4098+ To support lists of environments as the parent object, the static environment is merged into the parent object.
4099+ This would make the cyclic references leak earlier.
4100+ The cyclic strong reference 'shared_ptr<Environment>' would now formed immediate to the vau handler construction.
4101+ This is more consistent to 'make-environment'.
4102+ In the old implementation, the cyclic reference would be formed at locking any cyclic parent object in accessing the environment during the combiner call.
4103+ As a result, the runtime overhead of reference counting is also reduced slightly, as there are less total references saved in the vau handlers.
4104+ However, overhead of new environment list support is still more significant.
4105+ In fact, the overhead of saving the owning parent to the TCO action in the TCO implementation for combiner rvalues in each call is also greater.
4106+ Since this is already undefined behavior, no compatibility issues should be raised.
4107+ Requirements of reduction function implementations are changed, to allow getting rid of some redundant operations to set the next term in the NPLA1 context in asynchronous reductions.
4108+ The 'A1::ReduceOnce' is changed to have the setup at first.
4109+ This behavior is now consistent to the main reduction function 'A1::Reduce'.
4110+ This is only changed in asynchronous implementations, different to context rewriting functions which always setup the next term at first.
4111+ This is the only change that should be taken before the remained changes below.
4112+ The change is made here to minimize the incompatibility issues.
4113+ The 'A1::ReduceOnce' without next term setup before its call is used in several cases.
4114+ To name a few, YFramework module NPL::Dependency and the SHBuild implementation both rely on the behavior.
4115+ The change makes the loading in NPL::Dependency a bit less optimal. This can be improved later.
4116+ An internal helper function is provided to assert the next term stored in 'A1::ContextState' same to the current term (specified by 'TermNode&' argument of the reduction functions).
4117+ 'A1::ContextState::ReduceOnce' now requires more explicit precondition to ensure the next term would be always setup properly unless there is no 'A1::Continuation' calls implied by the impementation.
4118+ 'A1::ContextState::DefaultReduceOnce' is simplified.
4119+ The term setup before each pass is removed.
4120+ The assertion is added in the front of the administrative calls in asynchronous implementations.
4121+ As the default implementation of 'A1::ContextState::ReduceOnce', it is still conforming after the changes.
4122+ Many other reduction functions also uses the new assertion in asynchronous implementations.
4123+ 'A1::ReduceCombined' and its friends are simplified.
4124+ The term setup is now in the internal combiner thunk instead of the entries of each reduction functions.
40964125
40974126 ////
40984127
Show on old repository browser