1 using Mercury.Exceptions;
2 using Mercury.Nucleus.Collections;
5 using System.Collections.Generic;
9 namespace Mercury.Interpreting
15 internal static class RewriteRuleValidator<T>
20 #region [ Variables check ]
22 private static void Variables(RewriteRule<T> rule,
23 out Dictionary<string, Variable> vars)
25 vars =
new Dictionary<string, Variable>();
27 foreach (IElement element
in rule.LHS.Where(x =>
31 if (vars.ContainsKey(xvar.Name))
33 "multiple declarations of variable '{0}'", xvar.Name);
35 vars.Add(xvar.Name, xvar);
41 #region [ Type resolution ]
43 private static ArgumentType ResolveType(RewriteRule<T> rule, ActionCall<T> call,
47 List<ArgumentType> types =
new List<ArgumentType>();
49 for (
int ix = 0; ix < call.FormalParameters.Count; ++ix)
52 ArgumentType expected = call.Action.ArgumentTypes[argtix] & ArgumentType.Any;
53 ArgumentType actual = (ptype == ParameterType.ActionCall)
54 ? ResolveType(rule, call.FormalParameters[ix] as ActionCall<T>, vars, expected)
55 : Defaults.ParamToArgType(ptype);
57 if ((actual & expected) == ArgumentType.None)
59 "got {0} of type {1} but {2} was expected", ptype, actual, expected);
63 var vp = call.FormalParameters[ix] as VariableParameter;
64 if (!vars.ContainsKey(vp.Name))
67 var vv = vars[vp.Name];
70 if (!call.Action.AllowsWildcard)
72 "the action does not allow wildcard arguments");
74 if (call.Action.Arity.Item2 !=
int.MaxValue)
76 "action arity is unsuitable for wildcards");
78 if (ix < call.Action.ArgumentTypes.Length - 1)
80 "the wildcard must be specifiet at least at position {0}",
81 call.Action.ArgumentTypes.Length - 1);
83 if ((call.Action.ArgumentTypes[call.Action.ArgumentTypes.Length - 1]
86 "unsuitable wildcard type");
91 argtix = Math.Min(call.Action.ArgumentTypes.Length - 1, ++argtix);
95 var action = call.Action as GenericAction<T>;
98 var inferred = action.InferReturnType(erttp, types.ToArray());
99 var rtp = Defaults.TypeToArgType<T, T>();
100 action.ReturnType = inferred;
104 if ((rtp !=
ArgumentType.TValue) && ((rtp & inferred) == inferred))
116 if ((call.Action.ReturnType & erttp) == ArgumentType.None)
118 "invalid return type; expected {0}; got {1}", erttp, call.Action.ReturnType);
120 return call.Action.ReturnType;
130 public static void Validate(RewriteRule<T> rule)
132 if (rule == null)
throw new ArgumentNullException(
"rule");
134 Dictionary<string, Variable> vars;
135 Variables(rule, out vars);
136 ResolveType(rule, rule.RHS, vars, Defaults.TypeToArgType<T, T>());
145 public class RewriteRule<T> : IEquatable<RewriteRule<T>>
164 if (lhs == null)
throw new ArgumentNullException(
"lhs");
165 if (rhs == null)
throw new ArgumentNullException(
"rhs");
171 RewriteRuleValidator<T>.Validate(
this);
183 public ActionCall<T> RHS {
get;
private set; }
185 public IReadOnlyList<Variable> Variables {
get;
private set; }
194 return other == null ?
false : Equals(other);
198 {
return 17 * LHS.GetHashCode() + 41 * RHS.GetHashCode(); }
202 StringBuilder sb =
new StringBuilder();
203 sb.Append(LHS).Append(
" ==> ").Append(RHS);
205 return sb.ToString();
212 #region [ IEquatable ]
216 return (other != null)
217 && (GetHashCode() == other.GetHashCode())
218 && (LHS.Equals(other.LHS))
219 && (RHS.Equals(other.RHS));
RewriteRule(Structure lhs, ActionCall< T > rhs)
Creates s new RewriteRule. To be a valid rule, the following conditions must hold: ...
bool Equals(RewriteRule< T > other)
override bool Equals(object obj)
Represents a tree of Mercury.Interpreting.IElement instances. Must match precisely to the parse tree...
ArgumentType
Defines argument types using in the Mercury library
An exception representing a problem with Mercury.Interpreting.RewriteRule{T}.
An exception representing a problem with Mercury.Interpreting.ActionCall{T}
override string ToString()
An exception representing a problem while type checking the Mercury.Interpreting.RewriteRule{T}.
ElementType
Element Type enumeration
ParameterType
Formal Parameter Type
Variable - must match type and carries value to the RHS
override int GetHashCode()