Mercury library 1.0 Translation of CFG grammars into an object model (Bachelor's thesis).

- Main Page
- Packages
- Classes
- Files

- File List

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 }
Mercury.Interpreting.RewriteRule< T >.RewriteRule
RewriteRule(Structure lhs, ActionCall< T > rhs)
Creates s new RewriteRule. To be a valid rule, the following conditions must hold: ...
Definition: RewriteRule.cs:162
Mercury.Interpreting.RewriteRule< T >.Equals
bool Equals(RewriteRule< T > other)
Definition: RewriteRule.cs:214
Mercury.Interpreting.RewriteRule< T >.Equals
override bool Equals(object obj)
Definition: RewriteRule.cs:191
Mercury.Interpreting.RewriteRule< T >
Interpreter rewrite rule
Definition: RewriteRule.cs:145
Mercury.Interpreting.Structure
Represents a tree of Mercury.Interpreting.IElement instances. Must match precisely to the parse tree...
Definition: Element.cs:439
Mercury.Interpreting.ArgumentType
ArgumentType
Defines argument types using in the Mercury library
Definition: Argument.cs:11
Mercury.Exceptions.InvalidRewriteRuleException
An exception representing a problem with Mercury.Interpreting.RewriteRule{T}.
Definition: InterpretingExceptions.cs:158
Mercury.Exceptions.InvalidActionCallException
An exception representing a problem with Mercury.Interpreting.ActionCall{T}
Definition: InterpretingExceptions.cs:64
Mercury.Interpreting.RewriteRule< T >.ToString
override string ToString()
Definition: RewriteRule.cs:200
Mercury.Exceptions.InvalidActionArgumentException
An exception representing a problem while type checking the Mercury.Interpreting.RewriteRule{T}.
Definition: InterpretingExceptions.cs:132
Mercury.Interpreting.ElementType
ElementType
Element Type enumeration
Definition: Element.cs:15
Mercury.Interpreting.ParameterType
ParameterType
Formal Parameter Type
Definition: FormalParameter.cs:11
Mercury.Interpreting.Variable
Variable - must match type and carries value to the RHS
Mercury.Interpreting.IElement
Element interface
Definition: Element.cs:32
Mercury.Interpreting.RewriteRule< T >.GetHashCode
override int GetHashCode()
Definition: RewriteRule.cs:197