1 using Mercury.Nucleus.Trees;
4 using System.Collections.Generic;
6 using System.Runtime.Caching;
7 using System.Threading.Tasks;
9 namespace Mercury.Interpreting
20 public interface IInterpreter<T> where T : class
36 IReadOnlyList<InterpreterResult<T>> Interpret(IReadOnlyList<Tree<Symbol>> trees);
57 public class Interpreter<T> : IInterpreter<T> where T : class
67 #region [ Wildcard Context ]
69 private struct WildcardContext
77 public WildcardContext(
Wildcard w,
int six,
int tix,
int tc,
int ic)
80 strcix = six; treeix = tix;
81 treecnt = tc; instcnt = ic;
89 #region [ Structure matching ]
96 case ElementType.Constant:
return Instantiate(element as
Constant, tree, instances);
97 case ElementType.Variable:
return Instantiate(element as
Variable, tree, instances);
98 case ElementType.Structure:
return Instantiate(element as
Structure, tree, instances);
99 default:
return false;
105 {
return constant.MatchesSymbol(tree.Value); }
113 instances.Add(
new Instance(variable, tree));
120 int scc = structure.Children.Count;
121 int tcc = tree.Children.Count;
123 if (!structure.
HasWildcard && (scc != tcc))
return false;
125 int strcix = 0, treeix = 0;
126 Stack<WildcardContext> stack =
new Stack<WildcardContext>();
128 if ((structure.Value.
Type !=
ElementType.Wildcard) && !Instantiate(structure.Value, tree, instances))
133 if ((strcix >= scc) && (treeix >= tcc))
break;
138 if ((strcix >= scc) || ((treeix >= tcc) && (structure[strcix].Value.
Type !=
ElementType.Wildcard)))
140 else if ((strct = structure[strcix] as
Structure) != null)
141 status = Instantiate(strct, tree[treeix], instances);
144 stack.Push(
new WildcardContext(
145 structure[strcix].Value as
Wildcard,
146 strcix, treeix, 0, instances.
Count));
147 instances.Add(
new Instance(stack.Peek().wildcard,
new Tree<Symbol>[0]));
151 status = Instantiate(structure[strcix].Value, tree[treeix], instances);
153 if (!status && !Retry(stack, tree, instances, ref strcix, ref treeix))
164 private bool Retry(Stack<WildcardContext> stack, Tree<Symbol> tree,
InstanceList instances, ref
int sx, ref
int tx)
166 while(stack.Count != 0)
168 WildcardContext context = stack.Pop();
169 instances.RemoveLast(instances.Count - context.instcnt);
172 tx = context.treeix + (context.treecnt++);
174 if ((tx >= tree.Children.Count) || !context.wildcard.MatchesSymbol(tree[tx].Value))
177 var data =
new Tree<Symbol>[context.treecnt];
178 for (
int ix = 0; ix < context.treecnt; ++ix)
179 data[ix] = tree[context.treeix + ix];
182 instances.Add(
new Instance(context.wildcard, data));
191 #region [ Argument processing ]
201 case ArgumentType.ParserEntity:
if (!tree.IsLeaf)
goto case ArgumentType.Tree;
202 else goto case ArgumentType.Symbol;
209 throw new InvalidOperationException(
"This is not a wildcard");
211 var data = instance.Value as Tree<Symbol>[];
212 var args =
new Argument[data.Length];
214 for(
int ix = 0; ix < data.Length; ++ix)
215 args[ix] = GetArgument(data[ix] as Tree<Symbol>, required);
222 List<Argument> args =
new List<Argument>();
224 for(
int ix = 0; ix < call.FormalParameters.Count; ++ix)
230 case ParameterType.IntegralConstant: argtype = ArgumentType.Integer;
goto constant;
231 case ParameterType.RealConstant: argtype = ArgumentType.Real;
goto constant;
232 case ParameterType.StringConstant: argtype = ArgumentType.String;
goto constant;
233 case ParameterType.BooleanConstant: argtype = ArgumentType.Boolean;
goto constant;
239 case ParameterType.Variable:
241 Instance instance = instances[varparam.Name];
242 ArgumentType reqtp = call.Action.ArgumentTypes.ElementAtOrLast(ix);
245 args.Add(GetArgument(instance.
Value as Tree<Symbol>, reqtp));
247 args.AddRange(ExpandWildcard(instance, reqtp));
251 case ParameterType.ActionCall:
253 var xargs = GetArguments(xcall, instances, context);
254 var xctp = call.Action.ArgumentTypes.ElementAtOrLast(ix);
256 args.Add(
new Evaluator<T>(xcall.Action, xargs, InterpretTree, context));
261 return args.ToArray();
268 {
return new Evaluator<T>(actioncall.Action, GetArguments(actioncall, instances, context),
269 InterpretTree, context).Value as T; }
273 if (tree == null)
return null;
277 if (context.hroot == null) context.hroot = tentry;
278 else context.cnode.Entries.Add(tentry);
281 if (context.cache != null)
283 var tup = context.cache.Get(tree.CacheKey) as Tuple<T,byte>;
286 tentry.Rules.Add(
new MemoEntry<T>() { MemoizedValue = tup.Item1 });
287 tentry.Succeeded = tup.Item1 != null;
293 var reqtp = Defaults.TypeToArgType<T, T>();
299 foreach (var rule
in RewriteRules.RulesFor(tree.Value))
302 tentry.Rules.Add(rentry);
304 ctxtcpy = context.InternalClone(rentry);
305 ctxtcpy.reqtp = reqtp;
307 bool match = Instantiate(rule.LHS, tree, instances);
308 if (match && (result = ExecuteAction(rule.RHS, instances, ctxtcpy)) != null)
309 context.InternalCopy(ctxtcpy);
311 rentry.Match = match;
312 rentry.Value = result;
313 rentry.Error =
false;
314 rentry.Instances = match ? instances : null;
323 if (context.cache != null)
324 context.cache.Add(
new CacheItem(tree.CacheKey, Tuple.Create(result, (byte)0)),
325 new CacheItemPolicy() { SlidingExpiration = TimeSpan.FromSeconds(20.0) });
328 tentry.Succeeded = result != null;
334 var val =
default(T);
336 var context = contextFactory.CreateContext<T>();
337 context.cache = cache;
341 val = InterpretTree(tree, context);
343 context.hroot = null;
348 { context.cache = null; }
350 return new InterpreterResult<T>() { Input = tree, Result = val, Exception = ex, Context = context };
368 bool logging =
true,
int boostlim = 4)
370 if (rules == null)
throw new ArgumentNullException(
"rules");
372 RewriteRules = rules;
375 this.logging = logging;
376 this.boostlim = boostlim;
386 #region [ IInterpreter ]
392 {
return Interpret(tree, null); }
401 public IReadOnlyList<InterpreterResult<T>>
Interpret(IReadOnlyList<Tree<Symbol>> trees)
405 if (trees.Count >= boostlim)
407 Parallel.For(0, trees.Count, x => { res[x] = Interpret(trees[x], cache); });
409 for (
int ix = 0; ix < res.Length; ++ix)
410 res[ix] = Interpret(trees[ix], null);
431 public class SemanticInterpreter<T> : IInterpreter<T>
436 private IInterpreter<Tree<Symbol>> semintr;
448 if (semintr == null)
throw new ArgumentNullException(
"semintr");
449 if (finintr == null)
throw new ArgumentNullException(
"finintr");
451 this.semintr = semintr;
452 this.finintr = finintr;
459 public RewriteRuleCollection<Tree<Symbol>> SemanticRules {
get {
return semintr.RewriteRules; } }
467 #region [ IInterpreter ]
476 var tmp = semintr.Interpret(tree);
477 return tmp.Success ? finintr.Interpret(tmp.Result) : null;
496 public IReadOnlyList<InterpreterResult<T>>
Interpret(IReadOnlyList<Tree<Symbol>> trees)
498 var temp = semintr.Interpret(trees);
499 var fin = finintr.Interpret(temp.Where(x => x.Success).Select(x => x.Result).ToArray());
503 for(
int ix = 0; ix < temp.Count; ++ix)
506 res[ix] = fin[loc++];
509 { Context = null,
Exception = null, Input = trees[ix], Result = null };
Represents a binding between a Mercury.Interpreting.Variable and its value
Describes a rule that has been used to interpret a tree.
Represents an entry for tree interpretation.
Represents memoized value
InterpreterResult< T > Interpret(Tree< Symbol > tree)
Interprets the tree using rewrite rules.
IReadOnlyList< InterpreterResult< T > > Interpret(IReadOnlyList< Tree< Symbol >> trees)
Interprets the specified trees. If the number of trees is at least boostlim specified in the construc...
static string RandomString(int length, string init="")
Creates a random [A-Za-z] string.
Represents a tree of Mercury.Interpreting.IElement instances. Must match precisely to the parse tree...
Represents a named parameter that will be replaced by an actual value of a variable captured by inter...
ArgumentType
Defines argument types using in the Mercury library
bool MatchesSymbol(Symbol s)
Indicates whether this alternative matches the given symbol.
A read-only collection of rewrite rules
ElementType Type
Element type
Represents a variable element that captures value and can be used on the RHS of the RewriteRule as an...
int Count
Number of elements in the list
Result of the interpretation.
ElementType
Element Type enumeration
An exception has been thrown
Represents an argument passed to the Mercury.Interpreting.InterpreterAction{T}, the actual parameter ...
An element that matches zero or more values. Can be used as a variable, but the actioncall must be of...
InterpreterResult< T > Interpret(Tree< Symbol > tree)
Interprets the tree using rewrite rules.
Represents the list of instances
This class represents the application of Mercury.Interpreting.InterpreterAction{T} on the Mercury...
Interpreter Context class. Some languages may use it to override it and remember data when parse tree...
Produces contexts with no custom data
IReadOnlyList< InterpreterResult< T > > Interpret(IReadOnlyList< Tree< Symbol >> trees)
Interprets trees using parallelism (if underlying interprets use it).
Interpreter(RewriteRuleCollection< T > rules, IInterpreterContextFactory factory, bool logging=true, int boostlim=4)
Creates a new Interpreter instance.
IReadOnlyList< IFormalParameter > FormalParameters
The list of formal parameters.
The analysis was successful and there is at least one result
Provides extension methods for the Mercury library.
Interface for interpreters that create objects from derivation trees according to RewriteRules...
SemanticInterpreter(IInterpreter< Tree< Symbol >> semintr, IInterpreter< T > finintr)
Initializes a new instance of the SemanticInterpreter{T} class.
Constant element. Basically equivalent of Mercury.Interpreting.Alternative.
bool HasWildcard
Indicates whether this structure contains wildcard amongst its direct child nodes.