The YSLib project - main repository
Revision | 4a903ae70b2e3c8e3022f12f9f9e04981862990c (tree) |
---|---|
Time | 2021-08-07 18:05:04 |
Author | FrankHB <frankhb1989@gmai...> |
Commiter | FrankHB |
更新主分支版本: build 923 rev 10 。
@@ -58,6 +58,7 @@ | ||
58 | 58 | <ConformanceMode>true</ConformanceMode> |
59 | 59 | <LanguageStandard>stdcpplatest</LanguageStandard> |
60 | 60 | <MultiProcessorCompilation>true</MultiProcessorCompilation> |
61 | + <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions> | |
61 | 62 | </ClCompile> |
62 | 63 | <Link> |
63 | 64 | <AdditionalDependencies>$(SolutionDir)build\Win32\YFramework\$(Configuration)\YFramework.lib;$(SolutionDir)build\Win32\YBase\$(Configuration)\YBase.lib;imm32.lib;%(AdditionalDependencies)</AdditionalDependencies> |
@@ -72,6 +73,7 @@ | ||
72 | 73 | <ConformanceMode>true</ConformanceMode> |
73 | 74 | <LanguageStandard>stdcpplatest</LanguageStandard> |
74 | 75 | <MultiProcessorCompilation>true</MultiProcessorCompilation> |
76 | + <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions> | |
75 | 77 | </ClCompile> |
76 | 78 | <Link> |
77 | 79 | <EnableCOMDATFolding>true</EnableCOMDATFolding> |
@@ -160,6 +160,7 @@ | ||
160 | 160 | <ConformanceMode>true</ConformanceMode> |
161 | 161 | <LanguageStandard>stdcpplatest</LanguageStandard> |
162 | 162 | <MultiProcessorCompilation>true</MultiProcessorCompilation> |
163 | + <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions> | |
163 | 164 | </ClCompile> |
164 | 165 | </ItemDefinitionGroup> |
165 | 166 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release|Win32'"> |
@@ -172,6 +173,7 @@ | ||
172 | 173 | <ConformanceMode>true</ConformanceMode> |
173 | 174 | <LanguageStandard>stdcpplatest</LanguageStandard> |
174 | 175 | <MultiProcessorCompilation>true</MultiProcessorCompilation> |
176 | + <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions> | |
175 | 177 | </ClCompile> |
176 | 178 | </ItemDefinitionGroup> |
177 | 179 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
@@ -19,13 +19,13 @@ | ||
19 | 19 | /*! \file ydef.h |
20 | 20 | \ingroup YBase |
21 | 21 | \brief 语言实现和系统环境相关特性及公用类型和宏的基础定义。 |
22 | -\version r3975 | |
22 | +\version r3985 | |
23 | 23 | \author FrankHB <frankhb1989@gmail.com> |
24 | 24 | \since 早于 build 132 |
25 | 25 | \par 创建时间: |
26 | 26 | 2009-12-02 21:42:44 +0800 |
27 | 27 | \par 修改时间: |
28 | - 2021-07-07 19:12 +0800 | |
28 | + 2021-08-02 02:17 +0800 | |
29 | 29 | \par 文本编码: |
30 | 30 | UTF-8 |
31 | 31 | \par 模块名称: |
@@ -432,7 +432,11 @@ | ||
432 | 432 | \def YPP_Diag_Ignore |
433 | 433 | \brief 忽略诊断选项。 |
434 | 434 | */ |
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 | |
436 | 440 | # define YB_Diag_Push _Pragma("clang diagnostic push") |
437 | 441 | # define YB_Diag_Pop _Pragma("clang diagnostic pop") |
438 | 442 | # define YB_Diag_Ignore(_opt) _Pragma( \ |
@@ -975,7 +979,11 @@ | ||
975 | 979 | |
976 | 980 | #if YB_IMPL_MSCPP >= 1200 |
977 | 981 | //! \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. | |
979 | 987 | #endif |
980 | 988 | |
981 | 989 | /*! |
@@ -1,5 +1,5 @@ | ||
1 | 1 | /* |
2 | - © 2011-2016, 2018-2020 FrankHB. | |
2 | + © 2011-2016, 2018-2021 FrankHB. | |
3 | 3 | |
4 | 4 | This file is part of the YSLib project, and may only be used, |
5 | 5 | modified, and distributed under the terms of the YSLib project |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file cstdio.h |
12 | 12 | \ingroup YStandardEx |
13 | 13 | \brief ISO C 标准输入/输出扩展。 |
14 | -\version r728 | |
14 | +\version r830 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 245 |
17 | 17 | \par 创建时间: |
18 | 18 | 2011-09-21 08:30:08 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2020-11-29 20:23 +0800 | |
20 | + 2021-08-01 09:22 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -109,7 +109,7 @@ | ||
109 | 109 | |
110 | 110 | /*! |
111 | 111 | \brief ISO C/C++ 标准输入输出接口打开模式转换。 |
112 | -\since build 326 | |
112 | +\since build 923 | |
113 | 113 | */ |
114 | 114 | //@{ |
115 | 115 | /*! |
@@ -118,18 +118,118 @@ | ||
118 | 118 | \note 返回值未指定,但返回值指向的内容是确定的,且无副作用,因此可用 YB_STATELESS 。 |
119 | 119 | \see LWG 596 。 |
120 | 120 | */ |
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 | +} | |
123 | 163 | /*! |
124 | 164 | \brief ISO C/C++ 标准输入输出接口打开模式转换。 |
125 | 165 | \return 若失败(包括空参数情形)为 std::ios_base::openmode() ,否则为对应的值。 |
126 | 166 | \see ISO C11 7.21.5.3/3 。 |
127 | 167 | \note 顺序严格限定。 |
128 | 168 | \note 支持 x 转换。 |
129 | -\since build 326 | |
130 | 169 | */ |
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 | +} | |
133 | 233 | //@} |
134 | 234 | |
135 | 235 |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file iterator.hpp |
12 | 12 | \ingroup YStandardEx |
13 | 13 | \brief 通用迭代器。 |
14 | -\version r6148 | |
14 | +\version r6152 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since 早于 build 189 |
17 | 17 | \par 创建时间: |
18 | 18 | 2011-01-27 23:01:00 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-02-06 15:29 +0800 | |
20 | + 2021-08-01 12:41 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -166,11 +166,13 @@ | ||
166 | 166 | = typename std::iterator_traits<iterator_type>::difference_type; |
167 | 167 | using reference |
168 | 168 | = cond_t<is_same<_tReference, void>, transformed_type, _tReference>; |
169 | + //! \since build 923 | |
170 | + using value_type = remove_reference_t<reference>; | |
169 | 171 | /*! |
170 | 172 | \since build 667 |
171 | 173 | \todo 测试 operator-> 并支持代理指针。 |
172 | 174 | */ |
173 | - using pointer = remove_reference_t<reference>*; | |
175 | + using pointer = value_type*; | |
174 | 176 | }; |
175 | 177 | |
176 | 178 | } // namespace details; |
@@ -217,7 +219,7 @@ | ||
217 | 219 | //! \since build 667 |
218 | 220 | //@{ |
219 | 221 | 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; | |
221 | 223 | //@} |
222 | 224 | //! \since build 439 |
223 | 225 | using transformed_type = typename impl_traits::transformed_type; |
@@ -1,5 +1,5 @@ | ||
1 | 1 | /* |
2 | - © 2009-2016, 2018, 2020 FrankHB. | |
2 | + © 2009-2016, 2018, 2020-2021 FrankHB. | |
3 | 3 | |
4 | 4 | This file is part of the YSLib project, and may only be used, |
5 | 5 | modified, and distributed under the terms of the YSLib project |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file cstdio.cpp |
12 | 12 | \ingroup YStandardEx |
13 | 13 | \brief ISO C 标准输入/输出扩展。 |
14 | -\version r253 | |
14 | +\version r336 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 245 |
17 | 17 | \par 创建时间: |
18 | 18 | 2011-09-21 08:38:51 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2020-11-29 21:00 +0800 | |
20 | + 2021-08-01 09:10 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -64,96 +64,6 @@ | ||
64 | 64 | } |
65 | 65 | |
66 | 66 | |
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 | - | |
157 | 67 | ifile_iterator& |
158 | 68 | ifile_iterator::operator++() |
159 | 69 | { |
@@ -12,13 +12,13 @@ | ||
12 | 12 | \ingroup YCLib |
13 | 13 | \ingroup Win32 |
14 | 14 | \brief YCLib MinGW32 平台公共扩展。 |
15 | -\version r2149 | |
15 | +\version r2179 | |
16 | 16 | \author FrankHB <frankhb1989@gmail.com> |
17 | 17 | \since build 412 |
18 | 18 | \par 创建时间: |
19 | 19 | 2012-06-08 17:57:49 +0800 |
20 | 20 | \par 修改时间: |
21 | - 2021-06-24 21:41 +0800 | |
21 | + 2021-08-02 01:28 +0800 | |
22 | 22 | \par 文本编码: |
23 | 23 | UTF-8 |
24 | 24 | \par 模块名称: |
@@ -30,7 +30,7 @@ | ||
30 | 30 | #define YCL_Win32_INC_MinGW32_h_ 1 |
31 | 31 | |
32 | 32 | #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, | |
34 | 34 | // unique_ptr_from, ystdex::ends_with, ystdex::aligned_storage_t, |
35 | 35 | // ystdex::pun_ref, pair; |
36 | 36 | #include YFM_YCLib_NativeAPI // for ERROR_SUCCESS, |
@@ -228,12 +228,18 @@ | ||
228 | 228 | //@{ |
229 | 229 | //! \brief 加载过程地址得到的过程类型。 |
230 | 230 | 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."); | |
237 | 243 | |
238 | 244 | /*! |
239 | 245 | \brief 从模块加载指定过程的指针。 |
@@ -248,6 +254,8 @@ | ||
248 | 254 | YB_ATTR_nodiscard YB_NONNULL(2) inline _func& |
249 | 255 | LoadProc(::HMODULE h_module, const char* proc) |
250 | 256 | { |
257 | + static_assert(std::is_function<_func>(), "Invalid function type found."); | |
258 | + | |
251 | 259 | // NOTE: See https://gcc.gnu.org/gcc-8/changes.html. |
252 | 260 | #if YB_IMPL_GNUCPP >= 80000 |
253 | 261 | # pragma GCC diagnostic push |
@@ -255,7 +263,23 @@ | ||
255 | 263 | #endif |
256 | 264 | // NOTE: This should be safe with the additional ABI guarantees, similar to |
257 | 265 | // 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))); | |
259 | 283 | #if YB_IMPL_GNUCPP >= 80000 |
260 | 284 | # pragma GCC diagnostic pop |
261 | 285 | #endif |
@@ -516,6 +516,7 @@ | ||
516 | 516 | <ConformanceMode>true</ConformanceMode> |
517 | 517 | <LanguageStandard>stdcpplatest</LanguageStandard> |
518 | 518 | <MultiProcessorCompilation>true</MultiProcessorCompilation> |
519 | + <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions> | |
519 | 520 | </ClCompile> |
520 | 521 | </ItemDefinitionGroup> |
521 | 522 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release|Win32'"> |
@@ -528,6 +529,7 @@ | ||
528 | 529 | <ConformanceMode>true</ConformanceMode> |
529 | 530 | <LanguageStandard>stdcpplatest</LanguageStandard> |
530 | 531 | <MultiProcessorCompilation>true</MultiProcessorCompilation> |
532 | + <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions> | |
531 | 533 | </ClCompile> |
532 | 534 | </ItemDefinitionGroup> |
533 | 535 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file Dependency.h |
12 | 12 | \ingroup NPL |
13 | 13 | \brief 依赖管理。 |
14 | -\version r474 | |
14 | +\version r492 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 623 |
17 | 17 | \par 创建时间: |
18 | 18 | 2015-08-09 22:12:37 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-07-21 05:02 +0800 | |
20 | + 2021-08-07 05:00 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -205,7 +205,6 @@ | ||
205 | 205 | //@{ |
206 | 206 | /*! |
207 | 207 | \brief 加载代理求值模块。 |
208 | -\note 当前实现:加载时占用当前环境的实现保留变量 __ 。 | |
209 | 208 | \since build 856 |
210 | 209 | |
211 | 210 | 加载 promise 等类型和延迟求值等操作。 |
@@ -231,15 +230,30 @@ | ||
231 | 230 | |
232 | 231 | /*! |
233 | 232 | \brief 加载系统模块。 |
234 | -\pre 当前实现:求值合并子调用前已加载字符串模块或等价方式初始化为模块 std.strings 。 | |
235 | 233 | \sa LoadModule_std_strings |
236 | 234 | |
237 | 235 | 加载系统库操作。 |
236 | +当前实现:求值合并子调用前已加载字符串模块或等价方式初始化为模块 std.strings 。 | |
238 | 237 | */ |
239 | 238 | YF_API void |
240 | 239 | LoadModule_std_system(REPLContext&); |
241 | 240 | |
242 | 241 | /*! |
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 | +/*! | |
243 | 257 | \brief 加载 SHBuild 使用的内部模块。 |
244 | 258 | |
245 | 259 | 加载 SHBuild 自举使用的其它公共语法形式。 |
@@ -253,8 +267,8 @@ | ||
253 | 267 | /*! |
254 | 268 | \brief 加载 NPLA1 基础上下文和标准模块。 |
255 | 269 | \sa LoadGroundContext |
256 | -\sa LoadModule_std_environments | |
257 | 270 | \sa LoadModule_std_io |
271 | +\sa LoadModule_std_modules | |
258 | 272 | \sa LoadModule_std_promises |
259 | 273 | \sa LoadModule_std_strings |
260 | 274 | \sa LoadModule_std_system |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file NPLA1Forms.h |
12 | 12 | \ingroup NPL |
13 | 13 | \brief NPLA1 语法形式。 |
14 | -\version r8231 | |
14 | +\version r8260 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 882 |
17 | 17 | \par 创建时间: |
18 | 18 | 2020-02-15 11:19:21 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-08-01 05:46 +0800 | |
20 | + 2021-08-07 12:18 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -920,11 +920,9 @@ | ||
920 | 920 | |
921 | 921 | /*! |
922 | 922 | \brief 对指定项以指定的环境求值。 |
923 | -\note 支持保存当前动作。 | |
924 | 923 | \sa ResolveEnvironment |
925 | 924 | |
926 | -以表达式 \c \<expression> 和环境 \c \<environment> 为指定的参数进行求值。 | |
927 | -环境以 ContextNode 的引用表示。 | |
925 | +以视为表达式的对象 \c \<object> 和环境 \c \<environment> 为指定的参数进行求值。 | |
928 | 926 | */ |
929 | 927 | //@{ |
930 | 928 | /*! |
@@ -933,7 +931,7 @@ | ||
933 | 931 | 按值传递返回值:提升求值后的项。 |
934 | 932 | |
935 | 933 | 参考调用文法: |
936 | -<pre>eval \<expression> \<environment></pre> | |
934 | +<pre>eval \<object> \<environment></pre> | |
937 | 935 | */ |
938 | 936 | YF_API ReductionStatus |
939 | 937 | Eval(TermNode&, ContextNode&); |
@@ -944,16 +942,13 @@ | ||
944 | 942 | 不提升求值后的项,允许返回引用值。 |
945 | 943 | |
946 | 944 | 参考调用文法: |
947 | -<pre>eval% \<expression> \<environment></pre> | |
945 | +<pre>eval% \<object> \<environment></pre> | |
948 | 946 | */ |
949 | 947 | YF_API ReductionStatus |
950 | 948 | EvalRef(TermNode&, ContextNode&); |
951 | 949 | //@} |
952 | 950 | |
953 | -/*! | |
954 | -\since build 835 | |
955 | -\return ReductionStatus::Retained 。 | |
956 | -*/ | |
951 | +//! \since build 835 | |
957 | 952 | //@{ |
958 | 953 | /*! |
959 | 954 | \brief 在参数指定的环境中求值作为外部表示的字符串。 |
@@ -982,8 +977,8 @@ | ||
982 | 977 | /*! |
983 | 978 | \brief 在参数指定的 REPL 环境中规约字符串表示的翻译单元以求值。 |
984 | 979 | \exception LoggedEvent 翻译单元为空串。 |
980 | +\return ReductionStatus::Retained 。 | |
985 | 981 | \sa Reduce |
986 | -\since build 835 | |
987 | 982 | |
988 | 983 | 提供创建 REPL 新实例并求值的便利接口。 |
989 | 984 |
@@ -994,6 +989,33 @@ | ||
994 | 989 | EvalUnit(TermNode&); |
995 | 990 | //@} |
996 | 991 | |
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 | + | |
997 | 1019 | |
998 | 1020 | /*! |
999 | 1021 | \brief 创建空环境。 |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file FileIO.h |
12 | 12 | \ingroup YCLib |
13 | 13 | \brief 平台相关的文件访问和输入/输出接口。 |
14 | -\version r3236 | |
14 | +\version r3341 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 616 |
17 | 17 | \par 创建时间: |
18 | 18 | 2015-07-14 18:50:35 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-08-01 03:27 +0800 | |
20 | + 2021-08-05 05:25 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -34,12 +34,12 @@ | ||
34 | 34 | // ystdex::enable_for_string_class_t, errno, ystdex::throw_error, u16string, |
35 | 35 | // std::system_error, YTraceDe, array, wstring, string_view; |
36 | 36 | #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; | |
38 | 38 | #include <fstream> // for std::basic_filebuf, std::filebuf, std::wfilebuf, |
39 | 39 | // std::basic_ifstream, std::basic_ofstream, std::basic_fstream, |
40 | 40 | // std::ifstream, std::ofstream, std::fstream, std::wifstream, std::wofstream, |
41 | 41 | // std::wfstream; |
42 | -#if __GLIBCXX__ || _LIBCPP_VERSION || YB_IMPL_MSCPP | |
42 | +#if _LIBCPP_VERSION || __GLIBCXX__ || YB_IMPL_MSCPP | |
43 | 43 | #include <istream> // for std::basic_istream; |
44 | 44 | #include <ostream> // for std::basic_ostream; |
45 | 45 | # if __GLIBCXX__ |
@@ -48,6 +48,7 @@ | ||
48 | 48 | # elif YB_IMPL_MSCPP |
49 | 49 | # include <ystdex/cstdio.h> // for ystdex::openmode_conv; |
50 | 50 | # include <locale> // for std::use_facet, std::codecvt; |
51 | +# include <stdio.h> // for ::_wfdopen; | |
51 | 52 | # endif |
52 | 53 | #endif |
53 | 54 | #include <iosfwd> // for std::istream, std::ostream; |
@@ -435,22 +436,31 @@ | ||
435 | 436 | |
436 | 437 | |
437 | 438 | /*! |
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 | +/*! | |
438 | 448 | \brief ISO C++ 标准输入输出接口打开模式转换为 POSIX 文件打开模式。 |
439 | 449 | \return 若失败为 0 ,否则为对应的值。 |
450 | +\note 忽略二进制模式。 | |
440 | 451 | \since build 648 |
441 | 452 | */ |
442 | -//@{ | |
443 | -//! \note 忽略二进制模式。 | |
444 | 453 | YB_ATTR_nodiscard YF_API YB_STATELESS int |
445 | 454 | omode_conv(std::ios_base::openmode) ynothrow; |
446 | 455 | |
456 | + | |
447 | 457 | /*! |
448 | -\note 扩展:不忽略二进制模式。 | |
449 | -\note POSIX 平台:同 omode_conv 。 | |
458 | +\ingroup tags | |
459 | +\brief 使用 std::ios_base::openmode 的重载标签,保证非整数类型且可默认初始化。 | |
460 | +\since build 923 | |
450 | 461 | */ |
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 | + | |
454 | 464 | |
455 | 465 | /*! |
456 | 466 | \pre 断言:第一参数非空。 |
@@ -459,11 +469,12 @@ | ||
459 | 469 | //@{ |
460 | 470 | /*! |
461 | 471 | \param filename 文件名,意义同 POSIX \c ::open 。 |
462 | -\param oflag 打开旗标,基本语义同 POSIX.1 2004 ,具体行为取决于实现。 | |
463 | 472 | \param pmode 打开模式,基本语义同 POSIX.1 2004 ,具体行为取决于实现。 |
464 | 473 | \since build 720 |
465 | 474 | */ |
466 | 475 | //@{ |
476 | +//! \param oflag 打开旗标,基本语义同 POSIX.1 2004 ,具体行为取决于实现。 | |
477 | +//@{ | |
467 | 478 | //! \brief 以 UTF-8 文件名无缓冲打开文件。 |
468 | 479 | YB_ATTR_nodiscard YF_API YB_NONNULL(1) int |
469 | 480 | uopen(const char* filename, int oflag, mode_t pmode = DefaultPMode()) |
@@ -473,6 +484,26 @@ | ||
473 | 484 | uopen(const char16_t* filename, int oflag, mode_t pmode = DefaultPMode()) |
474 | 485 | ynothrowv; |
475 | 486 | //@} |
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 | +//@} | |
476 | 507 | |
477 | 508 | //! \param filename 文件名,意义同 std::fopen 。 |
478 | 509 | //@{ |
@@ -550,13 +581,16 @@ | ||
550 | 581 | \since build 616 |
551 | 582 | */ |
552 | 583 | //@{ |
553 | -#if __GLIBCXX__ || _LIBCPP_VERSION || YB_IMPL_MSCPP | |
584 | +#if _LIBCPP_VERSION || __GLIBCXX__ || YB_IMPL_MSCPP | |
554 | 585 | /*! |
555 | 586 | \note 扩展打开模式。 |
556 | 587 | \since build 721 |
557 | 588 | */ |
558 | 589 | //@{ |
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__ | |
560 | 594 | //! \brief 表示仅打开已存在文件而不创建文件的模式。 |
561 | 595 | yconstexpr const auto ios_nocreate( |
562 | 596 | std::ios_base::openmode(std::_Ios_Openmode::yimpl(_S_trunc << 1))); |
@@ -566,9 +600,6 @@ | ||
566 | 600 | */ |
567 | 601 | yconstexpr const auto ios_noreplace( |
568 | 602 | 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)); | |
572 | 603 | # else |
573 | 604 | yconstexpr const auto ios_nocreate(std::ios::_Nocreate); |
574 | 605 | yconstexpr const auto ios_noreplace(std::ios::_Noreplace); |
@@ -613,14 +644,7 @@ | ||
613 | 644 | if(p) |
614 | 645 | { |
615 | 646 | 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 | |
624 | 648 | # ifdef _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE |
625 | 649 | // XXX: See https://reviews.llvm.org/rL232049. This configuration shall |
626 | 650 | // not be used in the YCLib platforms. |
@@ -628,16 +652,22 @@ | ||
628 | 652 | # endif |
629 | 653 | this->__open(*p.get(), mode); |
630 | 654 | 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 | + } | |
631 | 662 | # else |
632 | 663 | 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)); | |
636 | 666 | |
637 | - if(fp) | |
638 | - p.release(); | |
639 | - return fp; | |
640 | - } | |
667 | + if(fp) | |
668 | + p.release(); | |
669 | + return fp; | |
670 | + } | |
641 | 671 | # endif |
642 | 672 | } |
643 | 673 | return {}; |
@@ -648,21 +678,34 @@ | ||
648 | 678 | { |
649 | 679 | if(!this->is_open()) |
650 | 680 | { |
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)); | |
653 | 689 | |
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)); | |
659 | 694 | |
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 | |
662 | 704 | # 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); | |
665 | 707 | # endif |
708 | + } | |
666 | 709 | } |
667 | 710 | return {}; |
668 | 711 | } |
@@ -699,8 +742,26 @@ | ||
699 | 742 | return {}; |
700 | 743 | } |
701 | 744 | # 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 | + | |
702 | 763 | //! \since build 837 |
703 | - YB_NONNULL(1) basic_filebuf<_tChar, _tTraits>* | |
764 | + YB_ATTR_nodiscard YB_NONNULL(2) basic_filebuf<_tChar, _tTraits>* | |
704 | 765 | open_file_ptr(std::FILE* p_file) |
705 | 766 | { |
706 | 767 | // NOTE: %::_Filet and %std::_Filet were aliases of %::FILE in |
@@ -1,5 +1,5 @@ | ||
1 | 1 | /* |
2 | - © 2011-2017, 2019 FrankHB. | |
2 | + © 2011-2017, 2019, 2021 FrankHB. | |
3 | 3 | |
4 | 4 | This file is part of the YSLib project, and may only be used, |
5 | 5 | modified, and distributed under the terms of the YSLib project |
@@ -10,14 +10,14 @@ | ||
10 | 10 | |
11 | 11 | /*! \file NativeAPI.h |
12 | 12 | \ingroup YCLib |
13 | -\brief 通用平台应用程序接口描述。 | |
14 | -\version r1671 | |
13 | +\brief 通用平台本机应用程序接口描述。 | |
14 | +\version r1682 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 202 |
17 | 17 | \par 创建时间: |
18 | 18 | 2011-04-13 20:26:21 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2019-10-25 08:38 +0800 | |
20 | + 2021-08-02 02:19 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -616,7 +616,16 @@ | ||
616 | 616 | # define NOMINMAX 1 |
617 | 617 | # endif |
618 | 618 | |
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 | |
619 | 625 | # include <Windows.h> |
626 | +#if YB_IMPL_MSCPP >= 1915 | |
627 | +YB_Diag_Pop | |
628 | +#endif | |
620 | 629 | // XXX: This may have effects on the system headers included later. |
621 | 630 | # if false && __has_include(<specstrings_undef.h>) |
622 | 631 | # include <specstrings_undef.h> |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file YAdaptor.h |
12 | 12 | \ingroup Adaptor |
13 | 13 | \brief 外部库关联。 |
14 | -\version r2455 | |
14 | +\version r2459 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since 早于 build 132 |
17 | 17 | \par 创建时间: |
18 | 18 | 2010-02-22 20:16:21 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-05-18 02:18 +0800 | |
20 | + 2021-08-03 19:35 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -326,8 +326,11 @@ | ||
326 | 326 | using platform::FileDescriptor; |
327 | 327 | using platform::UniqueFile; |
328 | 328 | using platform::DefaultPMode; |
329 | +//! \since build 923 | |
330 | +using platform::oflag_extend_binary; | |
329 | 331 | using platform::omode_conv; |
330 | -using platform::omode_convb; | |
332 | +//! \since build 923 | |
333 | +using platform::use_openmode_t; | |
331 | 334 | //! \since build 902 |
332 | 335 | using platform::StreamGet; |
333 | 336 | //! \since build 901 |
@@ -1,5 +1,5 @@ | ||
1 | 1 | /* |
2 | - © 2009-2020 FrankHB. | |
2 | + © 2009-2021 FrankHB. | |
3 | 3 | |
4 | 4 | This file is part of the YSLib project, and may only be used, |
5 | 5 | modified, and distributed under the terms of the YSLib project |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file File.h |
12 | 12 | \ingroup Service |
13 | 13 | \brief 平台中立的文件抽象。 |
14 | -\version r1680 | |
14 | +\version r1694 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 473 |
17 | 17 | \par 创建时间: |
18 | 18 | 2009-11-24 23:14:41 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2020-12-03 20:48 +0800 | |
20 | + 2021-08-03 19:35 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -44,12 +44,19 @@ | ||
44 | 44 | \pre 路径参数非空。 |
45 | 45 | \throw std::system_error 打开失败。 |
46 | 46 | \return 非空的文件指针。 |
47 | -\note 当前没有公开打开模式的参数,可能使用平台相关的值或 omode_conv 的结果。 | |
48 | 47 | \sa uopen |
49 | -\since build 905 | |
48 | +\since build 923 | |
50 | 49 | */ |
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 | +} | |
53 | 60 | |
54 | 61 | |
55 | 62 | /*! |
@@ -156,7 +163,7 @@ | ||
156 | 163 | #endif |
157 | 164 | UniqueLockedOutputFileStream(const _tChar* filename, |
158 | 165 | std::ios_base::openmode mode, mode_t pmode = DefaultPMode()) |
159 | - : UniqueLockedOutputFileStream(omode_convb(mode), filename, mode, pmode) | |
166 | + : UniqueLockedOutputFileStream(uopen(filename, {}, mode, pmode), mode) | |
160 | 167 | {} |
161 | 168 | //@} |
162 | 169 |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file Dependency.cpp |
12 | 12 | \ingroup NPL |
13 | 13 | \brief 依赖管理。 |
14 | -\version r5281 | |
14 | +\version r5831 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 623 |
17 | 17 | \par 创建时间: |
18 | 18 | 2015-08-09 22:14:45 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-08-01 05:48 +0800 | |
20 | + 2021-08-07 16:08 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -41,13 +41,13 @@ | ||
41 | 41 | // IsBoundLValueTerm, IsUncollapsedTerm, IsUniqueTerm, IsModifiableTerm, |
42 | 42 | // IsTemporaryTerm, ReferenceTerm, LiftTermRef, NPL::SetContentWith, LiftTerm, |
43 | 43 | // 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, | |
46 | 46 | // 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; | |
51 | 51 | #include YFM_NPL_NPLA1Forms // for NPL::Forms functions; |
52 | 52 | #include YFM_YSLib_Service_FileSystem // for YSLib::IO::Path, |
53 | 53 | // YSLib::Deployment::InstallHardLink; |
@@ -58,9 +58,10 @@ | ||
58 | 58 | #include <cerrno> // for errno, ERANGE; |
59 | 59 | #include <regex> // for std::regex, std::regex_match; |
60 | 60 | #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; | |
62 | 63 | #include YFM_YSLib_Core_YCoreUtilities // for YSLib::LockCommandArguments, |
63 | -// YSLib::FetchCommandOutput, YSLib::RandomizeTemplatedString, to_std_string; | |
64 | +// YSLib::FetchCommandOutput, YSLib::RandomizeTemplatedString; | |
64 | 65 | #include <ystdex/string.hpp> // for ystdex::begins_with; |
65 | 66 | #include <ystdex/cstdio.h> // for ystdex::fexists; |
66 | 67 | #include <cerrno> // for errno, EEXIST, EPERM; |
@@ -209,15 +210,28 @@ | ||
209 | 210 | *OpenUnique(context, string(filename, context.Allocator))); |
210 | 211 | } |
211 | 212 | |
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 | + | |
212 | 229 | ReductionStatus |
213 | 230 | ReduceToLoadExternal(TermNode& term, ContextNode& ctx, REPLContext& context) |
214 | 231 | { |
215 | 232 | 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())))); | |
221 | 235 | } |
222 | 236 | |
223 | 237 | ReductionStatus |
@@ -399,7 +413,8 @@ | ||
399 | 413 | con.insert(++++i, A1::AsForm(a, op)); |
400 | 414 | // NOTE: There should be one subterm exactly, but the check is still |
401 | 415 | // 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. | |
403 | 418 | // XXX: Assume the implementation of %Forms::DefineWithNoRecursion is |
404 | 419 | // synchronous. |
405 | 420 | return Forms::DefineWithNoRecursion(term, ctx); |
@@ -760,8 +775,11 @@ | ||
760 | 775 | return ReduceToReferenceList(term, ctx, tm); |
761 | 776 | }, term); |
762 | 777 | }); |
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. | |
765 | 783 | RegisterForm(renv, "$deflazy!", DefineLazy); |
766 | 784 | RegisterForm(renv, "$set!", SetWithNoRecursion); |
767 | 785 | RegisterForm(renv, "$setrec!", SetWithRecursion); |
@@ -918,26 +936,24 @@ | ||
918 | 936 | ThrowInsufficientTermsError(nd, p_ref); |
919 | 937 | }, x); |
920 | 938 | }); |
921 | - | |
922 | 939 | #else |
923 | 940 | context.ShareCurrentSource("<root:basic-derived>"); |
924 | 941 | context.Perform( |
925 | 942 | # if NPL_Impl_NPLA1_Native_EnvironmentPrimitives |
926 | 943 | 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; | |
932 | 948 | )NPL" |
933 | 949 | # else |
934 | 950 | 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)); | |
937 | 953 | )NPL" |
938 | 954 | # endif |
939 | 955 | R"NPL( |
940 | - $def! $quote $vau% (x) #ignore $move-resolved! x; | |
956 | +$def! $quote $vau% (x) #ignore $move-resolved! x; | |
941 | 957 | )NPL" |
942 | 958 | // NOTE: The function 'id' does not initialize new objects from the operand. |
943 | 959 | // XXX: The implementation of 'id' relies on the fact that an object other |
@@ -954,9 +970,9 @@ | ||
954 | 970 | // (first-class referents) from prvalues and all terms can be accessed as |
955 | 971 | // objects with arbitrary longer lifetime. |
956 | 972 | 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); | |
960 | 976 | )NPL" |
961 | 977 | # else |
962 | 978 | ); |
@@ -964,325 +980,310 @@ | ||
964 | 980 | RegisterForm(renv, "$lambda%", LambdaRef); |
965 | 981 | context.ShareCurrentSource("<root:basic-derived-1>"); |
966 | 982 | 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; | |
988 | 986 | )NPL" |
989 | 987 | # endif |
990 | 988 | 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; | |
1008 | 991 | )NPL" |
1009 | 992 | # if NPL_Impl_NPLA1_Use_Id_Vau |
1010 | 993 | 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); | |
1016 | 1030 | )NPL" |
1017 | 1031 | # endif |
1018 | 1032 | // NOTE: Use of 'eqv?' is more efficient than '$if'. |
1019 | 1033 | 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; | |
1216 | 1220 | )NPL" |
1217 | 1221 | # if NPL_Impl_NPLA1_Use_LockEnvironment |
1218 | 1222 | R"NPL( |
1219 | - $defl! make-standard-environment () () lock-current-environment; | |
1223 | +$defl! make-standard-environment () () lock-current-environment; | |
1220 | 1224 | )NPL" |
1221 | 1225 | # if true |
1222 | 1226 | 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)); | |
1227 | 1230 | )NPL" |
1228 | 1231 | # else |
1229 | 1232 | // XXX: This is also correct, but less efficient. |
1230 | 1233 | 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); | |
1235 | 1238 | )NPL" |
1236 | 1239 | # endif |
1237 | 1240 | # else |
1238 | 1241 | // XXX: Ground environment is passed by 'ce'. |
1239 | 1242 | 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); | |
1254 | 1256 | )NPL" |
1255 | 1257 | # endif |
1256 | 1258 | 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))); | |
1286 | 1287 | )NPL" |
1287 | 1288 | ); |
1288 | 1289 | #endif |
@@ -1320,14 +1321,14 @@ | ||
1320 | 1321 | // further avoids specific core functions. |
1321 | 1322 | context.ShareCurrentSource("<root:standard-derived>"); |
1322 | 1323 | 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); | |
1331 | 1332 | )NPL"); |
1332 | 1333 | #endif |
1333 | 1334 | } |
@@ -1339,16 +1340,15 @@ | ||
1339 | 1340 | { |
1340 | 1341 | context.ShareCurrentSource("<root:core>"); |
1341 | 1342 | 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; | |
1352 | 1352 | )NPL"); |
1353 | 1353 | } |
1354 | 1354 |
@@ -1380,6 +1380,34 @@ | ||
1380 | 1380 | } // namespace Ground; |
1381 | 1381 | //@} |
1382 | 1382 | |
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 | + | |
1383 | 1411 | } // unnamed namespace; |
1384 | 1412 | |
1385 | 1413 | void |
@@ -1393,43 +1421,37 @@ | ||
1393 | 1421 | void |
1394 | 1422 | LoadModule_std_promises(REPLContext& context) |
1395 | 1423 | { |
1424 | + context.ShareCurrentSource("<lib:std.promises>"); | |
1396 | 1425 | // NOTE: Call of 'set-first%!' does not check cyclic references. This is |
1397 | 1426 | // kept safe since it can occur only with NPLA1 undefined behavior. |
1398 | - context.ShareCurrentSource("<lib:std.promises>"); | |
1399 | 1427 | 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) | |
1421 | 1433 | ( |
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 | +); | |
1433 | 1455 | )NPL"); |
1434 | 1456 | } |
1435 | 1457 |
@@ -1609,8 +1631,8 @@ | ||
1609 | 1631 | }); |
1610 | 1632 | context.ShareCurrentSource("<lib:std.system>"); |
1611 | 1633 | 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); | |
1614 | 1636 | )NPL"); |
1615 | 1637 | RegisterStrict(renv, "system", CallSystem); |
1616 | 1638 | RegisterStrict(renv, "system-get", [](TermNode& term){ |
@@ -1638,6 +1660,150 @@ | ||
1638 | 1660 | } |
1639 | 1661 | |
1640 | 1662 | 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! ®istered-requirement? mods (&req) | |
1784 | + $if (string-empty? req) (() requirement-error) (bound-name? req), | |
1785 | + $defl/e! ®ister-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 | |
1641 | 1807 | LoadModule_SHBuild(REPLContext& context) |
1642 | 1808 | { |
1643 | 1809 | using namespace YSLib; |
@@ -1656,8 +1822,7 @@ | ||
1656 | 1822 | }))); |
1657 | 1823 | RegisterUnary<Strict, const string>(renv, "SHBuild_BuildGCH_existed_", |
1658 | 1824 | [](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)}) | |
1661 | 1826 | return file->GetSize() > 0; |
1662 | 1827 | return {}; |
1663 | 1828 | }); |
@@ -1864,9 +2029,10 @@ | ||
1864 | 2029 | }); |
1865 | 2030 | |
1866 | 2031 | load_std_module("promises", LoadModule_std_promises); |
1867 | - load_std_module("strings", LoadModule_std_strings); | |
2032 | + load_std_module("strings", LoadModule_std_strings), | |
1868 | 2033 | load_std_module("io", LoadModule_std_io), |
1869 | 2034 | load_std_module("system", LoadModule_std_system); |
2035 | + load_std_module("modules", LoadModule_std_modules); | |
1870 | 2036 | } |
1871 | 2037 | |
1872 | 2038 | } // namespace Forms; |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file NPLA1Forms.cpp |
12 | 12 | \ingroup NPL |
13 | 13 | \brief NPLA1 语法形式。 |
14 | -\version r24829 | |
14 | +\version r24854 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 882 |
17 | 17 | \par 创建时间: |
18 | 18 | 2014-02-15 11:19:51 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-08-01 03:30 +0800 | |
20 | + 2021-08-07 12:28 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -662,6 +662,17 @@ | ||
662 | 662 | .SwapContainer(expr); |
663 | 663 | return EvalImplUnchecked(term, ctx, no_lift); |
664 | 664 | } |
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 | +} | |
665 | 676 | //@} |
666 | 677 | |
667 | 678 |
@@ -2725,7 +2736,7 @@ | ||
2725 | 2736 | // NOTE: Subterms are extracted arguments for the call, optional 'e', |
2726 | 2737 | // extracted 'formals' for the lambda abstraction, |
2727 | 2738 | // 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."); | |
2729 | 2740 | return LetCombinePrepare([&, no_lift]{ |
2730 | 2741 | // NOTE: Now subterms are extracted arguments for the call plus |
2731 | 2742 | // the parent in %Value, extracted 'formals' for the lambda |
@@ -2749,7 +2760,7 @@ | ||
2749 | 2760 | // NOTE: Subterms are %operand (the term range of 'bindings' with optional |
2750 | 2761 | // temporary list), optional 'e', originally bound 'bindings', |
2751 | 2762 | // 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."); | |
2753 | 2764 | LetBindingsExtract(term, with_env); |
2754 | 2765 | // NOTE: Now subterms are extracted arguments for the call, |
2755 | 2766 | // optional 'e', extracted 'formals' for the lambda abstraction, |
@@ -2763,7 +2774,7 @@ | ||
2763 | 2774 | { |
2764 | 2775 | // NOTE: Subterms are the empty term, optional 'e', |
2765 | 2776 | // 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."); | |
2767 | 2778 | LetAddFormalsTerm(term, with_env); |
2768 | 2779 | // NOTE: This is required by %LetCombinePrepare. |
2769 | 2780 | term.begin()->Clear(); |
@@ -2951,12 +2962,12 @@ | ||
2951 | 2962 | // NOTE: Subterms are %operand (the term range of 'bindings' with optional |
2952 | 2963 | // temporary list), optional 'e', originally bound 'bindings', |
2953 | 2964 | // 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."); | |
2955 | 2966 | LetBindingsExtract(term, with_env); |
2956 | 2967 | // NOTE: Now subterms are extracted initializers for the definition, |
2957 | 2968 | // optional 'e', extracted 'formals' for the definition, |
2958 | 2969 | // 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."); | |
2960 | 2971 | return LetCombinePrepare([&, no_lift]() -> ReductionStatus{ |
2961 | 2972 | // NOTE: Now subterms are extracted initializers for the definition plus |
2962 | 2973 | // the parent in %Value, extracted 'formals' for the definition, |
@@ -3636,6 +3647,18 @@ | ||
3636 | 3647 | return ReductionStatus::Retained; |
3637 | 3648 | } |
3638 | 3649 | |
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 | + | |
3639 | 3662 | |
3640 | 3663 | void |
3641 | 3664 | MakeEnvironment(TermNode& term) |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file FileIO.cpp |
12 | 12 | \ingroup YCLib |
13 | 13 | \brief 平台相关的文件访问和输入/输出接口。 |
14 | -\version r3871 | |
14 | +\version r3905 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 615 |
17 | 17 | \par 创建时间: |
18 | 18 | 2015-07-14 18:53:12 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-06-02 23:10 +0800 | |
20 | + 2021-08-03 20:44 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -45,6 +45,7 @@ | ||
45 | 45 | #include <ystdex/functional.hpp> // for ystdex::compose, ystdex::addrof; |
46 | 46 | #include <ystdex/streambuf.hpp> // for ystdex::flush_input, |
47 | 47 | // ystdex::streambuf_equal; |
48 | +#include <ystdex/deref_op.hpp> // for ystdex::call_value_or; | |
48 | 49 | #if YCL_DS |
49 | 50 | # include "CHRLib/YModules.h" |
50 | 51 | # include YFM_CHRLib_CharacterProcessing // for CHRLib::MakeMBCS, |
@@ -52,7 +53,7 @@ | ||
52 | 53 | |
53 | 54 | #elif YCL_Win32 |
54 | 55 | # 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> | |
56 | 57 | // (and probably more) should have been included to make the MinGW-W64 macro |
57 | 58 | // available if it is really being used. |
58 | 59 | # undef _fileno |
@@ -678,6 +679,13 @@ | ||
678 | 679 | |
679 | 680 | |
680 | 681 | 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 | |
681 | 689 | omode_conv(std::ios_base::openmode mode) ynothrow |
682 | 690 | { |
683 | 691 | using namespace std; |
@@ -712,22 +720,17 @@ | ||
712 | 720 | default: |
713 | 721 | return int(res); |
714 | 722 | } |
715 | - // XXX: Order is significant. | |
723 | + // NOTE: %O_EXCL without %O_CREAT leads to undefined behavior in POSIX. | |
724 | + // XXX: The order is significant. | |
716 | 725 | if(mode & ios_noreplace) |
717 | 726 | res |= OpenMode::CreateExclusive; |
718 | - // NOTE: %O_EXCL without %O_CREAT leads to undefined behavior in POSIX. | |
719 | 727 | 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. | |
720 | 730 | res &= ~OpenMode::CreateExclusive; |
721 | 731 | return int(res); |
722 | 732 | } |
723 | 733 | |
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 | - | |
731 | 734 | |
732 | 735 | int |
733 | 736 | uopen(const char* filename, int oflag, mode_t pmode) ynothrowv |
@@ -753,6 +756,28 @@ | ||
753 | 756 | }); |
754 | 757 | #endif |
755 | 758 | } |
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 | +} | |
756 | 781 | |
757 | 782 | std::FILE* |
758 | 783 | ufopen(const char* filename, const char* mode) ynothrowv |
@@ -881,7 +906,7 @@ | ||
881 | 906 | #if YCL_Win32 |
882 | 907 | if(const auto p_sb = is.rdbuf()) |
883 | 908 | { |
884 | - // TODO: Implement for other standard library implementations. | |
909 | + // TODO: Opt-in other standard library implementations? | |
885 | 910 | # if __GLIBCXX__ |
886 | 911 | if(const auto p = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(p_sb)) |
887 | 912 | { |
@@ -13,13 +13,13 @@ | ||
13 | 13 | \ingroup YCLibLimitedPlatforms |
14 | 14 | \ingroup Host |
15 | 15 | \brief YCLib 宿主平台公共扩展。 |
16 | -\version r1134 | |
16 | +\version r1135 | |
17 | 17 | \author FrankHB <frankhb1989@gmail.com> |
18 | 18 | \since build 492 |
19 | 19 | \par 创建时间: |
20 | 20 | 2014-04-09 19:03:55 +0800 |
21 | 21 | \par 修改时间: |
22 | - 2021-07-07 00:26 +0800 | |
22 | + 2021-08-01 11:22 +0800 | |
23 | 23 | \par 文本编码: |
24 | 24 | UTF-8 |
25 | 25 | \par 模块名称: |
@@ -607,7 +607,7 @@ | ||
607 | 607 | # endif |
608 | 608 | } |
609 | 609 | // XXX: Errors are ignored. |
610 | - CatchIgnore(Exception& e) | |
610 | + CatchIgnore(Exception&) | |
611 | 611 | return {}; |
612 | 612 | }()) |
613 | 613 | {} |
@@ -1,5 +1,5 @@ | ||
1 | 1 | /* |
2 | - © 2009-2019 FrankHB. | |
2 | + © 2009-2019, 2021 FrankHB. | |
3 | 3 | |
4 | 4 | This file is part of the YSLib project, and may only be used, |
5 | 5 | modified, and distributed under the terms of the YSLib project |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file File.cpp |
12 | 12 | \ingroup Service |
13 | 13 | \brief 平台中立的文件抽象。 |
14 | -\version r719 | |
14 | +\version r729 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since 早于 build 132 |
17 | 17 | \par 创建时间: |
18 | 18 | 2009-11-24 23:14:51 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2019-07-07 14:53 +0800 | |
20 | + 2021-08-03 19:36 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -34,17 +34,6 @@ | ||
34 | 34 | namespace IO |
35 | 35 | { |
36 | 36 | |
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 | - | |
48 | 37 | SharedInputMappedFileStream::SharedInputMappedFileStream(const char* path) |
49 | 38 | : MappedFile(path), SharedIndirectLockGuard<const UniqueFile>( |
50 | 39 | GetUniqueFile()), ystdex::membuf(ystdex::replace_cast<const char*>( |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file FileSystem.cpp |
12 | 12 | \ingroup Service |
13 | 13 | \brief 平台中立的文件系统抽象。 |
14 | -\version r2307 | |
14 | +\version r2309 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since 早于 build 132 |
17 | 17 | \par 创建时间: |
18 | 18 | 2010-03-28 00:36:30 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-06-25 12:57 +0800 | |
20 | + 2021-08-03 19:36 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -148,8 +148,8 @@ | ||
148 | 148 | YB_NONNULL(1) UniqueFile |
149 | 149 | OpenFileForCopy(const char* src) |
150 | 150 | { |
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); | |
153 | 153 | } |
154 | 154 | |
155 | 155 | } // unnamed namespace; |
@@ -82,6 +82,7 @@ | ||
82 | 82 | <ConformanceMode>true</ConformanceMode> |
83 | 83 | <LanguageStandard>stdcpplatest</LanguageStandard> |
84 | 84 | <MultiProcessorCompilation>true</MultiProcessorCompilation> |
85 | + <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions> | |
85 | 86 | </ClCompile> |
86 | 87 | <Link> |
87 | 88 | <AdditionalDependencies>$(SolutionDir)build\Win32\YFramework\$(Configuration)\YFramework.lib;$(SolutionDir)build\Win32\YBase\$(Configuration)\YBase.lib;imm32.lib;%(AdditionalDependencies)</AdditionalDependencies> |
@@ -97,6 +98,7 @@ | ||
97 | 98 | <ConformanceMode>true</ConformanceMode> |
98 | 99 | <LanguageStandard>stdcpplatest</LanguageStandard> |
99 | 100 | <MultiProcessorCompilation>true</MultiProcessorCompilation> |
101 | + <AdditionalOptions>/Zc:preprocessor %(AdditionalOptions)</AdditionalOptions> | |
100 | 102 | </ClCompile> |
101 | 103 | <Link> |
102 | 104 | <EnableCOMDATFolding>true</EnableCOMDATFolding> |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file ChangeLog.V0.9.txt |
12 | 12 | \ingroup Documentation |
13 | 13 | \brief 版本更新历史记录 - V0.9 。 |
14 | -\version r4458 | |
14 | +\version r4592 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 800 |
17 | 17 | \par 创建时间: |
18 | 18 | 2020-10-12 17:19:23 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-08-01 06:08 +0800 | |
20 | + 2021-08-07 14:41 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -32,6 +32,139 @@ | ||
32 | 32 | |
33 | 33 | $now |
34 | 34 | ( |
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 | +( | |
35 | 168 | / $dev %YBase $= |
36 | 169 | ( |
37 | 170 | / $lib "suppressed Clang++ warning [-Wpointer-bool-conversion]" |
@@ -679,7 +812,8 @@ | ||
679 | 812 | ), |
680 | 813 | @ "operative '$setrec!'" $since b799 |
681 | 814 | $= (/ $impl ^ 'move!'), |
682 | - @ "operative '$provide/let!'" $since b | |
815 | + @ "operative '$provide/let!'" | |
816 | + $orig (@ '$provide!' $since b837) | |
683 | 817 | $= (/ $impl "'$let' expression construction" |
684 | 818 | ^ ('list%', 'forward!') ~ 'list') |
685 | 819 | ), |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file NPL.txt |
12 | 12 | \ingroup Documentation |
13 | 13 | \brief NPL 规范和实现规格说明。 |
14 | -\version r23900 | |
14 | +\version r23963 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 304 |
17 | 17 | \par 创建时间: |
18 | 18 | 2012-04-25 10:34:20 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-08-01 05:14 +0800 | |
20 | + 2021-08-07 13:34 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -479,8 +479,8 @@ | ||
479 | 479 | 其中,实现被要求确保通过翻译的程序符合语法规则和翻译时确保的可诊断(diagnostable) 语义规则。 |
480 | 480 | 不合式的程序应在运行前终止,不被完整地翻译。 |
481 | 481 | |
482 | -@2.5.2 错误(error) : | |
483 | -错误是不满足预期的正确性或其它派生实现定义的不变性质时的特定诊断。 | |
482 | +@2.5.2 错误: | |
483 | +错误(error) 是不满足预期的正确性或其它派生实现定义的不变性质时的特定诊断。 | |
484 | 484 | 非正确性或不满足这些不变性的条件是错误条件(error condition) 。 |
485 | 485 | 满足错误条件时,实现可引起(signal) 错误。 |
486 | 486 |
@@ -3491,7 +3491,7 @@ | ||
3491 | 3491 | 为确保嵌套函数调用时允许引用绑定到非直接主调函数的临时对象(@5.8.5) 形式参数,已被匹配作为绑定目标的项所在的不表示操作数的项(参见 @7.7.3 )可能被转移以保证其子项生存期足够长。 |
3492 | 3492 | 按 @6.4.7.2 ,此时被作为绑定目标的子项不需被修改(因此自动符合 @6.4.8 的要求)。 |
3493 | 3493 | 间接调用 A1::RelayForEval 或 A1::RelayForCall 的操作是求值规约操作。 |
3494 | -间接调用 A1::RelayForEval 的求值规约操作包括: | |
3494 | +等效间接调用 A1::RelayForEval 的求值规约操作包括: | |
3495 | 3495 | Forms::Eval(@8.4.4.1) |
3496 | 3496 | Forms::EvalRef(@8.4.4.1) |
3497 | 3497 | Forms::EvalString(@8.4.4.1) |
@@ -4221,6 +4221,8 @@ | ||
4221 | 4221 | Forms::EvalString |
4222 | 4222 | Forms::EvalStringRef |
4223 | 4223 | Forms::EvalUnit |
4224 | +Forms::RemoteEval | |
4225 | +Forms::RemoteEvalRef | |
4224 | 4226 | |
4225 | 4227 | @8.4.4.2 环境创建和访问操作: |
4226 | 4228 | Forms 提供以下函数实现对象语言中的环境创建和访问: |
@@ -4291,7 +4293,7 @@ | ||
4291 | 4293 | 求值结构的共享判断允许本机实现(@5.3) 直接复制 vau 抽象的处理器(@8.4.5.2) 。 |
4292 | 4294 | 在判断可转移后,第一个子项被移除。余下的子项即为参数绑定(@8.4.5.3) 使用的操作数。 |
4293 | 4295 | 被绑定的参数被添加到局部环境。 |
4294 | -参数绑定后对求值结构的项或其副本进行规约,使函数体(@4.5.2) 被求值。这通过 A1::RelayForCall(@7.7.2) 实现。 | |
4296 | +参数绑定后对求值结构的项或其副本进行规约,使函数体(@4.5.2) 被求值。这通过 A1::RelayForCall(@7.7.2) 或其等效的内部调用实现。 | |
4295 | 4297 | 之前判断可转移时,直接使用求值结构的项,否则使用副本。 |
4296 | 4298 | 规约在局部环境进行名称解析(@6.11.1) ,通过保存的 NPL::EnvironmentReference 值对静态环境的所有权进行检查,若失败则抛出异常。 |
4297 | 4299 | 保存在静态环境以外的对象的引用不受到以上机制保护,需要对形式参数对象可包含的对象进行限制以保证被规约项的所有权要求(@6.4.5) 。 |
@@ -4391,6 +4393,7 @@ | ||
4391 | 4393 | 函数 Forms::LoadModule_std_promises 提供延迟求值等操作(@12.1) ; |
4392 | 4394 | 函数 Forms::LoadModule_std_strings 提供字符串操作(@12.2) ; |
4393 | 4395 | 函数 Forms::LoadModule_std_io 提供输入/输出操作(@12.3) ; |
4396 | +函数 Forms::LoadModule_std_modules 提供模块管理操作(@12.5) ; | |
4394 | 4397 | 函数 Forms::LoadModule_std_system 提供系统操作(@12.4) ; |
4395 | 4398 | 函数 Forms::LoadModule_SHBuild 提供其它一些供 SHBuild 间接调用的操作(@13.1.1) 。 |
4396 | 4399 | 函数 Forms::LoadStandardContext 调用 Forms::LoadGroundContext 并加载基础上下文中提供的库模块(@10.2) ;另见 NPLA1 参考实现扩展环境(@12) 。 |
@@ -4419,6 +4422,7 @@ | ||
4419 | 4422 | eval-letrec-bind |
4420 | 4423 | eval-lift-sum |
4421 | 4424 | eval-map1-appv |
4425 | +eval-remote-eval-env | |
4422 | 4426 | eval-vau-parent |
4423 | 4427 | import-bindings |
4424 | 4428 | match-ptree |
@@ -4540,6 +4544,7 @@ | ||
4540 | 4544 | <eformal> :表示可选提供的环境名称或 #ignore 的符号。 |
4541 | 4545 | 使用和 <symbol> 相同的表示。通常为动态环境。 |
4542 | 4546 | <expression> :待求值的表达式。 |
4547 | +**注释** 这是 NPL 语法(@3.4.2) 的直接实现。 | |
4543 | 4548 | <expressions> :形式为 <expression>... 的待求值形式。 |
4544 | 4549 | 求值时,<expressions> 被作为单一表达式(即视为 (<expression>...) ),代替 <expression> 可避免语法中要求过多的括号及 eval(@11.3.7) 等求值形式中显式构造列表的需要。 |
4545 | 4550 | <binding> :绑定列表的元素,形式为 <symbol> <body> ,用于指定被求值的表达式和绑定参数的符号。 |
@@ -4743,7 +4748,7 @@ | ||
4743 | 4748 | 引起动态语法错误或动态语义错误的情形包括求值特定的函数应用(@9.5) ,由具体操作指定(参见 @11.2.1 )。 |
4744 | 4749 | 程序可通过引发(raise) 错误对象(error object) 指定引起诊断。 |
4745 | 4750 | 除非另行指定,NPLA1 的错误对象不需要是 NPLA1 支持的对象,而可以仅在宿主实现中可见。 |
4746 | -因果性引起的错误可构成错误的依赖。 | |
4751 | +因果性引起的错误可构成错误之间具有依赖关系。 | |
4747 | 4752 | 错误对象的其它具体形式由派生实现指定。 |
4748 | 4753 | |
4749 | 4754 | @9.5.2 异常(@4.8.1) : |
@@ -5455,7 +5460,7 @@ | ||
5455 | 5460 | 一些操作可涉及不同的环境,参数在这些环境中被求值可能得到引用值。 |
5456 | 5461 | 这些操作包括求值为操作子的以下函数: |
5457 | 5462 | 以求值 <body> 作为尾上下文(@4.4.7) 的操作(@9.7.4.1) ; |
5458 | -以求值 <expression>(及可能发生的返回值转换(@10.4.2) )作为唯一作用的函数。 | |
5463 | +以求值 <expression> 或视为 <expression> 的 <object>(及可能发生的返回值转换(@10.4.2) )作为唯一作用的函数。 | |
5459 | 5464 | 以上操作中,带有引用标记字符结尾的操作是间接保留引用值操作,表示求值结果不要求按值传递并可返回引用值。 |
5460 | 5465 | 不提供函数值转发(@10.5.4) 的形式,因为: |
5461 | 5466 | 选用经过返回值转换(@6.4.6.4) 得到的值已可保证避免求值结果中的悬空引用(@9.4.3.2) ; |
@@ -5620,6 +5625,8 @@ | ||
5620 | 5625 | 通过派生实现的操作不依赖非真合并子(@9.9.5) ,因此以合并子实现操作时,其中不使用分隔符(@9.7.1) ,也不需要实现在初始化(@10.1.1) 时支持中缀变换(@7.5.2) 。 |
5621 | 5626 | 但是,不同操作之间的定义可能使用分隔符。因为不需依赖 $sequence(@11.4.1) ,这种实现也更简单。 |
5622 | 5627 | 除非另行指定,当前实现中,操作引发错误对象(@9.5.2) 以抛出异常实现(@10.6.4) ,涉及具体的异常类型未指定。 |
5628 | +**注释** | |
5629 | +这允许引起错误处理(@10.6.4) 的使用引发错误对象的派生实现。 | |
5623 | 5630 | |
5624 | 5631 | @11 NPLA1 根环境特性(@10.2) : |
5625 | 5632 | 本章指定在根环境(@10.1) 提供的 NPLA1 标准库特性(@10.3.3) 。 |
@@ -5723,7 +5730,7 @@ | ||
5723 | 5730 | 以求值 <body> 作为尾上下文的操作,包括: |
5724 | 5731 | 结果是合并子或用于在环境中绑定合并子的构造器操作; |
5725 | 5732 | 以及核心库函数(@11.4.3) 中的绑定操作; |
5726 | -以求值 <expression> 作为尾上下文的函数,包括 eval 和 eval%(@11.3.7) 。 | |
5733 | +在尾上下文中求值视为 <expression> 的 <object> 的函数,包括 eval 和 eval%(@11.3.7) 。 | |
5727 | 5734 | 参见环境基本操作(@11.3.7) 和核心库(@11.4.3) 。 |
5728 | 5735 | **注释** |
5729 | 5736 | 以上操作中的求值符合词法闭包(@4.6.1.2) 规则,可使用 A1::RelayForEval 或 A1::RelayForCall(@7.7.2) 实现。 |
@@ -5937,10 +5944,12 @@ | ||
5937 | 5944 | 为避免引入过于容易引入循环引用(@9.9.1.1) ,仅通过个别操作引入环境强引用(@9.9.3) |
5938 | 5945 | make-environment |
5939 | 5946 | lock-environment |
5940 | -eval <expression> <environment> :在参数指定的环境中求值,结果作为函数值。 | |
5941 | -注意 <expression> 若为元素中有引用值的列表,元素不会被特殊处理,不隐含左值到右值转换(@10.4.1) 。 | |
5942 | 5947 | 操作: |
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 ,但保留引用值。 | |
5944 | 5953 | bound? <string> :判断指定字符串对应的符号是否被绑定。 |
5945 | 5954 | $resolve-identifier <symbol> :解析当前环境中的标识符。 |
5946 | 5955 | 直接保留解析结果中项的类型,不按成员访问规则确定值类别,因此和解析名称表达式的结果总是左值(@11.2) 不同,可保留消亡值(@6.4.6.1) 。 |
@@ -6008,13 +6017,15 @@ | ||
6008 | 6017 | |
6009 | 6018 | @11.3.9 错误处理(@10.6.4) 和检查: |
6010 | 6019 | raise-error <string> :引发表示错误的异常。 |
6011 | -实现引发错误对象(@10.9.4) 的异常对象类型具有 public 基类 NPL::NPLException 。 | |
6020 | +实现引发错误对象(@9.5.2) 的异常对象类型具有 public 基类 NPL::NPLException 。 | |
6012 | 6021 | raise-invalid-syntax-error <string> :引发包含参数指定的字符串内容的语法错误(@9.5.1) 。 |
6013 | 6022 | 实现引发错误对象的异常对象类型具有 public 基类 NPL::InvalidSyntax 。 |
6014 | 6023 | raise-type-error <string> :引发包含参数指定的字符串内容的类型错误(@9.5.4.1) 。 |
6015 | 6024 | 实现引发错误对象的异常对象类型具有 public 基类 NPL::InvalidSyntax 。 |
6016 | -check-list-reference <object> :检查对象是否是列表引用,若检查通过返回参数,否则引发错误对象(@9.5.1) 。 | |
6025 | +check-list-reference <object> :检查对象是否是列表引用,若检查通过返回参数,否则引发错误对象。 | |
6017 | 6026 | 实现引发错误对象的异常对象类型是 NPL::ListTypeError(@6.5) 或 NPL::ValueCategoryMismatch(@6.5) 。 |
6027 | +**注释** | |
6028 | +当前实现默认抛出异常(@10.9.4) 。 | |
6018 | 6029 | |
6019 | 6030 | @11.3.10 封装: |
6020 | 6031 | () make-encapsulation-type :创建封装类型。 |
@@ -6046,9 +6057,11 @@ | ||
6046 | 6057 | 和 [RnRK] 合并子的派生完全省略错误处理(@10.6.4) 而允许不同的诊断不同,NPLA1 中的操作的替代实现的没有被以上例外或操作自身的语义指定的其它行为(如符合诊断(@9.5) 和接口要求的诊断消息(@1.2.4) 的内容)仍应和本机实现保持一致。 |
6047 | 6058 | |
6048 | 6059 | @11.4.1 基本派生特性(basic derived feature) : |
6060 | +模块约定: | |
6049 | 6061 | 引入合并子的操作子对 <body> 的约定同 @11.3.8 。 |
6050 | 6062 | 因互相依赖,一些操作实现为派生操作时,不能用于直接派生特定一些其它操作。 |
6051 | 6063 | 和 $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 | +操作: | |
6052 | 6065 | () get-current-environment :取当前环境:取当前环境的环境弱引用。 |
6053 | 6066 | 结果具有宿主值类型 NPL::EnvironmentReference 。派生需要非派生实现的 vau/e 。 |
6054 | 6067 | () lock-current-environment :锁定当前环境:取当前环境的环境强引用。 |
@@ -6076,6 +6089,8 @@ | ||
6076 | 6089 | list% <object>... :同 list ,但每个参数都不隐含左值到右值转换,在结果中保留引用值。 |
6077 | 6090 | rlist <list> :转换参数为引用列表元素的列表。 |
6078 | 6091 | 若参数是左值,则结果是参数的元素的引用构成的列表;否则,结果同 idv 。 |
6092 | +$remote-eval <expression> <environment> :在动态环境求值第二参数得到的环境中求值第一参数,结果作为函数值。 | |
6093 | +$remote-eval% <expression> <environment> :同 $remote-eval ,但保留引用值。 | |
6079 | 6094 | $deflazy! <definiend> <body> :修改绑定。 |
6080 | 6095 | 同 $def! ,但不求值参数;在添加绑定前仍对冻结环境进行检查(@11.3.7) 。 |
6081 | 6096 | $set! <environment> <definiend> <body> :修改指定环境的变量绑定。 |
@@ -6165,9 +6180,9 @@ | ||
6165 | 6180 | 否则,引发错误对象。 |
6166 | 6181 | check-parent <object> :检查作为环境的父环境(@9.9.3) 的对象。 |
6167 | 6182 | 若参数是可以作为合并子环境的 <parent> 则检查通过,结果是转发的参数; |
6168 | -否则,引发错误对象。 | |
6183 | +否则,引发错误对象(@9.5.2) 。 | |
6169 | 6184 | 检查环境通过的条件同创建合并子时的检查(@11.3.8) 。 |
6170 | -引发的错误对象(@9.5.2) 同创建合并子时环境检查失败引发的错误对象,或其依赖(@9.5.1) 的错误对象(后者保证不是语法错误(@9.5.1) )。 | |
6185 | +引发错误对象的作用同创建合并子时环境检查失败引起错误或引发其依赖(@9.5.1) 的错误对象(后者保证不是语法错误(@9.5.1) )。 | |
6171 | 6186 | $cond <clauses> :条件选择。 |
6172 | 6187 | 类似 Kernel 的同名操作,但 <test> 的判断条件和 <body> 形式不同。 |
6173 | 6188 | $when <test> <expression-sequence> :条件成立时顺序求值。 |
@@ -6341,6 +6356,8 @@ | ||
6341 | 6356 | 默认加载使用 . 分隔标识符得到的符号作为名称。 |
6342 | 6357 | 加载的模块依赖根环境,需通过 Forms::LoadGroundContext(@8.5.2) 或等价的方式初始化。 |
6343 | 6358 | 当前实现中部分加载的环境依赖之前加载的环境,这些环境的名称是固定的。用户程序需要保证这些环境在加载时的静态环境中可用。 |
6359 | +在调用其中的合并子时,可能求值符号引用依赖的环境。其中的环境可能在求值定义时不依赖而不作为对应的本机 API 的前置条件。 | |
6360 | +环境是否具有依赖的环境的绑定绑定是未指定的。 | |
6344 | 6361 | 用户程序需保持加载为环境的模块具有适当的生存期(@9.9.3.5) ,以避免其中的合并子调用引起未定义行为。 |
6345 | 6362 | **注释** |
6346 | 6363 | 使用 . 分隔标识符得到的符号类似 CHICKEN Scheme 的转换 R7RS 的标准模块名(参见 http://wiki.call-cc.org/eggref/4/r7rs#import )。 |
@@ -6388,7 +6405,7 @@ | ||
6388 | 6405 | writable-file? <string> :判断参数指定的文件名对应的文件是否存在且可写。 |
6389 | 6406 | puts <string> :输出字符串(视为 NTCTS(@6.14.1) )和换行并刷新缓冲。 |
6390 | 6407 | 实现使用 REPLContext::GetOutputStreamRef(@7.8.1) 。 |
6391 | -在使用前,一般应初始化 REPLContext::OutputStreamPtr(@7.8.1) 指向特定的 std::ostream 对象;否则,总是失败引发错误。 | |
6408 | +在使用前,一般应初始化 REPLContext::OutputStreamPtr(@7.8.1) 指向特定的 std::ostream 对象;否则,总是失败,引起错误(@9.5.1) 。 | |
6392 | 6409 | load <string> :加载参数指定的翻译单元作为源的模块(@10.2) 。 |
6393 | 6410 | 加载时创建新环境(@9.9.3) ,以此为当前环境读取翻译单元后求值,以求值后的这个环境对象作为调用的结果。 |
6394 | 6411 | 当前实现中,参数为文件系统路径。 |
@@ -6396,6 +6413,7 @@ | ||
6396 | 6413 | 类似 klisp 的同名操作。类似地,不使用 klisp 的 find-required-filename 机制,直接以宿主的运行环境为基准使用路径。 |
6397 | 6414 | 和 klisp 不同,在尾上下文中求值被加载后读取的对象,并以其求值结果作为表达式的求值结果。 |
6398 | 6415 | [Shu09] 缺少 load 的详细描述而仅有标题。 |
6416 | +**注释** 参数一般指定视为外部翻译单元的文件名。 | |
6399 | 6417 | **注释** |
6400 | 6418 | http://klisp.org/docs/Ports.html#Ports 的 load 描述中求值环境有误: |
6401 | 6419 | 按 [Shu09] 一致的描述和 klisp 的实际实现,调用 load 时应在当前环境求值,而不同于 [Shu09] 的 get-module 中描述的使用创建的环境(即新环境(@9.9.3) )进行求值,否则使用 [Shu09] 的 get-module 的派生不能实现 klisp 和 [Shu09] 中描述的 get-module 的预期语义。 |
@@ -6403,7 +6421,6 @@ | ||
6403 | 6421 | |
6404 | 6422 | @12.4 系统: |
6405 | 6423 | 通过初始化基础上下文后调用 Forms::LoadModule_std_system(@8.5.2) 初始化,默认加载为根环境下的 std.system 环境。 |
6406 | -当前实现依赖可用的 std.strings 环境(@12.2) 。 | |
6407 | 6424 | () get-current-repl :取表示当前 REPL 环境的引用值。 |
6408 | 6425 | eval-string <string> <environment> :在参数指定的环境中求值作为外部表示的字符串。 |
6409 | 6426 | 类似 klisp 的同名操作,参见 http://klisp.org/docs/Environments.html#Environments 。 |
@@ -6427,6 +6444,34 @@ | ||
6427 | 6444 | system-quote <string> :检查参数,按需返回以半角双引号引用的用于命令行参数的字符串。 |
6428 | 6445 | 带空格或水平制表符的字符串、以半角引号开始或结束的字符串和空字符串会被引用。 |
6429 | 6446 | 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 | +通过不经过本模块的操作、重复字符串模板的重复项和字符串大小写不敏感的文件名等可能绕过本模块的注册机制而重复加载同一个外部文件。本模块的操作不对这些情形进行任何检查。 | |
6430 | 6475 | |
6431 | 6476 | @13 SHBuild 实现环境: |
6432 | 6477 | SHBuild 实现环境是派生 NPLA1 参考实现扩展环境(@12) 的用于 SHBuild 和外部脚本的构建的初始环境。 |
@@ -11,13 +11,13 @@ | ||
11 | 11 | /*! \file Workflow.txt |
12 | 12 | \ingroup Documentation |
13 | 13 | \brief 工作流汇总报告。 |
14 | -\version r4478 | |
14 | +\version r4494 | |
15 | 15 | \author FrankHB <frankhb1989@gmail.com> |
16 | 16 | \since build 433 |
17 | 17 | \par 创建时间: |
18 | 18 | 2013-07-31 01:27:41 +0800 |
19 | 19 | \par 修改时间: |
20 | - 2021-07-10 17:05 +0800 | |
20 | + 2021-08-05 11:09 +0800 | |
21 | 21 | \par 文本编码: |
22 | 22 | UTF-8 |
23 | 23 | \par 模块名称: |
@@ -4435,5 +4435,24 @@ | ||
4435 | 4435 | It is likely but not completely known to be sufficient to replace the current use of FreeImage. |
4436 | 4436 | There may need more review to analyze. |
4437 | 4437 | |
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 | + | |
4438 | 4457 | //// |
4439 | 4458 |