YSTest: NPLA1.cpp 源文件

YSTest PreAlpha_b700_20160611 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

NPLA1.cpp
浏览该文件的文档.
1 /*
2 © 2014-2016 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_NPLA1 // for ystdex::bind1, YSLib::RemoveEmptyChildren,
30 // ystdex::pvoid;
31 #include YFM_NPL_SContext
32 #include <ystdex/scope_guard.hpp> // for ystdex::unique_guard;
33
34 using namespace YSLib;
35
36 namespace NPL
37 {
38
39 namespace A1
40 {
41
42 void
43 InsertChild(TermNode&& term, TermNode::Container& con)
44 {
45 con.insert(term.GetName().empty() ? AsNode('$' + MakeIndex(con),
46 std::move(term.Value)) : std::move(MapToValueNode(term)));
47 }
48
49 void
50 InsertSequenceChild(TermNode&& term, NodeSequence& con)
51 {
52 con.emplace_back(std::move(MapToValueNode(term)));
53 }
54
55 ValueNode
56 TransformNode(const TermNode& term, NodeMapper mapper, NodeMapper map_leaf_node,
57 NodeToString node_to_str, NodeInserter insert_child)
58 {
59 auto s(term.size());
60
61 if(s == 0)
62 return map_leaf_node(term);
63
64 auto i(term.begin());
65 const auto nested_call(ystdex::bind1(TransformNode, mapper, map_leaf_node,
66 node_to_str, insert_child));
67
68 if(s == 1)
69 return nested_call(*i);
70
71 const auto& name(node_to_str(*i));
72
73 if(!name.empty())
74 yunseq(++i, --s);
75 if(s == 1)
76 {
77 auto&& nd(nested_call(*i));
78
79 if(nd.GetName().empty())
80 return AsNode(name, std::move(nd.Value));
81 return {ValueNode::Container{std::move(nd)}, name};
82 }
83
84 ValueNode::Container node_con;
85
86 std::for_each(i, term.end(), [&](const TermNode& tm){
87 insert_child(mapper ? mapper(tm) : nested_call(tm), node_con);
88 });
89 return {std::move(node_con), name};
90 }
91
92 ValueNode
93 TransformNodeSequence(const TermNode& term, NodeMapper mapper, NodeMapper
94 map_leaf_node, NodeToString node_to_str, NodeSequenceInserter insert_child)
95 {
96 auto s(term.size());
97
98 if(s == 0)
99 return map_leaf_node(term);
100
101 auto i(term.begin());
102 auto nested_call(ystdex::bind1(TransformNodeSequence, mapper,
103 map_leaf_node, node_to_str, insert_child));
104
105 if(s == 1)
106 return nested_call(*i);
107
108 const auto& name(node_to_str(*i));
109
110 if(!name.empty())
111 yunseq(++i, --s);
112 if(s == 1)
113 {
114 auto&& n(nested_call(*i));
115
116 return AsNode(name, n.GetName().empty() ? std::move(n.Value)
117 : ValueObject(NodeSequence{std::move(n)}));
118 }
119
120 NodeSequence node_con;
121
122 std::for_each(i, term.end(), [&](const TermNode& tm){
123 insert_child(mapper ? mapper(tm) : nested_call(tm), node_con);
124 });
125 return AsNode(name, std::move(node_con));
126 }
127
128
130 namespace
131 {
132
133 yconstexpr const auto GuardName("__$!");
134 yconstexpr const auto LeafTermName("__$$@");
135 yconstexpr const auto ListTermName("__$$");
136
137 } // unnamed namespace;
138
139 GuardPasses&
140 AccessGuardPassesRef(ContextNode& ctx)
141 {
142 return ctx.Place<GuardPasses>(GuardName);
143 }
144
145 EvaluationPasses&
146 AccessLeafPassesRef(ContextNode& ctx)
147 {
148 return ctx.Place<EvaluationPasses>(LeafTermName);
149 }
150
151 EvaluationPasses&
152 AccessListPassesRef(ContextNode& ctx)
153 {
154 return ctx.Place<EvaluationPasses>(ListTermName);
155 }
156
157 Guard
158 EvaluateGuard(TermNode& term, ContextNode& ctx)
159 {
160 return InvokePasses<GuardPasses>(term, ctx, GuardName);
161 }
162
163 bool
164 EvaluateLeafPasses(TermNode& term, ContextNode& ctx)
165 {
166 return InvokePasses<EvaluationPasses>(term, ctx, LeafTermName);
167 }
168
169 bool
170 EvaluateListPasses(TermNode& term, ContextNode& ctx)
171 {
172 return InvokePasses<EvaluationPasses>(term, ctx, ListTermName);
173 }
174
175
176 bool
177 Reduce(TermNode& term, ContextNode& ctx)
178 {
179 const auto gd(EvaluateGuard(term, ctx));
180
181 // NOTE: Rewriting loop until the normal form is got.
182 return ystdex::retry_on_cond(std::bind(DetectReducible, std::ref(term),
183 std::placeholders::_1), [&]() -> bool{
184 if(!term.empty())
185 {
186 YAssert(term.size() != 0, "Invalid node found.");
187 if(term.size() != 1)
188 // NOTE: List evaluation.
189 return EvaluateListPasses(term, ctx);
190 else
191 {
192 // NOTE: List with single element shall be reduced to its value.
193 LiftFirst(term);
194 return Reduce(term, ctx);
195 }
196 }
197 else if(!term.Value)
198 // NOTE: Empty list.
199 term.Value = ValueToken::Null;
200 else if(AccessPtr<ValueToken>(term))
201 // TODO: Handle special value token.
202 ;
203 else
204 return EvaluateLeafPasses(term, ctx);
205 // NOTE: Exited loop has produced normal form by default.
206 return {};
207 });
208 }
209
210 void
211 ReduceChildren(TermNode::iterator first, TermNode::iterator last,
212 ContextNode& ctx)
213 {
214 // NOTE: Here it can only be either left-to-right or right-to-left unless
215 // the separators has been predicted.
216 std::for_each(first, last,
217 std::bind(Reduce, std::placeholders::_1, std::ref(ctx)));
218 }
219
220 void
221 ReduceArguments(TermNode::Container& con, ContextNode& ctx)
222 {
223 if(con.size() > 1)
224 // NOTE: The order of evaluation is unspecified by the language
225 // specification. It should not be depended on.
226 ReduceChildren(std::next(con.begin()), con.end(), ctx);
227 else
228 throw LoggedEvent("Invalid term to handle found.", Err);
229 }
230
231
232 void
233 SetupTraceDepth(ContextNode& root, const string& name)
234 {
235 yunseq(
236 root.Place<size_t>(name),
237 AccessGuardPassesRef(root) = [name](TermNode& term, ContextNode& ctx){
238 using ystdex::pvoid;
239 auto& depth(AccessChild<size_t>(ctx, name));
240
241 YTraceDe(Informative, "Depth = %zu, context = %p, semantics = %p.",
242 depth, pvoid(&ctx), pvoid(&term));
243 ++depth;
244 return ystdex::unique_guard([&]() ynothrow{
245 --depth;
246 });
247 }
248 );
249 }
250
251
252 TermNode
253 TransformForSeparator(const TermNode& term, const ValueObject& pfx,
254 const ValueObject& delim, const string& name)
255 {
256 auto res(AsNode(name, term.Value));
257
258 if(!term.empty())
259 {
260 res += AsIndexNode(res, pfx);
261 ystdex::split(term.begin(), term.end(), std::bind(HasValue,
262 std::placeholders::_1, std::ref(delim)), [&](TNCIter b, TNCIter e){
263 auto child(AsIndexNode(res));
264
265 while(b != e)
266 {
267 child += {b->GetContainer(), MakeIndex(child), b->Value};
268 ++b;
269 }
270 res += std::move(child);
271 });
272 }
273 return res;
274 }
275
276 TermNode
277 TransformForSeparatorRecursive(const TermNode& term, const ValueObject& pfx,
278 const ValueObject& delim, const string& name)
279 {
280 auto res(AsNode(name, term.Value));
281
282 if(!term.empty())
283 {
284 res += AsIndexNode(res, pfx);
285 ystdex::split(term.begin(), term.end(), std::bind(HasValue,
286 std::placeholders::_1, std::ref(delim)), [&](TNCIter b, TNCIter e){
287 while(b != e)
288 res += TransformForSeparatorRecursive(*b++, pfx, delim,
289 MakeIndex(res));
290 });
291 }
292 return res;
293 }
294
295 bool
296 ReplaceSeparatedChildren(TermNode& term, const ValueObject& pfx,
297 const ValueObject& delim)
298 {
299 if(std::find_if(term.begin(), term.end(), std::bind(HasValue,
300 std::placeholders::_1, std::ref(delim))) != term.end())
301 term = TransformForSeparator(term, pfx, delim, term.GetName());
302 return {};
303 }
304
305
306 void
307 FormContextHandler::operator()(TermNode& term, ContextNode& ctx) const
308 {
309 // TODO: Is it worth matching specific builtin special forms here?
310 try
311 {
312 if(!term.empty())
313 Handler(term, ctx);
314 else
315 // TODO: Use more specific exceptions.
316 throw std::invalid_argument("Empty term found.");
317 }
318 CatchExpr(NPLException&, throw)
319 CatchThrow(ystdex::bad_any_cast& e, LoggedEvent(
320 ystdex::sfmt("Mismatched types ('%s', '%s') found.",
321 e.from(), e.to()), Warning))
322 // TODO: Use nest exceptions?
323 CatchThrow(std::exception& e, LoggedEvent(e.what(), Err))
324 }
325
326
327 void
328 FunctionContextHandler::operator()(TermNode& term, ContextNode& ctx) const
329 {
330 auto& con(term.GetContainerRef());
331
332 // NOTE: This implementes arguments evaluation in applicative order.
333 ReduceArguments(con, ctx);
334
335 const auto n(con.size());
336
337 if(n > 1)
338 {
339 // NOTE: Matching function calls.
340 auto i(con.begin());
341
342 // NOTE: Adjust null list argument application
343 // to function call without arguments.
344 // TODO: Improve performance of comparison?
345 if(n == 2 && Deref(++i).Value == ValueToken::Null)
346 con.erase(i);
347 Handler(term, ctx);
348 }
349 else
350 // TODO: Use other exception type for this type of error?
351 // TODO: Capture contextual information in error.
352 throw ListReductionFailure(ystdex::sfmt("Invalid list form with"
353 " %zu term(s) not reduced found.", n), YSLib::Warning);
354 // TODO: Add unreduced form check? Is this better to be inserted in other
355 // passes?
356 #if false
357 if(con.empty())
358 YTraceDe(Warning, "Empty reduced form found.");
359 else
360 YTraceDe(Warning, "%zu term(s) not reduced found.", n);
361 #endif
362 }
363
364
365 bool
366 EvaluateContextFirst(TermNode& term, ContextNode& ctx)
367 {
368 if(!term.empty())
369 {
370 const auto& fm(Deref(ystdex::as_const(term).begin()));
371
372 if(const auto p_handler = AccessPtr<ContextHandler>(fm))
373 (*p_handler)(term, ctx);
374 else
375 {
376 const auto p(AccessPtr<string>(fm));
377
378 // TODO: Capture contextual information in error.
379 throw ListReductionFailure(ystdex::sfmt("No matching form '%s'"
380 " with %zu argument(s) found.", p ? p->c_str()
381 : "#<unknown>", term.size()));
382 }
383 }
384 return false;
385 }
386
387 } // namesapce A1;
388
389 } // namespace NPL;
390
ystdex::mapped_set::begin
iterator begin()
Definition: set.hpp:284
NPL::term
const TermNode &term ValueNode &node const ValueNode &node const TermNode & term
Definition: SContext.h:72
platform::p
while p p
Definition: YCLib/FileSystem.h:225
NPL::A1::EvaluateLeafPasses
YF_API bool EvaluateLeafPasses(TermNode &term, ContextNode &)
求值叶节点遍。
Definition: NPLA1.cpp:164
NPL::DetectReducible
YF_API bool DetectReducible(TermNode &, bool)
移除节点的空子节点，然后判断是否可继续规约。
Definition: NPLA.cpp:364
ystdex::sfmt
auto sfmt(const _tChar *fmt,...) -> decltype(vsfmt(fmt, std::declval< std::va_list >()))
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1140
yconstexpr
#define yconstexpr
指定编译时常量表达式。
Definition: ydef.h:653
platform::Descriptions::Warning
Definition: YCommon.h:157
YSLib::GEvent
事件模板。
Definition: YEvent.hpp:312
platform::Descriptions::Informative
Definition: YCommon.h:159
YSLib::ValueNode::Place
ynothrow typename _tParams _type & Place(_tString &&str, _tParams &&...args)
Definition: ValueNode.h:327
NPL::A1::TransformForSeparator
YF_API TermNode TransformForSeparator(const TermNode &, const ValueObject &, const ValueObject &, const string &={})
变换分隔符中缀表达式为前缀表达式。
Definition: NPLA1.cpp:253
YSLib::MakeIndex
MakeIndex
Definition: ValueNode.h:865
YSLib::ValueNode::begin
begin
Definition: ValueNode.h:398
NPL::A1::name
ctx const string & name
Definition: NPLA1.h:248
NPL::A1::AccessLeafPassesRef
YF_API EvaluationPasses & AccessLeafPassesRef(ContextNode &)
访问叶节点遍。
Definition: NPLA1.cpp:146
NPL::MapToValueNode
const TermNode &term MapToValueNode
Definition: SContext.h:61
YSLib::ValueNode::end
const container container const ynothrow end
Definition: ValueNode.h:413
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:45
ystdex::mapped_set::size
size_type size() const
Definition: set.hpp:358
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:109
CHRLib::CharSet::Null
空字符集。
Definition: Encoding.h:63
NPL::A1::TransformForSeparatorRecursive
YF_API TermNode TransformForSeparatorRecursive(const TermNode &, const ValueObject &, const ValueObject &, const string &={})
递归变换分隔符中缀表达式为前缀表达式。
Definition: NPLA1.cpp:277
NPL::A1::Reduce
YF_API bool Reduce(TermNode &, ContextNode &)
NPLA1 节点规约。
Definition: NPLA1.cpp:177
CatchExpr
#define CatchExpr(_ex,...)
指定表达式作为异常处理器。
Definition: YBaseMacro.h:129
NPL::NodeInserter
GNodeInserter< TermNode::Container & > NodeInserter
Definition: NPLA.h:101
YSLib::LoggedEvent
记录日志的异常事件类。
Definition: YException.h:49
NPL::NodeSequenceInserter
GNodeInserter< NodeSequence > NodeSequenceInserter
Definition: NPLA.h:103
ystdex::mapped_set
允许指定不同于值类型的键的集合。
Definition: set.hpp:160
NPL::A1::InsertSequenceChild
YF_API void InsertSequenceChild(TermNode &&, NodeSequence &)
Definition: NPLA1.cpp:50
ystdex::bad_any_cast::to
const char * to() const
Definition: any.cpp:64
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:305
NPL::A1::TransformNode
YF_API ValueNode TransformNode(const TermNode &, NodeMapper={}, NodeMapper=MapNPLALeafNode, NodeToString=ParseNPLANodeString, NodeInserter=InsertChild)
变换 NPLA1 节点 S 表达式抽象语法树为 NPLA1 语义结构。 第三至五参数为空。
Definition: NPLA1.cpp:56
YSLib::ynothrow
YB_PURE const _type size_t n ynothrow
Definition: YCoreUtilities.h:168
ystdex::bad_any_cast
动态泛型转换失败异常。
Definition: any.h:636
ystdex::any
基于类型擦除的动态泛型对象。
Definition: any.h:823
NPL::A1::SetupTraceDepth
void SetupTraceDepth(ContextNode &root, const string &name)
Definition: NPLA1.cpp:233
NPL::GuardPasses
YSLib::GEvent< Guard(TermNode &, ContextNode &), YSLib::GDefaultLastValueInvoker< Guard >> GuardPasses
作用域守护遍：用于需在规约例程的入口和出口关联执行的操作。
Definition: NPLA.h:552
platform::Deref
yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:440
NPL::A1::EvaluateGuard
YF_API Guard EvaluateGuard(TermNode &term, ContextNode &)
求值守护。
Definition: NPLA1.cpp:158
YModules.h
NPL::A1::ReplaceSeparatedChildren
YF_API bool ReplaceSeparatedChildren(TermNode &, const ValueObject &, const ValueObject &)
查找项中的指定分隔符，若找到则替换项为去除分隔符并添加替换前缀的形式。
Definition: NPLA1.cpp:296
YSLib::YAssert
YAssert(!(v< Deref(a)),"Value less than lower bound found.")
NPL::A1::EvaluateContextFirst
YF_API bool EvaluateContextFirst(TermNode &, ContextNode &)
检查非空项的首项并尝试按上下文列表求值。
Definition: NPLA1.cpp:366
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:996
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:583
YSLib::UI::Styles::Handler
std::function< void(PaintEventArgs &&)> Handler
样式处理器。
Definition: YStyle.h:380
NPL
Definition: NPL/Configuration.h:34
ystdex::pvoid
enable_if_t< or_< is_object< _type >, is_void< _type > >::value, void * > pvoid(_type *p)
取 void* 类型的指针。
Definition: addressof.hpp:101
YSLib::ValueNode::empty
const container container empty
Definition: ValueNode.h:410
NPL::A1::AccessListPassesRef
YF_API EvaluationPasses & AccessListPassesRef(ContextNode &)
访问列表节点遍。
Definition: NPLA1.cpp:152
ystdex::mapped_set::end
iterator end()
Definition: set.hpp:295
YSLib::ValueNode::Value
ValueObject Value
Definition: ValueNode.h:83
YSLib::i
return i
Definition: YCoreUtilities.h:176
NPL::NodeToString
std::function< string(const ValueNode &)> NodeToString
Definition: NPLA.h:96
scope_guard.hpp
作用域守护。
NPL::A1::AccessGuardPassesRef
YF_API GuardPasses & AccessGuardPassesRef(ContextNode &)
访问守护遍。
Definition: NPLA1.cpp:140
YSLib::NodeSequence
yimpl(YSLib::vector)< ValueNode > NodeSequence
节点序列容器。
Definition: ValueNode.h:888
YSLib::ValueNode
值类型节点。
Definition: ValueNode.h:57
YSLib::ValueNode::size
const const ValueNode &node size
Definition: ValueNode.h:464
ystdex::split
void split(_tIn b, _tIn e, _fPred is_delim, _fInsert insert)
以指定分隔符分割序列。
Definition: algorithm.hpp:209
NPL::ListReductionFailure
列表规约失败。
Definition: NPLA.h:408
ystdex::cpp2011::begin
_type * begin(_type(&&array)[_vN])
Definition: range.hpp:46
NPL::A1::InsertChild
YF_API void InsertChild(TermNode &&, TermNode::Container &)
插入 NPLA1 子节点。
Definition: NPLA1.cpp:43
NPL::NPLException
NPL 异常基类。
Definition: NPLA.h:385
platform::Descriptions::Err
Definition: YCommon.h:156
ystdex::retry_on_cond
result_of_t< _fCallable &&(_tParams &&...)> retry_on_cond(_fCond cond, _fCallable &&f, _tParams &&...args)
循环重复调用：代替直接使用 do-while 语句以避免过多引入作用域外的变量。
Definition: functional.hpp:1019
NPL::A1::EvaluateListPasses
YF_API bool EvaluateListPasses(TermNode &term, ContextNode &)
求值列表节点遍。
Definition: NPLA1.cpp:170
NPL::A1::ReduceChildren
YF_API void ReduceChildren(TermNode::iterator, TermNode::iterator, ContextNode &)
规约子项。
Definition: NPLA1.cpp:211
ystdex::mapped_set::insert
std::pair< iterator, bool > insert(const value_type &x)
Definition: set.hpp:389
YSLib::ValueObject
值类型对象类。
Definition: YObject.h:272
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
ystdex::unique_guard
guard< one_shot< _type > > unique_guard(_type f)
Definition: scope_guard.hpp:92
YSLib::AsIndexNode
const ValueNode &node typename _tParams ValueNode AsIndexNode(_tParam &&arg, _tParams &&...args)
Definition: ValueNode.h:876
NPL::A1::TransformNodeSequence
YF_API ValueNode TransformNodeSequence(const TermNode &, NodeMapper={}, NodeMapper=MapNPLALeafNode, NodeToString=ParseNPLANodeString, NodeSequenceInserter=InsertSequenceChild)
变换 NPLA1 节点 S 表达式抽象语法树为 NPLA1 序列语义结构。 第三至五参数为空。
Definition: NPLA1.cpp:93
ystdex::as_const
add_const_t< _type > & as_const(_type &t)
转换 const 引用。
Definition: utility.hpp:50
ystdex::bad_any_cast::from
const char * from() const
Definition: any.cpp:57
platform::n
size_t n
Definition: YCLib/FileSystem.cpp:321
CatchThrow
#define CatchThrow(_ex,...)
指定抛出指定异常作为异常处理器。
Definition: YBaseMacro.h:141
NPL::NodeMapper
std::function< ValueNode(const TermNode &)> NodeMapper
节点映射操作类型：变换节点为另一个节点。
Definition: NPLA.h:92
ystdex::transformed_iterator
变换迭代器。
Definition: iterator.hpp:216
ystdex::ref
lref< _type > ref(_type &t)
构造引用包装。
Definition: ref.hpp:120
NPL::A1::ReduceArguments
con ctx ctx YF_API void ReduceArguments(TermNode::Container &, ContextNode &)
对容器中的第二项开始逐项规约。
Definition: NPLA1.cpp:221
NPL::HasValue
const TermNode &term ValueNode &node const ValueNode &node HasValue
Definition: SContext.h:72