Mercury library  1.0
Translation of CFG grammars into an object model (Bachelor's thesis).
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties
RewriteRule.cs
Go to the documentation of this file.
1 using Mercury.Exceptions;
2 using Mercury.Nucleus.Collections;
3 using Mercury.Syntax;
4 using System;
5 using System.Collections.Generic;
6 using System.Linq;
7 using System.Text;
8 
9 namespace Mercury.Interpreting
10 {
11 //=============================================================================
12 // RewriteRuleValidator
13 //=============================================================================
14 
15  internal static class RewriteRuleValidator<T>
16  where T : class
17  {
18  //--[ Private ]------------------------------------------------------
19 
20  #region [ Variables check ]
21 
22  private static void Variables(RewriteRule<T> rule,
23  out Dictionary<string, Variable> vars)
24  {
25  vars = new Dictionary<string, Variable>();
26 
27  foreach (IElement element in rule.LHS.Where(x =>
28  (x.Type == ElementType.Variable || x.Type == ElementType.Wildcard)))
29  {
30  var xvar = element as Variable;
31  if (vars.ContainsKey(xvar.Name))
32  throw new InvalidRewriteRuleException(rule.ToString(),
33  "multiple declarations of variable '{0}'", xvar.Name);
34 
35  vars.Add(xvar.Name, xvar);
36  }
37  }
38 
39  #endregion
40 
41  #region [ Type resolution ]
42 
43  private static ArgumentType ResolveType(RewriteRule<T> rule, ActionCall<T> call,
44  Dictionary<string, Variable> vars, ArgumentType erttp)
45  {
46  int argtix = 0;
47  List<ArgumentType> types = new List<ArgumentType>();
48 
49  for (int ix = 0; ix < call.FormalParameters.Count; ++ix)
50  {
51  ParameterType ptype = call.FormalParameters[ix].Type;
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);
56 
57  if ((actual & expected) == ArgumentType.None)
58  throw new InvalidActionArgumentException(rule.ToString(), call.ToString(), ix,
59  "got {0} of type {1} but {2} was expected", ptype, actual, expected);
60 
61  if (ptype == ParameterType.Variable)
62  {
63  var vp = call.FormalParameters[ix] as VariableParameter;
64  if (!vars.ContainsKey(vp.Name))
65  throw new InvalidRewriteRuleException(rule.ToString(), "undefined variable '{0}'", vp.Name);
66 
67  var vv = vars[vp.Name];
68  if (vv.Type == ElementType.Wildcard)
69  {
70  if (!call.Action.AllowsWildcard)
71  throw new InvalidActionArgumentException(rule.ToString(), call.ToString(), ix,
72  "the action does not allow wildcard arguments");
73 
74  if (call.Action.Arity.Item2 != int.MaxValue)
75  throw new InvalidActionArgumentException(rule.ToString(), call.ToString(), ix,
76  "action arity is unsuitable for wildcards");
77 
78  if (ix < call.Action.ArgumentTypes.Length - 1)
79  throw new InvalidActionArgumentException(rule.ToString(), call.ToString(), ix,
80  "the wildcard must be specifiet at least at position {0}",
81  call.Action.ArgumentTypes.Length - 1);
82 
83  if ((call.Action.ArgumentTypes[call.Action.ArgumentTypes.Length - 1]
84  & ArgumentType.ParserEntity) == ArgumentType.None)
85  throw new InvalidActionArgumentException(rule.ToString(), call.ToString(), ix,
86  "unsuitable wildcard type");
87  }
88  }
89 
90  types.Add(actual);
91  argtix = Math.Min(call.Action.ArgumentTypes.Length - 1, ++argtix);
92  }
93 
94  // generic type inference
95  var action = call.Action as GenericAction<T>;
96  if (action != null)
97  {
98  var inferred = action.InferReturnType(erttp, types.ToArray());
99  var rtp = Defaults.TypeToArgType<T, T>();
100  action.ReturnType = inferred;
101 
102  // removes TValue flag if T is one of
103  // { object/dynamic, int, double, string, bool, Tree<Symbol>, Symbol }
104  if ((rtp != ArgumentType.TValue) && ((rtp & inferred) == inferred))
105  inferred &= ~ArgumentType.TValue;
106 
107  // removes Real if inferred type is Integer | Real (coercion)
108  if (inferred == (ArgumentType.Integer | ArgumentType.Real))
109  inferred = ArgumentType.Integer;
110 
111  // actual type check
112  if ((inferred & ArgumentType.Any) == ArgumentType.None)
113  throw new InvalidActionCallException(call.ToString(), "generic return type inference failed");
114  }
115 
116  if ((call.Action.ReturnType & erttp) == ArgumentType.None)
117  throw new InvalidActionCallException(call.ToString(),
118  "invalid return type; expected {0}; got {1}", erttp, call.Action.ReturnType);
119 
120  return call.Action.ReturnType;
121  }
122 
123  #endregion
124 
125  //--[ Public methods ]-----------------------------------------------
126 
130  public static void Validate(RewriteRule<T> rule)
131  {
132  if (rule == null) throw new ArgumentNullException("rule");
133 
134  Dictionary<string, Variable> vars;
135  Variables(rule, out vars);
136  ResolveType(rule, rule.RHS, vars, Defaults.TypeToArgType<T, T>());
137  }
138  }
139 
140 //=============================================================================
141 // RewriteRule
142 //=============================================================================
143 
145  public class RewriteRule<T> : IEquatable<RewriteRule<T>>
146  where T : class
147  {
148  //--[ Constructors ]-------------------------------------------------
149 
162  public RewriteRule(Structure lhs, ActionCall<T> rhs)
163  {
164  if (lhs == null) throw new ArgumentNullException("lhs");
165  if (rhs == null) throw new ArgumentNullException("rhs");
166 
167  Head = lhs.Value;
168  LHS = lhs;
169  RHS = rhs;
170 
171  RewriteRuleValidator<T>.Validate(this);
172  }
173 
174  //--[ Properties ]---------------------------------------------------
175 
177  public IElement Head { get; private set; }
178 
180  public Structure LHS { get; private set; }
181 
183  public ActionCall<T> RHS { get; private set; }
184 
185  public IReadOnlyList<Variable> Variables { get; private set; }
186 
187  //--[ Overriden methods ]--------------------------------------------
188 
189  #region [ Object ]
190 
191  public override bool Equals(object obj)
192  {
193  RewriteRule<T> other = obj as RewriteRule<T>;
194  return other == null ? false : Equals(other);
195  }
196 
197  public override int GetHashCode()
198  { return 17 * LHS.GetHashCode() + 41 * RHS.GetHashCode(); }
199 
200  public override string ToString()
201  {
202  StringBuilder sb = new StringBuilder();
203  sb.Append(LHS).Append(" ==> ").Append(RHS);
204 
205  return sb.ToString();
206  }
207 
208  #endregion
209 
210  //--[ Interface implementation ]-------------------------------------
211 
212  #region [ IEquatable ]
213 
214  public bool Equals(RewriteRule<T> other)
215  {
216  return (other != null)
217  && (GetHashCode() == other.GetHashCode())
218  && (LHS.Equals(other.LHS))
219  && (RHS.Equals(other.RHS));
220  }
221 
222  #endregion
223 
224  }
225 }
RewriteRule(Structure lhs, ActionCall< T > rhs)
Creates s new RewriteRule. To be a valid rule, the following conditions must hold: ...
Definition: RewriteRule.cs:162
bool Equals(RewriteRule< T > other)
Definition: RewriteRule.cs:214
override bool Equals(object obj)
Definition: RewriteRule.cs:191
Represents a tree of Mercury.Interpreting.IElement instances. Must match precisely to the parse tree...
Definition: Element.cs:439
ArgumentType
Defines argument types using in the Mercury library
Definition: Argument.cs:11
An exception representing a problem with Mercury.Interpreting.RewriteRule{T}.
An exception representing a problem with Mercury.Interpreting.ActionCall{T}
An exception representing a problem while type checking the Mercury.Interpreting.RewriteRule{T}.
ElementType
Element Type enumeration
Definition: Element.cs:15
ParameterType
Formal Parameter Type
Variable - must match type and carries value to the RHS
Element interface
Definition: Element.cs:32