• R/O
  • SSH

YSLib: Commit

The YSLib project - main repository


Commit MetaInfo

Revision8f214fbb4405c6aa12ab962f2ff6c234315d760c (tree)
Time2021-04-21 19:41:47
AuthorFrankHB <frankhb1989@gmai...>
CommiterFrankHB

Log Message

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

Change Summary

Incremental Difference

diff -r dfccd642351f -r 8f214fbb4405 YFramework/include/NPL/NPLA.h
--- a/YFramework/include/NPL/NPLA.h Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/include/NPL/NPLA.h Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA.h
1212 \ingroup NPL
1313 \brief NPLA 公共接口。
14-\version r8285
14+\version r8293
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 663
1717 \par 创建时间:
1818 2016-01-07 10:32:34 +0800
1919 \par 修改时间:
20- 2021-03-12 18:01 +0800
20+ 2021-04-20 01:25 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -885,6 +885,14 @@
885885 */
886886 YB_NORETURN YF_API void
887887 ThrowListTypeErrorForNonlist(const TermNode&, bool);
888+
889+/*!
890+\brief 对项抛出指定预期访问值的类型的异常。
891+\throw TypeError 消息中包含由参数指定的预期访问值的类型的异常。
892+\since build 917
893+*/
894+YB_NORETURN YF_API void
895+ThrowTypeErrorForInvalidType(const ystdex::type_info&, const TermNode&, bool);
888896 //@}
889897
890898 /*!
@@ -1672,6 +1680,7 @@
16721680 使用第二参数以支持非正规表示。
16731681 假定第三参数引用的项是第二参数;
16741682 否则,若目标和源项不相同且引用值具有非正规表示,行为未定义。
1683+提升引用的目标项的标签设置为 TermTags::Unqualified 。
16751684 */
16761685 YF_API void
16771686 LiftCollapsed(TermNode&, TermNode&, TermReference);
diff -r dfccd642351f -r 8f214fbb4405 YFramework/include/NPL/NPLA1.h
--- a/YFramework/include/NPL/NPLA1.h Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/include/NPL/NPLA1.h Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1.h
1212 \ingroup NPL
1313 \brief NPLA1 公共接口。
14-\version r8550
14+\version r8631
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 472
1717 \par 创建时间:
1818 2014-02-02 17:58:24 +0800
1919 \par 修改时间:
20- 2021-03-17 04:45 +0800
20+ 2021-04-20 22:46 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -174,11 +174,21 @@
174174 //! \pre 间接断言:第一参数非空。
175175 YB_NORETURN YF_API YB_NONNULL(1) void
176176 ThrowInvalidSyntaxError(const char*);
177+//! \pre 间接断言:第一参数的数据指针非空。
177178 YB_NORETURN YF_API void
178179 ThrowInvalidSyntaxError(string_view);
179180 //@}
180181
181182 /*!
183+\brief 抛出无效记号值异常。
184+\pre 断言:第一参数的数据指针非空。
185+\throw InvalidSyntax 语法错误:记号不被上下文支持。
186+\since build 917
187+*/
188+YB_NORETURN YF_API void
189+ThrowInvalidTokenError(string_view);
190+
191+/*!
182192 \brief 抛出被赋值操作数不可修改的异常。
183193 \throw TypeError 被赋值操作数不可修改错误。
184194 */
@@ -1275,41 +1285,50 @@
12751285 //@}
12761286
12771287
1278-//! \throw ParameterMismatch 匹配失败。
1279-//@{
12801288 /*!
1281-\pre 断言:字符串参数的数据指针非空。
1282-\since build 794
1289+\brief 判断记号值是否为 #ignore 。
1290+\since build 917
1291+*/
1292+YB_ATTR_nodiscard YB_PURE inline
1293+ PDefH(bool, IsIgnore, const TokenValue& s) ynothrow
1294+ // XXX: This is more efficient than cast to %basic_string_view if the
1295+ // %basic_string implementation is optimized.
1296+ ImplRet(s == "#ignore")
1297+
1298+/*!
1299+\throw InvalidSyntax 嵌套异常:项不符合语法要求。
1300+\note 异常条件视为语法错误而非直接的类型错误。
1301+\since build 917
12831302 */
12841303 //@{
1285-//! \brief 检查记号值是符合匹配条件的符号。
1286-template<typename _func>
1287-auto
1288-CheckSymbol(string_view n, _func f) -> decltype(f())
1289-{
1290- if(IsNPLASymbol(n))
1291- return f();
1292- throw ParameterMismatch(ystdex::sfmt(
1293- "Invalid token '%s' found for symbol parameter.", n.data()));
1294-}
1304+/*!
1305+\brief 检查形式参数树。
12951306
1296-//! \brief 检查记号值是符合匹配条件的参数符号。
1297-template<typename _func>
1298-auto
1299-CheckParameterLeafToken(string_view n, _func f) -> decltype(f())
1300-{
1301- if(n != "#ignore")
1302- CheckSymbol(n, f);
1303-}
1307+递归遍历项及其子项,检查其中的子项符合对象语言 \<ptree> 形式的语法要求。
1308+一般适用提前检查对象语言操作的 \<formals> 而不是 \<definiend> 描述的参数。
1309+*/
1310+YF_API void
1311+CheckParameterTree(const TermNode&);
1312+
1313+/*!
1314+\brief 检查环境形式参数。
1315+\return 项表示 \c #ignore 时为空串,否则为非空的环境形式参数。
1316+*/
1317+YF_API YB_ATTR_nodiscard YB_PURE string
1318+CheckEnvironmentFormal(const TermNode&);
13041319 //@}
13051320
13061321 /*!
1322+\throw InvalidSyntax 嵌套异常 ArityMismatch :参数数匹配失败。
1323+\throw InvalidSyntax 嵌套异常 ParameterMismatch :参数匹配失败。
13071324 \note 不具有强异常安全保证。匹配失败时,其它的绑定状态未指定。
13081325
13091326 递归遍历参数和操作数树进行结构化匹配。
13101327 若匹配失败,则抛出异常。
13111328 */
13121329 //@{
1330+//! \throw InvalidSyntax 嵌套异常 InvalidSyntax :形式参数项不符合语法要求。
1331+//@{
13131332 /*!
13141333 \brief 匹配参数。
13151334 \exception std::bad_function_call 异常中立:参数指定的处理器为空。
@@ -1336,13 +1355,15 @@
13361355 若操作数的某一个需匹配的列表子项是 TermReference 或复制标识为 true ,
13371356 序列处理器中需要进行复制。
13381357 结尾序列处理器传入的字符串参数表示需绑定的表示结尾序列的列表标识符。
1339-匹配要求如下:
1340-若项是非空列表,则操作数的对应的项应为满足确定子项数的列表:
1341- 若最后的子项为 . 起始的符号,则匹配操作数中结尾的任意个数的项作为结尾序列:
1342- 其它子项一一匹配操作数的子项;
1343-若项是空列表,则操作数的对应的项应为空列表;
1344-若项是 TermReference ,则以其引用的项作为子项继续匹配;
1345-否则,匹配非列表项。
1358+匹配规则如下:
1359+ 若项是非空列表,则操作数的对应的项应为满足确定子项数的列表:
1360+ 若最后的子项为 . 起始的记号,则匹配操作数中结尾的任意个数的项作为结尾序列。
1361+ 其它子项一一匹配操作数的子项。
1362+ 若项是空列表,则操作数的对应的项应为空列表。
1363+ 若项是引用值,则以表示其被引用对象的项作为子项继续匹配。
1364+ 若项是 #ignore ,则忽略操作数对应的项。
1365+ 若项的值不是符号,则匹配出错。
1366+ 否则,匹配非列表项。
13461367 */
13471368 YF_API void
13481369 MatchParameter(const TermNode&, TermNode&, function<void(TermNode&, TNIter,
@@ -1363,22 +1384,36 @@
13631384 形式参数和操作数为项指定的表达式树。
13641385 第二参数指定形式参数,第三参数指定操作数。
13651386 进行匹配的算法递归搜索形式参数及其子项,要求参见 MatchParameter 。
1366-若匹配成功,在第一参数指定的环境内绑定未被忽略的匹配的项。
1387+若匹配成功,在第一参数指定的环境内绑定未被忽略的匹配的非列表项。
13671388 对结尾序列总是匹配前缀为 . 的符号为目标按以下规则忽略或绑定:
13681389 子项为 . 时,对应操作数的结尾序列被忽略;
13691390 否则,绑定项的目标为移除前缀 . 和后续可选前缀 & 后的符号。
1370-非列表项的绑定使用以下规则:
1371-若匹配成功,在第一参数指定的环境内绑定未被忽略的匹配的非列表项。
1372-匹配要求如下:
1373-若项是 #ignore ,则忽略操作数对应的项;
1374-若项的值是符号,则操作数的对应的项应为非列表项。
1375-若被绑定的目标有引用标记字符,则以按引用传递的方式绑定;否则以按值传递的方式绑定。
1376-当绑定的引用标记字符为 @ 且不是列表项时抛出异常。
1377-按引用传递绑定直接转移该项的内容。
1391+非列表项绑定规则如下:
1392+ 若被绑定的目标有引用标记字符,则以按引用传递的方式绑定,否则以按值传递的方式绑定。
1393+ 当绑定的引用标记字符为 @ 且不是列表项时抛出异常。
1394+ 按引用传递绑定直接转移该项的内容。
13781395 */
13791396 YF_API void
13801397 BindParameter(const shared_ptr<Environment>&, const TermNode&, TermNode&);
13811398 //@}
1399+
1400+/*!
1401+\brief 使用操作数结构化匹配并绑定参数到合式的形式参数树。
1402+\pre 参数指定的形式参数树确保通过检查没有语法错误。
1403+\throw ArityMismatch 参数数匹配失败。
1404+\throw ParameterMismatch 参数匹配失败。
1405+\sa CheckParameterTree
1406+\since build 917
1407+
1408+同 BindParameter ,但假定形式参数树确保通过检查没有语法错误,否则行为未定义。
1409+实现假定不存在形式参数树具有引起语法错误的错误条件。
1410+通过先前在同一形式参数树上的 CheckParameter 调用可保证符合前置条件。
1411+若确保绑定不具有引起对象语言中可观察行为的副作用,先前的 BindParameter
1412+ 或 BindParameterWellFormed 也可确保满足前置条件。
1413+*/
1414+YF_API void
1415+BindParameterWellFormed(const shared_ptr<Environment>&, const TermNode&,
1416+ TermNode&);
13821417 //@}
13831418
13841419
diff -r dfccd642351f -r 8f214fbb4405 YFramework/include/NPL/NPLA1Forms.h
--- a/YFramework/include/NPL/NPLA1Forms.h Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/include/NPL/NPLA1Forms.h Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Forms.h
1212 \ingroup NPL
1313 \brief NPLA1 语法形式。
14-\version r7933
14+\version r7981
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2020-02-15 11:19:21 +0800
1919 \par 修改时间:
20- 2021-04-08 18:13 +0800
20+ 2021-04-19 19:40 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -1469,28 +1469,26 @@
14691469 YF_API ReductionStatus
14701470 Map1(TermNode&, ContextNode&);
14711471
1472+//! \since build 917
1473+//@{
14721474 /*!
14731475 \brief 顺序连接两个列表。
1474-\since build 912
14751476
14761477 参考调用文法:
14771478 <pre>list-concat \<list1> \<list2></pre>
14781479 */
14791480 YF_API ReductionStatus
1480-ListConcat(TermNode&, ContextNode&);
1481+ListConcat(TermNode&);
14811482
14821483 /*!
14831484 \brief 顺序连接零个或多个列表。
1484-\since build 912
14851485
14861486 参考调用文法:
14871487 <pre>append \<list>...</pre>
14881488 */
14891489 YF_API ReductionStatus
1490-Append(TermNode&, ContextNode&);
1490+Append(TermNode&);
14911491
1492-//! \since build 914
1493-//@{
14941492 /*!
14951493 \brief 以 First 在指定列表中选取并合并内容为新的列表。
14961494 \sa First
@@ -1499,7 +1497,7 @@
14991497 <pre>list-extract-first \<list></pre>
15001498 */
15011499 YF_API ReductionStatus
1502-ListExtractFirst(TermNode&, ContextNode&);
1500+ListExtractFirst(TermNode&);
15031501
15041502 /*!
15051503 \brief 以 RestFwd 在指定列表中选取并合并内容为新的列表。
@@ -1509,8 +1507,11 @@
15091507 <pre>list-extract-rest% \<list></pre>
15101508 */
15111509 YF_API ReductionStatus
1512-ListExtractRestFwd(TermNode&, ContextNode&);
1510+ListExtractRestFwd(TermNode&);
1511+//@}
15131512
1513+//! \since build 914
1514+//@{
15141515 //! \brief 局部绑定求值。
15151516 //@{
15161517 /*
@@ -1554,6 +1555,51 @@
15541555 //@}
15551556 //@}
15561557
1558+//! \since build 917
1559+//@{
1560+//! \brief 顺序局部绑定求值。
1561+//@{
1562+/*
1563+不保留结果中的引用值。
1564+
1565+参考调用文法:
1566+<pre>$let* \<bindings> \<body></pre>
1567+*/
1568+YF_API ReductionStatus
1569+LetAsterisk(TermNode&, ContextNode&);
1570+
1571+/*
1572+保留结果中的引用值。
1573+
1574+参考调用文法:
1575+<pre>$let*% \<bindings> \<body></pre>
1576+*/
1577+YF_API ReductionStatus
1578+LetAsteriskRef(TermNode&, ContextNode&);
1579+//@}
1580+
1581+//! \brief 允许递归引用绑定的顺序局部绑定求值
1582+//@{
1583+/*
1584+不保留结果中的引用值。
1585+
1586+参考调用文法:
1587+<pre>$letrec \<bindings> \<body></pre>
1588+*/
1589+YF_API ReductionStatus
1590+LetRec(TermNode&, ContextNode&);
1591+
1592+/*
1593+保留结果中的引用值。
1594+
1595+参考调用文法:
1596+<pre>$letrec% \<bindings> \<body></pre>
1597+*/
1598+YF_API ReductionStatus
1599+LetRecRef(TermNode&, ContextNode&);
1600+//@}
1601+//@}
1602+
15571603
15581604 /*!
15591605 \brief 调用 UTF-8 字符串的系统命令,并保存 int 类型的结果到项的值中。
diff -r dfccd642351f -r 8f214fbb4405 YFramework/include/NPL/SContext.h
--- a/YFramework/include/NPL/SContext.h Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/include/NPL/SContext.h Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file SContext.h
1212 \ingroup NPL
1313 \brief S 表达式上下文。
14-\version r3996
14+\version r4010
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 304
1717 \par 创建时间:
1818 2012-08-03 19:55:41 +0800
1919 \par 修改时间:
20- 2021-03-31 07:04 +0800
20+ 2021-04-15 22:14 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -369,18 +369,18 @@
369369 Value = yforward(val);
370370 }
371371 PDefH(void, SetContent, const TermNode& nd)
372- ImplExpr(SetContent(nd.container, nd.Value))
372+ ImplExpr(SetContent(nd.container, nd.Value), Tags = nd.Tags)
373+ //! \pre 间接断言:容器分配器和参数的容器分配器相等。
373374 PDefH(void, SetContent, TermNode&& nd)
374- ImplExpr(SetContent(std::move(nd.container), std::move(nd.Value)),
375- Tags = nd.Tags)
375+ ImplExpr(SwapContainer(nd), Value = std::move(nd.Value), Tags = nd.Tags)
376376 //@}
377377
378378 //! \since build 853
379- PDefH(void, Add, const TermNode& term)
380- ImplExpr(container.push_back(term))
379+ PDefH(void, Add, const TermNode& nd)
380+ ImplExpr(container.push_back(nd))
381381 //! \since build 853
382- PDefH(void, Add, TermNode&& term)
383- ImplExpr(container.push_back(std::move(term)))
382+ PDefH(void, Add, TermNode&& nd)
383+ ImplExpr(container.push_back(std::move(nd)))
384384
385385 //! \since build 853
386386 //@{
@@ -484,6 +484,7 @@
484484 //@{
485485 /*!
486486 \brief 转移容器。
487+ \pre 间接断言:容器分配器和参数的容器分配器相等。
487488
488489 转移参数指定的节点的容器到对象。
489490 转移后的节点的容器是转移前的参数的容器。
@@ -493,6 +494,7 @@
493494
494495 /*!
495496 \brief 转移内容。
497+ \pre 间接断言:容器分配器和参数的容器分配器相等。
496498 \since build 853
497499
498500 转移参数指定的节点的内容到对象。
@@ -515,9 +517,10 @@
515517 PDefH(void, Remove, const_iterator i)
516518 ImplExpr(erase(i))
517519
518- PDefH(void, SwapContainer, TermNode& term) ynothrowv
519- ImplExpr(YAssert(get_allocator() == term.get_allocator(),
520- "Invalid allocator found."), container.swap(term.container))
520+ //! \pre 断言:容器分配器和参数的容器分配器相等。
521+ PDefH(void, SwapContainer, TermNode& nd) ynothrowv
522+ ImplExpr(YAssert(get_allocator() == nd.get_allocator(),
523+ "Invalid allocator found."), container.swap(nd.container))
521524
522525 void
523526 SwapContent(TermNode&) ynothrowv;
diff -r dfccd642351f -r 8f214fbb4405 YFramework/include/YSLib/Core/ValueNode.h
--- a/YFramework/include/YSLib/Core/ValueNode.h Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/include/YSLib/Core/ValueNode.h Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file ValueNode.h
1212 \ingroup Core
1313 \brief 值类型节点。
14-\version r4180
14+\version r4272
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 338
1717 \par 创建时间:
1818 2012-08-03 23:03:44 +0800
1919 \par 修改时间:
20- 2021-03-01 22:33 +0800
20+ 2021-04-15 22:17 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -188,13 +188,13 @@
188188 \sa ystdex::restore_key
189189 \since build 845
190190 */
191- static PDefH(void, restore_key, ValueNode& node, ValueNode&& ek)
192- ImplExpr(node.name = std::move(ek.name))
191+ static PDefH(void, restore_key, ValueNode& nd, ValueNode&& ek)
192+ ImplExpr(nd.name = std::move(ek.name))
193193
194194 //! \sa ystdex::set_value_move
195- static PDefH(ValueNode, set_value_move, ValueNode& node)
196- ImplRet({std::move(node.GetContainerRef()),
197- node.GetName(), std::move(node.Value)})
195+ static PDefH(ValueNode, set_value_move, ValueNode& nd)
196+ ImplRet({std::move(nd.GetContainerRef()),
197+ nd.GetName(), std::move(nd.Value)})
198198 //@}
199199 };
200200 using Container = ystdex::mapped_set<ValueNode, ystdex::less<>,
@@ -364,8 +364,8 @@
364364 //! \since build 768
365365 //@{
366366 //! \brief 复制赋值:使用参数副本和交换操作。
367- PDefHOp(ValueNode&, =, const ValueNode& node)
368- ImplRet(ystdex::copy_and_swap(*this, node))
367+ PDefHOp(ValueNode&, =, const ValueNode& nd)
368+ ImplRet(ystdex::copy_and_swap(*this, nd))
369369 /*!
370370 \pre 被转移的参数不是被子节点容器直接或间接所有的其它节点。
371371 \warning 违反前置条件的转移可能引起循环引用。
@@ -375,13 +375,13 @@
375375
376376 //! \since build 730
377377 //@{
378- PDefHOp(const ValueNode&, +=, const ValueNode& node)
379- ImplRet(Add(node), *this)
380- PDefHOp(const ValueNode&, +=, ValueNode&& node)
381- ImplRet(Add(std::move(node)), *this)
378+ PDefHOp(const ValueNode&, +=, const ValueNode& nd)
379+ ImplRet(Add(nd), *this)
380+ PDefHOp(const ValueNode&, +=, ValueNode&& nd)
381+ ImplRet(Add(std::move(nd)), *this)
382382
383- PDefHOp(const ValueNode&, -=, const ValueNode& node)
384- ImplRet(Remove(node), *this)
383+ PDefHOp(const ValueNode&, -=, const ValueNode& nd)
384+ ImplRet(Remove(nd), *this)
385385 PDefHOp(const ValueNode&, -=, const string& str)
386386 ImplRet(Remove(str), *this)
387387 /*!
@@ -389,10 +389,10 @@
389389 \return 自身引用。
390390 */
391391 //@{
392- PDefHOp(ValueNode&, /=, const ValueNode& node)
393- ImplRet(*this %= node, *this)
394- PDefHOp(ValueNode&, /=, ValueNode&& node)
395- ImplRet(*this %= std::move(node), *this)
392+ PDefHOp(ValueNode&, /=, const ValueNode& nd)
393+ ImplRet(*this %= nd, *this)
394+ PDefHOp(ValueNode&, /=, ValueNode&& nd)
395+ ImplRet(*this %= std::move(nd), *this)
396396 //@}
397397 /*!
398398 \brief 替换同名子节点。
@@ -511,8 +511,8 @@
511511 PDefH(void, SetChildren, Container&& con)
512512 ImplExpr(container = std::move(con))
513513 //! \since build 776
514- PDefH(void, SetChildren, ValueNode&& node)
515- ImplExpr(container = std::move(node.container))
514+ PDefH(void, SetChildren, ValueNode&& nd)
515+ ImplExpr(container = std::move(nd.container))
516516 //@}
517517 /*!
518518 \pre 断言:分配器相等。
@@ -533,20 +533,20 @@
533533 container = yforward(con);
534534 Value = yforward(val);
535535 }
536- PDefH(void, SetContent, const ValueNode& node)
537- ImplExpr(SetContent(node.GetContainer(), node.Value))
538- PDefH(void, SetContent, ValueNode&& node)
539- ImplExpr(SetContent(std::move(node.GetContainerRef()),
540- std::move(node.Value)))
536+ PDefH(void, SetContent, const ValueNode& nd)
537+ ImplExpr(SetContent(nd.GetContainer(), nd.Value))
538+ //! \pre 间接断言:容器分配器和参数的容器分配器相等。
539+ PDefH(void, SetContent, ValueNode&& nd)
540+ ImplExpr(SwapContainer(nd), Value = std::move(nd.Value))
541541 //@}
542542 //@}
543543
544544 //! \since build 667
545- PDefH(bool, Add, const ValueNode& node)
546- ImplRet(insert(node).second)
545+ PDefH(bool, Add, const ValueNode& nd)
546+ ImplRet(insert(nd).second)
547547 //! \since build 667
548- PDefH(bool, Add, ValueNode&& node)
549- ImplRet(insert(std::move(node)).second)
548+ PDefH(bool, Add, ValueNode&& nd)
549+ ImplRet(insert(std::move(nd)).second)
550550
551551 /*!
552552 \brief 添加参数节点指定容器和值的子节点。
@@ -558,10 +558,10 @@
558558 yimpl(typename = ystdex::enable_if_t<
559559 std::is_same<ValueNode&, ystdex::remove_cvref_t<_tNode>&>::value>)>
560560 yimpl(ystdex::enable_if_inconvertible_t)<_tKey&&, const_iterator, bool>
561- AddChild(_tKey&& k, _tNode&& node)
561+ AddChild(_tKey&& k, _tNode&& nd)
562562 {
563- return try_emplace(k, yforward(node).container, yforward(k),
564- yforward(node).Value).second;
563+ return try_emplace(k, yforward(nd).container, yforward(k),
564+ yforward(nd).Value).second;
565565 }
566566 //! \sa ystdex::try_emplace_hint
567567 //@{
@@ -569,10 +569,10 @@
569569 yimpl(typename = ystdex::enable_if_t<
570570 std::is_same<ValueNode&, ystdex::remove_cvref_t<_tNode>&>::value>)>
571571 bool
572- AddChild(const_iterator hint, _tKey&& k, _tNode&& node)
572+ AddChild(const_iterator hint, _tKey&& k, _tNode&& nd)
573573 {
574- return try_emplace_hint(hint, k, yforward(node).container, yforward(k),
575- yforward(node).Value);
574+ return try_emplace_hint(hint, k, yforward(nd).container, yforward(k),
575+ yforward(nd).Value);
576576 }
577577 //@}
578578 //@}
@@ -649,14 +649,14 @@
649649 \since build 913
650650 */
651651 //@{
652- PDefH(void, CopyContainer, const ValueNode& node)
653- ImplExpr(GetContainerRef() = Container(node.GetContainer()))
652+ PDefH(void, CopyContainer, const ValueNode& nd)
653+ ImplExpr(GetContainerRef() = Container(nd.GetContainer()))
654654
655- PDefH(void, CopyContent, const ValueNode& node)
656- ImplExpr(SetContent(ValueNode(node)))
655+ PDefH(void, CopyContent, const ValueNode& nd)
656+ ImplExpr(SetContent(ValueNode(nd)))
657657
658- PDefH(void, CopyValue, const ValueNode& node)
659- ImplExpr(Value = ValueObject(node.Value))
658+ PDefH(void, CopyValue, const ValueNode& nd)
659+ ImplExpr(Value = ValueObject(nd.Value))
660660 //@}
661661
662662 //! \brief 递归创建容器副本。
@@ -720,6 +720,7 @@
720720 //@{
721721 /*!
722722 \brief 转移容器。
723+ \pre 间接断言:容器分配器和参数的容器分配器相等。
723724
724725 转移参数指定的节点的容器到对象。
725726 转移后的节点的容器是转移前的参数的容器。
@@ -729,6 +730,7 @@
729730
730731 /*!
731732 \brief 转移内容。
733+ \pre 间接断言:容器分配器和参数的容器分配器相等。
732734 \since build 844
733735
734736 转移参数指定的节点的内容到对象。
@@ -789,8 +791,8 @@
789791 }
790792 //@}
791793
792- PDefH(bool, Remove, const ValueNode& node)
793- ImplRet(erase(node) != 0)
794+ PDefH(bool, Remove, const ValueNode& nd)
795+ ImplRet(erase(nd) != 0)
794796 //! \since build 754
795797 PDefH(iterator, Remove, const_iterator i)
796798 ImplRet(erase(i))
@@ -846,9 +848,9 @@
846848 */
847849 //@{
848850 //! \brief 交换容器。
849- PDefH(void, SwapContainer, ValueNode& node) ynothrowv
850- ImplExpr(YAssert(get_allocator() == node.get_allocator(),
851- "Invalid allocator found."), container.swap(node.container))
851+ PDefH(void, SwapContainer, ValueNode& nd) ynothrowv
852+ ImplExpr(YAssert(get_allocator() == nd.get_allocator(),
853+ "Invalid allocator found."), container.swap(nd.container))
852854
853855 //! \brief 交换容器和值。
854856 void
@@ -994,15 +996,15 @@
994996 //@{
995997 template<typename _type>
996998 YB_ATTR_nodiscard YB_PURE inline _type&
997-Access(ValueNode& node)
999+Access(ValueNode& nd)
9981000 {
999- return node.Value.Access<_type>();
1001+ return nd.Value.Access<_type>();
10001002 }
10011003 template<typename _type>
10021004 YB_ATTR_nodiscard YB_PURE inline const _type&
1003-Access(const ValueNode& node)
1005+Access(const ValueNode& nd)
10041006 {
1005- return node.Value.Access<_type>();
1007+ return nd.Value.Access<_type>();
10061008 }
10071009 //@}
10081010
@@ -1012,15 +1014,15 @@
10121014 //@{
10131015 template<typename _type>
10141016 YB_ATTR_nodiscard YB_PURE inline observer_ptr<_type>
1015-AccessPtr(ValueNode& node) ynothrow
1017+AccessPtr(ValueNode& nd) ynothrow
10161018 {
1017- return node.Value.AccessPtr<_type>();
1019+ return nd.Value.AccessPtr<_type>();
10181020 }
10191021 template<typename _type>
10201022 YB_ATTR_nodiscard YB_PURE inline observer_ptr<const _type>
1021-AccessPtr(const ValueNode& node) ynothrow
1023+AccessPtr(const ValueNode& nd) ynothrow
10221024 {
1023- return node.Value.AccessPtr<_type>();
1025+ return nd.Value.AccessPtr<_type>();
10241026 }
10251027 //@}
10261028 /*!
@@ -1125,27 +1127,27 @@
11251127 template<typename _tKey,
11261128 yimpl(typename = ValueNode::enable_if_key_t<_tKey>)>
11271129 YB_ATTR_nodiscard YB_PURE inline ValueNode&
1128-AccessNode(ValueNode& node, const _tKey& name)
1130+AccessNode(ValueNode& nd, const _tKey& name)
11291131 {
1130- return YSLib::AccessNode(node.GetContainerRef(), name);
1132+ return YSLib::AccessNode(nd.GetContainerRef(), name);
11311133 }
11321134 template<typename _tKey,
11331135 yimpl(typename = ValueNode::enable_if_key_t<_tKey>)>
11341136 YB_ATTR_nodiscard YB_PURE inline const ValueNode&
1135-AccessNode(const ValueNode& node, const _tKey& name)
1137+AccessNode(const ValueNode& nd, const _tKey& name)
11361138 {
1137- return YSLib::AccessNode(node.GetContainer(), name);
1139+ return YSLib::AccessNode(nd.GetContainer(), name);
11381140 }
11391141 //! \since build 670
11401142 //@{
11411143 //! \note 使用 ADL AccessNode 。
11421144 template<class _tNode, typename _tIn>
11431145 YB_ATTR_nodiscard YB_PURE _tNode&&
1144-AccessNode(_tNode&& node, _tIn first, _tIn last)
1146+AccessNode(_tNode&& nd, _tIn first, _tIn last)
11451147 {
1146- return std::accumulate(first, last, ystdex::ref(node),
1147- [](_tNode&& nd, decltype(*first) c){
1148- return ystdex::ref(AccessNode(nd, c));
1148+ return std::accumulate(first, last, ystdex::ref(nd),
1149+ [](_tNode&& x, decltype(*first) c){
1150+ return ystdex::ref(AccessNode(x, c));
11491151 });
11501152 }
11511153 //! \note 使用 ADL begin 和 end 指定范围迭代器。
@@ -1153,10 +1155,10 @@
11531155 yimpl(typename = typename ystdex::enable_if_t<
11541156 !std::is_constructible<const string&, const _tRange&>::value>)>
11551157 YB_ATTR_nodiscard YB_PURE inline auto
1156-AccessNode(_tNode&& node, const _tRange& c)
1157- -> decltype(YSLib::AccessNode(yforward(node), begin(c), end(c)))
1158+AccessNode(_tNode&& nd, const _tRange& c)
1159+ -> decltype(YSLib::AccessNode(yforward(nd), begin(c), end(c)))
11581160 {
1159- return YSLib::AccessNode(yforward(node), begin(c), end(c));
1161+ return YSLib::AccessNode(yforward(nd), begin(c), end(c));
11601162 }
11611163 //@}
11621164 //@}
@@ -1222,28 +1224,27 @@
12221224 template<typename _tKey, yimpl(typename = typename ystdex::enable_if_t<
12231225 ystdex::is_interoperable<const _tKey&, const string&>::value>)>
12241226 YB_ATTR_nodiscard YB_PURE inline observer_ptr<ValueNode>
1225-AccessNodePtr(ValueNode& node, const _tKey& name)
1227+AccessNodePtr(ValueNode& nd, const _tKey& name)
12261228 {
1227- return YSLib::AccessNodePtr(node.GetContainerRef(), name);
1229+ return YSLib::AccessNodePtr(nd.GetContainerRef(), name);
12281230 }
12291231 template<typename _tKey, yimpl(typename = typename ystdex::enable_if_t<
12301232 ystdex::is_interoperable<const _tKey&, const string&>::value>)>
12311233 YB_ATTR_nodiscard YB_PURE inline observer_ptr<const ValueNode>
1232-AccessNodePtr(const ValueNode& node, const _tKey& name)
1234+AccessNodePtr(const ValueNode& nd, const _tKey& name)
12331235 {
1234- return YSLib::AccessNodePtr(node.GetContainer(), name);
1236+ return YSLib::AccessNodePtr(nd.GetContainer(), name);
12351237 }
12361238 //! \since build 670
12371239 //@{
12381240 //! \note 使用 ADL AccessNodePtr 。
12391241 template<class _tNode, typename _tIn>
12401242 YB_ATTR_nodiscard YB_PURE auto
1241-AccessNodePtr(_tNode&& node, _tIn first, _tIn last)
1242- -> decltype(make_obsrever(std::addressof(node)))
1243+AccessNodePtr(_tNode&& nd, _tIn first, _tIn last)
1244+ -> decltype(make_obsrever(std::addressof(nd)))
12431245 {
12441246 // TODO: Simplified using algorithm template?
1245- for(auto p(make_observer(std::addressof(node))); p && first != last;
1246- ++first)
1247+ for(auto p(make_observer(std::addressof(nd))); p && first != last; ++first)
12471248 p = AccessNodePtr(*p, *first);
12481249 return first;
12491250 }
@@ -1252,10 +1253,10 @@
12521253 yimpl(typename = typename ystdex::enable_if_t<
12531254 !std::is_constructible<const string&, const _tRange&>::value>)>
12541255 YB_ATTR_nodiscard YB_PURE inline auto
1255-AccessNodePtr(_tNode&& node, const _tRange& c)
1256- -> decltype(YSLib::AccessNodePtr(yforward(node), begin(c), end(c)))
1256+AccessNodePtr(_tNode&& nd, const _tRange& c)
1257+ -> decltype(YSLib::AccessNodePtr(yforward(nd), begin(c), end(c)))
12571258 {
1258- return YSLib::AccessNodePtr(yforward(node), begin(c), end(c));
1259+ return YSLib::AccessNodePtr(yforward(nd), begin(c), end(c));
12591260 }
12601261 //@}
12611262 //@}
@@ -1275,15 +1276,15 @@
12751276 //@{
12761277 template<typename _type, typename... _tParams>
12771278 YB_ATTR_nodiscard YB_PURE inline _type&
1278-AccessChild(ValueNode& node, _tParams&&... args)
1279+AccessChild(ValueNode& nd, _tParams&&... args)
12791280 {
1280- return Access<_type>(AccessNode(node, yforward(args)...));
1281+ return Access<_type>(AccessNode(nd, yforward(args)...));
12811282 }
12821283 template<typename _type, typename... _tParams>
12831284 inline const _type&
1284-AccessChild(const ValueNode& node, _tParams&&... args)
1285+AccessChild(const ValueNode& nd, _tParams&&... args)
12851286 {
1286- return Access<_type>(AccessNode(node, yforward(args)...));
1287+ return Access<_type>(AccessNode(nd, yforward(args)...));
12871288 }
12881289 //@}
12891290
@@ -1291,17 +1292,17 @@
12911292 //@{
12921293 template<typename _type, typename... _tParams>
12931294 YB_ATTR_nodiscard YB_PURE inline observer_ptr<_type>
1294-AccessChildPtr(ValueNode& node, _tParams&&... args) ynothrow
1295+AccessChildPtr(ValueNode& nd, _tParams&&... args) ynothrow
12951296 {
12961297 return AccessPtr<_type>(
1297- AccessNodePtr(node.GetContainerRef(), yforward(args)...));
1298+ AccessNodePtr(nd.GetContainerRef(), yforward(args)...));
12981299 }
12991300 template<typename _type, typename... _tParams>
13001301 YB_ATTR_nodiscard YB_PURE inline observer_ptr<const _type>
1301-AccessChildPtr(const ValueNode& node, _tParams&&... args) ynothrow
1302+AccessChildPtr(const ValueNode& nd, _tParams&&... args) ynothrow
13021303 {
13031304 return AccessPtr<_type>(
1304- AccessNodePtr(node.GetContainer(), yforward(args)...));
1305+ AccessNodePtr(nd.GetContainer(), yforward(args)...));
13051306 }
13061307 template<typename _type, typename... _tParams>
13071308 YB_ATTR_nodiscard YB_PURE inline observer_ptr<_type>
@@ -1326,8 +1327,8 @@
13261327 //@{
13271328 //! \since build 852
13281329 YB_ATTR_nodiscard YB_PURE inline
1329- PDefH(const ValueNode&, AsNode, const ValueNode& node) ynothrow
1330- ImplRet(node)
1330+ PDefH(const ValueNode&, AsNode, const ValueNode& nd) ynothrow
1331+ ImplRet(nd)
13311332 //! \brief 传递指定名称和值参数构造值类型节点。
13321333 //@{
13331334 template<typename _tString, typename... _tParams,
@@ -1463,8 +1464,8 @@
14631464 //@{
14641465 YF_API void
14651466 RemoveHead(ValueNode::Container&) ynothrowv;
1466-inline PDefH(void, RemoveHead, ValueNode& node) ynothrowv
1467- ImplExpr(RemoveHead(node.GetContainerRef()))
1467+inline PDefH(void, RemoveHead, ValueNode& nd) ynothrowv
1468+ ImplExpr(RemoveHead(nd.GetContainerRef()))
14681469 //@}
14691470 //@}
14701471
@@ -1476,12 +1477,12 @@
14761477 */
14771478 template<typename _tNode, typename _fCallable>
14781479 void
1479-SetContentWith(ValueNode& dst, _tNode&& node, _fCallable f)
1480+SetContentWith(ValueNode& dst, _tNode&& nd, _fCallable f)
14801481 {
14811482 // NOTE: Similar reason but different to the implementation of
14821483 // %ValueNode::MoveContent.
1483- auto con(yforward(node).CreateWith(f));
1484- auto vo(ystdex::invoke(f, yforward(node).Value));
1484+ auto con(yforward(nd).CreateWith(f));
1485+ auto vo(ystdex::invoke(f, yforward(nd).Value));
14851486
14861487 dst.SetContent(std::move(con), std::move(vo));
14871488 }
diff -r dfccd642351f -r 8f214fbb4405 YFramework/source/NPL/Dependency.cpp
--- a/YFramework/source/NPL/Dependency.cpp Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/source/NPL/Dependency.cpp Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file Dependency.cpp
1212 \ingroup NPL
1313 \brief 依赖管理。
14-\version r4622
14+\version r4739
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 623
1717 \par 创建时间:
1818 2015-08-09 22:14:45 +0800
1919 \par 修改时间:
20- 2021-04-10 17:59 +0800
20+ 2021-04-20 02:45 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -33,17 +33,17 @@
3333 // Forms::CallResolvedUnary, NPL::AllocateEnvironment, function, ValueObject,
3434 // EnvironmentReference, std::piecewise_construct, NPL::forward_as_tuple,
3535 // 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-// ystdex::bind1, std::placeholders, LiftTermValueOrCopy, MoveResolved,
41-// ResolveIdentifier, ReduceToReferenceList, NPL::IsMovable, LiftTermOrCopy,
42-// IsBranchedList, AccessFirstSubterm, ReferenceTerm,
43-// ThrowInsufficientTermsError, ystdex::exchange, ystdex::plus,
44-// ystdex::tolower, YSLib::IO::StreamPut, FetchEnvironmentVariable,
45-// ystdex::swap_dependent, YSLib::IO::UniqueFile, YSLib::IO::omode_convb,
46-// YSLib::uremove, ystdex::throw_error;
36+// ValueToken, IsNPLASymbol, ThrowInvalidTokenError, ResolveTerm, TokenValue,
37+// IsEmpty, ComposeReferencedTermOp, IsBranch, IsReferenceTerm,
38+// IsBoundLValueTerm, IsUncollapsedTerm, IsUniqueTerm, IsModifiableTerm,
39+// IsTemporaryTerm, NPL::TryAccessLeaf, LiftTermRef, NPL::SetContentWith,
40+// Forms::CallRawUnary, LiftTerm, LiftOtherOrCopy, ystdex::bind1,
41+// std::placeholders, LiftTermValueOrCopy, MoveResolved, ResolveIdentifier,
42+// ReduceToReferenceList, NPL::IsMovable, LiftTermOrCopy, IsBranchedList,
43+// AccessFirstSubterm, ReferenceTerm, ThrowInsufficientTermsError,
44+// ystdex::exchange, ystdex::plus, ystdex::tolower, YSLib::IO::StreamPut,
45+// FetchEnvironmentVariable, ystdex::swap_dependent, YSLib::IO::UniqueFile,
46+// YSLib::IO::omode_convb, YSLib::uremove, ystdex::throw_error;
4747 #include YFM_NPL_NPLA1Forms // for NPL::Forms functions;
4848 #include YFM_YSLib_Service_FileSystem // for YSLib::IO::Path;
4949 #include <ystdex/iterator.hpp> // for std::istreambuf_iterator,
@@ -409,6 +409,16 @@
409409 return ValueToken::Unspecified;
410410 }
411411
412+//! \since build 917
413+template<typename _func>
414+auto
415+CheckSymbol(string_view id, _func f) -> decltype(f())
416+{
417+ if(IsNPLASymbol(id))
418+ return f();
419+ ThrowInvalidTokenError(id);
420+}
421+
412422 //! \since build 897
413423 YB_ATTR_nodiscard YB_FLATTEN ReductionStatus
414424 DoResolve(TermNode(&f)(const ContextNode&, string_view), TermNode& term,
@@ -766,6 +776,10 @@
766776 RegisterForm(renv, "$let%", LetRef);
767777 RegisterForm(renv, "$let/e", LetWithEnvironment);
768778 RegisterForm(renv, "$let/e%", LetWithEnvironmentRef);
779+ RegisterForm(renv, "$let*", LetAsterisk);
780+ RegisterForm(renv, "$let*%", LetAsteriskRef);
781+ RegisterForm(renv, "$letrec", LetRec);
782+ RegisterForm(renv, "$letrec%", LetRecRef);
769783 RegisterStrict(renv, "make-standard-environment", ystdex::bind1(
770784 // NOTE: The weak reference of the ground environment is saved and it
771785 // shall not be moved after being called.
@@ -886,7 +900,8 @@
886900 )NPL"
887901 # endif
888902 // XXX: The operatives '$defl!', '$defl%!', '$defw%!', '$defv%!',
889- // '$defw!' and '$lambda/e' are same to following derivations in %LoadCore.
903+ // '$defw!', '$lambda/e' and '$lambda/e%' are same to following derivations
904+ // in %LoadCore.
890905 // NOTE: Use of 'eqv?' is more efficient than '$if'.
891906 R"NPL(
892907 $def! $sequence
@@ -1011,12 +1026,60 @@
10111026 $defl! append (.&ls) foldr1 list-concat () (move! ls);
10121027 $defl%! list-extract-first (&l) map1 first l;
10131028 $defl%! list-extract-rest% (&l) map1 rest% l;
1029+ $defv! $lambda/e (&e &formals .&body) d
1030+ wrap (eval (list* $vau/e e formals ignore (move! body)) d);
1031+ $defv! $lambda/e% (&e &formals .&body) d
1032+ wrap (eval (list* $vau/e% e formals ignore (move! body)) d);
1033+ $def! ($let $let% $let/e $let/e% $let* $let*% $letrec $letrec%)
1034+ ($lambda (&ce)
1035+ (
1036+ $def! mods () ($lambda/e ce ()
1037+ (
1038+ $defv%! $lqual (&ls) d
1039+ ($if (eval (list $lvalue-identifier? ls) d) as-const rulist)
1040+ (eval% ls d);
1041+ $defv%! $lqual* (&x) d
1042+ ($if (eval (list $lvalue-identifier? x) d) as-const expire)
1043+ (eval% x d);
1044+ $defl%! mk-let ($ctor &bindings &body)
1045+ list* () (list* $ctor (list-extract-first bindings)
1046+ (list (move! body))) (list-extract-rest% bindings);
1047+ $defl%! mk-let/e ($ctor &e &bindings &body)
1048+ list* () (list* $ctor e (list-extract-first bindings)
1049+ (list (move! body))) (list-extract-rest% bindings);
1050+ $defl%! mk-let* ($let $let* &bindings &body)
1051+ $if (null? bindings) (list* $let () (move! body))
1052+ (list $let (list (first% ($lqual* bindings)))
1053+ (list* $let* (rest% ($lqual* bindings)) (move! body)));
1054+ $defl%! mk-letrec ($let &bindings &body)
1055+ list $let () $sequence (list $def! (list-extract-first
1056+ bindings) (list* () list (list-extract-rest% bindings)))
1057+ (move! body);
1058+ () lock-current-environment
1059+ ));
1060+ $defv/e%! $let mods (&bindings .&body) d
1061+ eval% (mk-let $lambda ($lqual bindings) (move! body)) d;
1062+ $defv/e%! $let% mods (&bindings .&body) d
1063+ eval% (mk-let $lambda% ($lqual bindings) (move! body)) d;
1064+ $defv/e%! $let/e mods (&e &bindings .&body) d
1065+ eval% (mk-let/e $lambda/e e ($lqual bindings) (move! body)) d;
1066+ $defv/e%! $let/e% mods (&e &bindings .&body) d
1067+ eval% (mk-let/e $lambda/e% e ($lqual bindings) (move! body)) d;
1068+ $defv/e%! $let* mods (&bindings .&body) d
1069+ eval% (mk-let* $let $let* ($lqual* bindings) (move! body)) d;
1070+ $defv/e%! $let*% mods (&bindings .&body) d
1071+ eval% (mk-let* $let% $let*% ($lqual* bindings) (move! body)) d;
1072+ $defv/e%! $letrec mods (&bindings .&body) d
1073+ eval% (mk-letrec $let ($lqual bindings) (move! body)) d;
1074+ $defv/e%! $letrec% mods (&bindings .&body) d
1075+ eval% (mk-letrec $let% ($lqual bindings) (move! body)) d;
1076+ map1 move!
1077+ (list% $let $let% $let/e $let/e% $let* $let*% $letrec $letrec%)
1078+ )) (() get-current-environment);
10141079 $defv! $defw! (&f &formals &ef .&body) d
10151080 eval (list $set! d f wrap (list* $vau formals ef (move! body))) d;
10161081 $defw! derive-current-environment (.&envs) d
10171082 apply make-environment (append envs (list d)) d;
1018- $defv! $lambda/e (&e &formals .&body) d
1019- wrap (eval (list* $vau/e e formals ignore (move! body)) d);
10201083 )NPL"
10211084 # if NPL_Impl_NPLA1_Use_LockEnvironment
10221085 R"NPL(
@@ -1143,89 +1206,6 @@
11431206 ((eqv? x (first& (first& alist))) first alist)
11441207 (#t assv (forward! x) (rest% alist));
11451208 )NPL");
1146-#if NPL_Impl_NPLA1_Native_Forms
1147- context.Perform(R"NPL(
1148- $def! ($let* $let*% $letrec $letrec%) ($lambda (&ce)
1149- (
1150- $def! mods () ($lambda/e ce ()
1151- (
1152- $defv%! $lqual (&ls) d
1153- ($if (eval (list $lvalue-identifier? ls) d) as-const rulist)
1154- (eval% ls d);
1155- $defv%! $lqual* (&x) d
1156- ($if (eval (list $lvalue-identifier? x) d) as-const expire)
1157- (eval% x d);
1158- $defl%! mk-let* ($let $let* &bindings &body)
1159- $if (null? bindings) (list* $let () (move! body))
1160- (list $let (list (first% ($lqual* bindings)))
1161- (list* $let* (rest% ($lqual* bindings)) (move! body)));
1162- $defl%! mk-letrec ($let &bindings &body)
1163- list $let () $sequence (list $def! (list-extract-first
1164- bindings) (list* () list (list-extract-rest% bindings)))
1165- (move! body);
1166- () lock-current-environment
1167- ));
1168- $defv/e%! $let* mods (&bindings .&body) d
1169- eval% (mk-let* $let $let* ($lqual* bindings) (move! body)) d;
1170- $defv/e%! $let*% mods (&bindings .&body) d
1171- eval% (mk-let* $let% $let*% ($lqual* bindings) (move! body)) d;
1172- $defv/e%! $letrec mods (&bindings .&body) d
1173- eval% (mk-letrec $let ($lqual bindings) (move! body)) d;
1174- $defv/e%! $letrec% mods (&bindings .&body) d
1175- eval% (mk-letrec $let% ($lqual bindings) (move! body)) d;
1176- map1 move! (list% $let* $let*% $letrec $letrec%)
1177- )) (() get-current-environment);
1178- )NPL");
1179-#else
1180- context.Perform(R"NPL(
1181- $def! ($let $let% $let/e $let/e% $let* $let*% $letrec $letrec%)
1182- ($lambda (&ce)
1183- (
1184- $def! mods () ($lambda/e ce ()
1185- (
1186- $defv%! $lqual (&ls) d
1187- ($if (eval (list $lvalue-identifier? ls) d) as-const rulist)
1188- (eval% ls d);
1189- $defv%! $lqual* (&x) d
1190- ($if (eval (list $lvalue-identifier? x) d) as-const expire)
1191- (eval% x d);
1192- $defl%! mk-let ($ctor &bindings &body)
1193- list* () (list* $ctor (list-extract-first bindings)
1194- (list (move! body))) (list-extract-rest% bindings);
1195- $defl%! mk-let/e ($ctor &e &bindings &body)
1196- list* () (list* $ctor e (list-extract-first bindings)
1197- (list (move! body))) (list-extract-rest% bindings);
1198- $defl%! mk-let* ($let $let* &bindings &body)
1199- $if (null? bindings) (list* $let () (move! body))
1200- (list $let (list (first% ($lqual* bindings)))
1201- (list* $let* (rest% ($lqual* bindings)) (move! body)));
1202- $defl%! mk-letrec ($let &bindings &body)
1203- list $let () $sequence (list $def! (list-extract-first
1204- bindings) (list* () list (list-extract-rest% bindings)))
1205- (move! body);
1206- () lock-current-environment
1207- ));
1208- $defv/e%! $let mods (&bindings .&body) d
1209- eval% (mk-let $lambda ($lqual bindings) (move! body)) d;
1210- $defv/e%! $let% mods (&bindings .&body) d
1211- eval% (mk-let $lambda% ($lqual bindings) (move! body)) d;
1212- $defv/e%! $let/e mods (&e &bindings .&body) d
1213- eval% (mk-let/e $lambda/e e ($lqual bindings) (move! body)) d;
1214- $defv/e%! $let/e% mods (&e &bindings .&body) d
1215- eval% (mk-let/e $lambda/e% e ($lqual bindings) (move! body)) d;
1216- $defv/e%! $let* mods (&bindings .&body) d
1217- eval% (mk-let* $let $let* ($lqual* bindings) (move! body)) d;
1218- $defv/e%! $let*% mods (&bindings .&body) d
1219- eval% (mk-let* $let% $let*% ($lqual* bindings) (move! body)) d;
1220- $defv/e%! $letrec mods (&bindings .&body) d
1221- eval% (mk-letrec $let ($lqual bindings) (move! body)) d;
1222- $defv/e%! $letrec% mods (&bindings .&body) d
1223- eval% (mk-letrec $let% ($lqual bindings) (move! body)) d;
1224- map1 move!
1225- (list% $let $let% $let/e $let/e% $let* $let*% $letrec $letrec%)
1226- )) (() get-current-environment);
1227- )NPL");
1228-#endif
12291209 context.Perform(R"NPL(
12301210 $defv! $as-environment (.&body) d
12311211 eval (list $let () (list $sequence (move! body)
@@ -1481,14 +1461,14 @@
14811461
14821462 RegisterStrict(renv, "cmd-get-args", [](TermNode& term){
14831463 RetainN(term, 0);
1484- term.GetContainerRef() = []{
1464+ {
14851465 const auto p_cmd_args(LockCommandArguments());
14861466 TermNode::Container con{};
14871467
14881468 for(const auto& arg : p_cmd_args->Arguments)
14891469 TermNode::AddValueTo(con, in_place_type<string>, arg);
1490- return con;
1491- }();
1470+ con.swap(term.GetContainerRef());
1471+ }
14921472 return ReductionStatus::Retained;
14931473 });
14941474 RegisterUnary<Strict, const string>(renv, "env-get", [](const string& var){
diff -r dfccd642351f -r 8f214fbb4405 YFramework/source/NPL/NPLA.cpp
--- a/YFramework/source/NPL/NPLA.cpp Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/source/NPL/NPLA.cpp Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA.cpp
1212 \ingroup NPL
1313 \brief NPLA 公共接口。
14-\version r3542
14+\version r3559
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 663
1717 \par 创建时间:
1818 2016-01-07 10:32:45 +0800
1919 \par 修改时间:
20- 2021-03-26 03:29 +0800
20+ 2021-04-20 01:29 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -596,11 +596,11 @@
596596
597597 void
598598 ThrowListTypeErrorForInvalidType(const ystdex::type_info& tp,
599- const TermNode& term, bool is_ref)
599+ const TermNode& term, bool has_ref)
600600 {
601601 throw ListTypeError(ystdex::sfmt("Expected a value of type '%s', got a list"
602602 " '%s'.", tp.name(),
603- TermToStringWithReferenceMark(term, is_ref).c_str()));
603+ TermToStringWithReferenceMark(term, has_ref).c_str()));
604604 }
605605
606606 void
@@ -611,6 +611,14 @@
611611 }
612612
613613 void
614+ThrowTypeErrorForInvalidType(const ystdex::type_info& tp, const TermNode& term,
615+ bool has_ref)
616+{
617+ throw TypeError(ystdex::sfmt("Expected a value of type '%s', got '%s'.",
618+ tp.name(), TermToStringWithReferenceMark(term, has_ref).c_str()));
619+}
620+
621+void
614622 TokenizeTerm(TermNode& term)
615623 {
616624 for(auto& child : term)
@@ -746,7 +754,8 @@
746754 term.SetContent(TermNode(std::move(tm.GetContainerRef()),
747755 std::move(pr.first)));
748756 else if(pr.second)
749- term.Value = std::move(pr.first);
757+ yunseq(term.Value = std::move(pr.first),
758+ term.Tags = TermTags::Unqualified);
750759 }
751760
752761 void
@@ -797,9 +806,9 @@
797806 void
798807 MoveRValueToForward(TermNode& term, TermNode& tm)
799808 {
800-# if true
809+#if true
801810 MoveRValueFor(term, tm, &TermReference::IsModifiable);
802-# else
811+#else
803812 // NOTE: For exposition only. The optimized implemenation shall be
804813 // equivalent to this, except for the copy elision.
805814 LiftOther(term, tm);
@@ -808,21 +817,21 @@
808817 if(const auto p = NPL::TryAccessLeaf<const TermReference>(term))
809818 LiftMovedOther(term, *p, p->IsModifiable());
810819 }
811-# endif
820+#endif
812821 }
813822
814823 void
815824 MoveRValueToReturn(TermNode& term, TermNode& tm)
816825 {
817-# if true
826+#if true
818827 MoveRValueFor(term, tm, &TermReference::IsMovable);
819-# else
828+#else
820829 // NOTE: For exposition only. The optimized implemenation shall be
821830 // equivalent to this, except for the copy elision.
822831 LiftOther(term, tm);
823832 if(!IsBoundLValueTerm(term))
824833 LiftToReturn(term);
825-# endif
834+#endif
826835 }
827836
828837
diff -r dfccd642351f -r 8f214fbb4405 YFramework/source/NPL/NPLA1.cpp
--- a/YFramework/source/NPL/NPLA1.cpp Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/source/NPL/NPLA1.cpp Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1.cpp
1212 \ingroup NPL
1313 \brief NPLA1 公共接口。
14-\version r20500
14+\version r20783
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 473
1717 \par 创建时间:
1818 2014-02-02 18:02:47 +0800
1919 \par 修改时间:
20- 2021-04-10 08:25 +0800
20+ 2021-04-21 18:08 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -600,6 +600,90 @@
600600 };
601601
602602
603+//! \since build 917
604+struct ParameterCheck final
605+{
606+ using HasReferenceArg = ystdex::true_;
607+
608+ static void
609+ CheckBack(const TermNode& t, bool t_has_ref)
610+ {
611+ if(YB_UNLIKELY(!IsList(t)))
612+ ThrowFormalParameterTypeError(t, t_has_ref);
613+ }
614+
615+ template<typename _func>
616+ static void
617+ HandleLeaf(_func f, const TermNode& t, bool t_has_ref)
618+ {
619+ if(const auto p = TermToNamePtr(t))
620+ {
621+ const auto& n(*p);
622+
623+ if(!IsIgnore(n))
624+ {
625+ if(IsNPLASymbol(n))
626+ f(n);
627+ else
628+ ThrowInvalidTokenError(n);
629+ }
630+ }
631+ else
632+ ThrowFormalParameterTypeError(t, t_has_ref);
633+ }
634+
635+ template<typename _func>
636+ static void
637+ WrapCall(_func f)
638+ {
639+ try
640+ {
641+ f();
642+ }
643+ CatchExpr(ParameterMismatch&, throw)
644+ CatchExpr(..., ThrowNestedParameterTreeCheckError())
645+ }
646+};
647+
648+
649+//! \since build 917
650+struct NoParameterCheck final
651+{
652+ using HasReferenceArg = ystdex::false_;
653+
654+ static void
655+ CheckBack(const TermNode& t)
656+ {
657+ yunused(t);
658+ YAssert(IsList(t), "Invalid parameter tree found.");
659+ }
660+
661+ template<typename _func>
662+ static void
663+ HandleLeaf(_func f, const TermNode& t)
664+ {
665+ const auto p(TermToNamePtr(t));
666+
667+ YAssert(bool(p), "Invalid parameter tree found.");
668+
669+ const auto& n(*p);
670+
671+ if(!IsIgnore(n))
672+ {
673+ YAssert(IsNPLASymbol(n), "Invalid parameter tree found.");
674+ f(n);
675+ }
676+ }
677+
678+ template<typename _func>
679+ static void
680+ WrapCall(_func f)
681+ {
682+ f();
683+ }
684+};
685+
686+
603687 //! \since build 882
604688 //@{
605689 #if false
@@ -612,9 +696,12 @@
612696 = GParameterBinder<TermNode::Container&, TNIter, const TokenValue&>;
613697 using _fBindValue = GParameterBinder<const TokenValue&, TermNode&>;
614698 #endif
699+//@}
615700
616-template<typename _fBindTrailing, typename _fBindValue>
617-class GParameterMatcher
701+//! \since build 917
702+//@{
703+template<class _tTraits, typename _fBindTrailing, typename _fBindValue>
704+class GParameterMatcher final
618705 {
619706 //! \since build 863
620707 //@{
@@ -628,6 +715,7 @@
628715 //@}
629716
630717 public:
718+ //! \since build 882
631719 template<class _type, class _type2>
632720 GParameterMatcher(_type&& arg, _type2&& arg2)
633721 : BindTrailing(yforward(arg)), BindValue(yforward(arg2))
@@ -641,27 +729,48 @@
641729 // so without handling of the environment for TCO, it still works. Anyway,
642730 // keeping it saner to be friendly to possible TCO compressions in future
643731 // seems OK.
732+ //! \since build 882
644733 void
645734 operator()(const TermNode& t, TermNode& o, TermTags o_tags,
646735 const EnvironmentReference& r_env) const
647736 {
648- // NOTE: This is a trampoline to eliminate the call depth limitation.
649- Match(t, o, o_tags, r_env);
650- while(act)
651- {
652- const auto a(std::move(act));
737+ _tTraits::WrapCall([&]{
738+ // NOTE: This is a trampoline to eliminate the call depth
739+ // limitation.
740+ DispatchMatch(typename _tTraits::HasReferenceArg(), t, o, o_tags,
741+ r_env, ystdex::false_());
742+ while(act)
743+ {
744+ const auto a(std::move(act));
653745
654- a();
655- }
746+ a();
747+ }
748+ });
656749 }
657750
658751 private:
752+ template<class _tArg>
753+ void
754+ DispatchMatch(ystdex::true_, const TermNode& t, TermNode& o,
755+ TermTags o_tags, const EnvironmentReference& r_env, _tArg) const
756+ {
757+ Match(t, o, o_tags, r_env, _tArg::value);
758+ }
759+ template<class _tArg>
760+ void
761+ DispatchMatch(ystdex::false_, const TermNode& t, TermNode& o,
762+ TermTags o_tags, const EnvironmentReference& r_env, _tArg) const
763+ {
764+ Match(t, o, o_tags, r_env);
765+ }
766+
659767 // XXX: The initial %o_tags shall have %TermTags::Temporary unless it is
660768 // known to bound to some non-temporary objects not stored in the term tree
661769 // to be reduced.
662- void
770+ template<typename... _tParams>
771+ YB_FLATTEN void
663772 Match(const TermNode& t, TermNode& o, TermTags o_tags,
664- const EnvironmentReference& r_env) const
773+ const EnvironmentReference& r_env, _tParams&&... args) const
665774 {
666775 if(IsList(t))
667776 {
@@ -684,10 +793,8 @@
684793 if(!p->empty() && p->front() == '.')
685794 --last;
686795 }
687- else if(!IsList(back))
688- throw ParameterMismatch(ystdex::sfmt(
689- "Invalid term '%s' found for symbol parameter.",
690- TermToString(back).c_str()));
796+ else
797+ _tTraits::CheckBack(back, yforward(args)...);
691798 }
692799 }
693800 // XXX: There is only one level of indirection. It should work
@@ -748,21 +855,19 @@
748855 has_ref).c_str()));
749856 }, o);
750857 }
751- else
858+ else if(const auto p_t = NPL::TryAccessLeaf<const TermReference>(t))
752859 {
753- const auto& tp(t.Value.type());
860+ auto& nd(p_t->get());
754861
755- if(tp == ystdex::type_id<TermReference>())
756- ystdex::update_thunk(act, [&, o_tags]{
757- Match(t.Value.GetObject<TermReference>().get(), o, o_tags,
758- r_env);
759- });
760- else if(tp == ystdex::type_id<TokenValue>())
761- BindValue(t.Value.GetObject<TokenValue>(), o, o_tags, r_env);
762- else
763- throw ParameterMismatch(ystdex::sfmt("Invalid parameter value"
764- " '%s' found.", TermToString(t).c_str()));
862+ ystdex::update_thunk(act, [&, o_tags]{
863+ DispatchMatch(typename _tTraits::HasReferenceArg(), nd, o,
864+ o_tags, r_env, ystdex::true_());
865+ });
765866 }
867+ else
868+ _tTraits::HandleLeaf([&](const TokenValue& n){
869+ BindValue(n, o, o_tags, r_env);
870+ }, t, yforward(args)...);
766871 }
767872
768873 //! \since build 898
@@ -791,7 +896,8 @@
791896 #endif
792897 });
793898 YAssert(j != o_tm.end(), "Invalid state of operand found.");
794- Match(NPL::Deref(i), NPL::Deref(j), tags, r_env);
899+ DispatchMatch(typename _tTraits::HasReferenceArg(), NPL::Deref(i),
900+ NPL::Deref(j), tags, r_env, ystdex::false_());
795901 }
796902 else if(ellipsis)
797903 {
@@ -808,13 +914,103 @@
808914 };
809915
810916 //! \relates GParameterMatcher
811-template<typename _fBindTrailing, typename _fBindValue>
812-YB_ATTR_nodiscard inline GParameterMatcher<_fBindTrailing, _fBindValue>
917+template<class _tTraits, typename _fBindTrailing, typename _fBindValue>
918+YB_ATTR_nodiscard inline
919+ GParameterMatcher<_tTraits, _fBindTrailing, _fBindValue>
813920 MakeParameterMatcher(_fBindTrailing bind_trailing_seq, _fBindValue bind_value)
814921 {
815- return GParameterMatcher<_fBindTrailing, _fBindValue>(
922+ return GParameterMatcher<_tTraits, _fBindTrailing, _fBindValue>(
816923 std::move(bind_trailing_seq), std::move(bind_value));
817924 }
925+
926+
927+template<class _tTraits>
928+YB_FLATTEN void
929+BindParameterImpl(const shared_ptr<Environment>& p_env, const TermNode& t,
930+ TermNode& o)
931+{
932+ auto& env(NPL::Deref(p_env));
933+
934+ // NOTE: No duplication check here. Symbols can be rebound.
935+ // TODO: Additional ownership and lifetime check to kept away undefined
936+ // behavior?
937+ // NOTE: The call is essentially same as %MatchParameter, with a bit better
938+ // performance by avoiding %function instances.
939+ MakeParameterMatcher<_tTraits>([&](TermNode& o_tm, TNIter first,
940+ string_view id, TermTags o_tags, const EnvironmentReference& r_env){
941+ YAssert(ystdex::begins_with(id, "."), "Invalid symbol found.");
942+ id.remove_prefix(1);
943+ if(!id.empty())
944+ {
945+ const char sigil(ExtractSigil(id));
946+
947+ if(!id.empty())
948+ {
949+ const auto a(o_tm.get_allocator());
950+ const auto last(o_tm.end());
951+ TermNode::Container con(a);
952+
953+ // XXX: As %TermReference::IsMovable for non-temporary objects.
954+ if((o_tags & (TermTags::Unique | TermTags::Nonmodifying))
955+ == TermTags::Unique || bool(o_tags & TermTags::Temporary))
956+ {
957+ if(sigil == char())
958+ LiftSubtermsToReturn(o_tm);
959+ // NOTE: This implements the copy elision of list members.
960+ con.splice(con.end(), o_tm.GetContainerRef(), first, last);
961+ MarkTemporaryTerm(env.Bind(id, TermNode(std::move(con))),
962+ sigil);
963+ }
964+ else
965+ {
966+ // NOTE: Make list subobject reference.
967+ for(; first != last; ++first)
968+ BindParameterObject{r_env}(sigil, {}, o_tags,
969+ NPL::Deref(first), [&](const TermNode& tm){
970+ CopyTermTags(con.emplace_back(tm.GetContainer(),
971+ tm.Value), tm);
972+ }, [&](TermNode::Container&& c, ValueObject&& vo)
973+ -> TermNode&{
974+ con.emplace_back(std::move(c), std::move(vo));
975+ return con.back();
976+ });
977+ if(sigil == '&')
978+ {
979+ // NOTE: Irregular representation is constructed for the
980+ // list subobject reference.
981+ // XXX: As %ReduceAsSubobjectReference in
982+ // NPLA1Internals.
983+ auto p_sub(YSLib::allocate_shared<TermNode>(a,
984+ std::move(con)));
985+ auto& sub(NPL::Deref(p_sub));
986+
987+ env.Bind(id, TermNode(std::allocator_arg, a,
988+ {NPL::AsTermNode(a, std::move(p_sub))},
989+ std::allocator_arg, a, TermReference(sub, r_env)));
990+ }
991+ else
992+ MarkTemporaryTerm(env.Bind(id,
993+ TermNode(std::move(con))), sigil);
994+ }
995+ }
996+ }
997+ }, [&](const TokenValue& n, TermNode& b, TermTags o_tags,
998+ const EnvironmentReference& r_env){
999+ YAssert(!IsIgnore(n) && IsNPLASymbol(n), "Invalid token found.");
1000+
1001+ string_view id(n);
1002+ const char sigil(ExtractSigil(id));
1003+
1004+ if(!id.empty())
1005+ BindParameterObject{r_env}(sigil, sigil == '&', o_tags, b,
1006+ [&](const TermNode& tm){
1007+ CopyTermTags(env.Bind(id, tm), tm);
1008+ }, [&](TermNode::Container&& c, ValueObject&& vo) -> TermNode&{
1009+ // XXX: Allocators are not used here for performance.
1010+ return env.Bind(id, TermNode(std::move(c), std::move(vo)));
1011+ });
1012+ })(t, o, TermTags::Temporary, p_env);
1013+}
8181014 //@}
8191015
8201016 } // unnamed namespace;
@@ -832,6 +1028,14 @@
8321028 }
8331029
8341030 void
1031+ThrowInvalidTokenError(string_view sv)
1032+{
1033+ YAssertNonnull(sv.data());
1034+ ThrowInvalidSyntaxError(ystdex::sfmt("Invalid token '%s' found",
1035+ sv.data()));
1036+}
1037+
1038+void
8351039 ThrowNonmodifiableErrorForAssignee()
8361040 {
8371041 throw TypeError("Destination operand of assignment shall be modifiable.");
@@ -978,9 +1182,9 @@
9781182 // evaluation can be potentionally parallel, though the simplest one is
9791183 // left-to-right.
9801184 // XXX: Use execution policies to be evaluated concurrently?
981- // NOTE: This does not support PTC, but allow it to be called
982- // in routines which expect proper tail actions, given the guarnatee that
983- // the precondition of %Reduce is not violated.
1185+ // NOTE: This does not support PTC, but allow it to be called in routines
1186+ // which expect proper tail actions, given the guarnatee that the
1187+ // precondition of %Reduce is not violated.
9841188 // XXX: The remained tail action would be dropped.
9851189 #if NPL_Impl_NPLA1_Enable_Thunked
9861190 ReduceChildrenOrderedAsync(first, last, ctx);
@@ -1605,117 +1809,55 @@
16051809
16061810
16071811 void
1812+CheckParameterTree(const TermNode& term)
1813+{
1814+ MakeParameterValueMatcher([&](const TokenValue&) ynothrow{})(term);
1815+}
1816+
1817+string
1818+CheckEnvironmentFormal(const TermNode& term)
1819+{
1820+ TryRet(ResolveTerm([&](const TermNode& nd, bool has_ref) -> string{
1821+ if(const auto p = TermToNamePtr(nd))
1822+ {
1823+ if(!IsIgnore(*p))
1824+ {
1825+ if(YB_UNLIKELY(!IsNPLASymbol(*p)))
1826+ ThrowInvalidTokenError(*p);
1827+ return string(*p, term.get_allocator());
1828+ }
1829+ }
1830+ else
1831+ ThrowFormalParameterTypeError(nd, has_ref);
1832+ return string(term.get_allocator());
1833+ }, term))
1834+ CatchExpr(..., std::throw_with_nested(InvalidSyntax("Failed checking for"
1835+ " environment formal parameter (expected a symbol).")))
1836+}
1837+
1838+void
16081839 MatchParameter(const TermNode& t, TermNode& o, function<void(TermNode&, TNIter,
16091840 const TokenValue&, TermTags, const EnvironmentReference&)>
16101841 bind_trailing_seq, function<void(const TokenValue&, TermNode&, TermTags,
16111842 const EnvironmentReference&)> bind_value, TermTags o_tags,
16121843 const EnvironmentReference& r_env)
16131844 {
1614- MakeParameterMatcher(std::move(bind_trailing_seq), std::move(bind_value))(t,
1615- o, o_tags, r_env);
1845+ MakeParameterMatcher<ParameterCheck>(std::move(bind_trailing_seq),
1846+ std::move(bind_value))(t, o, o_tags, r_env);
16161847 }
16171848
16181849 void
16191850 BindParameter(const shared_ptr<Environment>& p_env, const TermNode& t,
16201851 TermNode& o)
16211852 {
1622- auto& env(NPL::Deref(p_env));
1623- const auto check_sigil([&](string_view& id){
1624- char sigil(id.front());
1625-
1626- if(sigil != '&' && sigil != '%' && sigil != '@')
1627- sigil = char();
1628- else
1629- id.remove_prefix(1);
1630- return sigil;
1631- });
1632-
1633- // NOTE: No duplication check here. Symbols can be rebound.
1634- // TODO: Additional ownership and lifetime check to kept away undefined
1635- // behavior?
1636- // NOTE: The call is essentially same as %MatchParameter, with a bit better
1637- // performance by avoiding %function instances.
1638- MakeParameterMatcher([&, check_sigil](TermNode& o_tm, TNIter first,
1639- string_view id, TermTags o_tags, const EnvironmentReference& r_env){
1640- YAssert(ystdex::begins_with(id, "."), "Invalid symbol found.");
1641- id.remove_prefix(1);
1642- if(!id.empty())
1643- {
1644- const char sigil(check_sigil(id));
1645-
1646- if(!id.empty())
1647- {
1648- const auto a(o_tm.get_allocator());
1649- const auto last(o_tm.end());
1650- TermNode::Container con(a);
1853+ BindParameterImpl<ParameterCheck>(p_env, t, o);
1854+}
16511855
1652- // XXX: As %TermReference::IsMovable for non-temporary objects.
1653- if((o_tags & (TermTags::Unique | TermTags::Nonmodifying))
1654- == TermTags::Unique || bool(o_tags & TermTags::Temporary))
1655- {
1656- if(sigil == char())
1657- LiftSubtermsToReturn(o_tm);
1658- // NOTE: This implements the copy elision of list members.
1659- con.splice(con.end(), o_tm.GetContainerRef(), first, last);
1660- MarkTemporaryTerm(env.Bind(id, TermNode(std::move(con))),
1661- sigil);
1662- }
1663- else
1664- {
1665- // NOTE: Make list subobject reference.
1666- for(; first != last; ++first)
1667- // TODO: Blocked. Use C++17 sequence container return
1668- // value.
1669- BindParameterObject{r_env}(sigil, {}, o_tags,
1670- NPL::Deref(first), [&](const TermNode& tm){
1671- con.emplace_back(tm.GetContainer(), tm.Value);
1672- CopyTermTags(con.back(), tm);
1673- }, [&](TermNode::Container&& c, ValueObject&& vo)
1674- -> TermNode&{
1675- con.emplace_back(std::move(c), std::move(vo));
1676- return con.back();
1677- });
1678- if(sigil == '&')
1679- {
1680- // NOTE: Irregular representation is constructed for the
1681- // list subobject reference.
1682- // XXX: As %ReduceAsSubobjectReference in
1683- // NPLA1Internals.
1684- auto p_sub(YSLib::allocate_shared<TermNode>(a,
1685- std::move(con)));
1686- auto& sub(NPL::Deref(p_sub));
1687-
1688- env.Bind(id, TermNode(std::allocator_arg, a,
1689- {NPL::AsTermNode(a, std::move(p_sub))},
1690- std::allocator_arg, a, TermReference(sub, r_env)));
1691- }
1692- else
1693- MarkTemporaryTerm(env.Bind(id,
1694- TermNode(std::move(con))), sigil);
1695- }
1696- }
1697- }
1698- }, [&](const TokenValue& n, TermNode& b, TermTags o_tags,
1699- const EnvironmentReference& r_env){
1700- CheckParameterLeafToken(n, [&]{
1701- if(!n.empty())
1702- {
1703- string_view id(n);
1704- const char sigil(check_sigil(id));
1705-
1706- if(!id.empty())
1707- BindParameterObject{r_env}(sigil, sigil == '&', o_tags, b,
1708- [&](const TermNode& tm){
1709- CopyTermTags(env.Bind(id, tm), tm);
1710- }, [&](TermNode::Container&& c, ValueObject&& vo)
1711- -> TermNode&{
1712- // XXX: Allocators are not used here for performance.
1713- return env.Bind(id,
1714- TermNode(std::move(c), std::move(vo)));
1715- });
1716- }
1717- });
1718- })(t, o, TermTags::Temporary, p_env);
1856+void
1857+BindParameterWellFormed(const shared_ptr<Environment>& p_env, const TermNode& t,
1858+ TermNode& o)
1859+{
1860+ BindParameterImpl<NoParameterCheck>(p_env, t, o);
17191861 }
17201862
17211863
diff -r dfccd642351f -r 8f214fbb4405 YFramework/source/NPL/NPLA1Forms.cpp
--- a/YFramework/source/NPL/NPLA1Forms.cpp Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/source/NPL/NPLA1Forms.cpp Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Forms.cpp
1212 \ingroup NPL
1313 \brief NPLA1 语法形式。
14-\version r22371
14+\version r23303
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2014-02-15 11:19:51 +0800
1919 \par 修改时间:
20- 2021-04-14 12:01 +0800
20+ 2021-04-20 22:53 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -33,15 +33,18 @@
3333 // AccessFirstSubterm, ReduceSubsequent, ReduceCombinedBranch,
3434 // std::placeholders, std::ref, std::bind, ystdex::as_const, IsLeaf,
3535 // ValueObject, ystdex::ref_eq, RelaySwitched, ContextHandler, shared_ptr,
36-// string, unordered_map, Environment, lref, list, IsBranchedList, TokenValue,
37-// NPL::TryAccessLeaf, weak_ptr, any_ops::use_holder, in_place_type,
38-// ystdex::type_id, YSLib::allocate_shared, InvalidReference, MoveFirstSubterm,
39-// ShareMoveTerm, ThrowInvalidSyntaxError, LiftOtherOrCopy, ResolveTerm,
40-// ystdex::make_transform, ystdex::equality_comparable, std::allocator_arg,
41-// NPL::AsTermNode, ystdex::exchange, NPL::SwitchToFreshEnvironment, TermTags,
36+// string, unordered_map, Environment, lref, list, IsBranchedList,
37+// NPL::TryAccessLeaf, TokenValue, IsIgnore, IsNPLASymbol, any_ops::use_holder,
38+// in_place_type, YSLib::allocate_shared, InvalidReference, MoveFirstSubterm,
39+// BindParameter, ShareMoveTerm, BindParameterWellFormed,
40+// TermToStringWithReferenceMark, LiftOtherOrCopy, ResolveTerm,
41+// ystdex::make_transform, std::allocator_arg, ystdex::equality_comparable,
42+// CheckParameterTree, NPL::AsTermNode, ystdex::exchange,
43+// NPL::SwitchToFreshEnvironment, ThrowInvalidSyntaxError, TermTags,
4244 // ystdex::expand_proxy, NPL::AccessRegular, TermReference, GetLValueTagsOf,
4345 // RegularizeTerm, ThrowValueCategoryError, ThrowListTypeErrorForNonlist,
44-// ystdex::update_thunk, NPL::TryAccessReferencedLeaf, ystdex::invoke_value_or,
46+// CheckEnvironmentFormal, ystdex::type_id, ystdex::update_thunk,
47+// NPL::TryAccessReferencedLeaf, ystdex::invoke_value_or,
4548 // ystdex::call_value_or, LiftMovedOther, ystdex::bind1, LiftCollapsed,
4649 // NPL::AllocateEnvironment, NPL::TryAccessTerm, std::mem_fn;
4750 #include "NPLA1Internals.h" // for A1::Internals API;
@@ -120,8 +123,9 @@
120123 }
121124
122125 #if NPL_Impl_NPLA1_Enable_Thunked
126+//! \since build 917
123127 ReductionStatus
124-CondImpl(TermNode& term, ContextNode& ctx, TNIter i)
128+ReduceCond(TermNode& term, ContextNode& ctx, TNIter i)
125129 {
126130 if(i != term.end())
127131 {
@@ -133,7 +137,7 @@
133137 A1::NameTypedReducerHandler([&, i, j](ContextNode& c){
134138 if(CondTest(clause, j))
135139 return ReduceOnceLifted(term, c, clause);
136- return CondImpl(term, c, std::next(i));
140+ return ReduceCond(term, c, std::next(i));
137141 }, "eval-cond-list"));
138142 }
139143 return ReduceReturnUnspecified(term);
@@ -255,7 +259,8 @@
255259 }, static_cast<const TermNode&(&)(const TermNode&)>(ReferenceTerm));
256260 }
257261
258-YB_PURE inline PDefH(bool, TermUnequal, const TermNode& x, const TermNode& y)
262+YB_ATTR_nodiscard YB_PURE inline
263+ PDefH(bool, TermUnequal, const TermNode& x, const TermNode& y)
259264 ImplRet(x.size() != y.size() || x.Value != y.Value)
260265
261266 #if NPL_Impl_NPLA1_Enable_Thunked
@@ -321,7 +326,7 @@
321326 //! \since build 784
322327 using shared_ptr_t = shared_ptr<ContextHandler>;
323328 //! \since build 784
324- unordered_map<string, shared_ptr_t> store{};
329+ unordered_map<string, shared_ptr_t> store;
325330
326331 public:
327332 //! \since build 894
@@ -329,10 +334,9 @@
329334 //! \since build 893
330335 lref<const TermNode> TermRef;
331336
332- //! \since build 894
337+ //! \since build 917
333338 RecursiveThunk(const shared_ptr<Environment>& p_env, const TermNode& t)
334- ynothrow
335- : RecordPtr(p_env), TermRef(t)
339+ : store(t.get_allocator()), RecordPtr(p_env), TermRef(t)
336340 {
337341 Fix(RecordPtr, TermRef);
338342 }
@@ -347,30 +351,33 @@
347351 void
348352 Fix(const shared_ptr<Environment>& p_env, const TermNode& t)
349353 {
354+ // XXX: This is served as the addtional static environment.
350355 auto& env(NPL::Deref(p_env));
351356
352- if(IsBranchedList(t))
353- for(const auto& tm : t)
354- Fix(p_env, tm);
355- else if(const auto p = NPL::TryAccessLeaf<TokenValue>(t))
356- {
357- const auto& n(*p);
358-
359- // XXX: This is served as the addtional static environment.
360- CheckParameterLeafToken(n, [&]{
357+ MakeParameterValueMatcher([&](const TokenValue& n){
358+ YAssert(!IsIgnore(n) && IsNPLASymbol(n), "Invalid token found.");
359+
360+ string_view id(n);
361+
362+ ExtractSigil(id);
363+
364+ if(!id.empty())
365+ {
366+ string k(id, store.get_allocator());
367+
361368 // NOTE: The symbol can be bound more than once. Only one
362369 // instance is supported.
363- if(store.find(n) == store.cend())
364- // NOTE: This binds value to a local thunk value. The bound
365- // symbol can then be rebound to an ordinary (non-sharing)
366- // object.
367- env.Bind(n, TermNode(TermNode::Container(t.get_allocator()),
368- ValueObject(any_ops::use_holder, in_place_type<
369- HolderFromPointer<shared_ptr_t>>,
370- store[n] = YSLib::allocate_shared<ContextHandler>(
370+ if(store.find(k) == store.cend())
371+ // NOTE: This binds value to a local thunk value. The
372+ // bound symbol can then be rebound to an ordinary
373+ // (non-sharing object.
374+ env.Bind(k, TermNode(TermNode::Container(
375+ t.get_allocator()), ValueObject(any_ops::use_holder,
376+ in_place_type<HolderFromPointer<shared_ptr_t>>,
377+ store[k] = YSLib::allocate_shared<ContextHandler>(
371378 t.get_allocator(), ThrowInvalidCyclicReference))));
372- });
373- }
379+ }
380+ })(t);
374381 }
375382
376383 //! \since build 780
@@ -409,14 +416,19 @@
409416 CatchExpr(..., std::throw_with_nested(std::move(e)))
410417 }
411418
412-//! \since build 899
419+//! \since build 917
420+YB_NORETURN inline void
421+ThrowLetError(TermNode& term)
422+{
423+ RemoveHead(term);
424+ ThrowInsufficientTermsError(term, {});
425+}
426+
427+//! \since build 917
413428 void
414-BindParameterChecked(const shared_ptr<Environment>& p_env, const TermNode& t,
415- TermNode& o)
429+CheckFrozenEnvironment(const shared_ptr<Environment>& p_env)
416430 {
417- if(!p_env->Frozen)
418- BindParameter(p_env, t, o);
419- else
431+ if(YB_UNLIKELY(NPL::Deref(p_env).Frozen))
420432 throw TypeError("Cannot define variables in a frozen environment.");
421433 }
422434
@@ -494,28 +506,20 @@
494506 return ReduceSubsequent(term, ctx,
495507 A1::NameTypedReducerHandler(std::bind([&](const TermNode& saved,
496508 const shared_ptr<Environment>& p_e, const _tParams&...){
497- BindParameterChecked(p_e, saved, term);
509+ CheckFrozenEnvironment(p_e);
510+ BindParameter(p_e, saved, term);
498511 return ReduceReturnUnspecified(term);
499512 }, std::move(formals), std::move(p_env), std::move(args)...),
500513 "match-ptree"));
501514 #else
502515 yunseq(0, args...);
503516 // NOTE: This does not support PTC.
504- CallImpl(term, ctx, p_env, formals);
517+ ReduceOnce(term, ctx);
518+ CheckFrozenEnvironment(p_env);
519+ BindParameter(p_env, formals, term);
505520 return ReduceReturnUnspecified(term);
506521 #endif
507522 }
508-
509-#if !NPL_Impl_NPLA1_Enable_Thunked
510- //! \since build 894
511- static void
512- CallImpl(TermNode& term, ContextNode& ctx,
513- const shared_ptr<Environment>& p_env, TermNode& formals)
514- {
515- ReduceOnce(term, ctx);
516- BindParameterChecked(p_env, formals, term);
517- }
518-#endif
519523 };
520524
521525 template<>
@@ -538,7 +542,10 @@
538542 A1::NameTypedReducerHandler(std::bind([&](const
539543 shared_ptr<TermNode>&, const shared_ptr<RecursiveThunk>& p_gd,
540544 const _tParams&...){
541- BindParameterChecked(p_gd->RecordPtr, p_gd->TermRef, term);
545+ CheckFrozenEnvironment(p_gd->RecordPtr);
546+ // NOTE: The parameter tree shall have been checked in the
547+ // initialization of %RecursiveThunk.
548+ BindParameterWellFormed(p_gd->RecordPtr, p_gd->TermRef, term);
542549 // NOTE: This support PTC only when the thunk cleanup is not existed
543550 // at the tail context.
544551 return ReduceReturnUnspecified(term);
@@ -550,7 +557,11 @@
550557 RecursiveThunk gd(std::move(p_env), formals);
551558
552559 yunseq(0, args...);
553- DoDefineOrSet<>::CallImpl(term, ctx, gd.RecordPtr, formals);
560+ ReduceOnce(term, ctx);
561+ CheckFrozenEnvironment(gd.RecordPtr);
562+ // NOTE: The parameter tree shall have been checked in the
563+ // initialization of %RecursiveThunk.
564+ BindParameterWellFormed(gd.RecordPtr, formals, term);
554565 // NOTE: This support PTC only when the thunk cleanup is not existed at
555566 // the tail context.
556567 return ReduceReturnUnspecified(term);
@@ -577,55 +588,6 @@
577588 //@}
578589
579590
580-//! \since build 860
581-//@{
582-YB_ATTR_nodiscard YB_PURE inline
583- PDefH(bool, IsIgnore, const TokenValue& s) ynothrow
584- // XXX: This is more efficient than cast to %basic_string_view if the
585- // %basic_string implementation is optimized.
586- ImplRet(s == "#ignore")
587-
588-YB_ATTR_nodiscard YB_PURE inline
589- PDefH(bool, IsIgnoreOrNPLASymbol, const TokenValue& s) ynothrow
590- ImplRet(IsIgnore(s) || IsNPLASymbol(s))
591-
592-YB_NONNULL(2) void
593-CheckVauSymbol(const TokenValue& s, const char* target, bool is_valid)
594-{
595- if(YB_UNLIKELY(!is_valid))
596- ThrowInvalidSyntaxError(ystdex::sfmt("Token '%s' is not a symbol or"
597- " '#ignore' expected for %s.", s.data(), target));
598-}
599-//@}
600-
601-//! \since build 799
602-YB_NORETURN YB_NONNULL(2) void
603-ThrowInvalidSymbolType(const TermNode& term, const char* n)
604-{
605- ThrowInvalidSyntaxError(ystdex::sfmt("Invalid %s type '%s' found.", n,
606- term.Value.type().name()));
607-}
608-
609-//! \since build 781
610-YB_ATTR_nodiscard YB_PURE string
611-CheckEnvFormal(const TermNode& term)
612-{
613- const auto& nd(ReferenceTerm(term));
614-
615- if(const auto p = TermToNamePtr(nd))
616- {
617- if(!IsIgnore(*p))
618- {
619- CheckVauSymbol(*p, "environment formal parameter",
620- IsNPLASymbol(*p));
621- return *p;
622- }
623- }
624- else
625- ThrowInvalidSymbolType(nd, "environment formal parameter");
626- return {};
627-}
628-
629591 //! \since build 909
630592 YB_NORETURN void
631593 ThrowInvalidEnvironmentType(const TermNode& term, bool has_ref)
@@ -852,26 +814,6 @@
852814 return vau.DoCall(term, ctx, gd);
853815 }
854816
855-public:
856- //! \since build 799
857- static void
858- CheckParameterTree(const TermNode& term)
859- {
860- auto& nd(ReferenceTerm(term));
861-
862- for(const auto& child : nd)
863- CheckParameterTree(child);
864- if(nd.Value)
865- {
866- if(const auto p = TermToNamePtr(nd))
867- CheckVauSymbol(*p, "parameter in a parameter tree",
868- IsIgnoreOrNPLASymbol(*p));
869- else
870- ThrowInvalidSymbolType(nd, "parameter tree node");
871- }
872- }
873-
874-private:
875817 // TODO: Avoid TCO when the static environment has something with side
876818 // effects on destruction, to prevent semantic changes.
877819 //! \since build 847
@@ -890,8 +832,11 @@
890832 // substitute them as arguments for later closure reduction.
891833 // XXX: Do not lift terms if provable to be safe?
892834 // NOTE: The environment is assumed not frozen, so no need to use
893- // %BindParameterChecked.
894- BindParameter(ctx.GetRecordPtr(), NPL::Deref(p_formals), term);
835+ // %CheckFrozenEnvironment.
836+ // NOTE: The parameter tree shall have been checked in the
837+ // initialization of %VauHandler.
838+ BindParameterWellFormed(ctx.GetRecordPtr(), NPL::Deref(p_formals),
839+ term);
895840 #if NPL_Impl_NPLA1_TraceVauCall
896841 ctx.Trace.Log(Debug, [&]{
897842 return sfmt<string>("Function called, with %ld shared term(s),"
@@ -1024,37 +969,6 @@
1024969 }
1025970 //@}
1026971
1027-//! \since build 914
1028-//@{
1029-// NOTE: The tag is used for different call sites with the call to
1030-// %A1::NameTypedReducerHandler.
1031-enum ConsTag
1032-{
1033- //! \since build 916
1034- Map1Cons,
1035- ListConcatCons,
1036- ListExtractCons
1037-};
1038-
1039-template<ConsTag>
1040-struct ConsMoveSubNextRV final
1041-{
1042- TermNode& Term;
1043-
1044- YB_ATTR_nodiscard YB_FLATTEN ReductionStatus
1045- operator()() const
1046- {
1047- const auto i(std::next(Term.begin()));
1048- auto& nd_y(NPL::Deref(i));
1049-
1050- YAssert(IsList(nd_y), "Expected a list prvalue for cons.");
1051- MoveValueListSplice(Term, nd_y);
1052- Term.erase(i);
1053- return ReductionStatus::Retained;
1054- }
1055-};
1056-//@}
1057-
1058972
1059973 //! \since build 859
1060974 //@{
@@ -1308,24 +1222,27 @@
13081222 }, term);
13091223 }
13101224
1311-//! \since build 915
1225+//! \since build 917
13121226 void
1313-LiftCopyPropagate(TermNode& term, TermNode& tm, const TermReference& ref)
1227+LiftCopyPropagate(TermNode& term, TermNode& tm, TermTags tags)
13141228 {
13151229 // XXX: Similar to the implementation of %ReduceToReference in NPLA.cpp.
13161230 term.CopyContent(tm);
13171231 // NOTE: Propagate tags if it is a term reference.
13181232 if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
1319- p->SetTags(PropagateTo(p->GetTags(), ref.GetTags()));
1233+ p->SetTags(PropagateTo(p->GetTags(), tags));
13201234 // XXX: Term tags are currently not respected in prvalues.
13211235 }
1322-
13231236 //! \since build 915
1237+inline PDefH(void, LiftCopyPropagate, TermNode& term, TermNode& tm,
1238+ const TermReference& ref)
1239+ ImplExpr(LiftCopyPropagate(term, tm, ref.GetTags()))
1240+
1241+//! \since build 917
13241242 void
1325-LiftOtherOrCopyPropagate(TermNode& term, TermNode& tm,
1326- ResolvedTermReferencePtr p_ref)
1243+LiftOtherOrCopyPropagateRef(TermNode& term, TermNode& tm, const TermReference& ref)
13271244 {
1328- if(NPL::IsMovable(p_ref))
1245+ if(ref.IsMovable())
13291246 // XXX: Using %LiftOther (from %LiftOtherOrCopy) instead of
13301247 // %LiftTermOrCopy is safe, because the referent is not allowed to have
13311248 // cyclic reference to %term. And %LiftTermOrCopy is in that case is
@@ -1335,7 +1252,18 @@
13351252 else
13361253 // XXX: The call to %NPL::IsMovable has guarantees %p_ref is nonnull
13371254 // here.
1338- LiftCopyPropagate(term, tm, NPL::Deref(p_ref));
1255+ LiftCopyPropagate(term, tm, ref);
1256+}
1257+
1258+//! \since build 915
1259+void
1260+LiftOtherOrCopyPropagate(TermNode& term, TermNode& tm,
1261+ ResolvedTermReferencePtr p_ref)
1262+{
1263+ if(!p_ref)
1264+ LiftOther(term, tm);
1265+ else
1266+ LiftOtherOrCopyPropagateRef(term, tm, *p_ref);
13391267 }
13401268
13411269 //! \since build 914
@@ -1449,7 +1377,7 @@
14491377 }
14501378 else
14511379 for(; first != last; ++first)
1452- insert(con.emplace_back(), *first, p_ref);
1380+ insert(con.emplace_back(), *first, *p_ref);
14531381 con.swap(term.GetContainerRef());
14541382 return ReductionStatus::Retained;
14551383 }
@@ -1638,7 +1566,7 @@
16381566 shared_ptr<Environment>&& p_env, bool owning)
16391567 {
16401568 auto formals(ShareMoveTerm(NPL::Deref(++i)));
1641- auto eformal(CheckEnvFormal(NPL::Deref(++i)));
1569+ auto eformal(CheckEnvironmentFormal(NPL::Deref(++i)));
16421570
16431571 term.erase(term.begin(), ++i);
16441572 // XXX: Allocators are not used on %FormContextHandler for performance in
@@ -1680,7 +1608,7 @@
16801608 auto j(i);
16811609 // XXX: As %CreateVau.
16821610 auto formals(ShareMoveTerm(NPL::Deref(++j)));
1683- auto eformal(CheckEnvFormal(NPL::Deref(++j)));
1611+ auto eformal(CheckEnvironmentFormal(NPL::Deref(++j)));
16841612
16851613 term.erase(term.begin(), ++j);
16861614 return VauHandler(0, std::move(eformal),
@@ -2041,11 +1969,10 @@
20411969 ThrowInsufficientTermsError(term, {});
20421970 }
20431971
2044-//! \since build 912
2045-//@{
1972+//! \since build 917
20461973 template<typename _func>
20471974 YB_FLATTEN ReductionStatus
2048-DoAcc(_func f, TermNode& term, ContextNode& ctx)
1975+Acc(_func f, TermNode& term, ContextNode& ctx)
20491976 {
20501977 auto i(term.begin());
20511978 auto& nterm(*i);
@@ -2059,7 +1986,7 @@
20591986
20601987 tcon.push_back(EvaluateBoundLValueUnwrapped(tm, d));
20611988 tcon.push_back(lv_l);
2062- nterm.GetContainerRef() = std::move(tcon);
1989+ tcon.swap(nterm.GetContainerRef());
20631990 nterm.Value.Clear();
20641991 });
20651992
@@ -2089,64 +2016,66 @@
20892016 }, std::move(i)), "eval-acc-nested"));
20902017 }
20912018
2019+//! \since build 917
2020+//@{
20922021 YB_FLATTEN ReductionStatus
2093-DoAccL(TermNode& term, ContextNode& ctx)
2022+ReduceAccL(TermNode& term, ContextNode& ctx)
20942023 {
20952024 // NOTE: Subterms are %nterm, %l, %pred, %base, %head, %tail, %lv_sum_op,
20962025 // %lv_l.
20972026 YAssert(term.size() == 8, "Invalid recursive call found.");
2098- return DoAcc([&](TermNode& l, TermNode& base, TermNode& lv_l, TermNode&
2027+ return Acc([&](TermNode& l, TermNode& base, TermNode& lv_l, TermNode&
20992028 nterm, const shared_ptr<Environment>& d, TNIter& i) YB_FLATTEN{
21002029 auto& tail(*++i);
21012030
2102- base.GetContainerRef() = [&]{
2031+ {
21032032 TermNode::Container tcon(base.get_allocator());
21042033
21052034 tcon.push_back(std::move(EvaluateBoundLValueUnwrapped(*++i, d)));
21062035 tcon.push_back(std::move(nterm));
21072036 tcon.push_back(std::move(base));
2108- return tcon;
2109- }(),
2037+ tcon.swap(base.GetContainerRef());
2038+ }
21102039 base.Value.Clear();
21112040 return Combine<NonTailCall>::ReduceCallSubsequent(base, ctx, d,
21122041 // XXX: Capture of %d by copy is a slightly more efficient.
21132042 A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
2114- nterm.GetContainerRef() = [&]{
2043+ {
21152044 TermNode::Container tcon(nterm.get_allocator());
21162045
21172046 tcon.push_back(EvaluateBoundLValueUnwrapped(tail, d));
21182047 tcon.push_back(std::move(lv_l));
2119- return tcon;
2120- }(),
2048+ tcon.swap(nterm.GetContainerRef());
2049+ }
21212050 nterm.Value.Clear();
21222051 return Combine<NonTailCall>::ReduceCallSubsequent(nterm, ctx, d,
21232052 A1::NameTypedReducerHandler([&]() YB_FLATTEN{
21242053 l = std::move(nterm);
2125- return DoAccL(term, ctx);
2054+ return ReduceAccL(term, ctx);
21262055 }, "eval-accl-accl"));
21272056 }, "eval-accl-tail"));
21282057 }, term, ctx);
21292058 }
21302059
21312060 YB_FLATTEN ReductionStatus
2132-DoAccR(TermNode& term, ContextNode& ctx)
2061+ReduceAccR(TermNode& term, ContextNode& ctx)
21332062 {
21342063 // NOTE: Subterms are %nterm, %l, %pred, %base, %head, %tail, %lv_sum_op,
21352064 // %n2term, %lv_l.
21362065 YAssert(term.size() == 9, "Invalid recursive call found.");
2137- return DoAcc([&](TermNode& l, TermNode&, TermNode& lv_l, TermNode& nterm,
2066+ return Acc([&](TermNode& l, TermNode&, TermNode& lv_l, TermNode& nterm,
21382067 const shared_ptr<Environment>& d, TNIter& i) YB_FLATTEN{
21392068 auto& n2term(*std::next(term.rbegin()));
21402069 auto& tail(*++i);
21412070 const auto& lv_sum_op(*++i);
21422071
2143- n2term.GetContainerRef() = [&]{
2072+ {
21442073 TermNode::Container tcon(n2term.get_allocator());
21452074
21462075 tcon.push_back(EvaluateBoundLValueUnwrapped(tail, d));
21472076 tcon.push_back(std::move(lv_l));
2148- return tcon;
2149- }(),
2077+ tcon.swap(n2term.GetContainerRef());
2078+ }
21502079 n2term.Value.Clear();
21512080 return Combine<NonTailCall>::ReduceCallSubsequent(n2term, ctx, d,
21522081 // XXX: Capture of %d by copy is a slightly more efficient.
@@ -2159,7 +2088,7 @@
21592088 tcon.push_back(lv_sum_op);
21602089 tcon.push_back(std::move(nterm));
21612090 return tcon;
2162- }())), ctx, DoAccR,
2091+ }())), ctx, ReduceAccR,
21632092 A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
21642093 return Combine<NonTailCall>::ReduceEnvSwitch(term, ctx, d);
21652094 }, "eval-accr-sum"));
@@ -2222,21 +2151,6 @@
22222151 }, term);
22232152 }
22242153
2225-// XXX: Now terms are treated always movable without check for
2226-// %TermTags::Nonmodifying, respecting copy elision with 'first%'.
2227-YB_FLATTEN void
2228-ExtractFirst(TermNode& term, TermNode& tm)
2229-{
2230- YAssert(IsBranchedList(tm), "Invalid term found.");
2231- // NOTE: The source list %tm is not an lvalue. Copy or move the 1st
2232- // subterm of the source directly.
2233- // NOTE: As %FirstFwd. There should ne no cycle in the caller sites, so
2234- // %term and the 1st subterm of %tm is not the same.
2235- // XXX: Term tags are currently not respected in prvalues.
2236- LiftOther(term, AccessFirstSubterm(tm));
2237- RemoveHead(tm);
2238-}
2239-
22402154 //! \since build 916
22412155 YB_FLATTEN void
22422156 ExtractRangeFirstOrCopy(TermNode& term, TermRange& tr, bool move)
@@ -2244,18 +2158,13 @@
22442158 YAssert(!tr.empty(), "Invalid term found.");
22452159 if(move)
22462160 LiftOther(term, NPL::Deref(tr.First));
2247- // XXX: As %LiftCopyPropagate.
22482161 else
2249- {
2250- term.CopyContent(NPL::Deref(tr.First));
2251- if(const auto p = NPL::TryAccessLeaf<TermReference>(term))
2252- p->SetTags(PropagateTo(p->GetTags(), tr.Tags));
2253- }
2162+ LiftCopyPropagate(term, NPL::Deref(tr.First), tr.Tags);
22542163 ++tr.First;
22552164 }
22562165
22572166 YB_FLATTEN ReductionStatus
2258-DoFoldR1(TermNode& term, ContextNode& ctx)
2167+ReduceFoldR1(TermNode& term, ContextNode& ctx)
22592168 {
22602169 // NOTE: Subterms are the underlying combiner of 'kons', 'knil',
22612170 // the term range of 'l' with optional temporary list.
@@ -2281,7 +2190,7 @@
22812190 ExtractRangeFirstOrCopy(tcon.emplace_back(), tr,
22822191 !bool(tm.Tags & TermTags::Nonmodifying));
22832192 return tcon;
2284- }())), ctx, DoFoldR1, A1::NameTypedReducerHandler(
2193+ }())), ctx, ReduceFoldR1, A1::NameTypedReducerHandler(
22852194 // TODO: Blocked. Use C++14 lambda initializers to simplify the
22862195 // implementation.
22872196 std::bind([&](shared_ptr<Environment>& d) YB_FLATTEN{
@@ -2293,25 +2202,17 @@
22932202 return ReductionStatus::Retained;
22942203 }
22952204
2296-//! \since build 914
2297-template<typename _func>
22982205 YB_FLATTEN ReductionStatus
2299-DoBranchListOrNull(TermNode& term, TermNode& tm, _func f)
2206+ReduceMap1(TermNode& term, ContextNode& ctx)
23002207 {
2301- // XXX: This should have been guaranteed by preconditions in the caller
2302- // site.
2303- YAssert(IsList(tm), "Invalid non-list term found.");
2304- if(IsBranch(tm))
2305- return f(term.GetContainerRef().front());
2306- term.Clear();
2307- return ReductionStatus::Regular;
2308-}
2309-
2310-//! \since build 916
2311-template<typename _func>
2312-YB_FLATTEN ReductionStatus
2313-DoBranchListRangeOrNull(TermNode& term, TermNode& tm, _func f)
2314-{
2208+ // NOTE: Subterms are the underlying combiner of 'appv', the term range of
2209+ // 'l' with optional temporary list, and the converted list elements (i.e.
2210+ // the results have been applied by the applicative).
2211+ YAssert(term.size() >= 2, "Invalid recursive call found.");
2212+
2213+ auto& con(term.GetContainerRef());
2214+ auto& tm(*std::next(con.begin()));
2215+
23152216 // XXX: This should have been guaranteed by the call to %PrepareFoldRList.
23162217 YAssert(tm.Value.type() == ystdex::type_id<TermRange>(),
23172218 "Invalid non-list term found.");
@@ -2319,39 +2220,21 @@
23192220 auto& tr(tm.Value.GetObject<TermRange>());
23202221
23212222 if(!tr.empty())
2322- return f(tr, !bool(tm.Tags & TermTags::Nonmodifying));
2323- term.Clear();
2324- return ReductionStatus::Regular;
2325-}
2326-
2327-YB_FLATTEN ReductionStatus
2328-DoMap1(TermNode& term, ContextNode& ctx)
2329-{
2330- // NOTE: Subterms are the underlying combiner of 'appv', the term range of
2331- // 'l' with optional temporary list.
2332- YAssert(term.size() == 2, "Invalid recursive call found.");
2333-
2334- auto& con(term.GetContainerRef());
2335-
2336- return DoBranchListRangeOrNull(term, con.back(),
2337- [&](TermRange& tr, bool move) YB_FLATTEN{
2338- return A1::ReduceCurrentNextThunked(
2339- *term.emplace(ystdex::exchange(con, [&]{
2340- TermNode::Container tcon(term.get_allocator());
2341- auto& subtcon(tcon.emplace_back().GetContainerRef());
2342-
2343- subtcon.push_back(con.front());
2344- ExtractRangeFirstOrCopy(subtcon.emplace_back(), tr, move);
2345- return tcon;
2346- }())), ctx, DoMap1, A1::NameTypedReducerHandler(
2347- // TODO: Blocked. Use C++14 lambda initializers to simplify the
2348- // implementation.
2349- std::bind([&](shared_ptr<Environment>& d) YB_FLATTEN{
2350- return Combine<NonTailCall>::ReduceCallSubsequent(*term.begin(),
2351- ctx, std::move(d), A1::NameTypedReducerHandler(
2352- ConsMoveSubNextRV<Map1Cons>{term}, "eval-map1-cons"));
2353- }, ctx.ShareRecord()), "eval-map1-appv"));
2354- });
2223+ {
2224+ auto& nterm(con.emplace_back());
2225+ auto& tcon(nterm.GetContainerRef());
2226+
2227+ tcon.push_back(con.front());
2228+ ExtractRangeFirstOrCopy(tcon.emplace_back(), tr,
2229+ !bool(tm.Tags & TermTags::Nonmodifying));
2230+ return Combine<NonTailCall>::ReduceCallSubsequent(nterm, ctx,
2231+ ctx.ShareRecord(), A1::NameTypedReducerHandler([&]() YB_FLATTEN{
2232+ return ReduceMap1(term, ctx);
2233+ }, "eval-map1-appv"));
2234+ }
2235+ con.pop_front();
2236+ con.pop_front();
2237+ return ReductionStatus::Retained;
23552238 }
23562239
23572240 // NOTE: This is needed for the last operation called recursively. Also
@@ -2367,8 +2250,8 @@
23672250 // NOTE: This is only needed to maintain the lifetime of the tail operator
23682251 // initialized by the call to %PrepareTailOp in the whole liftime of the
23692252 // outmost call.
2370-YB_FLATTEN ReductionStatus
2371-DoRLiftSum(TermNode& term, ContextNode& ctx, TermNode& rterm,
2253+ReductionStatus
2254+ReduceLiftSum(TermNode& term, ContextNode& ctx, TermNode& rterm,
23722255 ReductionStatus(&f)(TermNode&, ContextNode&))
23732256 {
23742257 #if NPL_Impl_NPLA1_Enable_Thunked
@@ -2385,7 +2268,7 @@
23852268 }
23862269
23872270 YB_FLATTEN ReductionStatus
2388-DoFoldRMap1(TermNode& term, ContextNode& ctx,
2271+ReduceFoldRMap1(TermNode& term, ContextNode& ctx,
23892272 ReductionStatus(&f)(TermNode&, ContextNode&))
23902273 {
23912274 auto& con(term.GetContainerRef());
@@ -2400,206 +2283,335 @@
24002283
24012284 // NOTE: Save 'kons' (for %FoldR1) or 'appv' (for %Map1).
24022285 PrepareTailOp(term, ctx, *rterm.begin());
2403- return DoRLiftSum(term, ctx, rterm, f);
2286+ return ReduceLiftSum(term, ctx, rterm, f);
2287+}
2288+
2289+// \pre 第二参数不是第一参数所在的项或其被引用项。
2290+void
2291+PrependList(TermNode::Container& tcon, TermNode& tm)
2292+{
2293+ // NOTE: Bind the term of a list object owning %tcon as the local reference
2294+ // to list temporary object (as %PrepareFoldRList for lvalues and lifting
2295+ // directly for prvalues) and prepend the list elements. The term %tm shall
2296+ // have been lifted by %LiftToReturn or guaranteed as a list prvalue.
2297+ NPL::ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
2298+ if(IsList(nd))
2299+ {
2300+ if(p_ref)
2301+ {
2302+ if(p_ref->IsMovable())
2303+ LiftOther(tm, nd);
2304+ else
2305+ {
2306+ auto i(tcon.begin());
2307+
2308+ for(auto j(nd.begin()); j != nd.end(); yunseq(++i, ++j))
2309+ {
2310+ i = tcon.emplace(i);
2311+ LiftCopyPropagate(*i, *j, p_ref->GetTags());
2312+ }
2313+ return;
2314+ }
2315+ }
2316+ }
2317+ else
2318+ ThrowInsufficientTermsError(nd, true);
2319+ tcon.splice(tcon.begin(), tm.GetContainerRef());
2320+ }, tm);
24042321 }
24052322
24062323 YB_FLATTEN ReductionStatus
2407-DoListConcat(TermNode& term, ContextNode& ctx)
2408-{
2409- // NOTE: Subterms are the term range of 'x' with optional temporary list,
2410- // 'y'.
2411- YAssert(term.size() == 2, "Invalid recursive call found.");
2412-
2413- auto i(term.begin());
2414- auto& tm(*i);
2415-
2416- // XXX: This should have been guaranteed by the call to %PrepareFoldRList.
2417- YAssert(tm.Value.type() == ystdex::type_id<TermRange>(),
2418- "Invalid non-list term found.");
2419-
2420- auto& tr(tm.Value.GetObject<TermRange>());
2421-
2422- if(!tr.empty())
2423- {
2424- return A1::ReduceCurrentNextThunked(
2425- *term.emplace(ystdex::exchange(term.GetContainerRef(), [&]{
2426- TermNode::Container tcon(term.get_allocator());
2427-
2428- ExtractRangeFirstOrCopy(tcon.emplace_back(), tr,
2429- !bool(tm.Tags & TermTags::Nonmodifying));
2430- return tcon;
2431- }())), ctx, DoListConcat, A1::NameTypedReducerHandler(
2432- ConsMoveSubNextRV<ListConcatCons>{term}, "eval-list-concat-cons"));
2433- }
2434- LiftOther(term, *++i);
2435- return ReductionStatus::Retained;
2436-}
2437-
2438-YB_FLATTEN ReductionStatus
2439-DoAppend(TermNode& term, ContextNode& ctx)
2324+ReduceAppend(TermNode& term)
24402325 {
24412326 // NOTE: The subterm is %ls.
2442- YAssert(term.size() == 1, "Invalid recursive call found.");
2327+ YAssert(term.size() == 1, "Invalid call found.");
24432328
24442329 auto& con(term.GetContainerRef());
24452330 auto& ls(con.back());
24462331
2447- return DoBranchListOrNull(term, ls, [&](TermNode&) YB_FLATTEN{
2448- return A1::ReduceCurrentNextThunked(
2449- *term.emplace(ystdex::exchange(con, [&]{
2450- TermNode::Container tcon(term.get_allocator());
2451- auto& nterm(tcon.emplace_back());
2452-
2453- ExtractFirst(nterm, ls);
2454- // NOTE: Bind the first term as the local reference to list
2455- // temporary object.
2456- PrepareFoldRList(nterm);
2457- return tcon;
2458- }())), ctx, DoAppend, A1::NameTypedReducerHandler([&]() YB_FLATTEN{
2459- return DoListConcat(term, ctx);
2460- }, "eval-append-list-concat"));
2461- });
2332+ // XXX: This should have been guaranteed by preconditions in the caller
2333+ // site.
2334+ YAssert(IsList(ls), "Invalid non-list term found.");
2335+ if(IsBranch(ls))
2336+ {
2337+ auto& lcon(ls.GetContainerRef());
2338+ TermNode::Container tcon(con.get_allocator());
2339+
2340+ for(auto i(lcon.rbegin()); i != lcon.rend(); ++i)
2341+ // NOTE: The source list %ls is a prvalue. Copy or move the 1st
2342+ // subterm of the source directly.
2343+ // XXX: Terms are treated always movable without check for
2344+ // %TermTags::Nonmodifying, respecting copy elision with 'first%'.
2345+ // NOTE: As %FirstFwd. There should ne no cycle in the caller sites,
2346+ // so %nterm and the 1st subterm of %ls is not the same.
2347+ // XXX: Term tags are currently not respected in prvalues.
2348+ PrependList(tcon, *i);
2349+ con = std::move(tcon);
2350+ return ReductionStatus::Retained;
2351+ }
2352+ term.Clear();
2353+ return ReductionStatus::Regular;
24622354 }
2463-//@}
2464-
2465-//! \since build 916
2466-//@{
2355+
2356+template<typename _func, typename _func2>
24672357 void
2468-BindListExtractFirst_Ref(TermNode& nterm, TermReference& oref, TermTags tags)
2469-{
2470- TermReference ref(BindReferenceTags(tags), oref);
2471- auto& nd(ref.get());
2472-
2473- if(IsBranchedList(nd))
2474- RegularizeTerm(nterm,
2475- ReduceToFirst(nterm, AccessFirstSubterm(nd), &ref));
2476- else
2477- ThrowInsufficientTermsError(nd, true);
2478-}
2479-void
2480-BindListExtractFirst_Val(TermNode& nterm, TermNode& o, TermTags tm_tags)
2358+ListRangeExtract(TermNode& term, _func f, _func2 f2)
24812359 {
2482- auto& x(AccessFirstSubterm(o));
2483-
2484- if(const auto p = NPL::TryAccessLeaf<const TermReference>(x))
2360+ // NOTE: The term is the term range of 'l' with optional temporary list.
2361+ auto& con(term.GetContainerRef());
2362+ auto& tr(term.Value.GetObject<TermRange>());
2363+ TermNode::Container tcon(con.get_allocator());
2364+
2365+ while(!tr.empty())
24852366 {
2486- if(!p->IsReferencedLValue())
2487- {
2488- LiftMovedOther(nterm, *p, p->IsMovable());
2489- return;
2490- }
2367+ auto& nterm(tcon.emplace_back());
2368+ auto& o(NPL::Deref(tr.First));
2369+
2370+ if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
2371+ // NOTE: The tags of the term range shall be prepared in the
2372+ // call to %PrepareFoldRList. The nonmodifying tag indicates
2373+ // the reference is not movable.
2374+ f(nterm, *p,
2375+ GetLValueTagsOf(PropagateTo(p->GetTags(), tr.Tags)));
2376+ else if(IsBranchedList(o))
2377+ f2(nterm, o, tr.Tags);
2378+ else
2379+ ThrowInsufficientTermsError(o, true);
2380+ ++tr.First;
24912381 }
2492- // XXX: Term tags are currently not respected in prvalues.
2493- LiftOtherOrCopy(nterm, x,
2494- !bool((o.Tags | x.Tags | tm_tags) & TermTags::Nonmodifying));
2382+ tcon.swap(con),
2383+ term.Value.Clear(),
2384+ term.Tags = TermTags::Unqualified;
24952385 }
24962386
2497-void
2498-BindListExtractRestFwd_Ref(TermNode& nterm, TermReference& oref, TermTags tags)
2387+ReductionStatus
2388+ReduceListExtractFirst(TermNode& term)
24992389 {
2500- TermReference ref(tags, oref);
2501- auto& nd(ref.get());
2502-
2503- ReduceToRestOrVal(nterm, nd, &ref, [](TermNode&) ynothrow{},
2504- [&](TermNode& dst, TermNode& tm, ResolvedTermReferencePtr){
2505- LiftOtherOrCopy(dst, tm, ref.IsMovable());
2390+ ListRangeExtract(term,
2391+ [](TermNode& nterm, TermReference& oref, TermTags tags){
2392+ TermReference ref(BindReferenceTags(tags), oref);
2393+ auto& nd(ref.get());
2394+
2395+ if(IsBranchedList(nd))
2396+ RegularizeTerm(nterm,
2397+ ReduceToFirst(nterm, AccessFirstSubterm(nd), &ref));
2398+ else
2399+ ThrowInsufficientTermsError(nd, true);
2400+ }, [](TermNode& nterm, TermNode& o, TermTags tm_tags){
2401+ auto& x(AccessFirstSubterm(o));
2402+
2403+ if(const auto p = NPL::TryAccessLeaf<const TermReference>(x))
2404+ {
2405+ if(!p->IsReferencedLValue())
2406+ {
2407+ LiftMovedOther(nterm, *p, p->IsMovable());
2408+ return;
2409+ }
2410+ }
2411+ // XXX: Term tags are currently not respected in prvalues.
2412+ LiftOtherOrCopy(nterm, x,
2413+ !bool((o.Tags | x.Tags | tm_tags) & TermTags::Nonmodifying));
25062414 });
2415+ return ReductionStatus::Retained;
25072416 }
2508-void
2509-BindListExtractRestFwd_Val(TermNode& nterm, TermNode& o, TermTags tm_tags)
2417+
2418+ReductionStatus
2419+ReduceListExtractRestFwd(TermNode& term)
25102420 {
2511- TermNode::Container con(nterm.get_allocator());
2512-
2513- auto first(o.begin());
2514- const auto last(o.end());
2515-
2516- ++first;
2517- if(!bool((o.Tags | tm_tags) & TermTags::Nonmodifying))
2518- con.splice(con.end(), o.GetContainerRef(), first, last);
2519- else
2520- for(; first != last; ++first)
2521- con.emplace_back().CopyContent(*first);
2522- con.swap(nterm.GetContainerRef());
2421+ ListRangeExtract(term,
2422+ [](TermNode& nterm, TermReference& oref, TermTags tags){
2423+ TermReference ref(tags, oref);
2424+ auto& nd(ref.get());
2425+
2426+ ReduceToRestOrVal(nterm, nd, &ref, [](TermNode&) ynothrow{},
2427+ [&](TermNode& dst, TermNode& tm, const TermReference&){
2428+ LiftOtherOrCopy(dst, tm, ref.IsMovable());
2429+ });
2430+ }, [](TermNode& nterm, TermNode& o, TermTags tm_tags){
2431+ TermNode::Container con(nterm.get_allocator());
2432+
2433+ auto first(o.begin());
2434+ const auto last(o.end());
2435+
2436+ ++first;
2437+ if(!bool((o.Tags | tm_tags) & TermTags::Nonmodifying))
2438+ con.splice(con.end(), o.GetContainerRef(), first, last);
2439+ else
2440+ for(; first != last; ++first)
2441+ con.emplace_back().CopyContent(*first);
2442+ con.swap(nterm.GetContainerRef());
2443+ });
2444+ return ReductionStatus::Retained;
2445+}
2446+
2447+YB_FLATTEN void
2448+PrepareListExtract(TermNode& term)
2449+{
2450+ RetainN(term);
2451+ LiftOther(term, term.GetContainerRef().back());
2452+ // NOTE: Save the optional temporary list and bind the last argument as the
2453+ // local reference to list temporary object.
2454+ PrepareFoldRList(term);
25232455 }
25242456 //@}
25252457
2526-//! \since build 914
2458+//! \since build 917
25272459 //@{
2528-template<typename _func, typename _func2>
2529-YB_FLATTEN ReductionStatus
2530-DoListExtractFirstRest(TermNode& term, ContextNode& ctx, _func f, _func2 f2)
2460+TermNode&
2461+LetBodyFlatten(TermNode& term, TNIter i, bool with_env)
25312462 {
2532- // NOTE: The subterm is the term range of 'l'.
2533- YAssert(term.size() == 1, "Invalid recursive call found.");
2534-
25352463 auto& con(term.GetContainerRef());
25362464
2537- return DoBranchListRangeOrNull(term, con.back(),
2538- [&](TermRange& tr, bool) YB_FLATTEN{
2539- return A1::ReduceCurrentNextThunked(
2540- *term.emplace(ystdex::exchange(con, [&]{
2541- TermNode::Container tcon(term.get_allocator());
2542- auto& nterm(tcon.emplace_back());
2543- auto& o(NPL::Deref(tr.First));
2544-
2545- if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
2546- // NOTE: The tags of the term range shall be prepared in the
2547- // call to %PrepareFoldRList. The nonmodifying tag indicates
2548- // the reference is not movable.
2549- f(nterm, *p,
2550- GetLValueTagsOf(PropagateTo(p->GetTags(), tr.Tags)));
2551- else if(IsBranchedList(o))
2552- f2(nterm, o, tr.Tags);
2553- else
2554- ThrowInsufficientTermsError(o, true);
2555- ++tr.First;
2556- return tcon;
2557- }())), ctx, [=](TermNode& t, ContextNode& c){
2558- return DoListExtractFirstRest(t, c, f, f2);
2559- }, A1::NameTypedReducerHandler(ConsMoveSubNextRV<ListExtractCons>{term},
2560- "eval-list-extract-cons"));
2561- });
2465+ if(with_env)
2466+ ++i;
2467+ ++i;
2468+ {
2469+ TermNode::Container tcon(term.get_allocator());
2470+
2471+ tcon.splice(tcon.end(), con, ++i, con.end());
2472+ term.emplace(std::move(tcon));
2473+ // NOTE: Now subterms are 'bindings', optional 'e',
2474+ // originally bound 'bindings', 'body'.
2475+ }
2476+ return *term.emplace();
25622477 }
25632478
2564-YB_FLATTEN ReductionStatus
2565-DoListExtractFirst(TermNode& term, ContextNode& ctx)
2566-{
2567- return DoListExtractFirstRest(term, ctx, BindListExtractFirst_Ref,
2568- BindListExtractFirst_Val);
2569-}
2570-
2571-YB_FLATTEN ReductionStatus
2572-DoListExtractRestFwd(TermNode& term, ContextNode& ctx)
2573-{
2574- return DoListExtractFirstRest(term, ctx, BindListExtractRestFwd_Ref,
2575- BindListExtractRestFwd_Val);
2576-}
2577-
2578-//! \since build 916
2579-YB_ATTR_nodiscard ReductionStatus
2580-ListExtractFirstRest(TermNode& term, ContextNode& ctx,
2581- ReductionStatus(&f)(TermNode&, ContextNode&))
2479+ReductionStatus
2480+LetCallBody(TermNode& term, ContextNode& ctx, TermNode& body,
2481+ EnvironmentGuard& egd, bool no_lift)
25822482 {
2583- RetainN(term);
2584-
2585- auto& con(term.GetContainerRef());
2586-
2587- con.pop_front();
2588-
2589- auto& rterm(*term.emplace(ystdex::exchange(con,
2590- TermNode::Container(term.get_allocator()))));
2591- auto& tm(*rterm.begin());
2592-
2593- // NOTE: Save the optional temporary list and bind the last argument as the
2594- // local reference to list temporary object.
2595- PrepareFoldRList(con.emplace_back(std::move(tm)));
2596-
2597- tm.ClearContainer();
2598- tm.Value = std::move(con.back().Value);
2599- return DoRLiftSum(term, ctx, rterm, f);
2483+ // NOTE: Set 'body'.
2484+ LiftOther(term, body);
2485+#if NPL_Impl_NPLA1_Enable_Thunked
2486+ SetupNextTerm(ctx, term);
2487+#endif
2488+ return RelayForCall(ctx, term, std::move(egd), no_lift);
26002489 }
26012490
2602-YB_FLATTEN ReductionStatus
2491+template<typename _func>
2492+ReductionStatus
2493+LetCombineBody(_func f, TermNode& term, ContextNode& ctx)
2494+{
2495+ const auto let_call([&]{
2496+ EnvironmentGuard
2497+ egd(ctx, NPL::SwitchToFreshEnvironment(ctx));
2498+ auto j(term.begin());
2499+ auto& operand(*j);
2500+
2501+ ctx.GetRecordRef().Parent = std::move(operand.Value);
2502+ return f(operand, ++++j, egd);
2503+ });
2504+
2505+#if !NPL_Impl_NPLA1_Enable_TCO
2506+ auto gd(ystdex::unique_guard([&]() ynothrow{
2507+ term.Clear();
2508+ }));
2509+#endif
2510+#if NPL_Impl_NPLA1_Enable_Thunked
2511+# if !NPL_Impl_NPLA1_Enable_TCO
2512+
2513+ RelaySwitched(ctx, A1::NameTypedReducerHandler(
2514+ std::bind([&](decltype(gd)& g){
2515+ ystdex::dismiss(g);
2516+ return RegularizeTerm(term, ctx.LastStatus);
2517+ }, std::move(gd)), "eval-let-combine-return"));
2518+# endif
2519+ return let_call();
2520+#else
2521+ const auto res(RegularizeTerm(term, let_call()));
2522+
2523+ ystdex::dismiss(gd);
2524+ return res;
2525+#endif
2526+}
2527+
2528+template<typename _func>
2529+ReductionStatus
2530+LetCombinePrepare(_func f, TermNode& term, ContextNode& ctx, bool with_env)
2531+{
2532+ auto i(term.begin());
2533+ // NOTE: The original bound 'bindings' is not needed now. However,
2534+ // it is not reused to avoid redundant branch check of %with_env.
2535+ // Instead, the %Value in the 1st subterm is reused.
2536+ auto& parent(i->Value);
2537+
2538+ YAssert(!parent, "Invalid value found in list result.");
2539+ if(!with_env)
2540+ {
2541+ parent = ctx.ShareRecord();
2542+ return f();
2543+ }
2544+ ++i;
2545+ return ReduceSubsequent(NPL::Deref(i), ctx,
2546+ A1::NameTypedReducerHandler([&, i, f]() YB_FLATTEN{
2547+ // XXX: As %VauWithEnvironmentImpl.
2548+ ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
2549+ if(IsList(nd))
2550+ parent = MakeEnvironmentParent(nd.begin(), nd.end(),
2551+ nd.get_allocator(), !NPL::IsMovable(p_ref));
2552+ else if(IsLeaf(nd))
2553+ {
2554+ auto p_env_pr(ResolveEnvironment(nd.Value,
2555+ NPL::IsMovable(p_ref)));
2556+
2557+ Environment::EnsureValid(p_env_pr.first);
2558+ parent = std::move(p_env_pr.first);
2559+ }
2560+ else
2561+ ThrowInvalidEnvironmentType(nd, p_ref);
2562+ }, *i);
2563+ term.GetContainerRef().erase(i);
2564+ return f();
2565+ }, "eval-let-parent"));
2566+}
2567+
2568+ReductionStatus
2569+LetCommon(TermNode& term, ContextNode& ctx, bool no_lift, bool with_env)
2570+{
2571+ // NOTE: Subterms are extracted arguments for the call, optional 'e',
2572+ // originally bound 'bindings', 'body', extracted 'formals' for the lambda
2573+ // abstraction.
2574+ YAssert(term.size() >= (with_env ? 5 : 4), "Invalid nested call found.");
2575+ return LetCombinePrepare([&, no_lift]() -> ReductionStatus{
2576+ auto& con(term.GetContainerRef());
2577+
2578+ // NOTE: Now subterms are extracted arguments for the call plus
2579+ // the parent in %Value, unused 'bindings', 'body', extracted
2580+ // 'formals' for the lambda abstraction.
2581+ YAssert(term.size() == 4, "Invalid term found.");
2582+#if false
2583+ // NOTE: There is no need to check the parameter since it would be
2584+ // checked in the call to %BindParameter later.
2585+ CheckParameterTree(con.back());
2586+#endif
2587+
2588+ auto& alist(con.front());
2589+
2590+ // NOTE: This does not optimize for cases of zero arguments as in
2591+ // %FormContextHandler::CallN in NPLA1.cpp, since the fast path is
2592+ // preferred in %LetEmpty.
2593+ // NOTE: Capture the term regardless of the next term because
2594+ // continuation capture here is unsupported.
2595+ return A1::RelayCurrentNext(ctx, con.front(),
2596+ [&](TermNode&, ContextNode& c){
2597+ ReduceChildren(alist, c);
2598+ return ReductionStatus::Partial;
2599+ }, NPL::ToReducer(ctx.get_allocator(),
2600+ A1::NameTypedReducerHandler([&, no_lift]{
2601+ return LetCombineBody(
2602+ [&](TermNode& operand, TNIter j, EnvironmentGuard& egd){
2603+ auto& body(NPL::Deref(j));
2604+
2605+ operand.Value.Clear();
2606+ BindParameter(ctx.GetRecordPtr(), NPL::Deref(++j), operand);
2607+ return LetCallBody(term, ctx, body, egd, no_lift);
2608+ }, term, ctx);
2609+ }, "eval-let-combine-operator")));
2610+ }, term, ctx, with_env);
2611+}
2612+
2613+//! \since build 914
2614+ReductionStatus
26032615 LetCore(TermNode& term, ContextNode& ctx, bool no_lift, bool with_env)
26042616 {
26052617 // NOTE: Subterms are %nterm (the term range of 'bindings' with optional
@@ -2609,150 +2621,46 @@
26092621
26102622 auto i(term.begin());
26112623 auto& nterm(*i);
2612- auto& con(term.GetContainerRef());
2613- const auto& d(ctx.GetRecordPtr());
2614-
2615- if(with_env)
2616- ++i;
2617- ++i;
2618-
2619- return A1::ReduceCurrentNext(*term.emplace([&]{
2620- const auto a(term.get_allocator());
2621- TermNode::Container tcon(a);
2622-
2623- tcon.splice(tcon.end(), con, ++i, con.end());
2624- term.emplace(std::move(tcon));
2625- // NOTE: Now subterms are 'bindings', optional 'e',
2626- // originally bound 'bindings', 'body'.
2627- tcon.clear();
2628- tcon.emplace_back(NPL::AsTermNode(nterm.Value)).Tags = nterm.Tags;
2629- return tcon;
2630- }()), ctx, DoListExtractFirst,
2631- A1::NameTypedReducerHandler([&, d, no_lift, with_env]{
2632- // NOTE: Now subterms are %nterm, optional 'e', originally bound
2633- // 'bindings', 'body', extracted 'formals' for the lambda abstraction.
2634- const auto a(nterm.get_allocator());
2635- // NOTE: Replace %nterm directly to the call expression, as 'bindings'
2636- // is not needed after this call.
2637- auto& n2term(*nterm.emplace(ystdex::exchange(nterm, TermNode(a))));
2638-
2639- if(!bool(n2term.Tags & TermTags::Nonmodifying))
2640- {
2641- auto& n2tr(n2term.Value.GetObject<TermRange>());
2642-
2643- // NOTE: The old range is invalidated. Refresh it.
2644- n2tr = TermRange(n2term, n2tr.Tags);
2645- // TODO: Blocked. Use C++14 lambda initializers to simplify the
2646- // implementation.
2647- }
2648- return A1::ReduceCurrentNext(nterm, ctx, DoListExtractRestFwd,
2649- A1::NameTypedReducerHandler([&, d, no_lift, with_env]{
2650- // NOTE: Now subterms are extracted arguments for the call,
2651- // optional 'e', originally bound 'bindings', 'body',
2652- // extracted 'formals' for the lambda abstraction.
2653- const auto call_next([&, no_lift]{
2654- // NOTE: Now subterms are extracted arguments for the call plus
2655- // the parent in %Value, unused 'bindings', 'body', extracted
2656- // 'formals' for the lambda abstraction.
2657- YAssert(term.size() == 4, "Invalid term found.");
2658- VauHandler::CheckParameterTree(con.back());
2659-
2660- auto& alist(con.front());
2661-
2662- return A1::RelayCurrentNext(ctx, con.front(),
2663- Continuation([&](TermNode&, ContextNode& c){
2664- // NOTE: This does not support continuation capture, so
2665- // %alist is directly captured here without setup of the
2666- // next term.
2667- ReduceChildren(alist, c);
2668- return ReductionStatus::Partial;
2669- }, ctx), NPL::ToReducer(ctx.get_allocator(),
2670- A1::NameTypedReducerHandler([&, no_lift]{
2671- const auto let_call([&]{
2672- EnvironmentGuard
2673- egd(ctx, NPL::SwitchToFreshEnvironment(ctx));
2674- auto j(con.begin());
2675- auto& operand(*j);
2676-
2677- ++j;
2678-
2679- auto& body(*++j);
2680-
2681- ctx.GetRecordRef().Parent = std::move(operand.Value);
2682- operand.Value.Clear();
2683- BindParameter(ctx.GetRecordPtr(), *++j, operand);
2684- // NOTE: Set 'body'.
2685- LiftOther(term, body);
2686-#if NPL_Impl_NPLA1_Enable_Thunked
2687- SetupNextTerm(ctx, term);
2688-#endif
2689- return RelayForCall(ctx, term, std::move(egd), no_lift);
2690- });
2691-#if !NPL_Impl_NPLA1_Enable_TCO
2692- auto gd(ystdex::unique_guard([&]() ynothrow{
2693- term.Clear();
2694- }));
2695-#endif
2696-#if NPL_Impl_NPLA1_Enable_Thunked
2697-# if !NPL_Impl_NPLA1_Enable_TCO
2698-
2699- RelaySwitched(ctx, A1::NameTypedReducerHandler(
2700- std::bind([&](decltype(gd)& g){
2701- ystdex::dismiss(g);
2702- return RegularizeTerm(term, ctx.LastStatus);
2703- }, std::move(gd)), "eval-let-combine-return"));
2704-# endif
2705- return let_call();
2706-#else
2707- const auto res(RegularizeTerm(term, let_call()));
2708-
2709- ystdex::dismiss(gd);
2710- return res;
2711-#endif
2712- }, "eval-let-combine-operator")));
2713- });
2714-
2715- auto j(term.begin());
2716- // NOTE: The original bound 'bindings' is not needed now. However,
2717- // it is not reused to avoid redundant branch check of %with_env.
2718- // Instead, the %Value in the 1st subterm is reused.
2719- auto& parent(j->Value);
2720-
2721- YAssert(!parent, "Invalid value found in list result.");
2722- if(!with_env)
2723- {
2724- parent = ctx.ShareRecord();
2725- return call_next();
2726- }
2727- ++j;
2728- return ReduceSubsequent(NPL::Deref(j), ctx,
2729- A1::NameTypedReducerHandler([&, j, call_next]() YB_FLATTEN{
2730- // XXX: As %VauWithEnvironmentImpl.
2731- ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
2732- if(IsList(nd))
2733- parent = MakeEnvironmentParent(nd.begin(), nd.end(),
2734- nd.get_allocator(), !NPL::IsMovable(p_ref));
2735- else if(IsLeaf(nd))
2736- {
2737- auto p_env_pr(ResolveEnvironment(nd.Value,
2738- NPL::IsMovable(p_ref)));
2739-
2740- Environment::EnsureValid(p_env_pr.first);
2741- parent = std::move(p_env_pr.first);
2742- }
2743- else
2744- ThrowInvalidEnvironmentType(nd, p_ref);
2745- }, *j);
2746- con.erase(j);
2747- return call_next();
2748- }, "eval-let-parent"));
2749- }, "eval-let-make-combiner"));
2750- }, "eval-let-extract-arguments"));
2624+ auto& rterm(LetBodyFlatten(term, i, with_env));
2625+
2626+ yunseq(rterm.Value = nterm.Value, rterm.Tags = nterm.Tags);
2627+ ReduceListExtractFirst(rterm);
2628+ // NOTE: Now subterms are %nterm, optional 'e', originally bound
2629+ // 'bindings', 'body', extracted 'formals' for the lambda abstraction.
2630+ ReduceListExtractRestFwd(nterm);
2631+ // NOTE: Now subterms are extracted arguments for the call,
2632+ // optional 'e', originally bound 'bindings', 'body',
2633+ // extracted 'formals' for the lambda abstraction.
2634+ return LetCommon(term, ctx, no_lift, with_env);
27512635 }
27522636
2753-//! \since build 916
2637+// NOTE: Specialized %LetCore implementation for empty binding list.
2638+ReductionStatus
2639+LetEmpty(TermNode& term, ContextNode& ctx, bool no_lift, bool with_env)
2640+{
2641+ // NOTE: Subterms are the empty term, optional 'e',
2642+ // unused originally bound 'bindings', trailing 'body'.
2643+ YAssert(term.size() >= (with_env ? 3 : 2), "Invalid nested call found.");
2644+
2645+ auto i(term.begin());
2646+
2647+ i->Clear();
2648+ LetBodyFlatten(term, i, with_env);
2649+ // NOTE: Now subterms are extracted arguments for the call (an empty list),
2650+ // optional 'e', unused originally bound 'bindings', 'body',
2651+ // extracted 'formals' for the lambda abstraction (an empty list).
2652+ return LetCombinePrepare([&, no_lift]() -> ReductionStatus{
2653+ // NOTE: Now subterms are the parent in %Value, unused 'bindings',
2654+ // 'body', extracted 'formals' for the lambda abstraction.
2655+ YAssert(term.size() == 4, "Invalid term found.");
2656+ return LetCombineBody([&](TermNode&, TNIter j, EnvironmentGuard& egd){
2657+ return LetCallBody(term, ctx, NPL::Deref(j), egd, no_lift);
2658+ }, term, ctx);
2659+ }, term, ctx, with_env);
2660+}
2661+
27542662 void
2755-ExpireReferenceListLV(TermNode& term, TermNode& nd,
2663+LetExpire(TermNode& term, TermNode& nd,
27562664 const EnvironmentReference& r_env, TermTags o_tags)
27572665 {
27582666 if(IsList(nd))
@@ -2778,18 +2686,118 @@
27782686 else
27792687 ThrowListTypeErrorForNonlist(nd, true);
27802688 // NOTE: As %PrepareFoldRList.
2781- term.Value = TermRange(term);
2782- term.Tags = TermTags::Temporary;
2689+ term.Value = TermRange(term, TermTags::Temporary);
27832690 }
27842691
2785-YB_FLATTEN ReductionStatus
2786-LetImpl(TermNode& term, ContextNode& ctx, bool no_lift, bool with_env = {})
2692+ReductionStatus
2693+LetAsteriskImpl(TermNode& term, ContextNode& ctx, bool no_lift)
27872694 {
2788- Retain(term);
2695+ if(FetchArgumentN(term) > 0)
2696+ {
2697+ auto& con(term.GetContainerRef());
2698+ auto i(con.begin());
2699+ auto& bindings(*++i);
2700+
2701+ // NOTE: Optimize by the fast path for cases of zero arguments.
2702+ if(IsEmpty(bindings))
2703+ return LetEmpty(term, ctx, no_lift, {});
2704+
2705+ const auto add_con([&]() -> TermNode::Container&{
2706+ return con.emplace_front().GetContainerRef();
2707+ });
2708+
2709+ if(const auto p = NPL::TryAccessLeaf<TermReference>(bindings))
2710+ {
2711+ auto& nd(p->get());
2712+
2713+ // NOTE: Optimize by the fast path for cases of zero arguments.
2714+ if(IsEmpty(nd))
2715+ return LetEmpty(term, ctx, no_lift, {});
2716+ if(p->IsMovable())
2717+ {
2718+ auto& tcon(add_con());
2719+
2720+ tcon.splice(tcon.begin(), nd.GetContainerRef(), nd.begin());
2721+ }
2722+ else
2723+ {
2724+ p->AddTags(TermTags::Nonmodifying);
2725+ // NOTE: As %PrepareFoldRList.
2726+ if(!IsList(nd))
2727+ ThrowInsufficientTermsError(nd, true);
2728+ bindings.ClearContainer(),
2729+ bindings.Value = TermRange(nd, p->GetTags());
2730+ add_con().push_front(nd.GetContainer().front());
2731+ ++bindings.Value.GetObject<TermRange>().First;
2732+ }
2733+ }
2734+ else if(const auto p_tr = NPL::TryAccessLeaf<TermRange>(bindings))
2735+ {
2736+ if(p_tr->empty())
2737+ return LetEmpty(term, ctx, no_lift, {});
2738+ add_con().push_front(NPL::Deref(p_tr->First++));
2739+ }
2740+ else
2741+ {
2742+ auto& tcon(add_con());
2743+
2744+ tcon.splice(tcon.begin(), bindings.GetContainerRef(),
2745+ bindings.begin());
2746+ }
2747+
2748+ // NOTE: As %LetExpire with 1 prvalue subterm (see below).
2749+ auto& extracted(con.front());
2750+#if true
2751+ auto ref([&]() -> TermReference{
2752+ auto& o(extracted.GetContainerRef().front());
2753+
2754+ if(const auto p = NPL::TryAccessLeaf<TermReference>(o))
2755+ return TermReference(GetLValueTagsOf(p->GetTags()), *p);
2756+ return TermReference(GetLValueTagsOf(o.Tags | extracted.Tags)
2757+ | TermTags::Unique, o, ctx.GetRecordPtr());
2758+ }());
2759+ auto& nd(ref.get());
2760+
2761+ if(IsBranchedList(nd))
2762+ {
2763+ TermNode::Container tcon(term.get_allocator());
2764+
2765+ i = term.begin();
2766+ tcon.splice(tcon.end(), con, ++i, con.end());
2767+ term.emplace(std::move(tcon));
2768+
2769+ auto& nterm(*term.emplace()->emplace());
2770+ TermReference tref(BindReferenceTags(ref.GetTags()), ref);
2771+
2772+ RegularizeTerm(nterm,
2773+ ReduceToFirst(nterm, AccessFirstSubterm(nd), &tref));
2774+ ReduceToRestOrVal(*con.emplace_front().emplace(), nd, &ref,
2775+ [](TermNode&) ynothrow{},
2776+ [&](TermNode& dst, TermNode& tm, const TermReference&){
2777+ LiftOtherOrCopy(dst, tm, ref.IsMovable());
2778+ });
2779+ return LetCommon(term, ctx, no_lift, {});
2780+ }
2781+ ThrowInsufficientTermsError(nd, true);
2782+#else
2783+
2784+ LetExpire(con.emplace_front(), extracted,
2785+ ctx.GetRecordPtr(), extracted.Tags);
2786+ return LetCore(term, ctx, no_lift, {});
2787+#endif
2788+ }
2789+ ThrowLetError(term);
2790+}
2791+
2792+ReductionStatus
2793+LetOrRecImpl(TermNode& term, ContextNode& ctx,
2794+ ReductionStatus(&let_core)(TermNode&, ContextNode&, bool, bool),
2795+ bool no_lift, bool with_env = {})
2796+{
27892797 if(FetchArgumentN(term) > (with_env ? 1 : 0))
27902798 {
27912799 auto i(term.begin());
2792- // NOTE: This is to be the initial content of %nterm in %LetCore.
2800+ // NOTE: This is to be the initial content of %nterm in %let_core.
27932801 auto& forwarded(*i);
27942802
27952803 if(with_env)
@@ -2797,13 +2805,19 @@
27972805
27982806 auto& bindings(*++i);
27992807
2808+ // NOTE: Optimize by the fast path for cases of zero arguments.
2809+ if(IsEmpty(bindings))
2810+ return LetEmpty(term, ctx, no_lift, with_env);
28002811 if(const auto p = NPL::TryAccessLeaf<TermReference>(bindings))
28012812 {
28022813 auto& nd(p->get());
28032814
2815+ // NOTE: Optimize by the fast path for cases of zero arguments.
2816+ if(IsEmpty(nd))
2817+ return LetEmpty(term, ctx, no_lift, with_env);
28042818 if(p->IsMovable())
2805- ExpireReferenceListLV(forwarded, nd,
2806- p->GetEnvironmentReference(), p->GetTags());
2819+ LetExpire(forwarded, nd, p->GetEnvironmentReference(),
2820+ p->GetTags());
28072821 else
28082822 {
28092823 p->AddTags(TermTags::Nonmodifying);
@@ -2813,19 +2827,67 @@
28132827 forwarded.Tags = TermTags::Nonmodifying);
28142828 else
28152829 ThrowInsufficientTermsError(nd, true);
2816- return LetCore(term, ctx, no_lift, with_env);
28172830 }
28182831 }
28192832 else
2820- ExpireReferenceListLV(forwarded, bindings, ctx.GetRecordPtr(),
2833+ LetExpire(forwarded, bindings, ctx.GetRecordPtr(),
28212834 bindings.Tags);
2822- return LetCore(term, ctx, no_lift, with_env);
2835+ return let_core(term, ctx, no_lift, with_env);
28232836 }
2824- else
2825- {
2826- RemoveHead(term);
2827- ThrowInsufficientTermsError(term, {});
2828- }
2837+ ThrowLetError(term);
2838+}
2839+
2840+// XXX: Currently the object language has no feature requiring %with_env.
2841+// Nevertheless, keep it anyway for simplicity.
2842+ReductionStatus
2843+LetRecCore(TermNode& term, ContextNode& ctx, bool no_lift, bool with_env)
2844+{
2845+ // NOTE: Subterms are %nterm (the term range of 'bindings' with optional
2846+ // temporary list), optional 'e', originally bound 'bindings',
2847+ // trailing 'body'.
2848+ YAssert(term.size() >= (with_env ? 3 : 2), "Invalid nested call found.");
2849+
2850+ auto i(term.begin());
2851+ auto& nterm(*i);
2852+ auto& rterm(LetBodyFlatten(term, i, with_env));
2853+
2854+ yunseq(rterm.Value = nterm.Value, rterm.Tags = nterm.Tags);
2855+ ReduceListExtractFirst(rterm);
2856+ // NOTE: Now subterms are %nterm, optional 'e', originally bound
2857+ // 'bindings', 'body', extracted 'formals' for the definition.
2858+ ReduceListExtractRestFwd(nterm);
2859+ // NOTE: Now subterms are extracted initializers for the definition,
2860+ // optional 'e', originally bound 'bindings', 'body',
2861+ // extracted 'formals' for the definition.
2862+ YAssert(term.size() >= (with_env ? 5 : 4), "Invalid nested call found.");
2863+ return LetCombinePrepare([&, no_lift]() -> ReductionStatus{
2864+ // NOTE: Now subterms are extracted initializers for the definition plus
2865+ // the parent in %Value, unused 'bindings', 'body', extracted
2866+ // 'formals' for the definition.
2867+ YAssert(term.size() == 4, "Invalid term found.");
2868+#if false
2869+ // NOTE: There is no need to check the parameter since it would be
2870+ // checked in the call to %BindParameter later.
2871+ CheckParameterTree(term.GetContainer().back());
2872+#endif
2873+ return LetCombineBody(
2874+ [&](TermNode& operand, TNIter j, EnvironmentGuard& egd){
2875+ auto& body(NPL::Deref(j++));
2876+
2877+ operand.Value.Clear();
2878+ // NOTE: Capture the term regardless of the next term because
2879+ // continuation capture here is unsupported.
2880+ return A1::RelayCurrentNext(ctx, operand,
2881+ [&](TermNode&, ContextNode& c){
2882+ ReduceChildren(operand, c);
2883+ return ReductionStatus::Partial;
2884+ }, NPL::ToReducer(ctx.get_allocator(), A1::NameTypedReducerHandler(
2885+ std::bind([&, j, no_lift](EnvironmentGuard& gd){
2886+ BindParameter(ctx.GetRecordPtr(), NPL::Deref(j), operand);
2887+ return LetCallBody(term, ctx, body, gd, no_lift);
2888+ }, std::move(egd)), "eval-letrec-bind")));
2889+ }, term, ctx);
2890+ }, term, ctx, with_env);
28292891 }
28302892 //@}
28312893
@@ -2950,7 +3012,7 @@
29503012 Retain(term);
29513013 RemoveHead(term);
29523014 #if NPL_Impl_NPLA1_Enable_Thunked
2953- return CondImpl(term, ctx, term.begin());
3015+ return ReduceCond(term, ctx, term.begin());
29543016 #else
29553017 for(auto i(term.begin()); i != term.end(); ++i)
29563018 {
@@ -3047,13 +3109,13 @@
30473109 else
30483110 BindMoveLocalObject(x, assign_term);
30493111 ForwardToUnwrapped(appv);
3050- term.GetContainerRef() = [&]{
3112+ {
30513113 TermNode::Container tcon(term.get_allocator());
30523114
30533115 tcon.push_back(std::move(appv));
30543116 tcon.push_back(std::move(op));
3055- return tcon;
3056- }();
3117+ tcon.swap(term.GetContainerRef());
3118+ }
30573119 // NOTE: See the precondition of
30583120 // %Combine<TailCall>::ReduceEnvSwitch.
30593121 return Combine<TailCall>::ReduceEnvSwitch(term, ctx,
@@ -3106,9 +3168,7 @@
31063168 RestFwd(TermNode& term)
31073169 {
31083170 return RestOrVal(term, [](TermNode&) ynothrow{},
3109- [&](TermNode& dst, TermNode& tm, ResolvedTermReferencePtr p_ref){
3110- LiftOtherOrCopyPropagate(dst, tm, p_ref);
3111- });
3171+ LiftOtherOrCopyPropagateRef);
31123172 }
31133173
31143174 ReductionStatus
@@ -3134,7 +3194,10 @@
31343194 ReductionStatus
31353195 RestVal(TermNode& term)
31363196 {
3137- return RestOrVal(term, LiftSubtermsToReturn, DoFirstRestVal);
3197+ return RestOrVal(term, LiftSubtermsToReturn,
3198+ [](TermNode& dst, TermNode& tm, const TermReference&){
3199+ DoFirstRestVal(dst, tm, true);
3200+ });
31383201 }
31393202
31403203 void
@@ -3259,8 +3322,12 @@
32593322 ReductionStatus
32603323 DefineLazy(TermNode& term, ContextNode& ctx)
32613324 {
3262- DoDefine(term, std::bind(BindParameterChecked, ctx.GetRecordPtr(),
3263- std::placeholders::_1, std::ref(term)));
3325+ DoDefine(term, [&](const TermNode& t){
3326+ const auto& p_env(ctx.GetRecordPtr());
3327+
3328+ CheckFrozenEnvironment(p_env);
3329+ BindParameter(p_env, t, term);
3330+ });
32643331 return ReduceReturnUnspecified(term);
32653332 }
32663333
@@ -3443,7 +3510,7 @@
34433510 {
34443511 const auto a(term.get_allocator());
34453512 // NOTE: The %p_type handle can be extended to point to a metadata block.
3446- term.GetContainerRef() = [&]{
3513+ {
34473514 TermNode::Container tcon(a);
34483515 // XXX: Allocator is not used here for better performance.
34493516 shared_ptr<void> p_type(new yimpl(byte));
@@ -3452,8 +3519,8 @@
34523519 tcon.push_back(AsForm(a, Encapsulate(p_type), 1U));
34533520 tcon.push_back(AsForm(a, Encapsulated(p_type), 1U));
34543521 tcon.push_back(AsForm(a, Decapsulate(p_type), 1U));
3455- return tcon;
3456- }();
3522+ tcon.swap(term.GetContainerRef());
3523+ }
34573524 return ReductionStatus::Retained;
34583525 }
34593526
@@ -3508,7 +3575,7 @@
35083575 BindMoveNextNLocalSubobjectInPlace(std::next(term.begin()), 5);
35093576 // NOTE: This is for the store of lvalue list.
35103577 term.emplace();
3511- return DoAccL(term, ctx);
3578+ return ReduceAccL(term, ctx);
35123579 }
35133580
35143581 ReductionStatus
@@ -3526,7 +3593,7 @@
35263593 // NOTE: These are for the store of %n2term and the lvalue list.
35273594 rterm.emplace();
35283595 rterm.emplace();
3529- return DoRLiftSum(term, ctx, rterm, DoAccR);
3596+ return ReduceLiftSum(term, ctx, rterm, ReduceAccR);
35303597 }
35313598
35323599 ReductionStatus
@@ -3538,7 +3605,7 @@
35383605
35393606 BindMoveLocalObjectInPlace(*++i);
35403607 BindMoveLocalObjectInPlace(*++i);
3541- return DoFoldRMap1(term, ctx, DoFoldR1);
3608+ return ReduceFoldRMap1(term, ctx, ReduceFoldR1);
35423609 }
35433610
35443611 ReductionStatus
@@ -3549,25 +3616,28 @@
35493616 auto i(term.begin());
35503617
35513618 BindMoveLocalObjectInPlace(*++i);
3552- return DoFoldRMap1(term, ctx, DoMap1);
3619+ return ReduceFoldRMap1(term, ctx, ReduceMap1);
35533620 }
35543621
35553622 ReductionStatus
3556-ListConcat(TermNode& term, ContextNode& ctx)
3623+ListConcat(TermNode& term)
35573624 {
35583625 RetainN(term, 2);
3559-
3560- auto ri(term.rbegin());
3561-
3562- LiftToReturn(*ri);
3563- // NOTE: Bind 'x' as the local reference to list temporary object.
3564- PrepareFoldRList(*++ri);
35653626 RemoveHead(term);
3566- return DoListConcat(term, ctx);
3627+
3628+ auto i(term.begin());
3629+ auto& x(*i);
3630+ auto& y(*++i);
3631+ auto& ycon(y.GetContainerRef());
3632+
3633+ LiftToReturn(y);
3634+ PrependList(ycon, x);
3635+ TermNode::Container(std::move(ycon)).swap(term.GetContainerRef());
3636+ return ReductionStatus::Retained;
35673637 }
35683638
35693639 ReductionStatus
3570-Append(TermNode& term, ContextNode& ctx)
3640+Append(TermNode& term)
35713641 {
35723642 Retain(term);
35733643 #if true
@@ -3584,43 +3654,69 @@
35843654 tm.GetContainerRef().splice(tm.end(), term.GetContainerRef(), ++i,
35853655 term.end());
35863656 #endif
3587- return DoAppend(term, ctx);
3657+ return ReduceAppend(term);
35883658 }
35893659
35903660 ReductionStatus
3591-ListExtractFirst(TermNode& term, ContextNode& ctx)
3661+ListExtractFirst(TermNode& term)
35923662 {
3593- return ListExtractFirstRest(term, ctx, DoListExtractFirst);
3663+ PrepareListExtract(term);
3664+ return ReduceListExtractFirst(term);
35943665 }
35953666
35963667 ReductionStatus
3597-ListExtractRestFwd(TermNode& term, ContextNode& ctx)
3668+ListExtractRestFwd(TermNode& term)
35983669 {
3599- return ListExtractFirstRest(term, ctx, DoListExtractRestFwd);
3670+ PrepareListExtract(term);
3671+ return ReduceListExtractRestFwd(term);
36003672 }
36013673
36023674 ReductionStatus
36033675 Let(TermNode& term, ContextNode& ctx)
36043676 {
3605- return LetImpl(term, ctx, {});
3677+ return LetOrRecImpl(term, ctx, LetCore, {});
36063678 }
36073679
36083680 ReductionStatus
36093681 LetRef(TermNode& term, ContextNode& ctx)
36103682 {
3611- return LetImpl(term, ctx, true);
3683+ return LetOrRecImpl(term, ctx, LetCore, true);
36123684 }
36133685
36143686 ReductionStatus
36153687 LetWithEnvironment(TermNode& term, ContextNode& ctx)
36163688 {
3617- return LetImpl(term, ctx, {}, true);
3689+ return LetOrRecImpl(term, ctx, LetCore, {}, true);
36183690 }
36193691
36203692 ReductionStatus
36213693 LetWithEnvironmentRef(TermNode& term, ContextNode& ctx)
36223694 {
3623- return LetImpl(term, ctx, true, true);
3695+ return LetOrRecImpl(term, ctx, LetCore, true, true);
3696+}
3697+
3698+ReductionStatus
3699+LetAsterisk(TermNode& term, ContextNode& ctx)
3700+{
3701+ return LetAsteriskImpl(term, ctx, {});
3702+}
3703+
3704+ReductionStatus
3705+LetAsteriskRef(TermNode& term, ContextNode& ctx)
3706+{
3707+ return LetAsteriskImpl(term, ctx, true);
3708+}
3709+
3710+ReductionStatus
3711+LetRec(TermNode& term, ContextNode& ctx)
3712+{
3713+ return LetOrRecImpl(term, ctx, LetRecCore, {});
3714+}
3715+
3716+ReductionStatus
3717+LetRecRef(TermNode& term, ContextNode& ctx)
3718+{
3719+ return LetOrRecImpl(term, ctx, LetRecCore, {});
36243720 }
36253721
36263722
diff -r dfccd642351f -r 8f214fbb4405 YFramework/source/NPL/NPLA1Internals.cpp
--- a/YFramework/source/NPL/NPLA1Internals.cpp Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/source/NPL/NPLA1Internals.cpp Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Internals.cpp
1212 \ingroup NPL
1313 \brief NPLA1 内部接口。
14-\version r20439
14+\version r20459
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 473
1717 \par 创建时间:
1818 2020-02-15 13:20:08 +0800
1919 \par 修改时间:
20- 2021-03-01 18:44 +0800
20+ 2021-04-20 22:34 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 非公开模块名称:
@@ -27,7 +27,8 @@
2727
2828 #include "NPL/YModules.h"
2929 #include "NPLA1Internals.h" // for NPL::Deref, Environment, ystdex::dismiss,
30-// shared_ptr, std::make_move_iterator, NPL::AsTermNode;
30+// shared_ptr, std::throw_with_nested, InvalidSyntax, std::make_move_iterator,
31+// NPL::AsTermNode;
3132
3233 using namespace YSLib;
3334
@@ -222,6 +223,26 @@
222223 #endif
223224
224225
226+void
227+ThrowNestedParameterTreeCheckError()
228+{
229+ std::throw_with_nested(InvalidSyntax("Failed checking for parameter in a"
230+ " parameter tree (expected a symbol or '#ignore')."));
231+}
232+
233+char
234+ExtractSigil(string_view& id)
235+{
236+ char sigil(id.front());
237+
238+ if(sigil != '&' && sigil != '%' && sigil != '@')
239+ sigil = char();
240+ else
241+ id.remove_prefix(1);
242+ return sigil;
243+}
244+
245+
225246 ReductionStatus
226247 ReduceAsSubobjectReference(TermNode& term, shared_ptr<TermNode> p_sub,
227248 const EnvironmentReference& r_env)
@@ -256,6 +277,8 @@
256277 const auto& r_env(ref.GetEnvironmentReference());
257278 const auto a(term.get_allocator());
258279
280+ // XXX: Allocators are not used on %FormContextHandler for performance in
281+ // most cases.
259282 return ReduceAsSubobjectReference(term, YSLib::allocate_shared<TermNode>(a,
260283 NPL::AsTermNode(a, ContextHandler(std::allocator_arg, a,
261284 FormContextHandler(RefContextHandler(h, r_env), n)))),
diff -r dfccd642351f -r 8f214fbb4405 YFramework/source/NPL/NPLA1Internals.h
--- a/YFramework/source/NPL/NPLA1Internals.h Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/source/NPL/NPLA1Internals.h Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Internals.h
1212 \ingroup NPL
1313 \brief NPLA1 内部接口。
14-\version r20982
14+\version r21084
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2020-02-15 13:20:08 +0800
1919 \par 修改时间:
20- 2021-04-05 02:53 +0800
20+ 2021-04-20 22:39 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 非公开模块名称:
@@ -33,8 +33,11 @@
3333 // ReductionStatus, Reducer, ystdex::get_less, EnvironmentReference,
3434 // NPL::tuple, YSLib::get, list, ystdex::unique_guard, std::declval,
3535 // EnvironmentGuard, make_observer, std::bind, std::placeholders, std::ref,
36-// TermReference, YSLib::map, set, A1::NameTypedReducerHandler,
37-// A1::NameTypedContextHandler, ystdex::bind1;
36+// YSLib::map, set, A1::NameTypedReducerHandler, A1::NameTypedContextHandler,
37+// ystdex::bind1, std::placeholders::_2, TermReference,
38+// ThrowTypeErrorForInvalidType, ystdex::type_id, ParameterMismatch,
39+// NPL::TryAccessLeaf, ystdex::update_thunk, IsIgnore, IsNPLASymbol,
40+// ThrowInvalidTokenError;
3841 #include <ystdex/ref.hpp> // for ystdex::unref;
3942
4043 namespace NPL
@@ -885,6 +888,10 @@
885888 //@}
886889
887890
891+//! \since build 881
892+using Action = function<void()>;
893+
894+
888895 //! \since build 897
889896 YB_ATTR_nodiscard YB_PURE inline
890897 PDefH(TermReference, EnsureLValueReference, const TermReference& ref)
@@ -897,6 +904,116 @@
897904 ImplRet(TermReference(ref.GetTags() & ~TermTags::Unique, std::move(ref)))
898905
899906
907+//! \since build 917
908+YB_NORETURN void
909+ThrowNestedParameterTreeCheckError();
910+
911+//! \since build 917
912+YB_NORETURN inline PDefH(void, ThrowFormalParameterTypeError,
913+ const TermNode& term, bool has_ref)
914+ ImplExpr(ThrowTypeErrorForInvalidType(ystdex::type_id<TokenValue>(), term,
915+ has_ref))
916+
917+//! \since build 917
918+char
919+ExtractSigil(string_view&);
920+
921+
922+//! \since build 917
923+//@{
924+template<typename _fBindValue>
925+class GParameterValueMatcher final
926+{
927+public:
928+ _fBindValue BindValue;
929+
930+private:
931+ // XXX: Allocators are not used here for performance in most cases.
932+ mutable Action act{};
933+
934+public:
935+ template<class _type>
936+ GParameterValueMatcher(_type&& arg)
937+ : BindValue(yforward(arg))
938+ {}
939+
940+ void
941+ operator()(const TermNode& t) const
942+ {
943+ try
944+ {
945+ // NOTE: This is a trampoline to eliminate the call depth
946+ // limitation.
947+ Match(t, {});
948+ while(act)
949+ {
950+ const auto a(std::move(act));
951+
952+ a();
953+ }
954+ }
955+ CatchExpr(ParameterMismatch&, throw)
956+ CatchExpr(..., ThrowNestedParameterTreeCheckError())
957+ }
958+
959+private:
960+ YB_FLATTEN void
961+ Match(const TermNode& t, bool t_has_ref) const
962+ {
963+ if(IsList(t))
964+ {
965+ if(IsBranch(t))
966+ MatchSubterms(t.begin(), t.end());
967+ }
968+ else if(const auto p_t = NPL::TryAccessLeaf<const TermReference>(t))
969+ {
970+ auto& nd(p_t->get());
971+
972+ ystdex::update_thunk(act, [&]{
973+ Match(nd, true);
974+ });
975+ }
976+ else if(const auto p = TermToNamePtr(t))
977+ {
978+ const auto& n(*p);
979+
980+ if(!IsIgnore(n))
981+ {
982+ if(IsNPLASymbol(n))
983+ BindValue(n);
984+ else
985+ ThrowInvalidTokenError(n);
986+ }
987+ }
988+ else
989+ ThrowFormalParameterTypeError(t, t_has_ref);
990+ }
991+
992+ void
993+ MatchSubterms(TNCIter i, TNCIter last) const
994+ {
995+ if(i != last)
996+ {
997+ // XXX: Use explicit captures here to ensure ISO C++20
998+ // compatibility.
999+ ystdex::update_thunk(act, [this, i, last]{
1000+ return MatchSubterms(std::next(i), last);
1001+ });
1002+ Match(NPL::Deref(i), {});
1003+ }
1004+ }
1005+};
1006+
1007+//! \relates GParameterValueMatcher
1008+template<typename _fBindValue>
1009+YB_ATTR_nodiscard inline GParameterValueMatcher<_fBindValue>
1010+MakeParameterValueMatcher(_fBindValue bind_value)
1011+{
1012+ return GParameterValueMatcher<_fBindValue>(std::move(bind_value));
1013+}
1014+//@}
1015+
1016+
9001017 //! \since build 897
9011018 YB_ATTR_nodiscard YB_STATELESS yconstfn
9021019 PDefH(TermTags, BindReferenceTags, TermTags ref_tags) ynothrow
@@ -969,10 +1086,6 @@
9691086 ReduceForCombinerRef(TermNode&, const TermReference&, const ContextHandler&,
9701087 size_t);
9711088
972-
973-//! \since build 881
974-using Action = function<void()>;
975-
9761089 } // inline namespace Internals;
9771090
9781091 } // namesapce A1;
diff -r dfccd642351f -r 8f214fbb4405 YFramework/source/NPL/SContext.cpp
--- a/YFramework/source/NPL/SContext.cpp Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/source/NPL/SContext.cpp Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file SContext.cpp
1212 \ingroup NPL
1313 \brief S 表达式上下文。
14-\version r2052
14+\version r2061
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 329
1717 \par 创建时间:
1818 2012-08-03 19:55:59 +0800
1919 \par 修改时间:
20- 2021-03-31 06:26 +0800
20+ 2021-04-15 22:19 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -90,36 +90,36 @@
9090 }
9191
9292 void
93-TermNode::MoveContainer(TermNode&& node)
93+TermNode::MoveContainer(TermNode&& nd)
9494 {
95- YAssert(!ystdex::ref_eq<>()(*this, node), "Invalid self move found.");
95+ YAssert(!ystdex::ref_eq<>()(*this, nd), "Invalid self move found.");
9696
9797 // NOTE: Similar to %ValueNode::MoveContainer.
9898 const auto t(std::move(GetContainerRef()));
9999
100- container = std::move(node.container);
100+ SwapContainer(nd);
101101 }
102102
103103 void
104-TermNode::MoveContent(TermNode&& node)
104+TermNode::MoveContent(TermNode&& nd)
105105 {
106- YAssert(!ystdex::ref_eq<>()(*this, node), "Invalid self move found.");
106+ YAssert(!ystdex::ref_eq<>()(*this, nd), "Invalid self move found.");
107107
108108 // NOTE: Similar to %ValueNode::MoveContent.
109109 const auto t(std::move(*this));
110110
111- SetContent(std::move(node));
111+ SetContent(std::move(nd));
112112 }
113113
114114 void
115-TermNode::MoveValue(TermNode&& node)
115+TermNode::MoveValue(TermNode&& nd)
116116 {
117- YAssert(!ystdex::ref_eq<>()(*this, node), "Invalid self move found.");
117+ YAssert(!ystdex::ref_eq<>()(*this, nd), "Invalid self move found.");
118118
119119 // NOTE: Similar to %ValueNode::MoveValue.
120120 const auto t(std::move(Value));
121121
122- Value = std::move(node.Value);
122+ Value = std::move(nd.Value);
123123 }
124124
125125 void
diff -r dfccd642351f -r 8f214fbb4405 YFramework/source/YSLib/Core/ValueNode.cpp
--- a/YFramework/source/YSLib/Core/ValueNode.cpp Wed Apr 14 12:24:53 2021 +0800
+++ b/YFramework/source/YSLib/Core/ValueNode.cpp Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file ValueNode.cpp
1212 \ingroup Core
1313 \brief 值类型节点。
14-\version r875
14+\version r899
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 338
1717 \par 创建时间:
1818 2012-08-03 23:04:03 +0800
1919 \par 修改时间:
20- 2021-03-01 00:19 +0800
20+ 2021-04-15 22:30 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -35,14 +35,14 @@
3535 {
3636
3737 ValueNode&
38-ValueNode::operator%=(const ValueNode& node)
38+ValueNode::operator%=(const ValueNode& nd)
3939 {
40- return Deref(insert_or_assign(node.name, node).first);
40+ return Deref(insert_or_assign(nd.name, nd).first);
4141 }
4242 ValueNode&
43-ValueNode::operator%=(ValueNode&& node)
43+ValueNode::operator%=(ValueNode&& nd)
4444 {
45- return Deref(insert_or_assign(node.name, std::move(node)).first);
45+ return Deref(insert_or_assign(nd.name, std::move(nd)).first);
4646 }
4747
4848 ValueNode::Container
@@ -52,20 +52,20 @@
5252 }
5353
5454 void
55-ValueNode::MoveContainer(ValueNode&& node)
55+ValueNode::MoveContainer(ValueNode&& nd)
5656 {
57- YAssert(!ystdex::ref_eq<>()(*this, node), "Invalid self move found.");
57+ YAssert(!ystdex::ref_eq<>()(*this, nd), "Invalid self move found.");
5858
5959 // NOTE: As %ValueNode::MoveContent, but only the container is respected.
6060 const auto t(std::move(GetContainerRef()));
6161
62- container = std::move(node.container);
62+ SwapContainer(nd);
6363 }
6464
6565 void
66-ValueNode::MoveContent(ValueNode&& node)
66+ValueNode::MoveContent(ValueNode&& nd)
6767 {
68- YAssert(!ystdex::ref_eq<>()(*this, node), "Invalid self move found.");
68+ YAssert(!ystdex::ref_eq<>()(*this, nd), "Invalid self move found.");
6969
7070 // NOTE: This is required for the case when the moved-to object (referenced
7171 // by '*this') is an ancestor of the moved-from node (referenced by the
@@ -79,25 +79,25 @@
7979 // swap), which would leak resources (rather than destroy them properly).
8080 const auto t(std::move(*this));
8181
82- SetContent(std::move(node));
82+ SetContent(std::move(nd));
8383 }
8484
8585 void
86-ValueNode::MoveValue(ValueNode&& node)
86+ValueNode::MoveValue(ValueNode&& nd)
8787 {
88- YAssert(!ystdex::ref_eq<>()(*this, node), "Invalid self move found.");
88+ YAssert(!ystdex::ref_eq<>()(*this, nd), "Invalid self move found.");
8989
9090 // NOTE: As %ValueNode::MoveContent, but only %Value is respected.
9191 const auto t(std::move(Value));
9292
93- Value = std::move(node.Value);
93+ Value = std::move(nd.Value);
9494 }
9595
9696 void
97-ValueNode::SwapContent(ValueNode& node) ynothrowv
97+ValueNode::SwapContent(ValueNode& nd) ynothrowv
9898 {
99- SwapContainer(node),
100- swap(Value, node.Value);
99+ SwapContainer(nd),
100+ swap(Value, nd.Value);
101101 }
102102
103103 void
@@ -135,18 +135,18 @@
135135 ValueNode::ThrowWrongNameFound(name);
136136 }
137137 ValueNode&
138-AccessNode(ValueNode& node, size_t n)
138+AccessNode(ValueNode& nd, size_t n)
139139 {
140- const auto p(AccessNodePtr(node, n));
140+ const auto p(AccessNodePtr(nd, n));
141141
142142 if(p)
143143 return *p;
144144 ValueNode::ThrowIndexOutOfRange(n);
145145 }
146146 const ValueNode&
147-AccessNode(const ValueNode& node, size_t n)
147+AccessNode(const ValueNode& nd, size_t n)
148148 {
149- const auto p(AccessNodePtr(node, n));
149+ const auto p(AccessNodePtr(nd, n));
150150
151151 if(p)
152152 return *p;
@@ -166,18 +166,18 @@
166166 ystdex::addrof<>(), con.find(name), {}, ystdex::end(con)));
167167 }
168168 observer_ptr<ValueNode>
169-AccessNodePtr(ValueNode& node, size_t n)
169+AccessNodePtr(ValueNode& nd, size_t n)
170170 {
171- auto& con(node.GetContainerRef());
171+ auto& con(nd.GetContainerRef());
172172
173173 // XXX: Conversion to 'ptrdiff_t' might be implementation-defined.
174174 return n < con.size()
175175 ? make_observer(&*std::next(con.begin(), ptrdiff_t(n))) : nullptr;
176176 }
177177 observer_ptr<const ValueNode>
178-AccessNodePtr(const ValueNode& node, size_t n)
178+AccessNodePtr(const ValueNode& nd, size_t n)
179179 {
180- auto& con(node.GetContainer());
180+ auto& con(nd.GetContainer());
181181
182182 // XXX: Conversion to 'ptrdiff_t' might be implementation-defined.
183183 return n < con.size()
diff -r dfccd642351f -r 8f214fbb4405 doc/ChangeLog.V0.9.txt
--- a/doc/ChangeLog.V0.9.txt Wed Apr 14 12:24:53 2021 +0800
+++ b/doc/ChangeLog.V0.9.txt Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file ChangeLog.V0.9.txt
1212 \ingroup Documentation
1313 \brief 版本更新历史记录 - V0.9 。
14-\version r3465
14+\version r3714
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 800
1717 \par 创建时间:
1818 2020-10-12 17:19:23 +0800
1919 \par 修改时间:
20- 2021-04-14 12:02 +0800
20+ 2021-04-21 18:16 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -32,6 +32,245 @@
3232
3333 $now
3434 (
35+ / %YFramework $=
36+ (
37+ / %YSLib.Core.ValueNode $=
38+ (
39+ / $re_add(b915) DLDI "all %TermNode argument 'term' to be accessed \
40+ directly" => 'nd',
41+ // Also same to %TermNode below.
42+ / "required allocator equality" @ "functions %(SetContent#3, \
43+ MoveContent, MoveContainer") @ "class %ValueNode"
44+ $= (/ $impl ^ "%SwapContainer")
45+ // This is a bit efficient due to less assignments of the \
46+ allocator object.
47+ ),
48+ / %NPL $=
49+ (
50+ / @ "class %TermNode" @ %SContext $=
51+ (
52+ * $re_add(b914) "missing setting tags"
53+ @ "function %SetContent#2" @ %SContext $since b857,
54+ / $re_ex(b915) DLDI "all %TermNode argument 'term' to be \
55+ accessed directly" => 'nd',
56+ / "required allocator equality"
57+ @ "functions %(SetContent#3, MoveContent, MoveContainer")
58+ $= (/ $impl ^ "%SwapContainer")
59+ // Same to the change to %ValueNode in \
60+ %YSLib.Core.ValueNode.
61+ ),
62+ / @ %NPLA $=
63+ (
64+ (
65+ * "missing reset tags" @ "destination term"
66+ @ "function %LiftCollapsed" $since b857;
67+ * $comp "possible unexpected different effect on tags between \
68+ calls to %(LiftCollapsed, MoveCollapsed)" $since b854
69+ ),
70+ + "function %ThrowTypeErrorForInvalidType",
71+ / DLDI "parameter name %is_ref"
72+ @ "function %ThrowListTypeErrorForInvalidType" => "%has_Ref"
73+ // To be consistent with other functions.
74+ ),
75+ / DLDI "set container to temporary value when the container \
76+ allocator equality is known" ^ "%TermNode::Container::swap"
77+ ~ "move assignment" $effective @ ("functions %Forms::(AccL, \
78+ AccR, MakeEncapsulationType, ListConcat)" @ %NPLA1Forms,
79+ "native implementation" @ "applicative 'cmd-get-args'"
80+ @ "function %LoadModule_std_system" @ %Dependency),
81+ // To be consistent to %Forms::(ListExtractRestFwd, Let, \
82+ LetRef, LetWithEnvironment, LetWithEnvironmentRef, \
83+ RestFwd, RestVal) in %NPLA1Forms. Changing of these \
84+ implementations are also a bit more efficient due to one \
85+ less assignment of the allocator object.
86+ / %NPLA1Internals $=
87+ (
88+ + "function %ExtractSigil",
89+ (
90+ + "function %ThrowNestedParameterTreeCheckError",
91+ + "function %ThrowFormalParameterTypeError"
92+ ^ $dep_from ("%ThrowTypeErrorForInvalidType" @ %NPLA);
93+ + "class template %GParameterValueMatcher"
94+ ^ $dep_from ("%(ThrowNestedParameterTreeCheckError, \
95+ ThrowFormalParameterTypeError)",
96+ "%(IsIgnore, ThrowInvalidTokenError)" @ %NPLA1);
97+ + "function template %MakeParameterValueMatcher"
98+ )
99+ ),
100+ / %NPLA1 $=
101+ (
102+ / DLDI "simplified function %BindParameter" $=
103+ (
104+ / ^ "%list::emplace_back return value" ~ "%list::back",
105+ // This requires ISO C++17 for %std::list. Nevertheless, \
106+ %ystdex::list is already capable.
107+ / ^ $dep_from "%ExtractSigil" @ %NPLA1Internals
108+ ),
109+ + "functions %(IsIgnore, ThrowInvalidTokenError)",
110+ + "function %CheckParameterTree" ^ $dep_from
111+ ("%MakeParameterValueMatcher" @ %NPLA1Internals),
112+ + "function %CheckEnvironmentFormals" ^ ($dep_from
113+ "%ThrowInvalidTokenError", "%IsNPLAToken", $dep_from
114+ ("%ThrowFormalParameterTypeError" @ %NPLA1Internals)),
115+ - $revert(b794) "function template %CheckSymbol"
116+ $dep_from $dep_to "removal of CheckSymbol",
117+ - $revert(b794) "function template %CheckParameterLeafToken"
118+ $dep_from $dep_to "removal of CheckParameterLeafToken",
119+ / @ "functions %(BindParameter, MatchParameter)" $=
120+ (
121+ (
122+ / $impl "aligned token value handling to \
123+ %CheckParameterTree" ^ ($dep_from "%IsIgnore",
124+ "%IsNPLASymbol", "%TermToNamePtr",
125+ ($dep_from ("%ThrowInvalidTokenError",
126+ "%(ThrowNestedParameterTreeCheckError, \
127+ ThrowFormalParameterTypeError)")
128+ @ %NPLA1Internals)) ~ "%ParameterMismatch",
129+ // Exceptions other than %ParameterTree are caught and \
130+ rethrown with a nested error.
131+ / "supported detection of reference values"
132+ @ "token mismatch failure",
133+ // This makes differences on the call to \
134+ %ThrowTypeErrorForInvalidType.
135+ / "failure for trailing token type" ^ "same handling to \
136+ other non-trailing token type failure"
137+ ~ "%ParameterMismatch",
138+ // This also allows simplified lightweight parameter \
139+ tree matching checks without binding to ignore the \
140+ ellipsis (i.e. the existence of the trailing \
141+ parameter).
142+ * $comp "wrong base type of exception type \
143+ %ParameterMismatch thrown from token value check"
144+ $since b902
145+ // This should be %InvalidSyntax. Since b902, \
146+ %ParameterMismatch no longer has the base \
147+ %InvalidSyntax, but as a type error of \
148+ %ListTypeError.
149+ ),
150+ (
151+ / ("handled '#ignored' and NPLA symbol check"
152+ @ "value binding", "handled empty token ignorance \
153+ after removal of prefix '.'" @ "trailing binding")
154+ @ "function %MatchParameter";
155+ / DLDI "simplified function %BindParameter"
156+ ),
157+ / DLI "optimized for cases when parameter leaf node is of \
158+ a %TermReference value to a non-reference value"
159+ ),
160+ + "function %BindParameterWellFormed"
161+ ),
162+ / @ "namespace %Forms" @ %NPLA1Forms $=
163+ (
164+ / DLDI "adjusted 'YB_ATTR_nodiscard' and name"
165+ @ "several internal functions",
166+ / DLI "simplified list construction" ^ "syncronized calls"
167+ ~ "continuation" $=
168+ (
169+ / "simplified list extraction" $effective @ $impl
170+ ("functions %(ListExtractFirst, ListExtractRest, Let, \
171+ Let, LetRef, LetWithEnvironment, \
172+ LetWithEnvironmentRef)")
173+ $dep_to "avoided uses of context in list operations",
174+ / "simplified list concatenation"
175+ $effective @ "functions %(ListConcat, Append)"
176+ $dep_to "avoided uses of context in list operations",
177+ / "simplified mapping application" @ "function %Map1"
178+ ),
179+ - "2nd parameter" @ "functions %(ListConcat, Append, \
180+ ListExtractFirst, ListExtractRestFwd)"
181+ $dep_all_from "avoided uses of context in list operations",
182+ / DLI "simplified in cases for rvalues list of 1st argument by \
183+ list splicing" @ "function %ListConcat",
184+ / DLDI "functions %(RestFwd, RestVal)",
185+ / DLDI "simplified function with vau handler parameter checks"
186+ ^ $dep_from ("functions %(CheckParameterTree, \
187+ CheckEnvironmentFormals)" @ %NPLA1),
188+ / DLDI "function %DefineLazy",
189+ / "vau handlers" $=
190+ (
191+ / "parameter checks" @ "constructors" $=
192+ (
193+ / $impl ^ $dep_from ("%(CheckParameterTree, \
194+ CheckEnvironmentFormals)" @ %NPLA1);
195+ / $comp ^ "wrapped in the nested %InvalidSyntax \
196+ exception on failure",
197+ * $re_add(b917) $comp "missing nested call safety in \
198+ handling terms from object language"
199+ $orig (@ %NPLA1 $since b799)
200+ )
201+ / DLI "optimized binding" @ "%operator()"
202+ ^ ("%BindParameterWellFormed" @ %NPLA1)
203+ ~ "%BindParameter"
204+ ),
205+ / "optimized functions %(Let, LetRef, LetWithEnvironment, \
206+ LetWithEnvironmentRef) $=
207+ (
208+ / $design "simplified argument list evaluation"
209+ !^ "%Continuation",
210+ // The continuation was already removed in b916. The \
211+ explicit %Continuation is still redundant.
212+ / DLI "simplified" ^ "synchronous calls of binding list \
213+ decompositions",
214+ / DLI "optimized cases for zero arguments with a different \
215+ path",
216+ - DLI "redundant parameter check"
217+ $dep_from ("constructors" @ "vau handlers")
218+ // The call to %BindParameter now fully implies the \
219+ check implemented in %CheckParameter.
220+ ),
221+ + "functions %(LetAsterisk, LetAsteriskRef, LetRec, LetRecRef)",
222+ / @ "functions %(DefineWithRecurison, SetWithRecursion)" $=
223+ (
224+ / @ "thunk initialization" $=
225+ (
226+ ^ DLI "allocator from the term parameter",
227+ (
228+ * "wrong exception specifier" @ "constructor"
229+ $since b894;
230+ + "full token check" ^ $dep_from
231+ ("%MakeParameterValueMatcher" @ %NPLA1Internals);
232+ // As %BindParameter in %NPLA1.
233+ * $re_add(b917) "missing nested call safety in \
234+ handling terms from object language" $since b780
235+ )
236+ ),
237+ / DLI "optimized binding" ^ ("%BindParameterWellFormed"
238+ @ %NPLA1) ~ "%BindParameter"
239+ )
240+ ),
241+ / @ "function %LoadGroundContext" @ %Dependency $=
242+ (
243+ / $lib "added native derivation enabled by default"
244+ @ ("operative '$let*'" ^ $dep_from
245+ ("%LetAsterisk" @ %NPLA1Forms), "operative '$let*%'"
246+ ^ $dep_from ("%LetAsteriskRef" @ %NPLA1Forms),
247+ "operative '$letrec'" ^ $dep_from ("%LetRec" @ %NPLA1Forms),
248+ "operative '$letrec%'" ^ $dep_from
249+ ("%LetRecRef" @ %NPLA1Forms)),
250+ * "wrong base type of exception type %ParameterMismatch on \
251+ failure thown from call to function template %CheckSymbol"
252+ $since b902
253+ // As the implementations of %(BindParameter, \
254+ MatchParameter) @ %NPLA.
255+ $= (/ $impl $dep_from ^ "%ThrowInvalidTokenError" @ %NPLA1
256+ ~ "%CheckSymbol" $dep_to "removal of CheckSymbol")
257+ ),
258+ * "wrong base type of exception type %ParameterMismatch on \
259+ failure thown from call to function template \
260+ %CheckParameterLeafToken" $effective
261+ @ ("function %BindParameter" @ %NPLA1, "functions \
262+ %Forms::(DefineWithRecursion, SetWithRecursion)" @ %NPLA1Forms)
263+ $since b902
264+ // Ditto.
265+ $= (/ $impl $dep_from ^ "%ThrowInvalidTokenError" @ %NPLA1
266+ ~ "%CheckParameterLeafToken" $dep_to
267+ "removal of CheckParameterLeafToken")
268+ )
269+ )
270+),
271+
272+b916
273+(
35274 (
36275 / "supported 'FREEIMAGE_LIBRARY_TYPE=STATIC'"
37276 @ "%3rdparty/FreeImage/Makefile.gnu";
@@ -121,14 +360,15 @@
121360 - $revert(b914) "function %ListExtract"
122361 $dep_from ("applicative 'list-extract%'"
123362 @ "function %LoadGroundContext" @ %Dependency),
124- / "functions %Forms::(Let, LetRef, LetWithEnvironment, \
363+ / @ "functions %(Let, LetRef, LetWithEnvironment, \
125364 LetWithEnvironmentRef)" $=
126365 (
127366 * @ 'NPL_Impl_NPLA1_Enable_Thunked && \
128367 !NPL_Impl_NPLA1_Enable_InlineDirect' $since b915 $=
129368 (
130- * "current environment corrupted caused by missing \
131- internal capture of the dynamic environment",
369+ * "undefined bahavior caused by missing internal \
370+ variable of the dynamic environment in lambda-capture",
371+ // Current environment would be corrupted, typically.
132372 * "wrong term used as the initializers being initialized"
133373 ),
134374 / $forced "avoided binding temporary tags on elements of \
@@ -143,6 +383,8 @@
143383 redundant copies of list preparation"
144384 $dep_from "%(ListExtractFirst, ListExtractRest)"
145385 $dep_to "let-family native list forwarding",
386+ / DLI "avoided redundant continuation for argument list \
387+ evaluation",
146388 / DLDI
147389 "simplified initialization of binding from movable argument"
148390 )
@@ -207,7 +449,8 @@
207449
208450 ),
209451 + "restriction of copies" @ "applicative %foldr1"
210- @ %Documentation.NPL $dep_from %YFramework.NPL.Dependency
452+ @ %Documentation.NPL $dep_from ("applicative %foldr1"
453+ @ "function %LoadGroundContext" @ %YFramework.NPL.Dependency)
211454 ),
212455
213456 b915
@@ -219,12 +462,12 @@
219462 $effective @ %(SContext, NPLA1),
220463 / %SContext $=
221464 (
222- / DLDI "all %TermNode argument ('node', 'term', 'tm') to be \
465+ / DLDI "%TermNode argument ('node', 'term', 'tm') to be \
223466 accessed directly" => 'nd',
224467 // The direct accesses include member functions and some other \
225468 related functions.
226469 + "function %PropagateTo"
227- )
470+ ),
228471 / %NPLA1 $=
229472 (
230473 * "missing support for term references" @ "trailing \
@@ -408,7 +651,7 @@
408651 b857,
409652 // This also has effects on assignment and exchange \
410653 operations (but not for content setting and lifting).
411- * "missing setting tags" @ "function %SetContent#3"
654+ * "missing setting tags" @ "function %SetContent#3" $since b857
412655 // This also has effects on content setting and lifting \
413656 operations.
414657 )
diff -r dfccd642351f -r 8f214fbb4405 doc/NPL.txt
--- a/doc/NPL.txt Wed Apr 14 12:24:53 2021 +0800
+++ b/doc/NPL.txt Wed Apr 21 18:41:47 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPL.txt
1212 \ingroup Documentation
1313 \brief NPL 规范和实现规格说明。
14-\version r22216
14+\version r22338
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 304
1717 \par 创建时间:
1818 2012-04-25 10:34:20 +0800
1919 \par 修改时间:
20- 2021-04-12 23:37 +0800
20+ 2021-04-21 18:16 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -2486,9 +2486,10 @@
24862486 对项的提升(lifting) 指一类对项的替换变换,使用项进行一定的变换后取代其它项或其一部分,并满足下述提升条件。
24872487 决定替换变换是提升的条件为:被提升的项是提升后的项的一个直接或间接子项,以树表示项则为叶节点取代枝节点。
24882488 这可以视为作为语法变换的消去 λ 抽象的 lambda 提升(详见 https://en.wikipedia.org/wiki/Lambda_lifting )的一般化,但此处和 λ 抽象没有直接关联。
2489-被提升的项往往被转移,因此一般地,需要可修改。
2489+被提升的项往往被转移,因此一般地,需要在宿主语言中可修改(@4.1.4.2) 。若被提升的项表示对象语言的值,一般也需要在对象语言中可修改。
24902490 提升时对抽象的值表示进行操作实现基本的语义功能,可能进行检查,包括为满足接口行为的语义检查和实现为预防宿主语言的未定义行为的附加检查(@5.4) 。
24912491 提升项对象通过变换操作取作为项的值数据成员(@6.2) 。在此基础上有递归版本。
2492+提升项可能修改项的标签(@6.2.2) 。除非另行指定,修改整个项的内容的操作包含修改项的标签。
24922493 提升项可引入或消除(@6.4.6) 间接值(@6.4.3) 。
24932494 提升项通过被引用的对象替换作为项的值数据成员的引用值而消除引用值(@6.6.3.3.3) 。提升项的求值结果(@6.7.1) 是消除引用值的结果。
24942495 提升操作辅助对项的操作,可用于实现规约函数,包括以下各节中描述的 API 。其中:
@@ -3092,7 +3093,7 @@
30923093 规约前被规约项的第一个子项具有遍处理器的所有权,也对目标对象具有所有权。
30933094 假定满足限制而允许删除子项的情形(@6.4.8) 包括:
30943095 主规约函数(@6.7.6.3) 和 NPLA1 扩展实现(@8) 支持的本机函数(@5.3) 的实现可假定被在调用处理器前会转移子项的处理器调用;
3095-通过处理 WHNF 的调用遍处理器的 A1::ReduceCombined(@7.6.4.2) 在调用处理器前会转移子项,可保证调用时生存期不会因为直接清理第一个子项而结束,因此处理器可清理第一个子项。
3096+通过处理 WHNF(@4.4.3.1) 的调用遍处理器的 A1::ReduceCombined(@7.6.4.2) 在调用处理器前会转移子项,可保证调用时生存期不会因为直接清理第一个子项而结束,因此处理器可清理第一个子项。
30963097
30973098 @7.2.2 节点记号:
30983099 NPLA1 实现使用 A1::ValueToken 枚举类型表示用于特殊标记的扩展中间值(@6.6.3) 。
@@ -3108,6 +3109,7 @@
31083109 @7.3 错误处理例程:
31093110 除非另行指定,NPLA1 实现优先使用以下包装 NPLA 异常(@6.5) 的错误处理 API :
31103111 A1::ThrowInvalidSyntaxError
3112+A1::ThrowInvalidTokenError
31113113 A1::ThrowNonmodifiableErrorForAssignee
31123114 A1::ThrowUnsupportedLiteralError
31133115 A1::ThrowValueCategoryError
@@ -3212,9 +3214,12 @@
32123214 注意 A1::ReduceOnce 中的处理器(@7.2.1) 作为应符合关于中间值的使用约束(@7.2.1.1) 。
32133215 若实现中使用的处理器不符合约束,可能不满足 @6.4.7.1 并可能引起未定义行为。
32143216 对支持异步规约的实现(@7.9.2) ,上述处理器还应符合和同步规约实现兼容性(@7.9.1) 中的规则。
3215-A1::ReduceOnce 和辅助规约函数(@6.7.12) 类似,能处理一般的项,没有前置条件。参数中 TermNode(@6.2) 表示的表达式语法意义(@3.4.2) 上非空,但没有实现限制(即不附加检查)。
3216-A1::ReduceOnce 循环调用遍(@7.4.1) 进行必要的重规约,即迭代规约;通过 NPL::CheckReducible(@6.7.3) 判断是否需要重规约。
3217-A1::ReduceOnce 的实现中不直接指定需要重规约;所有 ReductionStatus::Retrying 都来自遍(@7.4.1) 的调用。
3217+A1::ReduceOnce 和辅助规约函数(@6.7.12) 类似,能处理一般的项,没有附加对项的内容的要求的前置条件。参数中 TermNode(@6.2) 表示的表达式语法意义(@3.4.2) 上非空,但没有实现限制(即不附加检查)。
3218+A1::ReduceOnce 循环调用遍(@7.4.1) 即迭代规约。迭代规约响应必要的 ReductionStatus::Retrying 规约状态支持重规约(@6.7.1) 的实现,但在此仅处理规约实现的内部公共状态。具体的重规约由遍(@7.4.1) 的调用实现。
3219+对异步规约中立的规约(包括遍的实现和 NPL 中如 ContextNode::RewriteLoop(@6.8.3.1) 这样的调用规约函数的重写入口)同时对重规约中立。默认实现中,仅有公共的叶遍(@7.4.3) 的实现直接实现重规约。这种实现方式是同步的,即判断需要重规约后不使用异步规约(@6.9) ,但仍保证嵌套调用安全(@6.1.3) 。
3220+遍的同步实现一般通过 NPL::CheckReducible(@6.7.3) 判断是否需要同步的重规约。这同时处理 ReductionStatus::Partial ,同步已被异步规约的部分规约。
3221+在具体操作的异步规约实现中实现的重规约,参见异步规约基本支持(@7.9.2.1) 和异步重规约(@7.10.8) 。当前默认实现中,这由列表遍(@7.4.3) 调用。
3222+A1::ReduceOnce 的实现中不直接指定需要重规约;所有 ReductionStatus::Retrying 都来自遍的调用。
32183223 遍的调用在支持异步规约(@7.9) 的实现中明确指定作为尾上下文(@4.4.7) 。
32193224 名称表达式的求值不进行进一步规约(@4.5.1) ,这由具体遍(@7.4.1) 的实现保证。关于记号,另见记号值(@6.6.3.1) 。
32203225 使用设置遍的 API(@7.4.1) 修改 ContextNode 中的具体遍以使用不同的规约规则。
@@ -3300,7 +3305,7 @@
33003305 @7.6.1.2 处理器调用:
33013306 A1::FormContextHandler::operator() 以构成函数合并(@4.5.3) 的语法构造作为参数。
33023307 宿主实现可访问比对象语言中的合并子(@4.5.3.2) 更多的数据。
3303-实现合并子时,应避免依赖合并中的子项(即 WHNF 第一项)的操作改变可观察行为(@4.1.3) 。一般地,本机实现需在确保第一项关联的对象不被依赖后的适当情形下调用 RemoveHead(@6.4.8) 。
3308+实现合并子时,应避免依赖合并中的子项(即 WHNF(@4.4.3.1) 第一项)的操作改变可观察行为(@4.1.3) 。一般地,本机实现需在确保第一项关联的对象不被依赖后的适当情形下调用 RemoveHead(@6.4.8) 。
33043309 A1::FormContextHandler::operator() 依次进行以下操作:
33053310 按 Wrapping 的次数指定调用合并子参数求值,每次调用 A1::ReduceArguments 求值每一个子项(函数参数);
33063311 若 Check 数据成员非空则调用 Check 进行检查,失败时抛出异常;
@@ -3311,7 +3316,7 @@
33113316 @7.6.1.3 前置条件检查和异常处理:
33123317 A1::FormContextHandler::operator() 调用时,按包装数(@7.6.1.1) 判断是否需要调用(被包装的处理器 Handler 数据成员)。
33133318 若需要调用,调用被包装的处理器 Handler 数据成员,并处理部分异常;
3314-否则,调用 A1::ReduceArguments(@7.4.6) 规约参数项并以减少包装数 1 的上下文处理器中的调用作为后继调用。
3319+否则,以 A1::ReduceArguments(@7.4.6) 方式规约参数项并以减少包装数 1 的上下文处理器中的调用作为后继调用。
33153320 Handler 调用至少可断言项满足 IsBranchedList ,但这在 A1::FormContextHandler::operator() 没有检查。
33163321 NPLA1 实现中,作为被调用的处理器(如 @7.4.6 和 @8.4 中的 API )中可能存在对参数数量的检查。这类检查中已对枝节点类别进行检查,即不需要指定 NPL::IsBranchedList 作为前置条件。
33173322
@@ -3358,7 +3363,7 @@
33583363 作为被规约项,规约合并项的第一个子项应能规约到 A1::FormContextHandler(@7.6.1.1) 的值或引用 A1::FormContextHandler 对象的引用值(@6.3.4) 。
33593364
33603365 @7.6.4.2 规约合并求值:
3361-A1 中包含 ReduceCombined 前缀的函数名的规约函数(@6.7.5) 是合并子调用创建操作,可蕴含合并子调用所需资源的初始化。
3366+A1 中包含 ReduceCombined 前缀的函数名的规约函数(@6.7.5) 是合并子(@4.5.3.2) 调用创建操作,可蕴含合并子调用所需资源的初始化。
33623367 函数 A1::ReduceCombined 对规约合并项(@7.6.4.1) 以已规约的第一个子项为上下文处理器(@7.6.1) 并返回调用结果,以节约严格性分析(@4.4.4.2) 开销;并根据处理器返回的规约结果进行正规化操作。
33633368 通过节点的值数据成员(@6.2) 是否持有 A1::ContextHandler 类型的值或引用到 A1::ContextHandler 的值上的 NPL::TermReference 的值确定是否为上下文处理器。
33643369 若存在 A1::ContextHandler 对象的子对象引用(@6.6.3.3.5) ,先变换子对象引用。这些子对象引用应符合 @6.7.11 约定的表示,否则断言检查失败。
@@ -3408,7 +3413,7 @@
34083413 Forms::EvalString(@8.4.4.1)
34093414 Forms::EvalStringRef(@8.4.4.1)
34103415 Forms::Apply(@8.4.9)
3411-间接调用 A1::RelayForCall 的求值规约操作包括通过过程抽象(@8.4.5) 中的函数引入合并子的调用。
3416+间接调用 A1::RelayForCall 的求值规约操作包括通过过程抽象(@8.4.5) 中的函数引入合并子(@4.5.3.2) 的调用。
34123417 求值规约操作附带绑定操作匹配被绑定的操作数树(@4.4.3.1) 。
34133418 求值规约操作中可能具有提升操作(@7.1.4) 。
34143419 忽略提升操作可允许对象语言的函数调用返回(@4.5.3.1) 引用值(@6.3.4) 。
@@ -3490,7 +3495,7 @@
34903495 @7.7.3.5 非递归绑定:
34913496 非递归绑定在一次匹配之后创建对应的变量绑定。
34923497 合并使用或不使用引用标记字符(@7.7.3.4) 的情形,非结尾列表(@7.7.3.3) 的单一参数对象的绑定初始化包含以下过程:
3493- 若没有绑定标记字符 @ ,则:
3498+ 若不存在绑定标记字符 @ ,则:
34943499 若操作数为可转移的(@6.6.3.3.4) 对象的引用值,则被绑定对象是按以下规则初始化的蕴含隐含的引用折叠(@7.7.3.4) 的引用值:
34953500 存在标记字符时,使用引用推断规则(@7.7.3.4) ,被绑定对象是操作数直接初始化的值,其中被绑定对象(引用值)的标签由操作数的(引用值)的标签决定:
34963501 当有标记字符 & 、绑定非结尾列表且引用值的标签指定唯一引用(@6.2.2) 时,被绑定对象(引用值)中包含绑定临时对象标签(@7.7.3.2) 。
@@ -3541,8 +3546,9 @@
35413546 @7.7.4 绑定支持 API :
35423547 绑定支持 API 包括引入绑定的 API ,通过引入新的绑定(@4.1) 修改求值环境(@4.6.1.1) 。
35433548 用于辅助引入绑定的 API 包括:
3544-函数模板 A1::CheckSymbol 检查记号值是符合匹配条件的符号。
3545-函数模板 A1::CheckParameterLeafToken 检查记号值是符合匹配条件的参数符号。
3549+函数 A1::IsIgnore
3550+函数 A1::CheckParameterTree
3551+函数 A1::CheckEnvironmentFormal
35463552 实现引入绑定的绑定操作(@7.7.3) 的 API 包括:
35473553 函数 A1::MatchParameter 匹配操作数树(@7.7.3) 。
35483554 函数 A1::BindParameter 匹配并绑定操作数到参数上。
@@ -3552,6 +3558,7 @@
35523558 为支持嵌套调用安全的约定(@6.1.3) ,实现应避免无法预测嵌套深度的递归调用,但实现内调用的重定向操作以尾调用形式进行递归调用,类似使用跳板的异步规约动作(@6.9.1) 。
35533559 引入绑定的规则参见绑定操作(@7.7.3) 。
35543560 另见环境修改操作(@8.4.4.3) 和过程抽象(@8.4.5) 。
3561+函数 A1::BindParameterWellFormed
35553562
35563563 @7.8 REPL API :
35573564 NPLA1 提供 API 通过解释器的各个子模块组装 REPL(read-eval-print loop) 的交互式界面。
@@ -3639,7 +3646,8 @@
36393646 NPLA1 主规约函数(@7.4.4) 隐含设置下一求值项(@7.4.3) 以维护约定(@7.4.1.5) 。
36403647 A1::Reduce 通过 ContextState::RewriteGuarded(@7.4.3) 在内部实现异步规约,自身可被作为同步规约函数调用。
36413648 规约函数通过 A1::ReduceOnce 的实现设置上下文中的当前动作(@6.8.3) 支持异步规约相关操作。
3642-和同步规约不同,异步的重规约(@7.4.4) 不由求值遍(@7.4.1.2) 根据规约状态处理。调用异步重规约的代码需插入 A1::ReduceOnce(@7.4.4) 作为起始动作引导重规约。
3649+和同步规约类似(@7.4.4) ,异步的重规约(@6.7.1) 不由求值遍(@7.4.1.2) 的实现规约状态处理。一般地,调用异步重规约(@7.10.8) 的代码需插入 A1::ReduceOnce(@7.4.4) 作为起始动作引导重规约。
3650+和同步规约不同,一般不使用 NPL::CheckReducible(@6.7.3) 而允许和异步的部分规约(@6.7.1) 区分。
36433651 规约状态 ReductionStatus::Retrying(@6.7.1) 在 A1::ReduceOnce 的实现中被用于判断是否跳过当前求值的子表达式支持重规约。
36443652 ContextState::ReduceOnce(@7.4.4) 的默认实现(及要求的替代实现)支持异步分发求值遍。
36453653 在每个表达式求值时,每个求值遍(@7.4.1.2) 的中间结果保存在 ContextNode::LastStatus(@6.8.3.1) 中,其中非 ReductionStatus::Partial(@6.7.1) 的结果被通过调用 CombineSequenceReductionResult 合并。
@@ -3650,7 +3658,7 @@
36503658 其它仅对表达式内的规约操作可直接返回规约状态而不设置上下文中的状态。
36513659
36523660 @7.9.2.2 异步规约派生支持:
3653-以下 NPLA1 API(可能包含直接或间接调用 @7.9.2.1 中异步规约中立(@6.9.5) 外的 API )依赖当前动作支持和实现异步规约:
3661+以下 NPLA1 API(可能包含直接或间接调用异步规约基本支持(@7.9.2.1) 中异步规约中立(@6.9.5) 外的 API )依赖当前动作支持和实现异步规约:
36543662 包含规约作为子表达式的子项的规约函数;
36553663 Forms 下 API 引入的 vau 处理器的 operator() 。
36563664
@@ -3667,7 +3675,7 @@
36673675 特别地,对象语言语法意义上的嵌套函数调用应能引用外层对象(例如,通过绑定引用参数(@7.7.3.5) )而不引起宿主语言的未定义行为(@5.4) 。
36683676 A1::ReduceCombined 在同步规约时通过宿主语言的规则自然地实现此要求,转移子项(@7.2.1.1) 时只需以宿主语言的自动对象作为新建的项。
36693677 而异步规约时,需要另行单独保存函数临时对象和操作数临时对象。这通过使临时对象保存在动作中实现。
3670-排除本机函数(@5.3) ,合并子中的求值都通过 A1::RelayForEval(直接求值)或 A1::RelayForCall(合并子调用)实现,转移子项保存临时对象不晚于 A1::RelayForCall(@7.7.2) 的调用。
3678+排除本机函数(@5.3) ,合并子(@4.5.3.2) 中的求值都通过 A1::RelayForEval(直接求值)或 A1::RelayForCall(合并子调用)实现,转移子项保存临时对象不晚于 A1::RelayForCall(@7.7.2) 的调用。
36713679 宿主语言直接实现的本机函数通常仍使用同步规约以避免转移子项等操作的复杂性;若使用异步规约,也需要保证子项的生存期以满足上述要求。
36723680 实现需自行决定是否使用内部存储保存临时对象以及需要保存临时对象的内部存储的位置。若需支持异步规约,不能使用宿主语言的自动对象。
36733681 一般地,因为 TermTags::Temporary(@6.2.2) 允许原地标记被绑定的临时对象而非引用其它存储(@5.8.5.3) ,不需要对被绑定的操作数临时对象特别处理。
@@ -3850,7 +3858,7 @@
38503858 为支持 TCO 操作上的不同调用,调用的结果需被反馈到 TCO 动作中。
38513859 操作压缩(@7.10.4) 的和在最后一项操作都包含这样的处理调用结果的请求。
38523860 请求包括当前项(@7.10.3.1) 上的以下非幂等操作(@7.10.4.1) :
3853-指定项表示合并子调用的结果而需正规化(@6.7.9) ;
3861+指定项表示合并子(@4.5.3.2) 调用的结果而需正规化(@6.7.9) ;
38543862 指定项表示需被提升的调用结果(@6.6.7) 。
38553863 处理操作结果返回规约结果(@6.7.1) :
38563864 若提升结果,同 NPL::ReduceForLiftedResult(@6.7.12.1) ;
@@ -3952,8 +3960,8 @@
39523960 另见 TCO 实现(@7.11.5) 。
39533961
39543962 @7.11.5 TCO 动作(@7.10.3) 实现和限制:
3955-因为维护资源(@7.10.5) 的需要,规范求值算法(@7.8.2) 不处理 WHNF 以外的操作数且允许宿主类型的调用(@7.6.1.2) 处理 WHNF 的第一项。
3956-当前在 TCO 动作中被分配的临时对象(@5.8.5) 的操作都针对作为 WHNF 的第一项的合并子,其中合并子相等性由 @8.4.5.5 或其它宿主实现提供的 == 操作确定。
3963+因为维护资源(@7.10.5) 的需要,规范求值算法(@7.8.2) 不处理 WHNF(@4.4.3.1) 以外的操作数且允许宿主类型的调用(@7.6.1.2) 处理 WHNF 的第一项。
3964+当前在 TCO 动作中被分配的临时对象(@5.8.5) 的操作都针对作为 WHNF 的第一项的合并子(@4.5.3.2) ,其中合并子相等性由 @8.4.5.5 或其它宿主实现提供的 == 操作确定。
39573965 由 @8.4.5.5 ,捕获不同环境的 vau 合并子不相等;不论是否具有相等的外部表示(@2.3.4) 和来源,其右值不会被直接操作压缩(@7.10.4) 避免多次添加而被 TCO ;若其嵌套调用因为捕获不同的存在引用关系的环境,不支持其它形式的 TCO ;因此,不支持 PTC 。
39583966 注意上述情形在其它语言中因为可达性分析等可能具有实现缺陷也不会释放存储,如 Kernel 程序 ($sequence ($define! f ($lambda (n) ((($vau (x y) e (eval ($sequence x y) e)) n (f n))))) (f 1)) 在 klisp 中实测不支持 PTC 。
39593967 当前 TCO 操作压缩不支持回收非 #ignore 的动态环境。这实际上较 [RnRK] 的保证弱。但 klisp 同样没有很好地支持此特性,如 Kernel 程序 ($sequence ($define! $f ($vau () #ignore (($f)))) ($f)) 在 klisp 中实测不支持 PTC 。
@@ -4001,8 +4009,9 @@
40014009 基于 NPLA1 的语言扩展主要在模块 NPL::NPLA1Forms 中提供;另见 @8.4.13 。
40024010
40034011 @8.1 语法形式支持:
4004-模块 NPL::NPLA1Forms 提供的命名空间 A1::Forms 的 API 专用于实现语法形式对应的功能而不是 NPLA1 的一般机制。
4012+模块 NPL::NPLA1Forms 提供的命名空间 A1::Forms 的 API 专用于实现语法形式对应的功能而不是 NPLA1 的核心语言(@9) 一般机制。
40054013 作为对象语言中可用的语言特性(@2.1.2) ,一部分功能是基本的(primitive) 。其余功能是派生的(derived) ,可在对象语言源代码的形式通过组合这些已有的其它特性实现。
4014+功能以操作(@4.4.3.1) 提供,可作为对象语言中的合并子类型的被绑定对象(@7.6.1.1) 的本机实现(@5.3) 。
40064015 派生操作的功能对 NPLA1 实现并非严格地必要,但适合使用宿主语言实现,被 NPLA1 代码间接地调用。
40074016 因性能等原因,一些基本派生操作在此直接提供 API 。
40084017 这些 API 可能使用重规约(@6.7.1) ,或假定使用默认解释(@7.8) 的合并遍(@7.4.1.2) 等价的实现。
@@ -4015,6 +4024,7 @@
40154024 以上下文处理器调用的操作应满足上下文需要的状态:
40164025 在进入调用前已使用 A1::ReduceCombined 确保存在 TCO 动作(@7.10.3) ,以允许尾上下文(@4.4.3) 求值。
40174026 基本派生操作包括 Forms::First(@8.4.3) 等针对特定类型的操作。关于不同类型的其它综合操作参见 @8.4.9 。
4027+A1::Forms 的公开 API 提供合并子的本机实现时确保调用这些合并子经过遍处理器依赖的检查(@7.6.1.3) 。这可使用如保留操作(@8.2.2) 实现。
40184028 这些 API 不被 A1::Forms 以外的 API 及实现依赖,且符合本节的以下约定。
40194029 除非另行指定,这些形式不是特殊形式(@5.2) ,一般作为按值传递(@4.4.4.5) 的函数(@4.5.2) ;其中的值对象(@6.1.7) 表示引用时,传递引用(@4.4.4.5) ;表示访问的值不被修改时,是否传递引用未指定。
40204030 这些 API 接受的输入被视为正规表示(@6.7.7) ,但用于求值表达式时,依赖 NPLA1 的约定,输出不需要保证规约后的项是正规表示(@6.7.7) ,而通过这些 API 以外的正规化操作(@6.7.9) 保证(参见 @7.4.1.4 )。
@@ -4238,6 +4248,10 @@
42384248 Forms::LetRef
42394249 Forms::LetWithEnvironment
42404250 Forms::LetWithEnvironmentRef
4251+Forms::LetAsterisk
4252+Forms::LetAsteriskRef
4253+Forms::LetRec
4254+Forms::LetRecRef
42414255
42424256 @8.4.10 外部调用:
42434257 Forms 提供以下在对象语言中调用实现环境外部功能的函数:
@@ -4263,7 +4277,6 @@
42634277 对之后的子项构成的序列有序或无序列表求值;
42644278 若存在操作数,有序求值保证最后一项是尾上下文(实现同 @8.4.9 );
42654279 不保证是真合并子(@4.5.3.2) 。
4266-因为不直接公开合并子的实现(如 @8 ),其中不需要有项检查(如 @8.2.2);但可能仍有遍处理器的检查(@7.6.1.3) 。
42674280 在对象语言中的对应接口参见 NPLA1 参考实现环境(@10) 。
42684281 模块 NPL::Dependency 还提供其它一些接口,调用函数 Forms::LoadGroundContext 初始化上下文后继续调用,初始化特定操作的环境:
42694282 函数模板 Forms::GetModuleFor 加载代码作为模块(@1.4.6.4) 以提供特定集合的对象语言实体的定义。
@@ -4289,20 +4302,15 @@
42894302 eval-accl-tail
42904303 eval-accr-accr
42914304 eval-accr-sum
4292-eval-append-list-concat
42934305 eval-booleans
42944306 eval-cond-list
42954307 eval-foldr1-kons
42964308 eval-let-combine-operator
42974309 eval-let-combine-return
4298-eval-let-extract-arguments
4299-eval-let-make-combiner
43004310 eval-let-parent
4311+eval-letrec-bind
43014312 eval-lift-sum
4302-eval-list-concat-cons
4303-eval-list-extract-cons
43044313 eval-map1-appv
4305-eval-map1-cons
43064314 eval-vau-parent
43074315 match-ptree
43084316 match-ptree-recursive
@@ -4323,21 +4331,16 @@
43234331 eval-accl-tail :Forms::AccL 调用取抽象列表余下的元素的函数。
43244332 eval-accr-accr :Forms::AccR 递归调用。
43254333 eval-accr-sum :Forms::AccR 调用取抽象列表部分和的函数。
4326-eval-append-list-concat :Forms::Append(@8.4.9) 列表连接调用。
43274334 eval-combine-return :非 TCO 的规约合并求值(@7.6.4.2) 实现中设置规约合并最后的返回结果。
43284335 eval-foldr1-kons :Forms::FoldR1(@8.4.9) 应用子调用。
43294336 eval-guard :非 TCO 的求值实现重置守卫的附加动作帧(@6.9.6)。
4330-eval-let-combine-operator :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef(@8.4.9) 中合并创建的合并子和初值符构成的操作数。
4331-eval-let-combine-return :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef 中设置最后的返回结果。
4332-eval-let-extract-arguments :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef 中从绑定列表中取形式实际参数。
4333-eval-let-make-combiner :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef 中从绑定列表中创建合并子。
4337+eval-let-combine-operator :Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 、Forms::LetWithEnvironmentRef 、Forms::LetAsterisk 和 Forms::LetAsteriskRef(@8.4.9) 中合并创建的合并子和初值符构成的操作数。
4338+eval-let-combine-return :非 TCO 的 Forms::Let 、Forms::LetRef 、Forms::LetWithEnvironment 、Forms::LetWithEnvironmentRef 、Forms::LetAsterisk 、Forms::LetAsteriskRef 、Forms::LetRec 和 Forms::LetRecRef(@8.4.9) 的实现中设置规约合并最后的返回结果。
43344339 eval-let-parent :Forms::LetWithEnvironment 和 Forms::LetWithEnvironmentRef 中求值过程抽象(@8.4.5) 的父环境的表达式。
4340+eval-letrec-bind :Forms::LetRec 和 Forms::LetRecRef 中的变量绑定。
43354341 eval-lift-result :非 TCO 的求值实现调用 NPL::ReduceForLiftedResult(@6.7.12.1) 提升返回结果。
4336-eval-lift-sum :Forms::AccR、Forms::FoldR1 、 Forms::Map1 、Forms::ListExtractFirst 和 Forms::ListExtractRestFwd(@8.4.9) 公共的部分和提升调用。
4337-eval-list-concat-cons :Forms::ListConcat(@8.4.9) 列表构造调用。
4338-eval-list-extract-cons :Forms::ListExtractFirst 和 Forms::ListExtractRestFwd(@8.4.9) 列表构造调用。
4342+eval-lift-sum :Forms::AccR、Forms::FoldR1 和 Forms::Map1(@8.4.9) 公共的部分和提升调用。
43394343 eval-map1-appv :Forms::Map1(@8.4.9) 应用子调用。
4340-eval-map1-cons :Forms::Map1 列表构造调用。
43414344 eval-sequence-return :非 TCO 的 A1::ReduceOrdered(@7.4.6) 实现中设置规约合并最后的返回结果。
43424345 eval-tail :TCO 动作尾上下文求值(和 klisp 不同,不依赖 GC(@5.6.4) 而在 TCO 动作单独保存资源(@7.10.5.1) )。
43434346 eval-vau-parent :合并子构造时求值过程抽象的父环境的表达式。
@@ -4427,8 +4430,11 @@
44274430 求值 <expression-sequence> 的结果被定义为求值其最后一个子表达式(若存在)的结果,或当不存在子表达式时为未指定值(@7.2.2)。
44284431 <consequent> :同 <expression> ,仅用于 <test> 求值为 #t 时。
44294432 <alternate> :同 <expression> ,仅用于 <test> 求值不为 #t 时。
4430-<definiend> :被绑定项的目标,是包含符号的 DAG(@4.2.4) 表达式。详见 @7.7.3 。
4431-<formals> :形式参数形式,即形式参数树。同 <definiend> 但允许派生实现定义更多检查。
4433+<ptree> :形式参数树(@7.3.3) ,是包含符号或 #ignore 的 DAG(@4.2.4) 表达式。语法要求由上下文无关文法描述:
4434+<ptree> ::= <symbol> | #ignore | () | (<ptree>...)
4435+<definiend> :作为被绑定项的目标的 <ptree> 。
4436+引入绑定时,蕴含按绑定规则(@7.7.3) 附加 <ptree> 以外的绑定匹配(@7.7.3.3) 等语义检查。
4437+<formals> :作为形式参数的 <ptree> 。同 <definiend> 但允许派生实现定义更多检查。
44324438 <clauses> :元素为条件分支的列表,形式为 (<test> <body>)... 。
44334439 <variable> :变量。用于表示被定义的名称。同 <symbol> ,其中的处理与作为非列表的 <formals> 相同。
44344440
@@ -4647,7 +4653,7 @@
46474653 其中,分隔符 , 优先组合。
46484654 对分隔符的处理使用和组合顺序相反的两遍分别对 ; 和 , 遍历替换,实现参见 @8.5 。
46494655 由此引起的其它语法差异参见绑定构造(@9.7.3) 。
4650-为避免可能引入非真合并子(@9.9.5) ,参考实现对分隔符的使用附加限制(@10.9.3) 。
4656+为避免可能引入非真合并子(@9.9.5) ,参考实现对分隔符的使用附加限制(@10.9.4) 。
46514657
46524658 @9.7.1.1 实现风格:
46534659 和 Scheme 不同而和 Kernel 类似,求值通常使用显式的风格(详见 [Shu10] )而不是依赖 quote 的隐式风格;这和不需要括号的语法特性无关。
@@ -5120,7 +5126,7 @@
51205126 特别地,被转发的函数值若需支持 PTC(@9.7.4.1) ,则不能作为操作使用的实际参数,以避免不满足在尾上下文(@4.4.7) 求值的条件。
51215127
51225128 @10.6 常规函数约定:
5123-本节提供作为库特性的函数(@10.3.1) 的默认规则以简化库特性的描述;另见函数实现使用约定(@10.9.1) 。
5129+本节提供作为库特性的函数(@10.3.1) 的默认规则以简化库特性的描述;另见函数实现使用约定(@10.9.3.1) 。
51245130 库的一般派生实现和用户程序的实现也建议参照本节约定。
51255131 除非另行指定,操作以指定名称的变量的形式提供,求值为可参与函数合并(@4.5.3) 的一等实体(但函数合并不一定保证是合式的(@2.5.1) 可求值的表达式)。
51265132 除非另行指定,函数作为表达式,求值为合并子(@4.5.3) ,其函数合并的求值蕴含函数调用(@4.5.3.1) 。
@@ -5349,25 +5355,38 @@
53495355 若使用保留环境引用的操作,如在返回值中保留环境引用的操作(@10.8.2) ,总是保存被依赖的环境以确保相关的环境对象及其中的被绑定对象(@6.8.1) 在间接访问对象时不被销毁;
53505356 不使用引入其它间接值的操作。
53515357
5352-@10.9 实体实现(@2.3.1.2) 约定:
5358+@10.9 参考实现约定:
53535359 本节约定对 NPLA1 参考实现内部有效,不作用在用户程序。
5354-因不预期通过派生实现,当前实现中,基本特性总是通过本机实现(@5.3) 提供。(这不被接口设计(@10.3.2) 严格要求。)
5355-类似 [RnRK] ,派生特性可通过基本特性及派生特性实现。
53565360 除非另行指定,NPLA1 参考实现环境作为公开接口提供的变量在根环境(@10.1) 中绑定。
5361+除非另行指定,以变量绑定的提供接口没有严格的跨版本兼容性保证,但一般可预期在 YSLib 发布版本([Documentation::ProjectRules @@2.2.4.5]) 之间保持向后兼容。
5362+
5363+@10.9.1 接口描述:
5364+除非显式指定,空环境没有父环境(@9.9.3) 。
5365+约定的接口通过绑定在根环境中的名称提供,参见以下各节。
53575366 除非是语义蕴含的操作结果或另行指定,所有作为函数值的操作(@10.3.1) 的结果(@4.4.3.1) 是未指定值(@7.2.2) 。另见函数名称约定(@10.7) 。
53585367 未指定值可等于 #inert(@9.3.1) 或其它值,但满足忽略值时不引起可观察行为(@4.1.3) 的改变(这排除了引入 volatile 类型或非平凡析构的宿主值)。
53595368 若操作(@10.3.1) 在 Kernel 或 klisp 中存在结果为 #inert 的对应的操作,且未指定作为函数值的结果,则返回等于 #inert 的右值。
5360-除非显式指定,空环境没有父环境(@9.9.3) 。
5361-约定的接口通过绑定在根环境中的名称提供,参见以下各节。
5369+操作中隐式分配的和按接口约定转移所有权给操作实现的资源不存在资源泄漏(@5.6.4) 。这包括抛出异常(@9.5.2) 时,操作的实现提供基本异常安全保证(basic exception safety) 。
5370+
5371+@10.9.2 操作符合性:
5372+除非另行指定,以下关于操作实现的行为未指定。
5373+对运行时错误条件(@9.5.3) 的检查及诊断(@9.5) 的顺序;
5374+满足运行时错误条件(@9.5.3) 时,按要求诊断之后的操作内部分配的资源的状态;
5375+变量的绑定(@4.1) 或其它可选地由派生实现定义的可调试实体的引入是否由本机实现(@5.3) 的机制提供;
5376+是否存在不改变操作语义的附加的可被捕获的续延和这些续延的操作数;
5377+操作的实现使用的续延名称(@7.11.6) 。
5378+以上未指定行为允许同一操作的接口约定和实现之间及不同实现之间允许存在引起调用操作时的可观察行为不同的次要差异。
5379+
5380+@10.9.3 实体实现(@2.3.1.2) 约定:
5381+因不预期通过派生实现,当前实现中,基本特性总是通过本机实现(@5.3) 提供。(这不被接口设计(@10.3.2) 严格要求。)
5382+类似 [RnRK] ,派生特性可通过基本特性及派生特性实现。
53625383 这些名称可能是本机实现(@5.3) ,即直接调用 NPLA 或 NPLA1 API(参见 @7 、@7 和 @8 )绑定定义;也可能是非本机的派生的(derive) 实现,即通过在当前的基础上求值特定的对象语言代码引入(其实现最终依赖本机实现)。
5363-变量的绑定(@4.1) 的引入是否由本机实现未指定。
5364-操作的实现使用的续延名称(@7.11.6) 未指定。
53655384 以下的派生操作(@11.4) 应能以派生的方式提供。派生操作是否以派生的形式提供未指定。
5366-派生不依赖隐式求值风格(@9.7.1.1) ,除非语义明确要求避免操作数的求值(如 $deflazy!(@11.4.1) )且对实现可提供必要的简化,应避免依赖 $quote(@11.4.1) ;$quote 自身通过派生实现引入。
5367-除非另行指定,这些名称指称的实体构成的接口没有严格的兼容性保证,但一般可预期在 YSLib 发布版本([Documentation::ProjectRules @@2.2.4.5]) 之间保持向后兼容。
5368-作为 @7.1.2 的扩展,函数的非本机也实现允许假定纯右值(@5.8.1) 的项不包含不被 @7.1.2 约定直接使用的标签。
5369-
5370-@10.9.1 函数实现约定:
5385+派生的操作不依赖隐式求值风格(@9.7.1.1) ,除非语义明确要求避免操作数的求值(如 $deflazy!(@11.4.1) )且对实现可提供必要的简化,应避免依赖 $quote(@11.4.1) ;$quote 自身通过派生实现引入。
5386+与引入绑定不同,实现内部不要求类似的优先使用,在需要明确实现需要符合的要求或减小实现开销时,可使用提供以引用标记字符结尾变体的操作(@10.7.2) 替代其它操作。
5387+作为扩展,操作的非本机实现也允许假定纯右值(@5.8.1) 的项不包含不被项的结构(@7.1.2) 约定直接使用的标签。
5388+
5389+@10.9.3.1 函数约定:
53715390 名称使用 $def 起始的函数用于在当前环境引入绑定。
53725391 需引入绑定时,优先使用核心库(@11.4.3) 中的函数;当使用这些函数并不能简化实现时,使用 $def!(@11.3.7) 。
53735392 除以下例外,优先使用函数名中不带有 % 及 %! 结尾的函数:
@@ -5376,13 +5395,12 @@
53765395 以上的实现方式可减少一部分不安全操作(@10.8) 并明确函数值是否可能只是非引用值。
53775396 如果可能,函数实现使用转移,避免不必要的对象复制。
53785397 强调使用没有 % 或 %! 结尾的函数避免一些可能的误用(@10.7.1.2) 。
5379-与引入绑定不同,实现内部不要求类似的优先使用,在需要明确实现需要符合的要求或减小实现开销时,可使用提供以引用标记字符结尾变体的操作(@10.7.2) 替代其它操作。
5380-
5381-@10.9.2 预定义对象:
5398+
5399+@10.9.3.2 预定义对象:
53825400 除操作外,特定名称的对象以变量的形式在库中初始化,直接提供具有预设目的的可编程特性。
53835401
5384-@10.9.3 操作实现注记:
5385-派生实现不依赖非真合并子(@9.9.5) ,因此以合并子实现操作时,其中不使用分隔符(@9.7.1) ,也不需要实现在初始化(@10.1.1) 时支持中缀变换(@7.5.2) 。
5402+@10.9.4 操作实现注记:
5403+通过派生实现的操作不依赖非真合并子(@9.9.5) ,因此以合并子实现操作时,其中不使用分隔符(@9.7.1) ,也不需要实现在初始化(@10.1.1) 时支持中缀变换(@7.5.2) 。
53865404 但是,不同操作之间的定义可能使用分隔符。因为不需依赖 $sequence(@11.4.1) ,这种实现也更简单。
53875405 除非另行指定,当前实现中,操作引发错误对象(@9.5.2) 以抛出异常实现(@10.6.4) ,涉及具体的异常类型未指定。
53885406
@@ -5550,9 +5568,9 @@
55505568 这类似宿主语言的容器对象一般不能转换为共享容器部分元素的 C++ 对象引用。
55515569
55525570 @11.3 根环境基本特性(@10.2) :
5553-和 [RnRK] 不同,为简化设计,NPLA1 不提供可选(optional) 的合并子,而通过预定义对象(@10.9.2) 的形式提供可选的模块(@12) 。
5571+和 [RnRK] 不同,为简化设计,NPLA1 不提供可选(optional) 的合并子,而通过预定义对象(@10.9.3.2) 的形式提供可选的模块(@12) 。
55545572 根环境基本特性是除了这些模块的以变量绑定形式提供的不要求可派生实现的特性。
5555-根环境基本特性的被绑定对象(@6.8.1) 包括基础环境(@10.1) 提供的预定义对象(@10.9.2) 和在基础上下文(@8.5.2) 的根环境中初始化的基础基本操作(grounded primitive operations) 的实现。
5573+根环境基本特性的被绑定对象(@6.8.1) 包括基础环境(@10.1) 提供的预定义对象(@10.9.3.2) 和在基础上下文(@8.5.2) 的根环境中初始化的基础基本操作(grounded primitive operations) 的实现。
55565574 派生实现可以通过提供不公开不安全操作(@9.4.5) 的根环境,但不符合此处的规格要求(@2.3.1.2) 。
55575575 若派生实现不提供在返回值中保留其它间接值的操作(@11.1.2) ,可以简化部分 @11.3.4 中与之关联的操作的实现。
55585576 部分可选的 Kernel 合并子被直接提供。
@@ -5753,14 +5771,14 @@
57535771 $vau/e% <parent> <formals> <eformal> <body> :同 $vau/e ,但保留引用值。
57545772 wrap <combiner> :包装(@4.5.3.2) 合并子为应用子(@7.6.1.1) 。
57555773 包装应用子可能符合包装数溢出的错误条件(@9.9.5) 。
5756-wrap% <combiner> :同 wrap ,但参数不隐含左值到右值转换,在结果保留引用值。
5774+wrap% <combiner> :同 wrap ,但参数不隐含左值到右值转换,在结果中保留引用值。
57575775 unwrap <applicative> :解包装(@4.5.3.2) 应用子为底层的合并子(@7.6.1.1) 。
57585776 和 Kernel 不同,参数是右值时子对象(@9.8.2) 被复制,由这些合并子创建的操作子当前仍不足以取代内置的一等操作子,因为不支持只能转移而不能复制的对象。传递这些对象作为操作数会引起构造失败的异常。
57595777 左值参数解包装的结果是合并子的子对象引用(@11.2.4) 。
57605778
5761-@11.3.9 错误处理和检查:
5779+@11.3.9 错误处理(@10.6.4) 和检查:
57625780 raise-invalid-syntax-error <string> :引发包含参数指定的字符串内容的语法错误(@9.5.1) 。
5763-实现引发错误对象(@10.9.3) 的异常对象类型具有 public 基类 NPL::InvalidSyntax 。
5781+实现引发错误对象(@10.9.4) 的异常对象类型具有 public 基类 NPL::InvalidSyntax 。
57645782 check-list-reference <object> :检查对象是否是列表引用,若检查通过返回参数,否则引发错误对象(@9.5.1) 。
57655783 实现引发错误对象的异常对象类型是 NPL::ListTypeError(@6.5) 或 NPL::ValueCategoryMismatch(@6.5) 。
57665784
@@ -5783,12 +5801,14 @@
57835801 NPL_Impl_NPLA1_Native_EnvironmentPrimitives
57845802 NPL_Impl_NPLA1_Use_Id_Vau
57855803 NPL_Impl_NPLA1_Use_LockEnvironment
5786-不直接使用本机实现的替代实现仅供参考,可能引入和本机实现不同的未指定行为(如子对象生存期(@9.8.2) 不同),且可能有和核心特性实现相关的限制:
5787-由合并子调用的参数绑定(@8.4.5.3) 引起(@9.5.1) 的静态语法错误(@9.5.1) 可能具有不同的诊断(@9.5) ;
5788-类型检查(@9.5.4.1) 可具有不同的顺序,多次失败的类型检查引起的类型错误可能具有不同的诊断;
5789-使用 TCO 实现 PTC(@9.7.4) ,可能具有不同的支持(@9.7.4.1) 和实现(如 TCO 动作消除(@7.10.9) );
5790-@10.9 约定的关于一般操作实现的一些未指定行为,特别地,包括续延名称(@7.11.6) 的差异。
5791-注意和 [RnRK] 合并子的派生完全省略错误处理而允许不同的诊断不同,NPLA1 中的操作的替代实现的没有被以上例外或操作自身的语义指定的其它行为(如诊断(@9.5) )仍应和本机实现保持一致。
5804+不直接使用本机实现的替代实现仅供参考,可能引入和本机实现不同的未指定行为(如子对象生存期(@9.8.2) 不同),且可能有和核心特性实现相关的限制,包括:
5805+ 以下不同实现可引起不同的诊断:
5806+ 由合并子调用的参数绑定(@8.4.5.3) 引起(@9.5.1) 的静态语法错误(@9.5.1) 。
5807+ 类型检查(@9.5.4.1) 可具有不同的顺序而引起不同的类型错误。
5808+ 使用 TCO 实现 PTC(@9.7.4) ,可能具有不同的支持(@9.7.4.1) 和实现(如 TCO 动作消除(@7.10.9) )。
5809+ 续延名称(@7.11.6) 等其它差异。
5810+其中,影响可观察行为的差异应为操作符合性(@10.9.2) 约定的实例。
5811+注意和 [RnRK] 合并子的派生完全省略错误处理(@10.6.4) 而允许不同的诊断不同,NPLA1 中的操作的替代实现的没有被以上例外或操作自身的语义指定的其它行为(如符合诊断(@9.5) 和接口要求的诊断消息(@2.3.4) 的内容)仍应和本机实现保持一致。
57925812
57935813 @11.4.1 基本派生特性(basic derived feature) :
57945814 引入合并子的操作子对 <body> 的约定同 @11.3.8 。
@@ -5805,7 +5825,7 @@
58055825 $quote <expression> 求值引用操作。结果为返回值转换(@6.4.6.4) 后的未被求值的操作数。
58065826 考虑通常引用操作对符号类型未被求值的左值操作数使用,保留引用值没有意义,因此不提供对应保留引用值的操作。
58075827 这个函数的使用在实现中受限制(@10.9) 。
5808-id <object> :结果为不隐含左值到右值转换的参数,在结果保留引用值。
5828+id <object> :结果为不隐含左值到右值转换的参数,在结果中保留引用值。
58095829 其作用等价返回值转换,可能引起对象转移(@5.8.5.2) 。
58105830 idv <object> :同 id ,但结果为返回值转换(@6.4.6.4) 后的值。
58115831 使用 idv 可指定在返回值中保留引用值的不安全操作(@10.8.1) 的个别操作数不再保留引用值。
@@ -5818,16 +5838,16 @@
58185838 本机实现使用 NPL::MoveRValueToForward(@6.6.7.3) 可简化操作。
58195839 这个函数类似宿主语言以对象类型参数和推断的函数参数类型作为模板参数调用 std::forward ,但若需转移,直接转移而非如 expire(@11.3.2) 返回指定结果是消亡值(@5.8.1) 的唯一引用(@6.2.2) 。
58205840 和宿主语言不同,直接转移允许区分消亡值和纯右值,同等地作为一等对象(如作为列表的元素)。
5821-list% <object>... :同 list ,但每个参数都不隐含左值到右值转换,在结果保留引用值。
5841+list% <object>... :同 list ,但每个参数都不隐含左值到右值转换,在结果中保留引用值。
58225842 rlist <list> :转换参数为引用列表元素的列表。
58235843 若参数是左值,则结果是参数的元素的引用构成的列表;否则,结果同 idv 。
58245844 $deflazy! <definiend> <body> :修改绑定。
58255845 同 $def! ,但不求值参数;在添加绑定前仍对冻结环境进行检查(@11.3.7) 。
5826-$set! <environment> <formals> <body> :修改指定环境的变量绑定。
5846+$set! <environment> <definiend> <body> :修改指定环境的变量绑定。
58275847 在当前环境求值 <environment> 和 <body> ,再以后者的求值结果修改前者的求值结果指定的环境中的绑定。绑定效果同使用 $def!(@11.3.7) 。
5828-类似 Kernel 的 $set! 。注意 <body> 的形式不同。允许的递归操作参见 $def! 。
5848+类似 Kernel 的 $set! ,但明确使用 <definiend> 而不是 <formals> 。注意 <body> 的形式不同。允许的递归操作参见 $def! 。
58295849 和 Kernel 不同而和 NPLA1 的 $def! 等类似,在修改绑定前对冻结环境进行检查。
5830-$setrec! <environment> <formals> <body> :修改指定环境的绑定,绑定效果同使用 $defrec!(@11.3.7) 。
5850+$setrec! <environment> <definiend> <body> :修改指定环境的绑定,绑定效果同使用 $defrec!(@11.3.7) 。
58315851 同 $set! ,但允许不同的递归操作,参见 $defrec! 。
58325852 $lambda <formals> <body> :创建 λ 抽象(@4.5.2.2) 。
58335853 和创建 vau 抽象类似,但创建的是调用时对操作数的元素求值一次的应用子(@7.6.1.1) ,且忽略动态环境。
@@ -5925,11 +5945,11 @@
59255945 指定 accr 的参数为 <list> 、null? 、(forward! <object>) 、first% 、rest% 和 <applicative> ;
59265946 调用应用子 rest% 时不复制 <object> 或其子对象。
59275947 参数指定的应用子的调用不添加或移除列表元素,否则行为未定义。
5928-同 SRFI-1 的 fold-right ,但只接受一个真列表(@9.9.4) 。
5929-名称中的 1 指 <list> 参数的个数。
5948+类似 SRFI-1 的 fold-right ,但只接受一个真列表(@9.9.4) 。
59305949 map1 <applicative> <list> :单列表映射操作:使用指定应用子对列表中每个参数进行调用,结果为调用结果的列表。
59315950 参数 <applicative> 应接受一个参数,否则引起错误。
5932-任意两个 <applicative> 调用的求值及列表构造操作的相对顺序未指定。
5951+操作中的应用子和列表构造的结果的确定满足过程调用的因果性(@4.5.2.1) ;其余任意 <applicative> 调用的求值、列表构造操作和销毁列表中的元素的操作的相对顺序未指定。
5952+foldr1 和 map1 名称中的 1 指 <list> 参数的个数。(更一般的其它形式可接受多个 <list> 。)
59335953 <applicative> 的调用不添加或移除列表元素,否则行为未指定。
59345954 类似 Kernel 的 map ,但只接受一个真列表(@9.9.4) 。
59355955 first-null? <list> :复合 first 和 null? 操作。
@@ -5953,6 +5973,15 @@
59535973 这允许传递引用值并保证环境的宿主值类型(包含所有权)被正确传递作为求值的父环境,而无需支持扩展 <parent> 中的环境为右值时其中的环境临时对象的生存期。
59545974 注意此时 <parent> 中的环境中创建的环境对象在表达式求值后仍会因为 $lambda/e% 引入的合并子生存期结束而被销毁。
59555975 $let/e% <parent> <bindings> <body> :同 $let/e ,但使用 $lambda/e%(@11.4.3) 而不是 $lambda/e 实现,保留引用值。
5976+$let* <bindings> <body> :顺序局部绑定求值。
5977+同 $let ,但 <bindings> 中的被用于绑定的表达式从左到右顺序求值,被用于初始化变量的表达式在求值时可访问 <bindings> 中之前绑定的符号。
5978+类似 Kernel 的同名操作。
5979+$let*% <bindings> <body> :同 $let* ,但保留引用值。
5980+$letrec <bindings> <body> :允许递归引用绑定的顺序局部绑定求值。
5981+类似 Kernel 的同名操作。
5982+和 $let 及 $let* 不同,操作求值 <bindings> 的初值符时保证使用和求值 <body> 时的同一环境作为当前环境,因此可配合 lock-current-environment 传递具有所有权的环境。
5983+$letrec% <bindings> <body> :同 $letrec ,但保留引用值。
5984+注意以上 $let 等函数的 <body> 形式和 Kernel 不同。
59565985 derive-current-environment <environment>... :创建当前环境的派生环境:以参数指定的环境和当前环境为父环境的空环境。
59575986 当前环境以外的父环境顺序同参数顺序。当前环境是最后一个父环境。
59585987 () make-standard-environment :创建标准环境(standard environment) :以基础环境(@10.1) 为父环境的空环境。
@@ -5987,7 +6016,7 @@
59876016 $defl/e! <variable> <parent> <formals> <body> :绑定指定静态环境的 λ 抽象,等价 $def! <variable> $lambda/e <parent> <formals> <body> 。
59886017 $defl/e%! <variable> <parent> <formals> <body> :绑定指定静态环境的 λ 抽象,等价 $def! <variable> $lambda/e% <parent> <formals> <body> 。
59896018 box <object> 装箱:构造箱(类型为 <box> 的对象)。
5990-box% <object> 同 box ,但参数不隐含左值到右值转换,在结果保留引用值。
6019+box% <object> 同 box ,但参数不隐含左值到右值转换,在结果中保留引用值。
59916020 box? <object> 判断是否为 <box> 类型的对象。
59926021 unbox <box> 拆箱:从箱中还原对象。作为传递操作,保留引用值。
59936022 以上 4 个函数除引用标记字符(@10.7) 对应处理引用值的差异外,功能和使用方式对应类似 SRFI-111 的 3 个过程 box 、box? 和 unbox 。
@@ -6001,18 +6030,9 @@
60016030 否则,值为空列表。
60026031 类似 Kernel 的 assoc ,但使用 eqv? 而不是 equal? ,且转发参数。
60036032 和 Scheme 的 assv 类似,但失败的值不返回 #f ,尽管和 Kernel 相同而和 Scheme 不同,<test> 支持非布尔类型的值(@11.3.3) 。
6004-$let* <bindings> <body> :顺序局部绑定求值。
6005-同 $let ,但 <bindings> 中的被用于绑定的表达式从左到右顺序求值,被用于初始化变量的表达式在求值时可访问 <bindings> 中之前绑定的符号。
6006-类似 Kernel 的同名操作。
6007-$let*% <bindings> <body> :同 $let* ,但保留引用值。
6008-$letrec <bindings> <body> :顺序局部绑定求值,允许递归引用绑定。
6009-类似 Kernel 的同名操作。
6010-和 $let 及 $let* 不同,操作保证使用同一环境,因此可配合 lock-current-environment 传递具有所有权的环境。
6011-$letrec% <bindings> <body> :同 $letrec ,但保留引用值。
6012-注意以上 $let 等函数的 <body> 形式和 Kernel 不同。
60136033 $bindings/p->environment (<environment>...) <binding>... :转换绑定列表为以指定的环境列表中的环境为父环境的具有这些绑定的环境。
60146034 类似 Kernel 的 $binding->environment ,但指定父环境,且具有适当的所有权。
6015-使用 make-environment 而不是 $let/e 等绑定构造实现。
6035+使用 make-environment(@11.3.7) 而不是 $let/e(@11.4.1) 等绑定构造实现。
60166036 $as-environment <body> :求值表达式构造环境。
60176037 创建以动态环境为父环境的空环境,并在其中求值参数指定的表达式。
60186038 结果是创建的环境强引用。
@@ -6025,7 +6045,7 @@
60256045 支持转发参数;
60266046 不带有引用标记字符和符号指称的对象不是临时对象(@5.8.5) 的默认情形复制值而不是初始化引用。
60276047 $provide/let! <symbols> <bindings> <body> :在当前环境中提供绑定:蕴含 $let <bindings> <body> ,在求值 <body> 后以结果作为操作数绑定到 <symbols> 的符号。
6028-<symbols> 应能被作为 <defindend> 使用。
6048+<symbols> 应能被作为 <definiend> 使用。
60296049 结果是对这些绑定具有所有权的环境强引用。
60306050 绑定后的符号可通过作为 vau 抽象的父环境(@9.9.3.5) 等形式依赖这个环境,因此用户需适当保存返回值使其生存期(@9.9.3.5) 覆盖在被使用的绑定符号指称的对象生存期。
60316051 $provide! <symbols> <body> :在当前环境中提供绑定:同 $provide/let! 但不指定单独的 <bindings> 。
Show on old repository browser