YSTest: Dependency.cpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

Dependency.cpp
浏览该文件的文档.
1 /*
2 © 2015-2020 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include "NPL/YModules.h"
29 #include YFM_NPL_Dependency // for set, string, ystdex::isspace, std::istream,
30 // YSLib::unique_ptr, YSLib::share_move, TokenValue, ystdex::bind1,
31 // ValueObject, NPL::AllocateEnvironment, std::piecewise_construct,
32 // NPL::forward_as_tuple, LiftOther, Collapse, LiftOtherOrCopy, NPL::IsMovable,
33 // LiftTermOrCopy, ResolveTerm, LiftTermValueOrCopy, MoveResolved,
34 // ResolveIdentifier, ystdex::plus, std::placeholders, NPL::ResolveRegular,
35 // ystdex::tolower, ystdex::swap_dependent, LiftTermRef, LiftTerm, NPL::Deref;
36 #include YFM_NPL_NPLA1Forms // for NPL::Forms functions;
37 #include YFM_YSLib_Service_FileSystem // for YSLib::IO::*;
38 #include <ystdex/iterator.hpp> // for std::istreambuf_iterator,
39 // ystdex::make_transform;
40 #include YFM_YSLib_Service_TextFile // for IO::SharedInputMappedFileStream,
41 // Text::OpenSkippedBOMtream;
42 #include <cerrno> // for errno, ERANGE;
43 #include <cstdio> // for std::puts;
44 #include <regex> // for std::regex, std::regex_match;
45 #include "NPLA1Internals.h" // for NPL_Impl_NPLA1_Enable_Thunked;
46 #include YFM_YSLib_Core_YCoreUtilities // for FetchCommandOutput;
47 #include <ystdex/string.hpp> // for ystdex::begins_with;
48
49 using namespace YSLib;
50
51 namespace NPL
52 {
53
54 // NOTE: The following options provide documented alternative implementations.
55 // Except implementation of '$sequence', they shall still be conforming. Native
56 // implementation of forms should provide better performance in general.
57
59
60 // NOTE: For general native implementations.
61 #define NPL_Impl_NPLA1_Native_Forms true
62 // NOTE: For environment primitive native implemantations.
63 #define NPL_Impl_NPLA1_Native_EnvironmentPrimitives true
64 // NOTE: For '$vau' in 'id' derivations instead of '$lambda'.
65 #define NPL_Impl_NPLA1_Use_Id_Vau true
66 // NOTE: For awareness of strong ownership of environments.
67 #define NPL_Impl_NPLA1_Use_LockEnvironment true
68
69
70 vector<string>
71 DecomposeMakefileDepList(std::streambuf& sb)
72 {
73 using s_it_t = std::istreambuf_iterator<char>;
74 // NOTE: Escaped spaces would be saved to prevent being used as delimiter.
75 set<size_t> spaces;
76 Session sess{};
77 auto& lexer(sess.Lexer);
78 string cbuf{};
79
80 yunused(sess.Process(s_it_t(&sb), s_it_t(), [&](char ch){
81 lexer.ParseQuoted(ch, cbuf,
82 [&](string& buf, char c, UnescapeContext& uctx, char) -> bool{
83 // NOTE: See comments in %munge function of 'mkdeps.c' from libcpp
84 // of GCC.
85 if(uctx.Length == 1)
86 {
87 uctx.VerifyBufferLength(buf.length());
88
89 const auto i(uctx.Start);
90
91 YAssert(i == buf.length() - 1, "Invalid buffer found.");
92 if(buf[i] == '\\')
93 switch(c)
94 {
95 case ' ':
96 spaces.insert(buf.size());
97 YB_ATTR_fallthrough;
98 case '\\':
99 case '#':
100 buf[i] = c;
101 uctx.Clear();
102 return true;
103 case '\n':
104 buf.pop_back();
105 uctx.Clear();
106 return true;
107 default:
108 uctx.Clear();
109 buf += c;
110 return {};
111 }
112 if(buf[i] == '$' && c == '$')
113 {
114 uctx.Clear();
115 return true;
116 }
117 }
118 buf += c;
119 return {};
120 }, [](string_view buf, UnescapeContext& uctx) -> bool{
121 YAssert(!buf.empty(), "Invalid buffer found.");
122 if(!uctx.IsHandling())
123 {
124 if(buf.back() == '\\' || buf.back() == '$')
125 {
126 yunseq(uctx.Start = buf.length() - 1,
127 uctx.Length = 1);
128 return true;
129 }
130 }
131 return {};
132 });
133 }));
134
135 vector<string> lst;
136
137 ystdex::split_if(cbuf.begin(), cbuf.end(), ystdex::isspace,
138 [&](string::const_iterator b, string::const_iterator e){
139 lst.push_back({b, e});
140 }, [&](string::const_iterator i) YB_PURE{
141 return !ystdex::exists(spaces, size_t(i - cbuf.cbegin()));
142 });
143 return lst;
144 }
145 vector<string>
146 DecomposeMakefileDepList(std::istream& is)
147 {
148 return ystdex::call_value_or(static_cast<vector<string>(&)(
149 std::streambuf&)>(DecomposeMakefileDepList), is.rdbuf());
150 }
151
152 bool
153 FilterMakefileDependencies(vector<string>& lst)
154 {
155 const auto i_c(std::find_if(lst.cbegin(), lst.cend(),
156 [](const string& dep){
157 return !dep.empty() && dep.back() == ':';
158 }));
159
160 return i_c != lst.cend()
161 && (lst.erase(lst.cbegin(), i_c + 1), !lst.empty());
162 }
163
164
165 void
166 InstallFile(const char* dst, const char* src)
167 {
168 using namespace YSLib::IO;
169
170 // FIXME: Blocked. TOCTTOU access.
171 try
172 {
173 if(HaveSameContents(dst, src))
174 return;
175 }
176 CatchExpr(std::system_error& e, YTraceDe(Err, "Failed accessing file for"
177 " comparison before installing file."), ExtractAndTrace(e, Err))
178 CopyFile(dst, src, PreserveModificationTime);
179 }
180
181 void
182 InstallDirectory(const string& dst, const string& src)
183 {
184 using namespace YSLib::IO;
185
186 TraverseTree([](const Path& dname, const Path& sname){
187 InstallFile(string(dname).c_str(), string(sname).c_str());
188 }, Path(dst), Path(src));
189 }
190
191 void
192 InstallHardLink(const char* dst, const char* src)
193 {
194 using namespace YSLib::IO;
195
196 if(VerifyDirectory(src))
197 throw std::invalid_argument("Source is a directory.");
198 else
199 Remove(dst);
200 TryExpr(CreateHardLink(dst, src))
201 CatchExpr(..., InstallFile(dst, src))
202 }
203
204 void
205 InstallSymbolicLink(const char* dst, const char* src)
206 {
207 using namespace YSLib::IO;
208
209 Remove(dst);
210 TryExpr(CreateSymbolicLink(dst, src))
211 CatchExpr(..., InstallFile(dst, src))
212 }
213
214 void
215 InstallExecutable(const char* dst, const char* src)
216 {
217 InstallFile(dst, src);
218 }
219
220 namespace A1
221 {
222
223 YSLib::unique_ptr<std::istream>
224 OpenFile(const char* filename)
225 {
226 return Text::OpenSkippedBOMtream<IO::SharedInputMappedFileStream>(
227 Text::BOM_UTF_8, filename);
228 }
229
230 YSLib::unique_ptr<std::istream>
231 OpenUnique(REPLContext& context, string filename)
232 {
233 auto p_is(A1::OpenFile(filename.c_str()));
234
235 // NOTE: Swap guard for %Context.CurrentSource is not used to support PTC.
236 context.CurrentSource = YSLib::share_move(filename);
237 return p_is;
238 }
239
240
241 void
242 PreloadExternal(REPLContext& context, const char* filename)
243 {
244 TryLoadSource(context, filename,
245 *OpenUnique(context, string(filename, context.Allocator)));
246 }
247
248 ReductionStatus
249 ReduceToLoadExternal(TermNode& term, ContextNode& ctx, REPLContext& context)
250 {
251 term = context.Load(context, ctx,
252 NPL::ResolveRegular<string>(NPL::Deref(std::next(term.begin()))));
253 // NOTE: This is explicitly not same to klisp. This is also friendly to PTC.
254 return A1::ReduceOnce(term, ctx);
255 }
256
257 ReductionStatus
258 RelayToLoadExternal(ContextNode& ctx, TermNode& term, REPLContext& context)
259 {
260 return RelaySwitched(ctx,
261 A1::NameTypedReducerHandler(std::bind(ReduceToLoadExternal,
262 std::ref(term), std::ref(ctx), std::ref(context)), "load-external"));
263 }
264
265 namespace Forms
266 {
267
269 namespace
270 {
271
273 YB_ATTR_nodiscard ReductionStatus
274 DoMoveOrTransfer(void(&f)(TermNode&, TermNode&, bool), TermNode& term)
275 {
276 return Forms::CallResolvedUnary(
277 [&](TermNode& tm, ResolvedTermReferencePtr p_ref){
278 // NOTE: Force move. No %IsMovable check is needed.
279 // XXX: Term tags are currently not respected in prvalues.
280 f(term, tm, !p_ref || p_ref->IsModifiable());
281 // NOTE: Term tags are not copied.
282 return ReductionStatus::Retained;
283 }, term);
284 }
285
287
288 void
289 CopyEnvironmentDFS(Environment& d, const Environment& e)
290 {
291 auto& m(d.GetMapRef());
292 // TODO: Check environments allocator equality.
293 const auto a(m.get_allocator());
294 // TODO: Support more implementations?
295 const auto copy_parent([&](Environment& dst, const Environment& parent){
296 auto p_env(NPL::AllocateEnvironment(a));
297
298 CopyEnvironmentDFS(*p_env, parent);
299 dst.Parent = std::move(p_env);
300 });
301 const auto copy_parent_ptr(
302 [&](function<Environment&()> mdst, const ValueObject& vo) -> bool{
303 if(const auto p = NPL::AccessPtr<EnvironmentReference>(vo))
304 {
305 if(const auto p_parent = p->Lock())
306 copy_parent(mdst(), *p_parent);
307 // XXX: Failure of locking is ignored.
308 return true;
309 }
310 else if(const auto p_e = NPL::AccessPtr<shared_ptr<Environment>>(vo))
311 {
312 if(const auto p_parent = *p_e)
313 copy_parent(mdst(), *p_parent);
314 // XXX: Empty parent is ignored.
315 return true;
316 }
317 return {};
318 });
319
320 copy_parent_ptr([&]() ynothrow -> Environment&{
321 return d;
322 }, e.Parent);
323 for(const auto& b : e.GetMapRef())
324 m.emplace(std::piecewise_construct, NPL::forward_as_tuple(b.first),
325 NPL::forward_as_tuple(b.second.CreateWith(
326 [&](const ValueObject& vo) -> ValueObject{
327 shared_ptr<Environment> p_env;
328
329 if(copy_parent_ptr([&]() ynothrow -> Environment&{
330 p_env = NPL::AllocateEnvironment(a);
331 return *p_env;
332 }, vo))
333 return ValueObject(std::move(p_env));
334 return vo;
335 }), b.second.Value));
336 }
337
338 void
339 CopyEnvironment(TermNode& term, ContextNode& ctx)
340 {
341 auto p_env(AllocateEnvironment(term, ctx));
342
343 CopyEnvironmentDFS(*p_env, ctx.GetRecordRef());
344 term.Value = ValueObject(std::move(p_env));
345 }
347
349 template<typename _func>
350 YB_ATTR_nodiscard ReductionStatus
351 DoIdFunc(_func f, TermNode& term)
352 {
353 return Forms::CallRawUnary([&](TermNode& tm){
354 LiftOther(term, tm);
355 return f(term);
356 }, term);
357 }
358
360 void
361 CheckForAssignment(TermNode& nd, ResolvedTermReferencePtr p_ref)
362 {
363 if(p_ref)
364 {
365 if(p_ref->IsModifiable())
366 return;
367 ThrowNonmodifiableErrorForAssignee();
368 }
369 ThrowValueCategoryErrorForFirstArgument(nd);
370 }
371
373 template<typename _func>
374 YB_ATTR_nodiscard ValueToken
375 DoAssign(_func f, TermNode& x)
376 {
377 ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
378 CheckForAssignment(nd, p_ref);
379 f(nd);
380 }, x);
381 return ValueToken::Unspecified;
382 }
383
385 YB_ATTR_nodiscard YB_FLATTEN ReductionStatus
386 DoResolve(TermNode(&f)(const ContextNode&, string_view), TermNode& term,
387 const ContextNode& c)
388 {
389 Forms::CallRegularUnaryAs<const TokenValue>([&](string_view id) YB_FLATTEN{
390 term = CheckSymbol(id, std::bind(f, std::ref(c), id));
391 }, term);
392 return ReductionStatus::Retained;
393 }
394
396
397 namespace Ground
398 {
399
400 void
401 LoadObjects(Environment& env)
402 {
403 // NOTE: This is like '#ignore' in Kernel, but with the symbol type. An
404 // alternative definition is by evaluating '$def! ignore $quote #ignore'
405 // (see '$def!' and '$quote').
406 env.Define("ignore", TokenValue("#ignore"));
407 }
408
409 namespace Primitive
410 {
411
412 void
413 LoadEquals(ContextNode& ctx)
414 {
415 RegisterStrict(ctx, "eq?", Equal);
416 RegisterStrict(ctx, "eql?", EqualLeaf);
417 RegisterStrict(ctx, "eqr?", EqualReference);
418 RegisterStrict(ctx, "eqv?", EqualValue);
419 }
420
421 void
422 LoadControl(ContextNode& ctx)
423 {
424 // NOTE: Like Scheme but not Kernel, '$if' treats non-boolean value as
425 // '#f', for zero overhead principle.
426 RegisterForm(ctx, "$if", If);
427 }
428
430 void
431 LoadObjects(ContextNode& ctx)
432 {
433 RegisterUnary<>(ctx, "null?", ComposeReferencedTermOp(IsEmpty));
434 RegisterUnary<>(ctx, "nullv?", IsEmpty);
435 RegisterUnary<>(ctx, "reference?", IsReferenceTerm);
436 RegisterUnary<>(ctx, "bound-lvalue?", IsBoundLValueTerm);
437 RegisterUnary<>(ctx, "uncollapsed?", IsUncollapsedTerm);
438 RegisterUnary<>(ctx, "unique?", IsUniqueTerm);
439 RegisterStrict(ctx, "deshare", [](TermNode& term){
440 return Forms::CallRawUnary([&](TermNode& tm){
441 if(const auto p = NPL::TryAccessLeaf<const TermReference>(tm))
442 LiftTermRef(tm, p->get());
443 NPL::SetContentWith(term, std::move(tm),
444 &ValueObject::MakeMoveCopy);
445 return ReductionStatus::Retained;
446 }, term);
447 });
448 RegisterStrict(ctx, "expire", [](TermNode& term){
449 return Forms::CallRawUnary([&](TermNode& tm){
450 if(const auto p = NPL::TryAccessLeaf<TermReference>(tm))
451 p->SetTags(p->GetTags() | TermTags::Unique);
452 LiftTerm(term, tm);
453 return ReductionStatus::Retained;
454 }, term);
455 });
456 RegisterStrict(ctx, "move!", std::bind(DoMoveOrTransfer,
457 std::ref(LiftOtherOrCopy), std::placeholders::_1));
458 RegisterStrict(ctx, "transfer!", std::bind(DoMoveOrTransfer,
459 std::ref(LiftTermValueOrCopy), std::placeholders::_1));
460 RegisterStrict(ctx, "ref&", [](TermNode& term){
461 CallUnary([&](TermNode& tm){
462 LiftToReference(term, tm);
463 }, term);
464 return ReductionStatus::Retained;
465 });
466 RegisterBinary<>(ctx, "assign@!", [](TermNode& x, TermNode& y){
467 return DoAssign(ystdex::bind1(static_cast<void(&)(TermNode&,
468 TermNode&)>(LiftTerm), std::ref(y)), x);
469 });
470 }
471
472 void
473 LoadLists(ContextNode& ctx)
474 {
475 // NOTE: Though NPLA does not use cons pairs, corresponding primitives are
476 // still necessary.
477 // NOTE: Since NPL has no con pairs, it only added head to existed list.
478 RegisterStrict(ctx, "cons", Cons);
479 RegisterStrict(ctx, "cons%", ConsRef);
480 // NOTE: Like '$set-cdr!' in Kernel, with no references.
481 RegisterStrict(ctx, "set-rest!", SetRest);
482 // NOTE: Like '$set-cdr!' in Kernel.
483 RegisterStrict(ctx, "set-rest%!", SetRestRef);
484 }
485
486 void
487 LoadEnvironments(ContextNode& ctx)
488 {
489 using namespace std::placeholders;
490
491 // NOTE: The applicative 'copy-es-immutable' is unsupported currently due to
492 // different implementation of control primitives.
493 RegisterStrict(ctx, "eval", Eval);
494 RegisterStrict(ctx, "eval%", EvalRef);
495 RegisterForm(ctx, "$resolve-identifier",
496 std::bind(DoResolve, std::ref(ResolveIdentifier), _1, _2));
497 RegisterForm(ctx, "$move-resolved!",
498 std::bind(DoResolve, std::ref(MoveResolved), _1, _2));
499 // NOTE: This is now be primitive since in NPL environment capture is more
500 // basic than vau.
501 RegisterStrict(ctx, "copy-environment", CopyEnvironment);
502 RegisterUnary<Strict, const EnvironmentReference>(ctx, "lock-environment",
503 [](const EnvironmentReference& wenv) ynothrow{
504 return wenv.Lock();
505 });
506 RegisterUnary<>(ctx, "freeze-environment!", [](TermNode& term){
507 Environment::EnsureValid(ResolveEnvironment(term).first).Frozen = true;
508 return ValueToken::Unspecified;
509 });
510 RegisterStrict(ctx, "make-environment", MakeEnvironment);
511 RegisterUnary<Strict, const shared_ptr<Environment>>(ctx,
512 "weaken-environment", [](const shared_ptr<Environment>& p_env) ynothrow{
513 return EnvironmentReference(p_env);
514 });
515 // NOTE: Environment mutation is optional in Kernel and supported here.
516 // NOTE: For zero overhead principle, the form without recursion (named
517 // '$def!') is preferred. The recursion variant (named '$defrec!') is more
518 // than '$define!' in Kernel because of more native interoperations
519 // (shared object holders) supported, and is used only when necessary.
520 RegisterForm(ctx, "$def!", DefineWithNoRecursion);
521 RegisterForm(ctx, "$defrec!", DefineWithRecursion);
522 }
523
524 void
525 LoadCombiners(ContextNode& ctx)
526 {
527 // NOTE: For ground environment applicatives (see below for
528 // 'get-current-environment'), the result of evaluation of expression
529 // 'eqv? (() get-current-environment) (() ($vau () d d))' shall be '#t'.
530 RegisterForm(ctx, "$vau/e", VauWithEnvironment);
531 RegisterForm(ctx, "$vau/e%", VauWithEnvironmentRef);
532 RegisterStrict(ctx, "wrap", Wrap);
533 RegisterStrict(ctx, "wrap%", WrapRef);
534 RegisterStrict(ctx, "unwrap", Unwrap);
535 }
536
538 void
539 LoadErrorsAndChecks(ContextNode& ctx)
540 {
541 RegisterUnary<Strict, const string>(ctx, "raise-invalid-syntax-error",
542 [](const string& str) YB_ATTR(noreturn){
543 ThrowInvalidSyntaxError(str);
544 });
545 RegisterStrict(ctx, "check-list-reference", CheckListReference);
546 }
547
549 void
550 LoadEncapsulations(ContextNode& ctx)
551 {
552 RegisterStrict(ctx, "make-encapsulation-type", MakeEncapsulationType);
553 }
554
555 void
556 Load(ContextNode& ctx)
557 {
558 // NOTE: Primitive features, listed as RnRK, except mentioned above.
559 /*
560 The primitives are provided here to maintain acyclic dependencies on derived
561 forms, also for simplicity of semantics.
562 The primitives are listed in order as Chapter 4 of Revised^-1 Report on the
563 Kernel Programming Language. Derived forms are not ordered likewise.
564 There are some difference of listed primitives.
565 See $2017-02 @ %Documentation::Workflow.
566 */
567 LoadEquals(ctx);
568 LoadControl(ctx);
569 LoadObjects(ctx);
570 LoadLists(ctx);
571 LoadEnvironments(ctx);
572 LoadCombiners(ctx);
573 LoadErrorsAndChecks(ctx);
574 LoadEncapsulations(ctx);
575 }
576
577 } // namespace Primitive;
578
579 namespace Derived
580 {
581
583 void
584 LoadGroundedDerived(REPLContext& context)
585 {
586 auto& renv(context.Root.GetRecordRef());
587
588 // NOTE: Some combiners are provided here as host primitives for
589 // more efficiency and less dependencies.
590 #if NPL_Impl_NPLA1_Native_Forms || NPL_Impl_NPLA1_Native_EnvironmentPrimitives
591 RegisterStrict(renv, "get-current-environment", GetCurrentEnvironment);
592 RegisterStrict(renv, "lock-current-environment", LockCurrentEnvironment);
593 #endif
594 #if NPL_Impl_NPLA1_Native_Forms || !NPL_Impl_NPLA1_Native_EnvironmentPrimitives
595 RegisterForm(renv, "$vau", Vau);
596 RegisterForm(renv, "$vau%", VauRef);
597 #endif
598 #if NPL_Impl_NPLA1_Native_Forms
599
600 const auto idv([](TermNode& term){
601 return DoIdFunc(ReduceForLiftedResult, term);
602 });
603
604 RegisterForm(renv, "$quote", idv);
605 RegisterStrict(renv, "id", [](TermNode& term){
606 return DoIdFunc(
607 [](TermNode&) YB_ATTR_LAMBDA_QUAL(ynothrow, YB_STATELESS){
608 return ReductionStatus::Retained;
609 }, term);
610 });
611 RegisterStrict(renv, "idv", idv);
612 RegisterStrict(renv, "list", ReduceBranchToListValue);
613 RegisterStrict(renv, "list%", ReduceBranchToList);
614 // NOTE: Lazy form '$deflazy!' is the basic operation, which may bind
615 // parameter as unevaluated operands.
616 RegisterForm(renv, "$deflazy!", DefineLazy);
617 RegisterForm(renv, "$set!", SetWithNoRecursion);
618 RegisterForm(renv, "$setrec!", SetWithRecursion);
619 RegisterForm(renv, "$lambda", Lambda);
620 RegisterForm(renv, "$lambda%", LambdaRef);
621 // NOTE: The sequence operator is also available as infix ';' syntax sugar.
622 RegisterForm(renv, "$sequence", Sequence);
623 RegisterStrict(renv, "collapse", [](TermNode& term){
624 return Forms::CallRawUnary([&](TermNode& tm){
625 MoveCollapsed(term, tm);
626 return ReductionStatus::Retained;
627 }, term);
628 });
629 RegisterStrict(renv, "forward", [](TermNode& term){
630 return Forms::CallRawUnary(std::bind(ReduceToValue, std::ref(term),
631 std::placeholders::_1), term);
632 });
633 RegisterStrict(renv, "forward!", [](TermNode& term){
634 return Forms::CallRawUnary([&](TermNode& tm){
635 MoveRValueToForward(term, tm);
636 return ReductionStatus::Retained;
637 }, term);
638 });
639 RegisterBinary<>(renv, "assign%!", [](TermNode& x, TermNode& y){
640 return DoAssign(ystdex::bind1(MoveCollapsed, std::ref(y)), x);
641 });
642 RegisterBinary<>(renv, "assign!", [](TermNode& x, TermNode& y){
643 return DoAssign([&](TermNode& nd_x){
644 ResolveTerm([&](TermNode& nd_y, ResolvedTermReferencePtr p_ref_y){
645 LiftTermOrCopy(nd_x, nd_y, NPL::IsMovable(p_ref_y));
646 }, y);
647 }, x);
648 });
649 RegisterStrict(renv, "apply", Apply);
650 RegisterStrict(renv, "list*", ListAsterisk);
651 RegisterStrict(renv, "list*%", ListAsteriskRef);
652 RegisterStrict(renv, "forward-list-first%", ForwardListFirst);
653 RegisterStrict(renv, "first", First);
654 RegisterStrict(renv, "first@", FirstAt);
655 RegisterStrict(renv, "first&", FirstRef);
656 RegisterStrict(renv, "firstv", FirstVal);
657 // NOTE: Like 'set-car!' in Kernel, with no references.
658 RegisterStrict(renv, "set-first!", SetFirst);
659 // NOTE: Like 'set-car!' in Kernel, with reference not collapsed.
660 RegisterStrict(renv, "set-first@!", SetFirstAt);
661 // NOTE: Like 'set-car!' in Kernel, with reference collapsed.
662 RegisterStrict(renv, "set-first%!", SetFirstRef);
663 RegisterStrict(renv, "check-environment", CheckEnvironment);
664 RegisterForm(renv, "$cond", Cond);
665 RegisterForm(renv, "$when", When);
666 RegisterForm(renv, "$unless", Unless);
667 RegisterUnary<>(renv, "not?", Not);
668 RegisterForm(renv, "$and?", And);
669 RegisterForm(renv, "$or?", Or);
670 RegisterStrict(renv, "accl", AccL);
671 RegisterStrict(renv, "accr", AccR);
672 RegisterStrict(renv, "foldr1", FoldR1);
673 RegisterStrict(renv, "map1", Map1);
674 #else
675 # if NPL_Impl_NPLA1_Native_EnvironmentPrimitives
676 context.Perform(R"NPL(
677 $def! $vau $vau/e (() get-current-environment) (&formals &ef .&body) d
678 eval (cons $vau/e (cons d (cons formals (cons ef (move! body))))) d;
679 $def! $vau% $vau (&formals &ef .&body) d
680 eval (cons $vau/e% (cons d (cons formals (cons ef (move! body)))))
681 d;
682 )NPL");
683 # else
684 context.Perform(R"NPL(
685 $def! get-current-environment (wrap ($vau () d d));
686 $def! lock-current-environment (wrap ($vau () d lock-environment d));
687 )NPL");
688 # endif
689 // XXX: The operative '$set!' is same to following derivations.
690 context.Perform(R"NPL(
691 $def! $quote $vau (&x) #ignore x;
692 )NPL");
693 // NOTE: The function 'id' does not initialize new objects from the operand.
694 // XXX: The implementation of 'id' relies on the fact that an object other
695 // than a reference (i.e. represented by a prvalue) cannot have qualifiers
696 // implying %TermTags::Nonmodifying. Otherwise, a new primitive (e.g. to
697 // cast away the tag) is needed to replace the plain use of 'move!', or it
698 // can just lift the operand as the native %LiftTerm does.
699 # if NPL_Impl_NPLA1_Use_Id_Vau
700 // NOTE: The parameter shall be in a list explicitly as '(.x)' to lift
701 // elements by value rather than by reference (as '&x'), otherwise the
702 // resulted 'list' is wrongly implemented as 'list%' with undefined
703 // behavior becuase it is not guaranteed the operand is alive to access.
704 // This is not the same in Kernel as it does not differentiate lvalues
705 // (first-class referents) from prvalues and all terms can be accessed as
706 // objects with arbitrary longer lifetime.
707 context.Perform(R"NPL(
708 $def! id wrap ($vau% (%x) #ignore $if (bound-lvalue? x) x (move! x));
709 $def! idv wrap $quote;
710 $def! list wrap ($vau (.x) #ignore x);
711 $def! list% wrap ($vau &x #ignore x);
712 )NPL");
713 # else
714 RegisterForm(renv, "$lambda", Lambda);
715 RegisterForm(renv, "$lambda%", LambdaRef);
716 context.Perform(R"NPL(
717 $def! id $lambda% (%x) $if (bound-lvalue? x) x (move! x);
718 $def! idv $lambda (&x) x;
719 $def! list $lambda (.x) x;
720 $def! list% $lambda &x x;
721 )NPL");
722 # endif
723 // XXX: The operative '$defv!' is same to following derivations in
724 // %LoadCore.
725 context.Perform(R"NPL(
726 $def! $deflazy! $vau (&definiend .&expr) d
727 eval (list $def! definiend $quote expr) d;
728 $def! $set! $vau (&e &formals .&expr) d
729 eval (list $def! formals (unwrap eval%) expr d) (eval e d);
730 $def! $defv! $vau (&$f &formals &ef .&body) d
731 eval (list $set! d $f $vau formals ef (move! body)) d;
732 $defv! $setrec! (&e &formals .&expr) d
733 eval (list $defrec! formals (unwrap eval%) expr d) (eval e d);
734 )NPL");
735 # if NPL_Impl_NPLA1_Use_Id_Vau
736 context.Perform(R"NPL(
737 $defv! $lambda (&formals .&body) d wrap
738 (eval (cons $vau (cons formals (cons ignore (move! body)))) d);
739 $defv! $lambda% (&formals .&body) d wrap
740 (eval (cons $vau% (cons formals (cons ignore (move! body)))) d);
741 )NPL");
742 # endif
743 // XXX: The operatives '$defl!', '$defl%!', '$defw%!', and '$defv%!', as
744 // well as the applicatives 'rest&' and 'rest%' are same to following
745 // derivations in %LoadCore.
746 // NOTE: Use of 'eqv?' is more efficient than '$if'.
747 context.Perform(R"NPL(
748 $def! $sequence
749 ($lambda (&se)
750 ($lambda #ignore $vau/e% se &exprseq d
751 $if (null? exprseq) #inert (eval% (cons% $aux exprseq) d))
752 ($set! se $aux
753 $vau/e% (weaken-environment se) (&head .&tail) d
754 $if (null? tail) (eval% head d)
755 (($vau% (&t) e ($lambda% #ignore eval% t e)
756 (eval% head d)) (eval% (cons% $aux tail) d))))
757 (make-environment (() get-current-environment));
758 $defv! $defl! (&f &formals .&body) d
759 eval (list $set! d f $lambda formals (move! body)) d;
760 $defv! $defl%! (&f &formals .&body) d
761 eval (list $set! d f $lambda% formals (move! body)) d;
762 $defl%! collapse (%x)
763 $if (uncollapsed? ($resolve-identifier x)) (idv x) x;
764 $defl%! forward (%x)
765 $if (bound-lvalue? ($resolve-identifier x)) x (idv x);
766 $defl%! forward! (%x)
767 $if (bound-lvalue? ($resolve-identifier x)) x (move! x);
768 $defl! assign! (&x &y) assign@! (forward! x) (idv (collapse y));
769 $defl! assign%! (&x &y) assign@! (forward! x) (forward! (collapse y));
770 $defl%! apply (&appv &arg .&opt)
771 eval% (cons% () (cons% (unwrap (forward! appv)) (forward! arg)))
772 ($if (null? opt) (() make-environment)
773 (($lambda ((&e .&eopt))
774 $if (null? eopt) e
775 (raise-invalid-syntax-error
776 "Syntax error in applying form.")) opt));
777 $defl! list* (&head .&tail)
778 $if (null? tail) head (cons head (apply list* tail));
779 $defl%! list*% (&head .&tail) $if (null? tail) (forward! head)
780 (cons% (forward! head) (apply list*% tail));
781 $defv! $defw%! (&f &formals &ef .&body) d
782 eval (list $set! d f wrap (list* $vau% formals ef (move! body))) d;
783 $defw%! forward-list-first% (&list-appv &appv &l) d
784 ($lambda% ((&x .))
785 apply (forward! appv) (list% ($move-resolved! x)) d)
786 (apply (forward! list-appv) (list% l) d);
787 $defl%! first@ (&l) ($lambda% ((@x .)) x) (check-list-reference l);
788 $defl%! first (%l)
789 ($lambda% (fwd) forward-list-first% fwd forward! l)
790 ($if (bound-lvalue? ($resolve-identifier l)) id expire);
791 $defl%! first& (&l) ($lambda% ((&x .)) x) (check-list-reference l);
792 $defl! firstv ((&x .)) x;
793 $defl! rest& (&l) ($lambda ((#ignore .&x)) x) (check-list-reference l);
794 $defl! rest% ((#ignore .%x)) x;
795 $defl! set-first! (&l x)
796 assign@! (first@ (check-list-reference l)) (move! x);
797 $defl! set-first@! (&l &x)
798 assign@! (first@ (check-list-reference l)) (forward! x);
799 $defl! set-first%! (&l &x)
800 assign%! (first@ (check-list-reference l)) (forward! x);
801 $defl%! check-environment (&e)
802 $sequence ($vau/e% e . #ignore) (forward! e);
803 $defv! $defv%! (&$f &formals &ef .&body) d
804 eval (list $set! d $f $vau% formals ef (move! body)) d;
805 $defv%! $cond &clauses d $if (null? clauses) #inert
806 (apply ($lambda% ((&test .&body) .&clauses)
807 $if (eval test d) (eval% (move! body) d)
808 (apply (wrap $cond) (move! clauses) d)) (move! clauses));
809 $defv%! $when (&test .&exprseq) d
810 $if (eval test d) (eval% (list*% () $sequence exprseq) d);
811 $defv%! $unless (&test .&exprseq) d
812 $if (eval test d) #inert (eval% (list*% () $sequence exprseq) d);
813 $defl! not? (&x) eqv? x #f;
814 $defv%! $and? &x d $cond
815 ((null? x) #t)
816 ((nullv? (rest& x)) eval% (first (forward! x)) d)
817 ((eval% (first& x) d) apply (wrap $and?) (rest% (forward! x)) d)
818 (#t #f);
819 $defv%! $or? &x d $cond
820 ((null? x) #f)
821 ((nullv? (rest& x)) eval% (first (forward! x)) d)
822 (#t ($lambda% (&r) $if r (forward! r) (apply (wrap $or?)
823 (rest% (forward! x)) d)) (eval% (move! (first& x)) d));
824 $defw%! accl (&l &pred? &base &head &tail &sum) d
825 $if (apply pred? (list% l) d) (forward! base)
826 (apply accl (list% (apply tail (list% l) d) pred?
827 (apply sum (list% (apply head (list% l) d)
828 (forward! base)) d) head tail sum) d);
829 $defw%! accr (&l &pred? &base &head &tail &sum) d
830 $if (apply pred? (list% l) d) (forward! base)
831 (apply sum (list% (apply head (list% l) d)
832 (apply accr (list% (apply tail (list% l) d)
833 pred? (forward! base) head tail sum) d)) d);
834 $defw%! foldr1 (&kons &knil &l) d
835 apply accr
836 (list% (forward! l) null? (forward! knil) first rest% kons) d;
837 $defw%! map1 (&appv &l) d
838 foldr1 ($lambda (&x &xs) cons%
839 (apply appv (list% (forward! x)) d) xs) () (forward! l);
840 )NPL");
841 #endif
842 }
843
845
846 void
847 LoadCore(REPLContext& context)
848 {
849 context.Perform(R"NPL(
850 $def! $defv! $vau (&$f &formals &ef .&body) d
851 eval (list $set! d $f $vau formals ef (move! body)) d;
852 $defv! $defv%! (&$f &formals &ef .&body) d
853 eval (list $set! d $f $vau% formals ef (move! body)) d;
854 $defv! $defv/e! (&$f &e &formals &ef .&body) d
855 eval (list $set! d $f $vau/e e formals ef (move! body)) d;
856 $defv! $defv/e%! (&$f &e &formals &ef .&body) d
857 eval (list $set! d $f $vau/e% e formals ef (move! body)) d;
858 $defv! $defl! (&f &formals .&body) d
859 eval (list $set! d f $lambda formals (move! body)) d;
860 $defv! $defl%! (&f &formals .&body) d
861 eval (list $set! d f $lambda% formals (move! body)) d;
862 $defl! restv ((#ignore .x)) x;
863 $defl! rest& (&l) ($lambda ((#ignore .&x)) x) (check-list-reference l);
864 $defl! rest% ((#ignore .%x)) x;
865 $defv! $defw! (&f &formals &ef .&body) d
866 eval (list $set! d f wrap (list* $vau formals ef (move! body))) d;
867 $defv! $defw%! (&f &formals &ef .&body) d
868 eval (list $set! d f wrap (list* $vau% formals ef (move! body))) d;
869 $defv! $defw/e! (&f &e &formals &ef .&body) d
870 eval (list $set! d f wrap (list* $vau/e e formals ef (move! body)))
871 d;
872 $defv! $defw/e%! (&f &e &formals &ef .&body) d
873 eval (list $set! d f wrap (list* $vau/e% e formals ef (move! body)))
874 d;
875 $defv! $lambda/e (&e &formals .&body) d
876 wrap (eval (list* $vau/e e formals ignore (move! body)) d);
877 $defv! $lambda/e% (&e &formals .&body) d
878 wrap (eval (list* $vau/e% e formals ignore (move! body)) d);
879 $defv! $defl/e! (&f &e &formals .&body) d
880 eval (list $set! d f $lambda/e e formals (move! body)) d;
881 $defv! $defl/e%! (&f &e &formals .&body) d
882 eval (list $set! d f $lambda/e% e formals (move! body)) d;
883 )NPL");
884 #if NPL_Impl_NPLA1_Use_LockEnvironment
885 context.Perform(R"NPL(
886 $def! make-standard-environment
887 $lambda () () lock-current-environment;
888 )NPL");
889 #else
890 context.Perform(R"NPL(
891 $def! make-standard-environment
892 ($lambda (&se &e)
893 ($lambda #ignore $vau/e se () #ignore (make-environment ce))
894 ($set! se ce e))
895 (make-environment (() get-current-environment))
896 (() get-current-environment);
897 )NPL");
898 #endif
899 context.Perform(R"NPL(
900 $def! (box% box? unbox) () make-encapsulation-type;
901 $defl! box (&x) box% x;
902 $defl! first-null? (&l) null? (first l);
903 $defl! list-rest% (&x) list% (rest% x);
904 $defl! list-concat (&x &y) foldr1 cons% y (forward! x);
905 $defl! append (.&ls) foldr1 list-concat () (move! ls);
906 $defl%! assv (&x &alist) $cond ((null? alist) ())
907 ((eqv? x (first& (first& alist))) first alist)
908 (#t assv (forward! x) (rest% alist));
909 $defv%! $let (&bindings .&body) d
910 eval% (list*% () (list*% $lambda (map1 firstv bindings)
911 (list (move! body))) (map1 list-rest% bindings)) d;
912 $defv%! $let% (&bindings .&body) d
913 eval% (list*% () (list*% $lambda% (map1 firstv bindings)
914 (list (move! body))) (map1 list-rest% bindings)) d;
915 $defv%! $let/d (&bindings &ef .&body) d
916 eval% (list*% () (list% wrap (list*% $vau (map1 firstv bindings)
917 ef (list (move! body)))) (map1 list-rest% bindings)) d;
918 $defv%! $let/d% (&bindings &ef .&body) d
919 eval% (list*% () (list% wrap (list*% $vau% (map1 firstv bindings)
920 ef (list (move! body)))) (map1 list-rest% bindings)) d;
921 $defv%! $let/e (&e &bindings .&body) d
922 eval% (list*% () (list*% $lambda/e e (map1 firstv bindings)
923 (list (move! body))) (map1 list-rest% bindings)) d;
924 $defv%! $let/e% (&e &bindings .&body) d
925 eval% (list*% () (list*% $lambda/e% e (map1 firstv bindings)
926 (list (move! body))) (map1 list-rest% bindings)) d;
927 $defv%! $let* (&bindings .&body) d
928 eval% ($if (null? bindings) (list*% $let bindings (move! body))
929 (list% $let (list% (firstv bindings))
930 (list*% $let* (rest% bindings) (move! body)))) d;
931 $defv%! $let*% (&bindings .&body) d
932 eval% ($if (null? bindings) (list*% $let* bindings (move! body))
933 (list% $let% (list (first bindings))
934 (list*% $let*% (rest% bindings) (move! body)))) d;
935 $defv%! $letrec (&bindings .&body) d
936 eval% (list $let () $sequence (list% $def! (map1 firstv bindings)
937 (list*% () list (map1 rest% bindings))) (move! body)) d;
938 $defv%! $letrec% (&bindings .&body) d
939 eval% (list $let% () $sequence (list% $def! (map1 firstv bindings)
940 (list*% () list (map1 rest% bindings))) (move! body)) d;
941 $defv! $bindings/p->environment (&parents .&bindings) d $sequence
942 ($def! res apply make-environment (map1 ($lambda% (x) eval% x d)
943 parents))
944 (eval% (list% $set! res (map1 firstv bindings)
945 (list*% () list (map1 rest% bindings))) d)
946 res;
947 $defv! $bindings->environment (.&bindings) d
948 eval (list*% $bindings/p->environment
949 (list (() make-standard-environment)) bindings) d;
950 $defv! $provide! (&symbols .&body) d
951 $sequence (eval% (list% $def! symbols (list $let () $sequence
952 (list% ($vau% (&e) d $set! e res (lock-environment d))
953 (() get-current-environment)) (move! body)
954 (list* () list symbols))) d) res;
955 $defv! $provide/d! (&symbols &ef .&body) d
956 $sequence (eval% (list% $def! symbols (list $let/d () ef $sequence
957 (list% ($vau% (&e) d $set! e res (lock-environment d))
958 (() get-current-environment)) (move! body)
959 (list* () list symbols))) d) res;
960 $defv! $import! (&e .&symbols) d
961 eval% (list $set! d symbols (list* () list symbols)) (eval e d);
962 $defl! nonfoldable? (&l)
963 $if (null? l) #f ($if (first-null? l) #t (nonfoldable? (rest& l)));
964 $defl%! list-extract (&l &extr)
965 accr l null? ()
966 ($lambda% (&l) forward-list-first% expire extr l) rest% cons%;
967 $defl%! list-extract-first (&l) list-extract l first;
968 $defl%! list-extract-rest% (&l) list-extract l rest%;
969 $defl! list-push-front! (&l &x)
970 assign! l (cons% (forward! x) (move! l));
971 $defw%! map-reverse (&appv .&ls) d
972 accl (move! ls) nonfoldable? () list-extract-first
973 list-extract-rest%
974 ($lambda (&x &xs) cons% (apply appv (forward! x) d) xs);
975 $defw! for-each-ltr &ls d $sequence (apply map-reverse ls d) #inert;
976 )NPL");
977 }
978
979 void
980 Load(REPLContext& context)
981 {
982 LoadGroundedDerived(context);
983 LoadCore(context);
984 }
986
987 } // namespace Derived;
988
990 void
991 Load(REPLContext& context)
992 {
993 auto& rctx(context.Root);
994 auto& renv(rctx.GetRecordRef());
995
996 LoadObjects(renv);
997 Primitive::Load(rctx);
998 Derived::Load(context);
999 // NOTE: Prevent the ground environment from modification.
1000 renv.Frozen = true;
1001 }
1002
1003 } // namespace Ground;
1005
1006 } // unnamed namespace;
1007
1008 void
1009 LoadGroundContext(REPLContext& context)
1010 {
1011 // NOTE: Dynamic separator handling is lifted to %REPLContext::Preprocess.
1012 // See $2020-02 @ %Documentation::Workflow.
1013 Ground::Load(context);
1014 }
1015
1016 void
1017 LoadModule_std_environments(REPLContext& context)
1018 {
1019 auto& renv(context.Root.GetRecordRef());
1020
1021 RegisterUnary<Strict, const string>(renv, "bound?",
1022 [](const string& id, ContextNode& ctx){
1023 return CheckSymbol(id, [&]{
1024 return bool(ResolveName(ctx, id).first);
1025 });
1026 });
1027 context.Perform(R"NPL(
1028 $defv/e! $binds1? (make-environment
1029 (() get-current-environment) std.strings) (&e &s) d
1030 eval (list (unwrap bound?) (symbol->string s)) (eval e d);
1031 )NPL");
1032 RegisterStrict(renv, "value-of", ValueOf);
1033 RegisterStrict(renv, "get-current-repl", [&](TermNode& term){
1034 RetainN(term, 0);
1035 term.Value = ValueObject(context, OwnershipTag<>());
1036 });
1037 RegisterStrict(renv, "eval-string", EvalString);
1038 RegisterStrict(renv, "eval-string%", EvalStringRef);
1039 RegisterStrict(renv, "eval-unit", EvalUnit);
1040 }
1041
1042 void
1043 LoadModule_std_promises(REPLContext& context)
1044 {
1045 // NOTE: Call of 'set-first%!' does not check cyclic references. This is
1046 // kept safe since it can occur only with NPLA1 undefined behavior.
1047 context.Perform(R"NPL(
1048 $def! __ $provide! (promise? memoize $lazy $lazy/e force)
1049 (
1050 $def! (encapsulate promise? decapsulate) () make-encapsulation-type,
1051 $defl%! memoize (&x) encapsulate (list (list% (forward! x) ())),
1052 $defv%! $lazy (.&expr) d encapsulate (list (list expr d)),
1053 $defv%! $lazy/e (&e .&expr) d
1054 encapsulate (list (list expr (check-environment (eval e d)))),
1055 $defl%! force (&x)
1056 $if (promise? x) (force-promise (decapsulate x)) (forward! x),
1057 $defl%! force-promise (&x) $let ((((&o &env)) x))
1058 $if (null? env) (forward! o)
1059 (
1060 $let% ((&y eval% o env)) $cond
1061 ((null? (first (rest& (first& x)))) first& (first& x))
1062 ((promise? y) $sequence
1063 (set-first%! x (first (decapsulate (forward! y))))
1064 (force-promise x))
1065 (#t $sequence
1066 ($let (((&o &e) first& x))
1067 list% (assign! o y) (assign@! e ()))
1068 (forward! y))
1069 )
1070 );
1071 )NPL");
1072 }
1073
1074 void
1075 LoadModule_std_strings(REPLContext& context)
1076 {
1077 auto& renv(context.Root.GetRecordRef());
1078
1079 RegisterStrict(renv, "++",
1080 std::bind(CallBinaryFold<string, ystdex::plus<>>, ystdex::plus<>(),
1081 string(), std::placeholders::_1));
1082 RegisterUnary<Strict, const string>(renv, "string-empty?",
1083 [](const string& str) ynothrow{
1084 return str.empty();
1085 });
1086 RegisterBinary<>(renv, "string<-", [](TermNode& x, TermNode& y){
1087 ResolveTerm([&](TermNode& nd_x, ResolvedTermReferencePtr p_ref_x){
1088 if(!p_ref_x || p_ref_x->IsModifiable())
1089 {
1090 auto& str_x(NPL::AccessRegular<string>(nd_x, p_ref_x));
1091
1092 ResolveTerm(
1093 [&](TermNode& nd_y, ResolvedTermReferencePtr p_ref_y){
1094 auto& str_y(NPL::AccessRegular<string>(nd_y, p_ref_y));
1095
1096 if(NPL::IsMovable(p_ref_y))
1097 str_x = std::move(str_y);
1098 else
1099 str_x = str_y;
1100 }, y);
1101 }
1102 else
1103 ThrowNonmodifiableErrorForAssignee();
1104 }, x);
1105 return ValueToken::Unspecified;
1106 });
1107 RegisterBinary<Strict, string, string>(renv, "string-contains-ci?",
1108 [](string x, string y){
1109 // TODO: Extract 'strlwr'.
1110 const auto to_lwr([](string& str) ynothrow{
1111 for(auto& c : str)
1112 c = ystdex::tolower(c);
1113 });
1114
1115 to_lwr(x),
1116 to_lwr(y);
1117 return x.find(y) != string::npos;
1118 });
1119 RegisterUnary<>(renv, "string->symbol", [](TermNode& term){
1120 return ResolveTerm([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
1121 auto& s(NPL::AccessRegular<string>(nd, p_ref));
1122
1123 return NPL::IsMovable(p_ref) ? StringToSymbol(std::move(s))
1124 : StringToSymbol(s);
1125 }, term);
1126 });
1127 RegisterUnary<Strict, const TokenValue>(renv, "symbol->string",
1128 SymbolToString);
1129 RegisterUnary<Strict, const string>(renv, "string->regex",
1130 [](const string& str){
1131 return std::regex(str);
1132 });
1133 RegisterStrict(renv, "regex-match?", [](TermNode& term){
1134 RetainN(term, 2);
1135
1136 auto i(std::next(term.begin()));
1137 const auto& str(NPL::ResolveRegular<const string>(NPL::Deref(i)));
1138 const auto& r(NPL::ResolveRegular<const std::regex>(NPL::Deref(++i)));
1139
1140 term.Value = std::regex_match(str, r);
1141 return ReductionStatus::Clean;
1142 });
1143 }
1144
1145 void
1146 LoadModule_std_io(REPLContext& context)
1147 {
1148 auto& renv(context.Root.GetRecordRef());
1149
1150 RegisterUnary<Strict, const string>(renv, "puts", [](const string& str){
1151 // FIXME: Use %EncodeArg?
1152 // XXX: Error from 'std::puts' is ignored.
1153 std::puts(str.c_str());
1154 return ValueToken::Unspecified;
1155 });
1156 #if true
1157 RegisterStrict(renv, "load", [&](TermNode& term, ContextNode& ctx){
1158 RetainN(term);
1159 # if NPL_Impl_NPLA1_Enable_Thunked
1160 return RelayToLoadExternal(ctx, term, context);
1161 # else
1162 return ReduceToLoadExternal(term, ctx, context);
1163 # endif
1164 });
1165 #else
1166 RegisterUnary<Strict, string>(renv, "load", [&](string& filename){
1167 // NOTE: This is not applicable since %load has no additional barrier
1168 // here.
1169 // XXX: As %PreloadExternal.
1170 const auto p_is(OpenUnique(context, std::move(filename)));
1171
1172 TryLoadSource(context, context.CurrentSource->c_str(), *p_is);
1173 return ValueToken::Unspecified;
1174 });
1175 #endif
1176 }
1177
1178 void
1179 LoadModule_std_system(REPLContext& context)
1180 {
1181 auto& renv(context.Root.GetRecordRef());
1182
1183 RegisterStrict(renv, "cmd-get-args", [](TermNode& term){
1184 RetainN(term, 0);
1185 term.GetContainerRef() = []{
1186 const auto p_cmd_args(LockCommandArguments());
1187 TermNode::Container con{};
1188
1189 for(const auto& arg : p_cmd_args->Arguments)
1190 TermNode::AddValueTo(con, in_place_type<string>, arg);
1191 return con;
1192 }();
1193 return ReductionStatus::Retained;
1194 });
1195 RegisterUnary<Strict, const string>(renv, "env-get", [](const string& var){
1196 string res;
1197
1198 FetchEnvironmentVariable(res, var.c_str());
1199 return res;
1200 });
1201 RegisterBinary<Strict, const string, const string>(renv, "env-set",
1202 [&](const string& var, const string& val){
1203 SetEnvironmentVariable(var.c_str(), val.c_str());
1204 });
1205 context.Perform(R"NPL(
1206 $defl/e! env-empty?
1207 (make-environment (() get-current-environment) std.strings) (&n)
1208 string-empty? (env-get n);
1209 )NPL");
1210 RegisterStrict(renv, "system", CallSystem);
1211 RegisterStrict(renv, "system-get", [](TermNode& term){
1212 CallUnaryAs<const string>([&](const string& cmd){
1213 TermNode::Container con;
1214 auto res(FetchCommandOutput(cmd.c_str()));
1215
1216 TermNode::AddValueTo(con, ystdex::trim(std::move(res.first)));
1217 TermNode::AddValueTo(con, res.second);
1218 ystdex::swap_dependent(con, term.GetContainerRef());
1219 }, term);
1220 return ReductionStatus::Retained;
1221 });
1222 RegisterUnary<Strict, const string>(renv, "system-quote",
1223 [](const string& w){
1224 return !w.empty() ? ((CheckLiteral(w) == char() && (w.find(' ')
1225 != string::npos || w.find('\t') != string::npos))
1226 || (w.front() == '\'' || w.front() == '"' || w.back() == '\''
1227 || w.back() == '"') ? ystdex::quote(w, '"') : w) : "\"\"";
1228 });
1229 }
1230
1231 void
1232 LoadModule_SHBuild(REPLContext& context)
1233 {
1234 auto& renv(context.Root.GetRecordRef());
1235
1236 // NOTE: SHBuild builtins.
1237 renv.DefineChecked("SHBuild_BaseTerminalHook_",
1238 ValueObject(function<void(const string&, const string&)>(
1239 [](const string& n, const string& val) ynothrow{
1240 // XXX: Error from 'std::printf' is ignored.
1241 std::printf("%s = \"%s\"\n", n.c_str(), val.c_str());
1242 })));
1243 RegisterUnary<Strict, const string>(renv, "SHBuild_BuildGCH_existed_",
1244 [](const string& str) -> bool{
1245 if(IO::UniqueFile
1246 file{uopen(str.c_str(), IO::omode_convb(std::ios_base::in))})
1247 return file->GetSize() > 0;
1248 return {};
1249 });
1250 RegisterUnary<Strict, const string>(renv, "SHBuild_BuildGCH_mkpdirp_",
1251 [](const string& str){
1252 IO::Path pth(str);
1253
1254 if(!pth.empty())
1255 {
1256 pth.pop_back();
1257 EnsureDirectory(pth);
1258 }
1259 });
1260 RegisterUnary<Strict, const string>(renv, "SHBuild_DirectoryOf_",
1261 [](const string& str){
1262 IO::Path pth(str);
1263
1264 if(!pth.empty())
1265 pth.pop_back();
1266 return string(pth);
1267 });
1268 RegisterUnary<Strict, const string>(renv, "SHBuild_EnsureDirectory_",
1269 [](const string& str){
1270 EnsureDirectory(IO::Path(str));
1271 });
1272 RegisterStrict(renv, "SHBuild_EchoVar", [&](TermNode& term){
1273 // XXX: To be overriden if %Terminal is usable (platform specific).
1274 CallBinaryAs<const string, const string>(
1275 [&](const string& n, const string& val){
1276 // NOTE: Since root environment can be switched, reference to the
1277 // initial instance is necessary to be captured explicitly.
1278 if(const auto p = GetValuePtrOf(renv.LookupName(
1279 "SHBuild_BaseTerminalHook_")))
1280 if(const auto p_hook = AccessPtr<
1281 function<void(const string&, const string&)>>(*p))
1282 (*p_hook)(n, val);
1283 }, term);
1284 });
1285 RegisterStrict(renv, "SHBuild_Install_HardLink", [&](TermNode& term){
1286 CallBinaryAs<const string, const string>(
1287 [](const string& dst, const string& src){
1288 InstallHardLink(dst.c_str(), src.c_str());
1289 }, term);
1290 });
1291 // TODO: Implement by derivations instead?
1292 RegisterUnary<Strict, const string>(renv, "SHBuild_QuoteS_",
1293 [](const string& str){
1294 if(str.find('\'') == string::npos)
1295 return ystdex::quote(str, '\'');
1296 throw NPLException("Error in quoted string.");
1297 });
1298 RegisterUnary<Strict, const string>(renv, "SHBuild_RaiseError_",
1299 [](const string& str) YB_ATTR(noreturn){
1300 throw LoggedEvent(str);
1301 });
1302 RegisterBinary<Strict, const string, const string>(renv,
1303 "SHBuild_RemovePrefix_",
1304 [&](const string& str, const string& pfx){
1305 return ystdex::begins_with(str, pfx) ? str.substr(pfx.length()) : str;
1306 });
1307 RegisterUnary<Strict, const string>(renv, "SHBuild_SDot_",
1308 [](const string& str){
1309 auto res(str);
1310
1311 for(auto& c : res)
1312 if(c == '.')
1313 c = '_';
1314 return res;
1315 });
1316 RegisterUnary<Strict, const string>(renv, "SHBuild_String_absolute_path?_",
1317 [](const string& str){
1318 return IO::IsAbsolute(str);
1319 });
1320 RegisterUnary<Strict, const string>(renv, "SHBuild_TrimOptions_",
1321 [](const string& src, const ContextNode& ctx){
1322 string res(src.get_allocator());
1323 const auto a(ctx.get_allocator());
1324 Session sess(a);
1325 set<size_t> left_qset(a);
1326 vector<size_t> qlist(a);
1327 typename string::size_type l(0);
1328 const auto decomp([&](string_view sv){
1329 using iter_t = string_view::const_iterator;
1330
1331 // XXX: As %DelimitedByteParser::DecomposeString.
1332 if(sv.front() != '\'' && sv.front() != '"')
1333 ystdex::split_l(sv.cbegin(), sv.cend(), ystdex::isspace,
1334 [&](iter_t b, iter_t e){
1335 string s(b, e);
1336
1337 ystdex::trim(s);
1338 if(!s.empty())
1339 {
1340 res += s;
1341 res += ' ';
1342 }
1343 });
1344 else
1345 {
1346 if(!res.empty() && l != 0 && left_qset.count(l) != 0
1347 && !ystdex::isspace(src[l - 1]))
1348 res.pop_back();
1349 res += sv;
1350 res += ' ';
1351 }
1352 l += sv.length();
1353 });
1354 auto& lexer(sess.Lexer);
1355 string cbuf(a);
1356 size_t i(0);
1357
1358 yunused(sess.Process(src, [&](char c){
1359 if(lexer.FilterChar(c, cbuf, NPLUnescape, IgnorePrefix))
1360 {
1361 if((c == '\'' || c == '"') && lexer.GetDelimiter() == char())
1362 left_qset.insert(cbuf.length() - 1);
1363 YAssert(!cbuf.empty(), "Invalid buffer found.");
1364 if(lexer.UpdateBack(cbuf.back(), c))
1365 {
1366 // NOTE: As %BufferedByteParserBase::QueryLastDelimited.
1367 const auto s(cbuf.length()
1368 - (lexer.GetDelimiter() != char() ? 1 : 0));
1369
1370 if(s != i)
1371 {
1372 decomp(string_view(&cbuf[i], s - i));
1373 i = s;
1374 }
1375 }
1376 }
1377 }));
1378 if(cbuf.size() != i)
1379 decomp(string_view(&cbuf[i], cbuf.size() - i));
1380 if(!res.empty())
1381 res.pop_back();
1382 return res;
1383 });
1384 }
1385
1386 void
1387 LoadStandardContext(REPLContext& context)
1388 {
1389 LoadGroundContext(context);
1390
1391 auto& rctx(context.Root);
1392 const auto load_std_module([&](string_view module_name,
1393 void(&load_module)(REPLContext&)){
1394 LoadModuleChecked(rctx, "std." + string(module_name),
1395 std::bind(load_module, std::ref(context)));
1396 });
1397
1398 load_std_module("strings", LoadModule_std_strings);
1399 load_std_module("environments", LoadModule_std_environments),
1400 load_std_module("io", LoadModule_std_io),
1401 load_std_module("system", LoadModule_std_system),
1402 load_std_module("promises", LoadModule_std_promises);
1403 }
1404
1405 } // namespace Forms;
1406
1407 } // namespace A1;
1408
1409 } // namespace NPL;
1410
NPL::A1::Forms::Apply
YF_API ReductionStatus Apply(TermNode &, ContextNode &)
函数应用：应用参数指定的函数和作为函数参数的列表。
Definition: NPLA1Forms.cpp:2613
NPL::A1::Forms::MakeEnvironment
YF_API void MakeEnvironment(TermNode &)
创建以参数指定的环境列表作为父环境的新环境。
Definition: NPLA1Forms.cpp:2348
YSLib::Environment
应用程序环境。
Definition: Environment.h:63
YSLib::IO::Path
路径。
Definition: YSLib/Service/FileSystem.h:217
ystdex::begins_with
bool begins_with(const _tRange1 &input, const _tRange2 &test, _fPred comp)
判断第一参数指定的串是否以第二参数起始。
Definition: string.hpp:1176
NPL::A1::Forms::LambdaRef
YF_API ReductionStatus LambdaRef(TermNode &, ContextNode &)
Definition: NPLA1Forms.cpp:2474
NPL::A1::ThrowValueCategoryErrorForFirstArgument
void ThrowValueCategoryErrorForFirstArgument(const TermNode &term)
Definition: NPLA1.cpp:790
YB_ATTR_nodiscard
#define YB_ATTR_nodiscard
标记返回值不被忽略的属性。
Definition: ydef.h:715
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:112
Path
IO::Path Path
Definition: Initialization.cpp:116
x
const EncapsulationBase & x
Definition: NPLA1Forms.cpp:1536
string.hpp
ISO C++ 标准字符串扩展。
NPL::A1::Forms::CallResolvedUnary
auto CallResolvedUnary(_func &&f, TermNode &term) -> yimpl(decltype(NPL::ResolveTerm(yforward(f), term)))
解析节点的子节点并调用一元函数。
Definition: NPLA1Forms.h:148
NPL::A1::Forms::ConsRef
YF_API ReductionStatus ConsRef(TermNode &)
Definition: NPLA1Forms.cpp:2134
NPL::A1::Forms::EvalString
YF_API ReductionStatus EvalString(TermNode &, ContextNode &)
在参数指定的环境中求值作为外部表示的字符串。
Definition: NPLA1Forms.cpp:2325
NPL::A1::Forms::ValueOf
YF_API ReductionStatus ValueOf(TermNode &, const ContextNode &)
求值标识符得到指称的实体。
Definition: NPLA1Forms.cpp:2400
NPL::A1::Forms::If
YF_API ReductionStatus If(TermNode &, ContextNode &)
分支判断：根据求值的条件选取表达式求值。
Definition: NPLA1Forms.cpp:2047
NPL::A1::Forms::VauRef
YF_API ReductionStatus VauRef(TermNode &, ContextNode &)
Definition: NPLA1Forms.cpp:2486
NPL::A1::Forms::ListAsteriskRef
YF_API ReductionStatus ListAsteriskRef(TermNode &)
Definition: NPLA1Forms.cpp:2637
NPL::A1::Forms::ListAsterisk
YF_API ReductionStatus ListAsterisk(TermNode &)
使用可选的参数指定的不定数量的元素和结尾列表构造新列表。
Definition: NPLA1Forms.cpp:2629
CHRLib::c
c
Definition: CharacterProcessing.h:84
NPL::A1::OpenUnique
YSLib::unique_ptr< std::istream > OpenUnique(REPLContext &context, string filename)
Definition: Dependency.cpp:231
NPL::A1::Forms::RetainN
ReductionStatus::Retained YF_API size_t RetainN(const TermNode &, size_t=1)
保留经检查确保具有指定个数参数的项：保留求值。
Definition: NPLA1Forms.cpp:2011
YSLib::IO
Definition: YAdaptor.h:308
ystdex::quote
decay_t< _tString > quote(_tString &&str, typename string_traits< decay_t< _tString >>::value_type c=typename string_traits< decay_t< _tString >>::value_type('"'))
取添加前缀和后缀的字符串。
Definition: string.hpp:1579
NPL::A1::Forms::EqualValue
YF_API void EqualValue(TermNode &)
比较两个子项表示的值相等。
Definition: NPLA1Forms.cpp:2040
YSLib::SetContentWith
_fCallable void SetContentWith(ValueNode &dst, _tNode &&node, _fCallable f)
Definition: ValueNode.h:1440
ystdex::bind1
auto bind1(_func &&f, _tParams &&... args) -> decltype(std::bind(std::forward< decltype(f)>(f), std::placeholders::_1, std::forward< decltype(args)>(args)...))
复合调用 std::bind 和 std::placeholders::_1 。
Definition: functional.hpp:53
YB_PURE
#define YB_PURE
指示函数或函数模板实例为纯函数。
Definition: ydef.h:919
NPL::A1::OpenFile
YSLib::unique_ptr< std::istream > OpenFile(const char *filename)
Definition: Dependency.cpp:224
NPL::IsEmpty
YB_ATTR_nodiscard YB_PURE const TermNode &term ynothrow IsEmpty
Definition: SContext.h:524
NPL::AccessPtr
YB_ATTR_nodiscard YB_PURE observer_ptr< _type > AccessPtr(TermNode &term) ynothrow
Definition: SContext.h:572
platform::CreateSymbolicLink
void CreateSymbolicLink(const char *dst, const char *src, bool is_dir)
Definition: YCLib/FileSystem.cpp:199
YB_ATTR_LAMBDA_QUAL
#define YB_ATTR_LAMBDA_QUAL(_q,...)
允许在 lambda 表达式的参数列表后和限定符共用的属性。
Definition: ydef.h:619
NPL::RelaySwitched
ReductionStatus RelaySwitched(ContextNode &ctx, _fCurrent &&cur)
异步规约指定动作和上下文中的当前动作。
Definition: NPLA.h:3101
NPL::Environment
环境。
Definition: NPLA.h:2004
NPL::A1::Forms::LoadModule_SHBuild
void LoadModule_SHBuild(REPLContext &context)
Definition: Dependency.cpp:1232
YSLib::Drawing::r
The boundary is out of the const Graphics const Rect const Point const Point Color c const Rect const Rect & r
Definition: YDraw.h:174
NPL::A1::Internals::term
_fCurrent TermNode &decltype(cur(term, ctx)) term
Definition: NPLA1Internals.h:593
NPL::A1::REPLContext::Root
ContextState Root
上下文根节点。
Definition: NPLA1.h:1601
platform::omode_convb
std::ios_base::sync_with_stdio(sync)) YB_ATTR_nodiscard YF_API YB_STATELESS int omode_conv(std YB_ATTR_nodiscard YF_API YB_STATELESS int omode_convb(std::ios_base::openmode) ynothrow
ISO C++ 标准输入输出接口打开模式转换为 POSIX 文件打开模式。
Definition: FileIO.cpp:839
ystdex::cpp2017::string_view
basic_string_view< char > string_view
Definition: string_view.hpp:437
NPL::A1::Forms::CallSystem
YF_API void CallSystem(TermNode &)
调用 UTF-8 字符串的系统命令，并保存 int 类型的结果到项的值中。
Definition: NPLA1Forms.cpp:2696
NPL::A1::Forms::LockCurrentEnvironment
YF_API void LockCurrentEnvironment(TermNode &, ContextNode &)
锁定当前环境的引用。
Definition: NPLA1Forms.cpp:2393
NPL::A1::Forms::FirstVal
YF_API ReductionStatus FirstVal(TermNode &)
Definition: NPLA1Forms.cpp:2260
YSLib::GetValuePtrOf
YB_ATTR_nodiscard YF_API YB_PURE observer_ptr< const ValueObject > GetValuePtrOf(observer_ptr< const ValueNode >)
取指定名称指称的值的指针。
Definition: ValueNode.cpp:172
NPL::A1::Forms::AccL
YF_API ReductionStatus AccL(TermNode &, ContextNode &)
在抽象列表元素上应用左结合的二元操作。
Definition: NPLA1Forms.cpp:2644
YB_FLATTEN
#define YB_FLATTEN
标记函数尽可能内联定义内的调用。
Definition: ydef.h:843
NPL::A1::Forms::CallBinaryFold
void CallBinaryFold(_func f, _type val, TermNode &term, _tParams &&... args)
访问节点并以指定的初始值为基础逐项调用二元函数。
Definition: NPLA1Forms.h:296
NPL::A1::Forms::Or
YF_API ReductionStatus Or(TermNode &, ContextNode &)
支持短路求值的逻辑或。
Definition: NPLA1Forms.cpp:2119
NPL::InstallDirectory
void InstallDirectory(const string &dst, const string &src)
Definition: Dependency.cpp:182
NPL::A1::REPLContext::Allocator
TermNode::allocator_type Allocator
节点分配器。
Definition: NPLA1.h:1596
NPL::A1::ThrowInvalidSyntaxError
YB_NORETURN YF_API void ThrowInvalidSyntaxError(string_view)
Definition: NPLA1.cpp:770
next
tidy_ptr< slink > next
Definition: memory_resource.cpp:223
CHRLib::d
_tDst * d
Definition: CharacterProcessing.h:142
NPL::A1::Forms::Equal
YF_API void Equal(TermNode &)
比较两个子项表示的值引用相同的对象。
Definition: NPLA1Forms.cpp:2022
NPL::AllocateEnvironment
shared_ptr< Environment > AllocateEnvironment(ContextNode &ctx, _tParams &&... args)
Definition: NPLA.h:2917
ystdex::share_move
std::shared_ptr< decay_t< _type > > share_move(_tValue &&v)
转移值创建对应的 std::shared_ptr 实例的对象。
Definition: memory.hpp:942
NPL::InstallExecutable
src void InstallExecutable(const char *, const char *)
Definition: Dependency.cpp:215
pfx
ValueObject pfx
Definition: NPLA1.cpp:363
NPL::A1::Forms::When
YF_API ReductionStatus When(TermNode &, ContextNode &)
条件顺序求值：预期条件成立。
Definition: NPLA1Forms.cpp:2093
NPL::A1::Forms::AccR
YF_API ReductionStatus AccR(TermNode &, ContextNode &)
在抽象列表元素上应用右结合的二元操作。
Definition: NPLA1Forms.cpp:2661
NPL::InstallHardLink
YF_API const char src const string const char const char *src void InstallHardLink(const char *, const char *)
Definition: Dependency.cpp:192
NPL::CheckLiteral
YB_ATTR_nodiscard YF_API YB_PURE char CheckLiteral(string_view) ynothrowv
检查指定字符串是否为字面量。
Definition: Lexical.cpp:147
NPL::A1::Forms::Unwrap
YF_API ReductionStatus Unwrap(TermNode &, ContextNode &)
解包装应用子为合并子。
Definition: NPLA1Forms.cpp:2540
NPL::A1::REPLContext::CurrentSource
SourceName CurrentSource
当前源代码名称。
Definition: NPLA1.h:1625
YSLib::IO::TraverseTree
const string &path const String &path class class class class typename _tParams auto TraverseTree(_func f, const Path &dst, const Path &src, _tParams &&... args) -> decltype(f(std::declval< Path & >(), std::declval< Path & >(), std::forward< _tParams >(args)...))
Definition: YSLib/Service/FileSystem.h:715
platform::CreateHardLink
void CreateHardLink(const char *dst, const char *src)
Definition: YCLib/FileSystem.cpp:168
NPL::A1::Forms::SetFirst
YF_API void SetFirst(TermNode &)
修改第一参数指定的列表以第二参数作为第一个元素。
Definition: NPLA1Forms.cpp:2275
NPL::LiftTermOrCopy
PDefH(void, LiftOther, TermNode &term, TermNode &tm) ImplExpr(term.MoveContent(std YF_API void LiftTermOrCopy(TermNode &, TermNode &, bool)
提升项：设置项的内容为参数指定的项或值。
Definition: NPLA.h:1637
NPL::A1::RegisterForm
void RegisterForm(_tTarget &target, string_view name, _tParams &&... args)
注册一般形式上下文处理器。
Definition: NPLA1.h:1028
NPL::ReduceBranchToListValue
PDefH(void, LiftSubtermsToReturn, TermNode &term) ImplExpr(std YF_API ReductionStatus ReduceBranchToListValue(TermNode &) ynothrowv
对每个子项提升项的值数据成员可能包含的引用值。
Definition: NPLA.h:1848
NPL::A1::Forms::Cond
YF_API ReductionStatus Cond(TermNode &, ContextNode &)
条件分支选择：根据条件列表顺序选取第一个符合其中条件对应的表达式求值。
Definition: NPLA1Forms.cpp:2072
NPLA1Internals.h
NPLA1 内部接口。
NPL::A1::Forms::StringToSymbol
YB_ATTR_nodiscard YF_API YB_PURE TokenValue StringToSymbol(const string &)
创建等于指定字符串值的记号值。
Definition: NPLA1Forms.cpp:1992
CHRLib::f
f(d, s)
NPL::Environment::Define
void Define(string_view, ValueObject &&)
以字符串为标识符在指定上下文中添加或覆盖定义。
Definition: NPLA.cpp:939
ystdex::swap_dependent
void swap_dependent(_type &x, _type &y)(is_nothrow_swappable< _type >())
支持基于 ystdex_swap::swap 的 ADL 的左值交换。
Definition: swap.hpp:371
YSLib::FetchCommandOutput
YF_API int FetchCommandOutput(const char *, size_t=DefaultCommandBufferSize)
Definition: YCoreUtilities.cpp:89
platform::SetEnvironmentVariable
void SetEnvironmentVariable(const char *envname, const char *envval)
Definition: YCommon.cpp:102
NPL::tm
tm
Definition: NPLA.h:1941
NPL::FilterMakefileDependencies
YF_API bool FilterMakefileDependencies(vector< string > &)
过滤 GCC 兼容编译器 -MMD 选项生成的 Makefile 项列表并选取依赖项。
Definition: Dependency.cpp:153
NPL::ResolveTerm
auto ResolveTerm(_func do_resolve, _tTerm &&term) -> yimpl(decltype(ystdex::expand_proxy< yimpl(void)(_tTerm &&, ResolvedTermReferencePtr)>::call(do_resolve, yforward(term), ResolvedTermReferencePtr())))
解析并间接引用处理可能是引用值的项。
Definition: NPLA.h:1410
YSLib::IO::PreserveModificationTime
const auto PreserveModificationTime(ystdex::bind_forward(&FileDescriptor::SetModificationTime, &FileDescriptor::GetModificationTime))
保持修改时间。
NPL::MoveCollapsed
YF_API void MoveCollapsed(TermNode &, TermNode &)
提升折叠后的第二参数指定的项。
Definition: NPLA.cpp:741
NPL::ReduceBranchToList
ReductionStatus ReduceBranchToList(TermNode &term) ynothrowv
Definition: NPLA.cpp:816
NPL::A1::Forms::Wrap
YF_API ReductionStatus Wrap(TermNode &, ContextNode &)
包装合并子为应用子。
Definition: NPLA1Forms.cpp:2505
NPL::A1::ThrowNonmodifiableErrorForAssignee
YB_NORETURN YF_API void ThrowNonmodifiableErrorForAssignee()
抛出被赋值操作数不可修改的异常。
Definition: NPLA1.cpp:776
NPL::A1::Forms::Unless
YF_API ReductionStatus Unless(TermNode &, ContextNode &)
条件顺序求值：预期条件不成立。
Definition: NPLA1Forms.cpp:2099
platform::UniqueFile
unique_ptr_from< FileDescriptor::Deleter > UniqueFile
Definition: FileIO.h:486
NPL::A1::REPLContext::Load
Loader Load
加载例程。
Definition: NPLA1.h:1639
NPL::A1::Forms::CallUnary
void CallUnary(_func &&f, TermNode &term, _tParams &&... args)
访问节点并调用一元函数。
Definition: NPLA1Forms.h:228
YSLib::FetchEnvironmentVariable
bool FetchEnvironmentVariable(string &res, const char *var)
Definition: YCoreUtilities.cpp:77
YModules.h
NPL 库模块配置文件。
NPL::A1::CheckSymbol
auto CheckSymbol(string_view n, _func f) -> decltype(f())
检查记号值是符合匹配条件的符号。
Definition: NPLA1.h:1262
YSLib::YAssert
YAssert(!(v< Deref(a)), "Value less than lower bound found.")
YSLib::LoggedEvent
记录日志的异常事件类。
Definition: YException.h:51
NPL::A1::Forms::SetRestRef
YF_API void SetRestRef(TermNode &)
Definition: NPLA1Forms.cpp:2306
NPL::A1::Forms::FirstRef
YF_API ReductionStatus FirstRef(TermNode &)
Definition: NPLA1Forms.cpp:2254
NPL::A1::Forms::FoldR1
YF_API ReductionStatus FoldR1(TermNode &, ContextNode &)
在列表元素上应用右结合的二元操作。
Definition: NPLA1Forms.cpp:2677
platform::uopen
int uopen(const char *filename, int oflag, mode_t pmode) ynothrowv
Definition: FileIO.cpp:872
YSLib::IO::EnsureDirectory
EnsureDirectory
Definition: YSLib/Service/FileSystem.h:558
YSLib::ValueObject
值类型对象类。
Definition: YObject.h:1068
NPL::IsUniqueTerm
YB_ATTR_nodiscard YF_API YB_PURE bool IsUniqueTerm(const TermNode &)
判断项（的值数据成员）是否表示非引用项或唯一引用。
Definition: NPLA.cpp:657
YSLib::Drawing::src
src
Definition: YGDI.h:442
NPL::DecomposeMakefileDepList
YF_API vector< string > DecomposeMakefileDepList(std::streambuf &)
从内容为 GCC 兼容编译器 -MMD 选项生成的 Makefile 的流中分解路径。
Definition: Dependency.cpp:71
NPL::NPLException
NPL 异常基类。
Definition: NPLA.h:445
NPL::EnvironmentReference
环境引用计数检查支持。
Definition: NPLA.h:986
YB_STATELESS
#define YB_STATELESS
指示函数或函数模板实例为无状态函数。
Definition: ydef.h:941
NPL::A1::Forms::FirstAt
YF_API ReductionStatus FirstAt(TermNode &)
Definition: NPLA1Forms.cpp:2248
NPL::A1::Forms::GetCurrentEnvironment
YF_API void GetCurrentEnvironment(TermNode &, ContextNode &)
取当前环境的引用。
Definition: NPLA1Forms.cpp:2386
YSLib::IO::CopyFile
YF_API void CopyFile(UniqueFile, FileDescriptor)
复制文件。
Definition: YSLib/Service/FileSystem.cpp:158
NPL::A1::Forms::Eval
YF_API ReductionStatus Eval(TermNode &, ContextNode &)
对指定项以指定的环境求值。
Definition: NPLA1Forms.cpp:2313
NPL::A1::RegisterStrict
void RegisterStrict(_tTarget &target, string_view name, _tParams &&... args)
注册严格上下文处理器。
Definition: NPLA1.h:1036
platform::HaveSameContents
YB_ATTR_nodiscard YF_API bool HaveSameContents(UniqueFile, UniqueFile, const char *, const char *)
Definition: FileIO.cpp:1290
NPL::A1::REPLContext
Definition: NPLA1.h:1554
NPL::A1::REPLContext::Perform
TermNode Perform(_tParams &&... args)
执行循环：从指定参数指定的来源读取并翻译源代码，并返回处理结果。
Definition: NPLA1.h:1722
NPL::A1::Forms::LoadModule_std_strings
void LoadModule_std_strings(REPLContext &context)
Definition: Dependency.cpp:1075
YB_ATTR
#define YB_ATTR(...)
GNU 风格属性。
Definition: ydef.h:567
NPL::A1::Forms::DefineWithNoRecursion
YF_API ReductionStatus DefineWithNoRecursion(TermNode &, ContextNode &)
不带递归匹配的定义。
Definition: NPLA1Forms.cpp:2427
iterator.hpp
通用迭代器。
NPL::A1::Forms::EvalRef
YF_API ReductionStatus EvalRef(TermNode &, ContextNode &)
Definition: NPLA1Forms.cpp:2319
NPL::ResolveIdentifier
YB_ATTR_nodiscard YF_API TermNode ResolveIdentifier(const ContextNode &, string_view)
解析标识符：解析名称并折叠引用。
Definition: NPLA.cpp:1214
YSLib::ExtractAndTrace
YF_API void ExtractAndTrace(const std::exception &, RecordLevel=Err) ynothrow
使用 TraceException 展开和跟踪异常类型和信息。
YSLib::OwnershipTag
指定对参数指定类型的成员具有所有权的标签。
Definition: YObject.h:91
YSLib::i
return i
Definition: YCoreUtilities.h:177
ystdex::exists
bool exists(const _tCon &con, const _tKey &key)
判断指定的容器中存在指定的键。
Definition: container.hpp:462
NPL::A1::Forms::SetWithNoRecursion
YF_API ReductionStatus SetWithNoRecursion(TermNode &, ContextNode &)
修改指定环境的绑定，不带递归匹配。
Definition: NPLA1Forms.cpp:2439
ystdex::trim
_tString && trim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续前缀与后缀字符。
Definition: string.hpp:1485
NPL::UnescapeContext
反转义上下文。
Definition: Lexical.h:119
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1535
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:407
NPL::A1::Forms::VauWithEnvironment
YF_API ReductionStatus VauWithEnvironment(TermNode &, ContextNode &)
带环境的 vau 抽象：求值为一个捕获当前上下文的非严格求值的函数。
Definition: NPLA1Forms.cpp:2492
platform::Descriptions::Err
@ Err
Definition: YCommon.h:182
NPL::A1::Forms::And
YF_API ReductionStatus And(TermNode &, ContextNode &)
支持短路求值的逻辑与。
Definition: NPLA1Forms.cpp:2113
platform::containers::vector
std::vector< _type, _tAlloc > vector
Definition: Container.h:102
NPL::IsBoundLValueTerm
YB_ATTR_nodiscard YF_API YB_PURE bool IsBoundLValueTerm(const TermNode &)
判断项（的值数据成员）是否表示被绑定的左值引用。
Definition: NPLA.cpp:642
NPL::A1::Forms::SymbolToString
YB_ATTR_nodiscard YF_API YB_STATELESS const string & SymbolToString(const TokenValue &) ynothrow
取符号对应的名称字符串。
Definition: NPLA1Forms.cpp:2005
NPL
Definition: NPL/Configuration.h:35
YSLib::UI::y
SPos SPos y
Definition: YWidget.cpp:44
ystdex::isspace
bool isspace(char c)
区域无关的 std::isspace 。
Definition: cctype.h:140
NPL::A1::Forms::Not
YF_API YB_PURE bool Not(TermNode &)
逻辑非。
Definition: NPLA1Forms.cpp:2105
CatchExpr
#define CatchExpr(_ex,...)
指定表达式作为异常处理器。
Definition: YBaseMacro.h:129
NPL::A1::Forms::Sequence
YF_API ReductionStatus Sequence(TermNode &, ContextNode &)
序列有序参数规约：移除第一项后顺序规约子项，结果为最后一个子项的规约结果。
Definition: NPLA1Forms.cpp:2605
NPL::InstallSymbolicLink
src void InstallSymbolicLink(const char *, const char *)
Definition: Dependency.cpp:205
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:46
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:143
NPL::A1::NameTypedReducerHandler
YB_ATTR_nodiscard YB_PURE _fCallable NameTypedReducerHandler(_fCallable &&x, string_view desc)
初始化作为规约器处理器的全局类型名称表项并转发参数。
Definition: NPLA1.h:1481
NPL::A1::ReduceToLoadExternal
ReductionStatus ReduceToLoadExternal(TermNode &term, ContextNode &ctx, REPLContext &context)
Definition: Dependency.cpp:249
ystdex::tolower
char tolower(char c)
转换大小写字符。
Definition: cctype.h:153
NPL::A1::Forms::CallRawUnary
auto CallRawUnary(_func &&f, TermNode &term, _tParams &&... args) -> yimpl(decltype(ystdex::expand_proxy< void(TermNode &, _tParams &&...)> ::call(f, NPL::Deref(std::next(term.begin())), yforward(args)...)))
访问节点的子节点并调用一元函数。
Definition: NPLA1Forms.h:136
YSLib::Text::BOM_UTF_8
yconstexpr const char BOM_UTF_8[]
Definition: TextFile.h:70
NPL::LiftToReference
void LiftToReference(TermNode &term, TermNode &tm)
Definition: NPLA.cpp:751
NPL::A1::Forms::Vau
YF_API ReductionStatus Vau(TermNode &, ContextNode &)
vau 抽象：求值为一个捕获当前上下文的非严格求值的函数。
Definition: NPLA1Forms.cpp:2480
NPL::A1::Forms::LoadStandardContext
void LoadStandardContext(REPLContext &context)
Definition: Dependency.cpp:1387
NPL::ContextNode
上下文节点。
Definition: NPLA.h:2385
NPL::A1::Forms::LoadModule_std_environments
void LoadModule_std_environments(REPLContext &context)
Definition: Dependency.cpp:1017
platform::Deref
YB_PURE yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:547
NPL::A1::Forms::LoadModule_std_system
void LoadModule_std_system(REPLContext &context)
Definition: Dependency.cpp:1179
NPL::A1::Forms::SetRest
YF_API void SetRest(TermNode &)
修改第一参数指定的列表以第二参数作为第一个元素外的列表。
Definition: NPLA1Forms.cpp:2300
NPL::A1::Forms::Cons
YF_API ReductionStatus Cons(TermNode &)
接受两个参数，返回以第一参数作为第一个元素插入第二参数创建的新的列表。
Definition: NPLA1Forms.cpp:2126
YSLib::Text::buf
YB_ATTR_nodiscard YB_PURE const char * buf
Definition: TextFile.h:83
NPL::Session
会话：分析组成 NPL 基本翻译单元的源代码。
Definition: SContext.h:797
NPL::A1::Forms::First
YF_API ReductionStatus First(TermNode &)
取参数指定的列表中的第一元素的引用值。
Definition: NPLA1Forms.cpp:2197
NPL::UnescapeContext::Length
size_t Length
转义序列长度。
Definition: Lexical.h:133
NPL::A1::RelayToLoadExternal
ReductionStatus RelayToLoadExternal(ContextNode &ctx, TermNode &term, REPLContext &context)
Definition: Dependency.cpp:258
NPL::IsMovable
YB_ATTR_nodiscard YB_PURE PDefH(TermNode &, ReferenceTerm, TermNode &term) ynoexcept_spec(std YB_ATTR_nodiscard YB_PURE yconstfn IsMovable
Definition: NPLA.h:1295
YSLib::Drawing::w
The boundary is out of the const Rect SDst w
Definition: YDraw.h:127
NPL::IsUncollapsedTerm
YB_ATTR_nodiscard YF_API YB_PURE bool IsUncollapsedTerm(const TermNode &)
判断项（的值数据成员）是否表示未折叠的引用。
Definition: NPLA.cpp:649
NPL::A1::Forms::EqualLeaf
YF_API void EqualLeaf(TermNode &)
比较两个子项的值相等。
Definition: NPLA1Forms.cpp:2028
YSLib::IO::IsAbsolute
IsAbsolute
Definition: YSLib/Service/FileSystem.h:62
NPL::LiftTermValueOrCopy
YF_API void LiftTermValueOrCopy(TermNode &, TermNode &, bool)
提升项的值数据成员或项的值数据成员的副本。
Definition: NPLA.cpp:716
NPL::MoveResolved
TermNode MoveResolved(const ContextNode &ctx, string_view id)
Definition: NPLA.cpp:1200
NPL::c_str
YF_API const char src c_str())) YF_API void InstallDirectory(const string &
安装目录：复制目录树。
Definition: Dependency.h:140
NPL::LiftOtherOrCopy
void LiftOtherOrCopy(TermNode &term, TermNode &tm, bool move)
Definition: NPLA.cpp:696
NPL::A1::Forms::EvalStringRef
YF_API ReductionStatus EvalStringRef(TermNode &, ContextNode &)
在参数指定的环境中求值作为外部表示的字符串。
Definition: NPLA1Forms.cpp:2331
NPL::A1::Forms::Map1
YF_API ReductionStatus Map1(TermNode &, ContextNode &)
单列表映射操作。
Definition: NPLA1Forms.cpp:2686
NPL::A1::Forms::Lambda
YF_API ReductionStatus Lambda(TermNode &, ContextNode &)
λ 抽象：求值为一个捕获当前上下文的严格求值的函数。
Definition: NPLA1Forms.cpp:2468
NPL::A1::Forms::EqualReference
YF_API void EqualReference(TermNode &)
比较两个子项的值引用相同的对象。
Definition: NPLA1Forms.cpp:2034
NPL::A1::Forms::DefineLazy
YF_API ReductionStatus DefineLazy(TermNode &, ContextNode &)
以惰性求值的表达式定义值。
Definition: NPLA1Forms.cpp:2419
platform::p
return p p
Definition: YCLib/FileSystem.h:209
NPL::A1::Forms::CheckEnvironment
YF_API ReductionStatus CheckEnvironment(TermNode &)
检查参数指定的项表示环境。
Definition: NPLA1Forms.cpp:2550
NPL::A1::ValueToken
ValueToken
值记号：节点中的值的占位符。
Definition: NPLA1.h:83
YSLib::Text::str
YB_ATTR_nodiscard YB_PURE const char const char * str
Definition: TextFile.h:83
NPL::A1::Forms::ForwardListFirst
YF_API ReductionStatus ForwardListFirst(TermNode &, ContextNode &)
取列表的第一元素并转发给指定的应用子。
Definition: NPLA1Forms.cpp:2141
NPL::MoveRValueToForward
YF_API void MoveRValueToForward(TermNode &, TermNode &)
提升第二参数指定的右值项作为转发的第一参数指定项中的返回值。
Definition: NPLA.cpp:784
ystdex::split_if
void split_if(_tIn b, _tIn e, _fPred is_delim, _fInsert insert, _func pred)
以满足迭代器谓词的指定分隔符分割序列。
Definition: algorithm.hpp:311
ystdex::cpp2014::plus
加法仿函数。
Definition: functor.hpp:357
NPL::A1::Forms::LoadModule_std_io
void LoadModule_std_io(REPLContext &context)
Definition: Dependency.cpp:1146
platform::bool
YB_ATTR_nodiscard std::FILE *fp bool
Definition: FileIO.h:1271
NPL::dst
YF_API const char src const string const char * dst
Definition: Dependency.h:96
NPL::A1::PreloadExternal
void PreloadExternal(REPLContext &context, const char *filename)
Definition: Dependency.cpp:242
NPL::A1::Forms::WrapRef
YF_API ReductionStatus WrapRef(TermNode &, ContextNode &)
包装合并子为应用子。
Definition: NPLA1Forms.cpp:2518
ystdex::cpp2017::string
basic_string< char > string
Definition: string.hpp:772
YSLib::IO::VerifyDirectory
VerifyDirectory
Definition: YSLib/Service/FileSystem.h:524
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:1199
NPL::InstallFile
void InstallFile(const char *dst, const char *src)
Definition: Dependency.cpp:166
NPL::A1::ReduceOnce
YF_API ReductionStatus ReduceOnce(TermNode &, ContextNode &)
NPLA1 表达式节点一次规约：转发调用到 NPLA1 表达式节点一次规约续延并调用。
Definition: NPLA1.cpp:959
NPL::A1::Forms::SetFirstAt
YF_API void SetFirstAt(TermNode &)
Definition: NPLA1Forms.cpp:2283
YSLib::vo
vo
Definition: YApplication.h:231
NPL::A1::Forms::CheckListReference
YF_API ReductionStatus CheckListReference(TermNode &)
检查参数指定的项表示非空列表的引用。
Definition: NPLA1Forms.cpp:2562
TryExpr
#define TryExpr(...)
指定表达式在 try 块中求值。
Definition: YBaseMacro.h:120
NPL::A1::Forms::SetFirstRef
YF_API void SetFirstRef(TermNode &)
Definition: NPLA1Forms.cpp:2291
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:1458
NPL::A1::Forms::VauWithEnvironmentRef
YF_API ReductionStatus VauWithEnvironmentRef(TermNode &, ContextNode &)
Definition: NPLA1Forms.cpp:2498
ystdex::ref
void ref(const _type &&)=delete
NPL::A1::Forms::LoadGroundContext
void LoadGroundContext(REPLContext &context)
Definition: Dependency.cpp:1009
YSLib::LockCommandArguments
locked_ptr< ArgumentsVector, recursive_mutex > LockCommandArguments()
Definition: YCoreUtilities.cpp:67
NPL::A1::Forms::MakeEncapsulationType
YF_API ReductionStatus MakeEncapsulationType(TermNode &)
创建封装类型。
Definition: NPLA1Forms.cpp:2574
NPL::ContextNode::GetRecordRef
!current Environment::BindingMap GetRecordRef().GetMapRef()) DefGetter(const ynothrow
NPL::IsReferenceTerm
YB_ATTR_nodiscard YF_API YB_PURE bool IsReferenceTerm(const TermNode &)
判断项（的值数据成员）是否为引用项。
Definition: NPLA.cpp:636
NPL::ReductionStatus
ReductionStatus
规约状态：某个项上的一遍规约可能的中间结果。
Definition: NPLA.h:1520
ystdex::call_value_or
auto call_value_or(_func f, _type &&p) -> decay_t< decltype(f(*std::forward< decltype(p)>(p)))>
调用非空值或取默认值。
Definition: deref_op.hpp:152
NPL::EnvironmentReference::Lock
const EnvironmentReference const EnvironmentReference &y ynothrow const AnchorPtr p_anchor Lock
Definition: NPLA.h:1043
YSLib::a
YB_PURE const _type * a
Definition: YCoreUtilities.h:168
NPL::A1::Forms::LoadModule_std_promises
void LoadModule_std_promises(REPLContext &context)
Definition: Dependency.cpp:1043
NPL::A1::Forms::EvalUnit
YF_API ReductionStatus EvalUnit(TermNode &)
在参数指定的 REPL 环境中规约字符串表示的翻译单元以求值。
Definition: NPLA1Forms.cpp:2337
platform::l
return l
Definition: YCLib/FileSystem.h:402
NPL::ResolveEnvironment
YB_ATTR_nodiscard YF_API pair< shared_ptr< Environment >, bool > ResolveEnvironment(const ValueObject &)
解析环境。
Definition: NPLA.cpp:1224
ystdex::split_l
_tIn split_l(_tIn b, _tIn e, _fPred is_delim, _fInsert insert)
以指定分隔符分割保留起始分隔符的序列。
Definition: algorithm.hpp:339
NPL::A1::Forms::SetWithRecursion
YF_API ReductionStatus SetWithRecursion(TermNode &, ContextNode &)
修改指定环境的绑定，带递归匹配。
Definition: NPLA1Forms.cpp:2445
NPL::A1::Forms::DefineWithRecursion
YF_API ReductionStatus DefineWithRecursion(TermNode &, ContextNode &)
带递归匹配的定义。
Definition: NPLA1Forms.cpp:2433