blob: 3b41828ff60fb7fa2ac6ebd5c4a67ff5ab806608 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
// Minimum amount of memory on the stack required by a visitor call.
// Use this value to control when to stop the visitor recursion before a SOE occurs.
#define PNODEVISIRORSIZE 256
template <class Context>
struct VisitorPolicyBase
{
typedef Context Context;
protected:
inline bool Preorder(ParseNode *pnode, Context context) { return true; }
inline void Inorder(ParseNode *pnode, Context context) { }
inline void Midorder(ParseNode *pnode, Context context) { }
inline void Postorder(ParseNode *pnode, Context context) { }
inline void InList(ParseNode *pnode, Context context) { }
// This will be useful when you want the reference of your current node.
inline void PassReference(ParseNode **ppnode, Context context) { }
};
template <class Visitor, class VisitorPolicy>
struct VisitorWalkerPolicy : public VisitorPolicy
{
public:
typedef ParseNode *ResultType;
typedef struct WalkerContext
{
typename VisitorPolicy::Context visitorContext;
Visitor *visitor;
WalkerContext(typename VisitorPolicy::Context context, Visitor *visitor): visitorContext(context), visitor(visitor) { }
} *Context;
inline ParseNode *DefaultResult() { return NULL; }
inline bool ContinueWalk(ParseNode *result) { return true; }
inline ParseNode *WalkNode(ParseNode *pnode, Context context) { Inorder(pnode, context->visitorContext); return pnode; }
inline ParseNode *WalkListNode(ParseNode *pnode, Context context) { InList(pnode, context->visitorContext); return NULL; }
inline ParseNode *WalkFirstChild(ParseNode *pnode, Context context) { context->visitor->VisitNode(pnode, context); return pnode; }
inline ParseNode *WalkSecondChild(ParseNode *pnode, Context context) { context->visitor->VisitNode(pnode, context); return pnode; }
inline ParseNode *WalkNthChild(ParseNode *pparentnode, ParseNode *pnode, Context context) { Midorder(pparentnode, context->visitorContext); context->visitor->VisitNode(pnode, context); return pnode; }
inline void WalkReference(ParseNode **ppnode, Context context) { context->visitor->PassReferenceNode(ppnode, context); }
};
template <class VisitorPolicy>
class ParseNodeVisitor : public ParseNodeWalker<VisitorWalkerPolicy<ParseNodeVisitor<VisitorPolicy>, VisitorPolicy> >
{
typedef VisitorWalkerPolicy<ParseNodeVisitor<VisitorPolicy>, VisitorPolicy> WalkerPolicy;
typedef typename WalkerPolicy::WalkerContext WalkerContext;
public:
typedef typename VisitorPolicy::Context VisitorContext;
void Visit(ParseNode *pnode, VisitorContext context = VisitorContext())
{
WalkerContext walkerContext(context, this);
VisitNode(pnode, &walkerContext);
}
void VisitNode(ParseNode *pnode, Context context)
{
if (!ThreadContext::IsCurrentStackAvailable(PNODEVISIRORSIZE))
return;
if (!pnode) return;
if (!Preorder(pnode, context->visitorContext))
return;
Walk(pnode, context);
Postorder(pnode, context->visitorContext);
}
void PassReferenceNode(ParseNode **ppnode, Context context)
{
PassReference(ppnode, context->visitorContext);
}
};