• R/O
  • SSH

YSLib: Commit

The YSLib project - main repository


Commit MetaInfo

Revision6ad22b72cee32293815086e99c94b01c6b654c45 (tree)
Time2021-01-23 18:00:30
AuthorFrankHB <frankhb1989@gmai...>
CommiterFrankHB

Log Message

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

Change Summary

Incremental Difference

diff -r d1f3d524f742 -r 6ad22b72cee3 Tools/Scripts/SHBuild-YSLib-common.txt
--- a/Tools/Scripts/SHBuild-YSLib-common.txt Sat Jan 09 04:33:56 2021 +0800
+++ b/Tools/Scripts/SHBuild-YSLib-common.txt Sat Jan 23 17:00:30 2021 +0800
@@ -4,22 +4,14 @@
44 "XXX", "'SHBuild_2*' depend on 'cygpath' optionally.";
55 "XXX", "'SHBuild_CheckUName_*' depend on 'uname'.";
66
7-$import! std.strings regex-match? string->regex ++ string->symbol symbol->string
8- string-empty? string<-,
9-$import! std.environments bound? $binds1? value-of,
10-$import! std.io puts,
11-$import! std.system system system-get system-quote remove-file,
12-$import! std.promises $lazy/e $lazy force;
13-$import! env_SHBuild_ SHBuild_RaiseError_ SHBuild_EchoVar SHBuild_QuoteS_
14- SHBuild_String_absolute_path?_ SHBuild_MakeTempFilename SHBuild_TrimOptions_
15- SHBuild_SDot_ SHBuild_BuildGCH_existed_ SHBuild_BuildGCH_mkpdirp_;
16-
177 "NOTE", "Prelude:", "Unsafe functions not friendly to environment stability",
188 " or dangerous to environments except 'move!', 'assign!' and",
199 " 'lock-current-environment' are poisoned.";
2010 $provide! (assign%! assign@! copy-environment lock-environment
2111 $defrec! $setrec! make-standard-environment)
2212 (
13+ $import! std.strings string->symbol symbol->string;
14+
2315 $def! fns (unwrap list) move! assign%! assign@! copy-environment
2416 lock-environment $defrec! $setrec!;
2517 $defl/e! raise-error (make-environment env_SHBuild_ std.strings) (&fn)
@@ -31,19 +23,60 @@
3123 $defw! poison (fns) d for-each-ltr ($lambda (fn) poison-fn fn d) fns;
3224 poison fns;
3325 $def! nstd (() make-standard-environment);
26+
3427 eval (list poison (list $quote fns)) nstd;
3528 $defl/e! make-standard-environment nstd () () lock-current-environment
3629 );
3730
3831 $def! $redef! $def!;
39-$defl! rmatch? (x r) regex-match? x (string->regex r);
40-$defl! putss (.xs) puts (apply ++ xs);
41-$defl! cmd-error-msg_ (cmd) ++ "Failed to call command: " cmd ".";
42-$defl! system-ok (cmd) eqv? (system cmd) 0;
43-$defl! system-check (cmd)
44- $unless (system-ok cmd) (SHBuild_RaiseError_ (cmd-error-msg_ cmd));
45-$defv! $set-if-empty! (var .vexpr) env $if (string-empty? (eval var env))
46- (eval (list $set! env var vexpr) env);
32+$defv/e! $set-if-empty! (derive-environment std.strings) (&var .&body) d
33+ $if (string-empty? (eval% var d))
34+ (eval% (list% $set! d var (move! body)) d);
35+$defl/e! cons-cmd (derive-environment std.strings) (.&xs)
36+ apply ++ (map1 ($lambda (&str) $if (string-empty? str) "" (++ str " ")) xs);
37+$defl/e! rmatch? std.strings (&x &r) regex-match? x (string->regex r);
38+$defl/e! putss (derive-environment std.io std.strings) (.&xs)
39+ puts (apply ++ xs);
40+$defl/e! system-ok (derive-environment std.system) (&cmd) eqv? (system cmd) 0;
41+$defl/e! win32? (() make-standard-environment) (os) eqv? os "Win32";
42+
43+$defl/e! cmd-fail (derive-environment std.strings env_SHBuild_) (&cmd)
44+ SHBuild_RaiseError_ (++ "Failed to call command: " cmd ".");
45+$defl/e! system-check ($let ((mods () make-standard-environment))
46+ ($set! mods (cmd-fail system-ok) list cmd-fail system-ok; (move! mods)))
47+ (cmd) $unless (system-ok cmd) (cmd-fail cmd);
48+$defv/e! $set-system-var! (() make-standard-environment) (&var &arg) d
49+(
50+ $import! std.environments $binds1?,
51+ $import! std.system system-get;
52+
53+ $unless (eval (list $binds1? d var) d)
54+ ($let* ((cmd eval arg d) ((&rstr code .) system-get cmd))
55+ $if (eqv? code 0) (eval (list $def! var rstr) d)
56+ (cmd-fail cmd))
57+);
58+$defv/e! $assert (derive-environment std.environments std.strings env_SHBuild_)
59+ (&var &pred? &msg) d
60+ $unless ($and? (eval (list $binds1? d var) d) ((eval pred? d) (eval var d)))
61+ (SHBuild_RaiseError_ (++ "Variable " (SHBuild_QuoteS_
62+ (symbol->string var)) " shall " (eval msg d) "."));
63+$provide!
64+(
65+ $assert-nonempty
66+ $assert-absolute-path
67+)
68+(
69+ $def! mods derive-environment std.strings env_SHBuild_;
70+ $set! mods $assert $assert;
71+
72+ "TODO", "Use 'string?'.";
73+ $defv/e! $assert-nonempty mods (&var) d
74+ eval (list $assert var ($lambda (str) not? (string-empty? str))
75+ "be a string of nonempty value") d;
76+ $defv/e! $assert-absolute-path mods (&var) d
77+ eval (list $assert var SHBuild_String_absolute_path?_
78+ "be a string of absolute path") d
79+);
4780
4881 "NOTE", "Saving environments at first to avoid being overriden unexpectedly.";
4982 $provide! (safeenv-get safeenv-set ss-verbose-puts)
@@ -77,58 +110,55 @@
77110 log-set name val;
78111 env-set name val
79112 ),
80- $defl/e! ss-verbose-puts mods (str)
81- ($if SS_Verbose (puts str))
113+ $defl/e! ss-verbose-puts mods (str) $if SS_Verbose (puts str)
82114 );
83-$defl! safeenv-empty? (&n) string-empty? (safeenv-get n);
84-$defl! safeenv-restore (&n) safeenv-set n (safeenv-get n);
115+$provide! (safeenv-empty? safeenv-restore)
116+(
117+ $def! mods derive-environment std.strings;
118+ $set! mods (safeenv-get safeenv-set) list safeenv-get safeenv-set;
119+ $defl/e! safeenv-empty? mods (&n) string-empty? (safeenv-get n),
120+ $defl/e! safeenv-restore mods (&n) safeenv-set n (safeenv-get n)
121+);
122+$provide!
123+(
124+ $lazy-env-val
125+ $env-de!
126+)
127+(
128+ $def! mods derive-environment std.strings std.promises std.environments
129+ std.system env_SHBuild_;
130+ $set! mods safeenv-get safeenv-get;
85131
86-$defv! $lazy-env-val (name .vexpr) d
87- $lazy/e (() lock-current-environment)
88- $let ((t safeenv-get name)) $if (string-empty? t) (eval vexpr d) t;
89-$defv! $env-de! (var .vexpr) d
90- $let ((t safeenv-get (symbol->string var)))
91- eval (list $def! var
92- ($if (string-empty? t) (list (unwrap eval) vexpr d) t)) d;
93-$defv! $set-system-var! (var arg) d
94- $unless (eval (list $binds1? d var) d)
95- ($let* ((cmd eval arg d) ((rstr code .) system-get cmd))
96- $if (eqv? code 0)
97- (eval (list $def! var rstr) d)
98- (SHBuild_RaiseError_ (cmd-error-msg_ cmd)));
99-$defv! $assert (var pred? msg) d
100- $unless ($and? (eval (list $binds1? d var) d) (pred? (eval var d)))
101- (SHBuild_RaiseError_ (++ "Variable " (SHBuild_QuoteS_
102- (symbol->string var)) " shall " msg "."));
103-"TODO", "Use 'string?'.";
104-$defv! $assert-nonempty (var) d
105- eval (list $assert var ($lambda (str) not? (string-empty? str))
106- "be a string of nonempty value") d;
107-$defv! $assert-absolute-path (var) d
108- eval (list $assert var SHBuild_String_absolute_path?_
109- "be a string of absolute path") d;
110-$defl! cons-cmd (.xs)
111- apply ++ (map1 ($lambda (str) $if (string-empty? str) "" (++ str " ")) xs);
132+ $defv/e! $lazy-env-val mods (&name .&body) d
133+ $lazy/e (() lock-current-environment)
134+ $let ((t safeenv-get name)) $if (string-empty? t)
135+ (eval (move! body) d) t;
136+ $defv/e! $env-de! mods (&var .&body) d
137+ $let ((t safeenv-get (symbol->string var)))
138+ eval (list $def! var
139+ ($if (string-empty? t)
140+ (list (unwrap eval) (move! body) d) t)) d;
141+);
112142
113-$defl! SHBuild_CheckUName_Case_ (x) $cond
114- ((rmatch? x ".*Darwin.*") "OS_X")
115- (($or? (rmatch? x ".*MSYS.*") (rmatch? x ".*MINGW.*")) "Win32")
116- ((rmatch? x ".*Linux.*") "Linux")
117- (#t "unknown");
118-$defl! SHBuild_CheckUNameM_Case_ (x) $cond
119- ((rmatch? x "x86_64|i.*86-64") "x86_64")
120- ((rmatch? x "i.*86") x)
121- ((rmatch? x "aarch64") x)
122- (#t "unknown");
143+$provide! (SHBuild_Env_OS SHBuild_Env_Arch)
144+(
145+ $defl! SHBuild_CheckUName_Case_ (&x) $cond
146+ ((rmatch? x ".*Darwin.*") "OS_X")
147+ (($or? (rmatch? x ".*MSYS.*") (rmatch? x ".*MINGW.*")) "Win32")
148+ ((rmatch? x ".*Linux.*") "Linux")
149+ (#t "unknown");
150+ $defl! SHBuild_CheckUNameM_Case_ (x) $cond
151+ ((rmatch? x "x86_64|i.*86-64") "x86_64")
152+ ((rmatch? x "i.*86") x)
153+ ((rmatch? x "aarch64") x)
154+ (#t "unknown");
123155
124-"XXX", "'SHBuild_CheckUName_*' depend on the external command 'uname'";
125-$env-de! SHBuild_Env_OS ($set-system-var! SHBuild_Env_uname "uname";
126- SHBuild_CheckUName_Case_ SHBuild_Env_uname),
127-$env-de! SHBuild_Env_Arch ($set-system-var! SHBuild_Env_uname_m "uname -m";
128- SHBuild_CheckUNameM_Case_ SHBuild_Env_uname_m);
129-
130-$defl! win32? (os) eqv? os "Win32";
131-
156+ "XXX", "'SHBuild_CheckUName_*' depend on the external command 'uname'";
157+ $env-de! SHBuild_Env_OS ($set-system-var! SHBuild_Env_uname "uname";
158+ SHBuild_CheckUName_Case_ SHBuild_Env_uname),
159+ $env-de! SHBuild_Env_Arch ($set-system-var! SHBuild_Env_uname_m "uname -m";
160+ SHBuild_CheckUNameM_Case_ SHBuild_Env_uname_m);
161+);
132162 $defl! SHBuild_GetPlatformStrings ()
133163 (
134164 $env-de! SHBuild_Host_OS SHBuild_Env_OS;
@@ -144,6 +174,8 @@
144174
145175 $def! nul_dev_ $if (win32? SHBuild_Env_OS) "NUL" "/dev/null";
146176
177+$import! std.system system-get system-quote;
178+
147179 $defl! system-or-puts (cmd str) $let (((rstr code .)
148180 system-get (cons-cmd cmd (system-quote str) "2>" nul_dev_)))
149181 $if (eqv? code 0) rstr str;
@@ -163,6 +195,9 @@
163195 search (list "TMPDIR" "TEMP" "TMP");
164196 );
165197
198+$import! std.strings ++;
199+$import! env_SHBuild_ SHBuild_MakeTempFilename;
200+
166201 $def! SHBuild_Env_TempDir () SHBuild_GetTempDir;
167202 $defl! mktmp_ () SHBuild_MakeTempFilename (++ SHBuild_Env_TempDir "/") "";
168203 "NOTE", "Suffix is now hard-coded. The suffix makes the output of the compiler",
@@ -173,6 +208,8 @@
173208 "The output path cannot be '/dev/null'. See http://sourceforge.net/p/msys2/discussion/general/thread/2d6adff2/?limit=25.";
174209 $defl! with-tmp-file_ (tmp-file f)
175210 (
211+ $import! std.system remove-file;
212+
176213 $def! r f tmp-file;
177214 $unless (remove-file tmp-file)
178215 (putss "Warning: Failed to remove temporary file '" tmp-file "'");
@@ -181,6 +218,8 @@
181218
182219 $defl! compile-ok (src compile out opt err-out)
183220 (
221+ $import! std.strings string<-;
222+
184223 $unless (safeenv-empty? "SHELL")
185224 (string<- src (system-quote src));
186225 system-ok (cons-cmd "echo" src "|" (system-quote compile) "-pipe" "-xc++"
@@ -192,8 +231,8 @@
192231 $defl! compile-ok-silent (src compile opt)
193232 compile-ok-discard_ src compile opt nul_dev_;
194233
195-$defl! SHBuild_EchoVar_N (var) SHBuild_EchoVar var
196- (safeenv-get (SHBuild_SDot_ var));
234+$defl/e! SHBuild_EchoVar_N (derive-current-environment env_SHBuild_) (var)
235+ SHBuild_EchoVar var (safeenv-get (SHBuild_SDot_ var));
197236
198237 $defl! SHBuild_GetSystemPrefix (platform) $cond
199238 ((eqv? platform "MinGW64") "/mingw64")
@@ -201,6 +240,8 @@
201240 (#t "/usr");
202241 $defl! SHBuild_Platform_Detect (os arch)
203242 (
243+ $import! env_SHBuild_ SHBuild_RaiseError_;
244+
204245 $env-de! MSYSTEM;
205246 $cond
206247 ((win32? os) $cond
@@ -227,8 +268,14 @@
227268 );
228269
229270 $defl! SHBuild_CheckCXX (host-os cxx)
271+(
272+ $import! std.strings string->symbol,
273+ $import! std.promises $lazy force;
274+
230275 $let ((e SHBuild_CmdCache_GetEnv_ host-os) (sym string->symbol cxx))
231276 (
277+ $import! std.environments bound?;
278+
232279 $unless (eval (list bound? cxx) e)
233280 (
234281 eval (list $def! sym ($lazy
@@ -236,12 +283,15 @@
236283 "Clang++" "G++")) e;
237284 );
238285 force (eval% sym e)
239- );
286+ )
287+);
240288
241289 $defl! SHBuild_Extend_CallVariables ()
242290 (
243291 $defv! $prepend (svar var) d
244292 (
293+ $import! std.strings string-empty? symbol->string;
294+
245295 eval (list $env-de! svar "") d;
246296 $def! sval eval svar d;
247297 $unless (string-empty? sval)
@@ -290,6 +340,8 @@
290340 $defl! get-thread-options-silent (cxx) get-thread-options cxx nul_dev_;
291341 $defl! get-SHBOPT_ (outdir shbopt-ext use-ld)
292342 (
343+ $import! env_SHBuild_ SHBuild_TrimOptions_;
344+
293345 $def! opt cons-cmd (++ "-xd,\"" outdir "\"") shbopt-ext;
294346 SHBuild_TrimOptions_ ($if use-ld (cons-cmd opt "-xmode,2") opt)
295347 );
@@ -313,6 +365,8 @@
313365 $defl! ld-ext-noadjust_ #ignore "";
314366 $defl! ld-ext-adjust_win32_subsystem_ (host-os)
315367 (
368+ $import! std.strings string-empty?;
369+
316370 $if ($and? (win32? host-os)
317371 (string-empty? (safeenv-get "SHBuild_NoAdjustSubsystem")))
318372 (ss-verbose-puts "Added \"-mwindows\" to LDFLAGS."; "-mwindows")
@@ -341,6 +395,10 @@
341395 $defl! build-with-conf-opt (outdir host-os debug dynamic shbopt-ext app
342396 do-ld-ext do-build)
343397 (
398+ $import! std.environments value-of,
399+ $import! std.promises $lazy force,
400+ $import! env_SHBuild_ SHBuild_EchoVar SHBuild_QuoteS_ SHBuild_TrimOptions_;
401+
344402 $def! use-ld $or? dynamic app;
345403 ($env-de! CXX "g++"; safeenv-set "CXX" CXX),
346404 ($env-de! AR (SHBuild_GetAR_ host-os CXX "ar"); safeenv-set "AR" AR),
@@ -549,6 +607,7 @@
549607 $def! e_S1_SHBuild_ () system-quote (safeenv-get "SHBuild");
550608 $defl! e_rm_ (pth)
551609 (
610+ $import! std.system system;
552611 "TODO", "Avoid deletion if possible?";
553612 "XXX", "This relies on 'rm'", "Error is ignored.";
554613 system (cons-cmd "rm" (system-quote pth) cmd_noerr_)
@@ -595,6 +654,9 @@
595654 "cmd = options for the tool";
596655 $defl! BuildGCH_ (header inc tool tool-opts)
597656 (
657+ $import! env_SHBuild_ SHBuild_BuildGCH_existed_
658+ SHBuild_BuildGCH_mkpdirp_ SHBuild_TrimOptions_;
659+
598660 $def! pch ++ inc ".gch";
599661 $def! qpch system-quote pch;
600662 $if (SHBuild_BuildGCH_existed_ pch)
diff -r d1f3d524f742 -r 6ad22b72cee3 Tools/Scripts/SHBuild-common-toolchain.sh
--- a/Tools/Scripts/SHBuild-common-toolchain.sh Sat Jan 09 04:33:56 2021 +0800
+++ b/Tools/Scripts/SHBuild-common-toolchain.sh Sat Jan 23 17:00:30 2021 +0800
@@ -1,32 +1,50 @@
11 #!/usr/bin/env bash
2-# (C) 2014-2015, 2017, 2020 FrankHB.
2+# (C) 2014-2015, 2017, 2020-2021 FrankHB.
33 # Common source script: toolchain configuration.
44
55 set -e
6+
67 : "${SHBuild_ToolDir:=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)}"
78 # shellcheck source=./SHBuild-common.sh
8-. "$SHBuild_ToolDir/SHBuild-common.sh" # for SHBuild_PrepareBuild.
9-SHBuild_PrepareBuild
9+. "$SHBuild_ToolDir/SHBuild-common.sh" # for SHBuild_PrepareBuild,
10+# SHBuild_AssertNonempty;
11+SHBuild_PrepareBuild # for SHBuild_Env_TempDir;
12+
13+# Check the availablity of the compiler by trying to compile the specified
14+# source.
15+# If the compiler is executable, The result is specified in the output.
16+# Params: $1 = path of the compiler.
17+# Params: $2 = the source to compile.
18+# Params: $3 = optional output on success.
19+# Params: $4 = optional output on failure.
20+SHBuild_CheckCompiler()
21+{
22+ local compile="$1"
23+ local src="$2"
24+ SHBuild_AssertNonempty compile
25+ SHBuild_AssertNonempty src
26+ # NOTE: The output path cannot be '/dev/null'. See http://sourceforge.net/p/msys2/discussion/general/thread/2d6adff2/?limit=25.
27+ if [[ "$compile" != */* ]] && (hash "$compile" > /dev/null 2>& 1) \
28+ || [[ "$compile" == */* && ! -d "$compile" && -x "$compile" ]]; then
29+ # XXX: %SHBuild_Env_TempDir is external.
30+ # shellcheck disable=2154
31+ if echo "$src" | "$compile" \
32+ -xc -o"$SHBuild_Env_TempDir/null" - 2> /dev/null; then
33+ SHBuild_Put "$3"
34+ else
35+ SHBuild_Put "$4"
36+ fi
37+ else
38+ SHBuild_Put ""
39+ fi
40+}
1041
1142 # Check the availablity of the C compiler.
1243 # The result is the style supported: either "Clang", "GCC" or invalid.
1344 # Params: $1 = path of the C compiler.
1445 SHBuild_CheckCC()
1546 {
16- # NOTE: The output path cannot be '/dev/null'. See http://sourceforge.net/p/msys2/discussion/general/thread/2d6adff2/?limit=25.
17- if [[ "$1" != */* ]] && (hash "$1" > /dev/null 2>& 1) \
18- || [[ "$1" == */* && ! -d "$1" && -x "$1" ]]; then
19- # XXX: %SHBuild_Env_TempDir is external.
20- # shellcheck disable=2154
21- if echo 'int main(void){return __clang__;}' | "$1" \
22- -xc -o"$SHBuild_Env_TempDir/null" - 2> /dev/null; then
23- SHBuild_Put "Clang"
24- else
25- SHBuild_Put "GCC"
26- fi
27- else
28- SHBuild_Put ""
29- fi
47+ SHBuild_CheckCompiler "$1" 'int main(void){return __clang__;}' "Clang" "GCC"
3048 }
3149
3250 # Check the availablity of the C++ compiler.
@@ -34,18 +52,7 @@
3452 # Params: $1 = path of the C++ compiler.
3553 SHBuild_CheckCXX()
3654 {
37- # NOTE: As %SHBuild_CheckCC.
38- if [[ "$1" != */* ]] && (hash "$1" > /dev/null 2>& 1) \
39- || [[ "$1" == */* && ! -d "$1" && -x "$1" ]]; then
40- if echo 'int main(){return __clang__;}' | "$1" \
41- -xc++ -o"$SHBuild_Env_TempDir/null" - 2> /dev/null; then
42- SHBuild_Put "Clang++"
43- else
44- SHBuild_Put "G++"
45- fi
46- else
47- SHBuild_Put ""
48- fi
55+ SHBuild_CheckCompiler "$1" 'int main(){return __clang__;}' "Clang++" "G++"
4956 }
5057
5158 SHBuild_GetAR_()
diff -r d1f3d524f742 -r 6ad22b72cee3 YBase/include/ystdex/string.hpp
--- a/YBase/include/ystdex/string.hpp Sat Jan 09 04:33:56 2021 +0800
+++ b/YBase/include/ystdex/string.hpp Sat Jan 23 17:00:30 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2012-2020 FrankHB.
2+ © 2012-2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file string.hpp
1212 \ingroup YStandardEx
1313 \brief ISO C++ 标准字符串扩展。
14-\version r3132
14+\version r3135
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 304
1717 \par 创建时间:
1818 2012-04-26 20:12:19 +0800
1919 \par 修改时间:
20- 2020-10-26 16:37 +0800
20+ 2021-01-22 17:33 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -176,7 +176,8 @@
176176 basic_string(const base& str)
177177 : base(str)
178178 {}
179- basic_string(base&& str)
179+ //! \since build 908
180+ basic_string(base&& str) ynothrow
180181 : base(std::move(str))
181182 {}
182183 basic_string(const basic_string&) = default;
diff -r d1f3d524f742 -r 6ad22b72cee3 YFramework/include/NPL/NPLA1.h
--- a/YFramework/include/NPL/NPLA1.h Sat Jan 09 04:33:56 2021 +0800
+++ b/YFramework/include/NPL/NPLA1.h Sat Jan 23 17:00:30 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2014-2020 FrankHB.
2+ © 2014-2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1.h
1212 \ingroup NPL
1313 \brief NPLA1 公共接口。
14-\version r8473
14+\version r8475
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 472
1717 \par 创建时间:
1818 2014-02-02 17:58:24 +0800
1919 \par 修改时间:
20- 2020-11-18 14:46 +0800
20+ 2021-01-20 06:06 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -1513,7 +1513,7 @@
15131513 \note 仅在 TCO 动作存在时支持。
15141514 \since build 896
15151515 */
1516-YB_ATTR_nodiscard YB_PURE YF_API observer_ptr<const ValueObject>
1516+YB_ATTR_nodiscard YF_API observer_ptr<const ValueObject>
15171517 QueryTailOperatorName(const Reducer&);
15181518
15191519 /*!
diff -r d1f3d524f742 -r 6ad22b72cee3 YFramework/source/NPL/Dependency.cpp
--- a/YFramework/source/NPL/Dependency.cpp Sat Jan 09 04:33:56 2021 +0800
+++ b/YFramework/source/NPL/Dependency.cpp Sat Jan 23 17:00:30 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file Dependency.cpp
1212 \ingroup NPL
1313 \brief 依赖管理。
14-\version r3938
14+\version r3996
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 623
1717 \par 创建时间:
1818 2015-08-09 22:14:45 +0800
1919 \par 修改时间:
20- 2021-01-09 04:02 +0800
20+ 2021-01-23 16:25 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -203,8 +203,7 @@
203203
204204 if(VerifyDirectory(src))
205205 throw std::invalid_argument("Source is a directory.");
206- else
207- Remove(dst);
206+ Remove(dst);
208207 TryExpr(CreateHardLink(dst, src))
209208 CatchExpr(..., InstallFile(dst, src))
210209 }
@@ -493,6 +492,16 @@
493492 RegisterStrict(ctx, "set-rest%!", SetRestRef);
494493 }
495494
495+//! \since build 908
496+void
497+LoadSymbols(ContextNode& ctx)
498+{
499+ RegisterUnary<Strict, const TokenValue>(ctx, "desigil", [](TokenValue s){
500+ return TokenValue(!s.empty() && (s.front() == '&' || s.front() == '%')
501+ ? s.substr(1) : std::move(s));
502+ });
503+}
504+
496505 void
497506 LoadEnvironments(ContextNode& ctx)
498507 {
@@ -578,6 +587,7 @@
578587 LoadControl(ctx);
579588 LoadObjects(ctx);
580589 LoadLists(ctx);
590+ LoadSymbols(ctx);
581591 LoadEnvironments(ctx);
582592 LoadCombiners(ctx);
583593 LoadErrorsAndChecks(ctx);
@@ -759,7 +769,8 @@
759769 $def! $sequence
760770 ($lambda (&se)
761771 ($lambda #ignore $vau/e% se &exprseq d
762- $if (null? exprseq) #inert (eval% (cons% $aux exprseq) d))
772+ $if (null? exprseq) #inert
773+ (eval% (cons% $aux (move! exprseq)) d))
763774 ($set! se $aux
764775 $vau/e% (weaken-environment se) (&head .&tail) d
765776 $if (null? tail) (eval% head d)
@@ -821,9 +832,10 @@
821832 $if (eval test d) (eval% (move! body) d)
822833 (apply (wrap $cond) (move! clauses) d)) (move! clauses));
823834 $defv%! $when (&test .&exprseq) d
824- $if (eval test d) (eval% (list*% () $sequence exprseq) d);
835+ $if (eval test d) (eval% (list () $sequence (move! exprseq)) d);
825836 $defv%! $unless (&test .&exprseq) d
826- $if (eval test d) #inert (eval% (list*% () $sequence exprseq) d);
837+ $if (eval test d) #inert
838+ (eval% (list () $sequence (move! exprseq)) d);
827839 $defl! not? (&x) eqv? x #f;
828840 $defv%! $and? &x d $cond
829841 ((null? x) #t)
@@ -897,14 +909,14 @@
897909 )NPL");
898910 #if NPL_Impl_NPLA1_Use_LockEnvironment
899911 context.Perform(R"NPL(
900- $def! make-standard-environment
901- $lambda () () lock-current-environment;
912+ $defl! make-standard-environment () () lock-current-environment;
902913 )NPL");
903914 #else
915+ // XXX: Ground environment is passed by 'ce'.
904916 context.Perform(R"NPL(
905917 $def! make-standard-environment
906918 ($lambda (&se &e)
907- ($lambda #ignore $vau/e se () #ignore (make-environment ce))
919+ ($lambda #ignore $lambda/e se () make-environment ce)
908920 ($set! se ce e))
909921 (make-environment (() get-current-environment))
910922 (() get-current-environment);
@@ -922,52 +934,63 @@
922934 (#t assv (forward! x) (rest% alist));
923935 $defw! derive-current-environment (.&envs) d
924936 apply make-environment (append envs (list d)) d;
937+ $def! derive-environment
938+ ($lambda (&se &e)
939+ ($lambda #ignore
940+ $lambda/e se (.&envs)
941+ apply make-environment (append envs (list ce)))
942+ ($set! se ce e))
943+ (make-environment (() get-current-environment))
944+ (() get-current-environment);
925945 $defv! $as-environment (.&body) d
926946 eval (list $let () (list $sequence (move! body)
927947 (list () lock-current-environment))) d;
928948 $defv%! $let (&bindings .&body) d
929- eval% (list*% () (list*% $lambda (map1 firstv bindings)
949+ eval% (list* () (list* $lambda (map1 firstv bindings)
930950 (list (move! body))) (map1 list-rest% bindings)) d;
931951 $defv%! $let% (&bindings .&body) d
932- eval% (list*% () (list*% $lambda% (map1 firstv bindings)
952+ eval% (list* () (list* $lambda% (map1 firstv bindings)
933953 (list (move! body))) (map1 list-rest% bindings)) d;
934954 $defv%! $let/e (&e &bindings .&body) d
935- eval% (list*% () (list*% $lambda/e e (map1 firstv bindings)
955+ eval% (list* () (list* $lambda/e e (map1 firstv bindings)
936956 (list (move! body))) (map1 list-rest% bindings)) d;
937957 $defv%! $let/e% (&e &bindings .&body) d
938- eval% (list*% () (list*% $lambda/e% e (map1 firstv bindings)
958+ eval% (list* () (list* $lambda/e% e (map1 firstv bindings)
939959 (list (move! body))) (map1 list-rest% bindings)) d;
940960 $defv%! $let* (&bindings .&body) d
941- eval% ($if (null? bindings) (list*% $let () (move! body))
942- (list% $let (list% (firstv bindings))
943- (list*% $let* (rest% bindings) (move! body)))) d;
961+ eval% ($if (null? bindings) (list* $let () (move! body))
962+ (list $let (list (firstv bindings))
963+ (list* $let* (rest% bindings) (move! body)))) d;
944964 $defv%! $let*% (&bindings .&body) d
945- eval% ($if (null? bindings) (list*% $let* () (move! body))
946- (list% $let% (list (first bindings))
947- (list*% $let*% (rest% bindings) (move! body)))) d;
965+ eval% ($if (null? bindings) (list* $let* () (move! body))
966+ (list $let% (list (first bindings))
967+ (list* $let*% (rest% bindings) (move! body)))) d;
948968 $defv%! $letrec (&bindings .&body) d
949- eval% (list $let () $sequence (list% $def! (map1 firstv bindings)
950- (list*% () list (map1 rest% bindings))) (move! body)) d;
969+ eval% (list $let () $sequence (list $def! (map1 firstv bindings)
970+ (list* () list (map1 rest% bindings))) (move! body)) d;
951971 $defv%! $letrec% (&bindings .&body) d
952- eval% (list $let% () $sequence (list% $def! (map1 firstv bindings)
953- (list*% () list (map1 rest% bindings))) (move! body)) d;
972+ eval% (list $let% () $sequence (list $def! (map1 firstv bindings)
973+ (list* () list (map1 rest% bindings))) (move! body)) d;
954974 $defv! $bindings/p->environment (&parents .&bindings) d $sequence
955975 ($def! res apply make-environment (map1 ($lambda% (x) eval% x d)
956976 parents))
957- (eval% (list% $set! res (map1 firstv bindings)
958- (list*% () list (map1 rest% bindings))) d)
977+ (eval% (list $set! res (map1 firstv bindings)
978+ (list* () list (map1 rest% bindings))) d)
959979 res;
960980 $defv! $bindings->environment (.&bindings) d
961- eval (list*% $bindings/p->environment () bindings) d;
981+ eval (list* $bindings/p->environment () bindings) d;
982+ $defl! symbols->imports (&symbols)
983+ list* () list
984+ (map1 ($lambda (&s) list forward! (desigil s)) symbols);
962985 $defv! $provide/let! (&symbols &bindings .&body) d
963- $sequence (eval% (list% $def! symbols (list $let bindings $sequence
964- (list% ($vau% (&e) d $set! e res (lock-environment d))
986+ $sequence (eval% (list $def! symbols (list $let bindings $sequence
987+ (list ($vau% (&e) d $set! e res (lock-environment d))
965988 (() get-current-environment)) (move! body)
966- (list* () list symbols))) d) res;
989+ (symbols->imports symbols))) d) res;
967990 $defv! $provide! (&symbols .&body) d
968- eval (list*% $provide/let! (forward! symbols) () (move! body)) d;
991+ eval (list* $provide/let! (forward! symbols) () (move! body)) d;
969992 $defv! $import! (&e .&symbols) d
970- eval% (list $set! d symbols (list* () list symbols)) (eval e d);
993+ eval% (list $set! d symbols (symbols->imports symbols)) (eval e d);
971994 $defl! nonfoldable? (&l)
972995 $if (null? l) #f ($if (first-null? l) #t (nonfoldable? (rest& l)));
973996 $defl%! list-extract (&l &extr)
@@ -1034,8 +1057,7 @@
10341057 });
10351058 });
10361059 context.Perform(R"NPL(
1037- $defv/e! $binds1? (make-environment
1038- (() get-current-environment) std.strings) (&e &s) d
1060+ $defv/e! $binds1? (derive-current-environment std.strings) (&e &s) d
10391061 eval (list (unwrap bound?) (symbol->string s)) (eval e d);
10401062 )NPL");
10411063 RegisterStrict(renv, "value-of", ValueOf);
@@ -1221,8 +1243,7 @@
12211243 SetEnvironmentVariable(var.c_str(), val.c_str());
12221244 });
12231245 context.Perform(R"NPL(
1224- $defl/e! env-empty?
1225- (make-environment (() get-current-environment) std.strings) (&n)
1246+ $defl/e! env-empty? (derive-current-environment std.strings) (&n)
12261247 string-empty? (env-get n);
12271248 )NPL");
12281249 RegisterStrict(renv, "system", CallSystem);
diff -r d1f3d524f742 -r 6ad22b72cee3 YFramework/source/NPL/NPLA.cpp
--- a/YFramework/source/NPL/NPLA.cpp Sat Jan 09 04:33:56 2021 +0800
+++ b/YFramework/source/NPL/NPLA.cpp Sat Jan 23 17:00:30 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2014-2020 FrankHB.
2+ © 2014-2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file NPLA.cpp
1212 \ingroup NPL
1313 \brief NPLA 公共接口。
14-\version r3424
14+\version r3428
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 663
1717 \par 创建时间:
1818 2016-01-07 10:32:45 +0800
1919 \par 修改时间:
20- 2020-11-18 14:46 +0800
20+ 2021-01-11 06:28 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -624,7 +624,7 @@
624624 TermNode&
625625 TermReference::get() const
626626 {
627- if(r_env.GetAnchorPtr() && r_env.GetPtr().lock())
627+ if(!(r_env.GetAnchorPtr() && r_env.GetPtr().expired()))
628628 return term_ref.get();
629629 throw InvalidReference("Invalid reference found on indirection, probably"
630630 " due to invalid context access by a dangling reference.");
@@ -1207,10 +1207,10 @@
12071207 }
12081208
12091209 void
1210-swap(ContextNode& x, ContextNode& y) ynothrow
1210+swap(ContextNode& x, ContextNode& y) ynothrow
12111211 {
12121212 swap(x.p_record, y.p_record),
1213- swap(x.Resolve, y.Resolve),
1213+ swap(x.Resolve, y.Resolve),
12141214 swap(x.current, y.current),
12151215 swap(x.stashed, y.stashed),
12161216 std::swap(x.LastStatus, y.LastStatus),
diff -r d1f3d524f742 -r 6ad22b72cee3 YFramework/source/NPL/NPLA1.cpp
--- a/YFramework/source/NPL/NPLA1.cpp Sat Jan 09 04:33:56 2021 +0800
+++ b/YFramework/source/NPL/NPLA1.cpp Sat Jan 23 17:00:30 2021 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2014-2020 FrankHB.
2+ © 2014-2021 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1.cpp
1212 \ingroup NPL
1313 \brief NPLA1 公共接口。
14-\version r20231
14+\version r20247
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 473
1717 \par 创建时间:
1818 2014-02-02 18:02:47 +0800
1919 \par 修改时间:
20- 2020-11-18 14:50 +0800
20+ 2021-01-21 06:41 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -343,7 +343,7 @@
343343
344344 YB_ATTR_nodiscard YB_PURE PDefH(any, Query, uintmax_t) const ynothrow
345345 ImplI(IValueHolder)
346- ImplRet(ystdex::ref(source_information))
346+ ImplRet(ystdex::ref(source_information))
347347
348348 using base::get_allocator;
349349 };
@@ -651,7 +651,6 @@
651651 // with the correct implementation of the reference collapse.
652652 ResolveTerm([&, n_p, o_tags](TermNode& nd,
653653 ResolvedTermReferencePtr p_ref){
654-
655654 if(IsList(nd))
656655 {
657656 const bool ellipsis(last != t.end());
@@ -661,8 +660,9 @@
661660 {
662661 auto tags(o_tags);
663662
664- // NOTE: All tags as type qualifiers should be checked
665- // here. Currently only glvalues can be qualified.
663+ // NOTE: All tags as type qualifiers should be
664+ // checked here. Currently only glvalues can be
665+ // qualified.
666666 // XXX: Term tags are currently not respected in
667667 // prvalues.
668668 if(p_ref)
@@ -675,8 +675,8 @@
675675 tags |= ref_tags & TermTags::Nonmodifying;
676676 }
677677 MatchSubterms(t.begin(), last, nd, nd.begin(), tags,
678- p_ref ? p_ref->GetEnvironmentReference() : r_env,
679- ellipsis
678+ p_ref ? p_ref->GetEnvironmentReference()
679+ : r_env, ellipsis
680680 #if NPL_Impl_NPLA1_AssertParameterMatch
681681 , t.end()
682682 #endif
@@ -703,7 +703,7 @@
703703 else
704704 {
705705 const auto& tp(t.Value.type());
706-
706+
707707 if(tp == ystdex::type_id<TermReference>())
708708 ystdex::update_thunk(act, [&, o_tags]{
709709 Match(t.Value.GetObject<TermReference>().get(), o, o_tags,
@@ -1490,9 +1490,8 @@
14901490 // behavior?
14911491 // NOTE: The call is essentially same as %MatchParameter, with a bit better
14921492 // performance by avoiding %function instances.
1493- MakeParameterMatcher([&, check_sigil](TermNode& o_tm,
1494- TNIter first, string_view id, TermTags o_tags,
1495- const EnvironmentReference& r_env){
1493+ MakeParameterMatcher([&, check_sigil](TermNode& o_tm, TNIter first,
1494+ string_view id, TermTags o_tags, const EnvironmentReference& r_env){
14961495 YAssert(ystdex::begins_with(id, "."), "Invalid symbol found.");
14971496 id.remove_prefix(1);
14981497 if(!id.empty())
@@ -1587,6 +1586,7 @@
15871586 passes += [](TermNode& term, ContextNode& ctx){
15881587 if(IsBranchedList(term))
15891588 ContextState::Access(ctx).SetCombiningTermRef(term);
1589+ return ReductionStatus::Neutral;
15901590 };
15911591 passes += ReduceFirst;
15921592 # endif
@@ -1656,6 +1656,11 @@
16561656 }, val.try_get_object_ptr<SourceInfoMetadata>());
16571657 }
16581658
1659+#if NPL_Impl_NPLA1_Enable_TCO
1660+YB_PURE
1661+#else
1662+YB_STATELESS
1663+#endif
16591664 observer_ptr<const ValueObject>
16601665 QueryTailOperatorName(const Reducer& act)
16611666 {
diff -r d1f3d524f742 -r 6ad22b72cee3 YFramework/source/NPL/NPLA1Forms.cpp
--- a/YFramework/source/NPL/NPLA1Forms.cpp Sat Jan 09 04:33:56 2021 +0800
+++ b/YFramework/source/NPL/NPLA1Forms.cpp Sat Jan 23 17:00:30 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Forms.cpp
1212 \ingroup NPL
1313 \brief NPLA1 语法形式。
14-\version r19640
14+\version r19731
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2014-02-15 11:19:51 +0800
1919 \par 修改时间:
20- 2021-01-08 19:20 +0800
20+ 2021-01-23 15:43 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -31,18 +31,18 @@
3131 // ThrowInsufficientTermsError, NPL::Deref, A1::NameTypedReducerHandler,
3232 // ReduceReturnUnspecified, RemoveHead, IsBranch, AccessFirstSubterm,
3333 // ReduceNextCombinedBranch, std::placeholders, ystdex::as_const, IsLeaf,
34-// ystdex::ref_eq, ContextHandler, shared_ptr, string, unordered_map,
35-// Environment, lref, list, IsBranchedList, TokenValue, NPL::TryAccessLeaf,
36-// ValueObject, weak_ptr, any_ops::use_holder, in_place_type, ystdex::type_id,
37-// YSLib::allocate_shared, InvalidReference, MoveFirstSubterm, ShareMoveTerm,
38-// ThrowInvalidSyntaxError, ReduceCombinedBranch, ResolvedTermReferencePtr,
39-// LiftOtherOrCopy, ResolveTerm, ystdex::equality_comparable,
40-// std::allocator_arg, NPL::AsTermNode, ystdex::exchange,
41-// NPL::SwitchToFreshEnvironment, TermTags, ystdex::expand_proxy,
42-// NPL::AccessRegular, TermReference, GetLValueTagsOf, RegularizeTerm,
43-// ThrowValueCategoryError, ThrowListTypeErrorForNonlist, ystdex::update_thunk,
44-// NPL::TryAccessReferencedLeaf, ystdex::invoke_value_or,
45-// ystdex::call_value_or, RelaySwitched, LiftMovedOther, LiftCollapsed,
34+// ystdex::ref_eq, RelaySwitched, ContextHandler, shared_ptr, string,
35+// unordered_map, Environment, lref, list, IsBranchedList, TokenValue,
36+// NPL::TryAccessLeaf, ValueObject, weak_ptr, any_ops::use_holder,
37+// in_place_type, ystdex::type_id, YSLib::allocate_shared, InvalidReference,
38+// MoveFirstSubterm, ShareMoveTerm, ThrowInvalidSyntaxError,
39+// ReduceCombinedBranch, ResolvedTermReferencePtr, LiftOtherOrCopy,
40+// ResolveTerm, ystdex::equality_comparable, std::allocator_arg,
41+// NPL::AsTermNode, ystdex::exchange, NPL::SwitchToFreshEnvironment, TermTags,
42+// ystdex::expand_proxy, NPL::AccessRegular, TermReference, GetLValueTagsOf,
43+// RegularizeTerm, ThrowValueCategoryError, ThrowListTypeErrorForNonlist,
44+// ystdex::update_thunk, NPL::TryAccessReferencedLeaf, ystdex::invoke_value_or,
45+// ystdex::call_value_or, LiftMovedOther, LiftCollapsed,
4646 // ystdex::make_transform, NPL::AllocateEnvironment, NPL::TryAccessTerm,
4747 // std::mem_fn;
4848 #include "NPLA1Internals.h" // for A1::Internals API;
@@ -259,6 +259,7 @@
259259 YB_PURE inline PDefH(bool, TermUnequal, const TermNode& x, const TermNode& y)
260260 ImplRet(x.size() != y.size() || x.Value != y.Value)
261261
262+#if NPL_Impl_NPLA1_Enable_Thunked
262263 ReductionStatus
263264 EqualSubterm(bool& r, ContextNode& ctx, bool orig, TNCIter first1,
264265 TNCIter first2, TNCIter last1)
@@ -274,8 +275,12 @@
274275 return ReductionStatus::Clean;
275276 }
276277 yunseq(++first1, ++first2);
278+ // XXX: The continuations in the middle are not required to be
279+ // preserved.
277280 RelaySwitched(ctx, [&, first1, first2, last1]{
278- return EqualSubterm(r, ctx, {}, first1, first2, last1);
281+ // XXX: This is not effective if the result is known to be false.
282+ return r ? EqualSubterm(r, ctx, {}, first1, first2, last1)
283+ : ReductionStatus::Neutral;
279284 });
280285 return RelaySwitched(ctx, [&]{
281286 return
@@ -284,6 +289,25 @@
284289 }
285290 return orig ? ReductionStatus::Clean : ReductionStatus::Partial;
286291 }
292+#else
293+//! \since build 908
294+bool
295+EqualSubterm(TNCIter first1, TNCIter first2, TNCIter last1)
296+{
297+ if(first1 != last1)
298+ {
299+ auto& x(ReferenceTerm(*first1));
300+ auto& y(ReferenceTerm(*first2));
301+
302+ if(TermUnequal(x, y))
303+ return {};
304+ yunseq(++first1, ++first2);
305+ return EqualSubterm(x.begin(), y.begin(), x.end())
306+ && EqualSubterm(first1, first2, last1);
307+ }
308+ return true;
309+}
310+#endif
287311 //@}
288312
289313
@@ -1887,11 +1911,13 @@
18871911 auto& rterm(*term.emplace(ystdex::exchange(con, TermNode::Container(
18881912 {std::move(lv_sum), std::move(nterm)}, a))));
18891913
1890- RelaySwitched(ctx, A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
1914+ return A1::ReduceCurrentNext(rterm, ctx,
1915+ [&](TermNode& t, ContextNode& c){
1916+ return AccRImpl(t, c, sum);
1917+ }, A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
18911918 SetupTailContext(ctx, term);
18921919 return RelayCombinedTail(ctx, term, d);
18931920 }, "eval-accr-sum"));
1894- return AccRImpl(rterm, ctx, sum);
18951921 }, "eval-accr-accr"));
18961922 }, term, ctx);
18971923 }
@@ -1928,8 +1954,7 @@
19281954 YAssert(nterm.empty(), "Invalid term found.");
19291955 if(NPL::Deref(p_ref).IsReferencedLValue())
19301956 {
1931- if(const auto p
1932- = NPL::TryAccessLeaf<const TermReference>(tm_first))
1957+ if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm_first))
19331958 nterm.SetContent(tm_first);
19341959 else
19351960 ReduceToReferenceAt(nterm, tm_first, p_ref);
@@ -1946,8 +1971,8 @@
19461971 ncon.emplace_back(tm);
19471972 else
19481973 // XXX: Same to %ReduceToReferenceAt.
1949- ncon.emplace_back(NPL::AsTermNode(TermReference(
1950- tm.Tags, tm,
1974+ ncon.emplace_back(
1975+ NPL::AsTermNode(TermReference(tm.Tags, tm,
19511976 NPL::Deref(p_ref).GetEnvironmentReference())));
19521977 }
19531978 l.Value.Clear();
@@ -1986,14 +2011,14 @@
19862011 TermNode::Container({std::move(lv_kons), std::move(nterm)},
19872012 term.get_allocator()))));
19882013
1989- RelaySwitched(ctx, A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
2014+ nterm.ClearContainer();
2015+ return A1::ReduceCurrentNext(rterm, ctx,
2016+ [&](TermNode& t, ContextNode& c){
2017+ return FoldR1Impl(t, c, kons);
2018+ }, A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
19902019 SetupTailContext(ctx, term);
19912020 return RelayCombinedTail(ctx, term, d);
19922021 }, "eval-foldr1-kons"));
1993- nterm.ClearContainer();
1994- return RelaySwitched(ctx, [&]{
1995- return FoldR1Impl(rterm, ctx, kons);
1996- });
19972022 }
19982023 LiftOther(term, knil);
19992024 return ReductionStatus::Retained;
@@ -2022,7 +2047,11 @@
20222047 TermNode::Container({TermNode({std::move(lv_appv),
20232048 std::move(nterm)}, a)}, a))));
20242049
2025- RelaySwitched(ctx, A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
2050+ nterm.ClearContainer();
2051+ return A1::ReduceCurrentNext(rterm, ctx,
2052+ [&](TermNode& t, ContextNode& c){
2053+ return Map1Impl(t, c, appv);
2054+ }, A1::NameTypedReducerHandler([&, d]() YB_FLATTEN{
20262055 return ReduceCallSubsequent(*term.begin(), ctx, d,
20272056 A1::NameTypedReducerHandler([&]() YB_FLATTEN{
20282057 auto i_term(term.begin());
@@ -2032,28 +2061,45 @@
20322061 return ReductionStatus::Retained;
20332062 }, "eval-map1-cons"));
20342063 }, "eval-map1-appv"));
2035- nterm.ClearContainer();
2036- return RelaySwitched(ctx, [&]{
2037- return Map1Impl(rterm, ctx, appv);
2038- });
20392064 }
20402065 term.Clear();
20412066 return ReductionStatus::Regular;
20422067 }, lv_l);
20432068 }
20442069
2070+//! \since build 908
20452071 YB_FLATTEN void
2046-AccFoldR1(TermNode& term, ContextNode& ctx, TermNode& rterm, ptrdiff_t n)
2072+AccFoldR1(TermNode& term, TermNode& rterm, ptrdiff_t n)
20472073 {
20482074 auto& sum(*std::next(rterm.begin(), n));
20492075
20502076 term.emplace(std::move(sum));
20512077 sum.Value.Clear();
20522078 rterm.GetContainerRef().emplace_back();
2053- RelaySwitched(ctx, A1::NameTypedReducerHandler([&]{
2079+}
2080+
2081+//! \since build 908
2082+template<typename _func>
2083+YB_FLATTEN ReductionStatus
2084+AccFoldR1LiftSum(TermNode& term, ContextNode& ctx, TermNode& rterm,
2085+ _func f, TermNode::Container& con)
2086+{
2087+ using namespace std::placeholders;
2088+
2089+#if NPL_Impl_NPLA1_Enable_Thunked
2090+ return A1::ReduceCurrentNext(rterm, ctx,
2091+ std::bind([&](_func& acc, TermNode& t, ContextNode& c){
2092+ return acc(t, c, con.back());
2093+ }, std::move(f), _1, _2), A1::NameTypedReducerHandler([&]{
20542094 LiftOther(term, rterm);
20552095 return ctx.LastStatus;
20562096 }, "eval-lift-sum"));
2097+#else
2098+ const auto res(f(rterm, ctx, con.back()));
2099+
2100+ LiftOther(term, rterm);
2101+ return res;
2102+#endif
20572103 }
20582104
20592105 template<typename _func>
@@ -2064,8 +2110,8 @@
20642110 auto& rterm(*term.emplace(ystdex::exchange(con,
20652111 TermNode::Container(term.get_allocator()))));
20662112
2067- AccFoldR1(term, ctx, rterm, 1);
2068- return f(rterm, ctx, con.back());
2113+ AccFoldR1(term, rterm, 1);
2114+ return AccFoldR1LiftSum(term, ctx, rterm, std::move(f), con);
20692115 }
20702116 //@}
20712117
@@ -2145,9 +2191,14 @@
21452191 term.Value = false;
21462192 return ReductionStatus::Clean;
21472193 }
2194+#if NPL_Impl_NPLA1_Enable_Thunked
21482195 term.Value = true;
21492196 return EqualSubterm(term.Value.GetObject<bool>(), ctx, true, x.begin(),
21502197 y.begin(), x.end());
2198+#else
2199+ term.Value = EqualSubterm(x.begin(), y.begin(), x.end());
2200+ return ReductionStatus::Clean;
2201+#endif
21512202 }, static_cast<const TermNode&(&)(const TermNode&)>(ReferenceTerm));
21522203 }
21532204
@@ -2778,8 +2829,8 @@
27782829 TermNode::Container(term.get_allocator()))));
27792830
27802831 rterm.GetContainerRef().emplace_back();
2781- AccFoldR1(term, ctx, rterm, 6);
2782- return AccRImpl(rterm, ctx, con.back());
2832+ AccFoldR1(term, rterm, 6);
2833+ return AccFoldR1LiftSum(term, ctx, rterm, AccRImpl, con);
27832834 }
27842835
27852836 ReductionStatus
diff -r d1f3d524f742 -r 6ad22b72cee3 doc/ChangeLog.V0.9.txt
--- a/doc/ChangeLog.V0.9.txt Sat Jan 09 04:33:56 2021 +0800
+++ b/doc/ChangeLog.V0.9.txt Sat Jan 23 17:00:30 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file ChangeLog.V0.9.txt
1212 \ingroup Documentation
1313 \brief 版本更新历史记录 - V0.9 。
14-\version r1983
14+\version r2129
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 800
1717 \par 创建时间:
1818 2020-10-12 17:19:23 +0800
1919 \par 修改时间:
20- 2021-01-09 04:08 +0800
20+ 2021-01-23 16:59 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -31,6 +31,151 @@
3131 // Scope: [b900, $now];
3232
3333 $now
34+(
35+ / %Tools.Scripts $=
36+ (
37+ / DLDI "simplified '$lambda'" @ "development tools build calls",
38+ / @ "%SHBuild-common-toolchain.sh" $=
39+ (
40+ + "function %SHBuild_CheckCompiler";
41+ / DLDI "simplified functions %(SHBuild_CheckCC, SHBuild_CheckCXX)"
42+ ),
43+ / @ "%SHBuild-YSLib-common.txt" $=
44+ (
45+ / DLDI "reordered imports",
46+ (
47+ / DLI "made static environment closed and avoided imports"
48+ @ "applicative 'rmatch?'";
49+ - "top-level imports ('regex-match?', 'string->regex')"
50+ ),
51+ (
52+ / DLDI "avoided imports"
53+ ^ $dep_from ('derive-environment' @ %YFramework.NPL.Dependency);
54+ - $impl "imports from 'std.strings'",
55+ - $impl "top-level import 'system'"
56+ ),
57+ / DLDI "simplified applicative 'ss-verbose-puts'",
58+ / DLI "made static environment closed"
59+ @ "applicatives ('safeenv-empty?, 'safeenv-restore')"
60+ ^ '$defl/e!' ~ '$defl!',
61+ / DLI "function parameters" ^ '&',
62+ * "missing evaluation on the predicate and message parameters"
63+ @ "operative '$assert'" $since b837
64+ // This worked occasionally for operatives '$assert-nonempty' \
65+ and '$assert-absolute-path' which called '$assert'.
66+ )
67+ ),
68+ * DD "wrong applicative %rest" @ %Documentation.NPL $mismatch $since b875,
69+ $= (/ "%rest" => "%restv"),
70+ * "missing 'ynothrow'" @ "constructor for moving from the base object"
71+ @ "class template %basic_string" @ %YBase.YStandardEx.String
72+ $since b833,
73+ / %YFramework $=
74+ (
75+ / %NPL $=
76+ (
77+ / @ "member function %TermReference::get"
78+ @ 'NPL_NPLA_CheckTermReferenceIndirection' @ %NPLA $=
79+ (
80+ / DLI "simplified" ^ 'expire' ~ 'lock',
81+ * "always failed check without the associatd environment"
82+ $since b876
83+ ),
84+ / @ "namespace %Forms" @ %NPLA1Forsm $=
85+ (
86+ / @ "functions %(AccR, FoldR1, Map1)" $=
87+ (
88+ * "unexpected early return"
89+ @ '!NPL_Impl_NPLA1_Enable_Thunked' $effective @ ("%AccR"
90+ $since b898, "%(FordR1, Map1)" $since b899) $=
91+ (
92+ / $impl ^ "%A1::ReduceCurrentNext" ~ "%RelaySwitched",
93+ / $impl !^ "%ContextNode::LastStatus"
94+ // See $2021-01 @ %Documentation::Workflow.
95+ ),
96+ / "avoided redundant %RelaySwitched calls"
97+ @ 'NPL_Impl_NPLA1_Enable_Thunked'
98+ // This was redundant because it actually does not \
99+ construct recursive calls in C++.
100+ ),
101+ / @ "function %EqualTermValue" $=
102+ (
103+ / DLI "avoided redundant accesses for short circuit \
104+ evaluations" @ 'NPL_Impl_NPLA1_Enable_Thunked',
105+ * "unexpected early return"
106+ @ !'NPL_Impl_NPLA1_Enable_Thunked' $since b904
107+ // See $2021-01 @ %Documentation::Workflow.
108+ )
109+ ),
110+ / DLDI %NPLA1 $=
111+ (
112+ + DLI 'YB_STATELESS' @ "function %QueryTailOperatorName"
113+ @ '!NPL_Impl_NPLA1_Enable_TCO',
114+ // To eliminate G++ 10.2 warning: \
115+ [-Wsuggest-attribute=const].
116+ * $design "missing reduction status" @ "one of alternative \
117+ implementations" @ "function %SetupDefaultInterpretation"
118+ $since b895
119+ / $= (+ "returning %ReductionStatus::Neutral")
120+ // See $2021-01 @ %Documentation::Workflow.
121+ ),
122+ / %Dependency $=
123+ (
124+ / "captured environments" $effective @ ("operative '$binds1?'"
125+ @ "function %LoadModule_std_environments", "applicative \
126+ 'env-empty?'" @ "function %LoadModule_std_system") $=
127+ (
128+ / $impl ^ "'derive-current-environment'";
129+ * "missing prevention of injections of 'std.strings' names \
130+ from the dynamic environment on the call site" $comp
131+ $since b839
132+ // The order of parent environments counts.
133+ ),
134+ / @ "function %LoadGroundContext" $=
135+ (
136+ / @ "applicative 'make-standard-environment'" $=
137+ (
138+ / DLDI "simplified derivations"
139+ / "unwrappable applicative provided" @ $since b802
140+ $= (/ $impl ^ '$lambda/e' ~ '$vau/e')
141+ ),
142+ + "applicative 'derive-environment'",
143+ / DLI "moved 'exprseq'" $effective
144+ @ "alternative derivation"
145+ @ "operatives ('$sequence', '$when', '$unless')"
146+ / $= (/ ^ 'move!'),
147+ / DLDI "construction of evaluation structure" ^ 'list*'
148+ ~ 'list*%' $effective @ ("alternative derivations"
149+ @ "operatives ('$when', '$unless')",
150+ "operatives ('$let', '$let%', '$let/e', '$let/e%', \
151+ '$let*', '$let*%', '$letrec', '$letrec%', \
152+ '$bindings/p->environment', '$bindings->environment', \
153+ $provide!)"),
154+ / DLDI "construction of evaluation structure" ^ 'list'
155+ ~ 'list*' $effective @ "operatives '$let*', '$let*%', \
156+ '$letrec', '$letrec%', '$bindings/p->environment', \
157+ $provide/let!)",
158+ // Also make the implementations consistent to ones of \
159+ operatives like '$defl!' and functions in other \
160+ modules.
161+ / DLDI "combined groups of primitive register calls",
162+ (
163+ + "applicative %desigil";
164+ + "applicative 'symbols->imports'";
165+ / ("supported sigil support for '&' and '%' and forwarding \
166+ imports", "forwarding imports") @ "operatives \
167+ ('$provide/let!'; '$provide!', '$import!')"
168+ ^ 'symbols->imports'
169+ )
170+ ),
171+ / DLDI "simplified function %InstallHardLink"
172+ )
173+ )
174+ )
175+),
176+
177+b907
178+(
34179 / %Tools $=
35180 (
36181 / %Scripts $=
@@ -186,7 +331,7 @@
186331 (
187332 / DLDI "simplified operatives ('$let*', '$let*%')"
188333 - "operative '$let/d%'",
189- // See $2020-01 @ %Documentation::Workflow.
334+ // See $2021-01 @ %Documentation::Workflow.
190335 (
191336 / "operative '$provide/d!'" -> '$provide/let!'
192337 $dep_from "removal of calls to '$provide/let!'";
@@ -196,7 +341,7 @@
196341 ),
197342 * "wrong parent environment constructed"
198343 @ "operative '$bindings->environment'" $since b839,
199- // See $2020-01 @ %Documentation::Workflow.
344+ // See $2021-01 @ %Documentation::Workflow.
200345 $= (/ $impl !^ 'make-standard-environment'),
201346 + "applicative 'derive-current-environment'",
202347 + "operative '$as-environment'"
diff -r d1f3d524f742 -r 6ad22b72cee3 doc/NPL.txt
--- a/doc/NPL.txt Sat Jan 09 04:33:56 2021 +0800
+++ b/doc/NPL.txt Sat Jan 23 17:00:30 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPL.txt
1212 \ingroup Documentation
1313 \brief NPL 规范和实现规格说明。
14-\version r17674
14+\version r19248
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 304
1717 \par 创建时间:
1818 2012-04-25 10:34:20 +0800
1919 \par 修改时间:
20- 2021-01-08 21:21 +0800
20+ 2021-01-23 16:54 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -81,15 +81,15 @@
8181 和大部分其它设计不同,为了确保一定程度的适应通用目的的性质,它们被设计整体首要考虑。这样的设计的语言是(自设计(by desing) 用于)满足通用目的的语言(general-purposed language) 。
8282
8383 @1.3 其它设计和实现参考:
84-NPL 是独立设计的语言,但它和 [RnRK](@1.1) 定义的 Kernel 有许多核心设计的相似之处,尽管设计的一些基本特征(如 @2.1.1.1 )以及基本哲学(@1.4) 相当不同(参见 @2.2.3 )。
85-NPL 的主要实现(@7) 的核心部分实质上支持了 Kernel 的形式模型(@2.1.1) —— vau 演算(vau calculi) 。具体的 NPL 语言在这些模型的基础上提供。
84+NPL 是独立设计的语言,但它和 [RnRK](@1.1) 定义的 Kernel 有许多核心设计的相似之处,尽管设计的一些基本特征(如资源可用性基本约定(@2.1.1.1) )以及基本哲学(@1.4) 相当不同。
85+NPL 的主要实现(@7) 的核心部分实质上支持了 Kernel 的形式模型(@2.1.1) —— vau 演算(vau calculi) 。(另见操作语义(@2.2.3) 。)具体的 NPL 语言在这些模型的基础上提供。
8686 NPL 的命名(@2.1) 即体现了 vau 演算和传统 λ 演算(@4.5) 为模型的语言的核心差异:
87-强调表达式(@3.4.2) 求值(@4.1) 前后的不同,特别地,关注在语言中直接表达的名称(@2.3.2) 和求值(@4.1) 后指称的实体的不同(@2.3.2) 。
87+强调表达式(@3.4.2) 求值(@4.1) 前后的不同,特别地,关注在语言中直接表达的名称(@2.3.4) 和求值(@4.1) 后指称的实体的不同(@2.3.4) 。
8888 更进一步地,NPL 普遍地支持区分一等引用(@4.2.3) 和被引用的一等实体(@4.1) 并具有更精确的资源控制机制,这是与 Kernel 的主要设计上的差异。
8989 关于 vau 演算的形式模型和其它相关内容,详见 [Shu10] 。
9090 历史上,vau 演算提供了 fexpr 类似的抽象,参见:
9191 https://en.wikipedia.org/wiki/Fexpr
92-另见 @7.8.2 。
92+另见求值算法设计的实例(@7.8.2) 。
9393 关于一些其它支持 fexpr 特性的语言设计,参见:
9494 PicoLisp :https://software-lab.de/doc/faq.html#lambda
9595 newLISP :http://www.newlisp.org/downloads/newlisp_manual.html#define-macro
@@ -196,7 +196,7 @@
196196 因此,只要可能,避免抽象泄漏。
197197
198198 @1.4.3.5 关注资源限制:
199-为了可实现性,宿主(host) 系统对总的资源(典型地,运行程序需要的存储)有未指定(@2.3.2) 的上限。
199+为了可实现性,宿主(host) 系统对总的资源(典型地,运行程序需要的存储)有未指定(@2.3.4) 的上限。
200200 除此之外,接口抽象不附加接口语义要求以外的限制。
201201 这个原则同时利于满足正确性(@1.4.3.1) 和简单性(@1.4.3.2) 。而不遵循这个原则的设计在接口描述上违反 @1.4.2.3 。
202202 在允许实现的前提下,附加具体特性上的使用限制(如 ISO C )可放宽对实现的要求;但无原则地随意选取此处的限制不足以直接证明具体的限制的有效性,而依赖实际实现的情况才能判断,造成抽象泄漏(@1.4.3.4) 。
@@ -211,7 +211,7 @@
211211 @1.4.4 结构和依赖原则:
212212
213213 @1.4.4.1 接口设计和实现分离:
214-语言设计独立于语言实现(@2.3.2) 。
214+语言设计独立于语言实现(@2.3.3) 。
215215 这是同时应用 @1.4.2.3 和 @1.4.2.4 的推论。
216216 这种分离允许避免抽象泄露(abstraction leaking) 。
217217 典型地,使用提供接口抽象层作为必要构造的架构方法,即分层设计。
@@ -266,7 +266,7 @@
266266 G1b 可扩展性(extensibility) :用户定义的设施能重现内建特性的能力。
267267 以上原则在 NPL 中略有变化。关于 G1a 的改变,详见 @4.2 。
268268 整体上的 G1b 在和 @1.4.3.1 冲突时不被要求。
269-注意 G1b 仅表示用户使用语言的扩展,不表示语言自身的可扩展性(这通过满足需求的能力 @1.4.2.1 体现),因为语言规范(@2.3.1.2) 不依赖使用对象语言(@2.3.2) 表达。
269+注意 G1b 仅表示用户使用语言的扩展,不表示语言自身的可扩展性(这通过满足需求的能力 @1.4.2.1 体现),因为语言规范(@2.3.1.2) 不依赖使用对象语言(@2.3.4) 表达。
270270
271271 @1.4.5.2 适用性(usability) :
272272 设计应提供合乎预期满足的问题领域的特性。
@@ -292,7 +292,7 @@
292292 在保持合理性的前提下,若能评估目标用户的接受能力,避免违反其直觉的设计。
293293 其中,合理性至少应蕴含正确性(@1.4.3.1) ,一般也蕴含简单性(@1.4.3.2) 和适用性(@1.4.5.2) 同时不违反其它原则(特别应注意尽量保持可复用性(@1.4.4.4) 和可组合性(@1.4.4.5) )。
294294 这个原则主要适用于人机交互接口的设计,但也适用于一般的 API 。
295-推论:约定优于配置(convention over configuration) :约定接口的合理的默认行为(@2.3.2) ,而不是隐藏其行为而提供配置另行实现。
295+推论:约定优于配置(convention over configuration) :约定接口的合理的默认行为(@2.3.4) ,而不是隐藏其行为而提供配置另行实现。
296296
297297 @1.4.5.4 正交性(orthogonality) :
298298 在满足正确性(@1.4.3.1) 的前提下,接口的设计应根据需求适当分解为排除冗余和重复(@1.4.4.4) 且能合理组合(@1.4.4.5) 的部分。
@@ -332,23 +332,23 @@
332332 @1.4.7 其它推论和比较:
333333 从对正确性(@1.4.3.1) 的强调可知,较简单性(@1.4.3.2) 优先考虑通用性(generality) 。
334334 这和 [RnRK] 中讨论的设计哲学虽然相当不同,但仍允许和 Kernel 具有相似的特性。
335-作为典型的 NPL 的一个派生实现(@2.3.2) ,NPLA1(@5) 具有以下和 Kernel 相似的核心设计:
336-相似的求值(@4.1) 算法(差异参见 @9.4 );
335+作为典型的 NPL 的一个派生实现(@2.3.4) ,NPLA1(@5) 具有以下和 Kernel 相似的核心设计:
336+相似的求值(@4.1) 算法(差异参见 NPLA1 求值算法(@9.7.1) );
337337 环境(@4.6.1.1) 可作为一等对象(@4.1) ;
338338 支持 vau 抽象(@4.5.2.3) ,且使用词法作用域(@4.6.1.1.2) ;
339339 强调表达式求值前后的不同(详见 @1.3 );
340-强调直接求值而非传统 LISP 方言的引用(@9.4) 。
340+强调直接求值而非传统 LISP 方言的 quote(@9.7.1.1) 。
341341
342342 @2 整体设计:
343343
344344 @2.1 基本原理、表达形式和抽象:
345345 具体讨论设计策略另见需求描述文档。
346-和设计原则的讨论另见 @1.4 。对本节内容的描述的理解应符合 @1.4 的原则。
346+另见设计原则(@1.4) 的讨论;对本节内容的描述的理解应符合其中的原则。
347347
348348 @2.1.1 模型:
349-可用计算机实现的语言首先是计算的模型(model of computation) ,它们对计算(computing) 进行建模。
350-与之相关地,为计算机系统建模作为计算机的模型(computational model) ,需对有限计算资源的现实进行适应。
351-这些模型可使用形式方法(formal method) 建立,即形式模型(formal model) 。
349+可用计算机实现的语言首先是计算的模型(model of computation) ,或者计算模型(@2.3.4) ,对计算(@2.3.4) 进行建模得到。
350+与之相关地,为计算机系统建模作为计算机的模型(model of computer) ,需对有限计算资源的现实进行适应。
351+这些模型可使用形式方法(@2.3.4) 建立,即形式模型(@2.3.4) 。
352352 被计算机实现的语言应同时具有两方面的特征。
353353 作为实用的语言,语言还应强调提供可编程性(programmability) 以允许用户利用;这样的语言称为编程语言(programming language) 。
354354 Turing 机、无类型 λ 演算等早期计算模型不考虑有限计算资源限制。
@@ -356,11 +356,11 @@
356356 同时,这些模型仅适合对计算建模,并没有强调允许可编程性的实现;扩充可编程设计而保持模型自身的主要性质相当困难。
357357 因此,基于计算的模型适配编程语言的设计必然需要妥协:
358358 对这些模型的裁剪和补充能提供若干编程语言的模型,但这无可避免地显著地复杂化模型自身,且不利用用户使用简单有效的规则实现通用目的上的可编程性。
359-事实上,使用严格形式化的模型描述编程语言的行为(@2.3.2) 较编程语言自身的发展更落后:
359+事实上,使用严格形式化的模型描述编程语言的行为(@2.3.4) 较编程语言自身的发展更落后:
360360 大部分编程语言并没有使用模型支持它们的设计;
361361 现实的实用语言,特别地,包括所有主流的工业语言(industrial language) ,几乎都没有在语言规范(@2.3.1.2) 中给出完整的模型;
362-通常的实用语言只形式化基本的语法(syntax) 上的规则,无法指导用户精确理解程序的含义。
363-这些落后集中体现在的语义(semantics) 模型的缺失,使对编程语言语义的判断取决于规格说明中模型外规则的理解。
362+通常的实用语言只形式化基本的语法(@2.3.4) 上的规则,无法指导用户精确理解程序的含义。
363+这些落后集中体现在的语义(@2.3.4) 模型的缺失,使对编程语言语义的判断取决于规格说明中模型外规则的理解。
364364 后验(postpone) 的语义模型可以使用不同形式语义方法(@2.2.3) 设计,但和语言规范差异的一些本应避免的附加工作,并且通常难以完整地作为标准规格的描述。
365365 本设计尝试在语言的原生设计中应对这些问题以避免这些妥协带来的消极影响,同时取得比非模型方法更强的可用性。
366366 这种可用性至少体现在语义的精确性可通过模型直接决定;仅为精确性,不需要另行补充模型设计(尽管现有模型可能仍然是不完全形式化的)。
@@ -373,7 +373,7 @@
373373
374374 @2.1.2 适用领域:
375375 为尽可能解决 @2.1.1 中的问题,优先以通用目的(@1.2) 而不是领域特定(domain-specific) 语言作为评估语言特性(feature) 设计的参考原则。
376-领域特定语言的特性应能合理地从支持通用目的的特性中派生(derive) ,且不影响实际的可用性。
376+领域特定语言的特性应能合理地从支持通用目的的特性中派生(@2.3.1.2) ,且不影响实际的可用性。
377377
378378 @2.2 理论背景、工具和依据:
379379 基本内容参见 [Documentation::CommonRules @@2.1] 。
@@ -384,8 +384,9 @@
384384 @2.2.2 设计意义:
385385 参见 [Documentation::Designation @@2.2] 。
386386
387-@2.2.3 形式语义方法:
388-形式语义方法是建立语义模型的形式方法(@2.1.1) ,主要有公理语义(axiomatic semantics) 、指称语义(denotational semantic) 和操作语义(operational semantics) 。
387+@2.2.3 形式语义(@2.3.2) 方法:
388+形式语义方法是建立语义模型的形式方法(@2.1.1) 。
389+形式语义方法主要有公理语义(axiomatic semantics) 、指称语义(denotational semantic) 和操作语义(operational semantics) 。
389390 操作语义可分为在抽象机(@2.6) 中指定具体规约(@4.1) 步骤状态的结构化操作语义(structural operational semantics) (小步(small-step) 语义),及仅指定规约的输入和输出的自然语义(natural semantics) (大步(big-step) 语义)。
390391 非确定语义:经验语义,不需要使用自然语言解释的部分。
391392 本文档不直接给出形式语义。语言规则(@2.3.1.2) 确定的经验语义可在一定条件下转写为上述形式语义方法表达的形式。
@@ -395,122 +396,40 @@
395396 其它参见 [Documentation::Designation @@2.3] 。
396397
397398 @2.3 基本概念和约定:
398-本文档中非形式地使用和这个一些术语的在特定理论中严格定义具有逻辑上相容的含义的概念,不进一步解释,详见 @2.3.1.1 。
399-例如,在程序语言理论中,上下文(context) 指形式上可继续补充内容的构造;本文档中非形式地使用和这个含义相容的概念。
400-描述中可能涉及上下文相关的略称参见 @2.3.3 。
401-
402-@2.3.1 通用约定:
399+本文档中概念使用参见 https://frankhb.github.io/YSLib-book/Tools/Terminology.zh-CN.html 。
400+描述中可能涉及上下文相关的略称参见 @2.3.5 。
401+
402+@2.3.1 通用领域:
403403 关于“语言”补充的基本概念和约定,使用元语言语法 <相关范畴/上下文> 。
404-除非有其它说明,适用于任意上下文。
404+参见 https://frankhb.github.io/YSLib-book/Tools/Terminology.zh-CN.html#%E9%80%9A%E7%94%A8%E9%A2%86%E5%9F%9F 。
405405
406406 @2.3.1.1 [<自指><名词>] :
407-实体(entity) :任意被自然语言表达的目标;不需要通过自然语言先验定义;参见经验语义。
408-语义(semantics) :参见经验语义。
409-经验(experience) :参见哲学或一般等价的经验语义。
410-范畴(category) :参见范畴论。
411-态射(morphism) :参见范畴论。
412-归纳(induction) :一种态射,可操作性参见经验语义。
413-方法学(methodology) :一个归纳经验得到的范畴;参见哲学或一般等价的经验语义。
414-方法(method) :方法学的一个子范畴;可操作性参见经验语义。
415-概念(concept) :参见形式逻辑学。
416-上下文(context) :一种概念范畴适用的态射;参见经验语义。
407+参见 https://frankhb.github.io/YSLib-book/Tools/Terminology.zh-CN.html#%E8%87%AA%E6%8C%87 。
417408
418409 @2.3.1.2 [<非自指>] :
419-形式(form) :参见经验语义和数学。
420-<概念> 内涵:参见形式逻辑学。
421-<概念> 外延:参见形式逻辑学。
422-<概念> 定义(definition) :确定概念内涵和外延的方法;参见任意一种形式逻辑学。
423-集合(set) :参见 NBG 集合论。
424-序列(sequence) :有序集合。
425-类(class) :参见 NBG 集合论和范畴论。
426-真类(proper class) :参见 NBG 集合论和范畴论。
427-<动词> 抽象(abstracting) :通过经验语义定义概念范畴或集合的方法。
428-<名词> 抽象(abstraction) :<动词>抽象的结果。
429-<动词> 封装(encapsulating) :从某一个范畴中抽象一个子范畴的方法。
430-<名词> 封装(encapsulation) :<动词>封装的结果。
431-接口(interface) :一种封装,参见软件工程学。
432-实现(implementation) :一种封装,参见软件工程学。
433-重用(reusing) :参见经验语义和软件工程学。
434-不变性(invariance) :满足某种等价关系(自反、传递、对称的二元关系)。
435-不变量(invariant) :具有不变性的实体。参见数学和契约式程序设计。
436-状态(state) :可以和其它实体关联的、可在某个上下文中保持变化或不变的实体。同一状态总是保持变化或保持不变。状态变化的含义参见经验语义、数学或另行指定。
437-可变状态(mutable state) :在某个上下文中可能映射到若干其它状态的状态。
438-不可变状态(immutable state) :不是可变状态的状态。
439-<动词> 派生(deriving) :基于重用的操作。
440-<名词> 派生(derivation) :<动词>派生的结果。
441-<语言> 接口(<language>interface) :和表达语义有关的语言的可见的特征。
442-<语言> 实现(<language>implementation):对语言表达语义的表达。
443-<语言> 人类接口(human interface) :语义仅对人类有意义(内容改变时可以导致语义的差异性),不提供为涉及作为计算模型实现的语言接口。
444-<语言> 机器接口(machine interface) :对机器(或特定语言实现的特定部分)有意义的语言接口。注意不同语言实现组成部分可以不同。例如,对 C 预处理器而言,C 源代码中的空白符是机器接口,而对翻译器来说则不是。就源代码而言,机器接口总是人类接口的子集。
445-语言特性(language feature) :作为功能提供的人类接口。
446-语言规则(language rule) :约定可实现及应被实现的语言接口的描述,可包含语言特性的表达。
447-语言规范(language specialization) :正式的(normative) 的语言规则的集合;或称语言规格说明。
448-符合性(conformance) :满足语言规范的实现性质。
449-要求(requirement) :语言规范对实现的作为判断符合性的条件。
450-
451-@2.3.2 领域约定:
452-适用于上下文 <NPL> 。
453-广义实体: <通用约定> 实体。语言抽象的目标,不另行定义(意义最终取决于自然语言)。
454-名称(name) :一种特殊的广义实体,专用于指称另一个广义实体。
455-实体(entity) :非名称的广义实体。
456-约束(constraint) :可被形式表达,用于限制和明确行为的规则。不一定使用形式表达。
457-违反(violation) :对约束指定的条件的不满足。
458-表示(representation) :以一个符合某种形式的约束的实体指称另一个实体。
459-语言实现(language implementation) :语言提供的接口的实现,是语言的表现形式,可以是具体语言实现或抽象语言实现之一。
460-具体语言实现(concreate language implementation) :能最终完全表达为可预测的物理现象一一对应的表达可计算性的实现(如机器指令),一般应为程序。
461-抽象语言实现(abstract language implementation) :非具体语言实现的语言实现。形式意义的标准定义的语言属于此类。
462-派生语言实现(derived language implementation) :派生已有实现的部分或全部得到的语言实现。以下简作“派生实现”。
463-实现环境(environment of implementation) :对应特定语言实现的特定不变状态(对机器来说可以是配置项,对人来说不确定,所以一般忽略)的集合。
464-符号(symbol) :语言规则允许的不使用其它对象表示的对象。符号可实现名称。
465-字母表(alphabet) :符号在语言中的全集。
466-串(string) :可能重复出现的符号的有限序列。
467-文法(grammar) :描述任意的可形式化的语言规则。
468-语法(syntax):以语言中的串作为基本元素,描述语言的字面(literal) 结构模式(pattern) 的语言规则,通常是文法的一部分。
469-语义(semantics):非语法的考虑逻辑上的释义(interpretation) 或含义(meaning) 的规则、原理和过程,通常可被语法以外的文法描述并可约束含义的表达。
470-形式语言(formal language): 特定语言规则确定的串的全集,是语言规则对应的语法的外延(也可能作为其它语言规则对应的某种形式语义)。
471-实例(instance) :具有代表性含义的集合的元素。
472-代码(code):任意有限的语言的实例片段组成的语法范畴。
473-伪代码(pseudo code):抽象语言实现的语言的代码。注意习惯上和具体语言实现代码完全一致的代码可以不作为伪代码考虑。
474-程序(program) :具体语言实现接受的以代码表示的输入,或被变换后对应的输出。
475-行为(behavior) :语言实现或在满足符合性的具体语言实现中的程序的外部表现。基于可操作性考虑,一般仅约束实现的机器接口(@2.3.1.2) 。
476-翻译(translation) :不同语言之间的变换,可作为语言实现的形式。
477-解释(interpretation) :通过直接执行(@2.1.1.1) 表现行为的具体语言实现的形式。
478-源语言(source language) :翻译的输入的语言。
479-目标语言(destination language) :翻译的输入的语言。
480-源程序(source program) :形式为作为翻译的输入的(以源语言编码的)程序。
481-计算复杂度(computational complexity) :某个形式化计算模型中以有限的正整数作为模型决定的规模(metric) 作为参数的渐进(asymptotic) 性质确定的度量,一般包括描述步骤规模的时间(time) 和描述存储规模的空间(space) 复杂度。
482-复杂度(complexity) :以程序的规模作为参数的关于程序的直接执行的计算复杂度,一般包括描述步骤规模的时间(time) 和描述存储规模的空间(space) 复杂度。
483-元语言(metalanguage) :描述其它语言的语言。
484-对象语言(object language):被元语言操作或实现的语言。
485-元编程(metaprograming) :使用元语言编程。
486-反射(reflection) :元语言和对象语言相同的元编程。
487-具现(reification) :在对象语言中以数据模型作为关联实体以表示程序的语义。
488-诊断(diagnostics) :明确的对特定预期或非预期执行的行为的响应的总和。
489-诊断消息(diagnostic message) :用于和用户交互的表现诊断的告知及提示。
490-未定义的(undefined) :可能导致违反语言规范的约束但语言规范同时没有要求提供任何可能影响符合性(@2.3.1.2) 的保证(如具有诊断消息)的。表示置于语言规则下的行为等不可预测。
491-未指定的(unspecified) :在各个实现中可能存在的,通常允许多种不同的实现选项。不应假定不同实现在明确未指定的规则上表现一致。
492-由实现定义的(implementation-defined) :取决于各个具体语言实现的,要求有文档说明。
493-由派生实现定义的(derived-implementation-defined) :取决于各个具体派生实现的,要求除存在默认定义或被派生实现的部分有明确的文档说明。
494-未定义行为(undefined behavior) :未定义的行为。
495-未指定行为(unspecified behavior) :未指定的行为,由实现选取规格中可能允许的指定行为的不确定选项,后者可能由显式或隐式的语言规则确定。
496-语言特性(language feature) :语言提供的功能接口,可以是具体语言特性或抽象语言特性之一。
497-具体语言特性(concrete language feature) :完全没有派生语言实现定义的语言特性。
498-抽象语言特性(abstract language feature) :非具体语言特性的语言特性。
499-过时的(obsolesent) :已确认因为存在更合适的选项而建议不继续使用的(接口/特性)。
500-废弃的(deprecated) :过时的但因为兼容性等原因,暂时保留的、一般可提供替代的接口或特性。
501-外部环境(external environment) :和程序及被翻译的程序没有交集的和实现环境无关的状态。
502-
503-@2.3.3 略称:
410+参见 https://frankhb.github.io/YSLib-book/Tools/Terminology.zh-CN.html#%E9%9D%9E%E8%87%AA%E6%8C%87 。
411+
412+@2.3.2 [<计算机科学>] :
413+参见 https://frankhb.github.io/YSLib-book/Tools/Terminology.zh-CN.html#%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6 。
414+
415+@2.3.3 [<规范>] :
416+参见 https://frankhb.github.io/YSLib-book/Tools/Terminology.zh-CN.html#%E8%A7%84%E8%8C%83 。
417+
418+@2.3.4 [<程序设计语言>] :
419+包含 <NPL> 。
420+参见 https://frankhb.github.io/YSLib-book/Tools/Terminology.zh-CN.html#%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%AD%E8%A8%80 。
421+
422+@2.3.5 略称:
504423 仅在不致混淆时使用。
505424 实现(implementation) :语言实现。
506425 环境(environment) :实现环境。
507426 派生实现(derived implementation) :派生语言实现。
508427
509-@2.4 NPL 实现模型:
510-NPL 是抽象的语言,没有具体语言实现(@2.3.2) ,但一些直接影响实现表现形式的规则被本节限定。
511-NPL 的实现可进行抽象解释(abstraction interpret) ,其目标不一定是程序(@2.3.2) 。
512-任一 NPL 实现(和派生实现)的符合性(@2.3.1.2) 由 NPL 符合性规则定义。
513-NPL 符合性规则是文档指定的满足对实现的要求(@2.3.1.2) 的语言规则子集,包括 @2.4 、@3 、@4 和其它派生实现定义的规则。
428+@2.4 NPL 规范模型:
429+NPL 是抽象的语言,没有具体语言实现(@2.3.3) ,但一些直接影响实现表现形式的规则被本节限定。
430+NPL 的实现可进行抽象解释(abstraction interpret) ,其目标不一定是程序(@2.3.4) 。
431+任一 NPL 实现(和派生实现(@2.3.5) )的符合性(@2.3.1.2) 由以下 NPL 符合性规则定义:
432+文档指定的满足对实现的要求(@2.3.1.2) 的语言规则子集,包括 @2.4 、@3 、@4 和其它派生实现定义的规则。
514433 这类规则总是包含对应语言的语义的 NPL 公共子集(@4) ,且蕴含实现行为(@2.6) 的要求,如 @4.1.3 。
515434 语言规则约定的未指定的程序或实现的属性及实现行为在符合性要求上等价。满足这类规则的前提下,实现选取特定的未指定的属性及对未指定行为的特定实现的选择不影响实现的符合性。
516435
@@ -525,7 +444,7 @@
525444 语义分析:语义检查(检验语义正确性(@2.5) )并实现其它语义规则。
526445 运行之前的阶段总称为翻译(translation) ,包含各个翻译阶段(phase of translation) 。
527446 对有宿主语言(host language) 支持的嵌入实现(embedded implementation) 或目标不是程序的情况,代码生成及之后的阶段不是必须的。
528-宿主语言实现可提供作为对象语言(@2.3.2) 的 NPL 的本机(native) 实现。
447+宿主语言实现可提供作为对象语言(@2.3.4) 的 NPL 的本机(native) 实现。
529448 嵌入实现的宿主语言可直接运行语义分析的结果(中间表示)。
530449 在语义不变的前提下,允许实现一次或多次翻译部分代码产生部分中间结果并复用。
531450 运行时(runtime) 程序实现运行阶段。
@@ -541,11 +460,11 @@
541460 @2.5 正确性:
542461 正确性规则包含语法正确性和语义正确性。
543462 当正确性规则被发现违反时,实现进入异常执行状态。
544-@2.5.1 以外的异常执行条件和状态由派生实现定义。
545-其它异常执行条件和状态以及异常执行的实现是否存在未定义行为(@2.3.2) 由派生实现定义。
463+翻译时正确性规则(@2.5.1) 以外的异常执行条件和状态由派生实现定义。
464+其它异常执行条件和状态以及异常执行的实现是否存在未定义行为(@2.3.4) 由派生实现定义。
546465
547466 @2.5.1 翻译时正确性规则:
548-翻译时的异常状态要求给出用于区分正常状态特定的行为(@2.3.2) ,包括诊断消息(@2.3.2) 和其它派生实现定义的实现行为(@2.6) 。
467+翻译时的异常状态要求给出用于区分正常状态特定的行为(@2.3.4) ,包括诊断消息(@2.3.4) 和其它派生实现定义的实现行为(@2.6) 。
549468 语法正确性规则是翻译时正确性规则。
550469 部分形式上的正确性规则在翻译时确保。
551470 翻译时确保的形式上正确的程序是合式的(well-formed) ;反之不合式(ill-formed) 。
@@ -571,14 +490,14 @@
571490 宿主语言提供的实现环境称为宿主实现环境,简称宿主环境(host environment) 。
572491
573492 @3 基本文法:
574-本章约定基本的 NPL 文法(@2.3.2) 规则中,包括语法及对应的基础词法。对应的语义单独列为一章(@4) 。
493+本章约定基本的 NPL 文法(@2.3.4) 规则中,包括语法及对应的基础词法。对应的语义单独列为一章(@4) 。
575494 多态文法规则:派生实现可完全不提供本章明确定义的词法和语法构造的支持,仅当提供同构的替代文法且符合语义规则。
576495
577496 @3.1 基本概念:
578497 字符(character) :组成语言代码的最小实体。
579498 基本翻译单元(basic transation unit) :任意连续字符的有限序列(可以是空序列)。
580499 翻译单元(translation unit) :基本翻译单元的集合,之间满足由派生实现定义的规则。
581-程序(@2.3.2) 以翻译单元或具体操作指定的以翻译单元进行翻译(@2.3.2) 得到的其它变换形式表示。
500+程序(@2.3.4) 以翻译单元或具体操作指定的以翻译单元进行翻译(@2.3.4) 得到的其它变换形式表示。
582501
583502 @3.2 字符集和字符串:
584503 字符集(character set) :对一个实现而言不变的字符的有限集合。
@@ -629,9 +548,9 @@
629548 不对空字符特殊处理。
630549
631550 @3.4 语法 :
632-本节指定 NPL 作为对象语言(@2.3.2) 的语法(@2.3.2) 。
633-约定元语言(@2.3.2) 的语法 x 表示语法元素 x ,::= 表示定义,| 表示析取。
634-程序被作为语言实现(@2.3.2) 组成部分的语法分析(@2.4.1) 程序规约(@4.1) ,结果能确定其和一定的语法元素匹配。
551+本节指定 NPL 作为对象语言(@2.3.4) 的语法(@2.3.4) 。
552+约定元语言(@2.3.4) 的语法 x 表示语法元素 x ,::= 表示定义,| 表示析取。
553+程序被作为语言实现(@2.3.3) 组成部分的语法分析(@2.4.1) 程序规约(@4.1) ,结果能确定其和一定的语法元素匹配。
635554 规约时应进行语法规则的检查。
636555
637556 @3.4.1 基本语法构造概述:
@@ -686,12 +605,12 @@
686605 反之,在分析 NPL-GA 语法前扩展其它语法预处理(preprocessing) 规则可以支持更多的文法扩展。这样的文法扩展可接受扩展的非 NPL-GA 文法,但仍允许保持语法分析器的实现使用 NPL-GA 语法。
687606
688607 @4 语义:
689-NPL 的语义规则(@2.3.2) 构成演绎系统(deductive system) ,通过对翻译单元(@3.1) 中的表达式(@3.4.2) 的求值(@4.1) 表达。
608+NPL 的语义规则(@2.3.4) 构成演绎系统(deductive system) ,通过对翻译单元(@3.1) 中的表达式(@3.4.2) 的求值(@4.1) 表达。
690609 除非派生实现另行指定,仅使用表达式指定对象语言的语义。
691610 基本语义规则要求:
692-所有不需要诊断消息(@2.3.2) 的规则由派生实现定义;
693-本章内的规则应不产生未定义行为(@2.3.2) 。
694-NPL 允许程序具有语义等价的未指定未指定行为(@2.3.2)。派生实现可能通过约定和限制其具体选项的选取以指定更具体的实现行为(@2.6) 。
611+所有不需要诊断消息(@2.3.4) 的规则由派生实现定义;
612+本章内的规则应不产生未定义行为(@2.3.4) 。
613+NPL 允许程序具有语义等价的未指定未指定行为(@2.3.4)。派生实现可能通过约定和限制其具体选项的选取以指定更具体的实现行为(@2.6) 。
695614
696615 @4.1 基本概念:
697616 区域(region) :和特定位置代码关联的有限实体集合。
@@ -710,7 +629,7 @@
710629 常量(constant) :满足某种不变量的约束以和不可变状态关联的实体。具体由派生实现定义。注意不和变量对立(表示不可变状态的变量可能是常量)。
711630 值(value) :表达式关联的不可变状态。
712631 修改(modification) :使状态(@2.3.1.2) 改变的操作。
713-副作用(side effect) :对表达式的值以外的表示的改变。
632+副作用(side effect) :对表达式的值以外的表示的改变的作用(@2.3.4) 。
714633 幂等性(idempotence) :重复后即不改变状态的操作性质。
715634 项(term) :特定的演绎系统(deductive system) 特别是项重写系统(term rewriting system) 中处理的对象,是带有基本递归构造的元素,可对应语法中的表达式。
716635 子项(subterm) :具有递归形式构造的文法描述的参与构成项的项。
@@ -718,18 +637,13 @@
718637 自由变量(free variable) :子项中出现的非约束变量。
719638 组合子(combinator) :不是变量也不含相对任何项的自由变量的子项。
720639 转换(conversion) :根据基于特定等价性(假设)前提的两个项之间的自反的演绎。
721-规约(reduction) :两个项之间的、实例(@2.3.2) 是某个转换的子集的满足反自反的演绎。
722-计算作用(computational effect) :可被某个形式化计算模型描述的行为。
723-作用(effect) :语言支持的一定上下文内的表达式规约的结果的计算作用,包括计算得到的值、产生的副作用以及其它可由区域和变化的状态二元组描述的实体。
640+规约(reduction) :两个项之间的、实例(@2.3.4) 是某个转换的子集的满足反自反的演绎。
724641 求值结果(evaluation result) :作用的子集,是求值得到的用于替换被求值的表达式的表达式或其它由派生实现定义的实体。不和其它结果混淆时,简称结果(result) 。
725642 抽象求值(abstract evaluation) :对表达式的不取得作用的规约。
726643 具体求值(concrete evaluation) :对表达式的取得作用的规约。
727644 求值(evaluation) :抽象求值或具体求值。
728645 控制状态(control state) :实现中决定求值的状态。
729646 控制作用(control effect) :引起控制状态改变的作用。在 NPL 中,控制作用是在对象或派生实现定义的实体上引起改变的副作用。
730-外部表示(external representation) :具有特定形式的用于和外部环境(@2.3.2) 交互的表示(@2.3.2) 。
731-内部表示(internal representation) :非外部表示的表示(@2.3.2) 。
732-等价关系(equivalence relationship) :自反的(reflexive) 、对称的(symentric) 和传递的(transitive) 的二元关系。
733647 相等关系(equality relationship) :定义在值的集合上的等价关系。
734648 布尔值(boolean value):逻辑真或逻辑假。
735649 谓词(predicate) :若具有结果,则结果是布尔值的计算实体。
@@ -745,9 +659,9 @@
745659 外部表示和内部表示是相对的。不同外部环境可以有不同的外部表示,这些外部表示相对其它外部环境而言可以不是外部表示。
746660 外部表示可能被读取(read) 处理为内部表示。内部表示可能被写入(write) 处理为外部表示。
747661 读取和写入操作的副作用分别是输入(input) 和输出(output) 。
748-外部表示为元素序列时,读取和写入是非特定格式数据和元素序列之间的转换,若不含其它作用(@4.1) ,其操作是进行反序列化(deserialize) 和序列化(serialize) 。
662+外部表示为元素序列时,读取和写入是非特定格式数据和元素序列之间的转换,若不含其它作用(@2.3.4) ,其操作是进行反序列化(deserialize) 和序列化(serialize) 。
749663 内部表示为对象时,读取和写入包含对象和非特定格式数据之间的转换,其操作是进行列集(marshall) 和散集(unmarshall) 。
750-文法(@3) 约定基准的表示作为翻译(@2.3.2) 的输入。这种表示是翻译所在外部环境的外部表示,称为源代码(source code) ;翻译结果为对象语言代码,简称对象代码(object code) ,可以是另外的外部表示。
664+文法(@3) 约定基准的表示作为翻译(@2.3.4) 的输入。这种表示是翻译所在外部环境的外部表示,称为源代码(source code) ;翻译结果为对象语言代码,简称对象代码(object code) ,可以是另外的外部表示。
751665 翻译单元(@3.1) 是这里翻译的外部表示。
752666 由基本文法(@3) ,空白符参与表示,不一一对应。为便于输出标准化,NPL 约定以下规范(canonical) 外部表示:
753667 对列表,输出的表示是以 `(` 和 `)` 作为边界,元素以单个 ` ` 为分隔符的序列,其中的元素在括号中被递归地嵌套表示;
@@ -759,7 +673,7 @@
759673 @4.1.2 演绎规则:
760674 指定转换的演绎规则是转换规则。
761675 指定规约的演绎规则是规约规则。
762-两两可转换的对象的传递闭包构成等价类,称为可转换等价类。除非另行指定,只讨论具有单一可转换等价类的转换规则的(抽象)重写系统。
676+两两可转换的对象的传递闭包构成等价类(@2.3.2) ,称为可转换等价类。除非另行指定,只讨论具有单一可转换等价类的转换规则的(抽象)重写系统。
763677 对象之间的转换保持某种等价关系的等价变换(transformation) 。对象之间的规约是其中的子集,即以存在等价关系的一个对象替代另一个对象的有向转换。
764678 若两个对象具有规约到相同结果的变换,这两个对象可连接的(joinable) 。
765679 若任意两个对象等价蕴含对象可连接,则此重写系统具有 Church-Rosser 属性(Church-Rosser property) 。
@@ -767,7 +681,7 @@
767681 若可从任意一个对象的一步规约到的任意两个对象可连接,则重写系统具有局部汇聚性(local confluence) ,或称为弱汇聚性(weak confluence) 。
768682 若可从一个对象规约到的任意两个对象可连接,则此对象具有汇聚性。
769683 若可从一个对象的一步规约到的任意两个对象可连接,则此对象具有局部汇聚性,或称为弱汇聚性。
770-规约中可包括实现环境(@2.3.2) 的交互。
684+规约中可包括涉及实现环境(@2.3.3) 的交互。
771685 若规约用于求值,汇聚性限定为:满足任意以此规则变换前和变换后的项被分别规约时,两者的作用相等。
772686
773687 @4.1.3 状态和行为:
@@ -781,8 +695,7 @@
781695 实现应满足实现行为(@2.6) 和语义蕴含的可观察行为等价,其余行为等价性未指定:不严格要求按抽象机(@2.6) 实现操作语义。
782696
783697 @4.1.4 等价谓词(equivalence predicate) :
784-等价关系(@4.1) 划分等价类(equivalence class) 。
785-等价谓词是判断等价关系的谓词,描述一些重要的等价类划分的基本操作,在避免依赖良序(well-ordering) 和良基(well-founded) 的理论中满足 @1.4.4.3 ,尽管判断本身依赖序关系。
698+等价谓词是判断等价关系的谓词,描述一些重要的等价类(@2.3.2) 划分的基本操作,在避免依赖良序(well-ordering) 和良基(well-founded) 的理论中满足 @1.4.4.3 ,尽管判断本身依赖序关系。
786699 语言提供等价谓词判断两个项之间是否满足等价关系,满足判断等价关系的需要。
787700 类似一般的值的集合上可能存在的相等关系,作用于实体的值的等价谓词(若存在)定义实体的相等关系。
788701 决定相等关系的谓词是相等谓词,可判断实体和实体的值相等(equal) 。
@@ -793,7 +706,7 @@
793706 EGAL 。
794707
795708 @4.1.4.1 实体的同一性:
796-同一性(@4.1) 是实体上的等价关系(@4.1) 的一个实例。
709+同一性(@4.1) 是实体上的等价关系(@2.3.2) 的一个实例。
797710 同一性决定任意两个实体可在语言中不依赖具体操作的行为被直接区分,即满足 Leibneiz 法则(Leibneiz's law) 。
798711 基于这个性质,可在实体上定义和 [So90] 相容的更强的(不依赖语言设计中不存在副作用(@4.1.4) 的)引用透明性(referential transparency) 。
799712 同一性决定的等价类之间的实体相同,即其整体和任意的属性(property) 在任意上下文中等价。
@@ -810,7 +723,7 @@
810723 通过限定不同的修改操作,定义不同的可修改性(modifiability) 和对立的不可修改性(nonmodifiability) 。
811724 通过明确不可修改性拒绝支持修改操作(例如通过通过实体的类型检查(@4.6.2.3) 拒绝特定的修改操作),或通过不提供修改操作(例如关于 ISO C++ 的非类且非数组类型的纯右值,尽管要求非纯右值可被视为是一种类型检查),语义规则保证实体不被修改操作改变状态。
812725 (不依赖和影响实体同一性(@4.1) 的)同一个实体上的修改操作是改变操作。只有具有可变状态(@2.3.1.2) 的实体可能支持这些操作。
813-一般地,一个实体不一定保证可区分是否具有不可变性以及具有何种不可变性(也蕴含一般不可区分可修改性),因为不可变性依赖实体的表示(@2.3.2) 进行约定。
726+一般地,一个实体不一定保证可区分是否具有不可变性以及具有何种不可变性(也蕴含一般不可区分可修改性),因为不可变性依赖实体的表示(@2.3.4) 进行约定。
814727 基于等价关系而不是预设具体表示之间的相等定义可变性,避免抽象的目的(如封装性(@1.4.6.2) )依赖特定相等关系(@4.1.4) 的实现细节(@1.4.3.4) ,支持开放世界假设(@1.4.3.6) 。
815728 这种设计的一类典型反例是在预设排除副作用的纯的(@4.4.2) 的设计为基础进行扩展定义改变操作,包括:
816729 默认使用不可变数据结构,并在此基础上扩展出可变的数据结构(如 [Rust] );
@@ -833,7 +746,7 @@
833746 数据结构也可在对象语言中通过实体包含关系以外的途径定义。例如,限定包含关系构成的图中的所有权关系(@4.2.2.3) 附加限制,详见 @4.2.4 。
834747
835748 @4.1.6 作用使用原则:
836-不同副作用(@4.1.4) 对行为(@2.3.2) 的影响可能依赖作用之间的顺序。
749+不同副作用(@4.1.4) 对行为(@2.3.4) 的影响可能依赖作用之间的顺序。
837750 为保持可组合性(@1.4.4.5) ,副作用仅在必要时引入,且通常需明确区分是否依赖副作用以避免非预期的行为。
838751
839752 @4.1.7 续延(continuation) :
@@ -865,19 +778,19 @@
865778 一等实体的具体表现形式通常是实现细节而要求不被依赖,为了支持前者不被显式表达,满足 @1.4.2.4 ;
866779 一等实体的普遍支持允许以统一(@1.4.5.1) 的方式抽象可变状态(@4.1.3) ,且扩展使便于满足 @1.4.2.1 。
867780 为简化设计,NPL 约定以下默认规则:
868-除非另行指定,名义同一性属性指定为对象在抽象机(@2.6) 实现的操作语义下的存储位置;对象占据存储位置起始的若干存储;存储位置的表示(@2.3.2) 未指定;派生实现可指定具体的表示。
781+除非另行指定,名义同一性属性指定为对象在抽象机(@2.6) 实现的操作语义下的存储位置;对象占据存储位置起始的若干存储;存储位置的表示(@2.3.4) 未指定;派生实现可指定具体的表示。
869782 在语言规则中,一等对象满足 @4.1.4.1 的默认规则。
870783
871784 @4.2.1.2 可变状态和普遍性:
872785 一等实体的普遍支持体现在:
873786 在一般的一等实体上引入可变状态,实质上提供了一等副作用(first-class side effect) ,而不把可修改性(@4.1.4.2) 限于特定的数据结构(如求值环境(@4.6.1.1) );
874-允许以一致的方式和实现的外部环境(@2.3.2) 进行互操作,特别地,允许物理上提供状态抽象的设备实体的状态直接映射为一等对象。
787+允许以一致的方式和实现的外部环境进行互操作(@2.3.3) ,特别地,允许物理上提供状态抽象的设备实体的状态直接映射为一等对象。
875788 普遍的一等实体支持使一等实体的访问不依赖非一等的实体(@4.2.3.5) 。
876789
877790 @4.2.1.3 Kernel 中的一等对象:
878791 尽管没有显式指出一等实体和一等对象的区别,在 [RnRK] 中的一等对象和此处的一等实体在目的上一致。因为 Kernel 不直接支持区分对象同一性,一等实体退化为一等对象。
879792 并不需要修改一等对象的判定准则(@4.1) 限定为后者并使前者依赖后者的定义,因为作为抽象,前者通常并非是后者的操作上进行限制得到(正相反,一般是通过补充约定假设得到,如 @4.1 的定义)。
880-类似的一个例子是不可修改对象(nonmodifiable object) 可以但不必要是对应的可修改对象(modifiable object) 的子类型。
793+类似的一个例子是不可修改对象(nonmodifiable object) 可以但不必要是对应的可修改对象(modifiable object) 的子类型(@4.6.2) 。
881794 作为 @1.4.5.1 的实例,一等实体避免特殊规则,和 [RnRK] 设计原则 G1a 一致。
882795 除非另行指定,本节中的以下描述提供允许派生实现提供保证或假设的机制,并非要求。派生实现可附加规则改变此处对一等对象的保证或性质。
883796
@@ -891,13 +804,13 @@
891804 为支持一等状态,有必要支持判断两个对象的同一性,确保修改(@4.1) 某个对象的操作不会关联到任意其它对象,以允许特定对象关联特定的一等状态。
892805 注意并非所有一等对象都需要支持一等状态;否则几乎总是会付出本不必要的代价(@1.4.2.2) 也难以避免违反适用性(@1.4.5.2) ;因此有必要区分一等状态的对象和非一等状态的对象。
893806 这种区分实质上更普遍地对具体的计算操作也存在意义,自然地引入了值类别(value category) ;最简单的设计如区分左值(lvalue) 和右值(rvalue) 分别关联是否需要支持一等状态的对象。
894-为允许一等状态和外部环境的互操作,不能总是假定只有一类总是可被程序局部预知的修改操作(@4.1.4.2)(典型地,定义为“设置被引用对象(@4.2.3)”操作,如 [RnRK] 3.1 )影响状态,而应允许和特定对象关联的求值时的不透明的副作用(一个实例是 ISO C 和 ISO C++ 的 volatile 类型对象)。
807+为允许一等状态和外部环境的互操作(@2.3.3) ,不能总是假定只有一类总是可被程序局部预知的修改操作(@4.1.4.2)(典型地,定义为“设置被引用对象(@4.2.3)”操作,如 [RnRK] 3.1 )影响状态,而应允许和特定对象关联的求值时的不透明的副作用(一个实例是 ISO C 和 ISO C++ 的 volatile 类型对象)。
895808 若不考虑互操作,则一等对象用有限的不同等价谓词(@4.1.4) 即能提供区分同一性的操作;否则,等价谓词的设计即便保持正交,也需区分不同的一等对象对各种副作用的不同支持情况。
896809
897810 @4.2.2.2 一等作用:
898811 语言可指定特定的求值自动创建对象。
899812 典型地,按值传递(@4.4.4.5) 时,被传递后的对象和实际参数(@4.5.3) 表示的对象具有不同的同一性,即按值传递时创建了新的对象。
900-基于此规则可在传递时附加不同的作用(@4.1) ,即实现可随一等对象传递的一等作用(first-class effect) 。
813+基于此规则可在传递时附加不同的作用(@2.3.4) ,即实现可随一等对象传递的一等作用(first-class effect) 。
901814 这里的一等作用可包括用于维护对象的不变性(@2.3.1.1) 的副作用,作为契约式编程(contract-based programming) 的基础实现方式。
902815 这种不变性可包括对象的生存期。通过限制特定表达式求值的作用域(@4.1) 内销毁对象以确保对象生存期有限,即基于作用域的对象管理(scope-based object management) 。
903816 基于作用域的对象管理可直接对应有限资源的普遍性质,使一等对象作为资源的抽象,确保资源的创建和销毁的副作用符合资源操作的语义,同时避免隐式的泄漏。这种惯用法(idiom) 在 C++ 中称为 RAII(resource aquisition is initialization) 。
@@ -943,7 +856,7 @@
943856 在形式模型(@2.1.1) 以外,使用以基本语言子集扩展特性得到派生语言的方式,也无法避免不在对象语言中使用非引用的设计满足通用可编程需求,而产生其它复杂性及可行性问题。
944857 特别地,这导致难以在基础语言的基础上复用和扩充语义规则派生其它语言。
945858 考虑设计和实现整体,要求一等对象都是引用,在简单性(@1.4.3.2) 上是一个过早的优化(@1.4.6.1) ,它限制了一些整体较简单的实用的试图把和同一性(@4.1) 关联的性质附加到对象上的设计。
946-使用这种关联性质的扩展参见 @4.2.2 的讨论。另见 @4.2.3.5 中的例子。
859+使用这种关联性质的扩展参见同一性关联扩展性质(@4.2.2) 的讨论。另见可变对象问题(@4.2.3.5) 中的例子。
947860
948861 @4.2.3.3 对象语义问题:
949862 单一类型(@4.6.2) 的普遍引用存在替代被引用的一等对象,容易和一等对象设计的语义冲突。
@@ -962,7 +875,7 @@
962875 @4.2.3.3.2 对一等状态(@4.2.2.1) 的支持:
963876 在具有引用的情况下,区分不同的副作用的实质由被引用对象引起,而并非引用的性质;要求一等对象都是引用并不简化派生实现添加不同一等状态的支持,反而引入了无法回避的复杂性。
964877 单一类型的引用和以上最简单的值类别(@4.2.2.1) 的设计兼容,只要把引用关联到左值,非引用关联到右值即可;但这种设计和要求一等对象都是引用矛盾,因为后者使这里的右值不再是一等对象。
965-若特定的对象访问操作都通过引用进行,这些操作中需要的状态可直接使用引用提供;这是一种保守的设计优化,不保证可替代任意的对象属性(@2.3.3.3) 及基于这些性质的其它操作。
878+若特定的对象访问操作都通过引用进行,这些操作中需要的状态可直接使用引用提供;这是一种保守的设计优化,不保证可替代任意的对象属性(@4.1.4.1) 及基于这些性质的其它操作。
966879
967880 @4.2.3.3.3 对所有权(@4.2.2.3) 的支持:
968881 实体的所有权无法通过单一类型的引用直接被区分。
@@ -996,7 +909,7 @@
996909 典型的多线程并发执行若需对象上的副作用,需要保护和排除不必要的共享,确保独占所有权以避免竞争条件(race condition) 。
997910 也有其它的一些类似的容易被忽略的场景,如:
998911 http://okmij.org/ftp/continuations/map-story.html
999-另见 @4.2.3.5.3 。
912+另见共享改变(@4.2.3.5.3) 。
1000913
1001914 @4.2.3.4.2 对象语言语义问题:
1002915 在未证明共享引用一定节约开销时,隐式的共享对象语言程序违反 @1.4.2.2 ,或者在实现需要明确对资源使用的约束时,对进一步的程序变换带来开销(如需要别名分析保证安全),进而鼓励用户代码违反 @1.4.2.3 。
@@ -1004,7 +917,7 @@
1004917
1005918 @4.2.3.4.3 普遍的设计限制:
1006919 除非在语言规则中添加复杂的约束(如通过 @4.6.2 的机制)以证明特定上下文可避免共享引用,无法避免引用引入不必要的别名(aliasing) 。若公开这样的性质作为接口约束,违反 @1.4.2.3 。
1007-隐式的共享使涉及修改(@4.1) 的操作的特性更难设计,参见 @4.2.3.5.3 。
920+隐式的共享使涉及修改(@4.1) 的操作的特性更难设计,参见共享改变(@4.2.3.5.3) 。
1008921
1009922 @4.2.3.4.4 普遍的实现限制:
1010923 隐式的共享会隐藏一些语言不可访问的全局属性,使实现在提供语言特性之前先行受到限制,而影响可移植性。
@@ -1027,7 +940,7 @@
1027940
1028941 @4.2.3.5 可变对象问题:
1029942 仅使用引用操作一等对象在涉及对象修改(@4.1) 的存在一些问题。
1030-一般地,和对象改变操作(@4.1.4.2) 对应的作用(@4.1) 及其类似的副作用(@4.1) 也和修改对象有类似的问题。
943+一般地,和对象改变操作(@4.1.4.2) 对应的作用(@2.3.4) 及其类似的副作用(@2.3.4) 也和修改对象有类似的问题。
1031944
1032945 @4.2.3.5.1 可变对象操作限制:
1033946 在使用普遍引用的设计中,实体的可修改性(@4.1.4.2) 可能以被引用对象的可变性提供:通过允许改变对象中包含的引用指定对象可变,而体现可修改性。
@@ -1045,7 +958,7 @@
1045958 @4.2.3.5.2 对象分类的复杂性:
1046959 限制一部分只包含引用的实体具有可变性,即便是只在基本的数据结构上应用,也容易导致对象分类的复杂化而使设计违反简单性。因为区分可变和不可变对象而需要更多的特设的操作,也一定程度上违反统一性。
1047960 例如,Racket 区分可变和不可变的基本数据结构(从 https://blog.racket-lang.org/2007/11/getting-rid-of-set-car-and-set-cdr.html ),修改操作不能通用。除非用户明确需要,这样要求选取的类型是否不变(特别是没有引入区分同一性的一等实体支持时)是过早的优化(@1.4.6.1) ,同时违反 @1.4.2.1 和 @1.4.2.3 。
1048-注意,改变操作的冲突可以是未定义的(@2.3.2) 。避免冲突不是语言设计选取不变数据结构的合理理由(相对地,选择避免冲突的数据结构是用户的合理理由)。提前放弃未定义的选项,要求任意无法具有实际意义的操作冲突具有一致的行为(@2.6) 也是设计上的过早优化。
961+注意,改变操作的冲突可以是未定义的(@2.3.4) 。避免冲突不是语言设计选取不变数据结构的合理理由(相对地,选择避免冲突的数据结构是用户的合理理由)。提前放弃未定义的选项,要求任意无法具有实际意义的操作冲突具有一致的行为(@2.6) 也是设计上的过早优化。
1049962
1050963 @4.2.3.5.3 共享改变:
1051964 仅允许这样的可变性也不允许被引用的对象通过不同引用可共享改变。
@@ -1071,7 +984,7 @@
1071984 对语言设计中的一些关键规则,要求使用引用同时保留非引用的形式访问对象并非必要,因为满足以上准则实际上仅关心对象(类似作为表达式)直接关联的值,而非其它属性。
1072985 这也体现是否仅允许通过引用访问对象应是实现细节,而不影响一等对象的判定。
1073986 依赖一等对象都是引用保证普遍的间接抽象能提供一部分实现的便利(如 TCO(@5.2.6.4) 可以直接移除活动记录帧(@4.5.3.4) ),但并非没有可忽略的代价(如要求全局 GC(@4.2.2.3) 引入非确定性)和替代实现方法。
1074-关于 TCO 的实现方式,另见 @7.4 。
987+另见规约实现(@7.4) 中关于 TCO 实现方式的讨论。
1075988
1076989 @4.2.3.7 其它替代:
1077990 不依赖普遍引用的设计仍允许特定一等对象以引用形式在对象语言中直接访问。
@@ -1107,7 +1020,7 @@
11071020 其次,在实现上,相对不具有循环引用的情形,有更大的且难以避免的时间和空间开销。
11081021 此外,无论是否附加外部所有者,都需要引入更多的处理循环的专用(ad-hoc) 规则。
11091022 以上问题体现在不使用循环引用的场合下,一般对象上的循环引用同时违反避免不必要付出的代价(@1.4.2.2) 、最小接口原则(@1.4.2.3) 和关注点分离原则(@1.4.2.4) ,也不利简单性(@1.4.3.2) 。
1110-这些问题的根本原因是所有权没有被足够早地显式区分。更进一步地,不附加外部所有者的普遍的循环引用要求不能直接区分,否则可通过定义某种规则从中判断出不循环的(acyclic) 的引用链的子集而不构成循环引用(实际上若能保证复杂度(@2.3.2) 上限,这也是消除循环引用的主要方式)。
1023+这些问题的根本原因是所有权没有被足够早地显式区分。更进一步地,不附加外部所有者的普遍的循环引用要求不能直接区分,否则可通过定义某种规则从中判断出不循环的(acyclic) 的引用链的子集而不构成循环引用(实际上若能保证复杂度(@2.3.4) 上限,这也是消除循环引用的主要方式)。
11111024 因此,除非允许语言隐含不由用户程序指定的所有者,保留循环引用无法解决这些问题;甚至即便允许这样的所有者,也无法彻底解决实现开销的问题(而需要更多地依赖语言实现系统外部的假定减缓这些开销),仍然一定程度上不符合以上提及的所有原则的要求。
11121025
11131026 @4.2.4.3 自引用数据结构相关的一般实现:
@@ -1134,7 +1047,7 @@
11341047 显式地放弃了生存期的抽象,不满足上述 @4.2.3 第一点要求的对象一般属性的抽象能力。
11351048
11361049 @4.3 名称规则:
1137-名称(@2.3.2) 和能标识特定含义、符合名称词法约束(@3.3) 的表达式(@3.4.2) 一一对应。
1050+名称(@2.3.4) 和能标识特定含义、符合名称词法约束(@3.3) 的表达式(@3.4.2) 一一对应。
11381051 具体的外延由派生实现定义。
11391052 表示名称的表达式不同于名称,但在无歧义时,语言中可直接以名称代指表达式和对应的词法元素。
11401053
@@ -1154,12 +1067,13 @@
11541067 名称验证确定可见名称(@4.3.2) 的基础上确定名称是否有效。
11551068 名称查找是从已知有效名称确定唯一指称的实体的过程,仅在名称验证成功后进行。
11561069 不同名称经过名称查找的结果可能等效。等效的有效名称视为同一的,规则由派生实现定义。
1157-除非另行指定,成功的名称解析没有副作用(@4.1) 。
1070+除非另行指定,成功的名称解析没有副作用(@2.3.4) 。
11581071 名称解析依赖从保存名称的目标中查找名称。若查找失败,解析可继续从替代的其它目标中进行。这种机制称为重定向(redirection) 。
1159-以上约定以外的具体规则以及失败的行为由派生实现定义(另见 @4.6.1.1.2 )。
1072+以上约定以外的具体规则以及失败的行为由派生实现定义。
1073+另见作用域(@4.6.1.1.2) 。
11601074
11611075 @4.3.4 命名空间(namespace) :
1162-命名空间是实体(@2.3.2) 。命名空间可以由名称指称。
1076+命名空间是实体(@2.3.4) 。命名空间可以由名称指称。
11631077 是否实现命名空间为程序中可由用户指定可变的实体及求值环境(@4.6.1.1) ,由派生实现定义。
11641078
11651079 @4.3.4.1 指称(denotation) :
@@ -1217,7 +1131,7 @@
12171131 语法形式(@3.4.3) 固定且求值总是空求值的表达式是空表达式(empty expression) ,这仅由派生实现可选提供。
12181132
12191133 @4.4.3 范式(normal form) :
1220-规范化形式(normalized form),或简称范式(normal form) ,是由派生实现定义的表示(@2.3.2) ,被一组规约(@4.1) 规则确定,满足:
1134+规范化形式(normalized form),或简称范式(normal form) ,是由派生实现定义的表示(@2.3.4) ,被一组规约(@4.1) 规则确定,满足:
12211135 通过有限的规约步骤后得到;
12221136 按规约规则,规范形式上不存在不和空求值等价(@4.4.2) 的进一步规约。
12231137 在具有 Church-Rosser 属性的重写系统(@4.1.2) 中,一个对象若具有范式则唯一。
@@ -1238,6 +1152,7 @@
12381152 WHNF 中除了操作符以外的子表达式是操作数(operand) 。
12391153 操作数以具有限定顺序或不限定顺序的数据结构表示,典型代表分别是操作数列表(operand list) 和操作数树(operand tree) 。
12401154 操作数树是有限的树形数据结构的 DAG(@4.2.4) (和 Kernel 类似),其具体构造和表示由派生实现定义。
1155+这种能以操作符和操作数的组合表达的计算形式是操作(operation) 。操作的结果和作用即这种可求值为 WHNF 表达式的求值结果(@4.1) 和作用(@4.1) 。
12411156
12421157 @4.4.4 组合求值:
12431158 表达式和子表达式之间的求值需满足一定约束。
@@ -1293,15 +1208,15 @@
12931208 派生实现的求值可满足以下节指定语义,此时应满足其中约定的规则。
12941209
12951210 @4.4.7 上下文相关求值:
1296-在被求值的表达式以外,对应的规约规则在实现此规约的元语言(@2.3.2) 中可能是上下文相关的,这种附加依赖的上下文为求值上下文(evaluation context) 。
1211+在被求值的表达式以外,对应的规约规则在实现此规约的元语言(@2.3.4) 中可能是上下文相关的,这种附加依赖的上下文为求值上下文(evaluation context) 。
12971212 求值上下文被作为元语言实现对象求值规则时的输入,可指定项所在的位置等不被被规约的项必然蕴含的附加信息。
12981213 由派生实现定义的特定求值上下文称为尾上下文(tail context) 。以尾上下文求值可提供附加的保证。
12991214 元语言中,一般的求值上下文 C 形式化为具有占位符 [] 和可选前缀 v 及可选后缀 e 的递归组合的串:
13001215 C ::= [] | Ce | vC
13011216 其中 e 是被求值表达式,v 是作为范式(@4.4.3) 的值。
13021217 通过附加适当的求值规则保证对象语言中的表达式总是可唯一地被分解为这种表示,抽象的求值上下文可直接实现对象语言的求值。但语义描述和实现的基准都以抽象机(@2.6) 替代,因为:
1303-抽象机语义允许不依赖源程序(@2.3.2) 的表示和构造(如特定的表达式的文法);
1304-这种分解一般要求遍历对象语言的源程序而难以具有较好的可实现性质,如复杂度(@2.3.2) ;
1218+抽象机语义允许不依赖源程序(@2.3.4) 的表示和构造(如特定的表达式的文法);
1219+这种分解一般要求遍历对象语言的源程序而难以具有较好的可实现性质,如复杂度(@2.3.4) ;
13051220 为满足良好的可实现性质,需描述实现中可能具有的离散状态与只和其中个别状态关联的局部的求值规则时,这种分解通常会渐进演化为某种抽象机的表示。
13061221
13071222 @4.5 λ 完备语义和对应语法:
@@ -1334,7 +1249,7 @@
13341249 除非另行指定,作为项的函数应具有符合类型构造器(type constructor) * → * 结果的类型(@4.6.2) ,如为简单类型 λ 演算(STLC, simply-typed lambda calculus) 兼容的函数类型实例。
13351250
13361251 @4.5.2.1 过程(procedure) :
1337-过程是操作符具现(@2.3.2) 的实体,决定特定的可提供求值的作用(包括决定求值结果)的计算。
1252+过程是操作符具现(@2.3.4) 的实体,决定特定的可提供求值的作用(包括决定求值结果)的计算。
13381253 函数表达式的最终求值结果(@4.4.3) 由过程实体的计算结果决定,以派生实现定义的方式关联。
13391254 过程中和过程外的计算的组合满足因果性(causality) :
13401255 以求值描述的过程中的计算整体非后序(@4.4.1) 于引起过程中计算的外部环境的计算;
@@ -1346,7 +1261,7 @@
13461261 作为不同的例程,不考虑被保存续延时,子例程(subroutine) 在返回一次后不重新进入,协程(coroutine) 则可能引起多次返回;
13471262 一般的续延支持返回多次并可能支持和调用者并发的计算。
13481263 过程可能同时使用这些形式的一种或多种,使用的具体形式由提供过程的派生实现指定。
1349-注意过程不一定具有可被对象语言(@2.3.2) 直接表达的一等(first-class) 函数而在元语言(@2.3.2) 中可能是,如无界续延(undelimited continuation) ,因为其不符合函数的类型要求(@4.5.2) 。
1264+注意过程不一定具有可被对象语言(@2.3.4) 直接表达的一等(first-class) 函数而在元语言(@2.3.4) 中可能是,如无界续延(undelimited continuation) ,因为其不符合函数的类型要求(@4.5.2) 。
13501265
13511266 @4.5.2.2 λ 抽象(lambda abstraction) :
13521267 λ 抽象是典型的操作符,是 λ 演算中的基本构成之一。
@@ -1403,11 +1318,12 @@
14031318
14041319 @4.5.3.3 续延捕获(capture) 和续延调用(continuation call) :
14051320 语言可提供一等实体(@4.2.1) 形式的续延即一等续延(first-class continuation) 。
1406-续延捕获把当前续延(@4.1.7) 具现(@2.3.2) 为对象语言中可操作的一等续延的操作。
1321+续延捕获把当前续延(@4.1.7) 具现(@2.3.4) 为对象语言中可操作的一等续延的操作。
14071322 符合函数类型要求(@4.5.2) 的一等续延可作为函数以直接作为合并子(@4.5.3.2) 构成函数合并(@4.5.3) 以外的方式进行函数调用,称为续延调用。
14081323 函数应用(如合并子调用(@4.5.3.2) )可隐含(非一等对象的)续延调用。
1409-续延调用的其它的具体形式由派生实现定义。另见 @4.7 。
1324+续延调用的其它的具体形式由派生实现定义。
14101325 除非另行捕获(capture) 续延,合并子被调用时以当前续延(current continuation) 返回(@4.5.3.1) 且仅返回一次。
1326+另见续延调用对程序控制的改变(@4.7) 。
14111327
14121328 @4.5.3.4 活动记录(activation record) :
14131329 活动的(@4.5.3.1) 合并子分配的对象称为活动记录。
@@ -1420,7 +1336,7 @@
14201336 在变量(@4.5.1) 绑定值后,兼容 λ 演算规约语义的表达式的具体求值(@4.1) 根据是否传递操作数对使用按需传递(@4.4.4.5) 的求值策略的情形分为三类:
14211337 (完全)惰性求值(lazy evaluation) 、部分惰性求值和热情求值(eager evaluation) 。
14221338 其中,惰性求值总是使用按需传递,热情求值总是不使用按需传递,部分惰性求值不总是使用或不适用按需传递。
1423-在保证不存在非纯求值(@4.4.2) 时这些求值的作用(@4.1) 没有实质差异。存在非纯求值时,使用的 λ 求值策略由派生实现定义。
1339+在保证不存在非纯求值(@4.4.2) 时这些求值的作用(@2.3.4) 没有实质差异。存在非纯求值时,使用的 λ 求值策略由派生实现定义。
14241340 非严格求值(@4.4.4.5) 严格蕴含惰性求值。两者经常但不总是一致,例如,实现可能并行地热情求值,并舍弃部分结果以实现非严格求值。
14251341 热情求值蕴含严格求值(@4.4.4.5) 。两者也经常但不总是一致,例如,实现可能使用应用序严格求值。但因为非严格的热情求值缺乏性能等可局部优化的实用动机,这种不一致的情况通常不作为附加的语言特性提供(而仅为简化实现默认作为全局策略使用)。
14261342 由于实现可能确定特定表达式的作用对约定必须保持的程序行为(@4.1.3) 没有影响而可能省略求值,按抽象机(@2.6) 语义的严格求值在实际实现中通常是不必要的。
@@ -1439,7 +1355,7 @@
14391355 @4.6.1.1 求值环境(evaluation environment) :
14401356 求值环境是在求值(@4.1) 时可访问的隐式上下文,包含变量的绑定(@4.1) 构成的集合。
14411357 按绑定的定义,求值环境即变量的名称和通过声明引入的被变量表示的实体构成的映射。
1442-不和实现环境(@2.3.2) 相混淆的情况下,简称(变量或绑定所在的)环境(environment) 。
1358+不和实现环境(@2.3.3) 相混淆的情况下,简称(变量或绑定所在的)环境(environment) 。
14431359 一个环境是空环境(empty environment) ,当且仅当其中的变量绑定是空集。
14441360
14451361 @4.6.1.1.1 实现环境提供的求值环境:
@@ -1455,7 +1371,7 @@
14551371 除非另行指定,NPL 只存在一种作用域,即所有作用域都使用相同的名称解析(@4.3.3) 和捕获规则。
14561372
14571373 @4.6.1.2 互操作上下文(interoperation context) :
1458-用于互操作的和求值(@4.1) 关联的隐式上下文是互操作上下文。
1374+用于互操作(@2.3.3) 的和求值(@4.1) 关联的隐式上下文是互操作上下文。
14591375 典型的实例为由 ISA 约定的通用架构寄存器的状态,可能需要在函数调用(@4.5.3.1) 或任务切换过程中保存和重置。
14601376 除非派生实现另行指定,语言不提供访问互操作上下文的公开接口。
14611377
@@ -1468,6 +1384,7 @@
14681384 称为类型的具体实体和之间的关联由派生实现的类型系统(type system) 规则指定。
14691385 默认类型系统不附加约束,所有表达式或关联的项都没有指定类型(untyped) ,为退化的平凡类型系统(trivial type system) 或单一类型系统(unityped system) ,实质上是动态类型。
14701386 对类型系统的分类中,类型也指确定类型的过程称为类型机制(typing discipline) ,其中确定类型的过程称为定型(typing) 。
1387+被定型的类型的实体可完全地满足其它类型的约束。前者具有后者的子类型(subtype) 。
14711388
14721389 @4.6.2.1 名义类型(nominal typing) 和结构化类型(structrual typing) :
14731390 通过显式指定标识(如名称)的方式定义类型的方法是名义类型,否则是结构化类型。
@@ -1511,7 +1428,7 @@
15111428 和控制状态不同,控制执行条件描述语言提供的不同控制机制的分类,而不被作为语言可编程的特性提供。
15121429 除非另行指定,仅由默认规约规则决定的执行条件是正常(normal) 的。
15131430 一个主要实例:以当前续延返回的合并子调用返回(@4.5.3.3) 是正常执行的。
1514-改变程序的正常的控制要求存在控制作用(@4.1) ,此时,控制执行条件是非正常(abnormal) 的。
1431+改变程序的正常的控制要求存在控制作用(@2.3.4) ,此时,控制执行条件是非正常(abnormal) 的。
15151432 一个主要实例:除非另行指定,隐含在默认规约规则确定的函数应用外的续延调用(@4.5.3.3) 是非正常的。
15161433 具有规约语义的语言总是支持正常控制条件。NPL 中,非正常的控制条件的支持是可选的。
15171434
@@ -1530,7 +1447,7 @@
15301447 除非派生实现另行指定,异常的控制作用总是同步(synchronized) 的,即:
15311448 在初始化异常实体时,保证存在与异常条件关联且可确定单一的执行线程(@2.4.2) 的状态作为引起控制状态改变即引发异常的来源;
15321449 异常条件的满足不依赖未和引发异常状态同步的程序中的其它的执行状态(包括其它未同步的线程的状态);
1533-确认满足异常条件和进入异常执行状态之间,上述执行线程内程序仅在引发异常的线程上的程序允许存在计算作用(@4.1)(这保证不被引起可观察行为改变的其它线程的操作中断)。
1450+确认满足异常条件和进入异常执行状态之间,上述执行线程内程序仅在引发异常的线程上的程序允许存在计算作用(@2.3.4)(这保证不被引起可观察行为改变的其它线程的操作中断)。
15341451 除非派生实现另行指定,未捕获的异常总是确定性地(deterministically) 持续引发异常的执行线程中引起控制的转移:
15351452 若捕获操作有效的上下文,控制转移捕获构造处理对应异常的异常处理器(exception handler) ;
15361453 否则,若在活动函数调用中,则单向地从当前活动(@4.5.3.4) 的函数向其主调函数(@4.5.2.1) 转移控制,使后者活动;
@@ -1540,7 +1457,7 @@
15401457 除非派生实现另行指定,活动函数的转移释放资源,应保证按和创建被其所有的实体的顺序的相反顺序一致的形式释放。这种释放活动记录占用资源的机制称为栈展开(stack unwinding) 。
15411458
15421459 @4.7.2 终止(termination) 保证:
1543-特定的求值具有(确定性地)终止保证,当且仅当预期求值总是在有限计算步骤内可描述的计算作用(@4.1) 。
1460+特定的求值具有(确定性地)终止保证,当且仅当预期求值总是在有限计算步骤内可描述的计算作用(@2.3.4) 。
15441461 具有终止保证的求值总是取得值或通过非正常控制的计算作用退出求值。
15451462 不具有终止保证的求值可能不终止,此时它具有取得值以外的计算作用;这种计算作用是副作用。
15461463 若一个函数的调用总是具有终止保证,则此函数是终止函数(terminating function) 。
@@ -1568,7 +1485,7 @@
15681485 通过回调对应依赖宿主语言(@5.2) 实现作为描述的指称语义;
15691486 在回调内对项和上下文进行操作,对应小步语义;
15701487 在回调内复用其它接口,对应大步语义。
1571-NPLA 可支持非固定的规约规则集合,以 API 的形式体现,详见 @6.5 ;另见 @5.5 。
1488+NPLA 可支持非固定的规约规则集合,以 API 的形式体现,详见规约 API(@6.5) ;另见表达式的求值(@5.5) 。
15721489 具体实现的编码风格导引参见 [Documentation::CommonRules @@5] 。
15731490
15741491 @5.2 NPLA 约定:
@@ -1592,24 +1509,24 @@
15921509 存在不保证先求值的子表达式(@3.4.2) 的形式是特殊形式(special form) 。
15931510 不保证求值都是纯求值;非特殊形式使用热情求值;其它情形使用热情求值或惰性求值(@4.5.4) 由具体特殊形式约定。
15941511 对象语言的函数(@4.5.2) 默认为过程(@4.5.2.1) 。过程默认实现为子例程(@4.5.2.1) 。过程指定的计算结果和函数表达式最终返回结果的关联(@4.5.2.1) 是过程调用(@4.5.3.1) 结果的一一映射。
1595-除非另行指定,实现函数(@4.5.2) 的宿主数据结构生存期要求默认同宿主语言;循环引用(@4.2.4) 可能行为未定义(另见 @5.2.4.4) 。
1512+除非另行指定,实现函数(@4.5.2) 的宿主数据结构生存期要求默认同宿主语言;循环引用(@4.2.4) 可能行为未定义(另见内存泄漏(@5.2.4.4) )。
15961513 除非另行指定,按值传递(@4.4.4.5) 支持复制初始化(@5.5.2) 对象的一等作用(@4.2.2.2) 。这和宿主语言的对应语义也保持兼容。
15971514 派生实现使用的项不满足特定的表示(@5.9.4) 。
15981515
1599-@5.2.1 本机实现(@2.4.1) 和互操作(interoperation) :
1516+@5.2.1 本机实现(@2.4.1) 和互操作(@2.3.3) :
16001517 NPLA 的宿主语言应能提供 NPLA 及派生实现的本机实现。
16011518 NPLA 的派生实现提供特定的和宿主语言的互操作支持。
16021519 本机实现可以具有 C++ 的实现兼容的二进制接口的函数提供,这些函数称为本机函数(native function) 。
16031520 本机实现可直接支持本机函数在实现中被调用。若被支持,具体接口由派生实现指定。
1604-本机函数作为函数的实现,其调用的求值可具有和非本机的函数一致的作用(@4.1) ,但不需要具有可被对象语言表达的函数体(@4.5.2) 。
1521+本机函数作为函数的实现,其调用的求值可具有和非本机的函数一致的作用(@2.3.4) ,但不需要具有可被对象语言表达的函数体(@4.5.2) 。
16051522 为确保函数求值的作用可能保持一致,本机函数应符合和本机函数调用时使用的规约一致的方式使用,即至少符合以下规约调用约定(calling convention) :
16061523 被调用时的子项被作为以 WHNF(@4.4.3.1) 形式表示的被调用的表达式使用;
16071524 调用后具有项被重写为必要的值以表示函数调用的返回值(@4.5.3.1) 。
16081525 本机函数的返回值应能表达任意的非本机函数调用的返回值,即通过求值函数调用(@4.5.3.1) 中函数体(@4.5.2) 的非本机函数的求值结果(@4.1) 。
16091526
1610-@5.2.2 NPLA 未定义行为(@2.3.2) :
1527+@5.2.2 NPLA 未定义行为(@2.3.4) :
16111528 NPLA 规则不排除未定义行为。其中,宿主语言的未定义行为是非特定体系结构或其它 ISO C++ 意义上不可预测或不可移植的行为。
1612-部分 NPLA 未定义行为会在实现中被检查以预防(尽可能避免)宿主语言的未定义行为,但这种检查不保证完全覆盖所有引起未定义行为的条件,不应预期其行为可移植。
1529+部分 NPLA 未定义行为可能在实现中被检查以预防(尽可能避免)宿主语言的未定义行为,但这种检查不保证完全覆盖所有引起未定义行为的条件,不应预期其行为可移植。
16131530 除非派生实现另行指定,NPLA 约定仅有具有以下情形的程序引起未定义行为:
16141531 互操作(@5.2.1) 时引起的宿主语言的未定义行为;
16151532 本机实现(@5.2.1) 不支持资源分配而引起宿主语言的未定义行为(如宿主语言函数调用的自动对象无法被分配);
@@ -1629,20 +1546,20 @@
16291546 类型映射可以是非空的多对一、一对多或一一映射。
16301547 若类型映射是一一映射,其类型等价性同宿主语言的语义规则;否则,由类型的语义规则约定。
16311548 类型系统(@4.6.2) 是开放(@1.4.3.6) 的,可能提供不被对象语言支持的宿主语言类型和值,如中间值(@5.6) 。
1632-因需提供与作为宿主语言的 C++ 的互操作性支持,所以明确约定实现中部分实体类型对应的 C++ 类型:
1549+但符合已指定的类型的实体需能被视为同种类型的实体使用,即子类型(@4.6.2) 。
1550+因需提供与作为宿主语言的 C++ 的互操作(@5.2.1) 支持,所以明确约定实现中部分实体类型对应的 C++ 类型:
16331551 用于条件判断的单一值的宿主类型是 bool 。
16341552 字符串(@3.2) 及和字符串的子集一一对应的词素(@3.3.1) 的宿主类型都是 string 类型(@5.3.1) 。
16351553 推论:字符串和词素可直接比较相等性或排序。
16361554 其它宿主类型所在的命名空间由实现(@5.4.1) 约定。具体宿主类型参见以下各节和对象语言类型对应的描述。
16371555 宿主类型在对应的 C++ API 中可能以类型别名的形式引入。
1638-另见 @4.2.6 。
16391556
16401557 @5.2.4 存储和对象模型:
16411558 NPLA 使用统一的模型对存储和对象进行抽象,并提供若干保证。
16421559 对象语言的存储被视为资源进行管理,称为存储资源(memory resource) 。
16431560
16441561 @5.2.4.1 基本模型:
1645-因需提供宿主语言(@5.2) 互操作性支持,除不支持静态(static) 存储和没有提供支持的存储操作外,NPLA 的基础存储模型和对象模型和 ISO C++11 相同。
1562+因需提供宿主语言互操作(@5.2.1) 支持,除不支持静态(static) 存储和没有提供支持的存储操作外,NPLA 的基础存储模型和对象模型和 ISO C++11 相同。
16461563 当前不支持的存储操作包括分配函数(allocation function) 取得的存储和线程局部(thread-local) 存储。
16471564 NPLA 还允许类似对象具有未指定的存储或不需要存储的实体,以使一等实体(@4.2) 可涵盖宿主语言在功能上等价的非对象类型(如 C++ 的引用)。这些实体若被支持,其存储实现和互操作接口由派生实现定义。
16481565 保证存储性质的差异不被依赖时,一等实体可按一等对象相同的方式实现。
@@ -1659,15 +1576,15 @@
16591576 求值结果(@4.1) 可包含一等对象(@4.1) ,称为结果对象(result object) 。结果对象和 ISO C++17(由提案 [WG21 P0135R1] 引入)中的概念对应。
16601577 函数调用(@4.5.3.1) 时以活动记录(@4.5.3.4) 保持被引用对象(@4.2.3) 的所有权。活动记录及其帧的具体结构、维护方式和生存期由派生实现定义。
16611578 除非另行指定,NPLA 只有一种作用域(@4.6.1.1.2) 。
1662-因为宿主语言函数调用实现(典型地,调用栈(call stack) 及其中的栈帧)不提供可移植的互操作性,除非另行指定,NPLA 的活动记录设计不需要保证直接对应关系。
1663-环境对象共享所有权,按值传递环境不引起其中所有的对象被复制。
1579+因为宿主语言函数调用实现(典型地,调用栈(call stack) 及其中的栈帧)不提供可移植的互操作(@5.2.1) ,除非另行指定,NPLA 的活动记录设计不需要保证直接对应关系。
1580+环境对象之间共享所有权(@5.4.3) ,按值传递环境不引起其中所有的对象被复制。
16641581
16651582 @5.2.4.3 内存安全(memory safety) :
16661583 (非并发)内存安全是存储资源避免特定类型不可预测错误使用的性质。
16671584 基本的内存安全保证蕴含非并发访问时不引起未定义行为。这至少满足:
1668-对存储的访问总是在提供存储的对象的存储期内,除非有其它另行指定的机制(如宿主环境的互操作)保证存储的访问不违反其它语义规则;
1585+对存储的访问总是在提供存储的对象的存储期内,除非有其它另行指定的机制(如宿主环境的互操作(@5.2.1) )保证存储的访问不违反其它语义规则;
16691586 宿主环境中不访问未被初始化的值。
1670-派生实现可能扩展内存安全,提供语言规则避免非预期的内存访问错误,提供安全 (security)保证,如保密性(secrecy) 和完整性(integrity) (另见 https://arxiv.org/abs/1705.07354 )。
1587+派生实现可能扩展内存安全,提供语言规则避免非预期的内存访问错误,提供更一般的高级安全(security) 保证,如保密性(secrecy) 和完整性(integrity) (另见 https://arxiv.org/abs/1705.07354 )。
16711588 除非另行指定,派生实现不提供扩展的内存安全保证。
16721589 NPLA 不对数据竞争避免(data race avoidence) 提供保证。
16731590 用户代码应注意避免违反内存安全的访问,包括非并发的,以及并发访问的内存冲突。
@@ -1676,12 +1593,12 @@
16761593 非内存安全操作是不保证内存安全的操作,在对象语言中即可能引起违反内存安全。
16771594 这些操作违反内存安全时,引起 NPLA 未定义行为(@5.2.2) ,且可能未被实现检查而同时引起宿主语言的未定义行为(@5.2.2) 。
16781595 NPLA 当前未被实现检查(@5.2.2) 的操作包括:
1679-未关联锚对象引用计数的 NPL::TermReference(@5.6.3) 初始化;
1596+未关联环境引用计数(@5.6.3.1) 的 NPL::TermReference(@5.6.3) 初始化;
16801597 非内存安全提升操作(@6.6.5) 。
16811598 对象语言中的非内存安全特性可能直接调用这些操作。NPLA 外依赖此类操作的其它操作也具有类似的性质。
16821599
16831600 @5.2.4.3.2 NPLA 对象语言内存安全保证:
1684-NPLA 中,确定地引入具有非内存安全操作(@5.2.4.3.1) 的对象的操作应仅只包括引入特定的间接值(@5.7.2) 或其它派生实现指定类型的值的操作:
1601+NPLA 中,确定地引入具有非内存安全操作(@5.2.4.3.1) 的对象的操作应仅只包括引入特定的间接值(@5.7.3) 或其它派生实现指定类型的值的操作:
16851602 调用引入不保证内存安全的间接值的 NPLA API(@6.6.5) ;
16861603 调用 NPLA 中其它取 YSLib::ValueNode 存储值的间接值的 API 。
16871604 排除非内存安全操作以及非内存安全的本机实现(@5.2.1) ,NPLA 实现的对象语言提供基本内存安全保证。
@@ -1723,7 +1640,7 @@
17231640 @5.2.5 生存期附加约定:
17241641 和宿主语言不同,NPLA 子表达式的求值顺序可被不同的函数(特别允许显式指定对特定操作数(@4.4.3.1) 求值的操作子(@4.5.3.2) )中的求值调整,不需要特别约定。
17251642 NPLA 不存在宿主意义上的完全表达式(@4.4.4.2) ,但在按宿主语言规则判断生存期时,使用本机实现(@5.2.1) 的函数合并(@4.5.3.2) 视同宿主语言的完全表达式,其本机函数调用不引起函数内创建的对象的生存期被延长。
1726-临时对象的生存期(@5.2.4.1) 同时约束隐含的隐式宿主函数调用(如复制构造)。
1643+临时对象(@5.2.4.2) 的生存期(@5.2.4.1) 同时约束隐含的隐式宿主函数调用(如复制构造)。
17271644 为保证求值表达式取得的临时对象(@5.2.4.2) 的内存安全(@5.2.4.3) ,函数合并同时满足以下规则:
17281645 操作符(@4.4.3.1) 和未被求值的操作数的直接或间接子表达式关联的对象以及求值操作数的子表达式引入的临时对象的生存期结束的作用应不后序(@4.4.1) 于活动调用(@4.5.3.1) 结束。
17291646 这同时确保引入临时对象时,其生存期不会任意地被延长(超过函数合并表达式的求值)。
@@ -1766,6 +1683,7 @@
17661683 http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.8567&rep=rep1&type=pdf
17671684 [Cl98]
17681685 https://www.akalin.com/evlis-tail-recursion
1686+因为本设计使用链接的环境(@5.4.3) ,不支持实现其中更激进的 safe-for-space 保证。
17691687
17701688 @5.2.6.4 TCO(Tail Call Optimization ,尾调用优化):
17711689 TCO 是在以尾上下文规约时,允许减少修改规约状态的优化。
@@ -1775,7 +1693,7 @@
17751693
17761694 @5.2.6.4.1 宿主语言中立:
17771695 C++ 不要求实现支持 PTC ,也不保证支持 TCO 。因此,对象语言的 PTC 要求显式的 TCO 实现。
1778-为可移植地支持 TCO ,NPLA 不依赖宿主语言中不可移植地互操作的活动记录(通常是体系结构相关的栈)。
1696+为可移植地支持 TCO ,NPLA 不依赖宿主语言中不可移植的互操作(@5.2.1) 的活动记录(通常是体系结构相关的栈)。
17791697 注意尾调用可避免尾上下文中非嵌套调用安全的情形的宿主语言实现的未定义行为(@5.2.7) ,但不保证非尾上下文中具有类似的性质。
17801698
17811699 @5.2.6.4.2 策略实现概述:
@@ -1788,7 +1706,7 @@
17881706 替换不满足 PTC 的对象语言原语为满足 PTC 的表达形式,称为目标(target) TCO 。
17891707 不依赖宿主语言特性的动态 TCO 包括以下形式:
17901708 通过合并不同活动调用(@4.5.3.1) 中活动记录占用的冗余状态,减少宿主语言的活动调用同时占用的总空间,称为 TCM(Tail Call Merging ,尾调用合并);
1791-引入具有便于操作控制作用(@4.1) 的构造,同时作为一些其它优化的基础,以消除部分活动记录状态的分配,称为 TCE(Tail Call Elimination ,尾调用消除)。
1709+引入具有便于操作控制作用(@2.3.4) 的构造,同时作为一些其它优化的基础,以消除部分活动记录状态的分配,称为 TCE(Tail Call Elimination ,尾调用消除)。
17921710 TCM 一般只减小尾调用(@5.2.6) 需要占用的活动记录,而 TCE 可能直接替换控制结构,同时减小运行操作需要的时间开销。但 TCE 变换自身可能需要额外开销且实现较复杂。因此,当前 NPLA 只支持 TCM 方式的 TCO 。
17931711 因为只使用 TCM ,相对没有 TCO 的基线版本,无法保证具有可预期的时间性能提升;相反,引入 TCM 可因为增加运行时存储分配和缓存局域性等原因降低性能(但一般实现应不影响复杂度类而只降低可接受的常数)。
17941712 TCM 引入的构造通常基于对象语言的内部变换。静态 TCO 使用的对宿主语言的自动变换和这种内部变换可基于相同的策略,如通过对程序全局变换得到的 CPS(@5.4.4) 或 ANF(Adminstrative Norm Form) )的中间表示(@2.4.1) 。
@@ -1867,7 +1785,7 @@
18671785 语法分析提供类 Session 表示分析处理一个翻译单元(@3.1) 的 NPL 源代码的会话。
18681786 会话利用词法分析器提取源代码中可被分析的信息,并提供使用指定词法解析器(@5.3.1) 取解析结果的 API 。
18691787 若不指定词法解析器,默认使用的词法解析器是 ByteParser(@5.3.1) 。
1870-会话的输出应满足可被 @5.4.1 表达的形式。这限制了可识别的外部表示(@4.1) 。
1788+会话的输出应满足可被 @5.4.1 表达的形式。这限制了可识别的外部表示(@2.3.4) 。
18711789 由 @4.1.1 ,这限定了翻译单元(@3.1) 的组成。例如,翻译单元中的源代码(@4.1.1) 一般应能对应语法上完整的表达式(@3.4.2) 。
18721790
18731791 @5.3.2.4 命名空间 NPL::SContext :
@@ -1879,8 +1797,8 @@
18791797
18801798 @5.4 NPLA 公共语言实现数据结构:
18811799 本节到 @5.8 节之间的内容外其它 NPLA 实现使用的接口详见模块 NPLA 和以下章节(@6) 。
1882-本节中的 API 都位于模块 NPLA ,详见 @6 。
1883-另见 @5.11.3 。
1800+本节中的 API 都位于模块 NPLA ,详见 NPLA 公共语言实现接口(@6) 。
1801+另见其它实现应用实例(@5.11.3) 。
18841802
18851803 @5.4.1 类型映射(@5.2.3) 实现:
18861804 类型映射使用的 C++ 类型在 namespace NPL 中声明,从 namespace YSLib 引入。
@@ -1893,8 +1811,8 @@
18931811 NPLA 实现语义规则时对 TermNode 进行处理,包括节点上的规约(@4.1) ,即树规约(tree reduction) 。TermNode 对象在树规约中表示被规约项(reduced term) 。
18941812 树规约的输入和各个规约步骤的结果中,变量不需要直接被表示,规约允许和输入 AST 中一致的未求值的名称,参见 @5.6.1 ;同时,允许在同一个树中包含经不同过程转换的结果,不需要显式区分阶段(@2.4.1) 。
18951813 因为绑定(@4.1) 的表示方法不在 IR 内特设指定,树规约不需要使用 HOAS(Higher-Order Abstract Syntax ,高阶抽象语法)。接受表达式到表达式的映射附加处理可通过派生实现约定对象语言中特定类型的对象实现,不要求被编码在规约的结果中。
1896-名称和作用域通过求值环境(@4.6.1.1) 维护,其数据结构参见 @5.4.3 。
1897-TermNode 中保存子节点的容器。当作为被规约项时,TermNode 的子节点对象是子项(@4.1) 的表示(@2.3.2) 。
1814+名称和作用域通过求值环境(@4.6.1.1) 维护,一般保存在环境数据结构(@5.4.3) 中。
1815+TermNode 中保存子节点的容器。当作为被规约项时,TermNode 的子节点对象是子项(@4.1) 的表示(@2.3.4) 。
18981816 TermNode 的 Value 数据成员称为值数据成员(value data member) ,是 ValueObject 类型的对象。用于表示对象语言( NPLA 实现)中表达式或对象储存的值,或者包装的中间值(@4.4.4.2) 。
18991817 TermNode 对子节点和值数据成员具有直接的独占所有权。
19001818 作为子节点的容器,TermNode 子节点的迭代器、指针和引用保持稳定,即移除子节点时不无效化(invalidate) 其它项的迭代器、指针和引用。
@@ -1936,7 +1854,7 @@
19361854 Unique :唯一引用。
19371855 Nonmodifying :不可修改。
19381856 Temporary :临时对象。
1939-默认值外仅用于 NPLA 项引用(term reference)(参见 @5.6.3 和 @5.6.3.1 )和派生实现。
1857+默认值外仅用于 NPLA 项引用(@5.6.3) 及其元数据(@5.6.3.1) 和派生实现。
19401858 在 TermTagIndices 中的枚举项带有 Index 后缀,和这些枚举项一一对应。
19411859 项的标签指定通过和标签关联的值访问的对象假定允许具有的性质。除非派生实现另行指定,违反这些假定不引起 NPLA 未定义行为(@5.2.2) 。
19421860 唯一引用允许通过通过具有唯一引用的项或项引用(@5.6.3) 访问关联的对象,对象可被假定不被其它引用而仅通过这个途径访问,即便实际存在其它途径的引用时可能引起不同的行为;在假定的基础上程序具有何种可能的行为是未指定的。
@@ -1944,7 +1862,10 @@
19441862 类似地,和宿主语言不同,违反不可修改标签引入的假定不引起未定义行为。
19451863
19461864 @5.4.3 环境数据结构:
1947-求值环境(@4.6.1.1) 以 Environment(@6.9.1) 类相关的类型表示,其中包含变量名称到表示被绑定对象(bound object) 的映射,称为名称绑定映射(name binding map) ,对被绑定对象具有所有权。
1865+求值环境(@4.6.1.1) 以 Environment(@6.9.1) 类相关的类型表示。
1866+环境对象包含变量名称到表示被绑定对象(bound object) 的映射,称为名称绑定映射(name binding map) 实现变量绑定(@4.1) 。
1867+名称绑定映射对被绑定对象具有所有权。
1868+推论:环境对象对被绑定对象具有所有权。
19481869 TermNode 对象在名称绑定映射中表示被绑定对象。
19491870 名称绑定映射释放变量绑定中的资源时,其中不同被绑定对象的销毁之间非决定性有序(@4.4.1) ,其它作用顺序未指定。
19501871 注意名称绑定映射中不同被绑定对象的生存期的起始和结束的顺序一般是不可追溯的,这和宿主语言在一些上下文中静态确定并保证销毁自动对象和创建对象的顺序相反不同。
@@ -1952,14 +1873,15 @@
19521873 环境引用共享环境对象的所有权。
19531874 根据所有权(@4.2.2.3) 管理机制的不同,环境引用包括环境强引用(strong reference) 和环境弱引用(weak reference) 。
19541875 引入环境弱引用作为一般的引用机制,且仅在必要时使用环境强引用,以避免过于容易引入循环引用引起强内存泄漏(@5.2.4.4.1) ,符合 @1.4.5.2 。
1955-传递环境引用不直接复制环境对象。另见 @4.2.3 。
1876+传递环境引用不直接复制环境对象。另见引用(@4.2.3) 。
19561877 环境是名称解析(@4.3.3) 时查找名称的目标(@4.3.3) 。
19571878 环境可引用关联的其它环境对象为父环境(parent environment) ,用于重定向(@4.3.3) 。
1879+通过其它环境实现重定向的方式表示环境是链接的(linked) 而非平坦的(flat) 。
19581880 Environment 支持定制名称解析和名称解析的重定向,其中包含以下相关的定制状态:
19591881 重定向算法;
19601882 名称解析算法;
19611883 可在运行时确定宿主类型(@5.2.3) 的父环境引用(用于重定向算法的实现)。
1962-默认的名称解析算法首先在名称绑定映射中查找局部变量的绑定(@4.1) ;若失败,调用重定向算法进行重定向,从父环境引用中取目标环境代替环境后代替环境继续使用其中的名称解析算法查找,直至没有可重定向的目标。
1884+默认的名称解析算法首先在名称绑定映射中查找局部变量的绑定;若失败,调用重定向算法进行重定向,从父环境引用中取目标环境代替环境后代替环境继续使用其中的名称解析算法查找,直至没有可重定向的目标。
19631885 默认的重定向算法依次检查重定向目标的宿主值(@5.5) 的类型。
19641886 对象语言中的环境引用类型的宿主类型是非递归的重定向目标类型。
19651887 不同宿主值类型具有不同的所有权。作为一等对象的环境引用的一般表达式值中,应根据是否需要具有所有权区分使用这些宿主类型的环境引用。
@@ -1968,7 +1890,7 @@
19681890
19691891 @5.4.4 上下文数据结构:
19701892 上下文(@4.6.1) 使用 ContextNode 类表示。
1971-ContextNode 对象保存上下文相关的公共状态,具体 API 详见 @6.9.4 。
1893+ContextNode 对象保存上下文相关的公共状态,具体接口详见上下文 API(@6.9.4) 。
19721894 上下文的公共状态包括当前处理的环境,称为环境记录(environment record) 。
19731895 环境记录指定了活动记录中当前的处理的帧(@4.5.3.4) ,指定对象语言中对应当前处理的帧的当前环境(current environment) 。
19741896 上下文对环境具有共享所有权(@5.2.4) ,通过环境对象的引用可以取指向它的引用(@6.9.1) 。
@@ -1994,7 +1916,7 @@
19941916 求值结果也用 TermNode 对象表示,以支持树规约(@5.4.2) 中直接基于项的替换操作实现求值。
19951917 求值结果可以是具有 TermNode 子项的列表(@5.4.2.1) 数据结构,详见 @5.9 。
19961918 TermNode 还可能表示求值的中间结果(即求值规约中取得对象语言表达式的值之前出现的值),如表示某些中间值(@5.6) 的情形。
1997-除非中间值也作为一等对象的表示(@4.1) ,NPLA 的规约范式(@5.8.4) 不会使用这些形式表示。
1919+除非中间值也作为一等对象的表示(@2.3.4) ,NPLA 的规约范式(@5.8.4) 不会使用这些形式表示。
19981920 表达式、表达式在求值过程中的中间表示(如中间值(@4.4.4.2) )和求值结果的表示统称规约表示。
19991921 在规约时,上下文(@4.6.1) 指定当前被求值项,确定当前被规约的 TermNode 。
20001922 表示值的 TermNode 是宿主语言对象具有的特定动态类型(@4.6.2) 的值是宿主值(hosted value) ,具有不固定的宿主类型(@5.2.3) 。
@@ -2016,18 +1938,18 @@
20161938 作为名称表达式(@4.5.1) 明确引用直接存储在环境中的对象及其包含的(数据成员)子对象的项都是左值。
20171939 右值一般存储在环境以外的项上;必要时,实现可能存储右值在特定的环境中。
20181940 值类别根据是否只关心表达式关联的(对象的或非对象的)值,在需要对象时提供区分两类一等对象(@4.2) 的机制,同时避免在仅需要表达式关联的值时引入不必要的其它对象。
2019-另见 @4.2.3 。
1941+另见引用(@4.2.3) 对一等状态(@4.2.2.1) 的支持(@4.2.3.3.2) 。
20201942
20211943 @5.5.1.1 类型系统和表示:
20221944 值类别在 NPLA 中被作为一种内建的类型系统,参见 @4.2.6 。
20231945 但在类型的值的内部表示上,值类别和特定的类型相关:
20241946 当前 NPLA 支持的左值都是项引用(@5.6.3) ,这同时表示引用值(@5.5.4) 。
2025-另见 @5.6.3 和 @5.9 。
1947+另见正规性(@5.9) 。
20261948
20271949 @5.5.1.2 设计原理:
20281950 按已有的规则,NPLA 约定求值至少需要支持以下的重要的性质:
20291951 第一,允许表达式直接表示一等实体而不论它是否是一等对象(@4.1)(即便按 @4.2.1 ,默认不会出现这种情形,派生实现仍然可能改变);
2030-第二,使用支持按引用传递的策略(@4.4.4.5) ,允许通过表达式构造引用不同对象的引用类型(reference type) 的值且被作为一等对象(@4.2) 传递(详见 @5.6.3 )。
1952+第二,使用支持按引用传递的策略(@4.4.4.5) ,允许通过表达式构造引用不同对象的引用类型(reference type) 的值且被作为一等对象(@4.2) 传递(详见项引用(@5.6.3) )。
20311953 一般地,这表示引入值类别的差异是必要的。因为,若假设平凡(trivial) 情形下,值类别可退化到都是泛左值或都是纯右值的情形。
20321954 若只存在泛左值,则任意的求值都决定一个对象;由于存在和一等对象无关的实体,无法满足第一条性质。
20331955 若只存在纯右值,则无法区分不同的对象,形式上无法构造出可用的引用类型的值满足第二条性质。
@@ -2035,14 +1957,14 @@
20351957 第三,求值满足递归蕴含规则(@4.4.4.1) ;
20361958 第四,允许对象的操作保持资源局域性,满足一等对象不依赖引用的抽象(@4.2.3) 同时允许按需区分是否依赖引用的两类一等对象;
20371959 第五,避免需要假设存在外部具有被引用对象(@4.2.3) 的所有权的所有者(@5.2.4.4) 。
2038-第三条性质保证表达式的作用(@4.1) 是可组合的并允许求值表达为树规约(@5.4.2) ,还保证能总是通过子表达式的值类别决定表达式的值类别。因为被求值的表达式是有限的,判定过程是总是能终止,即便求值不满足强规范化性质(@4.4.3) 。
1960+第三条性质保证表达式的作用(@2.3.4) 是可组合的并允许求值表达为树规约(@5.4.2) ,还保证能总是通过子表达式的值类别决定表达式的值类别。因为被求值的表达式是有限的,判定过程是总是能终止,即便求值不满足强规范化性质(@4.4.3) 。
20391961 第四条性质要求提供泛左值总是能作为纯右值使用的机制和通过纯右值引入对象的机制,详见值类别转换(@5.5.5) 。
20401962 第五条性质要求在表达式之外不存在地位相同的对象的存储资源(@5.2.4) 的所有者,限定了被决定同一性的对象的外延;存储由环境提供(@5.2.4) ,其中不需要保存对象的引用。
20411963
20421964 @5.5.2 初始化:
20431965 部分创建对象的表达式引入对象的初始化(initialization) 。
20441966 初始化包括被绑定对象(@5.4.3) 的初始化和作为函数值的返回值(@4.5.3.1) 对象的初始化。
2045-决定初始化这些对象的作用(@4.1) 的表达式是初始化的初值符(initializer) 。初值符的求值可能有副作用,其求值结果指定特定被初始化的对象的初始值(initial value) 。
1967+决定初始化这些对象的作用(@2.3.4) 的表达式是初始化的初值符(initializer) 。初值符的求值可能有副作用,其求值结果指定特定被初始化的对象的初始值(initial value) 。
20461968 初始化被绑定对象可能以修改操作(@4.1.4.2) 的形式体现,此时修改绑定具有副作用。若这样的副作用存在,每个被初始化的值后序(@4.4.1) 于对应初始的计算。
20471969 和宿主语言不同,初始化不是独立的依赖特定语法上下文的概念,但此处语义上的作用类似,一般可蕴含宿主对象的初始化。
20481970
@@ -2052,7 +1974,7 @@
20521974 复制初始化形式参数和函数值时,函数参数或返回值作为初值符。
20531975
20541976 @5.5.2.2 函数参数和函数值传递(@4.4.4.5) :
2055-部分函数可保证被初始化的值和初值符(@5.5.2) 的值及元数据(如 @5.6.3.1 )一致。
1977+部分函数可保证被初始化的值和初值符(@5.5.2) 的值及元数据(如项引用的元数据(@5.6.3.1) )一致。
20561978 类似宿主语言的完美转发(perfect forwarding) ,这样的参数或返回值的初始化的求值称为转发(forwarding) 。
20571979 转发也包括只部分保留上述部分元数据的情形。
20581980 在允许保留元数据不变的上下文,转发在本机实现(@5.2.1) 中可直接通过转移项实现。
@@ -2075,7 +1997,7 @@
20751997
20761998 @5.5.3.1 宿主对象转移消除:
20771999 一般地,当对象需要被转移且没有约定转移后要求类型不变(@5.5.2.3) 时,项的转移(@5.5.3) 可代替对象的转移(@5.5.2.3) ,避免初始化新的宿主对象。
2078-项的转移也类似 YSLib::ValueObject 自身的转移,其实现(当前通过 ValueObject 内部的 ystdex::any 的转移构造函数)保证直接转移对象而不保证转移构造所有的值。
2000+项的转移也类似 ValueObject 自身的转移,其实现(当前通过 ValueObject 内部的 ystdex::any 的转移构造函数)保证直接转移对象而不保证转移构造所有的值。
20792001 若需调用宿主对象的转移构造函数,需明确避免宿主对象转移消除的上下文中进行操作。派生实现可提供这些操作。
20802002
20812003 @5.5.4 引用值(reference value) :
@@ -2093,8 +2015,14 @@
20932015 前者是排除引用项表示且不是唯一引用(@5.4.2.2) 的引用值;后者是以引用项表示的唯一引用或临时对象初始化的非引用项的引用值。
20942016 左值引用和左值引用与宿主语言中的对象类型的左值引用与右值引用分别类似。
20952017 引用值是否作为左值(@5.5.1.1) 使用取决于上下文。除非另行指定,引用值都是左值。其中,在要求右值的上下文发生左值到右值转换(@5.5.5) 。
2096-引用值应引用在存储期(@5.2.4) 内的对象。否则,引用值是悬空引用(dangling reference) 。
2097-注意访问悬空引用不满足内存安全(@5.2.4.3) 而引起未定义行为。
2018+
2019+@5.5.4.1 有效性(@5.7.4) :
2020+有效的引用值应通过特定的构造引用值方式引入,包括:
2021+在对象语言通过被引用对象初始化引用值;
2022+互操作(@5.2.1) 引入的保证不引起未定义行为的引用值。
2023+一些对象语言的操作(如改变被引用对象)可能引起已被初始化的引用值成为悬空引用。
2024+指定引用无效化的具体操作(若存在)由派生实现定义。
2025+访问无效的引用值不满足内存安全(@5.2.4.3) 而引起未定义行为。
20982026
20992027 @5.5.5 值类别转换:
21002028 和宿主语言类似,具有特定值类别的表达式可转换为不同值类别的表达式:
@@ -2125,35 +2053,35 @@
21252053
21262054 @5.5.6 临时对象的引入:
21272055 和宿主语言的临时对象的使用方式类似,NPLA 的临时对象在特定的上下文中被引入。
2128-为简化规约和互操作机制的设计,和 ISO C++17 不同,临时对象仅在转换为消亡值(@5.5.1) 时的临时对象实质化转换(@5.5.5) 引入,而不包括延迟初始化或异常对象的创建。
2056+为简化规约和互操作(@5.2.1) 机制的设计,和 ISO C++17 不同,临时对象仅在转换为消亡值(@5.5.1) 时的临时对象实质化转换(@5.5.5) 引入,而不包括延迟初始化或异常对象的创建。
21292057 临时对象实质化转换引入临时对象的规则和 ISO C++17 不同:
21302058 不论表达式是否作为子表达式使其值被使用(未使用的情形对应 ISO C++ 中的 discarded-value expression ),都允许存在临时对象;
2131-要求复制消除(copy elision) 而避免特定对象的初始化(@5.5.2) ,参见 @5.5.6.3 。
2059+关于避免特定相关对象的初始化(@5.5.2) 的要求,参见复制消除(@5.5.6.3) 。
21322060
21332061 @5.5.6.1 实质化转换上下文:
21342062 可要求临时对象实质化转换的上下文包括:
21352063 使用纯右值初始化按引用绑定的变量(如函数的引用类型的形式参数(@4.5.2) );
21362064 求值函数调用以初始化返回值对象。
21372065 其中,按引用绑定的变量被可选地支持;若被支持,引入引用值的形式参数的具体形式由派生实现指定。
2138-一般地,按引用绑定的变量在活动调用(@4.5.3.1) 关联的环境分配临时对象(@5.2.4.2) 。此时,对象被调用表达式的项独占所有权,同时被绑定的环境独占资源所有权。
2066+一般地,按引用绑定的变量在活动调用(@4.5.3.1) 关联的环境分配临时对象。此时,对象被调用表达式的项独占所有权,同时被绑定的环境独占资源所有权。
21392067
21402068 @5.5.6.2 返回值转换上下文:
21412069 返回值转换(@5.5.5.2) 可引入实质化的临时对象,其中可能转移求值的中间结果(@5.5)(条件参见 @5.6.3.4 );否则,对象被复制。
2142-此处被转移对象符合 @5.2.4.2 的临时对象的定义,但除非另行指定,被转移的对象不在对象语言中可被访问。
2070+此处被转移对象符合求值和对象所有权(@5.2.4.2) 规则中的临时对象的定义,但除非另行指定,被转移的对象不在对象语言中可被访问。
21432071 此处的转移引起宿主对象转移消除(@5.5.3.1) 。
21442072 仅在对象被复制且复制具有副作用时,返回值转换具有等价复制的副作用。
21452073
2146-@5.5.6.3 复制消除:
2074+@5.5.6.3 复制消除(copy elision) :
21472075 和 ISO C++17 类似,NPLA 要求特定上下文中的复制消除,排除复制或转移操作且保证被消除操作的源和目的对象的同一性(@4.2.1.1) 。
21482076 和 ISO C++17 不同,NPLA 的复制消除限于临时对象的消除,但不限制对象的类型(特定的 C++ 类类型),且除以下约定外的所有表达式求值的上下文对复制消除相同(例如,不区分求值结果是否被作为返回值(@4.5.3.1) 或求值是否为常量表达式)。
2149-复制消除仅在以下转换上下文中被要求,即直接使用转换的源表达式中被求值项指称的对象(@5.7.3) 作为实质化的对象而不初始化新的临时对象:
2077+复制消除仅在以下转换上下文中被要求,即直接使用转换的源表达式中被求值项指称的对象(@5.7.5) 作为实质化的对象而不初始化新的临时对象:
21502078 实质化转换上下文(@5.5.6.1) ;
21512079 引起对象转移的返回值转换上下文(@5.5.6.2) 。
21522080 非本机实现(@5.2.1) 函数函数体内指定的返回值不属于上述的确定返回值的上下文,但也不要求被复制消除。这和 ISO C++17 要求 return 语句中的特定的表达式被消除不同,而不需要依赖特定上下文的语法性质。
21532081 实现仍可能根据当前环境(@5.4.4) 来判断是否在允许消除对象复制的上下文中(当前未实现),而进行复制消除。
21542082 在完成实质化转换前的不完整的求值规约(@4.4) 中的临时对象在逻辑上不需要作为一等对象(@4.1) 存在,但纯右值作为对象表示中的子项,随纯右值在宿主语言中作为对象存在,以允许互操作。
21552083 复制消除不在被初始化对象以外引入新的项。若被消除的对象来自不同的项,则复制消除为宿主对象转移消除(@5.5.3.1) 。这包括所有对象转移的返回值转换上下文的情形(@5.5.6.2) 。
2156-在使用纯右值初始化引用值时,延长源表达式的项指称的对象(@5.7.3) 的生存期(@5.2.5) 。这和初始化非引用值类似,但实现需区分是否初始化的是延长生存期的临时对象,以确保之后能区分是否按引用绑定。
2084+在使用纯右值初始化引用值时,延长源表达式的项指称的对象(@5.7.5) 的生存期(@5.2.5) 。这和初始化非引用值类似,但实现需区分是否初始化的是延长生存期的临时对象,以确保之后能区分是否按引用绑定。
21572085
21582086 @5.5.7 表达式的类型:
21592087 NPLA 的类型系统(@4.6.2) 使用隐式类型(@4.6.2.2) ;和 Scheme 及 Kernel 类似,默认使用潜在类型,保证表达式的值具有类型(@5.2) 。
@@ -2179,10 +2107,10 @@
21792107 @5.6.1 记号值(token value) :
21802108 NPL::TokenValue 类型的值表示记号(@3.3.1) ,可使用 string 类型的值构造,记号值类型。
21812109 由 @5.2.3 ,记号值对应的词素(@3.3.1) 作为名称,宿主类型为 string 。记号值对应的词素的宿主值和构造记号的 string 类型的值相等。
2182-记号值和词素在逻辑上非空,但因为除翻译单元外的外部表示(@4.1) 一般未指定(@4.1.1) ,不保证在 API 中取得的这些类型对应非空串,因此除特定的内部实现外不省略空串检查。
2110+记号值和词素在逻辑上非空,但因为除翻译单元外的外部表示(@2.3.4) 一般未指定(@4.1.1) ,不保证在 API 中取得的这些类型对应非空串,因此除特定的内部实现外不省略空串检查。
21832111 和字符串值不同,记号值求值的结果不会继续是记号值,以避免不经意的递归求值或无法和宿主语言字符串值区分的情形出现。
21842112 但在 API 层次上,记号值的求值不排除无限循环或递归,不保证对应的项作为表达式时具有强规范化性质(@4.4.3)。实现需注意保证作为名称表达式时满足强规范化要求(@5.2) 。
2185-表示一个未被求值的非字面量(@3.3.3) 记号的记号值称为符号(symbol) 。符号可构成名称表达式(@4.5.1) ,也可作为一等中间值。
2113+表示一个未被求值的非字面量(@3.3.3) 记号的记号值称为符号(@2.3.4) 。符号可构成名称表达式(@4.5.1) ,也可作为一等中间值。
21862114 符号的宿主类型(@5.2.3) 是 NPL::TokenValue 。
21872115 和 Kernel 类似,NPL 设计强调区分程序是否被求值的差异。符号是引入和表示为自求值项(@4.4.3) 的其它表达式的关键数据类型。
21882116 符号可能有外部表示。以未求值的记号值作为符号是其和外部表示关联的设计。由于外部表示未指定,这种关联是有限的。记号值蕴含了词素和符号的映射关系,即源代码文本;其余关系(包括源代码支持的文本编码)由派生实现指定。
@@ -2190,23 +2118,23 @@
21902118 记号值可出现在词法分析(@5.3.1) 阶段,由单独的规约过程(@5.8.3) 通过调用 NPL::TokenizeTerm(@6.4.3) 转换词素或直接初始化分析的中间结果得到。
21912119 记号值相关 API 参见 @6.4.2.1 。
21922120
2193-@5.6.2 环境引用:
2121+@5.6.2 环境引用(@5.4.3) :
21942122 环境引用是引用 Environment 类型的环境(@5.4.3) 并支持其共享所有权(@5.2.4.2) 的中间值。
21952123 环境引用类似引用值(@5.5.4) ,但隐含更复杂的所有权关系,因此不具有相同的类型(@5.5.7) 。
21962124 shared_ptr<Environment> 可引用环境对象,其非空值作为环境强引用(@5.4.3) 。
21972125 NPL::EnvironmentReference 可引用环境对象,封装 weak_ptr<Environment> 和锚对象(anchor object) 指针,其非空值表示可能具有共享所有权的环境弱引用(@5.4.3) 。
21982126 环境对象的弱引用的所有权关系使用其中的 weak_ptr<Environment> 确定。
2199-因为 weak_ptr<Environment> 不提供可靠的弱引用计数,引用锚对象附加的引用计数用于确定弱引用的数量,详见 @6.9.4 。
2127+因为 weak_ptr<Environment> 不提供可靠的弱引用计数,引用锚对象附加的引用计数用于确定弱引用的数量,详见上下文 API(@6.9.4) 。
22002128 默认构造的 shared_ptr<Environment> 是空的环境引用。
22012129 默认构造的 NPL::EnvironmentReference 具有空的 weak_ptr<Environment> 值,是空的环境引用。
22022130 非空的 shared_ptr<Environment> 和 NPL::EnvironmentReference 分别可作为对象语言的环境强引用和环境弱引用的宿主值。
22032131
2204-@5.6.3 项引用:
2132+@5.6.3 项引用(term reference) :
22052133 宿主语言中的 NPL::TermReference 是项引用。
22062134 NPL::TermReference 和所在的项中可能包含的子对象是引用值的宿主值(@5.5) 类型。
22072135 其中,子项只被 @5.6.3.5 的情形使用。
2208-子对象引用使用的这种形式的表示通常因为需要更多的操作比其它引用值的类似操作低效,但这种表示可避免依赖宿主语言中的本机对象内部表示(如成员布局)的依赖。
2209-一般地,在 C++ 的意义上不存在能满足语义的更有效的可移植表示,所以这种表示在和宿主语言的互操作上是必要的。
2136+子对象引用(@5.6.3.5) 使用的这种形式的表示通常因为需要更多的操作比其它引用值的类似操作低效,但这种表示可避免依赖宿主语言中的本机对象内部表示(如成员布局)的依赖。
2137+一般地,在 C++ 的意义上不存在能满足语义的更有效的可移植表示,所以这种表示在和宿主语言的互操作(@5.2.1) 上是必要的。
22102138 对 NPL::TermReference 相关操作详见 @6.4.4 ;可能使用 NPL::TermReference 访问项的操作详见 @6.4.5 。
22112139
22122140 @5.6.3.1 项引用的元数据(@4.2.3.3.1) :
@@ -2217,7 +2145,7 @@
22172145 当关联的环境不存在时,不提供对引入的对象内存安全(@5.2.4.3) 的检查(@5.2.2)。
22182146 引用值关联的环境是可靠的,当且仅当关联的环境是被引用对象的所有者。
22192147 不保证可靠的关联环境的引用值是不安全引用值(unsafe reference value) 。除非另行指定,仅有不存在关联环境的引用值是不安全引用值。
2220-(另见 @5.4.3 和 @5.2.4.3.1 。)
2148+另见非内存安全操作(@5.2.4.3.1) 和环境(@5.4.3) 。
22212149
22222150 @5.6.3.2 引用折叠(reference collapse) :
22232151 和 ISO C++ 类似,引用值在 NPLA 中默认不被继续引用,使用引用初始化引用会引用到被引用对象(@4.2.3) 上,即引用折叠。
@@ -2237,7 +2165,7 @@
22372165 一般地,非引用值的对象是可转移的。
22382166 确定引用值关联的被引用对象可转移的条件有两类:
22392167 由可转移项确定:引用值由可转移项表示,在特定的上下文使被引用对象能转换为右值(用例如 @7.1.4.2 );
2240-由被转发(@5.5.2.2) 表达式的值确定:除上述条件外,表示绑定临时对象的引用值(具有临时对象标签(@5.4.2.2) )的项蕴含被引用对象(@4.2.3) ,也是可转移的(用例如 @9.8 )。
2168+由被转发(@5.5.2.2) 表达式的值确定:除上述条件外,表示绑定临时对象的引用值(具有临时对象标签(@5.4.2.2) )的项蕴含被引用对象(@4.2.3) ,也是可转移的(用例如 @10.5 )。
22412169
22422170 @5.6.3.5 子对象引用(subobject reference) :
22432171 特定的引用值是子对象引用,通过一个引用值和它的子对象构造,引用被对象所有的一等对象。
@@ -2249,8 +2177,9 @@
22492177 NPLA 的实现约定统一的资源管理语义,并以此支持存储和对象模型(@5.2.4) 。
22502178 除非另行指定(如明确资源被共享使用),NPLA API 提供类型的对象按值传递(@4.4.4.5) 传递资源所有权(复制或转移资源)。
22512179 违反 NPLA 资源管理要求可引起宿主语言的未定义行为并违反 NPLA 内存安全保证(@5.2.4.3.3) 。
2252-基本的资源所有权约束由宿主语言的规则蕴含。部分数据结构可有更进一步的上下文相关的约定,如 TermNode 对象在作为被归约项(@5.4.2) 和被绑定对象(@5.4.3) 时具有不同的规则(参见 @5.7.3 )。
2253-NPLA 还引入称为间接值(indirect value) 的对象管理特定的资源,参见 @5.7.2 。
2180+基本的资源所有权约束由宿主语言的规则蕴含。
2181+部分数据结构可有更进一步的上下文相关的约定,如 TermNode 对象在作为被归约项(@5.4.2) 和被绑定对象(@5.4.3) 时具有不同的规则(参见有关的所有权规则(@5.7.5) )。
2182+NPLA 还引入称为间接值(indirect value) 的对象访问和管理特定的资源,详见 @5.7.3 。
22542183
22552184 @5.7.1 分配器(allocator) :
22562185 分配器分配资源,用于提供供实现指定的宿主语言的存储资源的来源。这和对象语言的存储资源(@5.2.4) 管理机制类似,但不保证对应。分配器隐含被映射的类型中,不显式出现在对象语言中。
@@ -2292,49 +2221,66 @@
22922221
22932222 @5.7.2 值所有权:
22942223 TermNode 对构成值的表示的子节点和值数据成员(@5.4.2) 具有所有权。和 @5.4.2 不同,非直接的所有权可能不是独占的。
2295-TermNode 表示对象语言中一等对象的所有权规则符合 @5.2.4 ,且作为被归约项时,符合 @5.7.3 或派生实现指定的其它规则的所有权约束。
2224+TermNode 表示对象语言中一等对象的所有权规则符合求值和对象所有权(@5.2.4.2) 规则,且作为被归约项时,符合被规约项的所有权(@5.7.5) 或派生实现指定的其它规则的所有权约束。
22962225 值对宿主对象(@5.5) 的所有权的机制由值数据成员(具有 ValueObject 类型)相关的 API 提供。
22972226 默认使用的 ValueObject 使用值的持有者 YSLib::ValueHolder ,直接作为对象的表示,同时具有对象的所有权。
2298-使用其它持有者或约定特定的中间值(@5.6) 实现间接值允许和所有权分离的其它形式的表示,提供和非间接值不同的对象所有权和附加操作。
2299-间接值具有访问被引用对象(@4.2.3) 的 API ,并确保允许复制或转移引用的对象以恢复对应的非间接值。
2227+引用一个项可能有多种方式,不具有所有权。关于引用相关的值的所有权,参见以下各个小节。
2228+
2229+@5.7.3 间接值分类和所有权:
2230+使用 ValueObject 的特定持有者或约定特定的中间值(@5.6) 实现间接值允许和所有权分离的其它形式的表示,提供和非间接值不同的对象所有权和附加操作。
2231+间接值的实例总是具有关联对象。间接值可间接访问关联对象。
2232+对作为对象语言中的一等对象的间接值,允许复制或转移关联的对象以恢复对应的非间接值作为一等对象直接访问。
23002233 间接值可用于代替非间接值,避免求值时改变环境(@5.4.3) 所有的非临时对象(@5.2.4.2) 的所有权。
23012234 间接值可实现和 C++ 引用类型表达式类似的行为。
23022235 NPLA 提供引入间接值的 API ,参见 @6.6.2 。
23032236 实现通过值数据成员以外的机制也可隐含固定(不通过用户代码修改定制)的所有权关系,如上下文(@5.4.4) 和环境(@5.4.3) 。
23042237 所有权机制和中间值(@5.6) 正交:具有间接值的对象可能作为中间值,也可能不作为中间值。
2305-引用一个项可能有多种方式,不具有所有权。关于引用相关的值的所有权,参见以下小节。
2306-
2307-@5.7.2.1 引用值:
2308-使用 NPL::TermReference(@5.6.3) 作为间接值引用一个项。
2309-
2310-@5.7.2.2 引用持有者:
2311-使用持有者 YSLib::RefHolder 的实例可实现间接值。
2238+本节以下约定要求被 NPLA 实现支持的间接值。派生实现可以定义 NPLA 扩展间接值。
2239+
2240+@5.7.3.1 环境引用(@5.6.2) :
2241+环境引用间接访问环境对象。
2242+环境强引用(@5.6.2) 可能共享环境对象的所有权,对环境对象的名称绑定映射(@5.4.3) 持有的项具有间接的所有权。
2243+
2244+@5.7.3.2 引用值:
2245+使用项引用(@5.6.3) 作为间接值引用一个项,访问被引用对象(@4.2.3) 。
2246+这也包括使用子对象引用(@5.6.3.5) 的情形。
2247+
2248+@5.7.3.3 引用持有者:
2249+使用持有者 YSLib::RefHolder 的实例可实现间接值,访问其它 ValueObject 对象。
23122250 被间接引用的值的类型和 TermNode 的值数据成员(@5.4.2) 取得的类型一致,可直接替换非间接引用的对象。
2313-引用持有者一般并不能替代引用值(@5.7.2.1) ,因为持有者仅影响存储来源和所有权,不区分类型,也无法要求用户代码使用明确的引用操作。
2251+引用持有者一般并不能替代引用值(@5.7.3.2) ,因为持有者仅影响存储来源和所有权,不区分类型,也无法要求用户代码使用明确的引用操作。
23142252 一般引用的持有者的项仅作为上述明确的引用操作的结果,作为中间结果继续以和非间接值一致的方式被规约(使用 NPL::LiftTermRef(@6.6.2) )。
23152253
2316-@5.7.3 被规约项(@5.4.2) 所有权:
2254+@5.7.4 间接值的有效性:
2255+间接值有效当且仅当存在关联的对象且访问对象不引起未定义行为。
2256+其它间接值是无效(invalid) 的。
2257+类似实现中项的无效化(@5.4.2) ,有效的引用值可能被无效化(invalidate) 不再有效。
2258+因关联的对象存储期(@5.2.4) 结束而被无效化的是悬空(dangling) 间接值。
2259+引用值(@5.7.3.2) 作为一种间接值,其规则是上述规则的实例。
2260+以下约定要求被 NPLA 实现支持的有效的引用值总是无条件地允许访问对象。
2261+
2262+@5.7.5 被规约项(@5.4.2) 所有权:
23172263 具有值类别的被规约项若指称对象,对应的对象是这个项的项对象(term object) 。项对象是求值结果(@4.1) 或求值的中间结果(@5.5) 对应的对象。
23182264 项对象可能不直接由项自身表示,即可以通过项引用其它途径引入的对象。
2319-基于 @5.7.2 ,为保证内存安全,避免临时对象被引用,仅在泛左值(@5.5.1) 中允许引入被可能引用的间接值。
2265+基于 @5.7.3 ,为保证内存安全,避免临时对象被引用,仅在泛左值(@5.5.1) 中允许引入被可能引用的间接值。
23202266 推论:泛左值的项对象不是临时对象,被环境所有。
23212267 通常纯右值作为其它项的子项而被独占所有权,求值时可能通过临时对象实质化转换(@5.5.5) 标识创建的临时对象(@5.5.6) 。
2322-作为 @5.2.4 的实现,临时对象以项自身作为表示(@5.5) ,被纯右值所有,也间接被其它项所有。
2323-特定情况下纯右值可能被环境所有,但应只通过复制等方式访问其值而不依赖所有权关系(如仅复制记号值(@5.7.4.2) )。
2324-
2325-@5.7.4 间接值使用规则:
2326-在特定的适当情形(详见以下小节)下复制或转移间接值引用的对象以保证满足生存期要求(@5.7.3) ,维护内存安全。
2268+为实现临时对象求值和对象所有权(@5.2.4.2) ,临时对象以项自身作为表示(@5.5) ,被纯右值所有,也间接被其它项所有。
2269+特定情况下纯右值可能被环境所有,但应只通过复制等方式访问其值而不依赖所有权关系(如仅复制记号值(@5.7.6.2) )。
2270+
2271+@5.7.6 间接值使用规则:
2272+在特定的适当情形(详见以下小节)下复制或转移间接值引用的对象以保证满足生存期要求(@5.7.5) ,维护内存安全。
23272273 不能满足上述适当情形条件的若不明确引起错误,则行为未定义。
23282274 间接值生存期规则:被规约对象中间接值的生存期总是不超过被引用的环境中的对象,以保证内存安全。
23292275 不满足间接值生存期规则的情形,除非提供派生实现定义的其它保证,不保证内存安全。
23302276 以含间接值的项替代不含间接值的项称为引入间接值。
23312277 包含间接值的项可被不含引用值的项替代,称为消除。
23322278 如需直接替换项表示的值,需消除间接值。否则,没有必要提前对项进行操作以提前移除间接值。
2333-关于被求值的被规约项中的对象的所有权,另见 @5.7.3 。
2279+另见被求值的被规约项中的对象的所有权(@5.7.5) 。
23342280 派生实现可基于本节约定其它规则。
23352281
2336-@5.7.4.1 引用值(@5.5.4) 作为间接值:
2337-由于左值(@5.5.1) 的项对象被环境所有(@5.7.3) ,在项上的求值需要其它项对象作为中间值。
2282+@5.7.6.1 引用值(@5.5.4) 作为间接值:
2283+由于左值(@5.5.1) 的项对象被环境所有(@5.7.5) ,在项上的求值需要其它项对象作为中间值。
23382284 这种中间值通过间接引用左值以确保左值标识的对象可作为一等对象(@4.1) 使用,也是一种间接值,即引用值(@5.5.4) ,是引用(@4.2.3) 的实例。
23392285 NPL::TermReference(@5.6.3) 类型是可能需要区分引用与被引用对象的值的内部表示。
23402286 这类似宿主语言的对象类型的左值引用和右值引用的差异(@5.5.4) 。
@@ -2343,30 +2289,31 @@
23432289 和宿主语言的涉及成员访问的表达式类似,直接使用标识符进行名称查找(@4.3.3) 得到的表达式是左值或消亡值。在此环境总是被视为左值,所以结果由环境中的对象类型确定:当且仅当对象是左值时,结果是左值引用;否则是右值引用。
23442290 和宿主语言类似,右值引用类型的表达式可作为左值使用。
23452291 一般地,并非所有对象需要引用,详见 @4.2.3 。
2346-引用值在必要时被消除(@5.6.4.3) ,以被进一步求值。
2347-
2348-@5.7.4.2 其它间接值:
2349-规约实现在特定情形的求值中使用 NPL::LiftTermRef 等(@6.6.2) 引入基于引用持有者(@5.7.2.2) 的间接值避免求值时改变泛左值(@5.5.1) 标识的非临时对象的所有权。
2292+引用值在必要时被消除(@5.6.3.3) ,以被进一步求值。
2293+
2294+@5.7.6.2 非引用值间接值:
2295+规约实现在特定情形的求值中使用 NPL::LiftTermRef 等(@6.6.2) 引入基于引用持有者(@5.7.3.3) 的间接值避免求值时改变泛左值(@5.5.1) 标识的非临时对象的所有权。
23502296 否则,引入的间接值引用环境所有的对象。
23512297 应注意存储环境以外的间接值时,不超出持有对象的存储期,避免未定义行为(@5.2.4) 。当前实现不对此附加检查。
23522298 注意不求值而仅替换项时,使用 NPL::LiftOther 或 NPL::LiftTerm(@6.6.1) ,这不引入间接值。
2353-除构造间接值的例程(@6.6) ,当前不直接引入引用持有者。如需要引入间接值,使用引用值(@5.5.4) 而不是其它间接值,以统一处理无法直接持有的列表项和非列表项的引用。
2354-
2355-@5.7.4.3 间接值的消除:
2299+除构造间接值的例程(@6.6) ,当前不直接引入引用持有者。
2300+如需要引入环境引用(@5.7.3.1) 外的间接值,一般使用引用值(@5.5.4) 而不是非引用值间接值,以统一处理无法直接持有的列表项和非列表项的引用。
2301+
2302+@5.7.6.3 间接值的消除:
23562303 访问间接值涉及维护内存安全保证(@5.2.4.3) 时,可能需要提升项(@6.6) 以移除允许非内存安全(@5.2.4.3.1) 访问的间接值。
23572304 引用值作为间接值可被消除(@5.6.3.3) 。
23582305 用于按值传递参数时,一般使用 NPL::LiftTerm(@6.6.2) 和确保创建值副本的 NPL::SetContentWith(@6.2.1) 实现;前者取非引用类型的右值(@5.5.1) ,后者提升间接值确保结果不是中间值。
2359-用于按值传递返回值时(@4.5.3.1) ,除显式分别对是否为引用值的情形进行处理,可使用 NPL::LiftToReturn(@6.6.3)(其中也使用以上方式实现),实现临时对象实质化转换(@5.5.5) ,详见 @5.7.4.4 。
2360-
2361-@5.7.4.4 返回值转换(@5.5.5.2) :
2362-作为提升项的使用用例(@5.7.4.3) ,在返回值转换上下文(@5.5.6.2) 中确定函数返回值的实质化转换上下文(@5.5.6.1) 的部分操作消除引用值(@5.6.3.3) ,即返回值转换。
2306+用于按值传递返回值时(@4.5.3.1) ,除显式分别对是否为引用值的情形进行处理,可使用 NPL::LiftToReturn(@6.6.3)(其中也使用以上方式实现),实现临时对象实质化转换(@5.5.5) ,详见 @5.7.6.4 。
2307+
2308+@5.7.6.4 返回值转换(@5.5.5.2) :
2309+作为提升项的使用用例(@5.7.6.3) ,在返回值转换上下文(@5.5.6.2) 中确定函数返回值的实质化转换上下文(@5.5.6.1) 的部分操作消除引用值(@5.6.3.3) ,即返回值转换。
23632310 这可约束作为间接值的引用值不逃逸(escape)(即使用被引用对象的值时不超出指向对象的生存期),而保证只考虑项的值数据成员(@5.4.2) 可能是引用值时的内存安全。
23642311 返回值转换不保证未折叠的引用值在消除引用值后的结果不逃逸。为确保内存安全,程序仍需要保证被引用的对象的间接引用的对象生存期结束后,不能访问间接引用的对象。
2365-除非证明不需要临时对象(当前未实现),返回值转换中初始化临时对象作为返回值的项对象(@5.7.3) 。
2312+除非证明不需要临时对象(当前未实现),返回值转换中初始化临时对象作为返回值的项对象(@5.7.5) 。
23662313 是否需要返回值转换由实质化转换上下文中的被调用的函数而非上下文是否需要使用右值决定,无关被转换的表达式是否是左值,因此返回值转换不是左值到右值转换(@5.5.5) 。
23672314 不论是否存在返回值转换,返回值的项对象来自返回的右值关联的临时对象实质化转换(@5.5.6) 。这可能在 NPL::LiftToReturn 或之前的求值规约的调用中蕴含。
23682315
2369-@5.7.5 被归约项稳定性:
2316+@5.7.7 被归约项稳定性:
23702317 基于 TermNode 的性质,未被规约修改的项的子项的迭代器、指针和引用保持稳定(@5.4.2) 。
23712318 被规约的项在取得求值结果(@5.8.1) 前不被删除,以避免项的迭代器、指针和引用失效。
23722319 结合 @4.2.4.1 得到推论:被规约的项在取得求值结果起可被非内部对象(@4.2.4.1) 引用。
@@ -2376,20 +2323,20 @@
23762323 在取得求值结果前,若项不改变可观察行为(@4.1.3)(例如,项不被作为对象语言中的表达式或求值结果的表示(@5.5) 或表示的值在对象语言中不可见),可能被转移。
23772324 这允许规约的本机实现内部在取得求值结果前保存表示不属于求值结果的中间结果的子项。
23782325
2379-@5.7.5.1 规约操作资源:
2326+@5.7.7.1 规约操作资源:
23802327 规约时保持决定当前规约操作的状态的资源的独占所有权([Documentation::CommonRules @@2.3.4.6]) 的项应具有足够长的生存期,以避免调用时引起未定义行为。
23812328 实现 WHNF(@4.4.3.1) 时,第一个子项对此资源具有独占所有权。
23822329 在无法预知子项是否需要被进一步使用而不会在被调用前另行存储包含这些资源的项时,实现使用的操作应避免删除这里的子项(对实现 WHNF 而言即第一个子项),以免无法使用其中的状态。
23832330
2384-@5.7.5.2 临时对象资源:
2331+@5.7.7.2 临时对象资源:
23852332 表示临时对象的项的子项的迭代器、指针和引用应保持稳定,以支持子项被绑定到对象语言中的引用值(@5.5.4) 。
23862333 表示临时对象的项自身不需被绑定到引用值,不保证稳定,可被直接存储为 TermNode(而不需要保存为指针等间接值)。
23872334 对临时对象分配资源可能转移表示临时对象的项,但不影响其子项的稳定性。
23882335
2389-@5.7.6 项修改限制:
2336+@5.7.8 项修改限制:
23902337 若规约需调整项的结构以便使用特定 API ,可使用 TermNode& 作为参数的规约函数(@5.8.5)(另见 @6.5.3 );
2391-如不可行,一般需转移到新创建的项上进行调用,以免改变现有的项导致无法使用项独占所有权的资源(如 @5.7.5.1 的状态)。
2392-单独转移可能具有宿主类型对象的子项会违反固定对象的约定(@5.7.5) ,因此除非确保子项不被引用,不单独转移或销毁可能带有宿主对象(@5.5) 的子项(包括引起子项对象被销毁的删除操作)。
2338+如不可行,一般需转移到新创建的项上进行调用,以免改变现有的项导致无法使用项独占所有权的资源(如 @5.7.7.1 的状态)。
2339+单独转移可能具有宿主类型对象的子项会违反固定对象的约定(@5.7.7) ,因此除非确保子项不被引用,不单独转移或销毁可能带有宿主对象(@5.5) 的子项(包括引起子项对象被销毁的删除操作)。
23932340 若规约内部确定符合内存安全(@5.2.4.3) 或派生实现指定的假定满足的条件(至少应满足 @5.7 中的资源管理要求),子项可被转移或销毁。这些操作包括:
23942341 被规约项取得自求值结果起,在非内部对象引用此项前被整体转移的操作;
23952342 NPLA 指定删除或其它可能转移或销毁子项的操作;
@@ -2424,8 +2371,8 @@
24242371
24252372 @5.8.2.1 子项的清理(cleanup) :
24262373 纯值规约(@5.8.1) 要求清理操作,即移除不被需要(@5.8.1) 的子项。
2427-清理时子项所有的对象被销毁,可具有副作用(@4.1) 。
2428-子项的清理属于 @5.7.6 中约定的删除子项的操作。
2374+清理时子项所有的对象被销毁,可具有副作用(@2.3.4) 。
2375+子项的清理属于 @5.7.8 中约定的删除子项的操作。
24292376
24302377 @5.8.3 规约迭代:
24312378 对项的一次规约可分解为若干个对这个项的分步规约的有序的迭代过程,每个过程称为一个遍(pass) ;另见 @6.8 。
@@ -2485,7 +2432,7 @@
24852432
24862433 @5.8.4.2 规范化规约(@4.4.3) 约定:
24872434 除非另行指定(@5.9.2) ,一次终止的规约迭代中若存在规范化规约,其发生的次数和时机未指定;一般在最后一遍(@5.8.3) 或之前存在一次即可。
2488-注意规范化规约可能有副作用(@4.1) ,实现应保证规约行为可被预期。
2435+注意规范化规约可能有副作用(@2.3.4) ,实现应保证规约行为可被预期。
24892436
24902437 @5.8.5 规约函数:
24912438 接受 TermNode 和其它参数进行规约的 API 主要以宿主语言的函数(子例程)的形式提供,称为规约函数。
@@ -2511,7 +2458,7 @@
25112458 推论:非正规表示中不能依赖特定对象的同一性(如值数据成员直接引用子项)。
25122459
25132460 @5.9.1 规约表示基本性质:
2514-除非另行指定(参见 @5.9.4 ),NPLA 实现应保证规约表示满足以下基本性质:
2461+除非另行指定(参见非平凡非正规表示(@5.9.4) ),NPLA 实现应保证规约表示满足以下基本性质:
25152462 任一遍规约中,非正规表示应是平凡的。
25162463 规约表示基本性质允许在已知 TermNode 得到范式时通过直接判断项的节点结构(@5.4.2.1) 是否存在子项代替推断此次规约中之前的规约结果。
25172464 在对象语言输入可保证不存在非正规表示的前提下,这样的设计满足原则 @1.4.1.1 和 @1.4.2.2 。
@@ -2526,12 +2473,12 @@
25262473 因为子项的删除时机未指定(@5.4.2) ,不假定 NPLA 实现的规约清理求值后的节点,即清理由派生的具体规约实现指定。
25272474 一般在一个表达式取得求值结果(@5.8.1) 前,清理纯值规约要求排除的子项。
25282475 纯列表规约的规范化标记值数据成员为特定的值,可以是默认构造的空值或派生实现定义的表达式项(@5.5) 内的值数据成员外的记号值(@5.6.1) 。
2529-除 @5.9.4 指定的情形(通过先行判断值数据成员而排除)外,当前未从非纯值规约结果中区分纯列表规约,因此不对纯列表规约进行操作。
2530-注意正规化操作和之前的清理操作可能会影响项的生存期;另见 @5.7.5.1 。
2476+除非平凡非正规表示(@5.9.4)(通过先行判断值数据成员而排除)外,当前未从非纯值规约结果中区分纯列表规约,因此不对纯列表规约进行操作。
2477+注意正规化操作和之前的清理操作可能会影响项的生存期;另见规约操作资源(@5.7.7.1) 。
25312478 对同一个规约结果的正规化操作是幂等(@4.1) 的,超过一次的连续正规化操作无其它作用。
25322479
25332480 @5.9.3 正规表示分类:
2534-基于规约表示基本性质(@5.9.1) ,除非另行指定(参见 @5.9.4 ),不需要单独判断正规表示。
2481+基于规约表示基本性质(@5.9.1) ,除非另行指定(参见非平凡非正规表示(@5.9.4) ),不需要单独判断正规表示。
25352482 基于正规化操作规则(@5.9.2) ,通过以下逻辑对作为表示(@5.5) 的 TermNode 分类:
25362483 具有非空子项的 TermNode 表示非空列表(@5.4.2.1) ;
25372484 空节点表示空列表(@5.4.2.1) ;
@@ -2625,12 +2572,13 @@
26252572 显式使用保留给实现的标识符。
26262573
26272574 @5.11.2 NPLA1 应用实例:
2575+在对象语言(@7) 外,NPLA1 的实现也被用于其它应用。
26282576 NPLA1 当前加入特定的序列化和反序列化作为配置文件,参见 NPL::Configuration 。
26292577 NPLA1 的上述配置文件加入特定的匹配和初始化机制作为 YSLib::UI::Loader([Documenatation::YSLib @@5.11.9]) 在运行时读取用户界面布局和配置的脚本。
26302578 NPLA1 用于 MIME 类型和文件名映射([Documentation::YSLib @@4.5.3]) 的实现,上述配置文件对应的外部配置格式。
26312579 注意这些应用不直接使用 NPLA1 的语义,其中使用的 TermNode 类型中名称直接表示上下文(@4.6.1) 中的实体名称。
26322580 计划使用完整的实现(@7) 取代这些应用的底层,使用 NPLA1 作为对象语言或作为附加的代码生成遍重新实现这些应用,但具体路线图未定。
2633-关于当前提供的应用,另见 @8.5 和 @10 。
2581+关于当前提供的应用,另见依赖管理模块(@8.5) 和 @10 。
26342582
26352583 @5.11.3 NPLA 其它实现应用实例:
26362584 NPL::SXML 命名空间提供的 API 部分支持以 NPLA 分析 SXML 及构造 NPLA 表示的节点并转换为 XML 输出。
@@ -2643,13 +2591,13 @@
26432591
26442592 @6 NPLA 公共语言实现接口:
26452593 部分实现的功能由公共 API 的形式提供,以便派生实现复用。
2646-用于 @5.11.2 和 @5.11.3 等部分不直接用于 NPLA 解释实现的 API 可能在本节中被略过。
2594+用于NPLA1 应用实例(@5.11.2) 和 NPLA 其它实现应用实例(@5.11.3) 等部分不直接用于 NPLA 解释实现的 API 可能在本节中被略过。
26472595 一些 API 仅列出名称,其具体描述详见接口文档(通过源代码注释生成)。
26482596
26492597 @6.1 安全保证:
26502598 除以下例外,NPLA 实现及对应可能由用户提供的替换的实现应支持嵌套调用安全(@5.2.7) :
26512599 直接递归遍历节点的操作如 NPL::SetContentWith(@6.2.1) 和 NPL::TokenizeTerm(@6.4.3) ;
2652-因为直接或间接调用上述遍历节点实现的操作,详见 @6.6.6 ;
2600+因为直接或间接调用上述遍历节点实现的操作,详见不支持嵌套调用安全的提升操作(@6.6.6) ;
26532601 派生实现定义的情形。
26542602
26552603 @6.2 节点(node) 操作:
@@ -2702,7 +2650,7 @@
27022650 NPL::InvalidReference
27032651 除 @6.2.2 外,NPLA 实现可能抛出这些异常或派生实现定义的派生这些类的其它异常。
27042652 NPLA 实现可能抛出标准库异常。
2705-一般地,不通过对象语言构造(而仅通过互操作或实现缺陷)引起的异常,不使用 NPL 异常基类。
2653+一般地,不通过对象语言构造(而仅通过互操作(@5.2.1) 或实现缺陷)引起的异常,不使用 NPL 异常基类。
27062654
27072655 @6.4 上下文无关非节点处理 API :
27082656 NPLA 实现提供不依赖一般项规约逻辑(@5.8) 的公共 TermNode 操作 API 。
@@ -2717,12 +2665,12 @@
27172665 @6.4.2 规约相关类型别名:
27182666
27192667 @6.4.2.1 记号值:
2720-基本概念参见 @5.6.1 。
2668+基本概念参见 NPLA 记号值(@5.6.1) 。
27212669 调用 NPL::TermToNamePtr(@6.4.3) 访问具有记号值的名称节点对应的字符串。
27222670
2723-@6.4.2.2 锚对象(@5.6.3) 指针:
2671+@6.4.2.2 锚对象(@5.6.2) 指针:
27242672 NPL::AnchorPtr 是锚对象的指针的类型,是不确定类型的 shared_ptr 实例。
2725-相关 API 详见 @6.9.4 。
2673+相关接口详见上下文 API(@6.9.4) 。
27262674
27272675 @6.4.3 项访问操作:
27282676 NPLA 提供访问若干访问 TermNode 的便利接口。
@@ -2741,6 +2689,7 @@
27412689 NPL::TermReference(@5.6.3) 包括若干成员,其中主要有以下 API :
27422690 IsMovable
27432691 GetEnvironmentReference
2692+get
27442693 对 NPL::TermReference 的相关操作包括以下 API :
27452694 NPL::Collapse
27462695 NPL::PrepareCollapse
@@ -2823,17 +2772,17 @@
28232772 NPL 的表达式的语法是递归表示的,因此包括对列表表达式子项的递归规约。使用单一规约函数实现的这种规约一般即树规约(@5.4.2) 。
28242773 规约实现作用在对象语言表达式上通用的求值算法(evaluaton algorithm) ,符合规约性质(@5.5) 。
28252774 主规约函数是提供这种单一规约函数实现的直接规约函数(@6.5.3.1) 。
2826-间接值(@5.7.2) 对主规约函数透明,不被直接处理。
2775+间接值(@5.7.3) 对主规约函数透明,不被直接处理。
28272776 推论:主规约函数实现的求值算法中,被求值的表达式不发生值类别转换(@5.5.5) 。这简化实现的复杂性,并允许派生实现单独处理需要间接值(如引用值)的情形,并在其它情形避免不需要的开销。
28282777
28292778 @6.6 提升项:
28302779 对项的提升(lifting) 指一类对项的替换变换,使用项进行一定的变换后取代其它项或其一部分,并满足下述提升条件。
28312780 决定替换变换是提升的条件为:被提升的项是提升后的项的一个直接或间接子项,以树表示项则为叶节点取代枝节点。
2832-这可以视为消去 λ 抽象的 lambda 提升(详见 https://en.wikipedia.org/wiki/Lambda_lifting )的一般化,但此处和 λ 抽象没有直接关联。
2781+这可以视为作为语法变换的消去 λ 抽象的 lambda 提升(详见 https://en.wikipedia.org/wiki/Lambda_lifting )的一般化,但此处和 λ 抽象没有直接关联。
28332782 被提升的项往往被转移,因此一般地,需要可修改。
28342783 提升时对抽象的值表示进行操作实现基本的语义功能,可能进行检查,包括为满足接口行为的语义检查和实现为预防宿主语言的未定义行为的附加检查(@5.2.2) 。
28352784 提升项对象通过变换操作取作为项的值数据成员(@5.4.2) 。在此基础上有递归版本。
2836-提升项可引入或消除(@5.7.4) 间接值(@5.7.2) 。
2785+提升项可引入或消除(@5.7.6) 间接值(@5.7.3) 。
28372786 提升项通过被引用的对象替换作为项的值数据成员的引用值而消除引用值(@5.6.3.3) 。提升项的求值结果(@5.8.1) 是消除引用值的结果。
28382787 提升操作辅助对项的操作,可用于实现规约函数,包括以下各节中描述的 API 。其中:
28392788 名称前缀为 Lift 的函数是一元提升操作,具有一个 TermNode& 参数和其它可选的参数,提升第一参数指定的项,提升后的项保存在第一参数指定的项;
@@ -2841,15 +2790,15 @@
28412790
28422791 @6.6.1 基本提升操作:
28432792 基本提升操作包括直接转移赋值及以下 API :
2844-成员函数 YSLib::ValueObject::MakeIndirect 取记号值或持有其它类型的值的引用的间接值(@5.7.2.2) 。
2845-成员函数 YSLib::ValueObject::MakeMoveCopy 转移或复制对象以消除间接值。
2793+成员函数 ValueObject::MakeIndirect 取记号值或持有其它类型的值的引用的间接值(@5.7.3.3) 。
2794+成员函数 ValueObject::MakeMoveCopy 转移或复制对象以消除间接值。
28462795 函数 NPL::LiftOther
28472796 函数 NPL::LiftTerm
28482797 函数 NPL::LiftOtherOrCopy
28492798 函数 NPL::LiftTermOrCopy
28502799 函数 NPL::LiftTermValueOrCopy
28512800
2852-@6.6.2 可能引入间接值(@5.7.3) 的提升操作:
2801+@6.6.2 可能引入间接值(@5.7.5) 的提升操作:
28532802 以下值操作可能引入间接值:
28542803 函数 NPL::LiftCollapsed
28552804 函数 NPL::MoveCollapsed
@@ -2870,14 +2819,14 @@
28702819 提升消除中间值只作用在被提升项,不作用在子项。需要递归复制的操作不在这里提供,以避免抽象泄漏。
28712820 为消除中间值需要进行复制消除(@5.5.6.3) ,其中使用不同的可转移条件(@5.6.3.4) 决定使用转移而非复制。
28722821 当前实现在转移项时使用的宿主转移操作总是使用宿主对象的转移(基于 NPL::SetContentWith(@6.2.1) )而不是 TermNode 的转移。
2873-另见 @5.7.4.3 。
2822+另见 @5.7.6.3 。
28742823
28752824 @6.6.4 辅助提升操作:
28762825 函数 NPL::LiftFirst 和 NPL::LiftLast 提升第一个和最后一个子项。
28772826
28782827 @6.6.5 非内存安全(@5.2.4.3.1) 的提升操作:
28792828 以上操作中,不保证引入的对象内存安全(@5.2.4.3) 且不提供检查(@5.2.2) 的操作有:
2880-NPL::LiftTermRef :通过 YSLib::ValueObject::MakeIndirect 引入间接值。
2829+NPL::LiftTermRef :通过 ValueObject::MakeIndirect 引入间接值。
28812830 NPL::LiftToReference :非内存安全的项引用操作(@5.2.4.3.1) 。
28822831
28832832 @6.6.6 不支持嵌套调用安全(@5.2.7) 的提升操作:
@@ -2930,10 +2879,10 @@
29302879 Bindings :类型为 Environment::BindingMap 的变量绑定容器,实现变量名称到表示被绑定对象的映射(@5.4.3) 。
29312880 Parent :作为可在运行时确定类型的父环境(@5.4.3) 引用,用于重定向(@4.3.3) 算法的实现。
29322881 类 Environment 还包含其它一些维护内部状态和绑定(@4.1) 的 API 。
2933-成员函数 IsOrphan 判断是否为孤立的环境,即锚对象(@5.6.3) 未被外部引用。
2882+成员函数 IsOrphan 判断是否为孤立的环境,即锚对象(@5.6.2) 未被外部引用。
29342883 成员函数 GetAnchorPtr 取锚对象指针(@6.4.2.2) 。
29352884 成员函数 GetAnchorCount
2936-成员函数 GetMapRef 取名称绑定映射(@5.4.3) 引用。
2885+成员函数 GetMapRef 取名称绑定映射的引用。
29372886 成员函数模板 AddValue
29382887 成员函数模板 Bind
29392888 静态成员函数 CheckParent
@@ -3028,6 +2977,18 @@
30282977 @6.9.8 其它辅助 API :
30292978 函数 NPL::TraceNPLException
30302979
2980+@6.10 实现选项:
2981+NPLA 实现中提供构建时确定的实现选项,以宿主语言的宏定义在构件时启用,以宿主语言条件包含的 #if 指令判断。
2982+
2983+@6.10.1 运行时检查:
2984+当前实现选项用于指定启用检查:
2985+NPL_NPLA_CheckEnvironmentReferenceCount 环境对象销毁时检查环境引用计数。
2986+NPL_NPLA_CheckParentEnvironment 默认解析父环境时,检查环境引用是否存在。
2987+要求环境弱引用锁定的强引用指针非空。
2988+NPL_NPLA_CheckTermReferenceIndirection 项引用(@5.6.3) 的间接操作(@6.4.4) 时检查关联环境(@5.6.3.2) 。
2989+若关联环境,要求关联环境的锚对象指针(@6.4.2.2) 和环境弱引用锁定的强引用指针非空。无法确保没有关联环境的非内存安全操作(@5.2.4.3.1) 中的引用有效性。
2990+启用以上检查可避免引起不满足检查条件时的一些宿主语言的未定义行为(@5.2.2) ,即便已引起 NPLA 和对象语言的未定义行为(@5.2.4.3.1) 。
2991+
30312992 @7 NPLA1 解释实现:
30322993 NPLA1 解释实现是 NPLA 给定的 AST(@5.3.2) 作为输入的解释器(@5.1) 。
30332994 和 NPLA 类似,NPLA1 的实现也注重可扩展性。在限制修改语言规则的前提下,部分实现可被语义等价地使用更高性能的简化实现替代。
@@ -3038,10 +2999,11 @@
30382999
30393000 @7.1 NPLA1 一般约定:
30403001 在 NPLA 的一般约定(@5.2) 外,本节概述不通过具体 API 指定的一般特性。
3041-关于内存安全和临时对象的基本规则,参见 @5.2.4 。
3042-关于所有权和生存期,基本规则参见 @5.7 ;其中关于求值对应的 API ,参见 @7.6.4 。
3043-NPLA1 实现可在实现中提供构建时确定的实现选项,以宿主语言的宏定义等方式启用。
3044-这些选项主要用于提供参考实现,不应被直接作为公开接口;通常情形不需要更改。
3002+参见存储和对象模型(@5.2.4)(包括临时对象(@5.2.4.2) 和内存安全(@5.2.4.3) )的基本规则。
3003+另见作为具体实现的 NPLA 间接值(@5.7) 使用规则(@7.1.4) 。
3004+关于所有权和生存期,参见 NPLA1 间接值的有关规则和求值对应的 API(@7.6.4) 。
3005+类似 NPLA(@6.10) ,NPLA1 实现可在实现中提供构建时确定的实现选项,以宿主语言的宏定义等方式启用。
3006+和 NPLA 不同,这些选项主要用于提供参考实现,不应被直接作为公开接口;通常情形不需要更改。
30453007 特定的 API 可间接依赖这些特性,以便派生实现提供不同的优化实现,包括:
30463008 A1::REPLContext::IsAsynchronous(@7.8.1)
30473009 @6.1 的部分保证依赖特定的实现选项支持(如 NPL_Impl_NPLA1_Enable_ThunkedSeparatorPass(@7.9.2) ),当没有启用时可能不满足。
@@ -3064,9 +3026,9 @@
30643026 NPLA1 本机实现初始化引用项时,仍应使用其中的标签初始化,以避免依赖具体标签的逻辑。以不表示求值结果的被规约项(如被绑定对象)的初始化可在标签中排除作为求值结果时未被使用的标签值如 TermTags::Temporary 。
30653027 以上限制不包含标签的单独使用(如 A1::BindParameter(@7.7.4) )。
30663028
3067-@7.1.3 NPLA1 间接值使用规则:
3068-基本规则参见 @5.7.4 。
3069-除非另行指定,不在求值引入右值引用(@5.7.4.1) 。
3029+@7.1.3 NPLA1 间接值(@5.7) 使用规则:
3030+基本规则参见 @5.7.6 。
3031+除非另行指定,不在求值引入右值引用(@5.7.6.1) 。
30703032 特别地,A1::EvaluateIdentifier(@7.6.4) 保证对应表达式求值的结果是左值引用。这使之实现求值符号(@5.2) 时的结果是左值(@5.5.1) 而不立即引入左值到右值转换(@5.5.5) 及复制对象,和宿主语言的行为类似。
30713033 作为替代,可通过 NPLA API(如 NPL::IsBoundLValueTerm(@6.4.5) )间接判断绑定的对象的是否为右值引用。
30723034 引入绑定的 API(@7.7.4) 可引入引用值(@5.5.4) 。已有的引用值的引用总是左值引用,否则是右值引用。
@@ -3080,14 +3042,15 @@
30803042 规约过程中可能使用 NPLA 项提升 API(@6.6) 。其中,消除中间值的操作(@6.6.3) 被用于实现内存安全的操作。
30813043
30823044 @7.1.4.2 过程返回值:
3083-NPLA1 的部分过程抽象隐含返回值转换(@5.7.4.4) 。这可使返回值引用的对象不逃逸。
3045+NPLA1 的部分过程抽象隐含返回值转换,可确保返回值引用的对象不逃逸(@5.7.6.4) 。
30843046 其它不隐含返回值转换的操作由用户代码避免非内存安全操作。
30853047
30863048 @7.1.4.3 非内存安全项:
3087-引用持有者(@5.7.2.2) 仅存在有限的求值中间过程中,调用引入间接值 NPLA API(@5.2.4.3.2) 在 NPLA1 实现中可能仍能保证内存安全。
3088-NPLA1 不直接调用非内存安全的提升操作(@6.6.5) 。派生实现可调用这些函数处理引用持有者(如 @5.7.4.3 )。
3049+引用持有者(@5.7.3.3) 仅存在有限的求值中间过程中,调用引入间接值 NPLA API(@5.2.4.3.2) 在 NPLA1 实现中可能仍能保证内存安全。
3050+NPLA1 不直接调用非内存安全的提升操作(@6.6.5) ,除非之后立即同步地消除访问时无法保证内存安全的结果(@6.6.3) 。
3051+提升引入引用值和消除引用值通常使用 NPLA API :消除引用值的实现可按 @5.7.6.3 调用;引入和消除间接值也可使用 @6.6.1 的 API 。派生实现也可调用这些函数处理引用持有者。
30893052 其它 NPLA1 非内存安全操作(@5.2.4.3.1) 包括实现中调用的明确取无所有权引用的 API ,参见 @8.1.2 关于间接值的约定以及 @8 中具体函数的描述。
3090-NPLA1 对后者的使用补充基于项引用(@5.6.3) 和环境的引用计数(@6.9.4) 的检查机制(如 @8.4.5 )以在非内存安全的操作中避免引起宿主语言的未定义行为(@5.2.2) ,即便已引起 NPLA 和对象语言的未定义行为(@5.2.4.3.1) 。
3053+NPLA1 对后者的使用可选地使用 NPLA 运行时检查(@6.10.1) 补充基于项引用(@5.6.3) 和环境的引用计数(@6.9.4) 的检查机制(如 @8.4.5.2 )。
30913054
30923055 @7.2 NPLA1 中间值:
30933056 NPLA1 扩展了 NPLA 的中间值(@5.6) 机制。
@@ -3107,10 +3070,10 @@
31073070 A1::LiteralHandler 可用于对特定单一记号(@5.6.1) 而不是记号组合作为输入时的处理,可配合交互式界面使用,参见 @7.8 。
31083071
31093072 @7.2.1.1 使用约束:
3110-规约实现需满足 @5.7.5 。
3111-在 @5.7.5.1 决定操作状态的资源包含当前使用的遍处理器中的目标对象(@6.8.1) 。
3073+规约实现需满足被规约项稳定性(@5.7.7) 。
3074+在 @5.7.7.1 决定操作状态的资源包含当前使用的遍处理器中的目标对象(@6.8.1) 。
31123075 规约前被规约项的第一个子项具有遍处理器的所有权,也对目标对象具有所有权。
3113-假定满足 @5.7.6 的要求而允许删除子项的情形包括:
3076+假定满足 @5.7.8 的要求而允许删除子项的情形包括:
31143077 主规约函数(@6.5.3.3) 和 @8 支持的本机函数(@5.2.1) 的实现可假定被在调用处理器前会转移子项的处理器调用;
31153078 通过处理 WHNF 的调用遍处理器的 A1::ReduceCombined(@7.6.4.2) 在调用处理器前会转移子项,可保证调用时生存期不会因为直接清理第一个子项而结束,因此处理器可清理第一个子项。
31163079
@@ -3181,7 +3144,7 @@
31813144 注意 NPLA 上下文中的续延由 NPL::ReducerSequence(@6.9.4) 表示,提供续延捕获直接支持(参见 @5.10.4),而 NPLA1 续延是这个机制上的扩充。
31823145 NPLA1 续延的必要性体现为的状态支持下一求值项(@7.4.3) 的支持(这隐含运行时对上下文状态类型的要求)。
31833146 此外,也可存在其它续延的对象。例如,Forms::Sequence(@8.4.9) 中的内部续延不支持访问(因此不依赖)下一求值项,而不需要实现为 A1::Continuation 。
3184-另见 @5.10.6 。
3147+另见动作帧(@5.10.6) 。
31853148
31863149 @7.4.3 NPLA1 上下文状态:
31873150 类 A1::ContextState 是 ContextNode 的 public 派生类,其对象表示 NPLA1 上下文状态,包含 NPLA 上下文的状态(@5.4.4) 。
@@ -3213,13 +3176,13 @@
32133176 @7.4 及以下各节中对 A1::ReduceOnce 的行为描述默认由 A1::ContextState::DefaultReduceOnce(@7.4.3) 实现。替换的实现应保持的要求相同。
32143177 A1::ReduceOnce 的规约对列表和非列表分别进行处理,实现求值算法(@6.5.3.3) ,要求单一子项的项规约为其子项,而其它列表或非列表项的规约操作由遍(@7.4.1) 提供。其中,列表被先匹配。
32153178 A1::ReduceOnce 中的处理器(@7.2.1) 应符合 @7.2.1.1 的约定。
3216-若实现中使用的处理器不符合约定,可能不满足 @5.7.5.1 并可能引起未定义行为。
3179+若实现中使用的处理器不符合约定,可能不满足 @5.7.7.1 并可能引起未定义行为。
32173180 对支持异步规约的实现(@7.9.2) ,还应符合 @7.9.1 。
32183181 A1::ReduceOnce 和辅助规约函数(@6.7) 类似,能处理一般的项,没有前置条件。参数中 TermNode(@5.4.2) 表示的表达式语法意义(@3.4.2) 上非空,但没有实现限制(即不附加检查)。
32193182 A1::ReduceOnce 循环调用遍(@7.4.1) 进行必要的重规约,即迭代规约;通过 NPL::CheckReducible(@6.5.2) 判断是否需要重规约。
32203183 A1::ReduceOnce 的实现中不直接指定需要重规约;所有 ReductionStatus::Retrying 都来自遍(@7.4.1) 的调用。
32213184 遍的调用在支持异步规约(@7.9) 的实现中明确指定作为尾上下文(@4.4.7) 。
3222-名称表达式的求值不进行进一步规约(@4.5.1) ,这由具体遍(@7.4.1) 的实现保证。关于记号,另见 @5.6.1 。
3185+名称表达式的求值不进行进一步规约(@4.5.1) ,这由具体遍(@7.4.1) 的实现保证。关于记号,另见记号值(@5.6.1) 。
32233186 使用设置遍的 API(@7.4.1) 修改 ContextNode 中的具体遍以使用不同的规约规则。
32243187 其它规约例程可直接作为规约函数实现遍规约,参见 @7.4.6 和 @7.4.7 。
32253188 NPLA1 主规约函数依赖 NPLA1 上下文状态(@7.4.3) 。
@@ -3302,7 +3265,7 @@
33023265 @7.6.1.2 处理器调用:
33033266 A1::FormContextHandler::operator() 以构成函数合并(@4.5.3) 的语法构造作为参数。
33043267 宿主实现可访问比对象语言中的合并子(@4.5.3.2) 更多的数据。
3305-实现合并子时,应避免依赖合并中的子项(即 WHNF 第一项)的操作改变可观察行为(@4.1.3) 。一般地,本机实现需在确保第一项关联的对象不被依赖后的适当情形下调用 RemoveHead(@5.7.6) 。
3268+实现合并子时,应避免依赖合并中的子项(即 WHNF 第一项)的操作改变可观察行为(@4.1.3) 。一般地,本机实现需在确保第一项关联的对象不被依赖后的适当情形下调用 RemoveHead(@5.7.8) 。
33063269 A1::FormContextHandler::operator() 依次进行以下操作:
33073270 按 Wrapping 的次数指定调用合并子参数求值,每次调用 A1::ReduceArguments 求值每一个子项(函数参数);
33083271 若 Check 数据成员非空则调用 Check 进行检查,失败时抛出异常;
@@ -3352,7 +3315,7 @@
33523315 A1::ReduceCombinedBranch
33533316 A1::ReduceCombinedReferent
33543317 A1::ReduceLeafToken 规约叶节点记号,提取名称并调用 A1::EvaluateLeafToken 求值对应项。
3355-记号值类型(@5.6.1) 预期已在必要时被处理(@5.7.4.2) ,以上 API 没有区分得到的求值结果(@5.8.1) 是否可以是总是被复制的非临时对象的值。
3318+记号值类型(@5.6.1) 预期已在必要时被处理(@5.7.6.2) ,以上 API 没有区分得到的求值结果(@5.8.1) 是否可以是总是被复制的非临时对象的值。
33563319
33573320 @7.6.4.1 规约合并项:
33583321 规约合并项是具有子项的枝节点(@5.4.2.1) ,满足 IsBranchedList(@6.2.1)(类似 @7.6.1.3 );或符合 @5.9.4.2 的非平凡非正规表示。
@@ -3376,7 +3339,7 @@
33763339 对叶节点直接返回 ReductionStatus::Clean ,无其它作用。
33773340 配合 A1::FormContextHandler 在第一个子项上提供中间值(@5.6) ,得到的项为 WHNF(@4.4.3.1) ; A1::ReduceCombined 实现 WHNF 的求值。
33783341 调用合并子时,合并子和操作数中的临时对象被延长生存期(@5.2.6.2) ,但在尾上下文(@4.4.7) 之前结束。
3379-按 @5.2.4.2 ,实现可选择不同的内部存储保存这些临时对象,具体策略和是否支持异步规约(@7.9) 相关,详见 @7.9.3 ;另见 @7.11.5 。
3342+按 @5.2.4.2 ,实现可选择不同的内部存储保存这些临时对象,具体策略和是否支持异步规约(@7.9) 相关,详见 @7.9.3 ;另见 TCO 实现(@7.11.5) 。
33803343 函数 A1::ReduceCombinedBranch 同 A1::ReduceCombined ,但断言项符合 IsBranch 。
33813344 函数 A1::ReduceCombinedReferent 同 ReduceCombined ,但使用第三参数指定的值。
33823345 规约合并项不判断处理器内部的操作,以同时支持宿主语言的本机实现和对象语言(@8.4.5) 引入的合并子。
@@ -3387,7 +3350,7 @@
33873350 使用这些操作实现对象语言对应操作的 API 详见 A1::Forms(@8.1)(以下简作 Forms )。
33883351 部分公用的操作规则也在本节中约定。
33893352
3390-@7.7.1 间接值(@5.7.3) 访问:
3353+@7.7.1 间接值(@5.7.5) 访问:
33913354 除因 @7.1.3 保证内存安全(@5.2.4.3) 而消除引用值(@6.6) 的操作外,其它操作的求值结果(@5.8.1) 中的引用值被保留。
33923355 以间接值访问对象时,项的值类别(@5.5.1) 和根据其它语义规则(可能在以后添加,如是否可修改的限定符)确定是否可修改,可分别进行不同的操作。
33933356 直接区分参数的值类别分别进行处理的操作有:
@@ -3400,8 +3363,8 @@
34003363 函数 A1::RelayForEval 直接求值(@4.1) 规约:规约并传递求值的结果。
34013364 函数 A1::RelayForCall 函数调用规约( β 规约(@4.5.3) ):规约并传递词法闭包规则(@4.6.1.1.2) 下求值的结果。
34023365 使用合并动作 API ,可定义依赖这些合并动作的求值规约操作,附加相同的约束。
3403-为确保嵌套函数调用时允许引用绑定到非直接主调函数的临时对象形式参数,已被匹配作为绑定目标的项所在的不表示操作数的项(参见 @7.7.3 )可能被转移以保证其子项生存期足够长。
3404-按 @5.7.5.2 ,此时被作为绑定目标的子项不需被修改(因此自动符合 @5.7.6 的要求)。
3366+为确保嵌套函数调用时允许引用绑定到非直接主调函数的临时对象(@5.2.4.2) 形式参数,已被匹配作为绑定目标的项所在的不表示操作数的项(参见 @7.7.3 )可能被转移以保证其子项生存期足够长。
3367+按 @5.7.7.2 ,此时被作为绑定目标的子项不需被修改(因此自动符合 @5.7.8 的要求)。
34053368 间接调用 A1::RelayForEval 或 A1::RelayForCall 的操作是求值规约操作。
34063369 间接调用 A1::RelayForEval 的求值规约操作包括:
34073370 Forms::Eval(@8.4.4.1)
@@ -3415,11 +3378,11 @@
34153378 忽略提升操作可允许对象语言的函数调用返回(@4.5.3.1) 引用值(@5.5.4) 。
34163379
34173380 @7.7.2.1 求值规约提升项:
3418-关于提升项的基本用例,参见 @5.7.4.3 。
3419-部分求值规约操作使用同返回值转换(@5.7.4.4) 效果相同的方式实现消除引用值(@6.6) :
3381+关于提升项的基本用例,参见 @5.7.6.3 。
3382+部分求值规约操作使用同返回值转换(@5.7.6.4) 效果相同的方式实现消除引用值(@6.6) :
34203383 A1::RelayForCall 和 A1::RelayForEval(@7.7.2) 间接依赖 NPL::LiftToReturn(@6.6.3) 。
34213384 对间接值的相关使用和检查另见 @7.6.5 。
3422-引用值外的其它间接值(@5.7.4.2) 对应复制或转移间接值参见 @8.1.2 。
3385+非引用值间接值(@5.7.6.2) 对应复制或转移间接值参见 @8.1.2 。
34233386 关于具体操作,另见 @8 中的保证,如 @8.4.5 。
34243387
34253388 @7.7.3 绑定操作:
@@ -3443,20 +3406,20 @@
34433406 绑定时不对形式参数对应的函数参数进行修改,所以不对形式参数除访问引用值外的间接处理。
34443407 若形式参数可能由求值得到,需在匹配前另行处理。
34453408
3446-@7.7.3.2 绑定临时对象标签:
3409+@7.7.3.2 绑定临时对象(@5.2.4.2) 标签:
34473410 绑定临时对象时设置对象上的 TermTags::Temporary 标签(@5.4.2.2) ,以实现区分通过引用绑定延长生存期的临时对象和非引用绑定的对象(@5.5.6.3) 。
34483411 一般地,表达式中的纯右值(非引用值)被绑定为临时对象,被绑定的对象在初始化后具有 TermTags::Temporary 。
34493412 这对应宿主语言中的转发引用(forwarding reference) 参数中的情形:
34503413 若模板参数 P 对应转发引用函数参数 P&& ,其中 P 是右值引用类型,保留从实际参数推断但不是实际参数类型的信息;
34513414 没有绑定临时对象标签的对象则同一般的非引用类型的对象类型参数(非转发引用)。
34523415 A1::EvaluateIdentifier(@7.6.4) 保证被绑定的对象名称解析的引用标签不包含 TermTags::Unique(@5.4.2.2) ,但不清除绑定临时对象引入的 TermTags::Temporary 。
3453-这允许 TermTags::Temporary 在作为返回值的名称表达式中直接被跨过程传递(若不经过返回值转换(@5.7.4.4) 或其它操作)。
3416+这允许 TermTags::Temporary 在作为返回值的名称表达式中直接被跨过程传递(若不经过返回值转换(@5.7.6.4) 或其它操作)。
34543417 被传递标签类似宿主语言的 std::forward 的模板参数中指定转发引用参数类型(因为宿主语言的引用折叠,此处 P 和 P&& 一致)。
34553418 跨过程传递实质上并不被宿主语言支持(因为 P 表示的静态类型信息不在函数外可用),因此一般仅限为了实现类似宿主语言的根据值类别和类型转发参数的转发上下文(forwarding context) 中使用。
34563419 使用引用标记字符(@7.7.3.4) 可保留来自引用值实际参数的绑定临时对象标签。
34573420
34583421 @7.7.3.3 绑定匹配:
3459-数据结构和匹配算法类似 Kernel 中用于 $define! 和 $vau 等操作子(@4.5.3.2) 的机制,但有以下不同(另见 @9.6.4 ):
3422+数据结构和匹配算法类似 Kernel 中用于 $define! 和 $vau 等操作子(@4.5.3.2) 的机制,但有以下不同(另见 @9.9.5 ):
34603423 #ignore 按符号处理(但作用一致);
34613424 不支持 cons 对(pair) 的中缀 . ,但支持形式参数树中的列表最后以带前缀 . 的符号(省略(ellipsis) )匹配多个列表项的参数(其它一些不支持 cons 对的语言,如 ECMAScript 2019 的 rest 参数的语义效果与此类似;列表外的 . 起始的词素(@5.6.1) 当前视为普通的符号,但此行为可能会在未来改变);
34623425 不提供转义,若符号去除可选的前缀 . 后为空则忽略绑定;
@@ -3472,7 +3435,7 @@
34723435 应用在形式参数树叶节点的前缀 % 、& 或 @ 为标记字符表示名称绑定的可按需引入引用,称为引用标记字符。
34733436 没有标记字符时,指示绑定的默认行为。
34743437 标记字符引起的绑定的差异为:
3475-没有标记字符则对操作数按值绑定,实际参数值传递给对应的形式参数,若为 NPL::TermReference 则发生左值到右值转换(@5.7.4.1) ;
3438+没有标记字符则对操作数按值绑定,实际参数值传递给对应的形式参数,若为 NPL::TermReference 则发生左值到右值转换(@5.7.6.1) ;
34763439 有标记字符 % 或 & 按引用推断规则直接绑定或转发操作数(当操作数为引用时;属于引用折叠(@5.6.3.2) );
34773440 有标记字符 @ 则绑定操作数的引用,不论操作数的类型和值类别(不进行引用折叠)。
34783441 使用引用推断规则绑定引用时,操作数按引用传递(@4.4.4.5) 给形式参数(@7.7.3.3) ;否则,操作数按值传递(@4.4.4.5) 给形式参数。
@@ -3526,12 +3489,12 @@
35263489 函数 A1::MatchParameter 匹配操作数树(@7.7.3) 。
35273490 函数 A1::BindParameter 匹配并绑定操作数到参数上。
35283491 为允许调用宿主对象的转移构造函数,绑定操作(@7.7.3) 仅在特定的上下文中使用复制消除(@5.5.6.3) 。(实际上,初始化引用之外的参数创建也不是 ISO C++17 约定要求消除复制的上下文。)
3529-对实际参数,检查尾部参数是否为省略(@7.7.3.3) 后,匹配前判断是否为 TermNode 以支持引用(@5.7.4.3) 。
3492+对实际参数,检查尾部参数是否为省略(@7.7.3.3) 后,匹配前判断是否为 TermNode 以支持引用(@5.7.6.3) 。
35303493 绑定尾部参数列表时,若对应的操作数是右值,直接转移子项,使用复制消除。
35313494 一般地,对操作数树的递归操作应在分配资源失败时,引起(可能派生)std::bad_alloc 的宿主异常而非宿主语言的未定义行为(@5.2.2) 。
35323495 为支持嵌套调用安全的约定(@6.1) ,实现应避免无法预测嵌套深度的递归调用,但实现内调用的重定向操作以尾调用形式进行递归调用,类似使用跳板的异步规约动作(@5.10.1) 。
3533-引入绑定的规则参见 @7.7.3 。
3534-另见 @8.4.4.3 和 @8.4.5 。
3496+引入绑定的规则参见绑定操作(@7.7.3) 。
3497+另见环境修改操作(@8.4.4.3) 和过程抽象(@8.4.5) 。
35353498
35363499 @7.8 REPL API :
35373500 NPLA1 提供 API 通过解释器的各个子模块组装 REPL(read-eval-print loop) 的交互式界面。
@@ -3570,7 +3533,7 @@
35703533 类 A1::REPLContext 还提供以下 API :
35713534 数据成员 Allocator
35723535 数据成员 Root
3573-数据成员 Preprocess 是内部保存的求值表达式一次预处理的处理器。这在 @7.8.2 的算法前生效,不处理子表达式。
3536+数据成员 Preprocess 是内部保存的求值表达式一次预处理的处理器。这在 NPLA1 规范求值算法(@7.8.2) 前生效,不处理子表达式。
35743537 数据成员 ConvertLeaf
35753538 数据成员 ConvertLeafSourced
35763539 数据成员 CurrentSource
@@ -3609,7 +3572,7 @@
36093572 求值符号的实现参见 A1::EvaluateIdentifier(@7.6.4) 。
36103573
36113574 @7.9 异步(@5.10.1) 规约支持:
3612-基本概念参见 @5.10 。
3575+基本概念参见异步规约(@5.10) 。
36133576 在 NPLA1 API 中同时提供对应的完全非异步规约的实现,不满足 TCO 要求(@5.2.6.4) ,仅供参考。
36143577 以下讨论的由上下文(@5.4.4) 支持的 NPLA API 使用方式和 NPLA1 相关。其它非 NPLA1 的派生实现可使用其它方式或选择不支持。
36153578
@@ -3667,7 +3630,7 @@
36673630 非 NPLA1 API 若支持异步规约,可能以关联的上下文中的当前动作为空作为前置条件以允许直接调用 ContextNode::SetupTail(@6.9.4) 等设置当前动作。
36683631 对具有前置条件的 API ,调用者应按需在其他操作前保存当前动作以维护符合预期的作用顺序。
36693632
3670-@7.9.3 临时对象管理:
3633+@7.9.3 临时对象(@5.2.4.2) 管理:
36713634 规约时,对象语言的函数右值和操作数右值需要被保存以避免引起宿主语言的未定义行为(@5.2.2) 。
36723635 特别地,对象语言语法意义上的嵌套函数调用应能引用外层对象(例如,通过绑定引用参数(@7.7.3.4) )而不引起宿主语言的未定义行为(@5.2.2) 。
36733636 A1::ReduceCombined 在同步规约时通过宿主语言的规则自然地实现此要求,转移子项(@7.2.1.1) 时只需以宿主语言的自动对象作为新建的项。
@@ -3677,13 +3640,13 @@
36773640 实现需自行决定是否使用内部存储保存临时对象以及需要保存临时对象的内部存储的位置。若需支持异步规约,不能使用宿主语言的自动对象。
36783641 一般地,因为 TermTags::Temporary(@5.4.2.2) 允许原地标记被绑定的临时对象而非引用其它存储(@5.5.6.3) ,不需要对被绑定的操作数临时对象特别处理。
36793642 当前不提供 API 辅助实现本机函数中的临时对象维护。
3680-按 @5.7.6 ,本机实现可对表示临时对象的子项分别转移,但转移前不应有非内部对象(@4.2.4.1) 引用被转移的子项。
3643+按 @5.7.8 ,本机实现可对表示临时对象的子项分别转移,但转移前不应有非内部对象(@4.2.4.1) 引用被转移的子项。
36813644
36823645 @7.10 TCO 支持:
36833646 因为要求对宿主语言中立(@5.2.6.4.1) ,基于 CPS 调用(@5.4.4) 的上下文 API 实现异步规约(@7.9) ,带有上下文状态的前置条件(@6.9.4) 。
36843647 这样的实现方式性能相对直接使用体系结构相关的方式较低,但仍可被接受。
3685-这样实现的 TCO 同时允许可移植地在对象语言中实现某些引入控制作用(@4.1) 的一等实体(@4.1) (如续延(@4.5.2.1) )。
3686-当前未支持宿主栈展开(stack unwinding) 的互操作。
3648+这样实现的 TCO 同时允许可移植地在对象语言中实现某些引入控制作用(@2.3.4) 的一等实体(@4.1) (如续延(@4.5.2.1) )。
3649+当前未支持宿主栈展开(stack unwinding) 的互操作(@5.2.1) 。
36873650 C++ 异常调用重写循环(@5.4.4) 内资源对象的析构函数顺序是未指定的。但是,对 C++ API 异常安全保证的要求(@7.4.1.4) 仍然不变。
36883651 在 NPLA1 API 中同时提供对应的异步规约但不使用 TCO 的实现,不满足本节要求,仅供参考。
36893652 TCO 应能支持实现 PTC(@5.2.6.2) 。
@@ -3696,7 +3659,7 @@
36963659 NPLA1 实现支持的 TCO 包括以下形式:
36973660 直接在实现中变换宿主语言的递归调用为循环可实现宿主 TCO(@5.2.6.4.2) ;
36983661 基于异步规约 API(@7.9.2) ,使用重写规则(直接通过现有 API 支持的即重规约(@7.4.4) )代替直接使用宿主语言的递归形式可实现目标 TCO(@5.2.6.4.2) ;
3699-动态 TCO(@5.2.6.4.2) ,具体机制详见 @7.10.3.2 。
3662+动态 TCO(@5.2.6.4.2) ,具体机制详见操作压缩(@7.10.3.2) 。
37003663 NPLA 除个别例外(@6.1) 均支持宿主 TCO ,不需要其它形式的静态 TCO(@5.2.6.4.2) 。
37013664 在此基础上,NPLA1 通过允许和动态 TCO 互操作的异步重规约的方式支持目标 TCO ,详见 @7.10.6 ;但当前 NPLA1 部分 API 不保证支持宿主 TCO ,这可能在以后完善。
37023665 NPLA1 支持的动态 TCO 按实现策略即 TCM(@5.2.6.4.2) 。
@@ -3736,7 +3699,7 @@
37363699 连续出现的幂等操作不受递归嵌套深度的影响。若操作序列(@7.10.3.1) 最后一项以外的操作都是幂等的,则可支持不受限制递归尾调用,即实现了 PTC 。
37373700 由于语义规则限制,不在任意情形下避免非幂等的操作而保证 PTC(这些操作随着嵌套深度的增加随之需要分配存储):
37383701 捕获动态环境(通过 vau 抽象(@4.5.2.3) 的创建(@8.4.5) )时,所在的环境记录(@5.4.4) 作为帧(@4.5.3.4) 占据的存储不保证有上界(unbounded) ;
3739-包含非平凡析构(trivially destructible) 对象的帧的存储是否支持 PTC 未指定(另见 @7.11.5 中关于生存期的实现注记)。
3702+包含非平凡析构(trivially destructible) 对象的帧的存储是否支持 PTC 未指定(另见 TCO 相关的生存期的实现注记(@7.11.5) )。
37403703
37413704 @7.10.3.2.1 非幂等操作:
37423705 非幂等的操作和生存期相关,包括:
@@ -3746,7 +3709,7 @@
37463709 这些操作可能有多个实例,因为以下几个原因而无法合并:
37473710 存储模型和对象模型(@5.2.4) 要求生存期开始和结束的顺序;
37483711 对象模型相关的语义规则没有允许合并不同的对象;
3749-需提供宿主语言(@5.2) 互操作性支持,一般无法证明实现这些合并不影响可观察行为(@4.1.3) 。
3712+需提供宿主语言(@5.2) 互操作(@5.2.1) 支持,一般无法证明实现这些合并不影响可观察行为(@4.1.3) 。
37503713 但注意调整语义规则或通过区分出非平凡析构等方式证明可观察行为不变后,减少父环境被隐藏的变量而完全实现 PTC 是可能的。
37513714 基于语义规则的许可,实现应支持部分非幂等操作的被合并,以支持 PTC :
37523715 若设置前的环境是被设置的环境的直接或间接父环境,其中可能影响可观察行为的变量都被新的环境隐藏,可确定父环境不再使用且不影响可观察行为,则仍然合并操作,并释放该父环境的资源。
@@ -3779,7 +3742,7 @@
37793742 @7.10.4 TCO 相关的资源管理:
37803743 TCO 动作(@7.10.3) 持有尾上下文的活动记录帧(@4.5.3.4) ,包括环境和被规约表达式中的右值对应的临时对象。
37813744 操作压缩(@7.10.3.2) 和以下资源管理的操作在 A1::RelayForCall 和 A1::RelayForEval(@7.7.2) 的调用中实现。
3782-关于临时对象,参见 @7.10.5 。
3745+另见临时对象管理(@7.10.5) 。
37833746
37843747 @7.10.4.1 帧记录(frame record) :
37853748 帧记录是保存无法被操作压缩安全释放的活动记录保存的对象和中间状态。
@@ -3800,10 +3763,10 @@
38003763 被从 TCO 对象中移除的环境对象是没有 NPL::TermReference 引用其锚对象的对象。当强引用计数为 1 时,压缩后最终会被清除而释放,持有的对应资源被回收。
38013764 这一过程在局部上类似基于引用计数的 GC(@5.2.4.4) 机制。
38023765
3803-@7.10.5 临时对象管理:
3804-关于临时对象和资源管理的一般机制,参见 @7.9.3 和 @7.10.4 。
3766+@7.10.5 TCO 临时对象(@5.2.4.2) 管理:
3767+一般机制参见临时对象管理(@7.9.3) 和 TCO 资源管理(@7.10.4) 。
38053768 TCO 异步规约对临时对象的管理基本策略同 @7.9.3 ,但因为操作压缩(@7.10.3.2) 具有更多的变化和限制,所以实现较复杂。
3806-和非 TCO 异步规约的实现相比,临时对象不仅因为引用绑定子项需保证子项的生存期足够长(@7.7.2) 的原因,还可因为操作压缩的需要,而可被转移。后者的情形应符合 @5.7.6 中取得求值结果后不被引用的项修改限制条件。
3769+和非 TCO 异步规约的实现相比,临时对象不仅因为引用绑定子项需保证子项的生存期足够长(@7.7.2) 的原因,还可因为操作压缩的需要,而可被转移。后者的情形应符合 @5.7.8 中取得求值结果后不被引用的项修改限制条件。
38073770
38083771 @7.10.5.1 非本机函数临时对象:
38093772 在 @7.9.3 的基础上,操作压缩保存函数临时对象时,尝试进行去重(deduplication) :比较函数是否相同,以在资源回收(@7.10.4.2) 前即尽可能接近 PTC 的要求。资源回收不处理函数临时对象。
@@ -3876,7 +3839,7 @@
38763839 这能同时支持同步和异步实现,同时在当前动作以序列表示时,不需要无效化被组合的动作的宿主对象。
38773840
38783841 @7.11.3 函数合并(@4.5.3) 的实现:
3879-NPLA1 规范求值算法(@7.8.2) 相对 Kernel 更简单以支持函数合并的 TCO 实现(参见 @7.11.5)。
3842+NPLA1 规范求值算法(@7.8.2) 相对 Kernel 更简单以支持函数合并的 TCO 实现(@7.11.5) 。
38803843 对应地,函数合并和 klisp 的 eval 实现略有不同:在处理器调用(@7.6.1.2) 实现参数列表中参数的求值。
38813844 NPLA1 使用包装数(@7.6.1.1) 处理包装调用,支持多重包装(这在 [RnRK] 被求值算法蕴含);而当前 klisp 的实现没有正确地支持多重包装调用,参见:https://bitbucket.org/AndresNavarro/klisp/issues/11 。
38823845 和 klisp 类似,参数列表求值前检查不存在实际参数(而无需求值)的情形进行优化。
@@ -3888,14 +3851,14 @@
38883851 klisp 还使用 ktail_call 提供本机实现。NPLA1 也可使用类似的实现。
38893852 其它更一般的情况下,在求值上下文(@4.4.7) 中隐含已构造 TCO 动作为前提,通过直接或间接调用 A1::ReduceOnce(@7.4.4) 提供 PTC 保证。
38903853 这对应 klisp 的 ktail_eval ;但和后者不同,A1::ReduceOnce 调用确切地只对应不显式引入新的环境的操作。
3891-可能引入新的环境的操作,如 [RnRK] 的 eval(对应 NPLA1 对象语言函数 eval 和 eval% 等,参见 @10.5.6 ),需要另行调用比 A1::ReduceOnce 更复杂的操作压缩。
3854+可能引入新的环境的操作,如 [RnRK] 的 eval(对应 NPLA1 对象语言函数 eval 和 eval% 等,参见 @11.3.7 ),需要另行调用比 A1::ReduceOnce 更复杂的操作压缩。
38923855 和 Kernel 要求以外,因为维护资源(@7.10.4) 的需要,TCO 动作在函数合并的底层操作子合并前被构造,因此进入参数求值时在资源管理的意义上也在所在函数合并的同一个尾上下文(@4.4.7) 。
3893-另见 @7.11.5 。
3856+另见 TCO 实现(@7.11.5) 。
38943857
38953858 @7.11.5 TCO 动作(@7.10.3) 实现和限制:
38963859 因为维护资源(@7.10.4) 的需要,规范求值算法(@7.8.2) 不处理 WHNF 以外的操作数且允许宿主类型的调用(@7.6.1.2) 处理 WHNF 的第一项。
38973860 当前在 TCO 动作中被分配的临时对象(@5.2.4.2) 的操作都针对作为 WHNF 的第一项的合并子,其中合并子相等性由 @8.4.5.5 或其它宿主实现提供的 == 操作确定。
3898-由 @8.4.5.5 ,捕获不同环境的 vau 合并子不相等;不论是否具有相等的外部表示(@4.1) 和来源,其右值不会被直接操作压缩(@7.10.3.2) 避免多次添加而被 TCO ;若其嵌套调用因为捕获不同的存在引用关系的环境,不支持其它形式的 TCO ;因此,不支持 PTC 。
3861+由 @8.4.5.5 ,捕获不同环境的 vau 合并子不相等;不论是否具有相等的外部表示(@2.3.4) 和来源,其右值不会被直接操作压缩(@7.10.3.2) 避免多次添加而被 TCO ;若其嵌套调用因为捕获不同的存在引用关系的环境,不支持其它形式的 TCO ;因此,不支持 PTC 。
38993862 注意上述情形在其它语言中因为可达性分析等可能具有实现缺陷也不会释放存储,如 Kernel 程序 ($sequence ($define! f ($lambda (n) ((($vau (x y) e (eval ($sequence x y) e)) n (f n))))) (f 1)) 在 klisp 中实测不支持 PTC 。
39003863 当前 TCO 操作压缩不支持回收非 #ignore 的动态环境。这实际上较 [RnRK] 的保证弱。但 klisp 同样没有很好地支持此特性,如 Kernel 程序 ($sequence ($define! $f ($vau () #ignore (($f)))) ($f)) 在 klisp 中实测不支持 PTC 。
39013864 (关于以上 klisp 的问题,参见 https://bitbucket.org/AndresNavarro/klisp/issues/12 。)
@@ -4002,15 +3965,15 @@
40023965 推论:正规表示以外的宿主值是否被保留以及保留的时机未指定。
40033966 本章中的 API 中的规约函数(@6.5.3) 具有间接断言:第一参数指定的项是枝节点。
40043967
4005-@8.1.2 间接值(@5.7.3) 访问:
3968+@8.1.2 间接值(@5.7.5) 访问:
40063969 基本规则参见 @7.7.1 。
40073970 部分 API 同时提供结果中消除引用值和保留引用值的版本,这些函数以 API 后缀名称区分:
40083971 以 At 和 Ref 的后缀表示保留未折叠和折叠(@5.6.3.2) 的引用值;
40093972 部分不带有特定后缀的函数为参数和返回值转发(@5.5.2.2) 操作(仅当参数指定引用值时保留参数值),同时以 Val 的后缀表示不保留引用值;
40103973 其它不带有特定后缀的函数不保留引用值。
40113974 保留的引用值若来自参数且被折叠,通常经过调用 NPL::Collapse(@6.4.4) 折叠。
4012-此处保留引用值和对象语言中的定义(@9.6.1.5) 应保持一致。
4013-显式涉及区分是否保留结果中的间接值的 API 包括:
3975+此处保留引用值和对象语言中的定义(@10.4.3) 应保持一致。
3976+显式涉及区分是否在结果中保留间接值的 API 包括:
40143977 求值规约操作(@7.7.2) API ;
40153978 元素和列表操作(@8.4.3) 。
40163979
@@ -4082,7 +4045,7 @@
40824045 Forms::SetRestRef
40834046
40844047 @8.4.4 环境和求值操作:
4085-Forms 提供环境相关的操作,以支持对象语言中的环境(参见 @9.6.2 )。
4048+Forms 提供环境相关的操作,以支持对象语言中的环境(参见 @9.9.3 )。
40864049
40874050 @8.4.4.1 求值操作:
40884051 Forms 提供以下函数实现对象语言中的求值:
@@ -4100,7 +4063,7 @@
41004063 Forms::ValueOf
41014064
41024065 @8.4.4.3 环境修改操作:
4103-Forms 提供以下函数实现对象语言中的环境修改,包括定义和修改变量绑定:
4066+Forms 提供以下函数实现对象语言中的环境修改,包括定义和修改名称绑定映射(@5.4.3) :
41044067 Forms::DefineLazy
41054068 Forms::DefineWithNoRecursion
41064069 Forms::DefineWithRecursion
@@ -4131,19 +4094,19 @@
41314094 存储在 vau 抽象对象内的数据包括:
41324095 形式参数对象;
41334096 上下文原型;
4134-捕获的静态环境;
4097+捕获的静态环境(@4.6.1.1.2) ;
41354098 作为过程实现的求值结构(evaluation structure)(对应表达式中可能被求值的函数体(@4.5.2) );
41364099 决定是否在调用后提升返回结果(@8.4.5.4) 的标记。
41374100 这些数据都是可被共享的。复制 vau 抽象的处理器对象共享这些数据。
41384101 其中,作为父环境的静态环境以 NPL::EnvironmentReference 弱引用值保存,并附加 shared_ptr 实例以可选被 vau 抽象所有;其它数据都以 shared_ptr 的值保存,被 vau 抽象所有。
41394102 这允许调用(@8.4.5.4) 引用父环境时对之前确定的绑定(如捕获(@8.4.5.1) 时) 进行生存期检查,发现循环引用(@5.2) 等引起未定义行为的错误(@7.6.5) 。注意在对象语言中出错时未定义行为,不应依赖此行为。
41404103 除可选的静态环境 shared_ptr 实例,所有指针数据在 vau 抽象对象的生存期内都保持非空。
4141-形式参数树(@7.7.3) 作为数据成员同 vau 抽象对象被项或环境所有,可能被不同值类别的表达式标识,但它作为表达式和子表达式时不被直接求值,且子表达式中的符号被复制而不是以间接值引用(@5.7.4.2) ,因此是纯右值(@5.7.3) 。
4104+形式参数树(@7.7.3) 作为数据成员同 vau 抽象对象被项或环境所有,可能被不同值类别的表达式标识,但它作为表达式和子表达式时不被直接求值,且子表达式中的符号被复制而不是以间接值引用(@5.7.6.2) ,因此是纯右值(@5.7.5) 。
41424105
41434106 @8.4.5.3 参数绑定:
41444107 通过 vau 抽象引入的函数调用(@4.5.3.1) 在求值时,以 TermNode 的项而不是 ValueObject 的值对象替换上下文中的形式参数(@4.5.2) 树,用于在调用时被操作数树(@7.7.4) 作为实际参数替换。
41454108 绑定参数通过调用 A1::BindParameter(@7.7.4) 实现,其中对参数和操作数进行匹配。
4146-按值传递时需使用效果等价返回值转换(@5.7.4.4) 的方式确保在被保存(@8.4.5.2) 前不再引用其它项对象而维护内存安全。
4109+按值传递时需使用效果等价返回值转换(@5.7.6.4) 的方式确保在被保存(@8.4.5.2) 前不再引用其它项对象而维护内存安全。
41474110 注意提升项不是递归的,按值传递的操作数的项的只提升直接子项(同 @6.6.3 )。
41484111
41494112 @8.4.5.4 过程调用:
@@ -4156,11 +4119,11 @@
41564119 参数绑定后对求值结构的项或其副本进行规约,使函数体(@4.5.2) 被求值。这通过 A1::RelayForCall(@7.7.2) 实现。
41574120 之前判断可转移时,直接使用求值结构的项,否则使用副本。
41584121 规约在局部环境进行名称解析(@5.4.3) ,通过保存的 NPL::EnvironmentReference 值对静态环境的所有权进行检查,若失败则抛出异常。
4159-保存在静态环境以外的对象的引用不受到以上机制保护,需要对形式参数对象可包含的对象进行限制以保证被规约项的所有权要求(@5.7.3) 。
4160-因此,vau 抽象初始化时对形式参数对象检查,确保其中的非列表项中只存在调用 NPL::LiftTermRef 后也不引入间接值的对象的值,即记号值(@5.6.1) 。
4122+保存在静态环境以外的对象的引用不受到以上机制保护,需要对形式参数对象可包含的对象进行限制以保证被规约项的所有权要求(@5.7.5) 。
4123+因此,vau 抽象初始化时对形式参数对象检查,确保其中的非列表项中只存在调用 NPL::LiftTermRef 后也不引入间接值(@5.7.5) 的对象的值,即记号值(@5.6.1) 。
41614124 恢复被切换的环境(@6.9.5) 时,环境内的对象被释放。
41624125 若需保证内存安全(@5.2.4.3),返回值(@4.5.3.1) 不能是在调用后生存期结束的对象的引用值(@5.5.4) ,以避免引用被释放或之后被正规化(@5.9.2) 清理的值引入未定义行为。
4163-避免返回(@4.5.3.1) 引用值(@5.5.4) 的通用机制为提升返回结果,即求值后的求值结果(@5.8.1) 进行进行返回值转换(@5.7.4.4) ,同时消除引用值(@7.1.4) ,使返回值总是按值传递。
4126+避免返回(@4.5.3.1) 引用值(@5.5.4) 的通用机制为提升返回结果,即求值后的求值结果(@5.8.1) 进行进行返回值转换(@5.7.6.4) ,同时消除引用值(@7.1.4) ,使返回值总是按值传递。
41644127
41654128 @8.4.5.5 相等性:
41664129 相等性作为弱函数应用规约等价谓词(@4.5.3.2) 提供,操作为对所有成员进行相等比较,当且仅当都相当时,结果为真。
@@ -4195,8 +4158,8 @@
41954158 Forms::Apply 函数应用:应用参数指定的函数和作为函数参数的列表。
41964159 操作的语义同 [RnRK] ,但在可选参数多余 1 个时的错误情形抛出 NPL::ArityMismatch(@6.3) 异常。
41974160 保证最后一项的规约是尾上下文,允许 PTC 。
4198-Forms::ListAsterisk 使用可选的参数指定的不定数量的元素和结尾列表构造新列表,不保留结果中的引用值。
4199-Forms::ListAsteriskRef 使用可选的参数指定的不定数量的元素和结尾列表构造新列表,保留结果中的引用值。
4161+Forms::ListAsterisk 使用可选的参数指定的不定数量的元素和结尾列表构造新列表,不在结果中保留引用值。
4162+Forms::ListAsteriskRef 使用可选的参数指定的不定数量的元素和结尾列表构造新列表,在结果中保留引用值。
42004163 Forms::AccL 在抽象列表元素上应用左结合的二元操作。
42014164 Forms::AccR 在抽象列表元素上应用右结合的二元操作。
42024165 Forms::FoldR1 在列表元素上应用右结合的二元操作。
@@ -4227,50 +4190,62 @@
42274190 若存在操作数,有序求值保证最后一项是尾上下文(实现同 @8.4.9 );
42284191 不保证是真合并子(@4.5.3.2) 。
42294192 因为不直接公开合并子的实现(如 @8 ),其中不需要有项检查(如 @8.2.2);但可能仍有遍处理器的检查(@7.6.1.3) 。
4230-相关对象语言的接口参见 @10 。
4193+在对象语言中的对应接口参见 NPLA1 参考实现环境(@10) 。
42314194 NPL::Dependency 还提供其它一些接口,调用函数 Forms::LoadGroundContext 初始化上下文后继续调用,初始化特定操作的环境:
42324195 函数模板 Forms::GetModuleFor 加载代码作为模块(@1.4.6.4) 以提供特定集合的对象语言实体的定义。
42334196 函数模板 Forms::LoadModule 和 Forms::LoadModuleChecked 加载模块为变量。后者在指定名称的绑定已存在时抛出异常。
4234-函数 Forms::LoadModule_std_environments 提供环境操作(@11.1) ;
4235-函数 Forms::LoadModule_std_promises 提供延迟求值等操作(@11.2) ;
4236-函数 Forms::LoadModule_std_strings 提供字符串操作(@11.3) ;
4237-函数 Forms::LoadModule_std_io 提供输入/输出操作(@11.4) ;
4238-函数 Forms::LoadModule_std_system 提供系统操作(@11.5) ;
4239-函数 Forms::LoadModule_SHBuild 提供其它一些供 SHBuild 间接调用的操作(@12.1.1) 。
4240-函数 Forms::LoadStandardContext 调用 Forms::LoadGroundContext 并加载基础上下文中提供的库模块(@10.1) ;另见 @11 。
4241-
4242-@9 NPLA1 对象语言规则和一般实现导引:
4243-以下实现中的 C++ 名称和项目模块命名空间的使用同 @7 。
4197+函数 Forms::LoadModule_std_environments 提供环境操作(@12.1) ;
4198+函数 Forms::LoadModule_std_promises 提供延迟求值等操作(@12.2) ;
4199+函数 Forms::LoadModule_std_strings 提供字符串操作(@12.3) ;
4200+函数 Forms::LoadModule_std_io 提供输入/输出操作(@12.4) ;
4201+函数 Forms::LoadModule_std_system 提供系统操作(@12.5) ;
4202+函数 Forms::LoadModule_SHBuild 提供其它一些供 SHBuild 间接调用的操作(@13.1.1) 。
4203+函数 Forms::LoadStandardContext 调用 Forms::LoadGroundContext 并加载基础上下文中提供的库模块(@10.2) ;另见 @12 。
4204+
4205+@9 NPLA1 核心语言设计:
4206+NPL 是独立设计的,但其派生语言和其它一些语言有类似之处;这些语言和 NPL 方言之间并不具有派生关系。但为简化描述,部分地引用这些现有语言规范(@2.3.1.2) 中的描述,仅强调其中的不同。
4207+NPLA1 符合 NPL 和 NPLA 的语言规则,其实现环境(@2.3.4) 还应提供本章起的其它程序接口。
4208+NPLA1 和 Kernel (参见 Revised Report on the Kernel Programming Language )的特性设计(如 vau(@4.5.2.3) 和作为一等对象(@4.1) 的环境表达过程抽象(@8.4.5) )有很多类似之处,因此许多概念是通用的;但从设计哲学(@1.4) 到本章介绍的各个细节(如默认求值规则(@9.7.1) )都存在深刻的差异。
4209+部分名称指定的操作和 [RnRS] 或 klisp (http://klisp.org/docs/index.html) 指定的类似。
4210+以下章节主要介绍和 Kernel 约定不同的设计。各节的通用约定不再在之后的各个接口单独说明。
42444211
42454212 @9.1 程序实现:
4246-程序(@2.3.2) 是语言的派生。实现程序即在语言的基础上指定派生规则。
4247-实现外的程序是用户程序(user program) 。
4213+程序(@2.3.4) 是语言的派生。实现程序即在语言的基础上指定派生规则。
4214+语言实现(@2.3.3) 外的程序是用户程序(user program) 。
42484215 以 NPLA1 程序或另行指定的其它形式实现的可复用程序被归类为库(@1.4.4.4) 。
42494216 不论是 NPLA1 的实现还是用户程序,都可能使用库。
42504217 除非另行指定,一个 NPLA1 程序支持多个库的实例,之间不共享内部的状态。
42514218 语言特性包含不依赖库的核心语言特性(core language feature) 和库特性(library feature) 。
4252-使用 REPL API(@7.8) 创建 REPL 实例用于实现解释器。
4253-使用 A1::Forms(@8.1) 的成员指定需要内建支持的语法形式。
4254-一般在初始化时自行绑定初始环境的名称。当前提供的实现参见 @10 。
4255-NPL 是独立设计的,但其派生语言和其它一些语言有类似之处;这些语言和 NPL 方言之间并不具有派生关系。但为简化描述,部分地引用这些现有语言规范(@2.3.1.2) 中的描述,仅强调其中的不同。
4256-NPLA1 和 Kernel (参见 Revised Report on the Kernel Programming Language )的特性设计(如 vau(@4.5.2.3) 和作为一等对象的环境表达过程抽象(@8.4.5) )有很多类似之处,因此许多概念是通用的;但从设计哲学(@1.4) 到本章介绍的各个细节(如默认求值规则(@9.4) )都存在深刻的差异。
4257-部分名称指定的操作和 [RnRS] 或 klisp (http://klisp.org/docs/index.html) 指定的类似。
4258-以下接口主要介绍和 Kernel 约定不同的设计。各节的通用约定不再在之后的各个接口单独说明。
4259-
4260-@9.1.1 外部环境(@2.3.2) :
4219+本章指定 NPLA1 对象语言的核心语言特性。包含库特性的其它设计参见 NPLA1 参考实现环境(@10) 。
4220+
4221+@9.1.1 外部环境(@2.3.4) :
42614222 基于 @5.2 约定,由 @2.7.1 ,NPLA 的实现不假定存在多线程执行环境。
42624223 但是,宿主语言可支持多线程环境执行,在没有适当同步下可引起宿主语言的未定义行为(@5.2.2) 。
42634224 作为 NPLA 的派生,NPLA1 对象语言程序也具有相同的性质,除非另行指定需要和外部环境交互的特定操作,不需要假定 NPLA1 引入存在多线程执行环境。
42644225
42654226 @9.1.2 附加元数据(extra metadata) :
4266-NPLA1 实现可提供和实现环境(@2.3.2) 或具体 NPLA 对象关联的附加的资源,用于提供程序运行时可得到的附加信息,如源代码位置。
4267-是否存在附加元数据和附加元数据的具体内容可影响特定的行为,如符合 @9.4.3 中要求的实现的具体行为。
4227+NPLA1 实现可提供和实现环境(@2.3.3) 或具体 NPLA 对象关联的附加的资源,用于提供程序运行时可得到的附加信息,如源代码位置。
4228+是否存在附加元数据和附加元数据的具体内容可影响特定的行为,如符合 @9.5 中要求的实现的具体行为。
42684229 这些影响是未指定的,但除 NPLA1 程序直接依赖具体数据而进行的操作外,不应影响程序的其它语义(例如,引起程序终止)。
42694230
4270-@9.2 规约文法约定:
4271-为描述语言规则,约定适用 @9 的文法(@2.3.2) 形式。注意这不需依赖 NPL 语言的基本文法(@3) 。
4231+@9.1.3 扩展支持:
4232+本章中除循环引用(@9.9.1.1) 的限制外,不支持的特性可能会在之后的实现中扩展并支持。
4233+
4234+@9.1.4 对象语言程序未定义行为(@2.3.4) :
4235+NPLA1 对象语言程序中的未定义行为包括 NPLA 未定义行为(@5.2.2) 和以下扩展 NPLA 未定义行为:
4236+特定情形下访问被修改的环境中绑定的对象(@9.9.3) 。
4237+
4238+@9.1.5 NPLA1 实现注记:
4239+使用 REPL API(@7.8) 创建 REPL 实例用于实现解释器。
4240+使用 A1::Forms(@8.1) 的成员指定需要内建支持的语法形式。
4241+一般在初始化时自行绑定初始环境的名称。
4242+以下实现中的 C++ 名称和项目模块命名空间的使用同 @7 。
4243+
4244+@9.2 接口文法约定:
4245+为描述对象语言规则和程序接口,约定适用 @9 的文法(@2.3.4) 形式。注意这不需依赖 NPL 语言的基本文法(@3) 。
42724246 规约操作中项的约束通过以 <> 中的同类名称表示。
4273-本节描述的项是被用于求值(参见 @9.4.1 )的项或它们的直接文法组合。前者应能涵盖原子表达式(@3.4.2) 、其求值结果以及预期在对象语言中实现 @9.4.1 所需的 NPLA1 用户程序(@9.1) 构造。
4247+为区分同类约束的不同项,约束的名称后(在 > 之前)的可带有以 1 起始的正整数序数。除非另行指定,这些序数仅用于区分不同的同类约束项,无其它附加含义。
4248+本节描述的项是被用于求值(参见求值算法(@9.7.1) )的项或它们的直接文法组合。前者应能涵盖原子表达式(@3.4.2) 、其求值结果以及预期在对象语言中实现 @9.7.1 所需的 NPLA1 用户程序(@9.1) 构造。
42744249 库可参照本节的方式约定通过库引入的项的文法。
42754250 除非另行指定,对不确定具体项内容的对应要求同时适用于本节中和这些库中引入的项。
42764251
@@ -4280,30 +4255,30 @@
42804255 ? :重复之前修饰的项 0 次或 1 次。
42814256
42824257 @9.2.2 实体元素文法约定:
4283-指定函数的文法中,第一项以符号(@5.6.1) 的形式在所在的环境中提供,指定求值结果指称为合并子(@4.5.3.2) 的函数名称();
4258+指定函数的文法中,第一项以符号(@9.9.2) 的形式在所在的环境中提供,指定求值结果指称为合并子(@4.5.3.2) 的函数名称();
42844259 其后指定的文法中不同的元素对应合并子的操作数或其被作为调用时的形式参数树(@7.7.3) 的子项。
42854260 名义不同相同的约束可能仅要求相同的检查,可用于区分特定的含义,便于被实现优化。
42864261 表达式形式的结果指表达式的求值结果(@4.1) 。
42874262 文法形式上,使用本节约定指定应用子的操作数(@9.2.2.2) 时,指定表达式形式求值的结果。
42884263 这和 [RnRK] 和 [Shu10] 中的斜体标识符的标记不同,但含义(表示语义变量(semantic variable) )和效果实质相同。
4289-操作数可能是左值或右值,参见 @9.7 、@10.4 和具体操作的约定。
4290-本节约定的不同类型的操作数构成的集合之间不相交。一般规则参见 @9.4.7 。
4264+操作数可能是左值或右值,参见常规函数约定(@10.6) 、函数分类(@11.2) 和具体操作的约定。
4265+本节约定的不同类型的操作数构成的集合之间不相交。一般规则参见类型分类(@9.8.7) 。
42914266 根据是否可作为操作子中指定不被求值的函数参数,本节的操作数及其子项分为未求值的操作数(@9.2.2.1) 和求值得到的操作数(@9.2.2.2) 。
42924267
42934268 @9.2.2.1 未求值的操作数:
4294-未求值的操作数作为数据结构和 AST(@5.3.2) 同构,是符号(@5.6.1) 或未求值操作数构成的真列表(@9.6.3) ,是未求值的 AST 子项或求值规约(@4.4) 未修改输入的项。
4269+未求值的操作数作为数据结构和 AST(@5.3.2) 同构,是符号或未求值操作数构成的真列表(@9.9.4) ,是未求值的 AST 子项或求值规约(@4.4) 未修改输入的项。
42954270 未求值的操作数的文法约定如下:
42964271 <symbol> :符号。
4297-基于 @5.6.1 ,内部使用和 <string>(@9.2.2.2) 一一对应的表示,不提供符号和外部表示的其它映射关系。
4272+内部使用和 <string>(@9.2.2.2) 一一对应的表示,不提供符号和外部表示的其它映射关系。
42984273 <symbols> :元素为 <symbol> 的列表,形式为 (<symbol>...) 。
42994274 <eformal> :表示可选提供的环境名称或 #ignore 的符号。
43004275 使用和 <symbol> 相同的表示。通常为动态环境。
43014276 <expression> :待求值的表达式。
43024277 <expressions> :形式为 <expression>... 的待求值形式。
4303-求值时,<expressions> 被作为单一表达式(即视为 (<expression>...) ),代替 <expression> 可避免语法中要求过多的括号及 eval(@10.5.6) 等求值形式中显式构造列表的需要。
4304-<binding> :绑定列表,形式为 <symbol> <body> ,用于指定被求值的表达式和绑定参数的符号。
4278+求值时,<expressions> 被作为单一表达式(即视为 (<expression>...) ),代替 <expression> 可避免语法中要求过多的括号及 eval(@11.3.7) 等求值形式中显式构造列表的需要。
4279+<binding> :绑定列表的元素,形式为 <symbol> <body> ,用于指定被求值的表达式和绑定参数的符号。
43054280 和 Kernel 不同,<symbol> 后不要求是整个 <expression> 。
4306-<bindings> :元素为 <binding> 的列表,形式为 (<binding>...) 。
4281+<bindings> :绑定列表,即元素为 <binding> 的列表,形式为 (<binding>...) 。
43074282 <body> :出现在元素的末尾 <expressions>? 形式,可用于函数体(@8.4.5) 等替换求值的目标。
43084283 <expression-sequence> :同 <body> 但蕴含顺序求值子项。
43094284 求值 <expression-sequence> 的结果被定义为求值其最后一个子表达式(若存在)的结果,或当不存在子表达式时为未指定值(@7.2.2)。
@@ -4316,9 +4291,9 @@
43164291
43174292 @9.2.2.2 求值得到的操作数:
43184293 求值得到的操作数的文法约定如下:
4319-<object> :一般对象,包括引用对象的引用值(@9.6.1) 。
4294+<object> :一般对象,包括引用对象的引用值(@9.9.1) 。
43204295 <reference> :对象引用值。
4321-<list> :列表。参见 @9.6.3 。
4296+<list> :列表。参见 @9.9.4 。
43224297 <lists> :元素都是列表的列表。
43234298 <bool> :布尔(boolean) 值,即取值为 #t 或 #f 的集合。
43244299 <test> :类似 <object> ,通常预期为 <bool> ,作为条件。
@@ -4328,118 +4303,172 @@
43284303 <combiner> :合并子。
43294304 <applicative> :应用子(@4.5.3.2) 。
43304305 <predicate> :谓词,是应用操作数的求值结果的值为 <test> 的 <applicative> 。通常实现结果为 <bool> 的纯求值(@4.4.2) 。
4331-<environment> :一等环境(@9.6.2) 。
4306+<environment> :一等环境(@9.9.3) 。
43324307 <string> :字符串,宿主值类型为 string(@5.6.1) 。
43334308 字符串(包括字符串字面量求值的结果)以 string 类型表示,编码和表示要求同 YFramework 默认约定([Documentation::YFramework @@3.3.1]) 。
43344309
43354310 @9.2.2.4 文法形式补充约定:
43364311 和 [RnRK] 不同,NPLA1 的符号可包含字面量。除非另行指定,以 <symbols> 指定的值被作为 <definiend> 或 <formals> 使用时不应引起错误,即不应包含 #ignore 以外的字面量。注意 <symbols> 在被其它上下文使用时仍可能引起错误。
4312+和 [RnRK] 不同,<symbols> 形式的符号列表在绑定变量名时支持引用标记字符 & 和 %(@7.7.3.4) 。符号作为被绑定的初值符时,移除符号中发现的这些引用标记字符。
43374313 和 [RnRK] 不同,<definiend> 和 <formals> 不要求重复符号检查。另见 @7.7.3 。
43384314 [RnRK] 和 [Shu10] 都没有显式区分 <definiend> 和 <formals> ,两者在上下文中实质可互换,差别仅在 [RnRS] 中的 define 形式中定义的位置可具有和 <formals> 不兼容的扩展形式。
4339-本文档补充约定,使用 <formals> 的情形包括合并子基本操作(@10.5.7) 和可通过这些操作派生的操作在对应位置的操作数。
4340-针对这个假设,派生实现可进行附加的语义检查。在 NPLA1 的当前实现(特别地,使用 @7.7.4 的 API )中,没有这样的检查。
4315+本文档补充约定,使用 <formals> 的情形包括合并子基本操作(@11.3.8) 和可通过这些操作派生的操作在对应位置的操作数。
4316+针对这个假设,派生实现可进行附加的语义检查。在 NPLA1 的当前实现(特别地,使用绑定支持 API(@7.7.4) )中,没有这样的检查。
43414317 这实质等价使用 [Shu09] 中的记法,即 <formals> 用于除和 [Shu09] 的 $define! 类似外的所有操作(包括 $set! 和 $let 等,而不论是否对应 <body> )。这些上下文中总是隐含了上述的可派生实现的要求。
43424318 和 [RnRK] 不同,<body> 不蕴含顺序求值子项。
43434319
43444320 @9.3 对象语言语法:
4345-基于 NPLA 基本语法约定参见 @5.2 。
4346-表达式的语法符合 @3.4.2 。
4321+基于 NPLA 基本语法约定参见 NPLA 约定(@5.2) 。
4322+表达式的语法符合 NPL 表达式(@3.4.2) 。
43474323
43484324 @9.3.1 字面量(@3.3.3) :
4349-由 @5.2 、@5.6.1 和 @9.2.2.2 ,字符串字面量的类型为 <string> 。
4325+由 NPLA 约定和 NPLA 记号值(@5.6.1) 的约定,字符串字面量的类型为 <string>(@9.2.2.2) 。
43504326 NPLA1 支持以下扩展字面量(@3.3.3) :
43514327 #t :类似 Kernel 的 #t 字面量,类型为 <bool> 。
43524328 #f :类似 Kernel 的 #f 字面量,类型为 <bool> 。
43534329 #true :同 #t 。
43544330 #false :同 #f 。
43554331 #inert :类似 Kernel 的 #inert 字面量,宿主值为 ValueToken::Unspecified(@7.2.2) 而不具有单独的类型(因此也不需要定义 inert? 谓词)。
4356-另见 @10.5.1 。
4357-NPLA1 字面量都是纯右值(@5.5.1) ,但总是允许实质化转换(@5.5.5) 为消亡值并引入可互操作的临时对象(@5.5.6.3) 。
4332+另见基本对象(@11.3.1) 。
4333+NPLA1 字面量都是纯右值(@5.5.1) ,但总是允许实质化转换(@5.5.5) 为消亡值并引入允许互操作(@2.3.3) 的临时对象(@5.5.6.3) 。
43584334 这和宿主语言的字符串字面量是左值不同。当前 NPLA1 对象语言不提供能引起互操作差异的接口(字符串字面量不被修改),以后可能改变。
43594335
43604336 @9.3.2 函数合并(@4.5.3) :
43614337 和 Scheme 及 Kernel 不同,求值算法决定求值为函数合并表达式的语法表达不需要括号,且具有不同的函数合并形式(@7.8.2) 。
43624338 以下使用 ...(@9.1) 作为函数的操作数时,可支持没有操作数的函数合并。此情形下应用表达式仍需要前缀 () ,但不在以下规约文法中显式地表示。
43634339
4364-@9.4 基本语义规则和约定:
4365-为区分同类约束(@9.2) 的不同项,约束的名称后(在 > 之前)的可带有以 1 起始的正整数序数。除非另行指定,这些序数仅用于区分不同的同类约束项,无其它附加含义。
4366-本节中除循环引用(@9.6.1.1) 的限制外,不支持的特性可能会在之后的实现中扩展并支持。
4367-NPLA1 对象语言程序中的未定义行为(@2.3.2) 包括 NPLA 未定义行为(@5.2.2) 和以下扩展 NPLA 未定义行为:
4368-特定情形下访问被修改的环境中绑定的对象(@9.6.2) 。
4369-
4370-@9.4.1 求值算法:
4371-除非另行指定,NPLA1 对象语言的求值总是使用规范求值算法(@7.8.2) 。
4372-在 REPL(@7.8) 中输入求值算法接受的语法形式之前,求值可使用基于中缀变换(@7.5.2) 识别的 ; 和 , 分隔符,分别表示对被分隔的序列参数进行有序和无序列表求值(替换后合并子功能对应参考实现环境中函数 $sequence(@10.6.1) 和 list%(@10.5.5) 求值后的合并子)。
4373-其中,分隔符 , 优先组合。
4374-对分隔符的处理使用和组合顺序相反的两遍分别对 ; 和 , 遍历替换,实现参见 @8.5 。
4375-由此引起的其它语法差异参见 @9.5.2 。
4376-为避免可能引入非真合并子(@9.6.4),参考实现对分隔符的使用附加限制,参见 @10 。
4377-
4378-@9.4.1.1 实现风格:
4379-和 Scheme 不同而和 Kernel 类似,求值通常使用显式的风格(详见 [Shu10] )而不是依赖 quote 的隐式风格;这和不需要括号的语法特性无关。
4380-NPL 仍提供 $quote(@10.6.1) 以避免用户可能的不必要的冗余代码;参考实现的限制参见 @10.2 。
4381-
4382-@9.4.2 对象语言内存安全保证:
4383-对象语言的内存安全保证及违反内存安全的(不完全)检查的基本机制基于 NPLA1 关于被规约项的约定(@7.1) 。
4384-引用持有者及其访问操作仅在有限的不保证内存安全的上下文中引入,其它限制同 @7.1.4.3 。被引入的引用持有者仅用于互操作,在对象语言中不可见。
4385-不进行引起内存安全以外的未定义行为的操作(包括 @9.6.1.1 等)且不存在通过无效引用值(@9.6) 的访问(如 @9.4.8.3 中的情形)时,对象语言保证内存安全。
4386-不保证内存安全的引用值的访问即访问超出生存期的被引用对象,可由以下情形引入:
4387-和实现进行(通常无法保证内存安全的)互操作;
4388-绑定列表(@9.2.2.1) 传递引用(@7.7.3) 且传递的引用值被求值(@5.7.4.1) 使用时,被引用的对象不在生存期内;
4389-调用可能返回引用值的合并子(通常通过 @8.4.5.4 实现),且返回值(@4.5.3.1) 对应的对象不在生存期内(另见 @10.4.1 );
4390-使用其它不保证内存安全的操作(可由 NPLA1 参考环境提供,参见 @10.1.4 )引入的不具有内存安全保证的间接值访问实体。
4391-绑定到形式参数的右值(@5.5.1) 保存在过程调用的局部环境(@8.4.5) 中,因此退出函数体(@8.4.5) 求值(局部环境被释放后)返回其引用总是无法满足安全保证;
4392-绑定到列表形式参数上的实际参数列表总是右值;
4393-对返回值中涉及到的安全保证机制,参见 @9.6.1.4 。
4394-
4395-@9.4.3 诊断(diagnostics) :
4396-NPLA1 的特定求值(@9.4.1) 步骤可引起诊断(@2.3.2) ,包括:
4340+@9.4 对象语言内存安全(@5.2.4.3) 保证:
4341+对象语言的内存安全保证及违反内存安全的(不完全)检查(参见 @7.1.4.3 )的基本机制基于 NPLA1 关于被规约项、生存期、所有权和间接值的约定(@7.1) 。
4342+
4343+@9.4.1 对象语言基本内存安全保证:
4344+对象语言提供关于内存安全的基本保证:
4345+不存在内存安全以外的未定义行为(包括 @9.9.1.1 等)、不存在不保证内存安全的互操作(@2.3.3) 且不存在不安全间接值访问(@9.4.2) 时,对象语言的程序执行保证内存安全。
4346+非内存安全操作(@5.2.4.3.1) 在对象语言中以不安全间接值访问(@9.4.2) 的一部分情形体现。
4347+除非另行指定,假定实现进行互操作(@5.2.1) 无法保证内存安全。
4348+
4349+@9.4.2 间接值实现规则:
4350+基本规则参见 @7.1.3 。
4351+环境引用(@5.7.3.1) 和引用值(@5.7.3.2) 在对象语言中可见。
4352+环境总是通过环境引用在对象语言中被访问;被引用的环境对象(@5.4.3) 在对象语言中不可见。
4353+引用持有者(@5.7.3.3) 及其访问操作仅在有限的不保证内存安全的上下文中引入,其它限制同 @7.1.4.3 。
4354+被引入的引用持有者仅用于互操作,在对象语言中不可见。
4355+
4356+@9.4.3 不安全间接值访问:
4357+对象语言的不安全间接值访问包括:
4358+通过未检查的不安全引用值(@5.6.3.1) 访问;
4359+通过无效的间接值(@5.7.3) 访问。
4360+
4361+@9.4.3.1 无效的环境引用(@5.7.3.1) :
4362+环境对象被销毁导致环境引用无效化。
4363+另见环境生存期(@9.9.3.5) 。
4364+
4365+@9.4.3.2 无效的引用值(@5.7.3.2) :
4366+无效的间接值包含无效的引用值(@5.7.3) ,因此通过无效间接值访问包括无效的引用值的访问。
4367+对象语言不提供悬空引用(@5.5.4.1) 以外构造无效引用值的操作。
4368+对象语言中引入悬空引用的情形包括:
4369+调用可能返回引用值的合并子(通常通过 @8.4.5.4 实现),且没有另行保存函数体求值所在的当前环境,返回值(@4.5.3.1) 对应的对象不在生存期内(另见 @11.2.1 ):
4370+ 绑定到形式参数的右值(@5.5.1) 保存在过程调用的局部环境(@8.4.5) 中,退出函数体(@8.4.5) 的求值,局部环境被释放后,返回的其引用是悬空引用。
4371+ 实现等效上述情形的派生操作的使用,如:
4372+ 绑定列表(@9.2.2.1) 传递引用(@7.7.3) 且传递的引用值被求值(@5.7.6.1) 使用。
4373+ 间接保留引用值(@10.4.3) 可能提供变量绑定,这些绑定的目标对象可能依赖环境(如合并子的静态环境(@4.6.1.1.2) ),被销毁时访问被依赖的环境(如合并子调用求值函数体)。
4374+ 未绑定对象(@9.7.4.3) 。
4375+另见对象语言的引用值(@9.9.1) 。
4376+
4377+@9.4.3.3 其它无效的间接值:
4378+使用其它不保证内存安全的操作可引入不具有内存安全保证的间接值(@5.7.5) 访问实体。
4379+这些间接值可能因为和悬空引用相同的情形无效化(@5.7.3) 。
4380+
4381+@9.4.4 保留间接值:
4382+对象的直接子对象或间接子对象是间接值时,对象包含间接值。
4383+修改对象为间接值,或者使之包含间接值时,对象保留间接值。
4384+函数调用返回(在对象语言中允许出现的,下同)间接值或包含间接值的对象时,在返回值中保留间接值。
4385+函数调用修改环境使环境对象保留间接值(绑定间接值或包含间接值作为子对象的对象作为被绑定对象(@5.4.3) )时,在环境中保留间接值。
4386+函数调用修改一等对象或其子对象,使之保留间接值时,在对象中保留间接值。
4387+函数返回包含间接值的对象由参数的值决定时,保留参数中的间接值。这典型地出现在构造器(@10.5.5) 中。
4388+在返回值中保留间接值、在环境中保留间接值、在对象中保留间接值或保留参数中的间接值的函数保留间接值。
4389+保留间接值操作的内存安全的一个必要条件是所有被保留的间接值在之后的使用中都满足内存安全。
4390+保留间接值在操作后可能因间接值无效(如悬空引用),无法继续保证内存安全。
4391+在环境中保留间接值时,应保证环境具有足够的生存期,以避免间接值依赖无效的环境引用(如引用值引用已被销毁的关联环境(@5.6.3.1) )导致访问环境中对象的未定义行为。
4392+按被保留的间接值的来源,保留间接值分为以下两个子类:
4393+直接保留间接值:接受间接值参数;
4394+间接保留间接值:接受的参数或参数在特定环境中被求值得到的结果决定是否直接保留间接值(如合并子或构成形式参数树(@7.7.3) 的可能带有引用标记字符(@7.7.3.4) 的符号)。
4395+操作可保留间接值:
4396+使用函数调用实现的操作可通过函数调用保留间接值(4.5.3.1) ;
4397+其它实现方式可等效地保留间接值。
4398+
4399+@9.4.5 不安全(unsafe) 操作(@4.4.3.1) :
4400+不安全操作是可能在程序的执行中引入未定义行为(@9.1.4) 的操作。
4401+这里的未定义行为包含在操作中直接引入的未定义行为,以及因为操作被执行而使程序在之后无法确保排除的未定义行为。
4402+不安全操作是实现可选提供的。这些操作可能因不同理由在操作中或操作之后的程序中引入未定义行为:
4403+保留可能无效的间接值(@9.4.4) :
4404+ 保留可能无效的引用值(@9.4.3.2) ;
4405+ 保留可能无效的环境引用。
4406+可能因为操作环境强引用而引入循环引用(@9.9.1.1) ;
4407+可能引入数据竞争(@5.2.4.3) ;
4408+是其它另行指定的可能引入未定义行为的操作。
4409+当前对象语言不支持并发访问对象。数据竞争仅可由和宿主语言的互操作(@5.2.4) 引入。
4410+
4411+@9.4.6 对象语言接口的安全保证机制:
4412+对象语言接口的安全保证机制提供不同接口的分类,通过允许区分是否具有内存安全保证的接口帮助程序利用对象语言基本内存安全保证(@9.4.1) 。
4413+对返回值中涉及到的安全保证机制,参见 @10.4.2 。
4414+通过避免或限制使用不安全操作(@9.4.5) ,实现上述安全保证。
4415+可由 NPLA1 参考环境(@10) 提供的不安全操作的具体约定参见不安全操作约定(@10.8) 和索引(@11.1) 。
4416+
4417+@9.4.6.1 安全性附加证明:
4418+一些不安全操作(@9.4.5) 是否蕴含未定义行为可能依赖具体调用使用的操作数。
4419+若能证明特定的前提保证任意的调用实例中的操作数满足附加的安全假设,则这些不安全操作的调用仍可保证安全。
4420+排除不确保安全性假设互操作(@2.3.3) 时,NPLA1 提供附加调用安全:
4421+若不存在隐藏环境(@9.9.3.1) 中绑定的可修改对象的引用,则仅因可能违反值稳定性(@9.9.3.6.2) 的不安全操作的调用是安全的。
4422+派生实现可对特定调用附加使用限制以便提供证明,或定义其它的调用并提供更强的保证。
4423+
4424+@9.5 诊断(diagnostics) :
4425+NPLA1 的特定求值(@9.7.1) 步骤可引起诊断(@2.3.4) ,包括:
43974426 抽象求值(@4.1) (如 REPL 中进行的翻译)的失败;
4398-在环境(@9.6.2) 中访问指定名称的对象失败时;
4427+在环境(@9.9.3) 中访问指定名称的对象失败时;
43994428 特定的函数应用。
44004429 引起诊断时,求值被终止,或在失败可被恢复时,以其它派生实现定义的方式继续求值。
44014430 其它求值条件详见具体操作的规定。
44024431 其它引起诊断的条件可被派生实现补充指定。
4403-注意未定义行为(@2.3.2) 取消对诊断的要求。
4404-本节以外的诊断消息(@2.3.2) 的其它形式未指定。
4405-
4406-@9.4.3.1 错误(@2.5.2) :
4407-NPLA1 中的错误是按接口的约定不符合预期的正常条件(如不被正常处理的操作数类型(@9.4.3.4) )引起的诊断。
4408-求值特定的表达式可引起(@2.5.2) 错误,包括在求值算法(@9.4.1) 中直接引起的语法错误(@7.8.2) 和其它的语义错误。
4409-以 @9.2 的形式约定的操作中,除类型检查(@9.4.3.4.1) 外,参数绑定(@8.4.5.3) 失败是语法错误。
4432+注意未定义行为(@2.3.4) 取消对诊断的要求。
4433+本节以外的诊断消息(@2.3.4) 的其它形式未指定。
4434+
4435+@9.5.1 错误(@2.5.2) :
4436+NPLA1 中的错误是按接口的约定不符合预期的正常条件(如不被正常处理的操作数类型(@9.5.4) )引起的诊断。
4437+求值特定的表达式可引起(@2.5.2) 错误,包括在求值算法(@9.7.1) 中直接引起的语法错误(@7.8.2) 和其它的语义错误。
4438+以 @9.2 的形式约定的操作中,除类型检查(@9.5.4.1) 外,参数绑定(@8.4.5.3) 失败是语法错误。
44104439 总是依赖程序运行时确定的合并子的具体实际参数的值引起的语法错误是动态语法错误;其它语法错误是静态语法错误。静态语法错误可能通过语法分析从源代码决定。
4411-其它错误包括求值特定的函数应用(@9.4.3) ,由具体操作指定(参见 @10.4.1 )。
4440+其它错误包括求值特定的函数应用(@9.5) ,由具体操作指定(参见 @11.2.1 )。
44124441 程序可通过引发(raise) 错误对象(error object) 指定引起诊断。
44134442 除非另行指定,NPLA1 的错误对象不需要是 NPLA1 支持的对象,而可以仅在宿主实现中可见。
44144443 因果性引起的错误可构成错误的依赖。
44154444 错误对象的其它具体形式由派生实现指定。
44164445
4417-@9.4.3.2 异常(@4.7.1) :
4446+@9.5.2 异常(@4.7.1) :
44184447 NPLA1 的当前诊断使用的异常执行机制由宿主语言支持,通过宿主语言中的异常类型区分不同的异常条件。其异常类型由 NPLA 提供,参见 @6.3 。
44194448 NPLA1 约定的所有要求引起异常的诊断情形都是错误(但用户操作引起异常不一定是错误)。
44204449 不引起未定义行为的翻译失败应抛出异常。
4421-引发错误对象(@9.4.3.1) 可能通过抛出异常实现。被抛出的宿主语言异常对象是错误对象。被抛出的异常类型可具有被显式指定的 public 基类,这些基类应无歧义以允许宿主语言捕获。
4422-若存在依赖错误(@9.4.3.1) 且引发被依赖的错误对象使用抛出异常实现,使用宿主语言标准库的嵌套异常(nested error) 机制实现依赖错误。
4423-除非由宿主环境(@2.7.1) (包括 @9.4.3.3 中指定的情形)、对 TermNode(@5.4.2) 的操作内部实现或另行指定的来源,被抛出的异常对象的类型总是 NPL::NPLException(@6.3) 或其 public 派生类。
4424-若语法错误(@9.4.3.1) 使用抛出异常实现,则异常对象的类型是 NPL::InvalidSyntax(@6.3) 或以其作为无歧义 public 基类的类。
4450+引发错误对象(@9.5.1) 可能通过抛出异常实现。被抛出的宿主语言异常对象是错误对象。被抛出的异常类型可具有被显式指定的 public 基类,这些基类应无歧义以允许宿主语言捕获。
4451+若存在依赖错误(@9.5.1) 且引发被依赖的错误对象使用抛出异常实现,使用宿主语言标准库的嵌套异常(nested error) 机制实现依赖错误。
4452+除非由宿主环境(@2.7.1) (包括 @9.5.3 中指定的情形)、对 TermNode(@5.4.2) 的操作内部实现或另行指定的来源,被抛出的异常对象的类型总是 NPL::NPLException(@6.3) 或其 public 派生类。
4453+若语法错误(@9.5.1) 使用抛出异常实现,则异常对象的类型是 NPL::InvalidSyntax(@6.3) 或以其作为无歧义 public 基类的类。
44254454 除显式指定的情形,抛出的具体异常类型未指定。通常实现可根据接口的含义使用 @6.3 中最合适的异常。
44264455
4427-@9.4.3.3 运行时(@2.4.1) 错误条件(@2.5.2) :
4456+@9.5.3 运行时(@2.4.1) 错误条件(@2.5.2) :
44284457 除非另行指定,实现应对以下全局的错误条件按要求引起诊断。
44294458 资源耗尽(resource exhastion) 时,引发特定于资源耗尽的错误对象。
44304459 除非另行指定,上述表示资源耗尽的错误对象满足宿主语言的以下类型的异常对象:
44314460 宿主资源耗尽时,异常类型满足常规宿主资源分配要求(@5.2.2.1) 的类型;
4432-否则,同 @9.4.3.2 。
4433-若规约不符合资源耗尽条件,则在满足 @9.4.8 时继续规约可能符合的资源耗尽条件应保证与继续规约的次数无关。
4434-
4435-@9.4.3.4 检查(check) :
4461+否则,同 @9.5.2 。
4462+若规约不符合资源耗尽条件,则在满足 @9.7.4 时继续规约可能符合的资源耗尽条件应保证与继续规约的次数无关。
4463+
4464+@9.5.4 检查(check) :
44364465 检查是限定成功的操作应满足的(必要非充分)条件引起诊断的操作。检查失败时要求引起诊断。
44374466 良定义的(well-formed) 检查应具有强规范化性质(@4.4.3) ,以保证有限数量的检查总在有限的计算步骤内终止。在进行检查的上下文,实现不需在此之前对检查的这个性质附加检查。
44384467 检查条件限定检查的通过或失败。除非另行指定,通过的检查没有作用,失败时总是具有作用(通常可引起副作用)。
4439-NPLA1 要求在特定上下文进行要求的类型检查(@9.4.3.4.1) 。派生实现可定义其它检查。
4468+NPLA1 要求在特定上下文进行要求的类型检查(@9.5.4.1) 。派生实现可定义其它检查。
44404469 函数操作的语义可单独指定检查,具体形式由具体操作指定。
44414470
4442-@9.4.3.4.1 类型检查:
4471+@9.5.4.1 类型检查:
44434472 基于 @5.5.7 ,对应对象语言表达式的表示实体的元素可用于表示操作中的名义(nominal) 类型检查。
44444473 类型检查包括:
44454474 对求值得到的操作数(@9.2.2.2) ,若操作的语义需要,则总是进行类型检查;
@@ -4448,112 +4477,98 @@
44484477 部分实体从属于其它实体类型而构成子类型(subtyping) 关系;部分的规约操作取得求值结果保证结果中的值可能具有的特定类型集合,这些类型也一并在以下描述中给出;其它情形不指定类型。
44494478 规约预期符合约束。若违反由项的值对应的动态类型(@5.5) 不匹配导致,则求值失败;否则,行为未指定。
44504479 除非另行指定,不同类型检查的作用的顺序未指定。
4451-类型检查失败引发错误(@9.4.3.1) ,称为类型错误(type error) 。
4452-
4453-@9.4.4 外部表示:
4480+类型检查失败引发错误(@9.5.1) ,称为类型错误(type error) 。
4481+
4482+@9.6 外部表示:
44544483 同 @4.1.1 ,外部表示由派生实现约定。
44554484 和 Kernel 不同,NPLA1 不要求对象和其它实体存在外部表示,也不要求外部表示唯一。
4456-NPLA1 当前不提供可移植的互操作接口(包括 I/O 操作),也不约定其涉及的外部表示形式。用户可自行通过调用 NPLA1 宿主语言中的实现的 API(@7) 扩展。
4457-
4458-@9.4.4.1 文本形式:
4459-除非另行指定,外部表示共享 NPLA 词法分析(@5.3.1) 兼容的字符串格式。另见 @5.2 。
4460-对和实现环境(@2.3.2) 交互的操作,当前使用外部表示附加约定如下:
4485+NPLA1 当前不提供可移植的互操作(@2.3.3) 接口(包括一些基本 I/O 操作),也不约定其涉及的外部表示形式。用户可自行通过调用 NPLA1 宿主语言中的实现的 API(@7) 扩展。
4486+
4487+@9.6.1 文本形式:
4488+除非另行指定,外部表示共享 NPLA 词法分析(@5.3.1) 兼容的字符串格式。另见 NPLA 约定(@5.2) 。
4489+对和实现环境(@2.3.3) 交互的操作,当前使用外部表示附加约定如下:
44614490 对来自任意外部文件的文本流的输入和输出:
44624491 首先忽略 UTF-8 BOM(若存在),不保证检查其余的内容相对使用的编码的有效性。
44634492 和 @5.3.1 一致的方式使用二进制模式处理内容(如处理换行)。
44644493 若程序的实现逻辑依赖具体编码,处理相对编码非法的流内容的程序行为未指定。
44654494
4466-@9.4.5 对象同一性(@4.1) :
4467-NPLA1 的对象是一等对象(@4.1) 。由定义,NPLA1 的对象默认确保同一性。
4468-
4469-@9.4.5.1 对象的修改和变化 :
4470-对象作为实体,其修改和变化的基本概念参见 @4.1.4.2 。
4471-NPLA 约定(@5.2) 对象的表示同宿主实现的对象,其修改也同宿主对象的修改。
4472-类似 Kernel ,对明确不可变的对象进行变化的操作引起错误(@9.4.3.1) 。
4473-类似 Kernel ,对象可能隐藏作为非一等状态(@4.2.2.1) 的管理状态(administrative state) 。引起对象内的管理状态的改变的操作不一定是改变对象的操作。
4474-管理操作在宿主语言可以类的 mutable 数据成员实现,但 NPLA1 不提供特性使子对象的可修改性的限制会如宿主语言的 const 限定符自动传播(propagate) ,因此也不需要提供对应的类型检查修改机制。
4475-类似地,对象还可能具有对外部不引起可观察行为(@4.1.3) 差异的隐藏的可变状态。引起这些对象内的可变状态的改变的操作不一定是修改操作。
4476-管理状态和不引起可观察行为的隐藏状态在针对对象语言的的讨论中被排除;除非另行指定(由具体操作的语义蕴含),所有可变状态都不属于这些被排除的状态。
4477-类似宿主语言(如关于 const 限定符的语义),生存期开始前或结束后的(可能并未完成构造的)对象中的子对象的修改不是对象的修改;对应地,此处的子对象的变化也不是对象的改变操作。
4478-改变上述被排除的状态的修改操作不被视为对象语言中的对象的改变操作(@4.1.4.2) 。
4479-和 Kernel 不同,NPLA1 允许直接修改对象而非通过指定子对象引用(@5.6.3.5) 的对象的改变操作(@4.1.4.2) 。
4480-对包含所有权的子对象(@9.6) 的修改是对所在对象的修改。
4481-除非另行指定,NPLA1 不限制任意对象不可修改。
4482-等价关系和限制不可修改性的方法的方式不唯一,因此不可修改性也不唯一。
4483-因为外部表示不唯一(@9.4.4) ,不需要基于此定义一种正规的关于外部表示的等价判断形式。
4484-开放类型映射(@5.2.3) 不保证非特定对象之间的不可修改性具有唯一的定义。
4485-
4486-@9.4.5.1.1 赋值(assignment) :
4487-NPLA1 的赋值操作专指以引用值操作数指定对象且不引起同一性改变的对象修改(@9.4.5.1) 。
4488-注意这和 Kernel 的赋值操作包含以特定对象进行替换(可使用项的转移(@5.5.3) 实现)而使对象被修改的情形不同。
4489-注意避免使用引用值作为操作数的自赋值(self assignment) 引起循环引用(@9.6.1.1) 。
4490-类似宿主语言,除非另行指定,赋值操作不保留源操作数的值类别(@9.5.1) 和可修改性。
4491-
4492-@9.4.5.1.2 转移:
4493-转移可导致被转移对象的外部可见的修改。
4494-转移不需要是直接显式求值特定的函数调用的副作用。
4495-例如,使用唯一引用(@5.4.2.2) 初始化对象,可转移被引用对象对应的项(@5.5.3) 。
4496-和宿主实现不同,当前实现不直接通过初始化转移宿主对象(@5.5.2.3) 。
4497-
4498-@9.4.5.2 驻留(interning) :
4499-出现在表达式中多个位置的值在实现中可共享一个对象作为内部表示。这个对象被驻留(interned) 。
4500-因为子对象允许通过引用值被直接修改(@9.4.5.1) ,驻留对象创建的共享可能影响可观察行为(@4.1.3) 。
4501-因此兼容 NPLA1 语义的驻留要求排除可修改的操作(@9.4.5.1) ,且被驻留的值对应的对象的同一性不被外部依赖。
4502-当前实现不使用对象驻留,以简化存储对象的互操作(@5.2.4) 。
4503-
4504-@9.4.5.3 等价比较:
4505-和 Kernel 不同,一些类型的对象若可修改(@9.4.5.1)(如环境(@9.6.2) ),不保证 eq? 和其它等价谓词(@10.5.2) 的比较结果等价。
4506-但是,基于 @6.9.1 已约定宿主值的类型,在对象语言中传递环境引用(@5.4.3) 不改变环境的这些等价性。
4507-为了满足不依赖引用的一等对象,区分引用和被引用的对象都作为一等实体,这是必要的。
4508-一般地,谓词 eq? 用于判断两个参数对象的同一性。
4509-
4510-@9.4.5.4 无效化(invalidation) :
4511-若对象的引用值保持有效(@9.6.1) ,则指称的左值的对象同一性不变。
4512-类似实现中项的无效化(@5.4.2) ,引用值可能被指定无效化(invalidate) ,不再保证有效,为无效的(invalid) 值,包括以下情形:
4513-被引用的对象生存期已结束(此时引用值是悬空引用(@5.6.3) );
4514-对象被除通过重绑定(@9.6.2.2) 、赋值(@9.4.5.1.1) 和另行指定的情形以外的方式修改(@9.4.5.1) ,而引起对象同一性的改变。
4515-使用被无效引用值访问对象的行为未定义。
4516-对项的赋值(@9.4.5.1.1) 仍可能因为对子项的修改而使其表示的对象的引用无效化。
4517-
4518-@9.4.7 类型分类:
4519-和 Kernel 不同,NPLA1 不要求支持任意类型的不相交集合即分区(partition) 。这避免假定类型全集。
4520-和 Kernel 不同,NPLA1 的类型判断谓词是一元谓词,接受一个参数(@4.6.2.5) ,以强调语言提供的接口的正交性(@1.4.2.4) 。这也避免对 map(@10.6.2) 等库函数的依赖。
4521-和 Kernel 不同,列表类型只包括真列表(@9.6.3) 。列表节点的实现的表示详见 @5.4.2.1 。
4522-
4523-@9.4.8 一般 TCO/PTC(@7.10) 保证和限制:
4524-一般实现策略参见 @7.10.1 。部分实现限制参见 @7.11.5 。
4525-当前实现的规约(如 A1::Reduce(@7.4.4) )直接递归规约子表达式支持的尾上下文(@4.4.7) 较少(详见 @9.4.8.1) ,和 Scheme 对大量特定的形式提供明确的尾上下文上的 PTC 保证不同。
4526-和 Kernel 类似,这是由于缺少针对特定的特殊形式(@5.2) 的特设规则。但因为程序实现(@9.1) 等限制,当前设计和实现支持的非调用的上下文(@9.4.8.3) 较 Kernel 少。
4495+@9.7 表达式(@4.1) 语义:
4496+表达式具有和语法(@3.4.2) 构造不直接相关的且可能上下文相关的语义。
4497+部分语义不需要通过求值(@4.1) 体现。
4498+
4499+@9.7.1 求值算法:
4500+除非另行指定,NPLA1 对象语言的求值总是使用规范求值算法(@7.8.2) 。
4501+在 REPL(@7.8) 中输入求值算法接受的语法形式之前,求值可使用基于中缀变换(@7.5.2) 识别的 ; 和 , 分隔符,分别表示对被分隔的序列参数进行有序和无序列表求值(替换后合并子功能对应参考实现环境中函数 $sequence(@11.4.1) 和 list%(@11.3.5) 求值后的合并子)。
4502+其中,分隔符 , 优先组合。
4503+对分隔符的处理使用和组合顺序相反的两遍分别对 ; 和 , 遍历替换,实现参见 @8.5 。
4504+由此引起的其它语法差异参见绑定构造(@9.7.3) 。
4505+为避免可能引入非真合并子(@9.9.5),参考实现对分隔符的使用附加限制(@10.9.3) 。
4506+
4507+@9.7.1.1 实现风格:
4508+和 Scheme 不同而和 Kernel 类似,求值通常使用显式的风格(详见 [Shu10] )而不是依赖 quote 的隐式风格;这和不需要括号的语法特性无关。
4509+NPL 仍提供 $quote(@11.4.1) 以避免用户可能的不必要的冗余代码;但参考实现限制使用(@10.9) 。
4510+
4511+@9.7.2 值类别和类型:
4512+基本内容参见 NPLA 值类别(@5.5.1) 和表达式的类型(@5.5.7) 。
4513+特定的表达式维护可修改性(@9.8.3) 。这类似宿主语言的 const 类型限定,但只适合左值(@5.5.1) 且仅使用隐式类型。
4514+
4515+@9.7.3 绑定构造(binding construct) :
4516+部分函数合并的求值用于表示在环境(@9.9.3) 中引入绑定,其调用指定绑定操作(@7.7.3) 。具有这样的语法构造的表达式是绑定构造。
4517+绑定构造包含形式参数树(@7.7.3) ,通过绑定规则(@7.7.3) 引入绑定。绑定在符号上的值引入变量(@4.1) 。另见初始化(@5.5.2) 。
4518+按 NPLA 约定(@5.2) 的要求以及绑定初始化(@7.7.3.1) 的约定,操作数树(@7.7.3) 的子节点初始化被绑定的形式参数树的对应子节点。
4519+一些绑定构造使用 <binding>(@9.7.3) 提供在一个表达式多次出现的形式参数树和操作数树。
4520+和 [RnRK] 不同,各种绑定构造可使用 <body>(@9.7.3) 提供操作数。
4521+对绑定项的处理和 [RnRK] 的其它不同参见文法形式补充约定(@9.2.2.4) 。
4522+另见绑定支持 API(@7.7.4) 。
4523+
4524+@9.7.3.1 强递归绑定:
4525+除类似 Kernel 的常规绑定外,NPLA1 的部分绑定构造支持延迟附加的绑定的形式。
4526+强递归绑定支持若同时绑定的递归符号构成循环引用(@9.9.1.1) ,则递归绑定的值都是中间值(@5.3.1.1) 而不引起错误(@9.5.1) 。
4527+
4528+@9.7.3.2 参数转发:
4529+绑定构造可支持参数转发,类似宿主语言中的转发引用(forwarding reference) 参数,保留值类别和可修改性(@9.7.2) 。
4530+
4531+@9.7.3.3 作用顺序(@4.4.1) :
4532+绑定构造引起的绑定初始化的作用顺序满足 @5.5.2 的约定。
4533+若其中存在的副作用,其顺序还满足:
4534+若存在同一形式参数树子节点的不同绑定的操作,则这些操作的副作用之间非决定性有序(@4.4.1) ;
4535+不同符号的形式参数树子节点的绑定操作的副作用之间无序(@4.4.1) ;
4536+形式参数树的子节点绑定的副作用先序(@4.4.1) 枝节点的副作用。
4537+
4538+@9.7.4 一般 TCO/PTC(@7.10) 保证和限制:
4539+参见一般实现策略(@7.10.1) 和部分实现限制(@7.11.5) 。
4540+当前实现的规约(如 A1::Reduce(@7.4.4) )直接递归规约子表达式支持的尾上下文(@4.4.7) 较少(详见 @9.7.4.1) ,和 Scheme 对大量特定的形式提供明确的尾上下文上的 PTC 保证不同。
4541+和 Kernel 类似,这是由于缺少针对特定的特殊形式(@5.2) 的特设规则。但因为程序实现(@9.1) 等限制,当前设计和实现支持的非调用的上下文(@9.7.4.3) 较 Kernel 少。
45274542 虽然不保证在所有情形下支持 PTC ,当前的实现一般支持使用自由存储分配,以尽可能地避免宿主语言的未定义行为(@5.2.2) :
4528-其中,异步规约(@7.9) 实现使分配以环境(@5.4.3)表示的活动记录失败时满足常规宿主资源分配要求(@5.2.2.1) 。
4529-类似地,另见 @5.3.2 和 @7.7.4 关于的资源分配失败时的约定。
4530-满足 @4.1.3 的前提下,实现可能实际支持更多的 TCO 和 PTC 尾上下文。
4531-
4532-@9.4.8.1 支持 PTC 的尾调用尾上下文:
4543+其中,异步规约(@7.9) 实现使分配以环境(@5.4.3) 表示的活动记录失败时满足常规宿主资源分配要求(@5.2.2.1) 。
4544+另见语法分析(@5.3.2) 和绑定支持 API(@7.7.4) 的类似的资源分配失败的约定。
4545+满足实现行为(@4.1.3) 要求的前提下,实现可能实际支持更多的 TCO 和 PTC 尾上下文。
4546+
4547+@9.7.4.1 支持 PTC 的尾调用尾上下文:
45334548 当允许忽略非平凡析构(@7.10.3.2) 时,可以在尾上下文求值中进行 TCO 并支持 PTC 。
45344549 注意尾上下文中被求值的子表达式中的对象生存期可被调整(@5.2.6) ,是否调整和具体调整的方式未指定,不同的实现可能不同。
45354550 提供 PTC 保证的尾上下文和 Kernel 类似,当前仅包括 PTC 不改变可观察行为(@4.1.3) 时的:
4536-函数调用(@4.5.3.1) 中,(使用 $vau 和 $lambda 等合并子抽象引入的)合并子(@9.6.4) 的调用(注意不包括其它途径引入的外部函数的调用);
4551+函数调用(@4.5.3.1) 中,(使用 $vau 和 $lambda 等合并子抽象引入的)合并子(@9.9.5) 的调用(注意不包括其它途径引入的外部函数的调用);
45374552 对 <body>(@9.2.2.1) 的求值;
4538-由 <test>(@9.2.2.1) 控制或连续求值多个表达式中最后被求值的子表达式求值,包括 $if(@10.5.3) 、$sequence(@10.6.1) 、$and?(@10.6.1) 和 $or?(@10.6.1) ;
4539-函数 eval(@10.5.6) 、eval%(@10.5.6) 、$quote(@10.6.1) 、id(@10.6.1) 、idv(@10.6.1) 、eval-string(@11.1) 和 eval-string%(@11.1) 对 <expression> 的求值或替换;
4540-函数 apply(@10.6.1) 对 <applicative> 和 <object> 在 <environment> 或默认的动态环境中的应用;
4541-函数 accl(@10.6.1) 、map-reverse(@10.6.2) 和 for-each-ltr(@10.6.2) 蕴含的尾上下文的递归调用。
4542-
4543-@9.4.8.2 支持 PTC 的非调用尾上下文:
4544-通过环境(@9.6.2) 支持的名称解析(@5.4.3) 的实现在符合嵌套调用安全的约定(@6.1) 。
4553+由 <test>(@9.2.2.1) 控制或连续求值多个表达式中最后被求值的子表达式求值,包括 $if(@11.3.3) 、$sequence(@11.4.1) 、$and?(@11.4.1) 和 $or?(@11.4.1) ;
4554+函数 eval(@11.3.7) 、eval%(@11.3.7) 、$quote(@11.4.1) 、id(@11.4.1) 、idv(@11.4.1) 、eval-string(@12.1) 和 eval-string%(@12.1) 对 <expression> 的求值或替换;
4555+函数 apply(@11.4.1) 对 <applicative> 和 <object> 在 <environment> 或默认的动态环境中的应用;
4556+函数 accl(@11.4.1) 、map-reverse(@11.4.2) 和 for-each-ltr(@11.4.2) 蕴含的尾上下文的递归调用。
4557+
4558+@9.7.4.2 支持 PTC 的非调用尾上下文:
4559+通过环境(@9.9.3) 支持的名称解析(@5.4.3) 的实现在符合嵌套调用安全的约定(@6.1) 。
45454560 名称解析可能是尾上下文。
45464561
4547-@9.4.8.3 未绑定对象:
4562+@9.7.4.3 未绑定对象:
45484563 按 @5.2.6 的约定,项上未被绑定到活动记录上的项中的对象生存期可提前结束。
4549-实现 PTC 时被规约时替换结果的清理(@5.7.4) 若实现支持 TCO(@7.4) 且没有实现保存未绑定操作数引起这种情形。
4550-当前通过参考实现环境(@10) 引入的合并子已经支持了保存操作数,但若互操作没有保存操作数,则可能产生问题。
4551-应注意合并子的参数绑定引用值(@7.7.3) 在同一个尾上下文求值引起清理导致悬空引用(@5.6.3) 破坏内存安全(@5.2.4.3) 。
4552-这里的求值典型地可通过显式求值引入。具体地,这主要包含使用引用值作为函数 eval 或 eval%(@10.5.6) 的参数的进行函数应用表达式求值的方式。
4553-对合并子的直接的函数调用求值较不容易引起这种情形,因为 <body> 内使用的参数是被绑定的,其中临时对象即便传递引用也会被转移值(@7.7.3) 。悬空引用通过其它方式(如在合并子的动态环境内显式求值)才被直接引入。
4554-考虑在调用前使用总是不保留引用值(@9.6.1.5) 的 list 和 list* 而不是保留引用值(@9.6.1.5) 的 list% 和 list*%(@10.6.1) ,或单独调用 idv(@10.6.1) 提升被传递项中的值避免此类问题。
4555-
4556-@9.4.8.4 限制影响:
4564+实现 PTC 时被规约时替换结果的清理(@5.7.6) 若实现支持 TCO(@7.4) 且没有实现保存未绑定操作数引起这种情形。
4565+当前通过参考实现环境(@10) 引入的合并子已经支持了保存操作数,但若互操作(@5.2.1) 没有保存操作数,则可能产生问题。
4566+应注意合并子的参数绑定引用值(@7.7.3) 在同一个尾上下文求值引起清理导致悬空引用(@9.4.3.2) 破坏内存安全(@9.4) 。
4567+这里的求值典型地可通过显式求值引入。具体地,这主要包含使用引用值作为函数 eval 或 eval%(@11.3.7) 的参数的进行函数应用表达式求值的方式。
4568+对合并子的直接的函数调用求值较不容易引起这种情形,因为 <body> 内使用的参数是被绑定的,其中临时对象(@5.2.4.2) 即便传递引用也会被转移值(@7.7.3) 。悬空引用通过其它方式(如在合并子的动态环境内显式求值)才被直接引入。
4569+考虑在调用前使用总是不保留引用值(@10.4.3) 的 list 和 list* 而不是保留引用值(@10.4.3) 的 list% 和 list*%(@11.4.1) ,或单独调用 idv(@11.4.1) 提升被传递项中的值避免此类问题。
4570+
4571+@9.7.4.4 限制影响:
45574572 在不保证支持 PTC 时,实现循环可控制结构的程序应注意避免无限递归。如以下 Kernel 程序:
45584573 ($define! (f g) (list ($lambda (x) (g (- x 1))) ($lambda (x) (f (- x 1)))))
45594574 对应 NPLA1 程序(设 - 是保证能终止计算的减法):
@@ -4561,62 +4576,95 @@
45614576 使用任意数值作为参数调用 f 时,若实现不支持 TCO ,以数值调用函数 f 或 g 可引起宿主语言的未定义行为(非异步规约(@7.9) )或最终无法分配存储(异步规约)而不是保持不终止求值。
45624577 实际实现当前支持这个例子的 TCO 。
45634578
4564-@9.5 表达式(@4.1) 语义:
4565-表达式具有和语法(@3.4.2) 构造不直接相关的且可能上下文相关的语义。
4566-部分语义不需要通过求值(@4.1) 体现。
4567-
4568-@9.5.1 值类别和类型:
4569-基本内容参见 @5.5.1 和 @5.5.7 。
4570-特定的表达式维护可修改性(@9.4.5.1) 。这类似宿主语言的 const 类型限定,但只适合左值(@5.5.1) 且仅使用隐式类型。
4571-
4572-@9.5.2 绑定构造(binding construct) :
4573-部分函数合并的求值用于表示在环境(@9.6.2) 中引入绑定,其调用指定绑定操作(@7.7.3) 。具有这样的语法构造的表达式是绑定构造。
4574-绑定构造包含形式参数树(@7.7.3) ,通过绑定规则(@7.7.3) 引入绑定。绑定在符号上的值引入变量(@4.1) 。另见 @5.5.2 。
4575-按 @5.2 的要求以及 @7.7.3.1 的约定,操作数树(@7.7.3) 的子节点初始化被绑定的形式参数树的对应子节点。
4576-一些绑定构造使用 <binding>(@9.5.2) 提供在一个表达式多次出现的形式参数树和操作数树。
4577-和 [RnRK] 不同,各种绑定构造可使用 <body>(@9.5.2) 提供操作数。
4578-对绑定项的处理和 [RnRK] 的其它不同参见 @9.2.2.4 。
4579-另见 @7.7.4 的 API 。
4580-
4581-@9.5.2.1 强递归绑定:
4582-除类似 Kernel 的常规绑定外,NPLA1 的部分绑定构造支持延迟附加的绑定的形式。
4583-强递归绑定支持若同时绑定的递归符号构成循环引用(@9.6.1.1) ,则递归绑定的值都是中间值(@5.3.1.1) 而不引起错误(@9.4.3.1) 。
4584-
4585-@9.5.2.2 参数转发:
4586-绑定构造可支持参数转发,类似宿主语言中的转发引用(forwarding reference) 参数,保留值类别和可修改性(@9.5.1) 。
4587-
4588-@9.5.2.3 作用顺序(@4.4.1) :
4589-绑定构造引起的绑定初始化的作用顺序满足 @5.5.2 的约定。
4590-若其中存在的副作用,其顺序还满足:
4591-若存在同一形式参数树子节点的不同绑定的操作,则这些操作的副作用之间非决定性有序(@4.4.1) ;
4592-不同符号的形式参数树子节点的绑定操作的副作用之间无序(@4.4.1) ;
4593-形式参数树的子节点绑定的副作用先序(@4.4.1) 枝节点的副作用。
4594-
4595-@9.6 对象语言数据结构:
4579+@9.8 对象语义:
4580+关于存储和对象模型,基本内容参见 @5.2.4 。另见 @9.4 。
4581+
4582+@9.8.1 对象同一性(@4.1) :
4583+NPLA1 的对象是一等对象(@4.1) 。由定义,NPLA1 的对象默认确保同一性。
4584+
4585+@9.8.2 子对象(subobject) :
4586+子对象(subobject) 同宿主语言的约定;在宿主语言的表示中表现为子对象的对象语言中的对象,也是对象语言的子对象。
4587+对象对其存储期和生存期的约束和宿主语言相同。
4588+子对象可具有引用值。子对象的引用值可能使用子对象引用(@5.6.3.5) 而非通常的项引用(@5.6.3) 实现。
4589+
4590+@9.8.3 对象的修改和变化 :
4591+对象作为实体,其修改和变化的基本概念参见 @4.1.4.2 。
4592+NPLA 约定(@5.2) 对象的表示同宿主实现的对象,其修改也同宿主对象的修改。
4593+类似 Kernel ,对明确不可变的对象进行变化的操作引起错误(@9.5.1) 。
4594+类似 Kernel ,对象可能隐藏作为非一等状态(@4.2.2.1) 的管理状态(administrative state) 。引起对象内的管理状态的改变的操作不一定是改变对象的操作。
4595+管理操作在宿主语言可以类的 mutable 数据成员实现,但 NPLA1 不提供特性使子对象(@9.8.2) 的可修改性的限制会如宿主语言的 const 限定符自动传播(propagate) ,因此也不需要提供对应的类型检查修改机制。
4596+类似地,对象还可能具有对外部不引起可观察行为(@4.1.3) 差异的隐藏的可变状态。引起这些对象内的可变状态的改变的操作不一定是修改操作。
4597+管理状态和不引起可观察行为的隐藏状态在针对对象语言的的讨论中被排除;除非另行指定(由具体操作的语义蕴含),所有可变状态都不属于这些被排除的状态。
4598+类似宿主语言(如关于 const 限定符的语义),生存期开始前或结束后的(可能并未完成构造的)对象中的子对象的修改不是对象的修改;对应地,此处的子对象的变化也不是对象的改变操作。
4599+改变上述被排除的状态的修改操作不被视为对象语言中的对象的改变操作(@4.1.4.2) 。
4600+和 Kernel 不同,NPLA1 支持直接修改对象,而不只是通过指定子对象关联的被引用对象的改变操作(@4.1.4.2) 。
4601+对包含所有权的子对象的修改是对所在对象的修改。
4602+除非另行指定,NPLA1 不限制任意对象不可修改。
4603+等价关系和限制不可修改性的方法的方式不唯一,因此不可修改性也不唯一。
4604+因为外部表示不唯一(@9.6) ,不需要基于此定义一种正规的关于外部表示的等价判断形式。
4605+开放类型映射(@5.2.3) 不保证非特定对象之间的不可修改性具有唯一的定义。
4606+
4607+@9.8.3.1 赋值(assignment) :
4608+NPLA1 的赋值操作专指以引用值操作数指定对象且不引起同一性(@4.1) 改变的对象修改(@9.8.3) 。
4609+注意这和 Kernel 的赋值操作包含以特定对象进行替换(可使用项的转移(@5.5.3) 实现)而使对象被修改的情形不同。
4610+注意避免使用引用值作为操作数的自赋值(self assignment) 引起循环引用(@9.9.1.1) 。
4611+类似宿主语言,除非另行指定,赋值操作不保留源操作数的值类别(@9.7.2) 和可修改性。
4612+注意,赋值不保证子对象(@9.8.2) 的同一性不被改变。
4613+
4614+@9.8.3.2 转移:
4615+转移可导致被转移对象的外部可见的修改。
4616+转移不需要是直接显式求值特定的函数调用的副作用。
4617+例如,使用唯一引用(@5.4.2.2) 初始化对象,可转移被引用对象对应的项(@5.5.3) 。
4618+和宿主实现不同,当前实现不直接通过初始化转移宿主对象(@5.5.2.3) 。
4619+
4620+@9.8.4 驻留(interning) :
4621+出现在表达式中多个位置的值在实现中可共享一个对象作为内部表示。这个对象被驻留(interned) 。
4622+因为子对象(@9.8.2) 允许通过引用值被直接修改(@9.8.3) ,驻留对象创建的共享可能影响可观察行为(@4.1.3) 。
4623+因此兼容 NPLA1 语义的驻留要求排除可修改的操作(@9.8.3) ,且被驻留的值对应的对象的同一性(@4.1) 不被外部依赖。
4624+当前实现不使用对象驻留,以简化存储对象的互操作(@5.2.4) 。
4625+
4626+@9.8.5 等价比较:
4627+和 Kernel 不同,一些类型的对象若可修改(@9.8.3)(如环境(@9.9.3) ),不保证 eq? 和其它等价谓词(@11.3.2) 的比较结果等价。
4628+但是,基于 @6.9.1 已约定宿主值的类型,在对象语言中传递环境引用(@5.4.3) 不改变环境的这些等价性。
4629+为了满足不依赖引用的一等对象(@4.1) ,区分引用和被引用的对象都作为一等实体,这是必要的。
4630+一般地,谓词 eq? 用于判断两个参数对象的同一性(@4.1) 。
4631+
4632+@9.8.6 无效化(@5.5.4) :
4633+若对象的引用值保持有效(@9.9.1) ,则指称的左值的对象同一性(@4.1) 不变。
4634+作为 @5.5.4 的派生实现,对象语言中的引用值的无效化包括以下情形:
4635+被引用的对象存储期已结束(此时引用值是悬空引用(@9.4.3.2) );
4636+对象被除通过重绑定(@9.9.3.6.1) 、赋值(@9.8.3.1) 和另行指定的情形以外的方式修改(@9.8.3) ,而引起对象同一性的改变。
4637+对项的赋值(@9.8.3.1) 仍可能因为对子项的修改而使其表示的对象的引用值无效化。
4638+
4639+@9.8.7 类型分类:
4640+和 Kernel 不同,NPLA1 不要求支持任意类型的不相交集合即分区(partition) 。
4641+这避免假定类型全集,并开放类型映射(@5.2.3) 。但基于实体文法(@9.2.2) 引入的类型仍被分区。
4642+和 Kernel 不同,NPLA1 的类型判断谓词是一元谓词,只接受一个参数(@4.6.2.5) ,以强调语言提供的接口的正交性(@1.4.2.4) 。这也避免对 map(@11.4.2) 等库函数的依赖。
4643+和 Kernel 不同,列表类型只包括真列表(@9.9.4) 。列表节点的实现的表示详见 @5.4.2.1 。
4644+
4645+@9.9 对象语言数据结构:
45964646 本节指定在 NPLA1 允许以一等实体(@4.2) 被使用的基本元素。
45974647 部分设计原则和规则和 Kernel 不同。
4598-关于存储和对象模型,基本内容参见 @5.2.4 。另见 @9.4.2 。
4599-子对象(subobject) 同宿主语言的约定;在宿主语言的表示中表现为子对象的对象语言中的对象,也是对象语言的子对象。
4600-
4601-@9.6.1 引用:
4602-NPLA1 基于 NPLA 项的引用(@5.6.3) 支持实体的左值引用(@5.7.4.1) ,和 Kernel 等的引用概念类似。
4603-NPLA1 语义中对广义实体(@2.3.2) 的构成依赖的使用也被称为引用,这不限被对象语言中的引用值表达。
4604-和 Kernel 不同,NPLA1 明确允许不通过对象的引用保存对象(参见 @9.6.2 ),但是也允许使用对象引用;即对象和对象的引用都是一等对象(@4.1) 。详见 @4.2 。这也允许子对象直接被所在的对象蕴含。
4648+关于对象语义,参见 @9.8 。
4649+
4650+@9.9.1 引用:
4651+NPLA1 基于 NPLA 项的引用(@5.6.3) 支持实体的左值引用(@5.7.6.1) ,和 Kernel 等的引用概念类似。
4652+NPLA1 语义中对广义实体(@2.3.4) 的构成依赖的使用也被称为引用,这不限被对象语言中的引用值表达。另见环境引用(@5.4.3) 。
4653+和 Kernel 不同,NPLA1 明确允许不通过对象的引用保存对象(参见 @9.9.3 ),但是也允许使用对象引用;即对象和对象的引用都是一等对象(@4.1) 。详见 @4.2 。这也允许子对象直接被所在的对象蕴含。
46054654 使用项引用(宿主类型为 NPL::TermReference )表示(使用 TermNode 表示的)其它对象的引用,即引用值(@5.5.4) 。
46064655 按 NPL::TermReference 初始化时保存的引用来源可区分被引用的对象是否是左值。
4607-左值(@5.5.1) 都通过引用值(参见 @5.7.4.1 ;另见 @4.1 和 @5.2.4 )表示。
4656+左值(@5.5.1) 都通过引用值(参见 @5.7.6.1 ;另见 @4.1 和 @5.2.4 )表示。
46084657 引用值在创建时即引用在生存期内的对象。
4609-有效的(valid) 引用值能安全地访问对象而不引起未定义行为。其它引用值是无效的(invalid) 。
46104658 不安全引用值(@5.6.3.1) 可以是有效的引用值,但运行时无法通过元数据验证其有效性。
46114659
4612-@9.6.1.1 循环引用:
4660+@9.9.1.1 循环引用:
46134661 除非另行指定,对象中的循环引用引起 NPLA 未定义行为(@5.2.2) 。
46144662 典型实现中,循环引用可引起资源泄漏如内存泄漏(@5.2.4.4) ;无条件遍历访问循环引用子对象的求值不具有终止保证(@4.7.2) 。
46154663 例如 NPLA1 参考实现环境(@10) 下求值以下表达式:
46164664 $let ((nenv () make-environment)) $set! nenv self nenv
46174665 可引起被捕获的环境中存储的对象无法释放。
46184666 能同时保证避免资源泄漏的实现引起一般意义上更根本的设计限制,因此不被使用。详见 @4.2.4 。
4619-此外,为了避免 $lambda 等引起不经意的循环引用误用,根据易预测性原则(@1.4.5.2) ,这些组合子的构造器默认不使用强引用作为静态环境。
4667+此外,为了避免 $lambda 等引起不经意的循环引用误用,根据易预测性原则(@1.4.5.2) ,这些组合子的构造器默认不使用强引用(@5.4.3) 作为静态环境。
46204668 若需保持静态环境的所有权,使用显式指定静态环境的构造器(如 $lambda/e ) 和 lock-current-environment 等。
46214669 否则,容易引起循环引用,如以下表达式:
46224670 $def! f $lambda ()
@@ -4626,57 +4674,50 @@
46264674 而求值当前设计中等价的:
46274675 $def! f $lambda/e (() get-current-environment)
46284676 不引起未定义行为。
4629-同时,若访问悬空引用(@5.6.3) ,实现可利用 NPL::EnvironmentReference(@6.9.1) 在闭包中对引用进行检查,使用户无需像 lock-current-environment 一样特别关照 get-current-environment 引起的风险。
4630-
4631-@9.6.1.2 自引用(self-referencing) 数据结构:
4632-因为不支持循环引用(@9.6.1.1) ,不支持引用自身的自引用数据结构。
4677+同时,若访问悬空引用(@9.4.3.2) ,实现可利用 NPL::EnvironmentReference(@6.9.1) 在闭包中对引用进行检查,使用户无需像 lock-current-environment 一样特别关照 get-current-environment 引起的风险。
4678+
4679+@9.9.1.2 自引用(self-referencing) 数据结构:
4680+因为不支持循环引用(@9.9.1.1) ,不支持引用自身的自引用数据结构。
46334681 详见 @4.2.4 。
46344682
4635-@9.6.1.3 引用值作为实际参数:
4636-除非另行指定(如 @9.8.2 和 @10.4.2 ),一般地,函数接受左值引用操作数,使用引用的对象的值和直接使用右值作用相同,但不会修改被左值引用的对象。
4637-这等价隐含无副作用的左值到右值转换(@5.5.5) 。此处的左值引用和宿主语言中的(非 volatile )左值作用类似。
4638-另见 @9.8.4 。
4639-
4640-@9.6.1.4 返回非引用值:
4641-为提供内存安全保证(@9.4.2) ,部分操作总是返回非引用值。
4642-返回非引用值的行为应等价返回值转换(@5.7.4.4) ,其实现未指定(可使用消除引用值的本机实现(@8.1.2) )。
4643-其它操作可返回引用值。
4644-
4645-@9.6.1.5 保留引用值:
4646-返回引用值的操作保留返回值的引用值。
4647-返回包含引用值的对象(如列表(@9.6.3) )由参数决定时,保留参数的引用值。
4648-保留返回值的引用值或保留参数的引用值的函数保留引用值。
4649-保留的引用值可能被引用折叠(@5.6.3.2) 。
4650-函数是否保留引用值以及保留引用值是否被折叠的要求,参见常规函数约定(@9.7) 、函数名称约定(@9.9) 和 NPLA1 参考实现环境(@10) 中的函数名称的约定(@10.4.2) 。
4651-保留引用值的过程返回值可能引入非内存安全操作(@7.1.4.2) 。
4652-
4653-@9.6.2 环境:
4654-和 Kernel 类似,NPLA1 支持一等环境(first-class environment) 。
4655-语言实现可提供非一等环境。总是不能被对象语言作为一等对象的环境是隐藏环境(hidden environment) 。
4683+@9.9.2 符号(@2.3.4) :
4684+在求值算法(@9.7.1) 中,求值符号依赖环境(@9.9.3) 进行名称解析(@4.3.3) ,求值为引用(@9.9.1) 。
4685+符号的实现(@5.6.1) 中和字符串的对应关系可简化互操作(@5.2.4) 。
4686+
4687+@9.9.3 环境:
4688+和 Kernel 类似,NPLA1 支持一等环境(first-class environment) ,即作为对象语言中的一等对象(@4.2.1) 的环境。
4689+和 Kernel 类似,NPLA1 的一等环境可关连一个或多个父环境(@5.4.3) ,其重定向(@4.3.3) 使用 DFS 形式的默认重定向算法(@5.4.3) 。
4690+和 Kernel 不同,环境对象(@5.4.3) 是语言中显式约定的和环境引用(@5.4.3) 不同的非一等对象。
4691+
4692+@9.9.3.1 隐藏环境:
4693+语言实现可提供环境对象以外的非一等环境。总是不能被对象语言以一等对象访问的环境是隐藏环境(hidden environment) 。
46564694 一般地,隐藏环境是某一个(非隐藏的)一等环境的直接或间接父环境(而能通过求值等间接操作被访问)。
4657-和 Kernel 类似,NPLA1 的一等环境可包含一个或多个父环境(@5.4.3) ,其重定向(@4.3.3) 使用 DFS 形式的默认重定向算法(@5.4.3) 。
4658-新环境(fresh environment) 是新创建的环境。除非另行指定,新环境是不存在能引起程序行为改变的父环境的空环境(@4.6.1.1) 。()
4659-和 Kernel 不同,环境绑定(@4.1) 的抽象不依赖对象语言中表达的引用的概念,允许直接关联一个没有引用的值。另见 @4.2.3 和 @5.4.3 。
4660-和 Kernel 不同,环境绑定对被绑定的对象具有所有权(@5.4.3) 。除非另行指定(参见 @10.1.4 ),这种直接所有权是独占的。
4661-和 Kernel 不同,环境对象符合默认的等价比较规则(@9.4.5.3) ,不提供不同等价谓词的结果一致性。
4662-和 Kernel 不同,环境中的绑定的对象可以在引入后通过对象的引用(@9.6.1) 被修改(@9.4.5.1) 。
4663-但环境在特定情形仍保证稳定性(stability) ,即总是可假定绑定维持一定意义的等价性,而可确保其中同名实体的同一性。在这些特定的情形中,违反环境稳定性引起未定义行为(@9.4) 。
4695+
4696+@9.9.3.2 新环境(fresh environment) :
4697+新环境是新创建的环境,和先前的现有环境不共享相同环境对象。
4698+除非另行指定,新环境是不存在能引起程序行为改变的父环境的空环境(@4.6.1.1) 。(创建新环境的一个例子是 Vau 抽象(@8.4.5) 实现过程调用。)
4699+
4700+@9.9.3.3 环境的宿主值和所有权:
4701+和 Kernel 不同,环境可使用环境强引用和环境弱引用(@5.4.3) 蕴含不同的所有权。
4702+环境对应多个宿主值类型(@6.9.3) 。
4703+除非另行指定,使用不同宿主值类型的环境引用被视为相同类型的一等环境。(另见开放类型映射(@5.2.3) 和相关的其它数据结构(@5.4.3) 。)
4704+
4705+@9.9.3.4 环境的同一性和稳定性:
4706+和 Kernel 不同,环境对象符合默认的等价比较规则(@9.8.5) ,不提供不同等价谓词的结果一致性。
4707+和 Kernel 不同,环境中的绑定的对象可以在引入后通过对象的引用(@9.9.1) 被修改(@9.8.3) 。
4708+但环境在特定情形仍保证稳定性(stability) ,即总是可假定绑定维持一定意义的等价性,而可确保其中同名实体的同一性。在这些特定的情形中,违反环境稳定性引起未定义行为(@9.1.4) 。
46644709 当前要求确保的稳定性包括:
4665-隐藏环境的绑定有效稳定性(@9.6.2.2) 和值稳定性(@9.6.2.3) ;
4666-从构造时即明确要求稳定的一等环境(参见 @10.1.1 )。
4667-一般地,环境的稳定性要求构造环境时不能依赖非特定的动态环境(作为被名称解析访问的父环境),因为这些环境的绑定可能具有在构造模块之后确定的绑定,而不能确保模块中的名称具有可预知的含义。
4710+隐藏环境(@9.9.3.1) 的绑定有效稳定性(@9.9.3.6.1) 和值稳定性(@9.9.3.6.2) ;
4711+从构造时即明确要求稳定的一等环境(@10.2.1) 。
4712+一般地,环境的稳定性要求构造环境时不能依赖非特定的动态环境(作为被名称解析(@5.4.3) 访问的父环境),因为这些环境的绑定可能具有在构造环境之后确定的绑定,而不能确保环境中的名称具有可预知的含义。
46684713 环境的稳定性简化分析程序的推理过程,也在许多上下文中允许程序更易被优化。
4669-和 Kernel 不同,环境(@10.5.6) 和合并子操作(@10.5.7) 及基于这些操作的一些派生操作(@10.6) 的操作数树(@7.7.3) 构造不检查其中的非列表项是否都为符号或 #ignore ;匹配时不检查符号重复;若形式参数中的符号重复,则绑定的目标未指定。
4670-此外,NPLA1 提供单独的递归绑定符号的机制,且明确支持在操作数中同时递归绑定之前未被绑定的多个符号(@9.5.2.1) 。
4671-环境对应多个宿主值类型(@6.9.3) 。
4672-关于环境的比较,另见 @9.4.5.3 。
4673-环境绑定中的对象是环境对象的子对象。
4674-关于引入绑定的表达式,参见 @9.5.2 。
4675-
4676-@9.6.2.1 环境生存期:
4714+和 Kernel 不同,环境(@11.3.7) 和合并子操作(@11.3.8) 及基于这些操作的一些派生操作(@11.4) 的操作数树(@7.7.3) 构造不检查其中的非列表项是否都为符号或 #ignore ;匹配时不检查符号重复;若形式参数中的符号重复,则绑定的目标未指定。
4715+此外,NPLA1 提供单独的递归绑定符号(@9.9.2) 的机制,且明确支持在操作数中同时递归绑定之前未被绑定的多个符号(@9.7.3.1) 。
4716+
4717+@9.9.3.5 环境生存期:
46774718 引用环境中的名称时,应确保环境在生存期内。
46784719 特别地,应注意使用函数时引入父环境的生存期。
4679-当前实现对环境引用是 NPL::EnvironmentReference(@6.9.1) 的情形提供一定程度的检查,这通过引用环境时锁定 NPL::EnvironmentReference 的弱引用实现。
4720+当前实现对环境引用(@5.4.3) 是 NPL::EnvironmentReference(@6.9.1) 的情形提供一定程度的检查(@6.10.1) ,这通过引用环境时检查 NPL::EnvironmentReference 中的弱引用是否可被实现。
46804721 特别地,这可针对在 vau 抽象(@8.4.5) 中捕获的静态环境。
46814722 如以下程序(假设 + 是可接受 2 个整数值的应用子)引起无效引用错误(抛出 NPL::InvalidReference 异常(@6.3) ):
46824723 $def! addn ($lambda (a) ($lambda (n) + a n)); (addn 1) 2;
@@ -4684,163 +4725,68 @@
46844725 $def! addn ($lambda (a) ($lambda/e (() lock-current-environment) (n) + a n)); (addn 1) 2;
46854726 其它情形不受检查。
46864727 注意正常的操作不应有生存期错误。
4687-引起这些错误时应已导致未定义行为如循环引用(@9.6.1.1) ,因此程序行为不应依赖检查(@8.4.5.2) 。
4688-另见 @9.4.2 。
4689-
4690-@9.6.2.2 重绑定(rebinding) :
4691-和 Scheme 类似,环境中允许变量被重新绑定,但被重新绑定的变量替换的对象会直接失效;若对象非独占,则结束其生存期并销毁。
4692-对象的引用(@9.6.1) 不因其引用的对象涉及重绑定操作而被无效化(@9.4.5.4) 。
4693-特别地,若继续访问已被求值(@9.4.1) 指称的引用值引用的对象,则超出生存期访问而引起 NPLA 未定义行为(@5.2.2) 。
4694-因为设计原则禁止无法避免的实现开销,这里没有检查而直接指定为无法满足保证所有权条件的未定义行为(@5.7.4.2) 。
4695-任意隐藏环境 E 应满足以下绑定有效稳定性:
4728+引起这些错误时应已导致未定义行为如循环引用(@9.9.1.1) ,因此程序行为不应依赖检查(@8.4.5.2) 。
4729+另见 @9.4 。
4730+
4731+@9.9.3.6 环境中的绑定(@4.1) :
4732+和 Kernel 不同,环境中的绑定的抽象不依赖对象语言中表达的引用的概念,允许直接关联一个没有引用的值。另见 @4.2.3 和 @5.4.3 。
4733+和 Kernel 不同,环境中的绑定对被绑定的对象具有所有权(@5.4.3) 。除在环境中绑定中间值的不安全操作(@9.4.5) ,这种直接所有权是独占的。
4734+基于环境对象的数据结构(@5.4.3) ,环境绑定中的对象是环境对象的子对象。
4735+绑定的变量名是符号构成的名称表达式(@4.5) ,解析(@6.9.5) 的结果总是左值(@5.5.1) 。
4736+另见绑定构造(@9.7.3) 。
4737+
4738+@9.9.3.6.1 重绑定(rebinding) :
4739+和 Scheme 类似,环境中允许变量以相同的名称被重新绑定,简称重绑定。
4740+对象的引用(@9.9.1) 不因其引用的对象被重绑定操作替换值而被无效化(@9.8.6) 。
4741+重绑定替换被绑定对象的值,不改变对象的同一性(@9.8.1) 。若其中存在子对象(@9.8.2) ,则子对象被销毁,任何子对象的引用值被无效化。
4742+特别地,若继续访问已被求值(@9.7.1) 指称的引用值引用的对象,则超出生存期访问而引起 NPLA 未定义行为(@5.2.2) 。
4743+因为设计原则禁止无法避免的实现开销,这里没有检查而直接指定为无法满足保证所有权条件的未定义行为(@5.7.6.2) 。
4744+任意隐藏环境(@9.9.3.1) E 应满足以下绑定有效稳定性:
46964745 通过引用值间接访问 E 中绑定的对象时绑定保持有效,即不被移除或重绑定,保持被绑定对象的生存期和 P 对其的所有权。
4697-这避免因为上述访问违反内存安全而引起 NPLA 未定义行为。
4698-
4699-@9.6.2.3 被绑定对象的值和可观察行为(@4.1.3) :
4700-任意隐藏环境的 E 的任意同一(@9.4.5) 被绑定对象 O 应满足以下的值稳定性:
4701-O 上若发生副作用(如被修改,参见 @9.4.5 ),之后在以 E 或任意以 E 作为直接或间接父环境的环境中以名称解析(@5.4.3) 或 O 的引用值访问 O 时,O 的值和发生作用前的 O 的值在影响可观察行为的意义上等价。
4702-若不满足值稳定性,访问副作用发生后的对象引起扩展 NPLA 未定义行为(@9.4) 。
4703-
4704-@9.6.2.4 冻结(freeze) 操作:
4746+这避免因为上述访问违反内存安全(@5.2.4.3) 而引起 NPLA 未定义行为。
4747+
4748+@9.9.3.6.2 被绑定对象的值和可观察行为(@4.1.3) :
4749+任意隐藏环境(@9.9.3.1) 的 E 的任意同一(@9.8) 被绑定对象 O 应满足以下的值稳定性:
4750+O 上若发生副作用(如被修改,参见 @9.8 ),之后在以 E 或任意以 E 作为直接或间接父环境的环境中以名称解析(@5.4.3) 或 O 的引用值访问 O 时,O 的值和发生作用前的 O 的值在影响可观察行为的意义上等价。
4751+若不满足值稳定性,访问副作用发生后的对象引起扩展 NPLA 未定义行为(@9.1.4) 。
4752+
4753+@9.9.3.7 冻结(freeze) 操作:
47054754 环境可被冻结。冻结后的环境中取得的绑定和引用值不可修改。
4706-特定的环境修改要求环境不在没有冻结状态以确保不变量,要求类型检查(@9.4.3.4.1) 。检查失败则引起类型错误(@9.4.3.4.1) 。
4755+特定的环境修改要求环境不在没有冻结状态以确保不变量,要求类型检查(@9.5.4.1) 。检查失败则引起类型错误(@9.5.4.1) 。
47074756 冻结一个已被冻结的环境没有作用。
4708-注意冻结的环境中仍可添加、移除绑定或重绑定(@9.6.2.2) 。
4709-NPLA1 隐藏环境是冻结的。当前 NPLA1 不提供在已有环境撤销冻结的方法。
4757+注意冻结的环境中仍可添加、移除绑定或重绑定(@9.9.3.6.1) 。
4758+NPLA1 隐藏环境(@9.9.3.1) 是冻结的。当前 NPLA1 不提供在已有环境撤销冻结的方法。
47104759 若提供其它由派生实现定义的方法(附加初始化或提供本机实现操作)撤销冻结而使上述调用的安全性失效,这种方法应由派生实现定义。
47114760
4712-@9.6.3 列表:
4713-和 Scheme 及 Kernel 不同,基于 @4.2.4 ,NPLA 支持的列表都是真列表(@5.4.2.1) ,元素有限且不存在环。
4761+@9.9.4 列表:
4762+和 Scheme 及 Kernel 不同,基于 @4.2.4 的理由,NPLA 支持的列表都是真列表(@5.4.2.1) ,元素有限且不存在环。
47144763 作为真列表,列表直接被表示为子项元素的列表节点的序列,其宿主类型为 TermNode(@5.4.2) 。
47154764 利用 TermNode 中可选的值数据成员(@5.4.2) ,列表节点可以退化为非列表的值的表示;列表自身也可作为其它列表的节点。列表节点的实现的表示详见 @5.4.2.1 。
47164765 由 TermNode 的性质,列表的元素是列表的子对象,列表对作为元素的节点具有所有权。同一个列表的元素节点之间没有所有权关系。
47174766 这些特性确保基于列表的数据结构在对象语言逻辑上的简单性。也因此 NPLA1 对应的操作中,没有对环存在性的检查。
47184767 没有环的结构能保证所有权语义能按需嵌入(embed) 到列表中,即列表可保证表示为同构的具有对节点所有权的嵌套 cons 对,即便当前实现不使用(@7.7.4) 。
4719-但是,这些特性也带来对元素引用的一些限制:列表的引用(@9.6.1) 只限引用完整的列表对象,而不引用部分列表(如 cons 的组成部分)。
4720-绑定构造(@9.5.2) 的形式参数树(@7.7.3) 是可能是符号或真列表。
4721-
4722-@9.6.4 合并子:
4768+但是,这些特性也带来对元素引用的一些限制:列表的引用(@9.9.1) 只限引用完整的列表对象,而不引用部分列表(如 cons 的组成部分)。
4769+绑定构造(@9.7.3) 的形式参数树(@7.7.3) 是可能是符号(@9.9.2) 或真列表。
4770+
4771+@9.9.5 合并子:
47234772 Kernel 的合并子对应 NPL 的真合并子(@4.5.3.2) 。
47244773 为维护语言规则的简单性(@1.4.3) ,除非另行指定,对象语言中的所有合并子都是真合并子。
47254774 尽管没有要求(@4.2.6) ,这种规约也更符合 [RnRK] 原则 G1b ;同时,这易于移植 Kernel 代码。
47264775 NPLA1 对象语言不提供其它合并子的普遍操作(不满足类似 G1b 的原则(@1.4.5.1) ),但 NPLA1 API 可支持其它合并子。
47274776 可能直接引入非真合并子的 API 包括项变换 API (@7.6.3) 。
47284777 NPLA1 的合并子使用包装数(@7.6.1.1) 存储可能需要求值操作数的次数。
4729-因为包装操作(@4.5.3.2) 不符合 TCO/PTC 的条件(@9.4.8) ,包装操作允许具有附加的开销。包装数使用的宿主类型的上限(@7.6.1.1) 足以保证修改包装数的开销严格不大于直接实现。
4778+因为包装操作(@4.5.3.2) 不符合 TCO/PTC 的条件(@9.7.4) ,包装操作允许具有附加的开销。包装数使用的宿主类型的上限(@7.6.1.1) 足以保证修改包装数的开销严格不大于直接实现。
47304779 在不出错时行为和不使用包装数而直接使用嵌套子对象实现的行为完全一致,但在到达包装数时继续包装即包装数溢出(wrapping count overflow) ,行为可能不相同:
4731-若某个操作使合并子超出上限,则符合非宿主资源耗尽的错误条件(@9.4.3.3) 。
4732-
4733-@9.6.5 数值类型:
4780+若某个操作使合并子超出上限,则符合非宿主资源耗尽的错误条件(@9.5.3) 。
4781+
4782+@9.9.6 数值:
47344783 NPLA1 不要求支持数值计算。数值类型和相关的操作由派生类型提供。
4735-和 Kernel 不同,NPL 不提供依赖数值的接口(用于描述列表长度等);核心库函数(@10.6.2) 的实现也不需要依赖数值。
4736-
4737-@9.7 常规函数约定:
4738-本节适用参考实现环境(@10) 、NPLA1 参考实现扩展环境(@11) 和 SHBuild 实现环境(@12) 以函数(@4.5.2) 形式提供的操作。
4739-这些环境以指定名称的变量的形式提供若干操作,求值为可参与函数合并(@4.5.3) 的一等实体(但函数合并不一定保证是合式的(@2.5.1) 可求值的表达式)。
4740-一般实现建议参照本节约定。
4741-引用值的基本使用规则参见 @9.6.1 。
4742-引入函数时需避免 @9.4.8.3 的问题以维护内存安全;另见 @7.7.3 。
4743-除非另行指定,函数作为表达式,求值为合并子(@4.5.3) ,其函数合并的求值蕴含函数调用(@4.5.3.1) 。
4744-除非另行指定,本文档约定的函数在其调用不依赖用户程序(@10) 提供的非终止函数时,总是终止函数(@4.7.2) 。
4745-注意无条件遍历访问循环引用子对象(@9.6.1.1) 的程序具有未定义行为,在此已被排除。
4746-若满足上述条件的函数不具有错误条件(@9.4.3.3) ,忽略因实现环境引发的错误(如宿主资源耗尽),视为(对象语言中的)全函数。
4747-
4748-@9.7.1 函数值(@4.5.2) 约定:
4749-除非另行指定,函数值不是引用值(@5.5.4) ,以便通过保证满足间接值生存期规则(@5.7.4) 维护内存安全(@5.2.4.3) 。
4750-除非另行指定,函数值是经过返回值转换(@5.7.4.4) 的值,不保留引用值(@9.6.1.5) 。注意保留引用值时,函数值仍可能是非引用值。
4751-除非另行指定,若函数值保留引用值,引用值被折叠。关于引用值是否被折叠的操作分类,详见 @9.9.1 。
4752-
4753-@9.7.2 实际参数约定:
4754-除非另行指定,函数的实际参数的传递(@4.4.4.5) 不具有影响可观察行为(@4.1.3) 的作用。(这一般要求避免复制宿主语言中的对象。)
4755-除非另行指定,函数的实际参数若被求值,则隐含左值到右值转换(@9.6.1.3) 。
4756-
4757-@9.7.3 错误处理:
4758-除非另行指定,若函数合并(@4.5.3) 指定的操作的约束(@9.2) 或要求检查(@9.4.3.4) 的条件不被满足,引起错误(@9.4.3.1) 。
4759-除非另行指定,引起错误抛出异常(@9.4.3.2) 。
4760-求值时引起的错误使求值中断可产生副作用,这样的副作用总是后序(@4.4.1) 于已被求值的表达式中产生的副作用。
4761-
4762-@9.7.4 非常规函数:
4763-不符合常规函数约定的例外的一个例子是续延(@4.5.2.1) 。
4764-类似 [RnRK] ,作为一等对象的续延和控制参数是否求值无关,因此不是合并子,且默认求值算法(@9.4.1) 不支持续延作为函数合并被求值;但续延可通过特定的操作转换为应用子。
4765-(当前未提供作为一等续延的正式支持;续延仅在非一等对象的情形(@4.5.3.3) 调用。)
4766-
4767-@9.8 函数参数和函数值传递(@4.4.4.5) 约定:
4768-函数可能接受引用值参数和返回引用值,是对函数的形式参数或函数值的初始化(@5.5.2) 。
4769-在复制初始化形式参数和函数值时,部分函数保证被初始化的值和初值符(@5.5.2) 的值类别(@5.5.1) 和可修改性一致。这些初始化是转发(@5.5.2.2) 操作。
4770-
4771-@9.8.1 传递非引用值参数:
4772-一些函数的参数进行左值到右值转换(@5.5.5) ,实现参数的按值传递(@4.4.4.5) 。
4773-这类似宿主语言中直接使用对象类型的形式参数。
4774-
4775-@9.8.2 函数参数转发:
4776-一些函数的部分参数也可不进行左值到右值转换(@5.5.5) 。
4777-这些参数的转发类似绑定构造支持的参数转发(@9.5.2.2) 。
4778-参数转发的实现可判断值类别(@9.5.2) 后分别对传递非引用值(@9.8.1) 或直接传递引用值提供实现,或直接使用绑定构造。前者支持本机实现。
4779-
4780-@9.8.3 返回非引用值:
4781-返回非引用值和参数的按值传递(@4.4.4.5) 类似,若初值符是引用,复制或转移被引用的对象的值而不是引用值。
4782-这类似宿主语言中返回 auto 类型。
4783-假定参数进过至多一次折叠(@9.9.1) ,其它操作保证总是返回非引用值。
4784-
4785-@9.8.4 函数值转发:
4786-一些其它保留引用值的操作中的引用值来自参数,且难以通过操作自身的逻辑决定可否安全地直接返回引用值,因此在返回之前根据决定返回值的参数是否为引用值,可选地转换结果以确定是否保留引用值,即进行转发。
4787-显式转发临时对象的引用值使临时对象被转移,以转发的值作为返回值,可不同于使用返回值转换(@5.7.4.4) :
4788-同返回值转换,转发转移右值,复制左值;但当转发临时对象可确定唯一使用时,也转移临时对象(实现参见 @5.6.3.4 )。
4789-确定是否保留引用值的机制类似 ISO C++14 中从没有括号的 id-expression 上推断返回 decltype(auto) 类型是否为引用类型。
4790-函数值转发使某些操作在默认情况下满足间接值生存期规则而保持内存安全,符合适用性原则(@1.4.5.2) 。
4791-函数值转发的实现可通过判断是否需要转发引用而按需决定返回引用值(@9.6.1.4) 或返回非引用值(@9.8.3) ,或使用 @10.4.2.4 的方式。前者支持本机实现。
4792-
4793-@9.8.5 创建和访问对象的函数:
4794-构造器(constructor) 是用于创建对象的函数,返回非引用值(@9.8.3) 。
4795-部分操作涉及对其它对象具有所有权的对象。
4796-一部分对象的构造器(@9.8.3) 创建的对象完全通过其它对象的引用或对象的值作为构造器的参数而决定,且创建的对象对这些参数具有所有权,这样的对象称为容器(container) 。
4797-容器构造器的参数作为容器的子对象(@9.6) ,是容器的元素(element) 。
4798-一些不是容器的对象(如真合并子(@9.6.4) )可通过非容器形式的构造器创建。
4799-以容器对象或其引用作为参数,取得容器元素对象或其引用的函数是容器元素访问器(accessor) 。
4800-
4801-@9.9 函数名称约定:
4802-除非另行指定,以指定名称的函数表示的操作时,其命名由本节的规则约定。
4803-修改(@9.4.5.1) 一个对象而不要求第一参数是引用值且不改变被赋值对象类型的赋值操作(@9.4.5.1.1) 以 <- 结尾。这通常和宿主语言的赋值操作对应,可能有附加的副作用而不是简单地替换值。
4804-类似 Kernel ,谓词的名称使用 ? 结尾,除 <- 结尾外的用于(不直接通过求值操作数或其子表达式产生的副作用的)修改(@9.4.5.1) 的(同时是改变操作(@4.1.4.2) )函数的名称使用 ! 结尾。
4805-和 Kernel 类似,管理状态(@9.4.5.1) 的变化不需要指示可修改;此外,类似地,不改变可观察行为(@4.1.3) 的隐藏状态的修改不属于上述可修改。
4806-和 Kernel 不同,不使用以上可修改的操作仍可引起对象修改,如隐式的转移操作(@9.4.5.1.2) 。
4807-和使用可用谓词 inert? 判断的惰性(inert) 值的 Kernel 不同,后者的结果是未指定值(@7.2.2) 。
4808-未指定值的类型未指定,因此用于修改的函数可能返回 A1::ValueToken::Unspecified(@7.2.2) 外的其它值;但应满足 @10.2 。
4809-作为一等实体的未指定值和 Kernel 类似,仍为 #inert(@9.3.1) ,但不提供谓词判断其类型。
4810-除去以上后缀,以引用标记字符(@7.7.3.4) 结尾的表示涉及引用的操作。
4811-一些操作以结尾引用标记字符和不以引用标记字符结尾的名称提供多个版本。其中不含结尾的引用标记字符的表示操作的结果不是引用值,要求按值传递(@8.4.5.4) 。
4812-其它一些操作可能只提供以 % 结尾的版本。
4813-不使用引用标记字符的函数及其函数值时,不因引入引用值违反内存安全。这允许通过避免公开带有引用标记字符后缀的操作提供一个内存安全的子集,以在派生实现对语言进行裁剪。
4814-具体规则详见以下描述。
4815-
4816-@9.9.1 可提供以引用标记字符结尾版本的操作:
4817-为满足适用性(@1.4.5.2) ,同时考虑维护内存安全、避免误用和允许使用引用避免复制,这些操作需显式使用以 % 或 & 结尾的函数名称以得到特别关注。
4818-对以求值 <body> 作为尾上下文(@4.4.7) 的操作(@9.4.8.1),以 % 结尾表示 <body> 所在的函数返回时不要求返回非引用值(@9.6.1.4) ,尽管这些操作不返回引用值。
4819-对其它提供不同引用标记字符的多个版本的操作:
4820-以 % 结尾表示函数可使用不进行左值到右值转换(@5.5.5) 的折叠(@5.6.3.2) 的引用值参数,或可返回折叠的引用值;
4821-以 & 结尾表示函数使用不进行左值到右值转换的折叠的引用值参数,或返回折叠的引用值;
4822-以 @ 结尾表示函数使用不进行左值到右值转换的未折叠的引用值参数,或返回未折叠的引用值。
4823-以上函数调用结果中的折叠的引用值对调用时引入的引用值有效。
4824-除非另行指定,不要求函数折叠(调用前的)参数中包含的引用值,依赖这些参数的函数结果仍可因此包含未折叠的引用值。这允许函数的内部实现引入一次引用值时,对来自每个参数的引用值至多只需要实现一次折叠。
4825-推论:若参数都不是未折叠的引用值,调用不以 @ 结尾的函数不引入未折叠的引用值。
4826-引用标记字符可弱化内存安全保证,参见 @8.4.5.4 和 @9.4.2 。
4827-若指定的操作按不同操作数可涉及或不涉及和当前不同环境下的求值,提供不保留引用值和保留引用值的多种版本的操作以便保证内存安全,包括 @10.4.1 和 @10.4.2 指定的操作。
4828-可提供不同版本的操作被严格限制,以避免过度区分造成在使用上不必要的复杂性。
4829-
4830-@9.9.2 不提供结尾引用标记字符对应名称的操作:
4831-若指定的函数值直接来自操作数或其子对象(@9.6)(和以 % 结尾操作的情形类似),可返回和参数对应的引用值,满足:
4832-函数的名称不含 % 或 & 结尾;
4833-不提供避免涉及引用的对应操作,或仅在此基础上提供总是包含等价返回值转换(@9.6.1.4) 的对应操作。
4834-否则,不提供结尾引用标记字符对应名称的函数不返回引用值。
4835-这些操作不会使用临时对象作为环境,所以不需要使用以引用标记字符结尾的版本要求注意区分返回引用值而避免误用。
4836-因此,不提供区分涉及引用的版本,这也使接口设计更清晰。
4837-这些操作包括 @9.9.3 的情形,并在 @10.4.2 明确指出。
4838-其它不提供结尾引用标记字符对应名称的操作暂不保证支持保留引用值。
4784+和 Kernel 不同,NPL 不提供依赖数值的接口(用于描述列表长度等);核心库函数(@11.4.2) 的实现也不需要依赖数值。
48394785
48404786 @9.10 实现注记:
48414787 NPLA1 中提供的一些名称以及实现架构和 klisp 相似,且都为 AST 解释器,但实现方式略不同。
48424788 作为比较实现的备注,以下是 klisp 中(除当前不支持的 [RnRK] 特性外)相较 NPLA1 的一些主要实现差异:
4843-使用跟踪 GC ,被 GC 管理的对象都支持跟踪回收,不特别处理 TCO(另见 @7.11.5 );
4789+使用跟踪 GC ,被 GC 管理的对象都支持跟踪回收,不特别处理 TCO(另见 TCO 实现(@7.11.5) );
48444790 使用紧凑的(类似 lua )的对象布局,依赖体系结构的数据模型假设(只实现了 32 位);
48454791 使用 C 函数且支持 FFI ;
48464792 使用 setjmp/longjmp 恢复跳板中的上下文;
@@ -4853,349 +4799,615 @@
48534799 特定上下文的 PTC 失败(@7.11.5) 。
48544800
48554801 @10 NPLA1 参考实现环境:
4856-NPLA1 提供参考实现环境,其实现可在内部使用 NPLA1 库特性(@9) ,提供给 NPLA1 用户程序(@9.1) 。
4857-NPLA1 参考实现环境和用户程序遵循部分不同的要求和约定,如 @10.2 。
4858-在参考实现环境中,NPLA1 以环境对象中的绑定作为公开的接口提供库特性。
4802+NPLA1 提供参考实现环境。其实现可在内部使用 NPLA1 库特性(@9.1) ,提供给 NPLA1 用户程序(@9.1) 。
4803+NPLA1 参考实现环境和用户程序遵循部分不同的要求和约定:实体实现的限制(@10.9) 。
4804+本章中的其它约定适用 NPLA1 参考实现环境,且可选地被用户程序使用。
4805+以下各章的实现中的 C++ 名称和项目模块命名空间的使用同 @7 。
4806+
4807+@10.1 求值环境(@4.6.1.1) :
4808+NPLA1 以环境对象中的绑定作为公开的接口提供库特性。
48594809 这些环境对象设计为在参考实现环境提供,因为:
48604810 不都保证能在用户程序中可移植地创建,而有必要在参考实现环境中提供;
48614811 提供的库特性在可移植程序中可能经常出现,而适合在参考实现环境中提供。
48624812 这些环境对象包含两类:
4863-自身是核心语言特性,而不是公开为库特性可访问的一等环境;
4864-自身是作为库特性的一等环境对象(通常是其它环境的子对象)。
4865-作为核心语言特性时,这些环境对象可以不是一等环境(@9.6.2) ,但应能和一等环境在名称解析(@5.4.3) 中的作用一致:作为父环境(@5.4.3) 。
4813+自身是核心语言特性(@9.1) ,而不是公开为库特性可访问的一等环境;
4814+自身是作为库特性(@9.1) 的一等环境对象(通常是其它环境的子对象)。
4815+作为核心语言特性时,这些环境对象可以不是一等环境(@9.9.3) ,但应能和一等环境在名称解析(@5.4.3) 中的作用一致:作为父环境(@5.4.3) 。
48664816 NPLA1 实现提供的这种由实现初始化的作为核心语言特性的环境对象称为根环境(root environment) 。
48674817 和 Kernel 类似,NPLA1 实现提供基础环境(ground environment) 。
48684818 基础环境应包含语言规范要求提供的所有绑定,且不包含名称除保留名称(@5.11.1.1) 外的绑定。
4869-基础环境是隐藏环境(@9.6.2.2) ,不被直接访问。
4870-除非另行指定,根环境和作为库特性的一等环境对象初始化后被冻结(@9.6.2.4) 。
4819+基础环境是隐藏环境(@9.9.3.1) ,不被直接访问。
4820+除非另行指定,根环境和作为库特性的一等环境对象初始化后被冻结(@9.9.3.7) 。
48714821 用户程序初始的当前环境(@5.4.4) 是一个包含基础环境作为直接或间接父环境的空环境(@4.6.1.1) 。
4872-实现可选地提供基础环境以外的根环境,允许派生实现定义在用户程序中修改其中的绑定的机制(而不一定是隐藏环境),直至被实现初始化参考环境的特定用户程序封装或冻结( @9.6.2.4 )而避免进一步修改。
4822+实现可选地提供基础环境以外的根环境,允许派生实现定义在用户程序中修改其中的绑定的机制(而不一定是隐藏环境),直至被实现初始化参考环境的特定用户程序封装或冻结而避免进一步修改。
48734823 如有必要,用户程序可通过派生实现定义的方式引入其它根环境。这些方式一般依赖本机实现。
4874-以下实现中的 C++ 名称和项目模块命名空间的使用同 @7 。
4875-通过 Forms::LoadGroundContext(@8.5.2) 初始化基础上下文(@8.5.2) 蕴含的根环境是求值(@9.4) 默认使用的求值环境(@4.6.1.1),初始化后可直接封装为基础环境使用。
4824+
4825+@10.1.1 初始化:
4826+通过 Forms::LoadGroundContext(@8.5.2) 初始化基础上下文(@8.5.2) 蕴含的根环境是求值(@9.7.1) 默认使用的求值环境(@4.6.1.1),初始化后可直接封装为基础环境使用。
48764827 以上初始化同时提供扩展字面量(@9.3.1) 支持。
48774828
4878-@10.1 接口约定:
4879-按实体区分,NPLA1 绑定提供的库特性有两类:对象和操作(operation) 。
4880-NPLA1 参考实现环境以符合常规函数约定(@9.7) 的方式指定具有明确名称的函数为应被支持的操作,作为用户可使用的可编程特性的基础之一(另见 @10.3 )。
4881-这表示可实现的操作可以是本机实现(@5.2.1) 的宿主语言函数或由现有操作派生的合并子(@9.6.4) 。
4882-除此之外,派生实现可指定对操作提供对应的非常规函数(@9.7.4) 。
4883-这些操作中的大部分具有特定的名称。这些名称符合 @9.9 的约定;其分类详见 @10.4 。
4884-其它操作不具有特定名称,可由上述操作间接地提供,如蕴含在某些操作涉及的函数值(@4.5.3) 中。
4885-
4886-@10.1.1 模块:
4829+@10.1.2 特性设计注记:
4830+为避免依赖逻辑上复杂的形式,一些特性当前在当前设计中排除。例如,依赖一阶算术的操作、其硬件加速形式的 ISA 表示的整数操作及依赖这些操作实现的数值塔(numerical tower) 被整体忽略。
4831+上述忽略的特性可由派生实现补充(如以类似 @11.4 的形式),在派生根环境后按需进行 AOT(ahead-of-time) 优化(如 Kernel 的 $let-safe! 中包含的内容,其中引用基础环境的符号不再可变),然后组成类似基础环境。
4832+
4833+@10.2 模块:
48874834 同 [RnRK] ,以绑定提供的语言特性被分组归类为模块(@1.4.6.4) 。
48884835 模块的源(source) 提供特性的实现,可以是本机实现或者 NPLA1 程序。
48894836 模块的源可以是实现内建的,或位于实现环境提供的外部资源(如文件系统)。
48904837 因为模块以绑定的集合的形式提供,需被包含在可访问的环境,或包含环境作为子对象的其它对象中。
48914838 从模块的源得到提供一个模块的所有绑定集合的环境对象的过程称为模块的加载(loading) 。
4892-模块加载可能失败。失败的模块加载引起错误(@9.4.3.1) 。
4839+模块加载可能失败。失败的模块加载引起错误(@9.5.1) 。
48934840 根环境加载的失败不被直接依赖这些环境的 NPLA1 用户程序处理(而视为实现初始化的运行时错误)。
48944841 一般地,模块和加载模块得到的环境对象没有直接对应关系:一个模块的绑定可以由一个或多个环境提供,一个已被加载的环境可能提供零个或多个程序可见的模块。但除非另行指定,一个模块的绑定不在超过一个的不相交的环境(之间没有直接或间接父环境关系)中提供。
48954842 程序可通过加载外部模块来源取得模块。除非另行指定,这种模块以一个一等环境对象(可包含作为环境的直接或间接子对象)中的绑定提供。
4896-同 [RnRK] 的 get-module 的约定,提供模块绑定的环境依赖已知来源的绑定而确保稳定(@9.6.2) 。
4897-
4898-@10.1.2 特性分类:
4899-同 @8.1 ,特性分为基本的和派生的。前者在设计上不分解为更小的其它特性的组合,通常需要本机实现;后者可由可移植的 NPLA1 源代码实现。
4843+
4844+@10.2.1 模块稳定性:
4845+同 [RnRK] 的 get-module 的约定,提供模块绑定的环境依赖已知来源的绑定而确保稳定(@9.9.3) 。
4846+对标准库模块,这一般表示其中的特性不能依赖用户程序运行时的非特定的当前环境,而可依赖从基础环境(@10.1) 及从基础环境派生的新环境(@9.9.3) 。
4847+除非另行指定,模块中的特性依赖提供模块绑定的环境的生存期。例如,其中的合并子(@9.9.5) 可具有静态环境是上述环境的子对象的合并子的实现。
4848+除非另行指定,标准库实现应确保其中的模块在程序的生存期中可用。这一般要求标准库实现在初始化后保存环境强引用(@5.4.3) 。
4849+用户程序应自行保证加载的其它模块具有足够的生存期,以避免访问悬空引用(@9.4.3.2) 导致的未定义行为,特别是使用在环境中保留引用值的操作(@10.8.4) 的情形。
4850+另见可能破坏环境稳定性的操作(@10.8.6) 。
4851+
4852+@10.3 库接口约定:
4853+基础环境的特性在根环境(@10.1) 中提供,统称根环境特性,详见 @11 。
4854+关于特性的约束作用于接口描述。不改变可观察行为(@4.1.3) 时,实现可使用不同的求值(如使用不同于基础环境的根环境)。
4855+
4856+@10.3.1 库接口实体:
4857+按实体区分,NPLA1 的库特性有两类:对象和操作(@4.4.3.1) 。
4858+可实现的操作以函数(@4.5.2) 形式提供,可以是本机实现(@5.2.1) 的宿主语言函数或由现有操作派生的合并子(@9.9.5) 。
4859+除此之外,派生实现可指定对操作提供对应的非常规函数(@10.6.5) 。
4860+本章其余各节适用 NPLA1 对象语言中的这些操作。
4861+这些操作中的大部分具有特定的名称。这些名称符合 @10.7 的约定;其分类详见 @11.2 。
4862+其它操作不具有特定名称,可由上述操作间接地提供,如蕴含在某些操作涉及的函数值(@4.5.3) 中。
4863+
4864+@10.3.2 库特性实现分类:
4865+库特性分为基本的和派生的(同 NPLA1 实现的支持(@8.1) )。
4866+前者在设计上不分解为更小的其它特性的组合,通常需要本机实现;后者可由可移植的 NPLA1 源代码实现。
49004867 实现加载本文档要求的模块的本机 API 入口参见 @8.5 。
49014868 区分基本和派生的特性在设计上类似 [RnRK] 中的基本和库特性。
49024869 注意和 [RnRK] 的库特性不同(而更接近宿主语言),NPLA1 的库特性是以 NPLA1 程序使用的接口而非实现的角度定义的,不总是使用对象语言实现,外延更广。
4903-本文档中要求的通过基础环境直接或间接提供的库(@9.1) 总称标准库(standard library) 。
4904-标准库的接口随语言规范在参考实现环境(@10) 和参考实现扩展环境(@11) 约定。
4870+
4871+@10.3.3 标准库(standard library) :
4872+本文档中要求的通过基础环境(@10.1) 直接或间接提供的库(@9.1) 总称标准库。
4873+标准库的接口随语言规范在参考实现环境(@10) 和参考实现扩展环境(@12) 约定。
49054874 核心库(core library) 是提供直接绑定在基础环境中的、保证可派生实现的接口的标准库模块。
49064875 在参考实现环境中的不同标准库模块的绑定都可在基础环境访问;
49074876 在参考实现扩展环境中的标准库模块以其它环境(通常作为基础环境的子对象提供)中的绑定和基础环境隔离。
49084877 派生实现可以库的形式提供语言扩展或其它功能特性,扩充标准库。
4909-基础环境也可提供其它当前实现附带的其它接口,如 @12 。
4878+
4879+@10.3.4 扩展库:
4880+基础环境也可提供的附带的其它接口,如 SHBuild 实现环境(@13) ,和标准库使用相同的约束。
49104881 一些操作的描述使用等价的表达式求值指定。除非另行指定,这些表达式中:
49114882 若符号和先前出现的函数同名,则指称对应的操作;
49124883 默认使用基础环境作为求值环境。
4913-注意这些约束作用于接口描述。不改变可观察行为(@4.1.3) 时,实现可使用不同的求值(如使用不同于基础环境的根环境)。
4914-本章中的接口在根环境中提供,统称根环境接口。
4915-@10.5 提供在基础上下文(@8.5.2) 初始化的根环境基本(primitive) 接口,作为单独的模块。
4916-@10.6 起的各节提供其余要求 NPLA1 实现直接支持的各个模块的操作。
4917-
4918-@10.1.3 限制:
4919-为避免依赖逻辑上复杂的形式,一些操作当前被核心功能排除。例如,依赖一阶算术的操作、其硬件加速形式的 ISA 表示的整数操作及依赖这些操作实现的数值塔(numerical tower) 被整体忽略。
4920-上述忽略的操作可由派生实现补充(如以类似 @10.6 的形式),在派生根环境后按需进行 AOT(ahead-of-time) 优化(如 Kernel 的 $let-safe! 中包含的内容,其中引用基础环境的符号不再可变),然后组成类似基础环境。
4921-派生实现不依赖非真合并子(@9.6.4) ,因此其中不使用分隔符(@9.4) ,也不需要实现在初始化时支持中缀变换(@7.5.2) 。
4922-
4923-@10.1.4 不安全(unsafe) 操作:
4924-除非另行指定,以下操作是不安全操作:
4925-以下不具有内存安全保证(@9.4.2) 的操作:
4926- 使用 @9.9 约定命名的带有后缀的操作;
4927- 保留参数的引用值的操作;
4928- 引入其它间接值的操作;
4929-引入引用现有环境(@9.6.2) 的 shared_ptr<Environment> 宿主值而可能通过循环引用等引起未定义行为(@9.6.1.1) 的操作;
4930-引入共享持有者的值数据成员(@5.4.2) 而可能通过循环引用等引起未定义行为操作。
4931-第一类不安全操作和引用值的使用(特别是保留引用值(@9.6.1.5) )相关,具体规则参见 @10.1.4.1 、@10.4.1 和 @10.4.2 。
4932-其中,可引起扩展 NPLA 未定义行为(@9.4) 的操作包括以下可能破坏环境稳定性(@9.6.2) 的第一类不安全操作(@10.1.4.1) :
4933-赋值操作(@10.4.1.3) ;
4934-move!(@10.5.4) 。
4935-第二类不安全操作可能通过非引用的操作引入循环引用破坏环境的资源所有权,其中的基本操作在 @10.5.6 提供,对应的函数名如下:
4936-copy-environment
4937-lock-environment
4938-第二类不安全操作中的派生操作在 @10.6.1 提供,对应的函数名如下:
4939-lock-current-environment
4940-第三类不安全操作支持强递归绑定(@9.5.2.1) ,对应的函数名如下:
4941-$defrec!(@10.5.6)
4942-$setrec!(@10.6.1)
4943-不安全操作中,在参数以外直接引入间接值的操作有:
4944-ref&(@10.5.4) ;
4945-第三类不安全操作的强递归绑定过程中引用共享对象(参见 $defrec!(@10.5.6) )的中间值。
4946-NPLA1 参考实现环境中,仅有第三类不安全操作的实现内部可能引入引用持有者;参见 @9.4.2 。
4947-
4948-@10.1.4.1 第一类不安全操作的子类:
4949-第一类不安全操作按被保留的引用值的来源分为以下两个子类:
4950-直接保留引用值操作:接受引用值参数并直接保留引用值;
4951-间接保留引用值操作:可涉及不同的环境,参数在这些环境中被求值得到引用值。
4952-间接保留引用值操作可包含部分直接转发引用值(@9.8) 的操作。整个操作不因此被视为直接保留引用值操作,即便部分引用通过直接转发引用值被保留。这保证以上两个子类不相交。
4953-直接保留引用值操作覆盖常规函数约定的实际参数约定(@9.7.2) ,指定参数不隐含左值到右值转换,可按引用值直接访问。
4954-直接保留引用值操作可配合 idv(@10.6.1) 指定个别参数不保留引用值。
4955-第一类不安全操作的子类和对应不带有引用标记字符的操作的两个并集之间不相交,类似具有分类:
4956-可能直接保留引用值的操作:结果(@4.1) 和副作用由实际参数(需要时经过隐含的左值到右值转换)的值确定;
4957-可能间接保留引用值的操作:可涉及不同的环境,结果和副作用由实际参数(需要时经过隐含的左值到右值转换)在这些环境中被求值后确定。
4958-通过引用进行的修改(@9.4.5.1) 操作可因破坏环境稳定性(@9.6.2) 而引起未定义行为(不一定违反内存安全)。
4959-
4960-@10.1.4.2 安全性附加证明:
4961-一些不安全操作是否蕴含未定义行为可能依赖具体调用使用的操作数。
4962-若能证明特定的前提保证任意的调用实例中的操作数满足附加的安全假设,则这些不安全操作的调用仍可保证安全。
4963-NPLA1 附加调用安全包括少量的第一类不安全操作的调用。派生实现可定义其它调用提供更强的保证。
4964-若不存在隐藏环境中(@9.6.2) 绑定的可修改对象的引用,则仅因可能违反值稳定性(@9.6.2.3) 的不安全操作的调用是安全的。
4965-当前,这种操作包括 assign!(@10.6.1) ;隐藏环境排除可修改对象的引用通过冻结(@9.6.2.4) 环境保证而提供静态的证明。
4966-
4967-@10.2 实体实现(@2.3.1.2) 约定:
4884+
4885+@10.4 函数的间接值使用:
4886+间接值使用和安全性相关(@9.4.2) 。
4887+引用值的基本使用规则参见 @9.9.1 。
4888+引入函数时需注意避免未绑定对象(@9.7.4.3) 等关于环境生存期的问题,以维护内存安全(@9.4) ;另见绑定操作(@7.7.3) 。
4889+
4890+@10.4.1 引用值作为实际参数:
4891+除非另行指定(如 @10.5.2 和 @11.2.2 ),一般地,函数接受左值引用操作数,使用引用的对象的值和直接使用右值作用相同,但不会修改被左值引用的对象。
4892+此处的左值引用和宿主语言中的( const 非 volatile )左值作用类似。
4893+这等价隐含无副作用的左值到右值转换(@5.5.5) 。
4894+注意这不蕴含对子对象的转换。例如,对列表元素是引用值的情形,提升项不是递归的(@6.6.3)(另见参数绑定(@8.4.5.3) 实现中的类似说明)。
4895+另见实际参数约定(@10.6.3) 和函数值转发(@10.5.4) 。
4896+
4897+@10.4.2 返回非引用值:
4898+部分操作总是返回非引用值,以满足具体操作的语义要求(如非引用值的构造器(@10.5.5) ),减少误用的可能性,并帮助提供内存安全保证(@9.4) 。
4899+返回非引用值的行为应等价返回值转换(@5.7.6.4) ,其实现未指定(可使用消除引用值的本机实现(@8.1.2) )。
4900+使用返回值转换可保证引用不逃逸(@7.1.4.2) 。
4901+其它操作可返回引用值。
4902+
4903+@10.4.3 保留引用值:
4904+保留间接值,包括直接保留间接值和间接保留间接值(@9.4.4),适用间接值是引用值的情形,对应地称为保留引用值、直接保留引用值和间接保留引用值。
4905+除非另行指定,保留的引用值被引用折叠(@5.6.3.2) 。
4906+通过要求引用折叠,可保证不引入引用的引用。
4907+函数是否保留引用值以及保留引用值是否被折叠的要求,参见常规函数约定(@10.6) 、函数名称约定(@10.7) 和 NPLA1 参考实现环境(@10) 中的函数名称的约定(@11.2.2) 。
4908+考虑内存安全时,因无法保证如引用值通过关联的环境(@5.6.3.1) 追溯被引用对象类似的机制可用,环境引用(@5.7.3.1) 外的非引用值间接值(@5.7.6.2) 视为不具有内存安全保证(@9.4.3) 。
4909+间接保留引用值可包含部分直接转发引用值(@10.5) 的情形。包含这种情形的操作不因此被视为直接保留引用值,即便部分引用通过直接转发引用值被保留。这保证以上两个子类不相交。
4910+直接保留引用值覆盖常规函数约定的实际参数约定(@10.6.3) ,指定参数不隐含左值到右值转换,可按引用值直接访问。
4911+
4912+@10.4.4 保留环境引用:
4913+保留间接值(@9.4.4) 适用环境引用。
4914+和保留引用值(@10.4.3) 的情形不同,因为只允许通过环境引用在对象语言中访问环境对象及其子对象(@9.4.2) ,访问环境但不保留环境引用的操作只可能在(不保证内存安全的)互操作(@9.4.1) 中出现。
4915+
4916+@10.5 函数参数和函数值传递(@4.4.4.5) 约定:
4917+函数可能接受引用值参数和返回引用值,是对函数的形式参数或函数值的初始化(@5.5.2) 。
4918+在复制初始化形式参数和函数值时,部分函数保证被初始化的值和初值符(@5.5.2) 的值类别(@5.5.1) 和可修改性一致。这些初始化是转发(@5.5.2.2) 操作。
4919+
4920+@10.5.1 传递非引用值参数:
4921+一些函数的参数进行左值到右值转换(@5.5.5) ,实现参数的按值传递(@4.4.4.5) 。
4922+这类似宿主语言中直接使用对象类型的形式参数。
4923+
4924+@10.5.2 函数参数转发:
4925+一些函数的部分参数也可不进行左值到右值转换(@5.5.5) 。
4926+这些参数的转发类似绑定构造支持的参数转发(@9.7.3.2) 。
4927+参数转发的实现可判断值类别(@9.7.3) 后分别对传递非引用值(@10.5.1) 或直接传递引用值提供实现,或直接使用绑定构造。前者支持本机实现。
4928+
4929+@10.5.3 返回非引用值:
4930+返回非引用值和参数的按值传递(@4.4.4.5) 类似,若初值符是引用,复制或转移被引用的对象的值而不是引用值。
4931+这类似宿主语言中返回 auto 类型。
4932+假定参数进过至多一次折叠(@10.7.2) ,其它操作保证总是返回非引用值。
4933+
4934+@10.5.4 函数值转发:
4935+一些其它保留引用值的操作中,引用值来自参数,且难以通过自身的逻辑单独决定可否安全地直接返回引用值。
4936+此时,在返回之前根据特定参数是否为引用值,可选地转换结果以确定是否保留引用值,即进行转发。
4937+显式转发临时对象(@5.2.4.2) 的引用值(@5.5.4) 使临时对象被转移,以转发的值作为返回值,可不同于使用返回值转换(@5.7.6.4) :
4938+同返回值转换,转发转移右值,复制左值;但当转发临时对象可确定唯一使用时,也转移临时对象(实现参见 @5.6.3.4 )。
4939+确定是否保留引用值的机制类似 ISO C++14 中从没有括号的 id-expression 上推断返回 decltype(auto) 类型是否为引用类型。
4940+函数值转发使某些操作在默认情况下满足间接值生存期规则而保持内存安全,符合适用性原则(@1.4.5.2) 。
4941+函数值转发的实现可通过判断是否需要转发引用而按需决定返回引用值(@10.4.2) 或返回非引用值(@10.5.3) ,或使用标准库的相关函数(@11.2.2.4) 。前者支持本机实现。
4942+
4943+@10.5.5 创建和访问对象的函数:
4944+构造器(constructor) 是用于创建对象的函数。
4945+除非显式指定创建的对象具有引用值类型,构造器是典型的(typical) ,返回非引用值(@10.5.3) 。
4946+部分操作涉及对其它对象具有所有权的对象。
4947+一部分对象的构造器(@10.5.3) 创建的对象完全通过其它对象的引用或对象的值作为构造器的参数而决定,且创建的对象对这些参数具有所有权,这样的对象称为容器(container) 。
4948+容器构造器的参数作为容器的子对象(@9.8.2) ,是容器的元素(element) 。
4949+一些不是容器的对象(如真合并子(@9.9.5) )可通过非容器形式的构造器创建。
4950+以容器对象或其引用作为参数,取得容器元素对象或其引用的函数是容器元素访问器(accessor) 。
4951+
4952+@10.5.6 转发参数或返回值的实现:
4953+可转发参数或返回值(@10.5) 的函数可包含以下实现方式:
4954+使用特定的操作,以需被转发的表达式作为其操作数;
4955+(仅对参数转发)使用标记字符 % 的参数绑定(@7.7.3.4) 的变量。
4956+上述特定的操作可在被求值的表达式中构造显式的转发。
4957+没有约定需要转发的情形不使用显式的转发。
4958+特别地,被转发的函数值若需支持 PTC(@9.7.4.1) ,则不能作为操作使用的实际参数,以避免不满足在尾上下文(@4.4.7) 求值的条件。
4959+
4960+@10.6 常规函数约定:
4961+本节提供作为库特性的函数(@10.3.1) 的默认规则以简化库特性的描述;另见函数实现使用约定(@10.9.1) 。
4962+库的一般派生实现和用户程序的实现也建议参照本节约定。
4963+除非另行指定,操作以指定名称的变量的形式提供,求值为可参与函数合并(@4.5.3) 的一等实体(但函数合并不一定保证是合式的(@2.5.1) 可求值的表达式)。
4964+除非另行指定,函数作为表达式,求值为合并子(@4.5.3) ,其函数合并的求值蕴含函数调用(@4.5.3.1) 。
4965+除非另行指定,本文档约定的函数在其调用不依赖用户程序提供的非终止函数时,总是终止函数(@4.7.2) 。
4966+注意无条件遍历访问循环引用子对象(@9.9.1.1) 的程序具有未定义行为,在此已被排除。
4967+若满足上述条件的函数不具有错误条件(@9.5.3) ,忽略因实现环境引发的错误(如宿主资源耗尽),视为(对象语言中的)全函数。
4968+
4969+@10.6.2 函数值(@4.5.2) 约定:
4970+除非另行指定,函数值不是引用值(@5.5.4) ,以便通过保证满足间接值生存期规则(@5.7.6) 维护内存安全(@5.2.4.3) 。
4971+除非另行指定,函数不在返回值中保留引用值(@10.4.3) ,即函数值经过返回值转换(@10.4.2) 。注意保留引用值时,函数值仍可能是非引用值。
4972+除非另行指定,若函数值保留引用值,引用值被折叠。关于引用值是否被折叠的操作分类,详见 @10.7.2 。
4973+
4974+@10.6.3 实际参数约定:
4975+除非另行指定,函数的实际参数的传递(@4.4.4.5) 不具有影响可观察行为(@4.1.3) 的作用。(这一般要求避免复制宿主语言中的对象。)
4976+除非另行指定,函数的实际参数若被求值,隐含左值到右值转换(@10.4.1) 。
4977+
4978+@10.6.4 错误处理:
4979+除非另行指定,若函数合并(@4.5.3) 指定的操作的约束(@9.2) 或要求检查(@9.5.4) 的条件不被满足,引起错误(@9.5.1) 。
4980+除非另行指定,引起错误抛出异常(@9.5.2) 。
4981+求值时引起的错误使求值中断可产生副作用,这样的副作用总是后序(@4.4.1) 于已被求值的表达式中产生的副作用。
4982+
4983+@10.6.5 非常规函数:
4984+不符合常规函数约定的例外的一个例子是续延(@4.5.2.1) 。非常规函数归类为对象而非操作(@10.3.1) ,但调用时候错误处理同常规函数(@10.6.4) 。
4985+类似 [RnRK] 而和 [RnRS] 不同,作为一等对象的续延和控制参数是否求值无关,因此不是合并子,且默认求值算法(@9.7.1) 不支持续延作为函数合并被求值;但续延可通过特定的操作转换为应用子。
4986+(当前未提供作为一等续延的正式支持;续延仅在非一等对象的情形(@4.5.3.3) 调用。)
4987+
4988+@10.7 函数名称约定:
4989+除非另行指定,以指定名称的函数表示具有名称的操作时,其命名由本节的规则约定。
4990+修改(@9.8.3) 一个对象而不要求第一参数是引用值且不改变被赋值对象类型的赋值操作(@9.8.3.1) 以 <- 结尾。这通常和宿主语言的赋值操作对应,可能有附加的副作用而不是简单地替换值。
4991+类似 Kernel ,谓词的名称使用 ? 结尾,除 <- 结尾外的用于(不直接通过求值操作数或其子表达式产生的副作用的)修改(@9.8.3) 的(同时是改变操作(@4.1.4.2) )函数的名称使用 ! 结尾。
4992+和 Kernel 类似,管理状态(@9.8.3) 的变化不需要指示可修改;此外,类似地,不改变可观察行为(@4.1.3) 的隐藏状态的修改不属于上述可修改。
4993+和 Kernel 不同,不使用以上可修改的操作仍可引起对象修改,如隐式的转移操作(@9.8.3.2) 。
4994+和使用可用谓词 inert? 判断的惰性(inert) 值的 Kernel 不同,后者的结果是未指定值(@7.2.2) 。
4995+未指定值的类型未指定,因此用于修改的函数可能返回 A1::ValueToken::Unspecified(@7.2.2) 外的其它值;但应满足实现限制(@10.9) 。
4996+作为一等实体的未指定值和 Kernel 类似,仍为 #inert(@9.3.1) ,但不提供谓词判断其类型。
4997+除去以上后缀,以引用标记字符(@7.7.3.4) 结尾的表示涉及引用的操作。
4998+一些操作以结尾引用标记字符和不以引用标记字符结尾的名称提供多个变体。其中不含结尾的引用标记字符的表示操作的结果不是引用值,要求按值传递(@8.4.5.4) 。
4999+其它一些操作可能只提供以 % 结尾的变体。
5000+不使用引用标记字符的函数及其函数值时,不因引入引用值违反内存安全(@9.4) 。这允许通过避免公开带有引用标记字符后缀的操作提供一个内存安全的子集,以在派生实现对语言进行裁剪。
5001+尽管设计时没有参照,使用函数结尾的引用标记字符和其它一些语言的类似特性的使用惯例也一致,如 PHP 的 function & 语法:
5002+https://www.php.net/references.return
5003+具体规则详见以下描述。
5004+
5005+@10.7.1 以引用标记字符结尾的函数名:
5006+为满足适用性(@1.4.5.2) ,同时考虑避免误用和允许使用引用避免复制,对一些操作显式使用以 % 或 & 结尾的函数名称以得到特别关注。
5007+名称以引用标记字符结尾的操作属于以下分类之一:
5008+可能直接保留引用值的操作:结果(@4.4.3.1)及作用(@4.4.3.1) 依赖实际参数(需要时经过隐含的左值到右值转换)的值;
5009+可能间接保留引用值的操作:可涉及不同的环境,结果和作用依赖实际参数(需要时经过隐含的左值到右值转换)在这些环境中被求值后确定。
5010+对可能在返回值中间接保留引用值的操作,以 % 结尾表示所在的函数返回时不要求返回非引用值(@10.4.2) 。
5011+其它可能在返回值中直接保留引用值的提供不同引用标记字符的多个变体的操作:
5012+以 % 结尾表示函数可使用不进行左值到右值转换(@5.5.5) 的折叠(@5.6.3.2) 的引用值参数,或可返回折叠的引用值;
5013+以 & 结尾表示函数使用不进行左值到右值转换的折叠的引用值参数,或返回折叠的引用值;
5014+以 @ 结尾表示函数使用不进行左值到右值转换的未折叠的引用值参数,或返回未折叠的引用值。
5015+
5016+@10.7.1.1 引用折叠:
5017+以上函数调用结果中的折叠的引用值对调用时引入的引用值有效。
5018+除非另行指定,不要求折叠(调用前的)参数中包含的引用值,依赖这些参数的函数结果仍可因此包含未折叠的引用值。
5019+这允许函数的内部实现引入一次引用值时,对来自每个参数的引用值至多只需要实现一次折叠。
5020+推论:若参数都不是未折叠的引用值,调用不以 @ 结尾的函数不引入未折叠的引用值。
5021+若指定的操作按不同操作数可涉及或不涉及和当前不同环境下的求值,提供不保留引用值和保留引用值的多个变体的操作以便保证内存安全,包括 @11.2.1 和 @11.2.2 指定的操作。
5022+
5023+@10.7.1.2 与内存安全的关系:
5024+利用区分引用标记字符结尾的操作,可指定具体关于具体操作的对象语言接口的安全保证机制(@9.4.6) 。
5025+结尾的引用标记字符用于强调无法总是保证内存安全的危险操作(@1.4.5.2) 。
5026+不带有引用标记字符结尾的操作通过避免保留引用值(@10.4.3) 提供一定的内存安全保证,而带有引用标记字符结尾的操作较容易引起注意。
5027+这符合易预测性(@1.4.5.2.1) 。
5028+一个典型例子是在函数中返回标识符求值的表达式:
5029+标识符求值(@9.7.1) 后指称左值引用值(@7.8.2) ,这个引用值的有效性依赖合并子调用时创建的新环境(@9.9.3) 的可被访问;
5030+这个环境在调用后通常被销毁,若使用带有引用标记字符结尾的操作关于返回引用值的语义,在返回值中保留引用值,返回为悬空引用(@9.4.3.2) ,容易误用。
5031+一般地,仅在明确需要引用值时使用引用标记字符结尾的操作,而避免返回悬空引用(这类似宿主语言函数的 auto 而非 auto&& 的返回类型,但宿主语言中返回非引用类型的表达式两者含义不同)。
5032+
5033+@10.7.1.3 保留引用值(@10.4.3) 的约定:
5034+可能直接保留引用值(@10.4.3) 的操作中,不带有引用标记字符的操作转发参数(@10.5.2) 。
5035+可能直接保留引用值的操作包括容器构造器或访问器(@10.5.5) ,以及可能使对象中包含引用值(@9.4.4) 的修改操作(@9.8.3) 。
5036+以上操作是否确定地保留引用值在一些情形容易证明附加调用安全(@9.4.6.1) ,此时可放宽安全子集(@10.8.7) 的条件确保安全性;在此不作要求。
5037+对构造器及部分修改操作区分引用标记字符结尾可强调一些非预期保留引用值的容易误用情形:
5038+尽管总是返回非引用值,转发参数保留的引用值不会被返回值转换(@10.4.2) 或类似的操作影响,在构造的容器对象作为非引用值返回仍会保留引用值。
5039+(对应宿主语言中,可有更显著的差异,如构造器对应的 std::tuple 的 std::make_tuple 和 std::forward_as_tuple 。)
5040+这些操作的结果由实际参数(根据是否存在引用标记字符 % 指定是否不经过隐含的左值到右值转换)的值确定。
5041+其中,带有引用标记字符结尾的操作是直接保留引用值操作。
5042+容器构造器可在元素保留参数的引用值,作为结果的容器总是作为非引用值返回(@10.4.2) 。
5043+
5044+@10.7.2 可提供以引用标记字符结尾变体的操作:
5045+部分操作使用以引用标记字符结尾的函数名(@10.7.1) 。
5046+可提供不同变体的操作被严格限制,以避免过度区分造成在使用上不必要的复杂性。
5047+
5048+@10.7.2.1 可能使结果包含引用值的容器构造器:
5049+容器构造器作为包括典型的构造器,可提供不同的变体(或其中之一):
5050+不在返回值中保留引用值,实际参数发生左值到右值转换作为容器的元素,这减少误用悬空引用(@9.4.3.2) 的可能性;
5051+在返回值中保留引用值,实际参数不发生左值到右值转换而直接作为容器的元素,是不安全操作,但可以确保构造的对象中包含参数指定的引用值。
5052+(当只提供没有结尾引用标记字符对应名称的操作时,不需要满足以下(@10.7.3) 的约定。)
5053+
5054+@10.7.2.2 可能使结果包含引用值的容器元素访问器:
5055+其中,带有引用标记字符结尾的操作是直接保留引用值(@10.4.3) 操作;
5056+函数名不带有标记字符结尾的访问器属于参数转发操作(@10.5.2) 和函数值转发操作(@10.5.4) 。
5057+
5058+@10.7.2.3 可能使对象中包含引用值的修改操作(@9.8.3) :
5059+修改对象或对象的子对象(@9.8.2) 可无效化引用值(@5.6.5) 而影响内存安全。
5060+对可能保留参数中的引用值(@9.4.4) 的操作,内存安全也依赖这些操作的指定修改后的值的内存安全性。
5061+在判定内存安全(@9.4)的意义上,以下操作的所有参数都是被使用的间接值(@9.4.4) :
5062+简单赋值(simple assignment)(包含于赋值操作(@9.8.3.1) );
5063+列表元素改变器(mutator) 。
5064+修改的结果由实际参数(需要时经过隐含的左值到右值转换)的值确定。
5065+以上操作都要求检查表示被修改的参数是左值。
5066+以上操作中,带有引用标记字符结尾的操作在对象中直接保留引用值(@10.4.3) 。
5067+
5068+@10.7.2.4 可能间接保留引用值(@10.4.3) 的操作:
5069+一些操作可涉及不同的环境,参数在这些环境中被求值可能得到引用值。
5070+这些操作包括求值为操作子的以下函数:
5071+以求值 <body> 作为尾上下文(@4.4.7) 的操作(@9.7.4.1) ;
5072+以求值 <expression>(及可能发生的返回值转换(@10.4.2) )作为唯一作用的函数。
5073+以上操作中,带有引用标记字符结尾的操作是间接保留引用值操作,表示求值结果不要求按值传递并可返回引用值。
5074+不提供函数值转发(@10.5.4) 的形式,因为:
5075+选用经过返回值转换(@5.7.6.4) 得到的值已可保证避免求值结果中的悬空引用(@9.4.3.2) ;
5076+直接返回可能是引用值的值具有更简明直观的语义;
5077+若需转发,可直接在被求值的表达式中显式构造(@10.5.6) ;
5078+不需要假设求值结果初值符(@5.5.2) 作为函数值转发依据的参数。
5079+和此处直接在参数中给出被求值表达式不同,应用子中的一些求值的操作不属于上述操作,而不提供结尾引用标记字符对应名称的操作(@10.7.3.5) 。
5080+
5081+@10.7.3 不提供结尾引用标记字符对应名称的操作:
5082+其它操作不使用以引用标记字符结尾的函数名(@10.7.1) 。
5083+若这些操作的结果直接来自操作数或其子对象(@9.8.2)(和以 % 结尾操作的情形类似),则:
5084+ 可保留参数中的引用值(@9.4.4) 并在返回值中保留;
5085+ 不提供避免保留值的对应操作,或仅在此基础上提供总是包含等价返回值转换(@10.4.2) 的对应操作。
5086+否则,这些操作不返回引用值。
5087+这些操作不会使用临时对象(@5.2.4.2) 作为环境,所以不需要使用以引用标记字符结尾的变体要求注意区分返回引用值而避免误用。
5088+因此,不提供区分涉及引用的变体,这也使接口设计更清晰。
5089+这些操作包括以下小节的情形。
5090+部分操作涉及参数转发(@10.5.2) 和函数值转发(@10.5.4) 。这些操作不包含可提供以引用标记字符结尾变体的操作中的个别变体(@10.7.2) 。
5091+另见具体函数分类(@11.2.2) 。
5092+其它不提供结尾引用标记字符对应名称的操作暂不保证支持保留引用值。
5093+部分操作的内存安全性和可提供以引用标记字符结尾变体的操作(@10.7.2) 类似,也是在返回值中保留引用值的不安全操作,但仅在引用值参数被保留且以此访问被引用对象时体现。
5094+这包括直接保留引用值和间接保留引用值(@10.4.3) 的不同情形。
5095+除可直接返回引用值的操作(@10.7.3.1) 和其它节的操作不相交,以下分类对操作的参数和函数值分别约定,可能相交。
5096+
5097+@10.7.3.1 可直接返回引用值的操作:
5098+一些求值为操作子提供的函数选取特定的参数进行求值,作为控制操作。
5099+操作数中被求值的参数直接决定是否为引用部分操作直接返回引用值。
5100+被求值的 <test> 进行左值到右值转换,其它被求值的参数不进行左值到右值转换,调用者需负责决定是否求值其它参数。
5101+这类似宿主语言中参数传递和返回 auto&& 类型。
5102+
5103+@10.7.3.2 返回非引用值的操作:
5104+部分操作类似容器构造器(@10.7.2.1) 保证返回非引用值(@10.5.3) ,但并非直接以参数实现决定函数值:
5105+若非构造器的操作总是返回列表和其它对元素具有所有权的容器对象,返回的对象总是按值传递。
5106+为简化接口以及满足其它分类(如直接参数转发操作(@10.7.3.3) ),不提供不保留引用值的操作。
5107+和提供不同的变体的作为构造器的操作不同,此处的情形的结果可能包含引用值(和以 % 结尾构造器的情形类似)。
5108+若需要排除通过参数引入的引用值,应进行适当处理使参数中不含有会使这些操作引入引用值的构造。
5109+类似保留引用值的列表构造器,这些操作可在结果中保留引用值。
5110+
5111+@10.7.3.3 直接参数转发操作:
5112+部分不带有引用标记字符的直接参数转发操作是可能直接保留引用值的操作(@10.4.3) 。
5113+函数名不使用引用标记字符,和可直接保留引用值的函数名(@10.7.2) 使用引用标记字符不一致:
5114+本节约定的函数和可直接保留引用值的函数名中带有 % 结尾的函数同属参数转发操作,但后者同时有不带有引用标记字符的变体;
5115+本节不约定和可直接保留引用值的函数名中不带有引用标记字符结尾的函数对应的操作。
5116+这种不一致(和函数值转发操作(@10.7.3.4) 不同)是预期的特性:
5117+和可直接保留引用值的操作不同:
5118+ 这些操作并非用于构造对参数具有所有权的对象,不适合提供不保留引用值的操作;
5119+ 这些操作并非用于取子对象(@9.8.2) ,返回值不一定是引用值,和具体操作相关,不适合使用引用标记字符区分;
5120+为简化接口及满足其它分类(如返回非引用值的操作(@10.7.3.2) ),不适合提供不保留引用值的操作。
5121+本节约定的函数对引用标记字符的使用和可提供以引用标记字符结尾变体的操作(@10.7.2) 的函数名的使用不一致,含义相当于前者的结尾的 % 。
5122+以下函数值转发操作(@10.7.3.4) 同时也是直接参数转发操作。
5123+其它函数的参数传递的一般规则参见引用值作为实际参数(@10.4.1) 、函数参数和函数值传递约定(@10.5) 和实际参数约定(@10.6.3) 。
5124+
5125+@10.7.3.4 函数值转发操作:
5126+若其它情形确需非转发操作取得引用值,可使用带有 % 或 & 结尾的操作(@10.7.2) 及可直接返回引用值的操作(@10.7.3.1) 替代实现。
5127+本节约定的函数不使用引用标记字符,和容器元素访问器(@10.7.2.2) 的函数名不使用引用标记字符一致:
5128+本节约定的函数和上述容器元素访问器的函数名中不带有引用标记字符结尾的函数同属函数值转发操作,但后者同时有带有引用标记字符的变体。
5129+和容器构造器(@10.7.2.1) 引入引用值的情形不同,不带有后缀 % 相对不容易引起误用,因为返回值保留的引用可以继续被返回值转换(@10.4.2) 影响。
5130+例如,使用保证返回非引用值的涉及环境中求值的操作(@10.7.2.4) ,引用值会在引用的对象生存期结束前被返回值转换而不影响内存安全。
5131+
5132+@10.7.3.5 可能间接保留引用值的操作:
5133+类似可提供以引用标记字符结尾变体的对应操作(@10.7.2.4) ,部分不带有引用标记字符的操作可能间接保留引用值(@10.4.3) 。
5134+这包括由类型为合并子的参数(而非 <body> 或 <expressions> )决定是否保留引用值同时对其它参数进行转发的操作。
5135+
5136+@10.8 不安全操作(@9.4.5) 约定:
5137+除非另行指定,执行时包含以下操作的操作是不安全操作:
5138+以下不具有内存安全保证(@9.4) 的操作:
5139+ 使用函数名称约定(@10.7) 的命名的带有后缀的操作(@10.7.2) ;
5140+ 其它保留间接值的操作(@9.4.4) ;
5141+以下可能引入循环引用的操作:
5142+ 引入引用现有环境对象(@9.9.3) 的环境强引用(@5.4.3) 的操作;
5143+ 引入共享持有者的值数据成员(@5.4.2) 而可能通过循环引用等引起未定义行为操作;
5144+和以上不安全操作等效的互操作;
5145+其它另行指定的操作。
5146+按不安全操作引起不同的未定义行为和不同的间接值(@9.3.3) ,以下小节对不安全操作进行分类。
5147+分类之间的关系详见保留间接值(@9.4.4) 。
5148+分类可能不完全的且可能相交的(不安全操作可能不属于任何一个分类或同时属于多个分类)。
5149+
5150+@10.8.1 在返回值中保留引用值(@10.4.3) 的操作:
5151+在返回值中保留引用值的操作可引起之后的不安全引用值访问(@9.4.2) 。
5152+例如,赋值操作(@9.8.3.1) 可无效化引用值(@9.8.6) 。
5153+这包括按函数名称约定(@10.7) 具有引用标记字符结尾的操作。
5154+直接保留引用值(@10.4.3) 操作可配合带有返回值转换(@5.7.6.4) 的操作,指定个别函数参数不再保留引用值。
5155+
5156+@10.8.2 在返回值中保留环境引用的操作:
5157+环境引用(@5.7.3.1) 被返回时,总是被保留(@10.4.4) 。
5158+创建环境强引用的操作(@5.4.3) 是在返回值中保留环境引用的操作。
5159+这些对象可能因为没有及时保存环境引用使环境对象和其中的绑定一并被销毁,而使引用值访问其中的对象的程序具有未定义行为:
5160+注意直接返回有效的环境弱引用的操作不引起环境失效,不在此列。
5161+
5162+@10.8.3 在返回值中保留其它间接值的操作:
5163+特定的支持强递归绑定(@9.7.3.1) 而在返回值中保留其它间接值,可能是无效的间接值(@9.4.3.3) 。
5164+在返回值中保留其它间接值的操作的强递归绑定过程中引用共享对象(参见 $defrec!(@11.3.7) )的中间值。
5165+NPLA1 参考实现环境中,仅有在返回值中保留其它间接值的操作的实现内部可能引入引用持有者(@5.7.3.3) 。
5166+
5167+@10.8.4 在环境中保留环境引用的操作:
5168+环境中的被绑定对象可具有环境引用子对象(@9.8.2) ,间接地在环境中保留环境引用。
5169+这些操作使当前环境或参数指定的环境(而不是合并子调用时创建的新环境(@9.9.3) )中的变量绑定包含间接值,后者可能依赖合并子调用时创建的新环境。
5170+被绑定的对象中可能保留环境引用,而使用环境间接地保留对象中的引用。典型的例子是合并子对象的静态环境。
5171+使用这些操作时应总是注意被依赖的环境的可用性。若环境对象销毁,所有直接和间接依赖环境对象的间接值被无效化。这些间接值的不安全间接值访问(@9.4.2) 引起未定义行为。
5172+
5173+@10.8.5 可能引入循环引用的操作:
5174+可能通过非引用的形式引入环境循环引用的操作可破坏环境的资源所有权。
5175+自赋值(@9.8.3.1) 可能引入循环引用值。
5176+
5177+@10.8.6 可能破坏环境稳定性的操作:
5178+通过引用值进行的修改操作(@9.8.3) 可因破坏环境稳定性(@9.9.3) 而引起扩展 NPLA 未定义行为(@9.1.4)(不一定违反内存安全)。
5179+这包括以下可无效化对象包含的引用值而使可通过环境访问的某个子对象的同一性被改变,从而破坏环境稳定性(@9.9.3) 的操作:
5180+对可能具有对象语言中可访问的子对象的对象的赋值操作(@9.8.3.1) ;
5181+可修改被绑定对象(@5.4.3) 的操作(包括重绑定(@9.9.3.6.1) )。
5182+
5183+@10.8.7 安全操作子集:
5184+作为对象语言安全性保证(@9.4.6) 的一部分,用户程序通过限制或避免依赖特定的不安全操作,在特定情形下可实现对象语言内存安全保证(@9.4) ,而不需要分析具体操作的语义:
5185+不依赖操作命名(@10.7) 约定的带有后缀的操作;
5186+若使用保留环境引用的操作,如在返回值中保留环境引用的操作(@10.8.2) ,总是保存被依赖的环境以确保相关的环境对象及其中的被绑定对象(@5.4.3) 在间接访问对象时不被销毁;
5187+不使用引入其它间接值的操作。
5188+
5189+@10.9 实体实现(@2.3.1.2) 约定:
49685190 本节约定对 NPLA1 参考实现内部有效,不作用在用户程序。
4969-因不预期通过派生实现,当前实现中,基本操作总是通过本机实现(@5.2.1) 提供。(这不被接口设计(@10.1) 严格要求。)
4970-类似 [RnRK] ,派生操作可通过基本操作及派生操作实现。
4971-除非另行指定,NPLA1 参考实现环境作为公开接口提供的变量在根环境中绑定。
4972-除非是语义蕴含的操作结果或另行指定,所有作为函数值的操作(@10.1) 的结果(@4.1) 是未指定值(@7.2.2) 。另见 @9.9 。
5191+因不预期通过派生实现,当前实现中,基本特性总是通过本机实现(@5.2.1) 提供。(这不被接口设计(@10.3.2) 严格要求。)
5192+类似 [RnRK] ,派生特性可通过基本特性及派生特性实现。
5193+除非另行指定,NPLA1 参考实现环境作为公开接口提供的变量在根环境(@10.1) 中绑定。
5194+除非是语义蕴含的操作结果或另行指定,所有作为函数值的操作(@10.3.1) 的结果(@4.4.3.1) 是未指定值(@7.2.2) 。另见函数名称约定(@10.7) 。
49735195 未指定值可等于 #inert(@9.3.1) 或其它值,但满足忽略值时不引起可观察行为(@4.1.3) 的改变(这排除了引入 volatile 类型或非平凡析构的宿主值)。
4974-若操作(@10.1) 在 Kernel 或 klisp 中存在结果为 #inert 的对应的操作,且未指定作为函数值的结果,则返回等于 #inert 的右值。
5196+若操作(@10.3.1) 在 Kernel 或 klisp 中存在结果为 #inert 的对应的操作,且未指定作为函数值的结果,则返回等于 #inert 的右值。
49755197 除非显式指定,空环境没有父环境。
49765198 约定的接口通过绑定在根环境中的名称提供,参见以下各节。
49775199 这些名称可能是本机实现(@5.2.1) ,即直接调用 NPLA 或 NPLA1 API(参见 @6 、@7 和 @8 )绑定定义;也可能是非本机的派生的(derive) 实现,即通过在当前的基础上求值特定的对象语言代码引入(其实现最终依赖本机实现)。
49785200 变量的绑定(@4.1) 的引入是否由本机实现未指定。
49795201 操作的实现使用的续延名称(@7.11.6) 未指定。
4980-以下的派生操作(@10.6) 应能以派生的方式提供。派生操作是否以派生的形式提供未指定。
4981-派生不依赖隐式求值风格(@9.4.1.1) ,除非语义明确要求避免操作数的求值(如 $deflazy!(@10.6.1) )且对实现可提供必要的简化,应避免依赖 $quote(@10.6.1) ;$quote 自身通过派生实现引入。
5202+以下的派生操作(@11.4) 应能以派生的方式提供。派生操作是否以派生的形式提供未指定。
5203+派生不依赖隐式求值风格(@9.7.1.1) ,除非语义明确要求避免操作数的求值(如 $deflazy!(@11.4.1) )且对实现可提供必要的简化,应避免依赖 $quote(@11.4.1) ;$quote 自身通过派生实现引入。
49825204 除非另行指定,这些名称指称的实体构成的接口没有严格的兼容性保证,但一般可预期在 YSLib 发布版本([Documentation::ProjectRules @@2.2.4.5]) 之间保持向后兼容。
49835205 作为 @7.1.2 的扩展,函数的非本机也实现允许假定纯右值(@5.5.1) 的项不包含不被 @7.1.2 约定直接使用的标签。
49845206
4985-@10.2.1 函数实现使用约定:
5207+@10.9.1 函数实现约定:
49865208 名称使用 $def 起始的函数用于在当前环境引入绑定。
4987-需引入绑定时,优先使用 @10.6.2 中的函数;当使用这些函数并不能简化实现时,使用 $def!(@10.5.6) 。
4988-其中优先使用函数名中没有 % 的函数,仅当语义要求时,使用 %! 结尾的函数,以减少不安全操作(@10.1.4) 并明确函数值是否可能只是非引用值(此时两者效果应一致)。
4989-这对应宿主实现中,使用 auto 而不是 auto&& 作为返回值;但宿主语言中返回非引用类型的表达式两者含义不同。
4990-尽管设计时没有参照,使用函数结尾的引用标记字符和其它一些语言的类似特性的使用惯例也一致,如 PHP 的 function & 语法:
4991-https://www.php.net/references.return
4992-应注意 NPLA1 的名称表达式解析(@6.9.5) 的结果保证求值为左值(@5.5.1)(参见 @9.4.1 )。强调使用没有 % 或 %! 结尾的函数避免过于容易地返回局部创建的变量的悬空引用(@5.6.3) 引起未定义行为,在此为避免误用而符合 @1.4.5.2 。
4993-与引入绑定不同,实现内部不要求类似的优先使用,在需要明确实现需要符合的要求或减小实现开销时,可使用提供以引用标记字符结尾版本的操作(@9.9.1) 替代其它操作。
4994-
4995-@10.3 预定义对象:
5209+需引入绑定时,优先使用核心库(@11.4.2) 中的函数;当使用这些函数并不能简化实现时,使用 $def!(@11.3.7) 。
5210+除以下例外,优先使用函数名中不带有 % 及 %! 结尾的函数:
5211+当实现操作的语义要求时;
5212+调用的结果明确是非引用值(此时是否使用带有 % 的函数的效果应一致)。
5213+以上的实现方式可减少一部分不安全操作(@10.8) 并明确函数值是否可能只是非引用值。
5214+如果可能,函数实现使用转移,避免不必要的对象复制。
5215+强调使用没有 % 或 %! 结尾的函数避免一些可能的误用(@10.7.1.2) 。
5216+与引入绑定不同,实现内部不要求类似的优先使用,在需要明确实现需要符合的要求或减小实现开销时,可使用提供以引用标记字符结尾变体的操作(@10.7.2) 替代其它操作。
5217+
5218+@10.9.2 预定义对象:
49965219 除操作外,特定名称的对象以变量的形式在库中初始化,直接提供具有预设目的的可编程特性。
49975220
4998-@10.4 函数分类:
5221+@10.9.3 操作实现注记:
5222+派生实现不依赖非真合并子(@9.9.5) ,因此以合并子实现操作时,其中不使用分隔符(@9.7.1) ,也不需要实现在初始化(@10.1.1) 时支持中缀变换(@7.5.2) 。
5223+但是,不同操作之间的定义可能使用分隔符。因为不需依赖 $sequence(@11.4.1) ,这种实现也更简单。
5224+
5225+@11 NPLA1 根环境特性(@10.2) :
5226+本章指定在根环境(@10.1) 提供的 NPLA1 标准库特性(@10.3.3) 。
5227+根环境基本特性(@11.3) 提供在基础上下文(@8.5.2) 初始化的根环境基本(primitive) 特性,作为单独的模块。
5228+基础派生特性(@11.4) 起的各节提供其余要求 NPLA1 实现直接支持的各个模块的操作。
5229+
5230+@11.1 不安全操作(@9.4.5) 索引:
5231+本节按不安全操作约定(@10.8) 的分类对根环境中的不安全操作进行归类。
5232+在返回值中保留引用值的不安全操作(@10.8.1) 已被操作命名(@10.7) 归纳和函数分类(@11.2) 枚举,此处从略。
5233+不安全操作中,在参数以外直接引入间接值的操作仅有以下的在返回值中保留引用值的不安全操作:
5234+ref&(@11.3.4) 。
5235+附加调用安全(@9.4.6.1) 包括少量的在返回值中保留引用值的不安全操作(@10.8.1) 的调用。
5236+当前,这种操作包括 assign!(@11.4.1) ;隐藏环境排除可修改对象的引用通过冻结(@9.9.3.7) 环境保证而提供静态的证明。
5237+
5238+@11.1.1 在返回值中保留环境引用的操作(@10.8.2) :
5239+包括基本操作(@11.3.7) :
5240+make-environment
5241+包括派生操作(@11.4.1) :
5242+make-standard-environment
5243+derive-current-environment
5244+derive-environment
5245+$provide!
5246+$provide/let!
5247+
5248+@11.1.2 在返回值中保留其它间接值的操作(@10.8.3) :
5249+包括:
5250+$defrec!(@11.3.7)
5251+$setrec!(@11.4.1)
5252+
5253+@11.1.3 在环境中保留环境引用的操作(@10.8.4) :
5254+包括派生操作(@11.4.1) :
5255+$provide!
5256+$provide/let!
5257+
5258+@11.1.4 可能引入循环引用的操作(@10.8.5) :
5259+包括可能引入环境循环引用的基本操作(@11.3.7) :
5260+copy-environment
5261+lock-environment
5262+包括可能引入环境循环引用的派生操作(@11.4.1) :
5263+lock-current-environment
5264+包括可能自赋值(@10.8.5) 引入循环引用值的基本操作(@11.2.1.3) :
5265+assign@!
5266+assign%!
5267+
5268+@11.1.5 可能破坏环境稳定性的操作(@10.8.6) :
5269+对可能具有对象语言中可访问的子对象的对象的赋值操作(@9.8.3.1) 包括:
5270+简单赋值(@10.7.2.3) 。
5271+可直接修改被绑定对象(@5.4.3) 的操作包括:
5272+move!(@11.3.4) 。
5273+
5274+@11.2 函数分类:
49995275 本节对函数按名称和其它不同性质进行分类。
5000-在 NPLA1 参考实现环境提供的函数具体详见 @10.5 和 @10.6 。
5276+在 NPLA1 参考实现环境提供的函数具体详见根环境基本特性和基础派生特性。
50015277 除非另行指定,本节约定的函数属于 NPLA1 参考实现环境。
5002-本节约定的函数提供的部分操作属于转发(@9.8) 。
5003-绑定的变量名是符号构成的名称表达式(@4.5) ,解析(@6.9.5) 的结果总是左值(@5.5.1) ,转发其指称的对象可使用 forward(@10.6.1) ,或(仅对参数转发)使用标记字符 % 的参数绑定(@7.7.3.4) 的变量实现。
5004-其它情形不需使用 forward 。特别地,被转发的函数值若需支持 PTC(@9.4.8.1) ,则不能作为 forward 或其它应用子的实际参数以避免不满足在尾上下文(@4.4.7) 求值的条件。
5005-
5006-@10.4.1 可提供以引用标记字符结尾版本的函数:
5007-一些函数区分引用值的使用,以引用标记字符结尾提供不同的版本。
5008-可能存在的结尾的引用标记字符用于强调无法总是保证内存安全(@9.4.2) 的危险操作(@1.4.5.2) ,参见 @9.9.1 。
5009-不带有引用标记字符结尾的操作通过避免保留引用值(@9.6.1.5) 提供一定的内存安全保证,而带有引用标记字符结尾的操作较容易引起注意。这符合易预测性(@1.4.5.2.1) 。
5010-带有引用标记字符结尾的不安全操作属于第一类不安全操作(@10.1.4) 。
5011-第一类不安全操作实际不满足内存安全的一个主要的必要非充分条件是操作保留引用值,且引用值在被引用对象的生存期外被使用。
5012-这主要包括直接使用标识符求值为引用值的情形:因为标识符求值(@9.4.1) 后指称左值引用值(@7.8.2) 。
5013-保留引用值操作的内存安全(@9.4.2) 依赖所有被保留的引用值在之后的使用中都满足内存安全。
5014-若保留引用值操作不返回引用值,则返回的值等价经过返回值转换(@9.6.1.4) 。
5015-一般仅在明确需要引用时,使用以引用标记字符结尾的版本的函数(特别是环境可能作为参数被使用时)。
5016-本节约定的函数提供的操作属于 @10.1.4.1 定义的可能直接保留引用值的操作和可能间接保留引用值的操作之一。
5017-可能直接保留引用值的操作中,不带有引用标记字符的操作转发参数(@10.4.2.3) 。
5018-可能直接保留引用值的操作包括容器构造器或访问器(@9.8.5) ,以及可能使对象中包含引用值的修改操作(@9.4.5.1) 。
5019-(引入非容器对象的操作另见 @10.4.1.4 。)
5020-对构造器的转发操作以及部分修改操作区分是否存在引用标记字符结尾可强调一些非预期保留引用值的容易误用情形:
5021-尽管总是返回非引用值,转发参数保留的引用值不会被返回值转换(@9.6.1.4) 影响,在构造的容器对象作为非引用值返回仍会保留引用值(@9.6.1.5) 。
5022-(对应宿主语言中,可有更显著的差异,如构造器对应的 std::tuple 的 std::make_tuple 和 std::forward_as_tuple 。)
5023-本节内的以下分类不相交,但部分分类中函数名不带有引用标记字符结尾的操作可能和 @10.4.2 中的操作相交。
5024-
5025-@10.4.1.1 可能使结果包含引用值的容器构造器:
5026-以下操作是容器构造器,包括:
5027-cons(@10.5.5)
5028-cons%(@10.5.5)
5029-wrap(@10.5.7)
5030-wrap%(@10.5.7)
5031-list(@10.6.1)
5032-list%(@10.6.1)
5033-list*(@10.6.1)
5034-list*%(@10.6.1)
5035-box(@10.6.2)
5036-box%(@10.6.2)
5037-这些操作的结果由实际参数(根据是否存在引用标记字符 % 指定是否不经过隐含的左值到右值转换)的值确定。
5038-其中,带有引用标记字符结尾的操作是直接保留引用值操作。
5039-容器构造器可保留元素中的引用值,作为结果的容器总是作为非引用值返回(@9.6.1.4) 。
5040-
5041-@10.4.1.2 可能使结果包含引用值的容器元素访问器:
5042-以下操作是容器元素访问器,包括:
5043-first(@10.6.1)
5044-first&(@10.6.1)
5045-first@(@10.6.1)
5046-rest(@10.6.2)
5047-rest&(@10.6.2)
5048-rest%(@10.6.2)
5049-其中,带有引用标记字符结尾的操作是直接保留引用值操作;函数名不带有标记字符结尾的访问器属于参数转发操作(@9.8.2) 和函数值转发操作(@9.8.4) 。
5050-因为正规表示(@5.9.4) 的限制,rest 、rest& 和 rest% 重新构造列表,并不直接返回子对象;其它访问器若带有引用标记字符,可直接返回引用值。
5051-此外,@10.4.2.4 中部分函数也符合容器元素访问器的要求,但当前不提供带有后缀标记字符的版本。这些函数包括:
5052-unwrap(@10.5.7)
5053-unbox(@10.6.2)
5054-
5055-@10.4.1.3 可能使对象中包含引用值的修改操作(@9.4.5.1) :
5056-以下操作的内存安全(@9.4.2) 依赖所有参数都满足内存安全:
5057-简单赋值(simple assignment) (包含于赋值操作(@9.4.5.1.1) ),包括:
5058-assign@!(@10.5.4)
5059-assign%!(@10.6.1)
5060-assign!(@10.6.1)
5061-列表元素改变器(mutator) ,包括:
5062-set-rest!(@10.5.5)
5063-set-rest%!(@10.5.5)
5064-set-first!(@10.6.1)
5065-set-first@!(@10.6.1)
5066-set-first%!(@10.6.1)
5067-修改的结果由实际参数(需要时经过隐含的左值到右值转换)的值确定。
5068-以上操作都要求检查表示被修改的参数是左值。
5069-以上操作中,带有引用标记字符结尾的操作是直接保留引用值操作。
5070-
5071-@10.4.1.4 可能间接保留引用值的操作:
5072-一些操作可涉及不同的环境,参数在这些环境中被求值可能得到引用值。
5073-这些操作包括求值为操作子的以下函数:
5074-以求值 <body> 作为尾上下文的操作(@9.4.8.1) ,包括结果是合并子或用于在环境中绑定合并子的构造器操作,以及核心库函数(@10.6.2) 中的绑定操作;
5075-以求值 <expression> 作为尾上下文的函数 eval 和 eval%(@10.5.6) 。
5076-以上操作中,带有引用标记字符结尾的操作是间接保留引用值操作,表示求值结果不要求按值传递并可返回引用值,参见 @10.5.6 和 @10.6.2 。
5278+本节约定的函数提供的部分操作属于转发(@10.5) 。
5279+转发的实现(@10.5.6) 中,可使用 forward!(@11.4.1) 作为其中的特定的操作。
5280+
5281+@11.2.1 可提供以引用标记字符结尾(@10.7.2) 变体的函数:
5282+本节内的以下分类不相交,但部分分类中函数名不带有引用标记字符结尾的操作可能和 @11.2.2 中的操作相交。
5283+
5284+@11.2.1.1 可能使结果包含引用值的容器构造器(@10.7.2.1) :
5285+包括:
5286+cons(@11.3.5)
5287+cons%(@11.3.5)
5288+wrap(@11.3.8)
5289+wrap%(@11.3.8)
5290+list(@11.4.1)
5291+list%(@11.4.1)
5292+list*(@11.4.1)
5293+list*%(@11.4.1)
5294+box(@11.4.2)
5295+box%(@11.4.2)
5296+
5297+@11.2.1.2 可能使结果包含引用值的容器元素访问器(@10.7.2.2) :
5298+包括:
5299+first(@11.4.1)
5300+first&(@11.4.1)
5301+first@(@11.4.1)
5302+restv(@11.4.2)
5303+rest&(@11.4.2)
5304+rest%(@11.4.2)
5305+因为正规表示(@5.9.4) 的限制,restv 、rest& 和 rest% 重新构造列表,并不直接返回子对象(@9.8.2) ;其它访问器若带有引用标记字符,可直接返回引用值。
5306+此外,@11.2.2.4 中部分函数也符合容器元素访问器的要求,但当前不提供带有后缀标记字符的变体。这些函数包括:
5307+unwrap(@11.3.8)
5308+unbox(@11.4.2)
5309+
5310+@11.2.1.3 可能使对象中包含引用值的修改操作(@10.7.2.3) :
5311+简单赋值,包括:
5312+assign@!(@11.3.4)
5313+assign%!(@11.4.1)
5314+assign!(@11.4.1)
5315+列表元素改变器,包括:
5316+set-rest!(@11.3.5)
5317+set-rest%!(@11.3.5)
5318+set-first!(@11.4.1)
5319+set-first@!(@11.4.1)
5320+set-first%!(@11.4.1)
5321+
5322+@11.2.1.4 可能间接保留引用值的操作(@10.7.2.4) :
5323+以求值 <body> 作为尾上下文的操作,包括:
5324+结果是合并子或用于在环境中绑定合并子的构造器操作;
5325+以及核心库函数(@11.4.2) 中的绑定操作;
5326+以求值 <expression> 作为尾上下文的函数,包括 eval 和 eval%(@11.3.7) 。
5327+参见环境基本操作(@11.3.7) 和核心库(@11.4.2) 。
50775328 以上操作中的求值符合词法闭包(@4.6.1.1.2) 规则,可使用 A1::RelayForEval 或 A1::RelayForCall(@7.7.2) 实现。
5078-注意和此处直接在参数中给出被求值表达式不同,如 apply(@10.6.1) 等应用子中的求值的操作不属于上述操作(@10.4.2.5) 。
5079-
5080-@10.4.2 不提供结尾 % 或 & 对应名称的函数:
5081-一些函数命名不提供结尾 % 或 & ,函数值是否保留引用值通过本节内的分类确定,符合 @9.9.2 。
5082-本节内部分操作涉及参数转发(@9.8.2) 和函数值转发(@9.8.4) 。
5083-本节约定的涉及参数转发或函数值转发的函数不提供引用标记字符(@9.9.1) ,但已在 @10.4.1 中的除外。
5084-尽管可能因为对左值进行求值而使用引用,不使用 @10.4.1.4 中的第一类不安全操作(@10.1.4) 仍能保证这些引用不逃逸(@7.1.4) 。
5085-通常使用 forward(@10.6.1) 转发实现上述保证(@9.8.2) 。
5086-部分操作的内存安全性和 @10.4.1 类似,也是第一类不安全操作,但仅在引用值参数被保留且在之后体现。
5087-和 @10.1.4.1 类似,包括直接保留引用值和间接保留引用值的不同情形。
5088-除 @10.4.2.1 和其它节的操作不相交,以下分类对操作的参数和函数值分别约定,可能相交。
5089-
5090-@10.4.2.1 可直接返回引用值的操作:
5091-一些求值为操作子提供的函数选取特定的参数进行求值,作为控制操作。
5092-操作数中被求值的参数直接决定是否为引用部分操作直接返回引用值。
5093-被求值的 <test> 进行左值到右值转换,其它被求值的参数不进行左值到右值转换,调用者需负责决定是否求值其它参数。
5094-这类似宿主语言中参数传递和返回 auto&& 类型。
5095-这些操作当前包括:
5096-$if(@10.5.3)
5097-$sequence(@10.6.1)
5098-$cond(@10.6.1)
5099-$when(@10.6.1)
5100-$unless(@10.6.1)
5101-$and?(@10.6.1)
5102-$or?(@10.6.1)
5103-
5104-@10.4.2.2 返回非引用值的操作:
5105-部分操作类似容器构造器(@10.4.1.1) 保证返回非引用值(@9.8.3) ,但并非直接以参数实现决定函数值:
5106-若非构造器的操作总是返回列表、箱(@10.6.2) 或其它的封装类型(@10.5.9) 对象,返回的对象总是按值传递。
5107-和作为构造器的操作不同,后者需区分结果中是否可能包含引用值(@10.4.1.1) :
5108-没有引用标记字符的操作(@9.9) 表示(假定一次折叠(@9.9.1) 后)不包含引用值的构造器;
5109-带有引用标记字符的操作表示可能包含引用值的构造器。
5110-而此处的情形的结果可能包含引用值。
5111-为简化接口以及满足其它分类(如 @10.4.2.3 ),不提供不保留引用值的操作。
5112-若需要排除通过参数引入的引用值,应进行适当处理使参数中不含有会使这些操作引入引用值的构造。
5113-这些操作包括核心库函数(@10.6.2) 中的:
5329+
5330+@11.2.2 不提供结尾 % 或 & 对应变体(@10.7.3) 的函数:
5331+通常使用 forward(@11.4.1) 转发实现上述保证(@10.5.2) 。
5332+
5333+@11.2.2.1 可直接返回引用值的操作(@10.7.3.1) :
5334+包括:
5335+$if(@11.3.3)
5336+$sequence(@11.4.1)
5337+$cond(@11.4.1)
5338+$when(@11.4.1)
5339+$unless(@11.4.1)
5340+$and?(@11.4.1)
5341+$or?(@11.4.1)
5342+
5343+@11.2.2.2 返回非引用值的操作(@10.7.3.2) :
5344+这些返回值总是按值传递的操作涉及的容器包括列表、箱(@11.4.2) 或其它的封装类型(@11.3.10) 对象。
5345+包括核心库函数(@11.4.2) :
51145346 map1
51155347 list-concat
51165348 append
5117-类似列表构造器,这些函数可在结果中保留引用值。
5118-
5119-@10.4.2.3 直接参数转发操作:
5120-部分不带有引用标记字符的直接参数转发操作是可能直接保留引用值的操作(@10.1.4.1) 。
5121-函数名不使用引用标记字符,和 @10.4.1.1 的函数名使用引用标记字符不一致:
5122-本节约定的函数和 @10.4.1.1 中函数名中带有 % 结尾的函数同属参数转发操作,但后者同时有不带有引用标记字符的版本;
5123-本节不约定和 @10.4.1.1 中函数名中不带有引用标记字符结尾的函数对应的操作。
5124-这种不一致(和 @10.4.2.4 不同)是预期的特性:
5125-和 @10.4.1.1 不同,这些操作并非用于构造对参数具有所有权的对象,不适合提供不保留引用值的操作;
5126-为简化接口及满足其它分类(如 @10.4.2.2 ),不适合提供不保留引用值的操作;
5127-和 @10.4.1.2 不同,这些操作并非用于取子对象,返回值不一定是引用值,和具体操作相关,不适合使用引用标记字符区分。
5128-本节约定的函数对引用标记字符的使用和 @10.4.1 的函数名的使用不一致,而相当于结尾的 % 。
5129-本节约定的函数包括合并子基本操作中的合并子访问器 unwrap(@10.5.7) 。
5130-非构造器函数参数支持转发操作的这些操作还包括核心库函数(@10.6.2) 中的:
5349+
5350+@11.2.2.3 直接参数转发操作(@10.7.3.3) :
5351+包括合并子基本操作(@11.3.8) :
5352+unwrap
5353+包括核心库函数(@11.4.2) :
51315354 accl
51325355 accr
51335356 foldr1
51345357 map1
5135-核心库函数(@10.6.2) 中的绑定操作的非 <environment> 的形式参数支持转发。
5136-注意 map1 同时返回非引用值(@10.4.2.2) 。
5137-参数形式上被转发但操作的语义并非总是转发到其它操作的操作不使用本节的名称约定,如以下仅有第二参数支持转发的操作是提供结尾 % 或 & 对应名称的函数(@10.4.1) ,有对象基本操作(@10.5.4) 中的:
5358+核心库函数(@11.4.2) 中的绑定操作的非 <environment> 的形式参数支持转发。
5359+注意 map1 同时返回非引用值(@11.2.2.2) 。
5360+参数形式上被转发但操作的语义并非总是转发到其它操作的操作不使用本节的名称约定,如以下仅有第二参数支持转发的操作是提供结尾 % 或 & 对应名称的函数(@11.2.1) ,有对象基本操作(@11.3.4) 中的:
51385361 assign%!
51395362 assign@!
5140-此外,@10.4.2.4 中的函数值转发操作同时也是直接参数转发操作。
5141-其它函数的参数传递的一般规则参见 @9.6.1.3 、 @9.7.2 和 @9.8 。
5142-
5143-@10.4.2.4 函数值转发操作:
5144-注意 @10.4.1.4 中的操作不提供具有转发返回值的形式,因为总是转发(提升后的)值比转发引用具有更严格的安全保证(因而通常不需要调用 idv(@10.6.1) 避免悬空引用(@5.6.3) ),而直接返回可能是引用值的值具有更简明的语义。
5145-若其它情形确需非转发操作取得引用值,可使用 @10.4.1 中带有 % 或 & 结尾的操作及 @10.4.2.1 中的操作替代实现。
5146-本节约定的函数不使用引用标记字符,和 @10.4.1.2 的函数名不使用引用标记字符一致:
5147-本节约定的函数和 @10.4.1.2 的函数名中不带有引用标记字符结尾的函数同属函数值转发操作,但后者同时有带有引用标记字符的版本。
5148-和 @10.4.1.1 引入引用值的情形不同,不带有后缀 % 相对不容易引起误用,因为返回值保留的引用可以继续被返回值转换(@9.6.1.4) 影响。
5149-例如,使用保证返回非引用值的涉及环境中求值的操作(@10.4.1.4) ,引用值会在引用的对象生存期结束前被返回值转换而不影响内存安全。
5150-NPLA1 参考实现环境的函数值转发操作包括以下访问对象或被引用对象自身或子对象的函数:
5151-unwrap(@10.5.7)
5152-id(@10.6.1)
5153-forward(@10.6.1)
5154-unbox(@10.6.2)
5155-基本操作(@10.5) 的不具有名称的相关操作中参数和函数值原生支持的转发操作包括:
5156-使用 make-encapsulation-type(@10.5.9) 返回的访问器合并子。
5157-
5158-@10.4.2.5 间接保留引用值的操作:
5159-部分不带有引用标记字符的操作是可能间接保留引用值的操作(@10.1.4.1) 。
5160-由类型为合并子的参数(而非 <body> 或 <expressions> )决定是否保留引用值同时对其它参数进行转发的操作有:
5161-apply(@10.6.1)
5162-由特定的参数在特定环境中的求值的结果决定是否保留引用值的操作有核心库函数(@10.6.2) :
5163-$provide!
5164-$provide/let!
5165-
5166-@10.4.3 引用值构造:
5363+
5364+@11.2.2.4 函数值转发操作(@10.7.3.4) :
5365+NPLA1 参考实现环境的函数值转发操作包括以下访问对象或被引用对象自身或子对象(@9.8.2) 的函数:
5366+unwrap(@11.3.8)
5367+id(@11.4.1)
5368+forward(@11.4.1)
5369+unbox(@11.4.2)
5370+基本操作(@11.3) 的不具有名称的相关操作中参数和函数值原生支持的转发操作包括:
5371+使用 make-encapsulation-type(@11.3.10) 返回的访问器合并子。
5372+
5373+@11.2.2.5 可能间接保留引用值的操作(@10.7.3.5) :
5374+包括:
5375+apply(@11.4.1)
5376+
5377+@11.2.4 引用值构造:
51675378 当前构造子对象引用(@5.6.3.5) 的操作有:
5168-基本操作中的 unwrap(@10.5.7) 。
5379+基本操作中的 unwrap(@11.3.8) 。
51695380 子对象引用具有非平凡非正规表示(@5.9.4.1) 。
51705381
5171-@10.5 根环境基本接口(@10.1) :
5172-和 [RnRK] 不同,为简化设计,NPLA1 不提供可选(optional) 的合并子,而通过预定义对象(@10.3) 的形式提供可选的模块(@11) 。
5173-根环境基本接口是除了这些模块的以变量绑定形式提供的不要求可派生实现的接口,被绑定对象(@5.4.3) 包括预定义对象(@10.3) 和在基础上下文(@8.5.2) 的根环境中初始化的基础基本操作(grounded primitive operations) 的实现。
5174-派生实现可以通过提供不公开不安全操作(@10.1.4) 的根环境,但不符合此处的规格要求(@2.3.1.2) 。
5175-若派生实现不提供第三类不安全操作(@10.1.4) ,可以简化部分 @10.5.4 中与之关联的操作的实现。
5382+@11.3 根环境基本特性(@10.2) :
5383+和 [RnRK] 不同,为简化设计,NPLA1 不提供可选(optional) 的合并子,而通过预定义对象(@10.9.2) 的形式提供可选的模块(@12) 。
5384+根环境基本特性是除了这些模块的以变量绑定形式提供的不要求可派生实现的特性。
5385+根环境基本特性的被绑定对象(@5.4.3) 包括基础环境(@10.1) 提供的预定义对象(@10.9.2) 和在基础上下文(@8.5.2) 的根环境中初始化的基础基本操作(grounded primitive operations) 的实现。
5386+派生实现可以通过提供不公开不安全操作(@9.4.5) 的根环境,但不符合此处的规格要求(@2.3.1.2) 。
5387+若派生实现不提供在返回值中保留其它间接值的操作(@11.1.2) ,可以简化部分 @11.3.4 中与之关联的操作的实现。
51765388 部分可选的 Kernel 合并子被直接提供。
51775389 和 Kernel 不同,一些函数显式地操作引用值(@5.5.4) ,包括未折叠的引用值(@5.5.4) 。
51785390 和 Kernel 不同,求值算法不直接处理对象的引用值(@6.5.3.3) 。
5179-为简化实现,部分提供 % 等后缀的函数(@10.4.1) 不被派生。
5391+为简化实现,部分提供 % 等后缀的函数(@11.2.1) 不被派生。
51805392 因为设计原因,不提供以下 Kernel 合并子对应的操作:
51815393 copy-es-immutable
51825394 inert?
51835395 ignore?
5184-考虑(可变对象的)一等引用和绑定构造(@9.5.2) 绑定引用的的平摊复杂度,不提供需要同时转换不同层次子项的 copy-es-immutable 操作。
5185-部分其它原理参见 @10.5.1 。关于引用值的处理另见 @10.4 。
5396+考虑(可变对象的)一等引用和绑定构造(@9.7.3) 绑定引用的的平摊复杂度,不提供需要同时转换不同层次子项的 copy-es-immutable 操作。
5397+部分其它原理参见根环境对象(@11.3.1) 。关于引用值的处理另见函数分类(@11.2) 。
51865398 其它没有包含在以下节中的 Kernel 操作可能会在之后的版本中被支持。
51875399
5188-@10.5.1 根环境对象:
5400+@11.3.1 基本对象:
51895401 根环境定义以下对象:
51905402 ignore :类似 Kernel 的 #ignore 字面量,但不作为字面量而是普通对象,关联的值是记号值(@5.6.1) 。
51915403 注意 ignore 是一等对象(@4.1) ,和 Kenerl 为 #ignore 单独提供值域仅有一个单元类型(unit type) 不同。
5192-原理:按 @1.4.2.3 ,提供单独的类型是不必要的。
5404+原理:按最小接口原则(@1.4.2.3) 和类型分类(@9.8.7) ,提供单独的类型是不必要的。
51935405 从表达上,#inert(@9.3.1) 和 ignore 仍都可以被视为特定单元类型的值:等价的类型判断谓词可以直接使用值的相等关系确定。
51945406 #inert 的值是 ValueToken 宿主类型唯一直接在对象语言中提供的宿主值。
51955407 ignore 的值是完全作为标签使用的记号,具有记号值类型。
51965408 以下各节引入的变量都表示操作。
51975409
5198-@10.5.2 基本等价谓词(@4.1.4) :
5410+@11.3.2 基本等价谓词(@4.1.4) :
51995411 等价谓词不应修改参数对象。
52005412 用户定义的类型提供等价谓词应满足和 NPLA1 提供的等价谓词的语义一致的等价关系,否则若谓词被求值,行为未指定。
52015413 开放类型映射(@5.2.3) 的类型系统(@4.6.2) 可能属于这种理论。不需要依赖序的等价谓词可以为名义类型(@4.6.2.1) 提供直接的支持。
@@ -5208,23 +5420,23 @@
52085420 eqr? <object1> <object2> :判断项的值数据成员引用相等。
52095421 eqv? <object1> <object2> :判断值相等。
52105422 使用 eq? 判断一般左值的标识,当且仅当两个操作数是同一对象时比较结果为 #t 。
5211-使用 eql? 比较忽略列表类型(@9.4.7) 时和 eqv? 相同,即仅比较宿主值 TermNode 的值数据成员(@5.4.2) 相等。
5423+使用 eql? 比较忽略列表类型(@9.8.7) 时和 eqv? 相同,即仅比较宿主值 TermNode 的值数据成员(@5.4.2) 相等。
52125424 由 @5.9.3 ,列表和非列表之间的 eql? 结果总是为 #f ,列表之间的 eql? 的比较结果总是 #t 。
52135425 使用 eqr? 判断宿主值 TermNode 的值数据成员表示的左值(@5.5.1) 的标识,当且仅当为操作数比较同一个对象时比较结果为 #t 。
52145426 由 @5.9.3 ,所有列表在 TermNode 的值数据成员中的表示都一致,在 eqr? 等价关系下视为相同的对象。
52155427 使用 eqv? 比较项表示的值的相等关系:当项都是非空列表时,同 eq? ;否则,同 eql? 。
52165428 不同左值或 eqv? 比较结果为 #f 的操作数的 eq? 比较结果总是 #f 。
5217-若右值之间 eqv? 比较结果为 #t ,eq? 比较结果未指定,以允许实现复用存储右值的驻留(@9.4.5.2) 对象。
5429+若右值之间 eqv? 比较结果为 #t ,eq? 比较结果未指定,以允许实现复用存储右值的驻留(@9.8.4) 对象。
52185430 因为对应等价的不变性(@2.3.1.1) 关系不具有唯一性(@4.1.4.3) ,且可能允许不唯一的方式产生副作用(如缓存),和 Kernel 不同,不以基本操作提供 equal? 对任意对象提供一般的相等操作。
52195431 不等价(@4.5.3.2) 的函数的 eqv? 比较结果为 #f 。
5220-除以上规则确定的结果外,eqv? 对函数或列表的比较结果未指定。在互操作的意义上,当前其 eqv? 定义的函数的相等性由 @8.4.5.5 或其它宿主实现提供的 == 操作确定(关于合并子相等,另见 @7.11.5 的说明)。
5432+除以上规则确定的结果外,eqv? 对函数或列表的比较结果未指定。在互操作(@2.3.3) 的意义上,当前其 eqv? 定义的函数的相等性由 @8.4.5.5 或其它宿主实现提供的 == 操作确定(关于合并子相等,另见 TCO 实现(@7.11.5) 中关于操作压缩判断的说明)。
52215433 通常,等价谓词比较的求值应保证能终止且对非列表项和 n 个子项的列表分别具有 O(1) 和 O(n) 平摊复杂度。但语言不需要约束这个性质。
52225434
5223-@10.5.3 控制:
5435+@11.3.3 控制:
52245436 $if <test> <consequent> <alternate> :条件分支,按条件成立与否返回 <consequent> 或 <alternative> 之一,可能是引用值。
52255437 $if <test> <consequent> :省略第三操作数的条件分支,条件成立时返回 <consequent> 。
52265438 和 Kernel 不同而和 Scheme 类似,如 <test> 的求值结果非 #f 即选择 <consequent> ,且支持省略第三参数。
5227-若省略 <alternative> 且 <test> 求值为 #f ,则结果未指定(@10.2) 。
5439+若省略 <alternative> 且 <test> 求值为 #f ,则结果未指定(@10.9) 。
52285440 对 <test> 的处理的主要原理和 Kernel 的 $and? 不要求尾上下文的表达式求值检查类型一致。
52295441 若需要检查类型避免误用,可以派生提供其它函数;相反的派生无法利用更简单的实现。
52305442 和 R7RS 类似,但和 Racket 及 Kernel 不同,省略 <alternative> 被支持。
@@ -5233,16 +5445,16 @@
52335445 NPLA1 不假设作为基本控制操作的 $if 的作用(仅要 <consequent> 或 <alternate> 求值的结果,或仅为了副作用);
52345446 $if 不假设用户对 <consequent> 和 <alternate> 顺序选择性偏好,以避免限制用户选择否定谓词简化 <test> ,从而支持 @1.4.2.1 。
52355447 此外, NPLA1 使用显式的 <expression-sequence>(而不是 <consequent> 和 <alternate> )语法表示顺序求值,这不适合基本的控制操作子:
5236-若分离二操作数和三操作数其它形式,则二操作数可以使用 <expression-sequence> ,即 $when(@10.6.1) 。
5448+若分离二操作数和三操作数其它形式,则二操作数可以使用 <expression-sequence> ,即 $when(@11.4.1) 。
52375449 但依赖 <expression-sequence> 的 $when 不应是比具有 <consequent> 的二操作数形式更基本的操作。
52385450 因此,仍然需要有 $when 以外的省略第三参数的基本控制操作子。基于同一性(@1.4.5.1) ,对应函数名仍然为 $if 。(尽管使用了相同的原则,这和 Kernel 的结论恰好相反。)
52395451 与此类似,和 Racket 的理由(参见 https://stackoverflow.com/questions/10863192/why-is-one-armed-if-missing-from-racket )不同,不因为 $when 提供只强调副作用的操作而取消 $if 的 <alternative> 。
52405452 NPLA1 不会如 Racket 一样在此避免遗漏 <alternate> 导致的非预期结果。这并不违反 @1.4.5.2 ,因为不使用 <alternate> 的结果非常显然,同时选择使用 $if 这样的基本控制操作而不是更特定派生控制操作或更高级的抽象已蕴含注意误用的必要性。
5241-一般地,NPLA1 不提供强调只存在副作用的操作。返回未指定(而不要求被使用)的求值结果的情形并不表示只有副作用(@10.2) ,因为副作用是否存在原则上依赖具体操作。这和 Kernel 的 #inert 以及 Racket 的 #<void> 值即便在实现上都一致,但含义不同。
5453+一般地,NPLA1 不提供强调只存在副作用的操作。返回未指定(而不要求被使用)的求值结果的情形并不表示只有副作用(@10.9) ,因为副作用是否存在原则上依赖具体操作。这和 Kernel 的 #inert 以及 Racket 的 #<void> 值即便在实现上都一致,但含义不同。
52425454 另见 $when 的说明。
52435455
5244-@10.5.4 对象基本操作:
5245-注意因为真列表(@9.6.3) 的限制,列表左值只能引用完整的列表的对象,而不支持部分列表。
5456+@11.3.4 对象基本操作:
5457+注意因为真列表(@9.9.4) 的限制,列表左值只能引用完整的列表的对象,而不支持部分列表。
52465458 这影响 set-rest! 和 set-rest%! 的 <list> 参数。
52475459 null? <object> :判断操作数是否为空列表。
52485460 nullv? <object> :判断操作数是否为空列表纯右值。
@@ -5253,60 +5465,64 @@
52535465 reference? <object> :判断操作数是否为引用值。
52545466 uncollapsed? <object> :判断操作数是否为未折叠的引用值。
52555467 bound-lvalue? <object> :判断操作数是否为被引用的被绑定对象左值。
5256-绑定临时对象的引用类型的参数不被视为左值引用。
5257-配合 $resolve-identifier(@10.5.6) 和 % 引用标记(@7.7.3.4) 绑定的变量,可确定实际参数是否为左值。
5468+绑定临时对象(@5.2.4.2) 的引用类型的参数不被视为左值引用。
5469+配合 $resolve-identifier(@11.3.7) 和 % 引用标记(@7.7.3.4) 绑定的变量,可确定实际参数是否为左值。
52585470 单独使用 bound-lvalue? 和 & 引用标记字符(@7.7.3.4) 绑定的变量,可确定实际参数是否为引用。
52595471 unique? <object> :判断操作数是否为唯一引用(@5.4.2.2) 。
52605472 deshare <object> :取指定对象取消共享的值。
5261-同 idv(@10.6.1) ,但显式提升操作数中具有共享持有者的值数据成员(@5.4.2) ,且不转移宿主值。
5262-因为提供第三类不安全操作(@10.1.4) ,这个区别是必要的。否则,使用 idv 替代应不影响可观察行为(@4.1.3) 。
5263-和通常的求值规约消除引用值(如 @7.7.2.1 )不同,以 NPL::LiftTermRef(@6.6.2) 和确保创建值副本的 NPL::SetContentWith(@6.2.1) 实现。
5473+同 idv(@11.4.1) ,但显式提升操作数中具有共享持有者的值数据成员(@5.4.2) ,且不转移宿主值。
5474+因为提供在返回值中保留其它间接值的操作(@11.1.2) ,这个区别是必要的。否则,使用 idv 替代应不影响可观察行为(@4.1.3) 。
5475+和通常的求值规约消除引用值(如求值规约提升项(@7.7.2.1) )不同,以 NPL::LiftTermRef(@6.6.2) 和确保创建值副本的 NPL::SetContentWith(@6.2.1) 实现。
52645476 expire <object> :取指定对象的消亡值(@5.5.1) 。
5265-同 id(@10.6.1) ,但当参数是引用值时,结果是和参数引用相同对象的唯一引用。
5266-可用于显式地指定之后被转移的对象(参见 @9.4.5.1.2 ),而不需要直接转移参数,因此这个操作也不是修改操作(@9.4.5.1) ,函数名不以 ! 结尾(@9.9) 。
5477+同 id(@11.4.1) ,但当参数是引用值时,结果是和参数引用相同对象的唯一引用。
5478+可用于显式地指定之后被转移(@9.8.3.2) 的对象,而不需要直接转移参数,因此这个操作也不是修改操作(@9.8.3) ,函数名不以 ! 结尾(@10.7) 。
52675479 这个函数类似宿主语言作用在对象类型实际参数的 std::move ,可能减少没有经过复制消除(@5.5.6.3) 的复制或转移(@5.5.2.3) 而改变使用这个函数的结果对象的副作用。
5268-特别地,指定列表的引用值被转移时,不需要立即转移列表的每个元素,而允许之后通过绑定构造(@9.5.2) 等方式选择转移的子对象(@9.6) 。
5269-可能包含立即转移的操作如 forward!(@10.6.1) 。
5480+特别地,指定列表的引用值被转移时,不需要立即转移列表的每个元素,而允许之后通过绑定构造(@9.7.3) 等方式选择转移的子对象(@9.8.2) 。
5481+可能包含立即转移的操作如 forward!(@11.4.1) 。
52705482 move! <object> :转移对象。
52715483 若参数是不可修改的左值,则以复制代替转移;否则,直接转移表示参数对象的项(@5.5.3) 。
52725484 结果是不经返回值转换的项。
52735485 被转移对象后的项满足 @5.2.4.2 。
5274-当前实现中项被转移后,表示的值为 () 。这和返回值转换(@5.7.4.4) 等引入实质化临时对象时可能具有的转移(@5.5.6) 的效果(仅在互操作时可见)不保证相同。
5486+当前实现中项被转移后,表示的值为 () 。这和返回值转换(@5.7.6.4) 等引入实质化临时对象时可能具有的转移(@5.5.6) 的效果(仅在互操作时可见)不保证相同。
52755487 transfer! <object> :转移对象。
52765488 同 move! ,但使用对象的转移(@5.5.2.3) ,而不是项的转移(@5.5.3) ,避免宿主对象转移消除而允许调用宿主对象的转移构造函数(@5.5.3.1) 。
5277-项被转移后,和返回值转换等引入实质化临时对象时可能具有的转移的效果(仅在互操作时可见)相同。
5489+项被转移后,和返回值转换等引入实质化临时对象时可能具有的转移的效果(仅在互操作(@2.3.3) 时可见)相同。
52785490 ref& <object> :取引用。
5279-对引用值同 id(@10.6.1) ;对具有共享持有者的值数据成员的对象也视为左值。通过后者构造的引用值不被检查。
5491+对引用值同 id(@11.4.1) ;对具有共享持有者的值数据成员的对象也视为左值。通过后者构造的引用值不被检查。
52805492 取得的引用值是不安全引用值(@5.6.3.1) 。
5281-因为提供第三类不安全操作,对共享持有者的值数据成员的对象使用不同的处理。否则,对引用值参数的情形,使用 id 替代应不影响可观察行为。
5493+因为提供在返回值中保留其它间接值的操作,对共享持有者的值数据成员的对象使用不同的处理。否则,对引用值参数的情形,使用 id 替代应不影响可观察行为。
52825494 以 NPL::LiftToReference(@6.6) 实现。
5283-assign@! <reference> <object> :赋值(@9.4.5.1.1) 被引用的对象为指定对象的值,且 <object> 不隐含左值到右值转换且不被折叠。
5284-同 assign%!(@10.6.1) ,但 <object> 不被折叠。
5495+assign@! <reference> <object> :赋值(@9.8.3.1) 被引用的对象为指定对象的值,且 <object> 不隐含左值到右值转换且不被折叠。
5496+同 assign%!(@11.4.1) ,但 <object> 不被折叠。
52855497 检查 <reference> 是可修改的左值。
5286-赋值对象直接修改(@9.4.5.1) 被引用的对象,但不无效化(@9.4.5.4) 参数指定的引用。
5498+赋值对象直接修改(@9.8.3) 被引用的对象,但不无效化(@9.8.6) 参数指定的引用。
52875499 Scheme 的 set! 在 SRFI-17 提供具有类似作用的支持,但第一操作数限于 set! 且为特定的过程调用;Kernel 没有类似的操作。
52885500
5289-@10.5.5 列表基本操作:
5501+@11.3.5 列表基本操作:
52905502 cons <object> <list> :构造两个元素的列表。
5291-和 Kernel 不同,NPL 不支持列表中存在环,因此第二个操作数应为列表,否则引起错误(@9.4.3.1) 。
5503+和 Kernel 不同,NPL 不支持列表中存在环,因此第二个操作数应为列表,否则引起错误(@9.5.1) 。
52925504 cons% <object> <list> :构造两个元素的列表,保留引用值。
52935505 同 cons ,但允许子项中有引用而不复制(@8.4.5.4) 子项的值。
52945506 set-rest! <list> <object> :修改列表的第一个以外的元素。
52955507 和 Kernel 的 set-cdr! 类似,但检查列表是左值,且不保留被添加元素中的引用值。
52965508 set-rest%! <list> <object> :同 set-rest! 但保留引用值。
52975509 和 Kernel 的 set-cdr! 类似,但检查列表是左值。
5298-不检查修改操作(@9.4.5.1) 导致循环引用(@9.6.1.1) ,用户应自行避免未定义行为(@5.2.2) 。
5299-
5300-@10.5.6 环境:
5301-和 Kernel 不同,环境可使用环境强引用和环境弱引用(@5.4.3) 蕴含不同的所有权。
5302-为避免引入过于容易引入循环引用(@9.6.1.1) ,仅通过个别操作引入环境强引用(另见 @5.4.3 ):
5510+不检查修改操作(@9.8.3) 导致循环引用(@9.9.1.1) ,用户应自行避免未定义行为(@5.2.2) 。
5511+
5512+@11.3.6 符号:
5513+desigil <symbol> :移除符号中的引用标记字符 & 或 %(@7.7.3.4) 。
5514+判断符号非空且以 & 或 % 起始,结果为移除起始字符的参数。否则,结果为参数。
5515+不处理引用标记字符 @(@7.7.3.4) 。
5516+
5517+@11.3.7 环境:
5518+为避免引入过于容易引入循环引用(@9.9.1.1) ,仅通过个别操作引入环境强引用(@9.9.3)
53035519 make-environment
53045520 lock-environment
53055521 eval <expression> <environment> :在参数指定的环境中求值,结果作为函数值。
5306-注意按 @9.4 ,<expression> 若为元素中有引用值的列表,元素不会被特殊处理,不隐含左值到右值转换。
5522+注意 <expression> 若为元素中有引用值的列表,元素不会被特殊处理,不隐含左值到右值转换(@10.4.1) 。
53075523 eval% <expression> <environment> :同 eval ,但保留引用值。
53085524 $resolve-identifier <symbol> :解析标识符。
5309-直接保留解析结果中项的类型,不按成员访问规则确定值类别,因此和解析名称表达式的结果总是左值(@10.4) 不同,可保留消亡值(@5.7.4.1) 。
5525+直接保留解析结果中项的类型,不按成员访问规则确定值类别,因此和解析名称表达式的结果总是左值(@11.2) 不同,可保留消亡值(@5.7.6.1) 。
53105526 $move-resolved! <symbol> :转移解析标识符的对象。
53115527 和 $resolve-identifier 类似,但直接取被绑定的对象并从环境中转移。
53125528 若环境被冻,则复制绑定的对象所在的项;否则,直接转移对象的项(@5.5.3) 。
@@ -5316,74 +5532,74 @@
53165532 使用类似 @5.4.3 的 DFS 搜索操作数的父环境和绑定的对象,若非环境则直接复制值,否则创建环境并递归使用 DFS 复制值。
53175533 当前只支持复制具有 shared_ptr<Environment> 和 EnvrionmentReference 的宿主值的环境,其它对象直接视为非环境对象。
53185534 警告:这个函数仅用于测试时示例构造环境,通常不应被用户程序使用,且可能在未来移除。未确定环境宿主值时可引起未定义行为。
5319-freeze-environment! <environment> :冻结(@9.6.2.4) 环境。
5320-这个操作处理操作数指定的一等环境。对隐藏环境初始化时的相同操作参见 @9.6.2.4 。
5535+freeze-environment! <environment> :冻结(@9.9.3.7) 环境。
5536+这个操作处理操作数指定的一等环境。对隐藏环境(@9.9.3.1) 初始化时的相同操作参见冻结操作(@9.9.3.7) 。
53215537 lock-environment <environment> :锁定环境:创建环境强引用。
53225538 检查操作数的宿主值类型是 NPL::EnvironmentReference ,结果的宿主类型 shared_ptr<Environment> 。
5323-强引用可能引起环境之间的不被检查的循环引用(@9.6.1.1) ,用户应自行避免未定义行为(@5.2.2) 。
5539+强引用可能引起环境之间的不被检查的循环引用(@9.9.1.1) ,用户应自行避免未定义行为(@5.2.2) 。
53245540 make-environment <environment>... :创建以参数为父环境的环境。
53255541 和 Kernel 不同,除对象类型外,没有对列表和绑定的附加检查。
53265542 结果为新创建的环境,是环境强引用,具有宿主值类型 shared_ptr<Environment> 。
53275543 weaken-environment <environment> :使用环境强引用创建环境弱引用。
5328-检查操作数的宿主值类型(@6.9.1) 是 shared_ptr<Environment> ,结果的宿主类型 NPL::EnvironmentReference 。因为 NPLA1 需要精确控制所有权而不依赖 GC(@5.2) ,这可用于派生实现某些操作(如 $sequence(@10.6.1) 必要的)。
5544+检查操作数的宿主值类型(@6.9.1) 是 shared_ptr<Environment> ,结果的宿主类型 NPL::EnvironmentReference 。因为 NPLA1 需要精确控制所有权而不依赖 GC(@5.2) ,这可用于派生实现某些操作(如 $sequence(@11.4.1) 必要的)。
53295545 $def! <definiend> <body> :修改当前环境中的绑定。
5330-类似 Kernel 的 $define! ,但满足 @9.5.2 的约定。
5331-和 Kernel 的 $define! 不同,$def! 和 $defrec! 在求值 <body> 后,进行类型检查(@9.6.2.4) ,确保环境没有被冻结后添加绑定。
5332-和 Kernel 类似,对在 <body> 中某些未被直接求值的子表达式(如 $lambda(@10.5.7) 的 <body>),因为其中的求值依赖 $def! 表达式求值后的环境,在之后仍可以实现递归。
5546+类似 Kernel 的 $define! ,但满足绑定构造(@9.7.3) 的约定。
5547+和 Kernel 的 $define! 不同,$def! 和 $defrec! 在求值 <body> 后,进行类型检查(@9.5.4.1) ,确保环境没有被冻结后添加绑定。
5548+和 Kernel 类似,对在 <body> 中某些未被直接求值的子表达式(如 $lambda(@11.3.8) 的 <body>),因为其中的求值依赖 $def! 表达式求值后的环境,在之后仍可以实现递归。
53335549 由于递归调用依赖环境中的绑定,修改以上定义引入的绑定后可影响被递归函数的调用。
5334-对 <definiend> 中已存在的标识符的绑定,保证直接替换对象的值,对象的引用不失效(@9.6.2.2) 。
5550+对 <definiend> 中已存在的标识符的绑定,保证直接替换对象的值,对象的引用不失效(@9.9.3.6.1) 。
53355551 $defrec! <definiend> <body> :修改绑定,同 $def! ,但在绑定时针对 <definiend> 指定的操作数树(@7.7.4) 中的绑定名称有附加的处理以支持直接递归。
5336-除和 $def! 相同过程的常规绑定(求值 <expression> 和绑定符号)外,支持强递归绑定(@9.5.2.1) ,其操作数树的附加处理分为两阶段;每个阶段深度优先遍历 <definiend> 指定的操作数树,对每个符号进行附加处理:
5552+除和 $def! 相同过程的常规绑定(求值 <expression> 和绑定符号)外,支持强递归绑定(@9.7.3.1) ,其操作数树的附加处理分为两阶段;每个阶段深度优先遍历 <definiend> 指定的操作数树,对每个符号进行附加处理:
53375553 在常规绑定前,每个遍历的待绑定符号在目标环境(被定义影响的环境)中预先进行绑定,保证指称一个对默认对象的弱引用,其中默认对象具有调用总是抛出异常的 A1::ContextHandler 类型(@7.2.1) 的值;和这个弱引用的共享的强引用被临时另行保存。
53385554 在常规绑定后,再次遍历操作数树,对每个 A1::ContextHandler 的值,替换之前在环境中保存的共享定义为默认对象的共享强引用,最后释放先前临时保存的默认对象的强引用。
5339-调用默认对象时,若默认对象的强引用存在,抛出默认对象内置的异常;否则,抛出由对象实现提供的引用不存在的异常。和 vau 抽象对环境的检查(@9.6.2.1) 类似,后者在对象语言中已引起未定义行为,不应被依赖。
5555+调用默认对象时,若默认对象的强引用存在,抛出默认对象内置的异常;否则,抛出由对象实现提供的引用不存在的异常。和 vau 抽象对环境的检查(@9.9.3.5) 类似,后者在对象语言中已引起未定义行为,不应被依赖。
53405556 常规绑定后转移未被 <body> 求值影响的绑定中的默认对象的所有权到环境中,但不影响绑定目标在对象语言中指称的值。
53415557 在环境中未被 <body> 求值替换的绑定,在 $defrec! 求值仍指称默认对象(而不会是持有合并子的宿主类型(@7.6.1.1) 的值),若被作为合并子调用,则显示存在循环递归调用。
53425558 和 $def! 不同,常规绑定后的操作使 <body> 不在尾上下文求值;而因为保证操作数树中的名称已存在默认定义,求值 $defrec! 的 <body> 前时可使用绑定。
53435559 这允许递归定义的名称在绑定完成前指称对象。例如,当环境中未绑定变量 a 和 b 时:
5344-求值表达式 $def! (a b) list b ($lambda () 1) 因为被求值的 b 未被绑定引起错误(@9.4.3.1) ;
5560+求值表达式 $def! (a b) list b ($lambda () 1) 因为被求值的 b 未被绑定引起错误(@9.5.1) ;
53455561 求值表达式 $defrec! (a b) list b ($lambda () 1) 不需要 a 或 b 已被绑定(即便 b 并不在 $lambda 的 <body> 中),求值后 a 为默认对象;
53465562 求值表达式 $defrec! (b &a) list ($lambda () 1) b 绑定要求同上,但求值后 a 可能为默认对象(操作数树中的同级叶节点被未指定的绑定顺序影响)。
5347-这也允许在 $vau/e(@10.5.7) 等表达式的 <environment> 指定的静态环境使 <body> 不能访问目标环境时,直接定义递归函数。
5563+这也允许在 $vau/e(@11.3.8) 等表达式的 <environment> 指定的静态环境使 <body> 不能访问目标环境时,直接定义递归函数。
53485564 递归定义的对象中的值数据成员(@5.4.2) 可能具有共享的持有者。若为合并子,直接调用会利用替换的值重新访问所在的环境。复制和转移这样的值不会改变被访问的环境。若访问的环境失效,则抛出异常,或无限递归调用自身。
5349-特定情形使用 deshare(@10.5.4) 可去除共享和避免以上可能非预期的行为。
5350-另见 @9.6.2 。
5351-
5352-@10.5.7 合并子:
5353-和 Scheme 及 Kernel 不同,<body> 可以是多个项,而不在派生另外的版本支持顺序求值。
5354-引入合并子的操作子不求值 <body> ,后者在被调用时替换操作数以后被求值。这允许安全地使用 $def! 而不需要 $defrec! 进行递归绑定(@10.5.6) 。
5355-创建合并子时对参数指定的求值环境 <environment> 进行类型检查(@9.4.3.4.1) 外,还进行内部的检查确保宿主值非空。
5356-检查失败的错误(@9.4.3.1) 是(可能依赖(@9.4.3.1) 类型错误(@9.4.3.4.1) 的)语法错误(@9.4.3.1) 。
5565+特定情形使用 deshare(@11.3.4) 可去除共享和避免以上可能非预期的行为。
5566+另见环境(@9.9.3) 。
5567+
5568+@11.3.8 合并子:
5569+和 Scheme 及 Kernel 不同,<body> 可以是多个项,而不在派生另外的变体支持顺序求值。
5570+引入合并子的操作子不求值 <body> ,后者在被调用时替换操作数以后被求值。这允许安全地使用 $def! 而不需要 $defrec! 进行递归绑定(@11.3.7) 。
5571+创建合并子时对参数指定的求值环境 <environment> 进行类型检查(@9.5.4.1) 外,还进行内部的检查确保宿主值非空。
5572+检查失败的错误(@9.5.1) 是(可能依赖(@9.5.1) 类型错误(@9.5.4.1) 的)语法错误(@9.5.1) 。
53575573 $vau/e <environment> <formals> <eformal> <body> :创建指定静态环境的 vau 抽象(@4.5.2.3) 。
53585574 创建的对象是操作子(@7.6.1.1) 。
53595575 和 Kernel 不同,因为支持保存环境的所有权,$vau/e 被设计为比 $vau 更基本的操作。
5360-不考虑所有权时,eval(@10.5.6) 和 $vau 可派生 $vau/e 。
5576+不考虑所有权时,eval(@11.3.7) 和 $vau 可派生 $vau/e 。
53615577 $vau/e% <environment> <formals> <eformal> <body> :同 $vau/e ,但保留引用值。
53625578 wrap <combiner> :包装(@4.5.3.2) 合并子为应用子(@7.6.1.1) 。
5363-包装应用子可能符合包装数溢出的错误条件(@9.6.4) 。
5579+包装应用子可能符合包装数溢出的错误条件(@9.9.5) 。
53645580 wrap% <combiner> :同 wrap ,但参数不隐含左值到右值转换,在结果保留引用值。
53655581 unwrap <applicative> :解包装(@4.5.3.2) 应用子为底层的合并子(@7.6.1.1) 。
5366-和 Kernel 不同,参数是右值时子对象被复制,由这些合并子创建的操作子当前仍不足以取代内置的一等操作子,因为不支持只能转移而不能复制的对象。传递这些对象作为操作数会引起构造失败的异常。
5367-
5368-@10.5.8 错误处理和检查:
5369-raise-invalid-syntax-error <string> :引发包含参数指定的字符串内容的语法错误(@9.4.3.1) 。
5582+和 Kernel 不同,参数是右值时子对象(@9.8.2) 被复制,由这些合并子创建的操作子当前仍不足以取代内置的一等操作子,因为不支持只能转移而不能复制的对象。传递这些对象作为操作数会引起构造失败的异常。
5583+
5584+@11.3.9 错误处理和检查:
5585+raise-invalid-syntax-error <string> :引发包含参数指定的字符串内容的语法错误(@9.5.1) 。
53705586 当前实现中引发的错误对象以抛出异常实现,其中异常对象类型具有 public 基类 NPL::InvalidSyntax 。
5371-check-list-reference <object> :检查对象是否是列表引用,若检查通过返回参数,否则引发错误对象(@9.4.3.1) 。
5587+check-list-reference <object> :检查对象是否是列表引用,若检查通过返回参数,否则引发错误对象(@9.5.1) 。
53725588 当前实现中引发错误对象以抛出异常实现,其中异常对象类型是 NPL::ListTypeError(@6.3) 或 NPL::ValueCategoryMismatch(@6.3) 。
53735589
5374-@10.5.9 封装:
5590+@11.3.10 封装:
53755591 () make-encapsulation-type :创建封装类型。
53765592 和 Kernel 类似,结果是三个合并子组成的列表,其元素分别表示用于构造封装类型对象的封装(encapsulate) 构造器、判断封装类型的谓词和用于解封装(decapsulate) 的访问器。
5377-构造器直接使用参数,类似(@10.4.1.1) 中带有 % 的容器构造器;
5593+构造器直接使用参数,类似(@11.2.1.1) 中带有 % 的容器构造器;
53785594 访问器根据参数的值类别转发被封装的值。
53795595 和 [RnRK] 不同,被封装的对象具有被装箱值的所有权,因此需要注意保存被构造的封装对象。
53805596 另见 https://small.r7rs.org/wiki/UniqueTypesSnellPym/ 和 SRFI-137 。
53815597 和 Kernel 及 Scheme 的各种实现(如 http://www.r6rs.org/r6rs-editors/2005-August/000831.html )不同,对相同类型的封装对象,eqv? 和 equal? 基于被封装对象的子对象(及子对象被引用的对象)递归比较,即使用封装的对象的 equal? 定义 eqv? 结果。
5382-另见 @4.1.4.3 。
5383-
5384-@10.6 基础派生操作(grounded derived operations) :
5385-根环境接口(@10.1) 中,除 @10.5 及模块外的剩余接口可通过既有对象语言提供的接口实现,或依赖其它实现特定的互操作接口的本机实现(@5.2.1) 组合实现。
5386-@10.6.1 的操作可使用派生实现(可能需要使用 @10.5 或 @10.6.1 中的部分非派生实现),但因为性能等原因在 NPLA1 API 中提供直接支持的本机实现(@10) 。
5598+另见等价谓词的设计用例(@4.1.4.3) 。
5599+
5600+@11.4 基础派生特性(grounded derived feature) :
5601+根环境特性(@10.2) 中,除 @11.3 及模块外的剩余接口可通过既有对象语言提供的接口实现,或依赖其它实现特定的互操作(@2.3.3) 接口的本机实现(@5.2.1) 组合实现。
5602+基本派生特性(@11.4.1) 可使用派生实现(可能需要使用 @11.3 或 @11.4.1 中的部分非派生实现),但因为性能等原因在 NPLA1 API 中提供直接支持的本机实现(@10) 。
53875603 这些操作的派生实现同时在 NPL::Dependency 模块内被给出作为替代实现。
53885604 启用本机实现使用以下实现选项(@7.1) 控制:
53895605 NPL_Impl_NPLA1_Native_Forms
@@ -5391,52 +5607,52 @@
53915607 NPL_Impl_NPLA1_Use_Id_Vau
53925608 NPL_Impl_NPLA1_Use_LockEnvironment
53935609 不直接使用本机实现的替代实现仅供参考,可能引入和本机实现不同的未指定行为,且可能有和核心特性实现相关的限制:
5394-由合并子调用的参数绑定(@8.4.5.3) 引起(@9.4.3.1) 的静态语法错误(@9.4.3.1) 可能具有不同的诊断(@9.4.3) ;
5395-类型检查(@9.4.3.4.1) 可具有不同的顺序,多次失败的类型检查引起的类型错误可能具有不同的诊断;
5396-使用 TCO 实现 PTC(@9.4.8) ,可能具有不同的支持(@9.4.8.1) 和实现(如 @7.10.8 );
5397-@10.2 约定的关于一般操作实现的一些未指定行为,特别地,包括续延名称(@7.11.6) 的差异。
5398-注意和 [RnRK] 合并子的派生完全省略错误处理而允许不同的诊断不同,NPLA1 中的操作的替代实现的没有被以上例外或操作自身的语义指定的其它行为(如诊断(@9.4.3) )仍应和本机实现保持一致。
5399-
5400-@10.6.1 基本派生操作:
5401-引入合并子的操作子对 <body> 的约定同 @10.5.7 。
5402-因为互相依赖,一些操作实现为派生操作时,不能用于直接派生特定一些其它操作。
5403-和 $vau/e 或 $vau/e%(@10.5.7) 不同,不指定静态环境的合并子构造器隐含总是使用环境弱引用(@5.4.3) 形式的静态环境,以避免过于容易引入循环引用(@9.6.1.1) 。另见 @5.4.3 。
5610+由合并子调用的参数绑定(@8.4.5.3) 引起(@9.5.1) 的静态语法错误(@9.5.1) 可能具有不同的诊断(@9.5) ;
5611+类型检查(@9.5.4.1) 可具有不同的顺序,多次失败的类型检查引起的类型错误可能具有不同的诊断;
5612+使用 TCO 实现 PTC(@9.7.4) ,可能具有不同的支持(@9.7.4.1) 和实现(如 TCO 动作消除(@7.10.8) );
5613+@10.9 约定的关于一般操作实现的一些未指定行为,特别地,包括续延名称(@7.11.6) 的差异。
5614+注意和 [RnRK] 合并子的派生完全省略错误处理而允许不同的诊断不同,NPLA1 中的操作的替代实现的没有被以上例外或操作自身的语义指定的其它行为(如诊断(@9.5) )仍应和本机实现保持一致。
5615+
5616+@11.4.1 基本派生特性(basic derived feature) :
5617+引入合并子的操作子对 <body> 的约定同 @11.3.8 。
5618+因互相依赖,一些操作实现为派生操作时,不能用于直接派生特定一些其它操作。
5619+和 $vau/e 或 $vau/e%(@11.3.8) 以及 $lambda/e 或 $lambda/e%(@11.4.2) 不同,不指定静态环境的合并子构造器隐含总是使用环境弱引用(@5.4.3) 形式的静态环境,以避免过于容易引入循环引用(@9.9.1.1) 。另见环境数据结构(@5.4.3) 。
54045620 () get-current-environment :取当前环境:取当前环境的环境弱引用。
54055621 结果具有宿主值类型 NPL::EnvironmentReference 。派生需要非派生实现的 vau/e 。
54065622 () lock-current-environment :锁定当前环境:取当前环境的环境强引用。
54075623 结果具有宿主值类型 shared_ptr<Environment> 。
54085624 $vau <formals> <eformal> <body> :创建 vau 抽象(@4.5.2.3) 。
5409-类似 $vau/e(@10.5.7) ,但以当前环境代替额外的求值环境作为静态环境。
5410-和 Kernel 不同,可通过 $vau/e(@10.5.7) 和(非派生的)get-current-environment 派生,不是基本操作(@10.5) 。
5411-$vau% <formals> <eformal> <body> :同 $vau(@10.6.1) ,但保留引用值。
5412-$quote <expression> 求值引用操作。结果为返回值转换(@5.7.4.4) 后的未被求值的操作数。
5625+类似 $vau/e(@11.3.8) ,但以当前环境代替额外的求值环境作为静态环境。
5626+和 Kernel 不同,可通过 $vau/e(@11.3.8) 和(非派生的)get-current-environment 派生,不是基本操作(@11.3) 。
5627+$vau% <formals> <eformal> <body> :同 $vau(@11.4.1) ,但保留引用值。
5628+$quote <expression> 求值引用操作。结果为返回值转换(@5.7.6.4) 后的未被求值的操作数。
54135629 考虑通常引用操作对符号类型未被求值的左值操作数使用,保留引用值没有意义,因此不提供对应保留引用值的操作。
5414-这个函数的使用在实现中受限制,参见 @10.2 。
5630+这个函数的使用在实现中受限制(@10.9) 。
54155631 id <object> :结果为不隐含左值到右值转换的参数,在结果保留引用值。
54165632 其作用等价返回值转换,可能引起对象转移(@5.5.6.2) 。
5417-idv <object> :同 id ,但结果为返回值转换(@5.7.4.4) 后的值。
5633+idv <object> :同 id ,但结果为返回值转换(@5.7.6.4) 后的值。
5634+使用 idv 可指定在返回值中保留引用值的不安全操作(@10.8.1) 的个别操作数不再保留引用值。
54185635 list <object>... :创建列表(类型为 <list> )对象。
54195636 list% <object>... :同 list ,但每个参数都不隐含左值到右值转换,在结果保留引用值。
54205637 $deflazy! <definiend> <body> :修改绑定。
5421-同 $def! ,但不求值参数;在添加绑定前仍对冻结环境进行检查(@10.5.6) 。
5638+同 $def! ,但不求值参数;在添加绑定前仍对冻结环境进行检查(@11.3.7) 。
54225639 $set! <environment> <formals> <body> :修改指定环境的变量绑定。
5423-在当前环境求值 <environment> 和 <body> ,再以后者的求值结果修改前者的求值结果指定的环境中的绑定。绑定效果同使用 $def!(@10.5.6) 。
5640+在当前环境求值 <environment> 和 <body> ,再以后者的求值结果修改前者的求值结果指定的环境中的绑定。绑定效果同使用 $def!(@11.3.7) 。
54245641 类似 Kernel 的 $set! 。注意 <body> 的形式不同。允许的递归操作参见 $def! 。
54255642 和 Kernel 不同而和 NPLA1 的 $def! 等类似,在修改绑定前对冻结环境进行检查。
5426-$setrec! <environment> <formals> <body> :修改指定环境的绑定,绑定效果同使用 $defrec!(@10.5.6) 。
5643+$setrec! <environment> <formals> <body> :修改指定环境的绑定,绑定效果同使用 $defrec!(@11.3.7) 。
54275644 同 $set! ,但允许不同的递归操作,参见 $defrec! 。
54285645 $lambda <formals> <body> :创建 λ 抽象(@4.5.2.2) 。
54295646 和创建 vau 抽象类似,但创建的是调用时对操作数的元素求值一次的应用子(@7.6.1.1) ,且忽略动态环境。
5430-可通过 vau 抽象或 $lambda/e 和(非派生的)get-current-environment 派生。
5647+可通过 vau 抽象或 $lambda/e(@11.4.2) 和(非派生的)get-current-environment 派生。
54315648 表达式项的用法和 vau 抽象类似。
5432-和 $lambda/e 不同,隐含总是使用弱引用的静态环境,以避免过于容易引入循环引用(@9.6.1.1) 。另见 @5.4.3 。
54335649 $lambda% <formals> <body> :同 $lambda ,但允许函数体求值返回引用值。
54345650 $sequence <expression-sequence> :顺序求值。
54355651 操作数非空时结果是最后的参数,可能是引用值。
54365652 类似 Kernel 的同名操作。
5437-求值每个 <object> 的副作用包括其中临时对象的销毁都被顺序限制,类似宿主语言的语句而不是保证子表达式中的临时对象的生存期延迟到完全表达式求值结束的逗号表达式。这也允许实现和 [RnRK] 同名操作类似的 PTC 要求。
5653+求值每个 <object> 的副作用包括其中临时对象(@5.2.4.2) 的销毁都被顺序限制,类似宿主语言的语句而不是保证子表达式中的临时对象的生存期延迟到完全表达式求值结束的逗号表达式。这也允许实现和 [RnRK] 同名操作类似的 PTC 要求。
54385654 collapse <object> :折叠可能是引用的值。
5439-forward <object> :转发(@9.8.4) 可能是引用的值(@10.4.2.4) 。
5655+forward <object> :转发(@10.5.4) 可能是引用的值(@11.2.2.4) 。
54405656 按在所在的环境中解析的操作数的类型可选地提升项(@6.6) 作为结果,其作用 id 或 idv 之一。
54415657 被转发的值若是形式参数树(@7.7.3) 中的变量,一般应以带有标记字符 & 的形式绑定(@7.7.3.4) ;否则,转发的不是对应的实际参数,而可能是其按值绑定的副本。
54425658 转移(而不是复制)可修改的右值操作数。注意若右值操作数不可修改(如本机实现引入带有 TermTags::Nonmodifying 标签(@5.4.2.2) 的引用操作数),复制不可复制构造的宿主对象会失败。
@@ -5444,11 +5660,11 @@
54445660 forward! <object> :同 forward ,但除转移右值操作数外,也转移(而不是复制)可修改的临时对象操作数。
54455661 其中,需转移时,使用使用项的转移(@5.5.3) 。这和对象的转移(@5.5.2.3) 不同,不保证调用宿主实现的转移构造函数。
54465662 本机实现使用 NPL::MoveRValueToForward(@6.6.3) 可简化操作。
5447-这个函数类似宿主语言以对象类型参数和推断的函数参数类型作为模板参数调用 std::forward ,但若需转移,直接转移而非如 expire(@10.5.2) 返回指定结果是消亡值(@5.5.1) 的唯一引用(@5.4.2.2) 。
5663+这个函数类似宿主语言以对象类型参数和推断的函数参数类型作为模板参数调用 std::forward ,但若需转移,直接转移而非如 expire(@11.3.2) 返回指定结果是消亡值(@5.5.1) 的唯一引用(@5.4.2.2) 。
54485664 和宿主语言不同,直接转移允许区分消亡值和纯右值,同等地作为一等对象(如作为列表的元素)。
54495665 apply <applicative> <object> <environment> :在指定环境中应用。
54505666 和 Kernel 的参考派生不同,检查 <environment> 确保为一个对象。
5451-apply <applicative> <object> :在新环境(@9.6.2) 中应用。
5667+apply <applicative> <object> :在新环境(@9.9.3) 中应用。
54525668 以上 apply 的函数值保留引用值。
54535669 list* <object>+ :在列表前附加元素创建列表。
54545670 类似 cons ,但支持一个和多个操作数。
@@ -5459,29 +5675,29 @@
54595675 对参数列表 (&list-appv &appv &l) ,结果定义为和以下求值表达式等价:
54605676 ($lambda% ((&x .)) (forward! appv) ($move-resolved! x)) ((forward! list-appv) l) ;
54615677 其中,调用 (forward! list-appv) 和 (forward! appv)(除参数求值外)的动态环境同调用 forward-list-first% 的动态环境。
5462-assign%! <reference> <object> :同 assign@!(@10.5.4) ,但 <object> 是引用时被折叠。
5678+assign%! <reference> <object> :同 assign@!(@11.3.4) ,但 <object> 是引用时被折叠。
54635679 assign! <reference> <object> :同 assign%! ,但 <object> 隐含左值到右值转换。
54645680 set-first! <list> <object> :修改列表的第一个元素。
54655681 和 Kernel 的 set-car! 类似,但可派生,检查列表是左值,且不保留引用值。
54665682 set-first@! <list> <object> :同 set-first%! ,但保留未折叠的引用值。
54675683 set-first%! <list> <object> :同 set-first! ,但保留引用值。
5468-不检查修改操作(@9.4.5.1) 导致循环引用,用户应自行避免未定义行为(@5.2.2) 。
5684+不检查修改操作(@9.8.3) 导致循环引用,用户应自行避免未定义行为(@5.2.2) 。
54695685 first <list> :取列表第一个元素的值。
54705686 类似传统 Lisp 及 Kernel 的 car 。命名和 SRFI-1 及 Clojure 等现代变体一致。
5471-当 <list> 是左值时结果是折叠的引用值,否则结果是返回值转换(@5.7.4.4) 后的值。
5687+当 <list> 是左值时结果是折叠的引用值,否则结果是返回值转换(@5.7.6.4) 后的值。
54725688 first@ <list> :同 first ,但结果总是未折叠的引用值。
5473-first& <list> :同 first ,但结果总是折叠的引用值,且首先调用 check-list-reference(@10.5.8) 检查参数是列表引用,对右值的抛出异常。
5689+first& <list> :同 first ,但结果总是折叠的引用值,且首先调用 check-list-reference(@11.3.9) 检查参数是列表引用,对右值的抛出异常。
54745690 firstv <list> :同 first ,但结果总是返回值转换后的值。
5475-equal? <object> <object> :一般相等关系。类似 eqv?(@10.5.2) ,但同时支持表示中具有子项作为子对象的对象。
5691+equal? <object> <object> :一般相等关系。类似 eqv?(@11.3.2) ,但同时支持表示中具有子项作为子对象(@9.8.2) 的对象。
54765692 相等定义为:
54775693 对叶节点,同 eqv? ;
54785694 否则,同 eqv? 且每个子节点对应满足 eqv?(蕴含节点数量相等)。
54795695 类似 Kernel 和 Scheme 的 equal? 的二元谓词,但在此保证可通过 eqv? 直接构造。:
5480-因为列表的性质(@9.6.3) ,不需要支持循环引用(@9.6.1.1) ,可以直接派生。后者被视为基本的抽象而非实现细节。
5696+因为列表的性质(@9.9.4) ,不需要支持循环引用(@9.9.1.1) ,可以直接派生。后者被视为基本的抽象而非实现细节。
54815697 check-environment <environment> :检查环境。
5482-检查环境通过的条件同创建合并子时的检查(@10.5.7) 。
5483-若检查通过,返回转发的参数,否则引发错误(@9.4.3.1)。
5484-引发的错误对象和创建合并子时环境检查失败引发的错误对象,或其依赖(@9.4.3.1) 的错误对象(后者保证不是语法错误(@7.8.2) )。
5698+检查环境通过的条件同创建合并子时的检查(@11.3.8) 。
5699+若检查通过,返回转发的参数,否则引发错误(@9.5.1)。
5700+引发的错误对象和创建合并子时环境检查失败引发的错误对象,或其依赖(@9.5.1) 的错误对象(后者保证不是语法错误(@7.8.2) )。
54855701 $cond <clauses> :条件选择。
54865702 类似 Kernel 的同名操作,但 <test> 的判断条件和 <body> 形式不同。
54875703 $when <test> <expression-sequence> :条件成立时顺序求值。
@@ -5505,16 +5721,16 @@
55055721 处理抽象的列表的操作通过余下的应用子分别定义:取列表头、取列表尾和部分和的二元合并操作。
55065722 accr <object1> <predicate> <object2> <applicative1> <applicative2> <applicative3> :在抽象列表的元素上应用右结合的二元操作。
55075723 操作方式同 accl 。
5508-和 accl 不同,可保证合并操作是尾调用;相应地,递归调用不是尾上下文而无法确保 PTC(@9.4.8.1) 。
5724+和 accl 不同,可保证合并操作是尾调用;相应地,递归调用不是尾上下文而无法确保 PTC(@9.7.4.1) 。
55095725 foldr1 <applicative> <object> <list> :同 accr ,但指定谓词为 null? ,应用子分别为 first 和 rest 。
5510-同 SRFI-1 的 fold-right ,但只接受一个真列表(@9.6.3) 。
5726+同 SRFI-1 的 fold-right ,但只接受一个真列表(@9.9.4) 。
55115727 名称中的 1 指 <list> 参数的个数。
55125728 map1 <applicative> <list> :单列表映射操作:使用指定应用子对列表中每个参数进行调用,结果为调用结果的列表。
5513-参数 <applicative> 应接受一个参数,否则引起错误。
5729+参数 <applicative> 应接受一个参数,否则引起错误(@9.5.1) 。
55145730 任意两个调用之间的相对求值顺序未指定。
5515-类似 Kernel 的 map ,但只接受一个真列表(@9.6.3) 。
5516-
5517-@10.6.2 核心库(core library) :
5731+类似 Kernel 的 map ,但只接受一个真列表(@9.9.4) 。
5732+
5733+@11.4.2 核心库(core library) :
55185734 本节约定以下求值得到的操作数:
55195735 <box> :箱(@4.2.3.5.3) 。
55205736 核心库提供以下操作,即核心库函数:
@@ -5532,20 +5748,20 @@
55325748 $lambda/e% <environment> <formals> <body> :同 $lambda/e ,但保留引用值。
55335749 $defl/e! <variable> <environment> <formals> <body> :绑定指定静态环境的 λ 抽象,等价 $def! <variable> $lambda/e <environment> <formals> <body> 。
55345750 $defl/e%! <variable> <environment> <formals> <body> :绑定指定静态环境的 λ 抽象,等价 $def! <variable> $lambda/e% <environment> <formals> <body> 。
5535-rest <list> :取列表第一个元素以外的元素值构成的列表。
5751+restv <list> :取列表第一个元素以外的元素值构成的列表。
55365752 rest& <list> :同 rest ,但在返回的列表值中的元素是引用值,且首先调用 check-list-reference 检查参数是列表引用,对右值的抛出异常。
55375753 rest% <list> :同 rest ,但在返回的列表值中的元素可能是传递的引用值。
5538-() make-standard-environment 创建标准环境:创建没有其它绑定的环境。
5539-根环境是新创建环境的唯一父环境。类似 Kernel 的 make-standard-kernel-environment 。
5754+() make-standard-environment 创建标准环境:创建没有基础环境绑定外其它绑定的环境。
5755+新创建环境的唯一父环境是基础环境(@10.1) 。类似 Kernel 的 make-standard-kernel-environment 。
55405756 box <object> 装箱:构造箱(类型为 <box> 的对象)。
55415757 box% <object> 同 box ,但参数不隐含左值到右值转换,在结果保留引用值。
55425758 box? <object> 判断是否为 <box> 类型的对象。
55435759 unbox <box> 拆箱:从箱中还原对象。作为传递操作,保留引用值。
5544-以上 4 个函数除引用标记字符(@9.9) 对应处理引用值的差异外,功能和使用方式对应类似 SRFI-111 的 3 个过程 box 、box? 和 unbox 。
5545-类型分区(@9.4.7) 使 box? 对 <list> 类型的参数的结果总是 #f 。若没有这个限制,用以下 <list> 的相关操作可整体替换进行功能等价的代替:
5760+以上 4 个函数除引用标记字符(@10.7) 对应处理引用值的差异外,功能和使用方式对应类似 SRFI-111 的 3 个过程 box 、box? 和 unbox 。
5761+类型分区(@9.8.7) 使 box? 对 <list> 类型的参数的结果总是 #f 。若没有这个限制,用以下 <list> 的相关操作可整体替换进行功能等价的代替:
55465762 用 list 、list% 和 first 可代替 box 、box% 和 unbox 。
55475763 和 http://community.schemewiki.org/?scheme-faq-language 关于装箱的描述不同,这样的代替不一定保证有更好的性能。
5548-以上这些函数可使用 make-encapsulation-type(@10.5.9) 实现。
5764+以上这些函数可使用 make-encapsulation-type(@11.3.10) 实现。
55495765 和 Scheme 等不同,箱具有被装箱对象的所有权,因此使用 box% 和 unbox 时,需注意保存被构造的箱或被箱中引用值引用的对象。
55505766 first-null? <list> :复合 first 和 null? 操作。可用于实现 nonfoldable? 的检查中的单个项。
55515767 list-rest% <list> :复合 list% 和 rest% 操作。可用于解析 <bindings> ,去除其中每个元素的符号项构成新的列表。
@@ -5555,14 +5771,19 @@
55555771 顺序查找列表中的元素,若列表的元素的第一个值以 eqv? 判断和参数指定的对象相等,则结果为这个元素转发的值;
55565772 否则,值为空列表。
55575773 类似 Kernel 的 assoc ,但使用 eqv? 而不是 equal? ,且转发参数。
5558-和 Scheme 的 assv 类似,但失败的值不返回 #f ,尽管和 Kernel 相同而和 Scheme 不同,<test> 支持非布尔类型的值(@10.5.3) 。
5774+和 Scheme 的 assv 类似,但失败的值不返回 #f ,尽管和 Kernel 相同而和 Scheme 不同,<test> 支持非布尔类型的值(@11.3.3) 。
55595775 derive-current-environment <environment>... :创建当前环境的派生环境。
55605776 创建参数指定的环境和当前环境作为父环境的空环境。
5777+父环境顺序同参数顺序。
5778+derive-environment <environment>... :创建基础环境的派生环境。
5779+创建参数指定的环境和基础环境作为父环境的空环境。
5780+父环境顺序同参数顺序。基础环境是最后一个父环境。
5781+类似 make-standard-environment ,但具有参数指定的环境作为其它的父环境。
55615782 $as-environment <body> :求值表达式构造环境。
55625783 创建以动态环境为父环境的空环境,并在其中求值参数指定的表达式。
55635784 结果是创建的环境强引用。
55645785 $let <bindings> <body> :局部绑定求值:创建以当前环境为父环境的空环境,在其中添加 <bindings> 指定的变量绑定,再求值 <body> 。
5565-类似 Kernel 的同名操作,但返回非引用值(@9.6.1.4) 。
5786+类似 Kernel 的同名操作,但返回非引用值(@10.4.2) 。
55665787 创建的环境同合并子的局部环境(@8.4.5) 。
55675788 $let% <bindings> <body> :同 $let ,但保留引用值。
55685789 当前派生使用 $lambda% 而不是 $lambda 实现。
@@ -5585,15 +5806,21 @@
55855806 使用 make-environment 而不是 $let/e 等绑定构造实现。
55865807 $bindings->environment <binding>... :转换绑定列表为没有父环境的具有这些绑定的环境。
55875808 类似 Kernel 的同名操作,但因为要求对内部父环境环境所有权,使用 $binding/p->environment 而不是 $let/e 等绑定构造实现。
5809+symbols->imports! <symbol>... :转换符号列表为未求值的适合初始化符号导入列表的初值符列表。
5810+结果是包含同 desigil(@11.3.6) 的方式移除标记字符(@9.2.2.4) 后的参数作为间接子项的列表。求值这个列表,结果是同 forward!(@11.4.1) 的方式转发每个符号的列表。
5811+类似 Kernel 的 $provide! 和 $import! 提供符号列表的方式,但有以下不同:
5812+支持移除引用标记字符;
5813+支持转发参数;
5814+不带有引用标记字符和符号指称的对象不是临时对象(@5.2.4.2) 的默认情形复制值而不是初始化引用。
55885815 $provide/let! <symbols> <bindings> <body> :在当前环境中提供绑定:蕴含 $let <bindings> <body> ,在求值 <body> 后以结果作为操作数绑定到 <symbols> 的符号。
55895816 <symbols> 应能被作为 <defindend> 使用。
55905817 结果是对这些绑定具有所有权的环境强引用。
5591-绑定后的符号可通过作为 vau 抽象的父环境(@9.6.2.1) 等形式依赖这个环境,因此用户需适当保存返回值使其生存期(@9.6.2.1) 覆盖在被使用的绑定符号指称的对象生存期。
5818+绑定后的符号可通过作为 vau 抽象的父环境(@9.9.3.5) 等形式依赖这个环境,因此用户需适当保存返回值使其生存期(@9.9.3.5) 覆盖在被使用的绑定符号指称的对象生存期。
55925819 $provide! <symbols> <body> :在当前环境中提供绑定:同 $provide/let! 但不指定单独的 <bindings> 。
55935820 作用同 <bindings> 为空列表的 $provide/let! 。
5594-类似 Kernel 的同名操作,但结果是创建的环境的强引用。
5821+类似 Kernel 的同名操作,但结果是创建的环境的强引用,且以同 symbols->imports! 的方式确定初值符。
55955822 $import! <environment> <symbols> :从第一参数指定的环境导入第二参数指定的符号。
5596-类似 Kernel 的同名操作。
5823+类似 Kernel 的同名操作,但以同 symbols->imports! 的方式确定初值符。
55975824 nonfoldable? <list> :判断参数是否不可被继续折叠映射:存在空列表。
55985825 输入类似 Kernel map 操作可接受的列表参数或空列表。若输入是空列表,结果为 #f 。
55995826 list-extract <list> <applicative> :以指定应用子在指定列表中选取并合并内容为新的列表。
@@ -5604,28 +5831,29 @@
56045831 对参数列表 (&l &extr) ,结果同求值 list-extract ls rest% 。
56055832 list-push-front! <list> <object> :在列表前插入元素。参数被转发。
56065833 map-reverse <applicative> <list>... :映射并反转结果。
5607-参数 <applicative> 应满足以下要求,否则引起错误:
5834+参数 <applicative> 应满足以下要求,否则引起错误(@9.5.1) :
56085835 <list>... 中的参数的元素数都相等;
56095836 <list>... 中的参数的元素数量等于 <applicative> 接受的形式参数的元数。
56105837 映射类似 Kernel map 操作,但支持空的 <list>... 且保证顺序。
56115838 for-each-ltr <applicative> <list>... :从左到右映射取副作用。
56125839 类似 Kernel 的 for-each 但支持空的 <list> 且保证顺序。
56135840
5614-@11 NPLA1 参考实现扩展环境:
5615-和 @10.5 和 @10.6 类似,NPLA1 以根环境的形式提供其它一些模块(@10.1) 的操作。
5841+@12 NPLA1 参考实现扩展环境:
5842+和 @11.3 和 @11.4 类似,NPLA1 以根环境(@10.1) 的形式提供其它一些模块(@10.2) 的操作。
5843+这些模块和 @10 的提供的特性一同构成了标准库(@10.3.3) 。
56165844 因为可移植性和模块化等原因,这些操作不直接引入基础上下文(@8.5.2) 的根环境中。
5617-这允许实现使用特殊的环境子类型延迟加载(@10.1.1)(当前 NPLA1 没有提供支持)。
5845+这允许实现使用特殊的环境子类型延迟加载(@10.2)(当前 NPLA1 没有提供支持)。
56185846 这也允许作为实现的用户程序可选地支持这些操作。作为被加载的模块的环境的名称由具体用户程序决定。
5619-修改(@9.4.5.1) 这些环境的程序行为未定义。
5847+修改(@9.8.3) 这些环境的程序行为未定义。
56205848 默认加载使用 . 分隔标识符得到的符号作为名称,类似 CHICKEN Scheme 的转换 R7RS 的标准模块名(参见 http://wiki.call-cc.org/eggref/4/r7rs#import )。
5621-除 @11.2 外的模块在 SHBuild 使用默认加载。
5849+除 @12.2 外的模块在 SHBuild 使用默认加载。
56225850 加载的模块依赖根环境,需通过 Forms::LoadGroundContext(@8.5.2) 或等价的方式初始化。
56235851 当前实现中部分加载的环境依赖之前加载的环境,这些环境的名称是固定的。用户程序需要保证这些环境在加载时的静态环境中可用。
5624-用户程序需保持加载为环境的模块具有适当的生存期(@9.6.2.1) ,以避免其中的合并子调用引起未定义行为。
5625-
5626-@11.1 环境:
5852+用户程序需保持加载为环境的模块具有适当的生存期(@9.9.3.5) ,以避免其中的合并子调用引起未定义行为。
5853+
5854+@12.1 环境:
56275855 通过初始化基础上下文后调用 Forms::LoadModule_std_environments(@8.5.2) 初始化,默认加载为根环境下的 std.environments 环境。
5628-当前实现依赖可用的 std.strings 环境(@11.3) 。
5856+当前实现依赖可用的 std.strings 环境(@12.3) 。
56295857 bound? <string> :判断指定字符串对应的符号是否被绑定。
56305858 $binds1? <environment> <symbol> :判断指定符号是否在指定表达式求值后指称的环境中绑定。
56315859 和 Kernel 中的 $binds? 类似但只支持判断一个符号。
@@ -5638,50 +5866,52 @@
56385866 类似 eval-string ,但保留引用值。
56395867 eval-unit <string> <object> :在参数指定的 REPL 环境中规约字符串表示的翻译单元以求值
56405868
5641-@11.2 代理求值:
5869+@12.2 代理求值:
56425870 通过初始化基础上下文后调用 Forms::LoadModule_std_promises(@8.5.2) 初始化,默认加载为根环境下的 std.promises 环境。
56435871 本节约定以下求值得到的操作数:
56445872 <promise> :求值代理:表示可被求值的封装结果。
5645-除 $laze/e 外,同 [RnRK] 的 promises 模块,但当前不支持 PTC(@9.4.8) 。
5873+除 $laze/e 外,同 [RnRK] 的 promises 模块,但当前不支持 PTC(@9.7.4) 。
56465874 promise? <object> :判断是否为 <promise> 类型的对象。
56475875 memoize <object> :记忆化求值。
5648-$lazy <body> :创建 promise 对象,延迟求值。
5876+$lazy <body> :创建求值代理对象,延迟求值。
56495877 $lazy/e <environment> <body> :同 $lazy ,但以指定环境替代动态环境。
56505878 force <promise> :立即求值指定的 promise 对象。
56515879
5652-@11.3 字符串:
5880+@12.3 字符串:
56535881 通过初始化基础上下文后调用 Forms::LoadModule_std_strings(@8.5.2) 初始化,默认加载为根环境下的 std.strings 环境。
56545882 本节约定以下求值得到的操作数:
56555883 <regex> :正则表达式。
56565884 正则表达式以 std::regex 类型表示,实现保证可通过 string 初始化。
56575885 ++ <string>... :字符串串接。
56585886 string-empty? <string> :判断字符串是否为空。
5659-string<- <string1> <string2> :字符串赋值(@9.4.5.1.1) 。
5660-string-contains-ci? <string1> <string2> :判断忽略大小写的字符串中前者是否包含后者。
5661-symbol->string <symbol> :转换符号为字符串。
5887+string<- <string1> <string2> :字符串赋值(@9.8.3.1) 。
5888+以第二参数为源,修改第一参数指定的目标。
5889+string-contains-ci? <string1> <string2> :判断第一参数是否包含第二参数作为子串,忽略大小写。
5890+只在单字节字符集内的字符中区分大小写。
56625891 string->symbol <string> :转换字符串为符号。
5892+symbol->string <symbol> :转换符号为字符串。
56635893 不检查值是否符合符号要求。
5664-regex->string <string> :创建字符串初始化的正则表达式。
5665-regex-match? <string> <regex> :在字符串中搜索正则表达式指定的模式串
5666-
5667-@11.4 输入/输出:
5894+string->regex <string> :创建字符串初始化的正则表达式。
5895+regex-match? <string> <regex> :在字符串中搜索正则表达式指定的模式串。
5896+
5897+@12.4 输入/输出:
56685898 通过初始化基础上下文后调用 Forms::LoadModule_std_io(@8.5.2) 初始化,默认加载为根环境下的 std.io 环境。
56695899 puts <string> :输出字符串(视为 NTCTS(@5.11.1) )和换行并刷新缓冲。
56705900 实现使用 REPLContext::GetOutputStreamRef(@7.8.1) 。
56715901 在使用前,一般应初始化 REPLContext::OutputStreamPtr(@7.8.1) 指向特定的 std::ostream 对象;否则,总是失败引发错误。
5672-load <string> :加载参数指定的翻译单元作为源的模块(@10.1.1) 。
5673-加载时创建新环境(@9.6.2) ,以此为当前环境读取翻译单元后求值,以求值后的这个环境对象作为调用的结果。
5902+load <string> :加载参数指定的翻译单元作为源的模块(@10.2) 。
5903+加载时创建新环境(@9.9.3) ,以此为当前环境读取翻译单元后求值,以求值后的这个环境对象作为调用的结果。
56745904 当前实现中,参数为文件系统路径。
56755905 被加载的翻译单元视为对象的外部表示(@4.1.1) ,经读取翻译为 NPLA1 对象。
56765906 类似 klisp 的同名操作。类似地,不使用 klisp 的 find-required-filename 机制,直接以宿主的运行环境为基准使用路径。
56775907 和 klisp 不同,在尾上下文中求值被加载后读取的对象,并以其求值结果作为表达式的求值结果。
56785908 [Shu09] 缺少 load 的详细描述而仅有标题。
5679-注意 http://klisp.org/docs/Ports.html#Ports 的 load 描述中求值环境有误,按 [Shu09] 一致的描述和实际实现,应为使用当前环境,而非同 [Shu09] 的 get-module 的使用创建的环境(即新环境(@9.6.2) )。
5909+注意 http://klisp.org/docs/Ports.html#Ports 的 load 描述中求值环境有误,按 [Shu09] 一致的描述和实际实现,应为使用当前环境,而非同 [Shu09] 的 get-module 的使用创建的环境(即新环境(@9.9.3) )。
56805910 和 [R7RS] 不同,load 不支持指定环境,而总是使用当前环境。类似 Kernel ,当前环境可通过不同机制改变,而不需由 load 提供特设的支持。
56815911
5682-@11.5 系统:
5912+@12.5 系统:
56835913 通过初始化基础上下文后调用 Forms::LoadModule_std_system(@8.5.2) 初始化,默认加载为根环境下的 std.system 环境。
5684-当前实现依赖可用的 std.strings 环境(@11.3) 。
5914+当前实现依赖可用的 std.strings 环境(@12.3) 。
56855915 () cmd-get-args :返回宿主环境(@2.7.1) 程序接受的命令行参数列表。
56865916 其中参数数组保存在函数 YSLib::LockCommandArguments 访问的对象中。
56875917 传递给 REPL 的命令行参数通常是宿主程序中主函数的 argv 参数数组中处理后去除特定参数后的程序。
@@ -5700,10 +5930,10 @@
57005930 带空格或水平制表符的字符串、以半角引号开始或结束的字符串和空字符串会被引用。
57015931 remove-file <string> :移除参数指定的路径命名的文件。
57025932
5703-@11.6 SHBuild 操作:
5704-以下互操作接口用于 SHBuild 和外部脚本的构建。
5933+@12.6 SHBuild 特性:
5934+以下互操作(@2.3.3) 特性用于 SHBuild 和外部脚本的构建。
57055935 通过初始化基础上下文后调用 Forms::LoadModule_SHBuild(@8.5.2) 初始化,加载为根环境下的 env_SHBuild_ 环境。
5706-这些接口主要用于内部使用,不保证稳定(特别是带有 _ 后缀的非公开绑定)。
5936+这些特性主要用于内部使用,不保证稳定(特别是带有 _ 后缀的非公开绑定)。
57075937 SHBuild_BaseTerminalHook_ :内部对象,用于终端控制。
57085938 SHBuild_BuildGCH_existed_ <string> :判断参数指定路径的预编译头文件是否存在。
57095939 SHBuild_BuildGCH_mkpdirp_ <string> :在预编译头文件构建时按需创建参数指定的路径的父目录。
@@ -5714,7 +5944,7 @@
57145944 SHBuild_Install_HardLink <string> :以参数为路径安装硬链接。
57155945 SHBuild_QuoteS_ <string> :为字符串添加单引号,以允许在 Shell 代码中使用。
57165946 处理时复用词法分析(@5.3.1) 和语法分析 (@5.3.2) 的部分实现。同 @3.3.4 ,不对空字符特殊处理。
5717-SHBuild_RaiseError_ <string> :引发包含参数指定的字符串内容的错误(@9.4.3.1) 。
5947+SHBuild_RaiseError_ <string> :引发包含参数指定的字符串内容的错误(@9.5.1) 。
57185948 SHBuild_RemovePrefix_ <string1> <string2> :若第二参数是第一参数的前缀则结果是移除前缀的字符串,否则是第一参数。
57195949 SHBuild_SDot_ <string> :替换字符串的点为下划线。
57205950 SHBuild_String_absolute_path?_ <string> :判断字符串的路径是否为绝对路径。
@@ -5725,34 +5955,90 @@
57255955 随机的文件名被打开以检查是否可访问。若失败则重试,当前实现的上限是 16 次(宿主平台)或 1 次(非宿主平台)。
57265956 若最终失败,抛出 std::system_error 异常。
57275957
5728-@12 SHBuild 实现环境:
5958+@13 SHBuild 实现环境:
57295959 SHBuild 实现环境是基于参考 NPLA1 实现环境(@10) 的用于 SHBuild 和外部脚本的构建的初始环境。
57305960 关于 SHBuild 的调用方式说明,详见 https://frankhb.github.io/YSLib-book/SHBuild.zh-CN.html 。
5731-操作约定同 @10 ,包括 @9.7 和 @9.9 。
5732-
5733-@12.1 NPL::Dependency 派生操作:
5734-SHBuild 实现环境由 NPL::Dependency 提供初始的派生操作。
5735-在基础上下文(@8.5.2) 上,SHBuild 实现环境通过切换新环境(@9.6.2) 并调用 Forms::LoadModule_SHBuild(@8.5.2) 初始化。
5736-SHBuild 的基础环境(@10) 的子环境中提供对象引用 env_SHBuild_ ,其中包含这些接口。
5737-部分 SHBuild 互操作接口在 YFramework 的 NPLA1 实现中提供,参见 @11.6 。
5738-此外,NPLA1 在默认实现的 SHBuild_BaseTerminalHook_(@12.1.1) 的实现被覆盖,以使 SHBuild_EchoVar(@12.1.1) 等和 SHBuild 的其它输出兼容。
5739-
5740-@12.2 派生接口:
5741-以下 SHBuild 互操作及脚本调用接口可能在 NPLA1 、SHBuild 工具或外部脚本中实现。
5742-因为相对其它脚本接口,名称保持稳定,也在此提供文档。
5743-
5744-@12.2.1 环境变量缓存:
5961+操作约定同 @10 ,包括 @10.6 和 @10.7 ;但除此之外,遵循 NPLA1 用户程序(@9.1) 的约定。
5962+
5963+@13.1 NPL::Dependency 派生特性:
5964+SHBuild 实现环境由 NPL::Dependency 提供初始的派生特性。
5965+在基础上下文(@8.5.2) 上,SHBuild 实现环境通过切换新环境(@9.9.3) 并调用 Forms::LoadModule_SHBuild(@8.5.2) 初始化。
5966+SHBuild 的基础环境(@10.1) 的子环境中提供对象引用 env_SHBuild_ ,其中包含这些特性。
5967+部分 SHBuild 互操作特性在 YFramework 的 NPLA1 实现中提供,参见 SHBuild 特性(@12.6) 。
5968+此外,NPLA1 在默认实现的 SHBuild_BaseTerminalHook_(@13.1.1) 的实现被覆盖,以使 SHBuild_EchoVar(@13.1.1) 等和 SHBuild 的其它输出兼容。
5969+
5970+@13.2 外部派生特性:
5971+以下 SHBuild 互操作特性及脚本调用接口可能在外部程序(包括提供 NPLA1 实现环境的程序如 SHBuild 工具和 NPLA1 脚本等)中实现。
5972+因为相对其它外部 NPLA1 接口,作用和名称保持稳定,也在此提供文档。
5973+此处的作用会影响加载所在翻译单元的其它翻译单元。
5974+前缀 SHBuild_ 的特性被设计为可被其它程序使用,但接口仍可能改变。部分特性参见外部用户文档 https://frankhb.github.io/YSLib-book/Tools/Scripts.zh-CN.html 。
5975+
5976+@13.2.1 序(prelude) :
5977+除 move!(@11.3.4) 及显式检查类型的赋值(如 string<-(@12.3) )外的不安全操作(@9.4.5) 被禁用,调用时引起错误(@9.5.1) :
5978+assign%!(@11.4.1)
5979+assign@!(@11.4.1)
5980+copy-environment(@11.3.7)
5981+lock-environment(@11.3.7)
5982+$defrec!(@11.3.7)
5983+$setrec!(@11.4.1)
5984+函数 make-standard-environment(@11.4.2) 被重新定义返回禁用了上述操作的环境。
5985+注意派生这些不安全的操作的操作如 lock-current-environment 未被禁用。
5986+
5987+@13.2.2 简单扩展接口:
5988+SHBuild 提供以下可仅依赖标准库(@10.3.3) 派生的可移植操作:
5989+$redef! <definiend> <body> :重定义。
5990+同 $def!(@11.3.7) ,用于显式指定变量绑定在定义的环境中被替换,可能简化安全性证明(@9.4.6.1) 。
5991+当前实现为 $def! 的副本。
5992+$set-if-empty! <variable> <body> :若第一参数指定的变量在当前环境中的值是空字符串,则修改绑定。
5993+修改绑定的作用同当前环境中使用 $set!(@11.4.1) 。
5994+cons-cmd <string>... :串接命令。
5995+参数指定构成命令的字符串。空字符串被忽略。结果是没有被忽略的字符串构成的串接,每个字符串附带一个后缀空格。
5996+rmatch? <string1> <string2> :简单正则匹配。
5997+使用 std.strings(@12.3) 的操作,对参数列表 (x r) ,结果同求值 regex-match? x (string->regex r) 。
5998+putss <string>... :输出串接的字符串。
5999+以 puts(@12.4) 输出参数字符串的串接结果。
6000+system-ok <string> :调用外部命令并判断是否调用成功。
6001+使用 system(@12.5) 调用外部命令。
6002+若 system 调用的值等于 0 ,结果为 #t ;否则,结果为 #f 。
6003+win32? <string> :判断字符串是否等于 "Win32" 。
6004+
6005+@13.2.3 SHBuild 错误和调用例程:
6006+cmd-fail <string> :为参数指定的命令字符串抛出异常。
6007+抛出的异常消息包含参数值。
6008+system-check <string> :调用外部命令并检查。
6009+使用 system-ok(@13.2.2) 调用命令和判断错误。
6010+若调用失败,则使用 cmd-fail 抛出异常。
6011+$set-system-var! <variable> <string> :设置变量绑定的值为命令结果。
6012+若第一参数指定的变量在当前环境中不存在绑定,则修改绑定为调用作为外部命令的第二参数的值的结果。
6013+使用 system-get(@12.5) 调用命令。
6014+判断错误的逻辑同 system-ok(@13.2.2) 。
6015+若调用失败,则使用 cmd-fail 抛出异常。
6016+$assert <variable> <predicate> <string> :断言第一参数指定的变量在当前环境中存在绑定,且其值符合第二参数指定的谓词。
6017+当断言失败时抛出异常。
6018+抛出的异常消息包含第三参数值。
6019+$assert-nonempty <variable> :断言参数指定的变量在当前环境中存在绑定,且其值是非空字符串。
6020+$assert-absolute-path <variable> :断言参数指定的变量在当前环境中存在绑定,且其值是表示文件系统绝对路径的字符串。
6021+
6022+@13.2.4 环境变量缓存:
57456023 脚本缓存环境变量并在访问缓存时可能按外部环境的要求以未指定的方式跟踪环境变量的访问操作。缓存的环境变量的值在第一次访问时确定。
5746-对环境变量的直接访问是使用系统模块(@11.5) 的 env-get、env-set 和 env-empty? 的访问,忽略缓存的环境变量。直接设置环境变量不更新缓存的值。
5747-除非另行指定,访问环境变量使用缓存的环境变量。
6024+对环境变量的直接访问是使用系统模块(@12.5) 的 env-get、env-set 和 env-empty? 的访问,忽略缓存的环境变量。直接设置环境变量不更新缓存的值。
6025+自本节起,除非另行指定,本章的特性访问环境变量时,使用缓存的环境变量。
57486026 带缓存环境变量的访问接口如下:
57496027 safeenv-get <string> :同 env-get ,但使用缓存。
57506028 初始化缓存的值为第一次调用时的环境变量的值。若环境变量未设置,则值为空。
57516029 safeenv-set <string1> <string2> :同 env-set ,但使用缓存。
6030+ss-verbose-puts <string> :若初始化时环境变量 SS_Verbose 的值非空字符串非空则调用 puts(@12.4) 输出参数。
57526031 safeenv-empty? <string> :同 env-empty? ,但使用缓存。
57536032 safeenv-restore <string> :重置参数指定名称的环境变量为缓存的值。
5754-
5755-@12.2.2 派生操作:
6033+$lazy-env-val <string> <body> :创建初始化参数指定名称的环境变量的值的求值代理对象(@12.2) 。
6034+若第一参数指定名称的环境变量非空,则结果被求值时,求值 <body> 取得求值结果。
6035+$env-de! <variable> <body> :按环境变量定义变量的值。
6036+使用 $def!(@11.3.7) 定义第一参数指定的变量绑定。
6037+若变量同名的环境变量具有非空值,则定义的变量的值为等于这个值的字符串;否则,求值 <body> 并定义变量的值为求值结果。
6038+
6039+@13.2.5 其它 SHBuild 派生特性:
6040+变量 SHBuild_Env_OS :参见用户文档。
6041+变量 SHBuild_Env_Arch :参见用户文档。
57566042 () SHBuild_GetPlatformStrings :取操作系统和体系结构字符串列表。
57576043 代替 shell 脚本的 SHBuild_PrepareBuild 初始化的宿主环境变量。
57586044 () SHBuild_Extend_CallVariables :扩展特定的环境变量的值为 SHBuild 工具接受的环境变量。
diff -r d1f3d524f742 -r 6ad22b72cee3 doc/Workflow.txt
--- a/doc/Workflow.txt Sat Jan 09 04:33:56 2021 +0800
+++ b/doc/Workflow.txt Sat Jan 23 17:00:30 2021 +0800
@@ -11,13 +11,13 @@
1111 /*! \file Workflow.txt
1212 \ingroup Documentation
1313 \brief 工作流汇总报告。
14-\version r4086
14+\version r4098
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 433
1717 \par 创建时间:
1818 2013-07-31 01:27:41 +0800
1919 \par 修改时间:
20- 2021-01-08 00:38 +0800
20+ 2021-01-23 15:52 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -4081,6 +4081,18 @@
40814081 A bug of wrong parent environment used in the constructed environment is fixed in the core library operative '$bindings->environment'.
40824082 The operative now correctly used the fresh environment without parents instead.
40834083 This is also consistent to the environments vs. modules definitions (requires a standard environment for the latter ones).
4084+The synchronous (non-thunked) implementation of NPLA1 has been reviewed and several bug has been fixed.
4085+ The bugs in the native implementations of sequence algorithms ('AccR', 'FoldR1' and 'Map1' in namespace 'NPL::Forms' has been fixed).
4086+ One of the bug is the wrong use of 'RelaySwitched'.
4087+ This should not be used by the synchronous implementation.
4088+ It would cause invalid results and invalid memory accesses eventually becuase of the unexpected early return.
4089+ The other is the wrong treatment of the call result. That is, 'ContextNode::LastResult' should not be used.
4090+ Without the previous bug, this bug would lead to wrong combiner call results determine by previous reductions.
4091+ For instance, '$let' would sometimes make no bindings by accident, since 'map1' results are empty lists (unless all of 'accr', 'foldr1' and 'map1' are derived rather than implemented natively).
4092+ An alternative implementation of 'A1::SetupDefaultInterpretation' is fixed.
4093+ The implementation was buggy because it missed the reduction result in the step to conditionally setup combining term reference.
4094+ The reduction result was implicitly 'ReductionStatus::Clean'.
4095+ This was wrong for the synchronous implementation because the implicit reduction status could override the reduction status from other handlers unexpectedly.
40844096
40854097 ////
40864098
Show on old repository browser