• R/O
  • SSH

YSLib: Commit

The YSLib project - main repository


Commit MetaInfo

Revision4a903ae70b2e3c8e3022f12f9f9e04981862990c (tree)
Time2021-08-07 18:05:04
AuthorFrankHB <frankhb1989@gmai...>
CommiterFrankHB

Log Message

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

Change Summary

Incremental Difference

diff -r ec368cc4b053 -r 4a903ae70b2e Tools/SHBuild/SHBuild.vcxproj
--- a/Tools/SHBuild/SHBuild.vcxproj Sun Aug 01 06:41:44 2021 +0800
+++ b/Tools/SHBuild/SHBuild.vcxproj Sat Aug 07 17:05:04 2021 +0800
@@ -58,6 +58,7 @@
5858 <ConformanceMode>true</ConformanceMode>
5959 <LanguageStandard>stdcpplatest</LanguageStandard>
6060 <MultiProcessorCompilation>true</MultiProcessorCompilation>
61+ <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions>
6162 </ClCompile>
6263 <Link>
6364 <AdditionalDependencies>$(SolutionDir)build\Win32\YFramework\$(Configuration)\YFramework.lib;$(SolutionDir)build\Win32\YBase\$(Configuration)\YBase.lib;imm32.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -72,6 +73,7 @@
7273 <ConformanceMode>true</ConformanceMode>
7374 <LanguageStandard>stdcpplatest</LanguageStandard>
7475 <MultiProcessorCompilation>true</MultiProcessorCompilation>
76+ <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions>
7577 </ClCompile>
7678 <Link>
7779 <EnableCOMDATFolding>true</EnableCOMDATFolding>
diff -r ec368cc4b053 -r 4a903ae70b2e YBase/YBase.vcxproj
--- a/YBase/YBase.vcxproj Sun Aug 01 06:41:44 2021 +0800
+++ b/YBase/YBase.vcxproj Sat Aug 07 17:05:04 2021 +0800
@@ -160,6 +160,7 @@
160160 <ConformanceMode>true</ConformanceMode>
161161 <LanguageStandard>stdcpplatest</LanguageStandard>
162162 <MultiProcessorCompilation>true</MultiProcessorCompilation>
163+ <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions>
163164 </ClCompile>
164165 </ItemDefinitionGroup>
165166 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release|Win32'">
@@ -172,6 +173,7 @@
172173 <ConformanceMode>true</ConformanceMode>
173174 <LanguageStandard>stdcpplatest</LanguageStandard>
174175 <MultiProcessorCompilation>true</MultiProcessorCompilation>
176+ <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions>
175177 </ClCompile>
176178 </ItemDefinitionGroup>
177179 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff -r ec368cc4b053 -r 4a903ae70b2e YBase/include/ydef.h
--- a/YBase/include/ydef.h Sun Aug 01 06:41:44 2021 +0800
+++ b/YBase/include/ydef.h Sat Aug 07 17:05:04 2021 +0800
@@ -19,13 +19,13 @@
1919 /*! \file ydef.h
2020 \ingroup YBase
2121 \brief 语言实现和系统环境相关特性及公用类型和宏的基础定义。
22-\version r3975
22+\version r3985
2323 \author FrankHB <frankhb1989@gmail.com>
2424 \since 早于 build 132
2525 \par 创建时间:
2626 2009-12-02 21:42:44 +0800
2727 \par 修改时间:
28- 2021-07-07 19:12 +0800
28+ 2021-08-02 02:17 +0800
2929 \par 文本编码:
3030 UTF-8
3131 \par 模块名称:
@@ -432,7 +432,11 @@
432432 \def YPP_Diag_Ignore
433433 \brief 忽略诊断选项。
434434 */
435-#if YB_IMPL_CLANGPP
435+#if YB_IMPL_MSCPP
436+# define YB_Diag_Push _Pragma("warning(push)")
437+# define YB_Diag_Pop _Pragma("warning(pop)")
438+# define YB_Diag_Ignore(_opt) _Pragma(YPP_Stringize(warning(disable: _opt)))
439+#elif YB_IMPL_CLANGPP
436440 # define YB_Diag_Push _Pragma("clang diagnostic push")
437441 # define YB_Diag_Pop _Pragma("clang diagnostic pop")
438442 # define YB_Diag_Ignore(_opt) _Pragma( \
@@ -975,7 +979,11 @@
975979
976980 #if YB_IMPL_MSCPP >= 1200
977981 //! \since build 454
978-# pragma warning(disable: 4646)
982+YB_Diag_Ignore(4646)
983+// NOTE: See https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4646.
984+// NOTE: The warning "function declared with __declspec(noreturn) has non-void
985+// return type" is unwanted since the type of function may be significant even
986+// it does not return.
979987 #endif
980988
981989 /*!
diff -r ec368cc4b053 -r 4a903ae70b2e YBase/include/ystdex/cstdio.h
--- a/YBase/include/ystdex/cstdio.h Sun Aug 01 06:41:44 2021 +0800
+++ b/YBase/include/ystdex/cstdio.h Sat Aug 07 17:05:04 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2011-2016, 2018-2020 FrankHB.
2+ © 2011-2016, 2018-2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file cstdio.h
1212 \ingroup YStandardEx
1313 \brief ISO C 标准输入/输出扩展。
14-\version r728
14+\version r830
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 245
1717 \par 创建时间:
1818 2011-09-21 08:30:08 +0800
1919 \par 修改时间:
20- 2020-11-29 20:23 +0800
20+ 2021-08-01 09:22 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -109,7 +109,7 @@
109109
110110 /*!
111111 \brief ISO C/C++ 标准输入输出接口打开模式转换。
112-\since build 326
112+\since build 923
113113 */
114114 //@{
115115 /*!
@@ -118,18 +118,118 @@
118118 \note 返回值未指定,但返回值指向的内容是确定的,且无副作用,因此可用 YB_STATELESS 。
119119 \see LWG 596 。
120120 */
121-YB_ATTR_nodiscard YB_API YB_STATELESS const char*
122-openmode_conv(std::ios_base::openmode) ynothrow;
121+template<typename _tChar = char>
122+YB_ATTR_nodiscard YB_STATELESS const _tChar*
123+openmode_conv(std::ios_base::openmode mode) ynothrow
124+{
125+ using namespace std;
126+ yconstexpr static const _tChar modes[12][4] = {
127+ {_tChar('w'), _tChar('b'), _tChar()},
128+ {_tChar('w'), _tChar()},
129+ {_tChar('a'), _tChar('b'), _tChar()},
130+ {_tChar('a'), _tChar()},
131+ {_tChar('r'), _tChar('b'), _tChar()},
132+ {_tChar('r'), _tChar()},
133+ {_tChar('w'), _tChar('+'), _tChar('b'), _tChar()},
134+ {_tChar('w'), _tChar('+'), _tChar()},
135+ {_tChar('a'), _tChar('+'), _tChar('b'), _tChar()},
136+ {_tChar('a'), _tChar('+'), _tChar()},
137+ {_tChar('r'), _tChar('+'), _tChar('b'), _tChar()},
138+ {_tChar('r'), _tChar('+'), _tChar()}
139+ };
140+
141+ switch(unsigned((mode &= ~ios_base::ate) & ~ios_base::binary))
142+ {
143+ case ios_base::out:
144+ case ios_base::out | ios_base::trunc:
145+ return mode & ios_base::binary ? modes[0] : modes[1];
146+ case ios_base::out | ios_base::app:
147+ case ios_base::app:
148+ return mode & ios_base::binary ? modes[2] : modes[3];
149+ case ios_base::in:
150+ return mode & ios_base::binary ? modes[4] : modes[5];
151+ case ios_base::in | ios_base::out:
152+ return mode & ios_base::binary ? modes[6] : modes[7];
153+ case ios_base::in | ios_base::out | ios_base::trunc:
154+ return mode & ios_base::binary ? modes[8] : modes[9];
155+ case ios_base::in | ios_base::out | ios_base::app:
156+ case ios_base::in | ios_base::app:
157+ return mode & ios_base::binary ? modes[10] : modes[11];
158+ default:
159+ break;
160+ }
161+ return {};
162+}
123163 /*!
124164 \brief ISO C/C++ 标准输入输出接口打开模式转换。
125165 \return 若失败(包括空参数情形)为 std::ios_base::openmode() ,否则为对应的值。
126166 \see ISO C11 7.21.5.3/3 。
127167 \note 顺序严格限定。
128168 \note 支持 x 转换。
129-\since build 326
130169 */
131-YB_ATTR_nodiscard YB_API YB_PURE std::ios_base::openmode
132-openmode_conv(const char*) ynothrow;
170+template<typename _tChar = char>
171+YB_ATTR_nodiscard YB_PURE std::ios_base::openmode
172+openmode_conv(const _tChar* s) ynothrow
173+{
174+ using namespace std;
175+
176+ if(s)
177+ {
178+ ios_base::openmode mode;
179+
180+ switch(*s)
181+ {
182+ case _tChar('w'):
183+ mode = ios_base::out | ios_base::trunc;
184+ break;
185+ case _tChar('r'):
186+ mode = ios_base::in;
187+ break;
188+ case _tChar('a'):
189+ mode = ios_base::app;
190+ break;
191+ default:
192+ goto invalid;
193+ }
194+ if(s[1] != char())
195+ {
196+ auto l(char_traits<char>::length(s));
197+
198+ if(s[l - 1] == _tChar('x'))
199+ {
200+ if(mode & ios_base::out)
201+ mode &= ~ios_base::out;
202+ else
203+ goto invalid;
204+ --l;
205+ }
206+
207+ bool b(s[1] == 'b'), p(s[1] == '+');
208+
209+ switch(l)
210+ {
211+ case 2:
212+ if(b != p)
213+ break;
214+ goto invalid;
215+ case 3:
216+ yunseq(b = b != (s[2] == _tChar('b')),
217+ p = p != (s[2] == _tChar('+')));
218+ if(b && p)
219+ break;
220+ default:
221+ goto invalid;
222+ }
223+ if(p)
224+ mode |= *s == _tChar('r') ? ios::out : ios::in;
225+ if(b)
226+ mode |= ios::binary;
227+ }
228+ return mode;
229+ }
230+invalid:
231+ return ios_base::openmode();
232+}
133233 //@}
134234
135235
diff -r ec368cc4b053 -r 4a903ae70b2e YBase/include/ystdex/iterator.hpp
--- a/YBase/include/ystdex/iterator.hpp Sun Aug 01 06:41:44 2021 +0800
+++ b/YBase/include/ystdex/iterator.hpp Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file iterator.hpp
1212 \ingroup YStandardEx
1313 \brief 通用迭代器。
14-\version r6148
14+\version r6152
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since 早于 build 189
1717 \par 创建时间:
1818 2011-01-27 23:01:00 +0800
1919 \par 修改时间:
20- 2021-02-06 15:29 +0800
20+ 2021-08-01 12:41 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -166,11 +166,13 @@
166166 = typename std::iterator_traits<iterator_type>::difference_type;
167167 using reference
168168 = cond_t<is_same<_tReference, void>, transformed_type, _tReference>;
169+ //! \since build 923
170+ using value_type = remove_reference_t<reference>;
169171 /*!
170172 \since build 667
171173 \todo 测试 operator-> 并支持代理指针。
172174 */
173- using pointer = remove_reference_t<reference>*;
175+ using pointer = value_type*;
174176 };
175177
176178 } // namespace details;
@@ -217,7 +219,7 @@
217219 //! \since build 667
218220 //@{
219221 using iterator_category = typename impl_traits::iterator_category;
220- using value_type = typename impl_traits::transformed_type;
222+ using value_type = typename impl_traits::value_type;
221223 //@}
222224 //! \since build 439
223225 using transformed_type = typename impl_traits::transformed_type;
diff -r ec368cc4b053 -r 4a903ae70b2e YBase/source/ystdex/cstdio.cpp
--- a/YBase/source/ystdex/cstdio.cpp Sun Aug 01 06:41:44 2021 +0800
+++ b/YBase/source/ystdex/cstdio.cpp Sat Aug 07 17:05:04 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2009-2016, 2018, 2020 FrankHB.
2+ © 2009-2016, 2018, 2020-2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file cstdio.cpp
1212 \ingroup YStandardEx
1313 \brief ISO C 标准输入/输出扩展。
14-\version r253
14+\version r336
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 245
1717 \par 创建时间:
1818 2011-09-21 08:38:51 +0800
1919 \par 修改时间:
20- 2020-11-29 21:00 +0800
20+ 2021-08-01 09:10 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -64,96 +64,6 @@
6464 }
6565
6666
67-const char*
68-openmode_conv(std::ios_base::openmode mode) ynothrow
69-{
70- using namespace std;
71-
72- switch(unsigned((mode &= ~ios_base::ate) & ~ios_base::binary))
73- {
74- case ios_base::out:
75- case ios_base::out | ios_base::trunc:
76- return mode & ios_base::binary ? "wb" : "w";
77- case ios_base::out | ios_base::app:
78- case ios_base::app:
79- return mode & ios_base::binary ? "ab" : "a";
80- case ios_base::in:
81- return mode & ios_base::binary ? "rb" : "r";
82- case ios_base::in | ios_base::out:
83- return mode & ios_base::binary ? "r+b" : "r+";
84- case ios_base::in | ios_base::out | ios_base::trunc:
85- return mode & ios_base::binary ? "w+b" : "w+";
86- case ios_base::in | ios_base::out | ios_base::app:
87- case ios_base::in | ios_base::app:
88- return mode & ios_base::binary ? "a+b" : "a+";
89- default:
90- break;
91- }
92- return {};
93-}
94-std::ios_base::openmode
95-openmode_conv(const char* str) ynothrow
96-{
97- using namespace std;
98-
99- if(str)
100- {
101- ios_base::openmode mode;
102-
103- switch(*str)
104- {
105- case 'w':
106- mode = ios_base::out | ios_base::trunc;
107- break;
108- case 'r':
109- mode = ios_base::in;
110- break;
111- case 'a':
112- mode = ios_base::app;
113- break;
114- default:
115- goto invalid;
116- }
117- if(str[1] != char())
118- {
119- auto l(char_traits<char>::length(str));
120-
121- if(str[l - 1] == 'x')
122- {
123- if(mode & ios_base::out)
124- mode &= ~ios_base::out;
125- else
126- goto invalid;
127- --l;
128- }
129-
130- bool b(str[1] == 'b'), p(str[1] == '+');
131-
132- switch(l)
133- {
134- case 2:
135- if(b != p)
136- break;
137- goto invalid;
138- case 3:
139- yunseq(b = b != (str[2] == 'b'), p = p != (str[2] == '+'));
140- if(b && p)
141- break;
142- default:
143- goto invalid;
144- }
145- if(p)
146- mode |= *str == 'r' ? ios::out : ios::in;
147- if(b)
148- mode |= ios::binary;
149- }
150- return mode;
151- }
152-invalid:
153- return ios_base::openmode();
154-}
155-
156-
15767 ifile_iterator&
15868 ifile_iterator::operator++()
15969 {
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/Win32/include/YCLib/MinGW32.h
--- a/YFramework/Win32/include/YCLib/MinGW32.h Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/Win32/include/YCLib/MinGW32.h Sat Aug 07 17:05:04 2021 +0800
@@ -12,13 +12,13 @@
1212 \ingroup YCLib
1313 \ingroup Win32
1414 \brief YCLib MinGW32 平台公共扩展。
15-\version r2149
15+\version r2179
1616 \author FrankHB <frankhb1989@gmail.com>
1717 \since build 412
1818 \par 创建时间:
1919 2012-06-08 17:57:49 +0800
2020 \par 修改时间:
21- 2021-06-24 21:41 +0800
21+ 2021-08-02 01:28 +0800
2222 \par 文本编码:
2323 UTF-8
2424 \par 模块名称:
@@ -30,7 +30,7 @@
3030 #define YCL_Win32_INC_MinGW32_h_ 1
3131
3232 #include "YCLib/YModules.h"
33-#include YFM_YCLib_Host // for string, ystdex::remove_reference_t, wstring,
33+#include YFM_YCLib_Host // for string, ystdex::remove_pointer_t, wstring,
3434 // unique_ptr_from, ystdex::ends_with, ystdex::aligned_storage_t,
3535 // ystdex::pun_ref, pair;
3636 #include YFM_YCLib_NativeAPI // for ERROR_SUCCESS,
@@ -228,12 +228,18 @@
228228 //@{
229229 //! \brief 加载过程地址得到的过程类型。
230230 using ModuleProc
231-#if YB_IMPL_MSCPP
232- = ystdex::remove_reference_t<decltype(::GetProcAddress(::HMODULE(), {})())>(
233- __stdcall)();
234-#else
235- = ystdex::remove_reference_t<decltype(*::GetProcAddress(::HMODULE(), {}))>;
236-#endif
231+ = ystdex::remove_pointer_t<decltype(::GetProcAddress(::HMODULE(), {}))>;
232+// XXX: Microsoft VC++'s compiler (but not IntelliSense) would not play well on
233+// 'decltype' with an lvalue of function type, as there is an unexpected
234+// function-to-pointer conversion, so
235+// 'decltype(*::GetProcAddress(::HMODULE(), {}))' is actually a function
236+// pointer type, instead of a function reference type in an conforming
237+// implementation. An alternative workaround is
238+// 'decltype(::GetProcAddress(::HMODULE(), {})())(__stdcall)()', requiring the
239+// explicit calling conversion Anyway, handling on the pointer here is simpler.
240+
241+//! \since build 923
242+static_assert(std::is_function<ModuleProc>(), "Invalid type found.");
237243
238244 /*!
239245 \brief 从模块加载指定过程的指针。
@@ -248,6 +254,8 @@
248254 YB_ATTR_nodiscard YB_NONNULL(2) inline _func&
249255 LoadProc(::HMODULE h_module, const char* proc)
250256 {
257+ static_assert(std::is_function<_func>(), "Invalid function type found.");
258+
251259 // NOTE: See https://gcc.gnu.org/gcc-8/changes.html.
252260 #if YB_IMPL_GNUCPP >= 80000
253261 # pragma GCC diagnostic push
@@ -255,7 +263,23 @@
255263 #endif
256264 // NOTE: This should be safe with the additional ABI guarantees, similar to
257265 // https://debarshiray.wordpress.com/2019/04/01/about-wextra-and-wcast-function-type/.
258- return platform::Deref(reinterpret_cast<_func*>(LoadProc(h_module, proc)));
266+ return
267+ // XXX: This should be OK for other implementations, but just keep it for
268+ // the specific buggy implementations.
269+#if YB_IMPL_MSCPP
270+ // XXX: This is required sometimes with %platform::Deref, as the result
271+ // may be a function pointer instead of the function reference. It
272+ // seems a compiler bug in VC++ for the inconsistent behaviors. The
273+ // diagnostic message shows the type of the expression is the type
274+ // the template parameter '_type' in of %platform::Deref, which
275+ // indicates some improper deduction directly performed in the call and
276+ // there is an unexpected function-to-pointer conversion. Such
277+ // conversion seems to be in the unevaluated lvalue operand of
278+ // 'decltype', behaving same to the common implementation of
279+ // %ModuleProc.
280+ *
281+#endif
282+ platform::Deref(reinterpret_cast<_func*>(LoadProc(h_module, proc)));
259283 #if YB_IMPL_GNUCPP >= 80000
260284 # pragma GCC diagnostic pop
261285 #endif
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/YFramework.vcxproj
--- a/YFramework/YFramework.vcxproj Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/YFramework.vcxproj Sat Aug 07 17:05:04 2021 +0800
@@ -516,6 +516,7 @@
516516 <ConformanceMode>true</ConformanceMode>
517517 <LanguageStandard>stdcpplatest</LanguageStandard>
518518 <MultiProcessorCompilation>true</MultiProcessorCompilation>
519+ <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions>
519520 </ClCompile>
520521 </ItemDefinitionGroup>
521522 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release|Win32'">
@@ -528,6 +529,7 @@
528529 <ConformanceMode>true</ConformanceMode>
529530 <LanguageStandard>stdcpplatest</LanguageStandard>
530531 <MultiProcessorCompilation>true</MultiProcessorCompilation>
532+ <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions>
531533 </ClCompile>
532534 </ItemDefinitionGroup>
533535 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/include/NPL/Dependency.h
--- a/YFramework/include/NPL/Dependency.h Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/include/NPL/Dependency.h Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file Dependency.h
1212 \ingroup NPL
1313 \brief 依赖管理。
14-\version r474
14+\version r492
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 623
1717 \par 创建时间:
1818 2015-08-09 22:12:37 +0800
1919 \par 修改时间:
20- 2021-07-21 05:02 +0800
20+ 2021-08-07 05:00 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -205,7 +205,6 @@
205205 //@{
206206 /*!
207207 \brief 加载代理求值模块。
208-\note 当前实现:加载时占用当前环境的实现保留变量 __ 。
209208 \since build 856
210209
211210 加载 promise 等类型和延迟求值等操作。
@@ -231,15 +230,30 @@
231230
232231 /*!
233232 \brief 加载系统模块。
234-\pre 当前实现:求值合并子调用前已加载字符串模块或等价方式初始化为模块 std.strings 。
235233 \sa LoadModule_std_strings
236234
237235 加载系统库操作。
236+当前实现:求值合并子调用前已加载字符串模块或等价方式初始化为模块 std.strings 。
238237 */
239238 YF_API void
240239 LoadModule_std_system(REPLContext&);
241240
242241 /*!
242+\brief 加载模块管理模块。
243+\pre 当前实现:已加载初始化依赖的模块。
244+\since build 923
245+
246+加载模块管理操作。
247+当前实现:已加载初始化以下模块:
248+字符串模块 std.strings ;
249+输入/输出模块 std.io ;
250+代理求值模块 std.promises ;
251+系统模块 std.system 。
252+*/
253+YF_API void
254+LoadModule_std_modules(REPLContext&);
255+
256+/*!
243257 \brief 加载 SHBuild 使用的内部模块。
244258
245259 加载 SHBuild 自举使用的其它公共语法形式。
@@ -253,8 +267,8 @@
253267 /*!
254268 \brief 加载 NPLA1 基础上下文和标准模块。
255269 \sa LoadGroundContext
256-\sa LoadModule_std_environments
257270 \sa LoadModule_std_io
271+\sa LoadModule_std_modules
258272 \sa LoadModule_std_promises
259273 \sa LoadModule_std_strings
260274 \sa LoadModule_std_system
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/include/NPL/NPLA1Forms.h
--- a/YFramework/include/NPL/NPLA1Forms.h Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/include/NPL/NPLA1Forms.h Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Forms.h
1212 \ingroup NPL
1313 \brief NPLA1 语法形式。
14-\version r8231
14+\version r8260
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2020-02-15 11:19:21 +0800
1919 \par 修改时间:
20- 2021-08-01 05:46 +0800
20+ 2021-08-07 12:18 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -920,11 +920,9 @@
920920
921921 /*!
922922 \brief 对指定项以指定的环境求值。
923-\note 支持保存当前动作。
924923 \sa ResolveEnvironment
925924
926-以表达式 \c \<expression> 和环境 \c \<environment> 为指定的参数进行求值。
927-环境以 ContextNode 的引用表示。
925+以视为表达式的对象 \c \<object> 和环境 \c \<environment> 为指定的参数进行求值。
928926 */
929927 //@{
930928 /*!
@@ -933,7 +931,7 @@
933931 按值传递返回值:提升求值后的项。
934932
935933 参考调用文法:
936-<pre>eval \<expression> \<environment></pre>
934+<pre>eval \<object> \<environment></pre>
937935 */
938936 YF_API ReductionStatus
939937 Eval(TermNode&, ContextNode&);
@@ -944,16 +942,13 @@
944942 不提升求值后的项,允许返回引用值。
945943
946944 参考调用文法:
947-<pre>eval% \<expression> \<environment></pre>
945+<pre>eval% \<object> \<environment></pre>
948946 */
949947 YF_API ReductionStatus
950948 EvalRef(TermNode&, ContextNode&);
951949 //@}
952950
953-/*!
954-\since build 835
955-\return ReductionStatus::Retained 。
956-*/
951+//! \since build 835
957952 //@{
958953 /*!
959954 \brief 在参数指定的环境中求值作为外部表示的字符串。
@@ -982,8 +977,8 @@
982977 /*!
983978 \brief 在参数指定的 REPL 环境中规约字符串表示的翻译单元以求值。
984979 \exception LoggedEvent 翻译单元为空串。
980+\return ReductionStatus::Retained 。
985981 \sa Reduce
986-\since build 835
987982
988983 提供创建 REPL 新实例并求值的便利接口。
989984
@@ -994,6 +989,33 @@
994989 EvalUnit(TermNode&);
995990 //@}
996991
992+/*!
993+\brief 在动态环境求值第二参数得到的环境中求值第一参数。
994+\sa ResolveEnvironment
995+\since build 923
996+
997+以表达式 \c \<expression> 和环境 \c \<environment> 为指定的参数进行求值。
998+*/
999+//@{
1000+/*!
1001+按值传递返回值:提升求值后的项。
1002+
1003+参考调用文法:
1004+<pre>$remote-eval \<expression> \<environment></pre>
1005+*/
1006+YF_API ReductionStatus
1007+RemoteEval(TermNode&, ContextNode&);
1008+
1009+/*!
1010+不提升求值后的项,允许返回引用值。
1011+
1012+参考调用文法:
1013+<pre>$remote-eval% \<expression> \<environment></pre>
1014+*/
1015+YF_API ReductionStatus
1016+RemoteEvalRef(TermNode&, ContextNode&);
1017+//@}
1018+
9971019
9981020 /*!
9991021 \brief 创建空环境。
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/include/YCLib/FileIO.h
--- a/YFramework/include/YCLib/FileIO.h Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/include/YCLib/FileIO.h Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file FileIO.h
1212 \ingroup YCLib
1313 \brief 平台相关的文件访问和输入/输出接口。
14-\version r3236
14+\version r3341
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 616
1717 \par 创建时间:
1818 2015-07-14 18:50:35 +0800
1919 \par 修改时间:
20- 2021-08-01 03:27 +0800
20+ 2021-08-05 05:25 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -34,12 +34,12 @@
3434 // ystdex::enable_for_string_class_t, errno, ystdex::throw_error, u16string,
3535 // std::system_error, YTraceDe, array, wstring, string_view;
3636 #include YFM_YCLib_Reference // for unique_ptr_from;
37-#include <ios> // for std::ios_base::sync_with_stdio;
37+#include <ios> // for std::ios_base::sync_with_stdio, std::ios_base::openmode;
3838 #include <fstream> // for std::basic_filebuf, std::filebuf, std::wfilebuf,
3939 // std::basic_ifstream, std::basic_ofstream, std::basic_fstream,
4040 // std::ifstream, std::ofstream, std::fstream, std::wifstream, std::wofstream,
4141 // std::wfstream;
42-#if __GLIBCXX__ || _LIBCPP_VERSION || YB_IMPL_MSCPP
42+#if _LIBCPP_VERSION || __GLIBCXX__ || YB_IMPL_MSCPP
4343 #include <istream> // for std::basic_istream;
4444 #include <ostream> // for std::basic_ostream;
4545 # if __GLIBCXX__
@@ -48,6 +48,7 @@
4848 # elif YB_IMPL_MSCPP
4949 # include <ystdex/cstdio.h> // for ystdex::openmode_conv;
5050 # include <locale> // for std::use_facet, std::codecvt;
51+# include <stdio.h> // for ::_wfdopen;
5152 # endif
5253 #endif
5354 #include <iosfwd> // for std::istream, std::ostream;
@@ -435,22 +436,31 @@
435436
436437
437438 /*!
439+\brief 在 POSIX 文件打开旗标扩展第一参数指定的二进制模式。
440+\return 扩展后的模式。
441+\note POSIX 平台:忽略第一参数。
442+\since build 923
443+*/
444+YB_ATTR_nodiscard YF_API YB_STATELESS int
445+oflag_extend_binary(std::ios_base::openmode, int) ynothrow;
446+
447+/*!
438448 \brief ISO C++ 标准输入输出接口打开模式转换为 POSIX 文件打开模式。
439449 \return 若失败为 0 ,否则为对应的值。
450+\note 忽略二进制模式。
440451 \since build 648
441452 */
442-//@{
443-//! \note 忽略二进制模式。
444453 YB_ATTR_nodiscard YF_API YB_STATELESS int
445454 omode_conv(std::ios_base::openmode) ynothrow;
446455
456+
447457 /*!
448-\note 扩展:不忽略二进制模式。
449-\note POSIX 平台:同 omode_conv 。
458+\ingroup tags
459+\brief 使用 std::ios_base::openmode 的重载标签,保证非整数类型且可默认初始化。
460+\since build 923
450461 */
451-YB_ATTR_nodiscard YF_API YB_STATELESS int
452-omode_convb(std::ios_base::openmode) ynothrow;
453-//@}
462+using use_openmode_t = yimpl(nullptr_t);
463+
454464
455465 /*!
456466 \pre 断言:第一参数非空。
@@ -459,11 +469,12 @@
459469 //@{
460470 /*!
461471 \param filename 文件名,意义同 POSIX \c ::open 。
462-\param oflag 打开旗标,基本语义同 POSIX.1 2004 ,具体行为取决于实现。
463472 \param pmode 打开模式,基本语义同 POSIX.1 2004 ,具体行为取决于实现。
464473 \since build 720
465474 */
466475 //@{
476+//! \param oflag 打开旗标,基本语义同 POSIX.1 2004 ,具体行为取决于实现。
477+//@{
467478 //! \brief 以 UTF-8 文件名无缓冲打开文件。
468479 YB_ATTR_nodiscard YF_API YB_NONNULL(1) int
469480 uopen(const char* filename, int oflag, mode_t pmode = DefaultPMode())
@@ -473,6 +484,26 @@
473484 uopen(const char16_t* filename, int oflag, mode_t pmode = DefaultPMode())
474485 ynothrowv;
475486 //@}
487+/*!
488+\param mode 打开模式,基本语义与 ISO C++11 对应,具体行为取决于实现。
489+\note 第二参数避免重载歧义。
490+\since build 923
491+
492+第三参数首先转换得到打开旗标。若转换失败,则打开文件失败。
493+否则,打开旗标经过以第三参数模式扩展二进制模式,
494+继续同没有 use_openmode_t 参数的 uopen 重载的方式打开文件。
495+*/
496+//@{
497+//! \brief 以 UTF-8 文件名无缓冲打开文件。
498+YB_ATTR_nodiscard YF_API YB_NONNULL(1) int
499+uopen(const char* filename, use_openmode_t, std::ios_base::openmode mode,
500+ mode_t pmode = DefaultPMode()) ynothrowv;
501+//! \brief 以 UCS-2 文件名无缓冲打开文件。
502+YB_ATTR_nodiscard YF_API YB_NONNULL(1) int
503+uopen(const char16_t* filename, use_openmode_t, std::ios_base::openmode mode,
504+ mode_t pmode = DefaultPMode()) ynothrowv;
505+//@}
506+//@}
476507
477508 //! \param filename 文件名,意义同 std::fopen 。
478509 //@{
@@ -550,13 +581,16 @@
550581 \since build 616
551582 */
552583 //@{
553-#if __GLIBCXX__ || _LIBCPP_VERSION || YB_IMPL_MSCPP
584+#if _LIBCPP_VERSION || __GLIBCXX__ || YB_IMPL_MSCPP
554585 /*!
555586 \note 扩展打开模式。
556587 \since build 721
557588 */
558589 //@{
559-# if __GLIBCXX__
590+# if _LIBCPP_VERSION
591+yconstexpr const auto ios_nocreate(yimpl(std::ios::yimpl(trunc << 1)));
592+yconstexpr const auto ios_noreplace(yimpl(std::ios::yimpl(trunc << 2)));
593+# elif __GLIBCXX__
560594 //! \brief 表示仅打开已存在文件而不创建文件的模式。
561595 yconstexpr const auto ios_nocreate(
562596 std::ios_base::openmode(std::_Ios_Openmode::yimpl(_S_trunc << 1)));
@@ -566,9 +600,6 @@
566600 */
567601 yconstexpr const auto ios_noreplace(
568602 std::ios_base::openmode(std::_Ios_Openmode::yimpl(_S_trunc << 2)));
569-# elif _LIBCPP_VERSION
570-yconstexpr const auto ios_nocreate(yimpl(std::ios::trunc << 1));
571-yconstexpr const auto ios_noreplace(yimpl(std::ios::trunc << 2));
572603 # else
573604 yconstexpr const auto ios_nocreate(std::ios::_Nocreate);
574605 yconstexpr const auto ios_noreplace(std::ios::_Noreplace);
@@ -613,14 +644,7 @@
613644 if(p)
614645 {
615646 mode &= ~(ios_nocreate | ios_noreplace);
616-# if __GLIBCXX__
617- this->_M_file.sys_open(*p.get(), mode);
618- if(open_check(mode))
619- {
620- p.release();
621- return this;
622- }
623-# elif _LIBCPP_VERSION
647+# if _LIBCPP_VERSION
624648 # ifdef _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE
625649 // XXX: See https://reviews.llvm.org/rL232049. This configuration shall
626650 // not be used in the YCLib platforms.
@@ -628,16 +652,22 @@
628652 # endif
629653 this->__open(*p.get(), mode);
630654 return this;
655+# elif __GLIBCXX__
656+ this->_M_file.sys_open(*p.get(), mode);
657+ if(open_check(mode))
658+ {
659+ p.release();
660+ return this;
661+ }
631662 # else
632663 if(!this->is_open())
633- if(const auto mode_str = ystdex::openmode_conv(mode))
634- {
635- const auto fp(open_file_ptr(::_fdopen(*p.get(), mode_str)));
664+ {
665+ const auto fp(open_fd(*p.get(), mode));
636666
637- if(fp)
638- p.release();
639- return fp;
640- }
667+ if(fp)
668+ p.release();
669+ return fp;
670+ }
641671 # endif
642672 }
643673 return {};
@@ -648,21 +678,34 @@
648678 {
649679 if(!this->is_open())
650680 {
651-# if __GLIBCXX__
652- const auto smode(mode & ~(ios_nocreate | ios_noreplace));
681+ // XXX: Now %std::_Fiopen is always not used as in Microsoft VC++'s
682+ // <fstream> implementation, for some potential bugs. See
683+ // https://github.com/microsoft/STL/issues/2093.
684+ // NOTE: To handle %ios_nocreate, %::ufopen is not used directly. To
685+ // avoid redendant overhead of the mode conversion to the C file
686+ // mode in the underlying calls, the result of %uopen is checked at
687+ // first.
688+ const int fd(uopen(s, {}, mode));
653689
654- this->_M_file.sys_open(uopen(s, omode_convb(mode)), smode);
655- if(open_check(smode))
656- return this;
657-# elif _LIBCPP_VERSION
658- const auto smode(mode & ~(ios_nocreate | ios_noreplace));
690+ if(fd != -1)
691+ {
692+# if _LIBCPP_VERSION || __GLIBCXX__
693+ const auto smode(mode & ~(ios_nocreate | ios_noreplace));
659694
660- this->__open(uopen(s, omode_convb(mode)), smode);
661- return this;
695+# if _LIBCPP_VERSION
696+ // TODO: Is it worthy to support %_LIBCPP_HAS_OPEN_WITH_WCHAR?
697+ return this->__open(fd, smode);
698+# elif __GLIBCXX__
699+ // XXX: If %smode is invalid, it would fail and to be checked.
700+ this->_M_file.sys_open(fd, smode);
701+ if(open_check(smode))
702+ return this;
703+# endif
662704 # else
663- return open_file_ptr(std::_Fiopen(s, mode,
664- int(std::ios_base::_Openprot)));
705+ // XXX: See the overload above.
706+ return open_fd(fd, mode);
665707 # endif
708+ }
666709 }
667710 return {};
668711 }
@@ -699,8 +742,26 @@
699742 return {};
700743 }
701744 # elif YB_IMPL_MSCPP
745+ //! \since build 923
746+ YB_ATTR_nodiscard basic_filebuf<_tChar, _tTraits>*
747+ open_fd(int fd, std::ios_base::openmode mode)
748+ {
749+ // XXX: Assume Win32 using MSVCRT (with %::_wfdopen) here. Note
750+ // traditional Windows (non-NT) versions without %::_wfdopen are not
751+ // supported.
752+ if(const auto c_mode = ystdex::openmode_conv<wchar_t>(mode))
753+ // XXX: With MSVCRT, %::_fdopen may convert the encoding of the mode
754+ // string internally before the call to %::_wfdopen. This is
755+ // useless since the underlying API does not support mode valid
756+ // mode strings to be encoded differently. Use wide-string
757+ // %ystdex::openmode_conv to directly eliminate the unnecessary
758+ // conversion.
759+ return open_file_ptr(::_wfdopen(fd, c_mode));
760+ return {};
761+ }
762+
702763 //! \since build 837
703- YB_NONNULL(1) basic_filebuf<_tChar, _tTraits>*
764+ YB_ATTR_nodiscard YB_NONNULL(2) basic_filebuf<_tChar, _tTraits>*
704765 open_file_ptr(std::FILE* p_file)
705766 {
706767 // NOTE: %::_Filet and %std::_Filet were aliases of %::FILE in
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/include/YCLib/NativeAPI.h
--- a/YFramework/include/YCLib/NativeAPI.h Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/include/YCLib/NativeAPI.h Sat Aug 07 17:05:04 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2011-2017, 2019 FrankHB.
2+ © 2011-2017, 2019, 2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -10,14 +10,14 @@
1010
1111 /*! \file NativeAPI.h
1212 \ingroup YCLib
13-\brief 通用平台应用程序接口描述。
14-\version r1671
13+\brief 通用平台本机应用程序接口描述。
14+\version r1682
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 202
1717 \par 创建时间:
1818 2011-04-13 20:26:21 +0800
1919 \par 修改时间:
20- 2019-10-25 08:38 +0800
20+ 2021-08-02 02:19 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -616,7 +616,16 @@
616616 # define NOMINMAX 1
617617 # endif
618618
619+#if YB_IMPL_MSCPP >= 1915
620+YB_Diag_Push
621+YB_Diag_Ignore(5105)
622+// NOTE: See https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/c5105.
623+// NOTE: This is only effective for non-conforming WinSDK headers currently.
624+#endif
619625 # include <Windows.h>
626+#if YB_IMPL_MSCPP >= 1915
627+YB_Diag_Pop
628+#endif
620629 // XXX: This may have effects on the system headers included later.
621630 # if false && __has_include(<specstrings_undef.h>)
622631 # include <specstrings_undef.h>
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/include/YSLib/Adaptor/YAdaptor.h
--- a/YFramework/include/YSLib/Adaptor/YAdaptor.h Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/include/YSLib/Adaptor/YAdaptor.h Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file YAdaptor.h
1212 \ingroup Adaptor
1313 \brief 外部库关联。
14-\version r2455
14+\version r2459
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since 早于 build 132
1717 \par 创建时间:
1818 2010-02-22 20:16:21 +0800
1919 \par 修改时间:
20- 2021-05-18 02:18 +0800
20+ 2021-08-03 19:35 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -326,8 +326,11 @@
326326 using platform::FileDescriptor;
327327 using platform::UniqueFile;
328328 using platform::DefaultPMode;
329+//! \since build 923
330+using platform::oflag_extend_binary;
329331 using platform::omode_conv;
330-using platform::omode_convb;
332+//! \since build 923
333+using platform::use_openmode_t;
331334 //! \since build 902
332335 using platform::StreamGet;
333336 //! \since build 901
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/include/YSLib/Service/File.h
--- a/YFramework/include/YSLib/Service/File.h Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/include/YSLib/Service/File.h Sat Aug 07 17:05:04 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2009-2020 FrankHB.
2+ © 2009-2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file File.h
1212 \ingroup Service
1313 \brief 平台中立的文件抽象。
14-\version r1680
14+\version r1694
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 473
1717 \par 创建时间:
1818 2009-11-24 23:14:41 +0800
1919 \par 修改时间:
20- 2020-12-03 20:48 +0800
20+ 2021-08-03 19:35 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -44,12 +44,19 @@
4444 \pre 路径参数非空。
4545 \throw std::system_error 打开失败。
4646 \return 非空的文件指针。
47-\note 当前没有公开打开模式的参数,可能使用平台相关的值或 omode_conv 的结果。
4847 \sa uopen
49-\since build 905
48+\since build 923
5049 */
51-YF_API YB_NONNULL(1) UniqueFile
52-OpenFile(const char*, int, mode_t = DefaultPMode());
50+template<typename... _tParams>
51+YB_NONNULL(1) UniqueFile
52+OpenFile(const char* filename, _tParams&&... args)
53+{
54+ if(UniqueFile p_ifile{uopen(filename, yforward(args)...)})
55+ return p_ifile;
56+ else
57+ ystdex::throw_error(errno, "Failed opening file '"
58+ + std::string(filename) + '\'');
59+}
5360
5461
5562 /*!
@@ -156,7 +163,7 @@
156163 #endif
157164 UniqueLockedOutputFileStream(const _tChar* filename,
158165 std::ios_base::openmode mode, mode_t pmode = DefaultPMode())
159- : UniqueLockedOutputFileStream(omode_convb(mode), filename, mode, pmode)
166+ : UniqueLockedOutputFileStream(uopen(filename, {}, mode, pmode), mode)
160167 {}
161168 //@}
162169
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/source/NPL/Dependency.cpp
--- a/YFramework/source/NPL/Dependency.cpp Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/source/NPL/Dependency.cpp Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file Dependency.cpp
1212 \ingroup NPL
1313 \brief 依赖管理。
14-\version r5281
14+\version r5831
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 623
1717 \par 创建时间:
1818 2015-08-09 22:14:45 +0800
1919 \par 修改时间:
20- 2021-08-01 05:48 +0800
20+ 2021-08-07 16:08 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -41,13 +41,13 @@
4141 // IsBoundLValueTerm, IsUncollapsedTerm, IsUniqueTerm, IsModifiableTerm,
4242 // IsTemporaryTerm, ReferenceTerm, LiftTermRef, NPL::SetContentWith, LiftTerm,
4343 // LiftOtherOrCopy, ystdex::bind1, std::placeholders, LiftTermValueOrCopy,
44-// MoveResolved, ResolveIdentifier, ReduceToReferenceList, NPL::IsMovable,
45-// LiftTermOrCopy, IsBranchedList, AccessFirstSubterm,
44+// MoveResolved, ResolveIdentifier, NPLException, ReduceToReferenceList,
45+// NPL::IsMovable, LiftTermOrCopy, IsBranchedList, AccessFirstSubterm,
4646 // ThrowInsufficientTermsError, NPL::AsTermNode, ystdex::fast_any_of, Ensigil,
47-// YSLib::OwnershipTag, ystdex::plus, ystdex::tolower, YSLib::ufexists,
48-// YSLib::IO::StreamPut, YSLib::FetchEnvironmentVariable,
49-// YSLib::SetEnvironmentVariable, YSLib::IO::UniqueFile,
50-// YSLib::IO::omode_convb, YSLib::uremove, ystdex::throw_error;
47+// YSLib::ufexists, YSLib::to_std_string, ystdex::plus, ystdex::tolower,
48+// YSLib::OwnershipTag, YSLib::IO::StreamPut, YSLib::FetchEnvironmentVariable,
49+// YSLib::SetEnvironmentVariable, YSLib::IO::UniqueFile, YSLib::uremove,
50+// YSLib::allocate_shared, ReduceReturnUnspecified, ystdex::throw_error;
5151 #include YFM_NPL_NPLA1Forms // for NPL::Forms functions;
5252 #include YFM_YSLib_Service_FileSystem // for YSLib::IO::Path,
5353 // YSLib::Deployment::InstallHardLink;
@@ -58,9 +58,10 @@
5858 #include <cerrno> // for errno, ERANGE;
5959 #include <regex> // for std::regex, std::regex_match;
6060 #include <ostream> // for std::endl;
61-#include "NPLA1Internals.h" // for NPL_Impl_NPLA1_Enable_Thunked;
61+#include "NPLA1Internals.h" // for NPL_Impl_NPLA1_Enable_Thunked,
62+// ReduceSubsequent;
6263 #include YFM_YSLib_Core_YCoreUtilities // for YSLib::LockCommandArguments,
63-// YSLib::FetchCommandOutput, YSLib::RandomizeTemplatedString, to_std_string;
64+// YSLib::FetchCommandOutput, YSLib::RandomizeTemplatedString;
6465 #include <ystdex/string.hpp> // for ystdex::begins_with;
6566 #include <ystdex/cstdio.h> // for ystdex::fexists;
6667 #include <cerrno> // for errno, EEXIST, EPERM;
@@ -209,15 +210,28 @@
209210 *OpenUnique(context, string(filename, context.Allocator)));
210211 }
211212
213+//! \since build 923
214+namespace
215+{
216+
217+ReductionStatus
218+ReduceToLoadFile(TermNode& term, ContextNode& ctx, REPLContext& context,
219+ string filename)
220+{
221+ term = context.Load(context, ctx, filename);
222+ // NOTE: This is explicitly not same to klisp. This is also friendly to PTC.
223+ // XXX: Same to %A1::ReduceOnce, without setup the next term.
224+ return ContextState::Access(ctx).ReduceOnce.Handler(term, ctx);
225+}
226+
227+} // unnamed namespace;
228+
212229 ReductionStatus
213230 ReduceToLoadExternal(TermNode& term, ContextNode& ctx, REPLContext& context)
214231 {
215232 Forms::RetainN(term);
216- term = context.Load(context, ctx,
217- NPL::ResolveRegular<string>(NPL::Deref(std::next(term.begin()))));
218- // NOTE: This is explicitly not same to klisp. This is also friendly to PTC.
219- // XXX: Same to %A1::ReduceOnce, without setup the next term.
220- return ContextState::Access(ctx).ReduceOnce.Handler(term, ctx);
233+ return ReduceToLoadFile(term, ctx, context,
234+ NPL::ResolveRegular<const string>(NPL::Deref(std::next(term.begin()))));
221235 }
222236
223237 ReductionStatus
@@ -399,7 +413,8 @@
399413 con.insert(++++i, A1::AsForm(a, op));
400414 // NOTE: There should be one subterm exactly, but the check is still
401415 // required as the derivations, so just deferred it in
402- // %Forms::DefineWithNoRecursion, but not some combiner with %BindSymbol.
416+ // %Forms::DefineWithNoRecursion, but not some combiner with
417+ // %BindSymbol.
403418 // XXX: Assume the implementation of %Forms::DefineWithNoRecursion is
404419 // synchronous.
405420 return Forms::DefineWithNoRecursion(term, ctx);
@@ -760,8 +775,11 @@
760775 return ReduceToReferenceList(term, ctx, tm);
761776 }, term);
762777 });
763- // NOTE: Lazy form '$deflazy!' is the basic operation, which may bind
764- // parameter as unevaluated operands.
778+ RegisterForm(renv, "$remote-eval", RemoteEval);
779+ RegisterForm(renv, "$remote-eval%", RemoteEvalRef);
780+ // NOTE: Conceptionally the lazy form '$deflazy!' is a more basic operation
781+ // than other environment mutation operations, which may bind parameter as
782+ // unevaluated operands.
765783 RegisterForm(renv, "$deflazy!", DefineLazy);
766784 RegisterForm(renv, "$set!", SetWithNoRecursion);
767785 RegisterForm(renv, "$setrec!", SetWithRecursion);
@@ -918,26 +936,24 @@
918936 ThrowInsufficientTermsError(nd, p_ref);
919937 }, x);
920938 });
921-
922939 #else
923940 context.ShareCurrentSource("<root:basic-derived>");
924941 context.Perform(
925942 # if NPL_Impl_NPLA1_Native_EnvironmentPrimitives
926943 R"NPL(
927- $def! $vau $vau/e (() get-current-environment) (&formals &ef .&body) d
928- eval (cons $vau/e (cons d (cons formals (cons ef (move! body))))) d;
929- $def! $vau% $vau (&formals &ef .&body) d
930- eval (cons $vau/e% (cons d (cons formals (cons ef (move! body)))))
931- d;
944+$def! $vau $vau/e (() get-current-environment) (&formals &ef .&body) d
945+ eval (cons $vau/e (cons d (cons formals (cons ef (move! body))))) d;
946+$def! $vau% $vau (&formals &ef .&body) d
947+ eval (cons $vau/e% (cons d (cons formals (cons ef (move! body))))) d;
932948 )NPL"
933949 # else
934950 R"NPL(
935- $def! get-current-environment (wrap ($vau () d d));
936- $def! lock-current-environment (wrap ($vau () d lock-environment d));
951+$def! get-current-environment (wrap ($vau () d d));
952+$def! lock-current-environment (wrap ($vau () d lock-environment d));
937953 )NPL"
938954 # endif
939955 R"NPL(
940- $def! $quote $vau% (x) #ignore $move-resolved! x;
956+$def! $quote $vau% (x) #ignore $move-resolved! x;
941957 )NPL"
942958 // NOTE: The function 'id' does not initialize new objects from the operand.
943959 // XXX: The implementation of 'id' relies on the fact that an object other
@@ -954,9 +970,9 @@
954970 // (first-class referents) from prvalues and all terms can be accessed as
955971 // objects with arbitrary longer lifetime.
956972 R"NPL(
957- $def! id wrap ($vau% (%x) #ignore $move-resolved! x);
958- $def! idv wrap $quote;
959- $def! list wrap ($vau (.x) #ignore move! x);
973+$def! id wrap ($vau% (%x) #ignore $move-resolved! x);
974+$def! idv wrap $quote;
975+$def! list wrap ($vau (.x) #ignore move! x);
960976 )NPL"
961977 # else
962978 );
@@ -964,325 +980,310 @@
964980 RegisterForm(renv, "$lambda%", LambdaRef);
965981 context.ShareCurrentSource("<root:basic-derived-1>");
966982 context.Perform(R"NPL(
967- $def! id $lambda% (%x) $move-resolved! x;
968- $def! idv $lambda% (x) $move-resolved! x;
969- $def! list $lambda (.x) move! x;
970- )NPL"
971-# endif
972- R"NPL(
973- $def! $lvalue-identifier? $vau (&s) d
974- eval (list bound-lvalue? (list $resolve-identifier s)) d;
975- )NPL"
976-# if NPL_Impl_NPLA1_Use_Id_Vau
977- R"NPL(
978- $def! forward! wrap
979- ($vau% (%x) #ignore $if ($lvalue-identifier? x) x (move! x));
980- $def! list% wrap ($vau &x #ignore forward! x);
981- $def! rlist wrap ($vau ((.&x)) #ignore move! x);
982- )NPL"
983-# else
984- R"NPL(
985- $def! forward! $lambda% (%x) $if ($lvalue-identifier? x) x (move! x);
986- $def! list% $lambda &x forward! x;
987- $def! rlist $lambda ((.&x)) move! x;
983+$def! id $lambda% (%x) $move-resolved! x;
984+$def! idv $lambda% (x) $move-resolved! x;
985+$def! list $lambda (.x) move! x;
988986 )NPL"
989987 # endif
990988 R"NPL(
991- $def! $deflazy! $vau (&definiend .&body) d
992- eval (list $def! definiend $quote body) d;
993- $def! $set! $vau (&e &formals .&body) d
994- eval (list $def! formals (unwrap eval%) (move! body) d) (eval e d);
995- $def! $setrec! $vau (&e &formals .&body) d
996- eval (list $defrec! formals (unwrap eval%) (move! body) d)
997- (eval e d);
998- $def! $wvau $vau (&formals &ef .&body) d
999- wrap (eval (cons $vau (cons formals (cons ef (move! body)))) d);
1000- $def! $wvau% $vau (&formals &ef .&body) d
1001- wrap (eval (cons $vau% (cons formals (cons ef (move! body)))) d);
1002- $def! $wvau/e $vau (&e &formals &ef .&body) d
1003- wrap (eval (cons $vau/e
1004- (cons e (cons formals (cons ef (move! body))))) d);
1005- $def! $wvau/e% $vau (&e &formals &ef .&body) d
1006- wrap (eval (cons $vau/e%
1007- (cons e (cons formals (cons ef (move! body))))) d);
989+$def! $lvalue-identifier? $vau (&s) d
990+ eval (list bound-lvalue? (list $resolve-identifier s)) d;
1008991 )NPL"
1009992 # if NPL_Impl_NPLA1_Use_Id_Vau
1010993 R"NPL(
1011- $def! $lambda $vau (&formals .&body) d
1012- wrap (eval (cons $vau (cons formals (cons ignore (move! body)))) d);
1013- $def! $lambda% $vau (&formals .&body) d
1014- wrap
1015- (eval (cons $vau% (cons formals (cons ignore (move! body)))) d);
994+$def! forward! wrap
995+ ($vau% (%x) #ignore $if ($lvalue-identifier? x) x (move! x));
996+$def! list% wrap ($vau &x #ignore forward! x);
997+$def! rlist wrap ($vau ((.&x)) #ignore move! x);
998+ )NPL"
999+# else
1000+ R"NPL(
1001+$def! forward! $lambda% (%x) $if ($lvalue-identifier? x) x (move! x);
1002+$def! list% $lambda &x forward! x;
1003+$def! rlist $lambda ((.&x)) move! x;
1004+ )NPL"
1005+# endif
1006+ R"NPL(
1007+$def! $remote-eval $vau (&o &e) d eval o (eval e d);
1008+$def! $remote-eval% $vau% (&o &e) d eval% o (eval e d);
1009+$def! $deflazy! $vau (&definiend .&body) d
1010+ eval (list $def! definiend $quote body) d;
1011+$def! $set! $vau (&e &formals .&body) d
1012+ eval (list $def! formals (unwrap eval%) (move! body) d) (eval e d);
1013+$def! $setrec! $vau (&e &formals .&body) d
1014+ eval (list $defrec! formals (unwrap eval%) (move! body) d) (eval e d);
1015+$def! $wvau $vau (&formals &ef .&body) d
1016+ wrap (eval (cons $vau (cons formals (cons ef (move! body)))) d);
1017+$def! $wvau% $vau (&formals &ef .&body) d
1018+ wrap (eval (cons $vau% (cons formals (cons ef (move! body)))) d);
1019+$def! $wvau/e $vau (&e &formals &ef .&body) d
1020+ wrap (eval (cons $vau/e (cons e (cons formals (cons ef (move! body))))) d);
1021+$def! $wvau/e% $vau (&e &formals &ef .&body) d
1022+ wrap (eval (cons $vau/e% (cons e (cons formals (cons ef (move! body))))) d);
1023+ )NPL"
1024+# if NPL_Impl_NPLA1_Use_Id_Vau
1025+ R"NPL(
1026+$def! $lambda $vau (&formals .&body) d
1027+ wrap (eval (cons $vau (cons formals (cons ignore (move! body)))) d);
1028+$def! $lambda% $vau (&formals .&body) d
1029+ wrap (eval (cons $vau% (cons formals (cons ignore (move! body)))) d);
10161030 )NPL"
10171031 # endif
10181032 // NOTE: Use of 'eqv?' is more efficient than '$if'.
10191033 R"NPL(
1020- $def! $lambda/e $vau (&e &formals .&body) d
1021- wrap (eval (cons $vau/e
1022- (cons e (cons formals (cons ignore (move! body))))) d);
1023- $def! $lambda/e% $vau (&e &formals .&body) d
1024- wrap (eval (cons $vau/e%
1025- (cons e (cons formals (cons ignore (move! body))))) d);
1026- $def! $sequence
1027- ($lambda (&se)
1028- ($lambda #ignore $vau/e% se &exprseq d
1029- $if (null? exprseq) #inert
1030- (eval% (cons% $aux (move! exprseq)) d))
1031- ($set! se $aux
1032- $vau/e% (weaken-environment se) (&head .&tail) d
1033- $if (null? tail) (eval% (forward! head) d)
1034- (($vau% (&t) e ($lambda% #ignore eval% t e)
1035- (eval% (forward! head) d))
1036- (eval% (cons% $aux (move! tail)) d))))
1037- (make-environment (() get-current-environment));
1038- $def! collapse $lambda% (%x)
1039- $if (uncollapsed? ($resolve-identifier x)) (idv x) x;
1040- $def! forward $lambda% (%x) $if ($lvalue-identifier? x) x (idv x);
1041- $def! assign! $lambda (&x &y) assign@! (forward! x) (idv (collapse y));
1042- $def! assign%!
1043- $lambda (&x &y) assign@! (forward! x) (forward! (collapse y));
1044- $def! apply $lambda% (&appv &arg .&opt)
1045- eval% (cons% () (cons% (unwrap (forward! appv)) (forward! arg)))
1046- ($if (null? opt) (() make-environment)
1047- (($lambda ((&e .&eopt))
1048- $if (null? eopt) e
1049- (raise-invalid-syntax-error
1050- "Syntax error in applying form.")) opt));
1051- $def! list* $lambda (&head .&tail)
1052- $if (null? tail) (forward! head)
1053- (cons (forward! head) (apply list* (move! tail)));
1054- $def! list*% $lambda (&head .&tail)
1055- $if (null? tail) (forward! head)
1056- (cons% (forward! head) (apply list*% (move! tail)));
1057- $def! $defv! $vau (&$f &formals &ef .&body) d
1058- eval (list* $def! $f $vau formals ef (move! body)) d;
1059- $defv! $defv%! (&$f &formals &ef .&body) d
1060- eval (list* $def! $f $vau% formals ef (move! body)) d;
1061- $defv! $defv/e! (&$f &e &formals &ef .&body) d
1062- eval (list* $def! $f $vau/e e formals ef (move! body)) d;
1063- $defv! $defv/e%! (&$f &e &formals &ef .&body) d
1064- eval (list* $def! $f $vau/e% e formals ef (move! body)) d;
1065- $defv! $defw! (&f &formals &ef .&body) d
1066- eval (list* $def! f $wvau formals ef (move! body)) d;
1067- $defv! $defw%! (&f &formals &ef .&body) d
1068- eval (list* $def! f $wvau% formals ef (move! body)) d;
1069- $defv! $defw/e! (&f &e &formals &ef .&body) d
1070- eval (list* $def! f $wvau/e e formals ef (move! body)) d;
1071- $defv! $defw/e%! (&f &e &formals &ef .&body) d
1072- eval (list* $def! f $wvau/e% e formals ef (move! body)) d;
1073- $defv! $defl! (&f &formals .&body) d
1074- eval (list* $def! f $lambda formals (move! body)) d;
1075- $defv! $defl%! (&f &formals .&body) d
1076- eval (list* $def! f $lambda% formals (move! body)) d;
1077- $defv! $defl/e! (&f &e &formals .&body) d
1078- eval (list* $def! f $lambda/e e formals (move! body)) d;
1079- $defv! $defl/e%! (&f &e &formals .&body) d
1080- eval (list* $def! f $lambda/e% e formals (move! body)) d;
1081- $defw%! forward-first% (&appv (&x .)) d
1082- apply (forward! appv) (list% ($move-resolved! x)) d;
1083- $defl%! first (%l)
1084- ($lambda% (fwd) forward-first% forward! (fwd l))
1085- ($if ($lvalue-identifier? l) id expire);
1086- $defl%! first@ (&l)
1087- ($lambda% ((@x .)) x) (check-list-reference (forward! l));
1088- $defl%! first% (%l)
1089- ($lambda (fwd (@x .)) fwd x)
1090- ($if ($lvalue-identifier? l) id expire) l;
1091- $defl%! first& (&l)
1092- ($lambda% ((&x .)) x) (check-list-reference (forward! l));
1093- $defl! firstv ((&x .)) x;
1094- $defl! rest% ((#ignore .%xs)) move! xs;
1095- $defl%! rest& (&l)
1096- ($lambda% ((#ignore .&xs)) xs) (check-list-reference (forward! l));
1097- $defl! restv ((#ignore .xs)) move! xs;
1098- $defl! set-first! (&l x) assign@! (first@ (forward! l)) (move! x);
1099- $defl! set-first@! (&l &x) assign@! (first@ (forward! l)) (forward! x);
1100- $defl! set-first%! (&l &x) assign%! (first@ (forward! l)) (forward! x);
1101- $defl! equal? (&x &y)
1102- $if ($if (branch? x) (branch? y) #f)
1103- ($if (equal? (first& x) (first& y))
1104- (equal? (rest& x) (rest& y)) #f) (eqv? x y);
1105- $defl%! check-environment (&e)
1106- $sequence (eval% #ignore e) (forward! e);
1107- $defl%! check-parent (&e)
1108- $sequence ($vau/e% e . #ignore) (forward! e);
1109- $defv%! $cond &clauses d
1110- $if (null? clauses) #inert
1111- (apply ($lambda% ((&test .&body) .&clauses)
1112- $if (eval test d) (eval% (move! body) d)
1113- (apply (wrap $cond) (move! clauses) d))
1114- (move! clauses));
1115- $defv%! $when (&test .&exprseq) d
1116- $if (eval test d) (eval% (list* () $sequence (move! exprseq)) d);
1117- $defv%! $unless (&test .&exprseq) d
1118- $if (eval test d) #inert
1119- (eval% (list* () $sequence (move! exprseq)) d);
1120- $defl! not? (&x) eqv? x #f;
1121- $defv%! $and? &x d
1122- $cond
1123- ((null? x) #t)
1124- ((null? (rest& x)) eval% (first (forward! x)) d)
1125- ((eval% (first& x) d) apply (wrap $and?) (rest% (forward! x)) d)
1126- (#t #f);
1127- $defv%! $or? &x d
1128- $cond
1129- ((null? x) #f)
1130- ((null? (rest& x)) eval% (first (forward! x)) d)
1131- (#t ($lambda% (&r) $if r (forward! r) (apply (wrap $or?)
1132- (rest% (forward! x)) d)) (eval% (move! (first& x)) d));
1133- $defw%! accl (&l &pred? &base &head &tail &sum) d
1134- $if (apply pred? (list% l) d) (forward! base)
1135- (apply accl (list% (apply tail (list% l) d) pred?
1136- (apply sum (list% (apply head (list% l) d)
1137- (forward! base)) d) head tail sum) d);
1138- $defw%! accr (&l &pred? &base &head &tail &sum) d
1139- $if (apply pred? (list% l) d) (forward! base)
1140- (apply sum (list% (apply head (list% l) d)
1141- (apply accr (list% (apply tail (list% l) d)
1142- pred? (forward! base) head tail sum) d)) d);
1143- $defw%! foldr1 (&kons &knil &l) d
1144- apply accr (list% (($lambda ((.@xs)) xs) l) null? (forward! knil)
1145- ($if ($lvalue-identifier? l) ($lambda (&l) first% l)
1146- ($lambda (&l) expire (first% l))) rest% kons) d;
1147- $defw%! map1 (&appv &l) d
1148- foldr1 ($lambda (%x &xs) cons%
1149- (apply appv (list% ($move-resolved! x)) d) (move! xs)) ()
1150- (forward! l);
1151- $defl! first-null? (&l) null? (first l);
1152- $defl%! rulist (&l)
1153- $if ($lvalue-identifier? l)
1154- (accr (($lambda ((.@xs)) xs) l) null? ()
1155- ($lambda% (%l) $sequence ($def! %x idv (first@ l))
1156- (($if (uncollapsed? x) idv expire) (expire x))) rest%
1157- ($lambda (%x &xs)
1158- (cons% ($resolve-identifier x) (move! xs))))
1159- (idv (forward! l));
1160- $defl! list-concat (&x &y) foldr1 cons% (forward! y) (forward! x);
1161- $defl! append (.&ls) foldr1 list-concat () (move! ls);
1162- $defl%! list-extract-first (&l) map1 first l;
1163- $defl%! list-extract-rest% (&l) map1 rest% l;
1164- $defl! list-push-front! (&l &x) $if (modifiable? l)
1165- (assign! l (cons% (forward! x)
1166- (($lambda ((.l)) (move! l)) (forward! l))))
1167- (raise-type-error "Modifiable object expected.");
1168- $def! ($let $let% $let/e $let/e% $let* $let*% $letrec $letrec%)
1169- ($lambda (&ce)
1170- (
1171- $def! mods () ($lambda/e ce ()
1172- (
1173- $defv%! $lqual (&ls) d
1174- ($if (eval (list $lvalue-identifier? ls) d) as-const rulist)
1175- (eval% ls d);
1176- $defv%! $lqual* (&x) d
1177- ($if (eval (list $lvalue-identifier? x) d) as-const expire)
1178- (eval% x d);
1179- $defl%! mk-let ($ctor &bindings &body)
1180- list* () (list* $ctor (list-extract-first bindings)
1181- (list (move! body))) (list-extract-rest% bindings);
1182- $defl%! mk-let/e ($ctor &e &bindings &body)
1183- list* () (list* $ctor e (list-extract-first bindings)
1184- (list (move! body))) (list-extract-rest% bindings);
1185- $defl%! mk-let* ($let $let* &bindings &body)
1186- $if (null? bindings) (list* $let () (move! body))
1187- (list $let (list (first% ($lqual* bindings)))
1188- (list* $let* (rest% ($lqual* bindings)) (move! body)));
1189- $defl%! mk-letrec ($let &bindings &body)
1190- list $let () $sequence (list $def! (list-extract-first
1191- bindings) (list* () list (list-extract-rest% bindings)))
1192- (move! body);
1193- () lock-current-environment
1194- ));
1195- $defv/e%! $let mods (&bindings .&body) d
1196- eval% (mk-let $lambda ($lqual bindings) (move! body)) d;
1197- $defv/e%! $let% mods (&bindings .&body) d
1198- eval% (mk-let $lambda% ($lqual bindings) (move! body)) d;
1199- $defv/e%! $let/e mods (&e &bindings .&body) d
1200- eval% (mk-let/e $lambda/e e ($lqual bindings) (move! body)) d;
1201- $defv/e%! $let/e% mods (&e &bindings .&body) d
1202- eval% (mk-let/e $lambda/e% e ($lqual bindings) (move! body)) d;
1203- $defv/e%! $let* mods (&bindings .&body) d
1204- eval% (mk-let* $let $let* ($lqual* bindings) (move! body)) d;
1205- $defv/e%! $let*% mods (&bindings .&body) d
1206- eval% (mk-let* $let% $let*% ($lqual* bindings) (move! body)) d;
1207- $defv/e%! $letrec mods (&bindings .&body) d
1208- eval% (mk-letrec $let ($lqual bindings) (move! body)) d;
1209- $defv/e%! $letrec% mods (&bindings .&body) d
1210- eval% (mk-letrec $let% ($lqual bindings) (move! body)) d;
1211- map1 move!
1212- (list% $let $let% $let/e $let/e% $let* $let*% $letrec $letrec%)
1213- )) (() get-current-environment);
1214- $defw! derive-current-environment (.&envs) d
1215- apply make-environment (append envs (list d)) d;
1034+$def! $lambda/e $vau (&e &formals .&body) d
1035+ wrap (eval
1036+ (cons $vau/e (cons e (cons formals (cons ignore (move! body))))) d);
1037+$def! $lambda/e% $vau (&e &formals .&body) d
1038+ wrap (eval
1039+ (cons $vau/e% (cons e (cons formals (cons ignore (move! body))))) d);
1040+$def! $sequence
1041+ ($lambda (&se)
1042+ ($lambda #ignore $vau/e% se &exprseq d
1043+ $if (null? exprseq) #inert (eval% (cons% $aux (move! exprseq)) d))
1044+ ($set! se $aux
1045+ $vau/e% (weaken-environment se) (&head .&tail) d
1046+ $if (null? tail) (eval% (forward! head) d)
1047+ (($vau% (&t) e ($lambda% #ignore eval% t e)
1048+ (eval% (forward! head) d))
1049+ (eval% (cons% $aux (move! tail)) d))))
1050+ (make-environment (() get-current-environment));
1051+$def! collapse $lambda% (%x)
1052+ $if (uncollapsed? ($resolve-identifier x)) (idv x) x;
1053+$def! forward $lambda% (%x) $if ($lvalue-identifier? x) x (idv x);
1054+$def! assign! $lambda (&x &y) assign@! (forward! x) (idv (collapse y));
1055+$def! assign%! $lambda (&x &y) assign@! (forward! x) (forward! (collapse y));
1056+$def! apply $lambda% (&appv &arg .&opt)
1057+ eval% (cons% () (cons% (unwrap (forward! appv)) (forward! arg)))
1058+ ($if (null? opt) (() make-environment)
1059+ (($lambda ((&e .&eopt))
1060+ $if (null? eopt) e
1061+ (raise-invalid-syntax-error
1062+ "Syntax error in applying form.")) opt));
1063+$def! list* $lambda (&head .&tail)
1064+ $if (null? tail) (forward! head)
1065+ (cons (forward! head) (apply list* (move! tail)));
1066+$def! list*% $lambda (&head .&tail)
1067+ $if (null? tail) (forward! head)
1068+ (cons% (forward! head) (apply list*% (move! tail)));
1069+$def! $defv! $vau (&$f &formals &ef .&body) d
1070+ eval (list* $def! $f $vau formals ef (move! body)) d;
1071+$defv! $defv%! (&$f &formals &ef .&body) d
1072+ eval (list* $def! $f $vau% formals ef (move! body)) d;
1073+$defv! $defv/e! (&$f &e &formals &ef .&body) d
1074+ eval (list* $def! $f $vau/e e formals ef (move! body)) d;
1075+$defv! $defv/e%! (&$f &e &formals &ef .&body) d
1076+ eval (list* $def! $f $vau/e% e formals ef (move! body)) d;
1077+$defv! $defw! (&f &formals &ef .&body) d
1078+ eval (list* $def! f $wvau formals ef (move! body)) d;
1079+$defv! $defw%! (&f &formals &ef .&body) d
1080+ eval (list* $def! f $wvau% formals ef (move! body)) d;
1081+$defv! $defw/e! (&f &e &formals &ef .&body) d
1082+ eval (list* $def! f $wvau/e e formals ef (move! body)) d;
1083+$defv! $defw/e%! (&f &e &formals &ef .&body) d
1084+ eval (list* $def! f $wvau/e% e formals ef (move! body)) d;
1085+$defv! $defl! (&f &formals .&body) d
1086+ eval (list* $def! f $lambda formals (move! body)) d;
1087+$defv! $defl%! (&f &formals .&body) d
1088+ eval (list* $def! f $lambda% formals (move! body)) d;
1089+$defv! $defl/e! (&f &e &formals .&body) d
1090+ eval (list* $def! f $lambda/e e formals (move! body)) d;
1091+$defv! $defl/e%! (&f &e &formals .&body) d
1092+ eval (list* $def! f $lambda/e% e formals (move! body)) d;
1093+$defw%! forward-first% (&appv (&x .)) d
1094+ apply (forward! appv) (list% ($move-resolved! x)) d;
1095+$defl%! first (%l)
1096+ ($lambda% (fwd) forward-first% forward! (fwd l))
1097+ ($if ($lvalue-identifier? l) id expire);
1098+$defl%! first@ (&l) ($lambda% ((@x .)) x) (check-list-reference (forward! l));
1099+$defl%! first% (%l)
1100+ ($lambda (fwd (@x .)) fwd x) ($if ($lvalue-identifier? l) id expire) l;
1101+$defl%! first& (&l)
1102+ ($lambda% ((&x .)) x) (check-list-reference (forward! l));
1103+$defl! firstv ((&x .)) x;
1104+$defl! rest% ((#ignore .%xs)) move! xs;
1105+$defl%! rest& (&l)
1106+ ($lambda% ((#ignore .&xs)) xs) (check-list-reference (forward! l));
1107+$defl! restv ((#ignore .xs)) move! xs;
1108+$defl! set-first! (&l x) assign@! (first@ (forward! l)) (move! x);
1109+$defl! set-first@! (&l &x) assign@! (first@ (forward! l)) (forward! x);
1110+$defl! set-first%! (&l &x) assign%! (first@ (forward! l)) (forward! x);
1111+$defl! equal? (&x &y)
1112+ $if ($if (branch? x) (branch? y) #f)
1113+ ($if (equal? (first& x) (first& y))
1114+ (equal? (rest& x) (rest& y)) #f) (eqv? x y);
1115+$defl%! check-environment (&e) $sequence (eval% #ignore e) (forward! e);
1116+$defl%! check-parent (&e) $sequence ($vau/e% e . #ignore) (forward! e);
1117+$defv%! $cond &clauses d
1118+ $if (null? clauses) #inert
1119+ (apply ($lambda% ((&test .&body) .&clauses)
1120+ $if (eval test d) (eval% (move! body) d)
1121+ (apply (wrap $cond) (move! clauses) d))
1122+ (move! clauses));
1123+$defv%! $when (&test .&exprseq) d
1124+ $if (eval test d) (eval% (list* () $sequence (move! exprseq)) d);
1125+$defv%! $unless (&test .&exprseq) d
1126+ $if (eval test d) #inert
1127+ (eval% (list* () $sequence (move! exprseq)) d);
1128+$defl! not? (&x) eqv? x #f;
1129+$defv%! $and? &x d
1130+ $cond
1131+ ((null? x) #t)
1132+ ((null? (rest& x)) eval% (first (forward! x)) d)
1133+ ((eval% (first& x) d) apply (wrap $and?) (rest% (forward! x)) d)
1134+ (#t #f);
1135+$defv%! $or? &x d
1136+ $cond
1137+ ((null? x) #f)
1138+ ((null? (rest& x)) eval% (first (forward! x)) d)
1139+ (#t ($lambda% (&r) $if r (forward! r) (apply (wrap $or?)
1140+ (rest% (forward! x)) d)) (eval% (move! (first& x)) d));
1141+$defw%! accl (&l &pred? &base &head &tail &sum) d
1142+ $if (apply pred? (list% l) d) (forward! base)
1143+ (apply accl (list% (apply tail (list% l) d) pred?
1144+ (apply sum (list% (apply head (list% l) d)
1145+ (forward! base)) d) head tail sum) d);
1146+$defw%! accr (&l &pred? &base &head &tail &sum) d
1147+ $if (apply pred? (list% l) d) (forward! base)
1148+ (apply sum (list% (apply head (list% l) d)
1149+ (apply accr (list% (apply tail (list% l) d)
1150+ pred? (forward! base) head tail sum) d)) d);
1151+$defw%! foldr1 (&kons &knil &l) d
1152+ apply accr (list% (($lambda ((.@xs)) xs) l) null? (forward! knil)
1153+ ($if ($lvalue-identifier? l) ($lambda (&l) first% l)
1154+ ($lambda (&l) expire (first% l))) rest% kons) d;
1155+$defw%! map1 (&appv &l) d
1156+ foldr1 ($lambda (%x &xs) cons%
1157+ (apply appv (list% ($move-resolved! x)) d) (move! xs)) () (forward! l);
1158+$defl! first-null? (&l) null? (first l);
1159+$defl%! rulist (&l)
1160+ $if ($lvalue-identifier? l)
1161+ (accr (($lambda ((.@xs)) xs) l) null? ()
1162+ ($lambda% (%l) $sequence ($def! %x idv (first@ l))
1163+ (($if (uncollapsed? x) idv expire) (expire x))) rest%
1164+ ($lambda (%x &xs) (cons% ($resolve-identifier x) (move! xs))))
1165+ (idv (forward! l));
1166+$defl! list-concat (&x &y) foldr1 cons% (forward! y) (forward! x);
1167+$defl! append (.&ls) foldr1 list-concat () (move! ls);
1168+$defl%! list-extract-first (&l) map1 first l;
1169+$defl%! list-extract-rest% (&l) map1 rest% l;
1170+$defl! list-push-front! (&l &x) $if (modifiable? l)
1171+ (assign! l (cons% (forward! x)
1172+ (($lambda ((.l)) (move! l)) (forward! l))))
1173+ (raise-type-error "Modifiable object expected.");
1174+$def! ($let $let% $let/e $let/e% $let* $let*% $letrec $letrec%) ($lambda (&ce)
1175+(
1176+ $def! mods () ($lambda/e ce ()
1177+ (
1178+ $defv%! $lqual (&ls) d
1179+ ($if (eval (list $lvalue-identifier? ls) d) as-const rulist)
1180+ (eval% ls d);
1181+ $defv%! $lqual* (&x) d
1182+ ($if (eval (list $lvalue-identifier? x) d) as-const expire)
1183+ (eval% x d);
1184+ $defl%! mk-let ($ctor &bindings &body)
1185+ list* () (list* $ctor (list-extract-first bindings)
1186+ (list (move! body))) (list-extract-rest% bindings);
1187+ $defl%! mk-let/e ($ctor &e &bindings &body)
1188+ list* () (list* $ctor e (list-extract-first bindings)
1189+ (list (move! body))) (list-extract-rest% bindings);
1190+ $defl%! mk-let* ($let $let* &bindings &body)
1191+ $if (null? bindings) (list* $let () (move! body))
1192+ (list $let (list (first% ($lqual* bindings)))
1193+ (list* $let* (rest% ($lqual* bindings)) (move! body)));
1194+ $defl%! mk-letrec ($let &bindings &body)
1195+ list $let () $sequence (list $def! (list-extract-first bindings)
1196+ (list* () list (list-extract-rest% bindings))) (move! body);
1197+ () lock-current-environment
1198+ ));
1199+ $defv/e%! $let mods (&bindings .&body) d
1200+ eval% (mk-let $lambda ($lqual bindings) (move! body)) d;
1201+ $defv/e%! $let% mods (&bindings .&body) d
1202+ eval% (mk-let $lambda% ($lqual bindings) (move! body)) d;
1203+ $defv/e%! $let/e mods (&e &bindings .&body) d
1204+ eval% (mk-let/e $lambda/e e ($lqual bindings) (move! body)) d;
1205+ $defv/e%! $let/e% mods (&e &bindings .&body) d
1206+ eval% (mk-let/e $lambda/e% e ($lqual bindings) (move! body)) d;
1207+ $defv/e%! $let* mods (&bindings .&body) d
1208+ eval% (mk-let* $let $let* ($lqual* bindings) (move! body)) d;
1209+ $defv/e%! $let*% mods (&bindings .&body) d
1210+ eval% (mk-let* $let% $let*% ($lqual* bindings) (move! body)) d;
1211+ $defv/e%! $letrec mods (&bindings .&body) d
1212+ eval% (mk-letrec $let ($lqual bindings) (move! body)) d;
1213+ $defv/e%! $letrec% mods (&bindings .&body) d
1214+ eval% (mk-letrec $let% ($lqual bindings) (move! body)) d;
1215+ map1 move!
1216+ (list% $let $let% $let/e $let/e% $let* $let*% $letrec $letrec%)
1217+)) (() get-current-environment);
1218+$defw! derive-current-environment (.&envs) d
1219+ apply make-environment (append envs (list d)) d;
12161220 )NPL"
12171221 # if NPL_Impl_NPLA1_Use_LockEnvironment
12181222 R"NPL(
1219- $defl! make-standard-environment () () lock-current-environment;
1223+$defl! make-standard-environment () () lock-current-environment;
12201224 )NPL"
12211225 # if true
12221226 R"NPL(
1223- $def! derive-environment ()
1224- ($vau () d $lambda/e (() lock-current-environment) (.&envs)
1225- () ($lambda/e (append envs (list d)) ()
1226- () lock-current-environment));
1227+$def! derive-environment ()
1228+ ($vau () d $lambda/e (() lock-current-environment) (.&envs)
1229+ () ($lambda/e (append envs (list d)) () () lock-current-environment));
12271230 )NPL"
12281231 # else
12291232 // XXX: This is also correct, but less efficient.
12301233 R"NPL(
1231- $def! derive-environment ()
1232- ($vau () d eval (list $lambda/e (() lock-current-environment)
1233- ((unwrap list) .&envs) () (list $lambda/e ((unwrap list) append
1234- envs (list d)) () () lock-current-environment)) d);
1234+$def! derive-environment ()
1235+ ($vau () d eval (list $lambda/e (() lock-current-environment)
1236+ ((unwrap list) .&envs) () (list $lambda/e ((unwrap list) append envs
1237+ (list d)) () () lock-current-environment)) d);
12351238 )NPL"
12361239 # endif
12371240 # else
12381241 // XXX: Ground environment is passed by 'ce'.
12391242 R"NPL(
1240- $def! make-standard-environment
1241- ($lambda (&se &e)
1242- ($lambda #ignore $lambda/e se () make-environment ce)
1243- ($set! se ce e))
1244- (make-environment (() get-current-environment))
1245- (() get-current-environment);
1246- $def! derive-environment
1247- ($lambda (&se &e)
1248- ($lambda #ignore
1249- $lambda/e se (.&envs)
1250- apply make-environment (append envs (list ce)))
1251- ($set! se ce e))
1252- (make-environment (() get-current-environment))
1253- (() get-current-environment);
1243+$def! make-standard-environment
1244+ ($lambda (&se &e) ($lambda #ignore $lambda/e se () make-environment ce)
1245+ ($set! se ce e))
1246+ (make-environment (() get-current-environment))
1247+ (() get-current-environment);
1248+$def! derive-environment
1249+ ($lambda (&se &e)
1250+ ($lambda #ignore
1251+ $lambda/e se (.&envs)
1252+ apply make-environment (append envs (list ce)))
1253+ ($set! se ce e))
1254+ (make-environment (() get-current-environment))
1255+ (() get-current-environment);
12541256 )NPL"
12551257 # endif
12561258 R"NPL(
1257- $defv! $as-environment (.&body) d
1258- eval (list $let () (list $sequence (move! body)
1259- (list () lock-current-environment))) d;
1260- $defv! $bindings/p->environment (&parents .&bindings) d $sequence
1261- ($def! (res bref) list (apply make-environment
1262- (map1 ($lambda% (x) eval% x d) parents)) (rulist bindings))
1263- (eval% (list $set! res (list-extract-first bref)
1264- (list* () list (list-extract-rest% bref))) d)
1265- res;
1266- $defv! $bindings->environment (.&bindings) d
1267- eval (list* $bindings/p->environment () (move! bindings)) d;
1268- $defl! symbols->imports (&symbols)
1269- list* () list% (map1 ($lambda (&s) list forward! (desigil s))
1270- (forward! symbols));
1271- $defv! $provide/let! (&symbols &bindings .&body) d
1272- eval% (list% $let (forward! bindings) $sequence
1273- (move! body) (list% $set! d (append symbols ((unwrap list%) .))
1274- (symbols->imports symbols)) (list () lock-current-environment))
1275- d;
1276- $defv! $provide! (&symbols .&body) d
1277- eval (list*% $provide/let! (forward! symbols) () (move! body)) d;
1278- $defv! $import! (&e .&symbols) d
1279- eval% (list $set! d (append symbols ((unwrap list%) .))
1280- (symbols->imports symbols)) (eval e d);
1281- $defv! $import&! (&e .&symbols) d
1282- eval% (list $set! d (append (map1 ensigil symbols)
1283- ((unwrap list%) .)) (symbols->imports symbols)) (eval e d);
1284- $defl! nonfoldable? (&l)
1285- $if (null? l) #f ($if (first-null? l) #t (nonfoldable? (rest& l)));
1259+$defv! $as-environment (.&body) d
1260+ eval (list $let () (list $sequence (move! body)
1261+ (list () lock-current-environment))) d;
1262+$defv! $bindings/p->environment (&parents .&bindings) d $sequence
1263+ ($def! (res bref) list (apply make-environment
1264+ (map1 ($lambda% (x) eval% x d) parents)) (rulist bindings))
1265+ (eval% (list $set! res (list-extract-first bref)
1266+ (list* () list (list-extract-rest% bref))) d)
1267+ res;
1268+$defv! $bindings->environment (.&bindings) d
1269+ eval (list* $bindings/p->environment () (move! bindings)) d;
1270+$defl! symbols->imports (&symbols)
1271+ list* () list% (map1 ($lambda (&s) list forward! (desigil s))
1272+ (forward! symbols));
1273+$defv! $provide/let! (&symbols &bindings .&body) d
1274+ eval% (list% $let (forward! bindings) $sequence
1275+ (move! body) (list% $set! d (append symbols ((unwrap list%) .))
1276+ (symbols->imports symbols)) (list () lock-current-environment)) d;
1277+$defv! $provide! (&symbols .&body) d
1278+ eval (list*% $provide/let! (forward! symbols) () (move! body)) d;
1279+$defv! $import! (&e .&symbols) d
1280+ eval% (list $set! d (append symbols ((unwrap list%) .))
1281+ (symbols->imports symbols)) (eval e d);
1282+$defv! $import&! (&e .&symbols) d
1283+ eval% (list $set! d (append (map1 ensigil symbols)
1284+ ((unwrap list%) .)) (symbols->imports symbols)) (eval e d);
1285+$defl! nonfoldable? (&l)
1286+ $if (null? l) #f ($if (first-null? l) #t (nonfoldable? (rest& l)));
12861287 )NPL"
12871288 );
12881289 #endif
@@ -1320,14 +1321,14 @@
13201321 // further avoids specific core functions.
13211322 context.ShareCurrentSource("<root:standard-derived>");
13221323 context.Perform(R"NPL(
1323- $def! ensigil $lambda (&s)
1324- $let/e (derive-current-environment std.strings) ()
1325- $let ((&str symbol->string s))
1326- $if (string-empty? str) s
1327- (string->symbol (++ "&" (symbol->string (desigil s))));
1328- $def! $binds1? $vau (&e &s) d
1329- $let/e (derive-current-environment std.strings) ()
1330- eval (list (unwrap bound?) (symbol->string s)) (eval e d);
1324+$def! ensigil $lambda (&s)
1325+ $let/e (derive-current-environment std.strings) ()
1326+ $let ((&str symbol->string s))
1327+ $if (string-empty? str) s
1328+ (string->symbol (++ "&" (symbol->string (desigil s))));
1329+$def! $binds1? $vau (&e &s) d
1330+ $let/e (derive-current-environment std.strings) ()
1331+ eval (list (unwrap bound?) (symbol->string s)) (eval e d);
13311332 )NPL");
13321333 #endif
13331334 }
@@ -1339,16 +1340,15 @@
13391340 {
13401341 context.ShareCurrentSource("<root:core>");
13411342 context.Perform(R"NPL(
1342- $def! (box% box? unbox) () make-encapsulation-type;
1343- $defl! box (&x) box% x;
1344- $defl%! assv (&x &alist) $cond ((null? alist) ())
1345- ((eqv? x (first& (first& alist))) first alist)
1346- (#t assv (forward! x) (rest% alist));
1347- $defw%! map-reverse (&appv .&ls) d
1348- accl (move! ls) nonfoldable? () list-extract-first
1349- list-extract-rest%
1350- ($lambda (&x &xs) cons% (apply appv (forward! x) d) xs);
1351- $defw! for-each-ltr &ls d $sequence (apply map-reverse ls d) #inert;
1343+$def! (box% box? unbox) () make-encapsulation-type;
1344+$defl! box (&x) box% x;
1345+$defl%! assv (&x &alist) $cond ((null? alist) ())
1346+ ((eqv? x (first& (first& alist))) first alist)
1347+ (#t assv (forward! x) (rest% alist));
1348+$defw%! map-reverse (&appv .&ls) d
1349+ accl (move! ls) nonfoldable? () list-extract-first list-extract-rest%
1350+ ($lambda (&x &xs) cons% (apply appv (forward! x) d) xs);
1351+$defw! for-each-ltr &ls d $sequence (apply map-reverse ls d) #inert;
13521352 )NPL");
13531353 }
13541354
@@ -1380,6 +1380,34 @@
13801380 } // namespace Ground;
13811381 //@}
13821382
1383+#if NPL_Impl_NPLA1_Native_Forms
1384+//! \since build 923
1385+void
1386+CheckRequirement(const string& req)
1387+{
1388+ if(YB_UNLIKELY(req.empty()))
1389+ throw NPLException("Empty requirement name found.");
1390+}
1391+
1392+//! \since build 923
1393+YB_ATTR_nodiscard string
1394+FindValidRequirementIn(const vector<string>& specs, const string req)
1395+{
1396+ YAssert(!req.empty(), "Invalid requirement found.");
1397+ const std::regex re("\\?");
1398+
1399+ for(const auto& spec : specs)
1400+ {
1401+ string path(std::regex_replace(spec, re, req));
1402+
1403+ if(YSLib::ufexists(path.c_str()))
1404+ return path;
1405+ }
1406+ throw NPLException("No module for requirement '" + YSLib::to_std_string(req)
1407+ + "' found.");
1408+}
1409+#endif
1410+
13831411 } // unnamed namespace;
13841412
13851413 void
@@ -1393,43 +1421,37 @@
13931421 void
13941422 LoadModule_std_promises(REPLContext& context)
13951423 {
1424+ context.ShareCurrentSource("<lib:std.promises>");
13961425 // NOTE: Call of 'set-first%!' does not check cyclic references. This is
13971426 // kept safe since it can occur only with NPLA1 undefined behavior.
1398- context.ShareCurrentSource("<lib:std.promises>");
13991427 context.Perform(R"NPL(
1400- $provide/let! (promise? memoize $lazy $lazy/e force)
1401- ((mods $as-environment (
1402- $def! (encapsulate% promise? decapsulate)
1403- () make-encapsulation-type;
1404- $defl%! force-promise (&x) $let ((((&o &env)) x))
1405- $if (null? env) (forward! o)
1406- (
1407- $let% ((&y eval% o env))
1408- $cond
1409- ((null? (first (rest& (first& x))))
1410- first& (first& x))
1411- ((promise? y) $sequence
1412- (set-first%! x
1413- (first (decapsulate (forward! y))))
1414- (force-promise x))
1415- (#t $sequence
1416- ($let (((&o &e) first& x))
1417- list% (assign! o y) (assign@! e ()))
1418- (forward! y))
1419- )
1420- )))
1428+$provide/let! (promise? memoize $lazy $lazy/e force)
1429+((mods $as-environment (
1430+ $def! (encapsulate% promise? decapsulate) () make-encapsulation-type;
1431+ $defl%! force-promise (&x) $let ((((&o &env)) x))
1432+ $if (null? env) (forward! o)
14211433 (
1422- $import! mods &promise?,
1423- $defl/e%! &memoize mods (&x)
1424- encapsulate% (list (list% (forward! x) ())),
1425- $defv/e%! &$lazy mods (.&body) d
1426- encapsulate% (list (list (move! body) d)),
1427- $defv/e%! &$lazy/e mods (&e .&body) d
1428- encapsulate%
1429- (list (list (move! body) (check-parent (eval e d)))),
1430- $defl/e%! &force mods (&x)
1431- $if (promise? x) (force-promise (decapsulate x)) (forward! x)
1432- );
1434+ $let% ((&y eval% o env))
1435+ $cond
1436+ ((null? (first (rest& (first& x)))) first& (first& x))
1437+ ((promise? y) $sequence
1438+ (set-first%! x (first (decapsulate (forward! y))))
1439+ (force-promise x))
1440+ (#t $sequence
1441+ ($let (((&o &e) first& x))
1442+ list% (assign! o y) (assign@! e ()))
1443+ (forward! y))
1444+ )
1445+)))
1446+(
1447+ $import! mods &promise?,
1448+ $defl/e%! &memoize mods (&x) encapsulate% (list (list% (forward! x) ())),
1449+ $defv/e%! &$lazy mods (.&body) d encapsulate% (list (list (move! body) d)),
1450+ $defv/e%! &$lazy/e mods (&e .&body) d
1451+ encapsulate% (list (list (move! body) (check-parent (eval e d)))),
1452+ $defl/e%! &force mods (&x)
1453+ $if (promise? x) (force-promise (decapsulate x)) (forward! x)
1454+);
14331455 )NPL");
14341456 }
14351457
@@ -1609,8 +1631,8 @@
16091631 });
16101632 context.ShareCurrentSource("<lib:std.system>");
16111633 context.Perform(R"NPL(
1612- $defl/e! env-empty? (derive-current-environment std.strings) (&n)
1613- string-empty? (env-get n);
1634+$defl/e! env-empty? (derive-current-environment std.strings) (&n) string-empty?
1635+ (env-get n);
16141636 )NPL");
16151637 RegisterStrict(renv, "system", CallSystem);
16161638 RegisterStrict(renv, "system-get", [](TermNode& term){
@@ -1638,6 +1660,150 @@
16381660 }
16391661
16401662 void
1663+LoadModule_std_modules(REPLContext& context)
1664+{
1665+#if NPL_Impl_NPLA1_Native_Forms
1666+ using YSLib::to_std_string;
1667+ auto& renv(context.Root.GetRecordRef());
1668+ const auto a(renv.Bindings.get_allocator());
1669+ const auto p_registry(YSLib::allocate_shared<set<string>>(a));
1670+ auto& registry(*p_registry);
1671+ const auto p_specs([&]{
1672+ auto p_vec(YSLib::allocate_shared<vector<string>>(a));
1673+ string x(a);
1674+
1675+ YSLib::FetchEnvironmentVariable(x, "NPLA1_PATH");
1676+ if(x.empty())
1677+ {
1678+ p_vec->push_back("./?");
1679+ p_vec->push_back("./?.txt");
1680+ }
1681+ else
1682+ {
1683+ string::size_type pos(0), orig(0);
1684+
1685+ while((pos = x.find('?', pos)) != string::npos)
1686+ {
1687+ p_vec->push_back(x.substr(orig, pos - orig));
1688+ orig = ++pos;
1689+ }
1690+ p_vec->push_back(x.substr(orig, pos - orig));
1691+ }
1692+ return p_vec;
1693+ }());
1694+ auto& specs(*p_specs);
1695+
1696+ RegisterUnary<Strict, const string>(renv, "registered-requirement?",
1697+ // TODO: Blocked. Use C++14 lambda initializers to optimize the
1698+ // implementation.
1699+ // XXX: Not using binding to prevent overloading ambiguity.
1700+ [p_registry](const string& req){
1701+ if(!req.empty())
1702+ return ystdex::exists(NPL::Deref(p_registry), req);
1703+ throw NPLException("Empty requirement name found.");
1704+ });
1705+ RegisterStrict(renv, "register-requirement!", [&](TermNode& term){
1706+ auto i(term.begin());
1707+ const auto& req(NPL::ResolveRegular<const string>(NPL::Deref(++i)));
1708+
1709+ CheckRequirement(req);
1710+ if(registry.insert(req).second)
1711+ return ReduceReturnUnspecified(term);
1712+ throw NPLException("Requirement '" + to_std_string(req)
1713+ + "' is already registered.");
1714+ });
1715+ RegisterUnary<Strict, const string>(renv, "unregister-requirement!",
1716+ [&](const string& req){
1717+ CheckRequirement(req);
1718+ if(YB_UNLIKELY(registry.erase(req) == 0))
1719+ throw NPLException("Requirement '" + to_std_string(req)
1720+ + "' is not registered.");
1721+ });
1722+ RegisterUnary<Strict, const string>(renv, "find-requirement-filename",
1723+ // TODO: Blocked. Use C++14 lambda initializers to optimize the
1724+ // implementation.
1725+ // XXX: Not using binding to prevent overloading ambiguity.
1726+ [p_specs](const string& req){
1727+ CheckRequirement(req);
1728+ return FindValidRequirementIn(NPL::Deref(p_specs), req);
1729+ });
1730+ RegisterStrict(renv, "require",
1731+ [&](TermNode& term, ContextNode& ctx) -> ReductionStatus{
1732+ auto i(term.begin());
1733+ const auto& req(NPL::ResolveRegular<const string>(NPL::Deref(++i)));
1734+
1735+ CheckRequirement(req);
1736+ if(!ystdex::exists(registry, req))
1737+ {
1738+ auto filename(FindValidRequirementIn(specs, req));
1739+
1740+ registry.insert(req);
1741+ return ReduceToLoadFile(term, ctx, context, std::move(filename));
1742+ }
1743+ return ReduceReturnUnspecified(term);
1744+ });
1745+#else
1746+ context.ShareCurrentSource("<lib:std.modules>");
1747+ // XXX: Thread-safety is not respected currently.
1748+ context.Perform(R"NPL(
1749+$provide/let! (registered-requirement? register-requirement!
1750+ unregister-requirement! find-requirement-filename)
1751+((mods $as-environment (
1752+ $import! std.strings &string-empty? &++ &string->symbol;
1753+
1754+ $defl! requirement-error ()
1755+ raise-error "Empty requirement name found.",
1756+ (
1757+ $def! registry () make-environment;
1758+ $defl! bound-name? (&req)
1759+ $and? (eval (list bound? req) registry)
1760+ (not? (string-empty? (eval (string->symbol req) registry))),
1761+ $defl! set-value! (&req &v)
1762+ eval (list $def! (string->symbol req) v) registry
1763+ ),
1764+ (
1765+ $def! placeholder ($remote-eval% string->regex std.strings) "\?",
1766+ $def! prom_pathspecs ($remote-eval% $lazy std.promises)
1767+ $let ((spec ($remote-eval% env-get std.system) "NPLA1_PATH"))
1768+ $if (string-empty? spec) (list "./?" "./?.txt")
1769+ (($remote-eval% string-split std.strings) spec ";");
1770+ $defl! get-requirement-filename (&specs &req)
1771+ $if (null? specs)
1772+ (raise-error (++ "No module for requirement '" req
1773+ "' found."))
1774+ (
1775+ $let* ((spec first& specs) (path ($remote-eval% regex-replace
1776+ std.strings) spec placeholder req))
1777+ $if (($remote-eval% readable-file? std.io) path) path
1778+ (get-requirement-filename (rest& specs) req)
1779+ )
1780+ )
1781+)))
1782+(
1783+ $defl/e! &registered-requirement? mods (&req)
1784+ $if (string-empty? req) (() requirement-error) (bound-name? req),
1785+ $defl/e! &register-requirement! mods (&req)
1786+ $if (string-empty? req) (() requirement-error)
1787+ ($if (bound-name? req) (raise-error (++ "Requirement '" req
1788+ "' is already registered.")) (set-value! req req)),
1789+ $defl/e! &unregister-requirement! mods (&req)
1790+ $if (string-empty? req) (() requirement-error)
1791+ ($if (bound-name? req) (set-value! req "") (raise-error
1792+ (++ "Requirement '" req "' is not registered."))),
1793+ $defl/e! &find-requirement-filename mods (&req)
1794+ get-requirement-filename
1795+ (($remote-eval% force std.promises) prom_pathspecs) req
1796+);
1797+$defl%! &require (&req)
1798+ $if (registered-requirement? req) #inert
1799+ ($let ((filename find-requirement-filename req))
1800+ $sequence (register-requirement! (move! req))
1801+ (($remote-eval% load std.io) filename));
1802+ )NPL");
1803+#endif
1804+}
1805+
1806+void
16411807 LoadModule_SHBuild(REPLContext& context)
16421808 {
16431809 using namespace YSLib;
@@ -1656,8 +1822,7 @@
16561822 })));
16571823 RegisterUnary<Strict, const string>(renv, "SHBuild_BuildGCH_existed_",
16581824 [](const string& str) -> bool{
1659- if(IO::UniqueFile
1660- file{uopen(str.c_str(), IO::omode_convb(std::ios_base::in))})
1825+ if(IO::UniqueFile file{uopen(str.c_str(), {}, std::ios_base::in)})
16611826 return file->GetSize() > 0;
16621827 return {};
16631828 });
@@ -1864,9 +2029,10 @@
18642029 });
18652030
18662031 load_std_module("promises", LoadModule_std_promises);
1867- load_std_module("strings", LoadModule_std_strings);
2032+ load_std_module("strings", LoadModule_std_strings),
18682033 load_std_module("io", LoadModule_std_io),
18692034 load_std_module("system", LoadModule_std_system);
2035+ load_std_module("modules", LoadModule_std_modules);
18702036 }
18712037
18722038 } // namespace Forms;
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/source/NPL/NPLA1Forms.cpp
--- a/YFramework/source/NPL/NPLA1Forms.cpp Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/source/NPL/NPLA1Forms.cpp Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Forms.cpp
1212 \ingroup NPL
1313 \brief NPLA1 语法形式。
14-\version r24829
14+\version r24854
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2014-02-15 11:19:51 +0800
1919 \par 修改时间:
20- 2021-08-01 03:30 +0800
20+ 2021-08-07 12:28 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -662,6 +662,17 @@
662662 .SwapContainer(expr);
663663 return EvalImplUnchecked(term, ctx, no_lift);
664664 }
665+
666+//! \since build 923
667+ReductionStatus
668+RemoteEvalImpl(TermNode& term, ContextNode& ctx, bool no_lift)
669+{
670+ RetainN(term, 2);
671+ return ReduceSubsequent(term.GetContainerRef().back(), ctx,
672+ A1::NameTypedReducerHandler([&, no_lift]{
673+ return EvalImplUnchecked(term, ctx, no_lift);
674+ }, "eval-remote-eval-env"));
675+}
665676 //@}
666677
667678
@@ -2725,7 +2736,7 @@
27252736 // NOTE: Subterms are extracted arguments for the call, optional 'e',
27262737 // extracted 'formals' for the lambda abstraction,
27272738 // unused 'bindings', trailing 'body'.
2728- YAssert(term.size() >= (with_env ? 4 : 3), "Invalid nested call found.");
2739+ YAssert(term.size() >= (with_env ? 4U : 3U), "Invalid nested call found.");
27292740 return LetCombinePrepare([&, no_lift]{
27302741 // NOTE: Now subterms are extracted arguments for the call plus
27312742 // the parent in %Value, extracted 'formals' for the lambda
@@ -2749,7 +2760,7 @@
27492760 // NOTE: Subterms are %operand (the term range of 'bindings' with optional
27502761 // temporary list), optional 'e', originally bound 'bindings',
27512762 // trailing 'body'.
2752- YAssert(term.size() >= (with_env ? 3 : 2), "Invalid nested call found.");
2763+ YAssert(term.size() >= (with_env ? 3U : 2U), "Invalid nested call found.");
27532764 LetBindingsExtract(term, with_env);
27542765 // NOTE: Now subterms are extracted arguments for the call,
27552766 // optional 'e', extracted 'formals' for the lambda abstraction,
@@ -2763,7 +2774,7 @@
27632774 {
27642775 // NOTE: Subterms are the empty term, optional 'e',
27652776 // unused originally bound 'bindings', trailing 'body'.
2766- YAssert(term.size() >= (with_env ? 3 : 2), "Invalid nested call found.");
2777+ YAssert(term.size() >= (with_env ? 3U : 2U), "Invalid nested call found.");
27672778 LetAddFormalsTerm(term, with_env);
27682779 // NOTE: This is required by %LetCombinePrepare.
27692780 term.begin()->Clear();
@@ -2951,12 +2962,12 @@
29512962 // NOTE: Subterms are %operand (the term range of 'bindings' with optional
29522963 // temporary list), optional 'e', originally bound 'bindings',
29532964 // trailing 'body'.
2954- YAssert(term.size() >= (with_env ? 3 : 2), "Invalid nested call found.");
2965+ YAssert(term.size() >= (with_env ? 3U : 2U), "Invalid nested call found.");
29552966 LetBindingsExtract(term, with_env);
29562967 // NOTE: Now subterms are extracted initializers for the definition,
29572968 // optional 'e', extracted 'formals' for the definition,
29582969 // originally bound 'bindings', trailing 'body'.
2959- YAssert(term.size() >= (with_env ? 4 : 3), "Invalid term found.");
2970+ YAssert(term.size() >= (with_env ? 4U : 3U), "Invalid term found.");
29602971 return LetCombinePrepare([&, no_lift]() -> ReductionStatus{
29612972 // NOTE: Now subterms are extracted initializers for the definition plus
29622973 // the parent in %Value, extracted 'formals' for the definition,
@@ -3636,6 +3647,18 @@
36363647 return ReductionStatus::Retained;
36373648 }
36383649
3650+ReductionStatus
3651+RemoteEval(TermNode& term, ContextNode& ctx)
3652+{
3653+ return RemoteEvalImpl(term, ctx, {});
3654+}
3655+
3656+ReductionStatus
3657+RemoteEvalRef(TermNode& term, ContextNode& ctx)
3658+{
3659+ return RemoteEvalImpl(term, ctx, true);
3660+}
3661+
36393662
36403663 void
36413664 MakeEnvironment(TermNode& term)
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/source/YCLib/FileIO.cpp
--- a/YFramework/source/YCLib/FileIO.cpp Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/source/YCLib/FileIO.cpp Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file FileIO.cpp
1212 \ingroup YCLib
1313 \brief 平台相关的文件访问和输入/输出接口。
14-\version r3871
14+\version r3905
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 615
1717 \par 创建时间:
1818 2015-07-14 18:53:12 +0800
1919 \par 修改时间:
20- 2021-06-02 23:10 +0800
20+ 2021-08-03 20:44 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -45,6 +45,7 @@
4545 #include <ystdex/functional.hpp> // for ystdex::compose, ystdex::addrof;
4646 #include <ystdex/streambuf.hpp> // for ystdex::flush_input,
4747 // ystdex::streambuf_equal;
48+#include <ystdex/deref_op.hpp> // for ystdex::call_value_or;
4849 #if YCL_DS
4950 # include "CHRLib/YModules.h"
5051 # include YFM_CHRLib_CharacterProcessing // for CHRLib::MakeMBCS,
@@ -52,7 +53,7 @@
5253
5354 #elif YCL_Win32
5455 # if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
55-// At least one headers of <stdlib.h>, <stdio.h>, <Windows.h>, <Windef.h>
56+// At least one headers of <stdlib.h>, <stdio.h>, <Windows.h>, <windef.h>
5657 // (and probably more) should have been included to make the MinGW-W64 macro
5758 // available if it is really being used.
5859 # undef _fileno
@@ -678,6 +679,13 @@
678679
679680
680681 int
682+oflag_extend_binary(std::ios_base::openmode mode, int oflag) ynothrow
683+{
684+ return int(mode & std::ios_base::binary ? OpenMode::Binary : OpenMode::Text)
685+ | oflag;
686+}
687+
688+int
681689 omode_conv(std::ios_base::openmode mode) ynothrow
682690 {
683691 using namespace std;
@@ -712,22 +720,17 @@
712720 default:
713721 return int(res);
714722 }
715- // XXX: Order is significant.
723+ // NOTE: %O_EXCL without %O_CREAT leads to undefined behavior in POSIX.
724+ // XXX: The order is significant.
716725 if(mode & ios_noreplace)
717726 res |= OpenMode::CreateExclusive;
718- // NOTE: %O_EXCL without %O_CREAT leads to undefined behavior in POSIX.
719727 if(mode & ios_nocreate)
728+ // XXX: This is not the same to %std::_Fiopen in Microsoft VC++ when %ios_base::out or
729+ // %ios_base::app is set. See https://github.com/microsoft/STL/blob/main/stl/src/fiopen.cpp.
720730 res &= ~OpenMode::CreateExclusive;
721731 return int(res);
722732 }
723733
724-int
725-omode_convb(std::ios_base::openmode mode) ynothrow
726-{
727- return omode_conv(mode)
728- | int(mode & std::ios_base::binary ? OpenMode::Binary : OpenMode::Text);
729-}
730-
731734
732735 int
733736 uopen(const char* filename, int oflag, mode_t pmode) ynothrowv
@@ -753,6 +756,28 @@
753756 });
754757 #endif
755758 }
759+int
760+uopen(const char* filename, use_openmode_t, std::ios::openmode mode,
761+ mode_t pmode) ynothrowv
762+{
763+ YAssertNonnull(filename);
764+
765+ const int oflag(omode_conv(mode));
766+
767+ return oflag != 0 ? uopen(filename, oflag_extend_binary(mode, oflag), pmode)
768+ : -1;
769+}
770+int
771+uopen(const char16_t* filename, use_openmode_t, std::ios::openmode mode,
772+ mode_t pmode) ynothrowv
773+{
774+ YAssertNonnull(filename);
775+
776+ const int oflag(omode_conv(mode));
777+
778+ return oflag != 0 ? uopen(filename, oflag_extend_binary(mode, oflag), pmode)
779+ : -1;
780+}
756781
757782 std::FILE*
758783 ufopen(const char* filename, const char* mode) ynothrowv
@@ -881,7 +906,7 @@
881906 #if YCL_Win32
882907 if(const auto p_sb = is.rdbuf())
883908 {
884- // TODO: Implement for other standard library implementations.
909+ // TODO: Opt-in other standard library implementations?
885910 # if __GLIBCXX__
886911 if(const auto p = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(p_sb))
887912 {
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/source/YCLib/Host.cpp
--- a/YFramework/source/YCLib/Host.cpp Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/source/YCLib/Host.cpp Sat Aug 07 17:05:04 2021 +0800
@@ -13,13 +13,13 @@
1313 \ingroup YCLibLimitedPlatforms
1414 \ingroup Host
1515 \brief YCLib 宿主平台公共扩展。
16-\version r1134
16+\version r1135
1717 \author FrankHB <frankhb1989@gmail.com>
1818 \since build 492
1919 \par 创建时间:
2020 2014-04-09 19:03:55 +0800
2121 \par 修改时间:
22- 2021-07-07 00:26 +0800
22+ 2021-08-01 11:22 +0800
2323 \par 文本编码:
2424 UTF-8
2525 \par 模块名称:
@@ -607,7 +607,7 @@
607607 # endif
608608 }
609609 // XXX: Errors are ignored.
610- CatchIgnore(Exception& e)
610+ CatchIgnore(Exception&)
611611 return {};
612612 }())
613613 {}
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/source/YSLib/Service/File.cpp
--- a/YFramework/source/YSLib/Service/File.cpp Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/source/YSLib/Service/File.cpp Sat Aug 07 17:05:04 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2009-2019 FrankHB.
2+ © 2009-2019, 2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file File.cpp
1212 \ingroup Service
1313 \brief 平台中立的文件抽象。
14-\version r719
14+\version r729
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since 早于 build 132
1717 \par 创建时间:
1818 2009-11-24 23:14:51 +0800
1919 \par 修改时间:
20- 2019-07-07 14:53 +0800
20+ 2021-08-03 19:36 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -34,17 +34,6 @@
3434 namespace IO
3535 {
3636
37-UniqueFile
38-OpenFile(const char* filename, int omode, mode_t pmode)
39-{
40- if(UniqueFile p_ifile{uopen(filename, omode, pmode)})
41- return p_ifile;
42- else
43- ystdex::throw_error(errno, "Failed opening file '"
44- + std::string(filename) + '\'');
45-}
46-
47-
4837 SharedInputMappedFileStream::SharedInputMappedFileStream(const char* path)
4938 : MappedFile(path), SharedIndirectLockGuard<const UniqueFile>(
5039 GetUniqueFile()), ystdex::membuf(ystdex::replace_cast<const char*>(
diff -r ec368cc4b053 -r 4a903ae70b2e YFramework/source/YSLib/Service/FileSystem.cpp
--- a/YFramework/source/YSLib/Service/FileSystem.cpp Sun Aug 01 06:41:44 2021 +0800
+++ b/YFramework/source/YSLib/Service/FileSystem.cpp Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file FileSystem.cpp
1212 \ingroup Service
1313 \brief 平台中立的文件系统抽象。
14-\version r2307
14+\version r2309
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since 早于 build 132
1717 \par 创建时间:
1818 2010-03-28 00:36:30 +0800
1919 \par 修改时间:
20- 2021-06-25 12:57 +0800
20+ 2021-08-03 19:36 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -148,8 +148,8 @@
148148 YB_NONNULL(1) UniqueFile
149149 OpenFileForCopy(const char* src)
150150 {
151- return OpenFile(src, omode_convb(std::ios_base::in | std::ios_base::binary),
152- 0);
151+ return OpenFile(src, use_openmode_t(),
152+ std::ios_base::in | std::ios_base::binary, 0);
153153 }
154154
155155 } // unnamed namespace;
diff -r ec368cc4b053 -r 4a903ae70b2e YSTest/YSTest.vcxproj
--- a/YSTest/YSTest.vcxproj Sun Aug 01 06:41:44 2021 +0800
+++ b/YSTest/YSTest.vcxproj Sat Aug 07 17:05:04 2021 +0800
@@ -82,6 +82,7 @@
8282 <ConformanceMode>true</ConformanceMode>
8383 <LanguageStandard>stdcpplatest</LanguageStandard>
8484 <MultiProcessorCompilation>true</MultiProcessorCompilation>
85+ <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions>
8586 </ClCompile>
8687 <Link>
8788 <AdditionalDependencies>$(SolutionDir)build\Win32\YFramework\$(Configuration)\YFramework.lib;$(SolutionDir)build\Win32\YBase\$(Configuration)\YBase.lib;imm32.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -97,6 +98,7 @@
9798 <ConformanceMode>true</ConformanceMode>
9899 <LanguageStandard>stdcpplatest</LanguageStandard>
99100 <MultiProcessorCompilation>true</MultiProcessorCompilation>
101+ <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions>
100102 </ClCompile>
101103 <Link>
102104 <EnableCOMDATFolding>true</EnableCOMDATFolding>
diff -r ec368cc4b053 -r 4a903ae70b2e doc/ChangeLog.V0.9.txt
--- a/doc/ChangeLog.V0.9.txt Sun Aug 01 06:41:44 2021 +0800
+++ b/doc/ChangeLog.V0.9.txt Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file ChangeLog.V0.9.txt
1212 \ingroup Documentation
1313 \brief 版本更新历史记录 - V0.9 。
14-\version r4458
14+\version r4592
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 800
1717 \par 创建时间:
1818 2020-10-12 17:19:23 +0800
1919 \par 修改时间:
20- 2021-08-01 06:08 +0800
20+ 2021-08-07 14:41 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -32,6 +32,139 @@
3232
3333 $now
3434 (
35+ / %YBase $=
36+ (
37+ / %YStandardEx $=
38+ (
39+ / "functions %openmode_conv" @ %CStandardIO -> "function templates \
40+ with support of character type other than %char",
41+ * "missing removal of reference" @ "%value_type" @ "class template \
42+ %transformed_iterator" @ %Iterator $since b667,
43+ // This would break %std::indirectly_readable_traits and \
44+ %std::iter_value_t since ISO C++20.
45+ ),
46+ / @ 'YB_IMPL_MSCPP' @ %YDefinition $=
47+ (
48+ + "%(YB_Diag_Push, YB_Diag_Pop, YB_Diag_Ignore) definitions";
49+ / DLDI "simplified disabling warning C4646" ^ "%YB_Diag_Ignore"
50+ )
51+ ),
52+ / %YFramework $=
53+ (
54+ / %YCLib $=
55+ (
56+ / %FileIO $=
57+ (
58+ (
59+ + "function %oflag_extend_binary",
60+ + "tag %use_openmode_t";
61+ + "2 %uopen overloads with %use_openmode_t parameter",
62+ ),
63+ / @ "class template %basic_filebuf" $=
64+ (
65+ // See $2021-08 @ %Documentation::Workflow.
66+ / DLI "enhanced function template %open#1"
67+ @ ('!__GLIBCXX__ && !_LIBCPP_VERSION') %FileIO
68+ ^ $dep_from ("%openmode_conv"
69+ @ %YBase.YStandardEx.CStandardIO, "%::_wfdopen")
70+ ~ "%::_fdopen",
71+ / @ "function template %open#2" $=
72+ (
73+ * "wrong return value" @ '_LIBCPP_VERSION' $since b866,
74+ / @ 'YB_IMPL_MSCPP' $=
75+ (
76+ * "wrong handling of filename encoding for \
77+ 'const char*' parameter, %ios_nocreation and \
78+ possible TOCTTOU access for %ios_noreplace"
79+ $since b709
80+ $= (/ $impl ^ "%uopen" ~ "%std::_Fiopen");
81+ / $comp DLDI !^ 'std::ios_base::_Openprot'
82+ )
83+ )
84+ ),
85+ + DLDI 'yimpl' @ "%(ios_nocreate, ios_noreplace)"
86+ @ '_LIBCPP_VERSION',
87+ - "function %omode_convb" $dep_all_from "removal of omode_convb"
88+ ),
89+ - DLDI "unused exception parameter" @ %Host,
90+ // To eliminate Microsoft VC++ warning: C4101.
91+ / $dev "disabled warning C5105 around inclusion of header \
92+ <Windows.h>" @ %NativeAPI
93+ ^ $dep_from "%YB_Diag_Ignore" @ %YBase.Definition
94+ ),
95+ / $dev %'YCLib_(Win32)'.MinGW32 $=
96+ (
97+ / $re_add(b852) "improved compatibility" @ 'YB_IMPL_MSCPP'
98+ @ "function %LoadProc",
99+ / $re_ex(b852) "simplifed compatibility workaround"
100+ @ "alias %ModuleProc" ^ "%ystdex::remove_pointer_t"
101+ ~ "%ystdex::remove_reference_t or explicit '__stdcall'",
102+ + "static assertion to ensure %ModuleProc is a function type"
103+ ),
104+ / %NPL $=
105+ (
106+ / %NPLA1Forms $=
107+ (
108+ / $re_add(b617) DLDI "integer-literal" @ "functions"
109+ ^ "unsigned-suffix",
110+ // To eliminate Microsoft VC++ warning: C4018.
111+ * "wrong '\return' command" @ "Doxygen comment"
112+ @ "functions %(EvalString, EvalStringRef)" $since b835,
113+ + "functions %(RemoteEval, RemoteEvalRef)"
114+ ),
115+ / %Dependency $=
116+ (
117+ * DD "oudated descriptions" @ "Doxygen comments"
118+ @ ("function %LoadModule_std_promises" $since b907,
119+ "function %LoadStandardContext" @ $since b922),
120+ - DLI "all tabs of common intends" @ "NPLA1 literals",
121+ // This makes less overhead in parsing during the \
122+ initialization.
123+ (
124+ + "operatives ('$remote-eval', '$remote-eval%')"
125+ @ "function %LoadGroundContext"
126+ ^ $dep_from ("%(RemoteEval, RemoteEvalRef)" @ %NPLA1Forms);
127+ + "function %LoadModule_std_modules"
128+ $= (+ "applicatives ('registered-requirement?', \
129+ 'register-requirement!' 'unregister-requirement!', \
130+ 'find-requirement-filename'; %require)")
131+ )
132+ )
133+ ),
134+ / %YSLib $=
135+ (
136+ / %Adaptor.YAdaptor $=
137+ (
138+ + ('using platform::oflag_extend_binary',
139+ 'using::platform::use_openmode_t') $dep_from
140+ "%(oflag_extend_binary, use_openmode_t)" @ %YCLib.FileIO,
141+ - $revert(b639) 'using platform::omode_convb'
142+ $dep_to "removal of omode_convb"
143+ ),
144+ / "function %OpenFile" @ %Service.File -> "function template",
145+ )
146+ ),
147+ + "option '/Zc:preprocessor'" @ "Microsoft VC++ projects"
148+ @ %(YBase, YFramework, YSTest, Tools.SHBuild),
149+ * "'_LIBCPP_VERSION' not checked before '__GLIBCXX__'"
150+ $effective @ %YFramework.YCLib.FileIO $since b866,
151+ // '__GLIBCXX__' may be defined with libstdc++ in some cases, e.g. \
152+ https://reviews.llvm.org/rL173164.
153+ * "file unexpectedly created with no permissions for invalid mode with \
154+ its file descriptor leaked" $effective @ ((('_LIBCPP_VERSION'
155+ $since b866, '__GLIBCXX__' $since b618) @ "function template %open#2"
156+ @ "class template %basic_filebuf" @ %YCLib.FileIO, "constructor#3"
157+ @ "class %UniqueLockedOutputFileStream" @ %YSLib.Service.File)
158+ ^ $dep_from ("%uopen" @ %YCLib.IO), ("%CopyFile#(2, 4, 6)"
159+ @ %YSLib.Service.FileSystem, "applicative 'SHBuild_BuildGCH_existed_'"
160+ @ "function %LoadModule_SHBuild" @ %NPL.Dependency) ^ $dep_from
161+ ("%OpenFile" @ %Service.File, "%use_openmode_t" @ %Adaptor.YAdaptor)
162+ @ %YSLib) @ %YFramework ~ "%omode_convb"
163+ $dep_to "removal of omode_convb"
164+),
165+
166+b922
167+(
35168 / $dev %YBase $=
36169 (
37170 / $lib "suppressed Clang++ warning [-Wpointer-bool-conversion]"
@@ -679,7 +812,8 @@
679812 ),
680813 @ "operative '$setrec!'" $since b799
681814 $= (/ $impl ^ 'move!'),
682- @ "operative '$provide/let!'" $since b
815+ @ "operative '$provide/let!'"
816+ $orig (@ '$provide!' $since b837)
683817 $= (/ $impl "'$let' expression construction"
684818 ^ ('list%', 'forward!') ~ 'list')
685819 ),
diff -r ec368cc4b053 -r 4a903ae70b2e doc/NPL.txt
--- a/doc/NPL.txt Sun Aug 01 06:41:44 2021 +0800
+++ b/doc/NPL.txt Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPL.txt
1212 \ingroup Documentation
1313 \brief NPL 规范和实现规格说明。
14-\version r23900
14+\version r23963
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 304
1717 \par 创建时间:
1818 2012-04-25 10:34:20 +0800
1919 \par 修改时间:
20- 2021-08-01 05:14 +0800
20+ 2021-08-07 13:34 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -479,8 +479,8 @@
479479 其中,实现被要求确保通过翻译的程序符合语法规则和翻译时确保的可诊断(diagnostable) 语义规则。
480480 不合式的程序应在运行前终止,不被完整地翻译。
481481
482-@2.5.2 错误(error) :
483-错误是不满足预期的正确性或其它派生实现定义的不变性质时的特定诊断。
482+@2.5.2 错误:
483+错误(error) 是不满足预期的正确性或其它派生实现定义的不变性质时的特定诊断。
484484 非正确性或不满足这些不变性的条件是错误条件(error condition) 。
485485 满足错误条件时,实现可引起(signal) 错误。
486486
@@ -3491,7 +3491,7 @@
34913491 为确保嵌套函数调用时允许引用绑定到非直接主调函数的临时对象(@5.8.5) 形式参数,已被匹配作为绑定目标的项所在的不表示操作数的项(参见 @7.7.3 )可能被转移以保证其子项生存期足够长。
34923492 按 @6.4.7.2 ,此时被作为绑定目标的子项不需被修改(因此自动符合 @6.4.8 的要求)。
34933493 间接调用 A1::RelayForEval 或 A1::RelayForCall 的操作是求值规约操作。
3494-间接调用 A1::RelayForEval 的求值规约操作包括:
3494+等效间接调用 A1::RelayForEval 的求值规约操作包括:
34953495 Forms::Eval(@8.4.4.1)
34963496 Forms::EvalRef(@8.4.4.1)
34973497 Forms::EvalString(@8.4.4.1)
@@ -4221,6 +4221,8 @@
42214221 Forms::EvalString
42224222 Forms::EvalStringRef
42234223 Forms::EvalUnit
4224+Forms::RemoteEval
4225+Forms::RemoteEvalRef
42244226
42254227 @8.4.4.2 环境创建和访问操作:
42264228 Forms 提供以下函数实现对象语言中的环境创建和访问:
@@ -4291,7 +4293,7 @@
42914293 求值结构的共享判断允许本机实现(@5.3) 直接复制 vau 抽象的处理器(@8.4.5.2) 。
42924294 在判断可转移后,第一个子项被移除。余下的子项即为参数绑定(@8.4.5.3) 使用的操作数。
42934295 被绑定的参数被添加到局部环境。
4294-参数绑定后对求值结构的项或其副本进行规约,使函数体(@4.5.2) 被求值。这通过 A1::RelayForCall(@7.7.2) 实现。
4296+参数绑定后对求值结构的项或其副本进行规约,使函数体(@4.5.2) 被求值。这通过 A1::RelayForCall(@7.7.2) 或其等效的内部调用实现。
42954297 之前判断可转移时,直接使用求值结构的项,否则使用副本。
42964298 规约在局部环境进行名称解析(@6.11.1) ,通过保存的 NPL::EnvironmentReference 值对静态环境的所有权进行检查,若失败则抛出异常。
42974299 保存在静态环境以外的对象的引用不受到以上机制保护,需要对形式参数对象可包含的对象进行限制以保证被规约项的所有权要求(@6.4.5) 。
@@ -4391,6 +4393,7 @@
43914393 函数 Forms::LoadModule_std_promises 提供延迟求值等操作(@12.1) ;
43924394 函数 Forms::LoadModule_std_strings 提供字符串操作(@12.2) ;
43934395 函数 Forms::LoadModule_std_io 提供输入/输出操作(@12.3) ;
4396+函数 Forms::LoadModule_std_modules 提供模块管理操作(@12.5) ;
43944397 函数 Forms::LoadModule_std_system 提供系统操作(@12.4) ;
43954398 函数 Forms::LoadModule_SHBuild 提供其它一些供 SHBuild 间接调用的操作(@13.1.1) 。
43964399 函数 Forms::LoadStandardContext 调用 Forms::LoadGroundContext 并加载基础上下文中提供的库模块(@10.2) ;另见 NPLA1 参考实现扩展环境(@12) 。
@@ -4419,6 +4422,7 @@
44194422 eval-letrec-bind
44204423 eval-lift-sum
44214424 eval-map1-appv
4425+eval-remote-eval-env
44224426 eval-vau-parent
44234427 import-bindings
44244428 match-ptree
@@ -4540,6 +4544,7 @@
45404544 <eformal> :表示可选提供的环境名称或 #ignore 的符号。
45414545 使用和 <symbol> 相同的表示。通常为动态环境。
45424546 <expression> :待求值的表达式。
4547+**注释** 这是 NPL 语法(@3.4.2) 的直接实现。
45434548 <expressions> :形式为 <expression>... 的待求值形式。
45444549 求值时,<expressions> 被作为单一表达式(即视为 (<expression>...) ),代替 <expression> 可避免语法中要求过多的括号及 eval(@11.3.7) 等求值形式中显式构造列表的需要。
45454550 <binding> :绑定列表的元素,形式为 <symbol> <body> ,用于指定被求值的表达式和绑定参数的符号。
@@ -4743,7 +4748,7 @@
47434748 引起动态语法错误或动态语义错误的情形包括求值特定的函数应用(@9.5) ,由具体操作指定(参见 @11.2.1 )。
47444749 程序可通过引发(raise) 错误对象(error object) 指定引起诊断。
47454750 除非另行指定,NPLA1 的错误对象不需要是 NPLA1 支持的对象,而可以仅在宿主实现中可见。
4746-因果性引起的错误可构成错误的依赖。
4751+因果性引起的错误可构成错误之间具有依赖关系。
47474752 错误对象的其它具体形式由派生实现指定。
47484753
47494754 @9.5.2 异常(@4.8.1) :
@@ -5455,7 +5460,7 @@
54555460 一些操作可涉及不同的环境,参数在这些环境中被求值可能得到引用值。
54565461 这些操作包括求值为操作子的以下函数:
54575462 以求值 <body> 作为尾上下文(@4.4.7) 的操作(@9.7.4.1) ;
5458-以求值 <expression>(及可能发生的返回值转换(@10.4.2) )作为唯一作用的函数。
5463+以求值 <expression> 或视为 <expression> 的 <object>(及可能发生的返回值转换(@10.4.2) )作为唯一作用的函数。
54595464 以上操作中,带有引用标记字符结尾的操作是间接保留引用值操作,表示求值结果不要求按值传递并可返回引用值。
54605465 不提供函数值转发(@10.5.4) 的形式,因为:
54615466 选用经过返回值转换(@6.4.6.4) 得到的值已可保证避免求值结果中的悬空引用(@9.4.3.2) ;
@@ -5620,6 +5625,8 @@
56205625 通过派生实现的操作不依赖非真合并子(@9.9.5) ,因此以合并子实现操作时,其中不使用分隔符(@9.7.1) ,也不需要实现在初始化(@10.1.1) 时支持中缀变换(@7.5.2) 。
56215626 但是,不同操作之间的定义可能使用分隔符。因为不需依赖 $sequence(@11.4.1) ,这种实现也更简单。
56225627 除非另行指定,当前实现中,操作引发错误对象(@9.5.2) 以抛出异常实现(@10.6.4) ,涉及具体的异常类型未指定。
5628+**注释**
5629+这允许引起错误处理(@10.6.4) 的使用引发错误对象的派生实现。
56235630
56245631 @11 NPLA1 根环境特性(@10.2) :
56255632 本章指定在根环境(@10.1) 提供的 NPLA1 标准库特性(@10.3.3) 。
@@ -5723,7 +5730,7 @@
57235730 以求值 <body> 作为尾上下文的操作,包括:
57245731 结果是合并子或用于在环境中绑定合并子的构造器操作;
57255732 以及核心库函数(@11.4.3) 中的绑定操作;
5726-以求值 <expression> 作为尾上下文的函数,包括 eval 和 eval%(@11.3.7) 。
5733+在尾上下文中求值视为 <expression> 的 <object> 的函数,包括 eval 和 eval%(@11.3.7) 。
57275734 参见环境基本操作(@11.3.7) 和核心库(@11.4.3) 。
57285735 **注释**
57295736 以上操作中的求值符合词法闭包(@4.6.1.2) 规则,可使用 A1::RelayForEval 或 A1::RelayForCall(@7.7.2) 实现。
@@ -5937,10 +5944,12 @@
59375944 为避免引入过于容易引入循环引用(@9.9.1.1) ,仅通过个别操作引入环境强引用(@9.9.3)
59385945 make-environment
59395946 lock-environment
5940-eval <expression> <environment> :在参数指定的环境中求值,结果作为函数值。
5941-注意 <expression> 若为元素中有引用值的列表,元素不会被特殊处理,不隐含左值到右值转换(@10.4.1) 。
59425947 操作:
5943-eval% <expression> <environment> :同 eval ,但保留引用值。
5948+eval <object> <environment> :在参数指定的环境中求值,结果作为函数值。
5949+<object> 在求值前被视为 <expression> 。
5950+若 <object> 为元素中有引用值的列表,元素不会被特殊处理,不隐含左值到右值转换(@10.4.1) 。
5951+**注释** [RnRK] 中第一参数为 <expression> ,但这不是已求值的操作数的类型。
5952+eval% <object> <environment> :同 eval ,但保留引用值。
59445953 bound? <string> :判断指定字符串对应的符号是否被绑定。
59455954 $resolve-identifier <symbol> :解析当前环境中的标识符。
59465955 直接保留解析结果中项的类型,不按成员访问规则确定值类别,因此和解析名称表达式的结果总是左值(@11.2) 不同,可保留消亡值(@6.4.6.1) 。
@@ -6008,13 +6017,15 @@
60086017
60096018 @11.3.9 错误处理(@10.6.4) 和检查:
60106019 raise-error <string> :引发表示错误的异常。
6011-实现引发错误对象(@10.9.4) 的异常对象类型具有 public 基类 NPL::NPLException 。
6020+实现引发错误对象(@9.5.2) 的异常对象类型具有 public 基类 NPL::NPLException 。
60126021 raise-invalid-syntax-error <string> :引发包含参数指定的字符串内容的语法错误(@9.5.1) 。
60136022 实现引发错误对象的异常对象类型具有 public 基类 NPL::InvalidSyntax 。
60146023 raise-type-error <string> :引发包含参数指定的字符串内容的类型错误(@9.5.4.1) 。
60156024 实现引发错误对象的异常对象类型具有 public 基类 NPL::InvalidSyntax 。
6016-check-list-reference <object> :检查对象是否是列表引用,若检查通过返回参数,否则引发错误对象(@9.5.1) 。
6025+check-list-reference <object> :检查对象是否是列表引用,若检查通过返回参数,否则引发错误对象。
60176026 实现引发错误对象的异常对象类型是 NPL::ListTypeError(@6.5) 或 NPL::ValueCategoryMismatch(@6.5) 。
6027+**注释**
6028+当前实现默认抛出异常(@10.9.4) 。
60186029
60196030 @11.3.10 封装:
60206031 () make-encapsulation-type :创建封装类型。
@@ -6046,9 +6057,11 @@
60466057 和 [RnRK] 合并子的派生完全省略错误处理(@10.6.4) 而允许不同的诊断不同,NPLA1 中的操作的替代实现的没有被以上例外或操作自身的语义指定的其它行为(如符合诊断(@9.5) 和接口要求的诊断消息(@1.2.4) 的内容)仍应和本机实现保持一致。
60476058
60486059 @11.4.1 基本派生特性(basic derived feature) :
6060+模块约定:
60496061 引入合并子的操作子对 <body> 的约定同 @11.3.8 。
60506062 因互相依赖,一些操作实现为派生操作时,不能用于直接派生特定一些其它操作。
60516063 和 $vau/e 或 $vau/e%(@11.3.8) 以及 $lambda/e 或 $lambda/e%(@11.4.3) 不同,不指定静态环境的合并子构造器隐含总是使用环境弱引用(@6.11.1) 形式的静态环境,以避免过于容易引入循环引用(@9.9.1.1) 。另见环境数据结构(@6.11.1) 。
6064+操作:
60526065 () get-current-environment :取当前环境:取当前环境的环境弱引用。
60536066 结果具有宿主值类型 NPL::EnvironmentReference 。派生需要非派生实现的 vau/e 。
60546067 () lock-current-environment :锁定当前环境:取当前环境的环境强引用。
@@ -6076,6 +6089,8 @@
60766089 list% <object>... :同 list ,但每个参数都不隐含左值到右值转换,在结果中保留引用值。
60776090 rlist <list> :转换参数为引用列表元素的列表。
60786091 若参数是左值,则结果是参数的元素的引用构成的列表;否则,结果同 idv 。
6092+$remote-eval <expression> <environment> :在动态环境求值第二参数得到的环境中求值第一参数,结果作为函数值。
6093+$remote-eval% <expression> <environment> :同 $remote-eval ,但保留引用值。
60796094 $deflazy! <definiend> <body> :修改绑定。
60806095 同 $def! ,但不求值参数;在添加绑定前仍对冻结环境进行检查(@11.3.7) 。
60816096 $set! <environment> <definiend> <body> :修改指定环境的变量绑定。
@@ -6165,9 +6180,9 @@
61656180 否则,引发错误对象。
61666181 check-parent <object> :检查作为环境的父环境(@9.9.3) 的对象。
61676182 若参数是可以作为合并子环境的 <parent> 则检查通过,结果是转发的参数;
6168-否则,引发错误对象。
6183+否则,引发错误对象(@9.5.2) 。
61696184 检查环境通过的条件同创建合并子时的检查(@11.3.8) 。
6170-引发的错误对象(@9.5.2) 同创建合并子时环境检查失败引发的错误对象,或其依赖(@9.5.1) 的错误对象(后者保证不是语法错误(@9.5.1) )。
6185+引发错误对象的作用同创建合并子时环境检查失败引起错误或引发其依赖(@9.5.1) 的错误对象(后者保证不是语法错误(@9.5.1) )。
61716186 $cond <clauses> :条件选择。
61726187 类似 Kernel 的同名操作,但 <test> 的判断条件和 <body> 形式不同。
61736188 $when <test> <expression-sequence> :条件成立时顺序求值。
@@ -6341,6 +6356,8 @@
63416356 默认加载使用 . 分隔标识符得到的符号作为名称。
63426357 加载的模块依赖根环境,需通过 Forms::LoadGroundContext(@8.5.2) 或等价的方式初始化。
63436358 当前实现中部分加载的环境依赖之前加载的环境,这些环境的名称是固定的。用户程序需要保证这些环境在加载时的静态环境中可用。
6359+在调用其中的合并子时,可能求值符号引用依赖的环境。其中的环境可能在求值定义时不依赖而不作为对应的本机 API 的前置条件。
6360+环境是否具有依赖的环境的绑定绑定是未指定的。
63446361 用户程序需保持加载为环境的模块具有适当的生存期(@9.9.3.5) ,以避免其中的合并子调用引起未定义行为。
63456362 **注释**
63466363 使用 . 分隔标识符得到的符号类似 CHICKEN Scheme 的转换 R7RS 的标准模块名(参见 http://wiki.call-cc.org/eggref/4/r7rs#import )。
@@ -6388,7 +6405,7 @@
63886405 writable-file? <string> :判断参数指定的文件名对应的文件是否存在且可写。
63896406 puts <string> :输出字符串(视为 NTCTS(@6.14.1) )和换行并刷新缓冲。
63906407 实现使用 REPLContext::GetOutputStreamRef(@7.8.1) 。
6391-在使用前,一般应初始化 REPLContext::OutputStreamPtr(@7.8.1) 指向特定的 std::ostream 对象;否则,总是失败引发错误。
6408+在使用前,一般应初始化 REPLContext::OutputStreamPtr(@7.8.1) 指向特定的 std::ostream 对象;否则,总是失败,引起错误(@9.5.1) 。
63926409 load <string> :加载参数指定的翻译单元作为源的模块(@10.2) 。
63936410 加载时创建新环境(@9.9.3) ,以此为当前环境读取翻译单元后求值,以求值后的这个环境对象作为调用的结果。
63946411 当前实现中,参数为文件系统路径。
@@ -6396,6 +6413,7 @@
63966413 类似 klisp 的同名操作。类似地,不使用 klisp 的 find-required-filename 机制,直接以宿主的运行环境为基准使用路径。
63976414 和 klisp 不同,在尾上下文中求值被加载后读取的对象,并以其求值结果作为表达式的求值结果。
63986415 [Shu09] 缺少 load 的详细描述而仅有标题。
6416+**注释** 参数一般指定视为外部翻译单元的文件名。
63996417 **注释**
64006418 http://klisp.org/docs/Ports.html#Ports 的 load 描述中求值环境有误:
64016419 按 [Shu09] 一致的描述和 klisp 的实际实现,调用 load 时应在当前环境求值,而不同于 [Shu09] 的 get-module 中描述的使用创建的环境(即新环境(@9.9.3) )进行求值,否则使用 [Shu09] 的 get-module 的派生不能实现 klisp 和 [Shu09] 中描述的 get-module 的预期语义。
@@ -6403,7 +6421,6 @@
64036421
64046422 @12.4 系统:
64056423 通过初始化基础上下文后调用 Forms::LoadModule_std_system(@8.5.2) 初始化,默认加载为根环境下的 std.system 环境。
6406-当前实现依赖可用的 std.strings 环境(@12.2) 。
64076424 () get-current-repl :取表示当前 REPL 环境的引用值。
64086425 eval-string <string> <environment> :在参数指定的环境中求值作为外部表示的字符串。
64096426 类似 klisp 的同名操作,参见 http://klisp.org/docs/Environments.html#Environments 。
@@ -6427,6 +6444,34 @@
64276444 system-quote <string> :检查参数,按需返回以半角双引号引用的用于命令行参数的字符串。
64286445 带空格或水平制表符的字符串、以半角引号开始或结束的字符串和空字符串会被引用。
64296446 remove-file <string> :移除参数指定的路径命名的文件。
6447+**注释**
6448+当前实现依赖可用的 std.strings(@12.2) 环境。
6449+
6450+@12.5 模块管理:
6451+通过初始化基础上下文后调用 Forms::LoadModule_std_modules(@8.5.2) 初始化,默认加载为根环境下的 std.modules 环境。
6452+模块约定:
6453+需求字符串(requirement string) 是具有 <string> 类型的非空字符串。
6454+若操作的形式参数是需求字符串,实际参数是空字符串,则引起错误(@9.5.1) 。
6455+本模块共享可变状态以支持操作访问确定的模块字符串集合。
6456+本模块隐含一个字符串序列作为需求字符串模板。
6457+除非派生实现另行指定,需求字符串模板初始化后不可变。
6458+需求字符串模板初始化的值由实现定义。
6459+**注释** 当前实现中,若环境变量 NPLA1_PATH 的值非空,则模板是这个值以单字符子串 ";" 分隔后的结果;否则,默认值是序列 "./?" 和 "./?.txt" 构成的序列。
6460+操作:
6461+registered-requirement? <string> :判断参数是否是已在本模块注册的需求字符串。
6462+register-requirement! <string> :在本模块注册参数为需求字符串。
6463+unregister-requirement! <string> :在本模块注册解除参数为需求字符串。
6464+find-requirement-filename <string> :查找需求字符串对应的文件名。
6465+在需求字符串模板中顺序地搜索字符串,返回匹配字符串的结果。若不存在这样的结果,则引起错误。
6466+判断需求字符串模板中的每一个字符串是否能被需求字符串匹配时,首先替换字符串中的单字符子串 "?" 为需求字符串,取得替换结果,再判断它是否为可读的文件的文件名。
6467+替换字符串时,每一个子串被同时一次替换;不对替换结果进一步递归地替换。
6468+require <string> :按需加载需求字符串对应的模块。
6469+若参数指定的需求字符串没有注册,则注册需求字符串并加载同调用 find-requirement-filename 等价的方式搜索得到的结果;否则没有作用。
6470+**注释**
6471+当前实现依赖可用的 std.strings(@12.2) 、std.io(@12.3) 和 std.system(@12.4) 环境。
6472+操作的设计同 klisp 的 ports 模块中的同名操作。
6473+当前实现中,加载操作同 std.io 模块中的 load(@12.3) 。
6474+通过不经过本模块的操作、重复字符串模板的重复项和字符串大小写不敏感的文件名等可能绕过本模块的注册机制而重复加载同一个外部文件。本模块的操作不对这些情形进行任何检查。
64306475
64316476 @13 SHBuild 实现环境:
64326477 SHBuild 实现环境是派生 NPLA1 参考实现扩展环境(@12) 的用于 SHBuild 和外部脚本的构建的初始环境。
diff -r ec368cc4b053 -r 4a903ae70b2e doc/Workflow.txt
--- a/doc/Workflow.txt Sun Aug 01 06:41:44 2021 +0800
+++ b/doc/Workflow.txt Sat Aug 07 17:05:04 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file Workflow.txt
1212 \ingroup Documentation
1313 \brief 工作流汇总报告。
14-\version r4478
14+\version r4494
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 433
1717 \par 创建时间:
1818 2013-07-31 01:27:41 +0800
1919 \par 修改时间:
20- 2021-07-10 17:05 +0800
20+ 2021-08-05 11:09 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -4435,5 +4435,24 @@
44354435 It is likely but not completely known to be sufficient to replace the current use of FreeImage.
44364436 There may need more review to analyze.
44374437
4438+
4439+$2021-08:
4440+
4441+report.impl:
4442+The implementation of file stream opening in YFramework module YCLib::FileIO is revised.
4443+ In Win32, the '_fdopen' call is replaced by '_wfdopen', to eliminate the unnecessary transcoding of the mode string argument in the underlying implementation.
4444+ As a result, no errors will occur during the conversion to the mode string.
4445+ Implmentation specific to Microsoft VC++ is fixed.
4446+ Native 'std::_Fiopen' is now avoided to prevent potential bugs in the overload with the path parameter.
4447+ Instead, the newly added 'uopen' with 'std::ios_base::openmode' support is used.
4448+ These issues also exist in the current Microsoft VC++'s standard library.
4449+ See https://github.com/microsoft/STL/issues/2093.
4450+ As a result, the file sharing option ('shflag' in UCRT lowio) is also not used explicitly.
4451+ Previously, 'std::ios_base::_Openprot' is used.
4452+ There should be no effects.
4453+ Both 'std::ios_base::_Openprot' and the implicit default 'shflag' in the implementation of '::open' (at least in UCRT) used by the newly added 'uopen' is the same, i.e. '_SH_DENYNO'.
4454+ '_SH_DENYNO' is also the value of the default flag 'std::ios_base::_Default_open_prot' used by <fstream> buffer interface in Microsoft VC++'s standard library as the default argument of some 'open' functions, as well as the 'std::fopen' implementation in UCRT.
4455+ This is expected for compatibility, since other implementations has few file mandatory locking as the Win32 file sharing options enabled by default.
4456+
44384457 ////
44394458
Show on old repository browser