aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptVarDict.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XMREngine/MMRScriptVarDict.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/XMREngine/MMRScriptVarDict.cs371
1 files changed, 371 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptVarDict.cs b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptVarDict.cs
new file mode 100644
index 0000000..67e1c34
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptVarDict.cs
@@ -0,0 +1,371 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31
32/**
33 * @brief Collection of variable/function/method definitions
34 */
35
36namespace OpenSim.Region.ScriptEngine.XMREngine
37{
38 public class VarDict : IEnumerable {
39 public VarDict outerVarDict; // next outer VarDict to search
40 public TokenDeclSDTypeClass thisClass; // this VarDict is for members of thisClass
41
42 private struct ArgTypes {
43 public TokenType[] argTypes;
44
45 public bool CanBeCalledBy (TokenType[] calledBy)
46 {
47 if ((argTypes == null) && (calledBy == null)) return true;
48 if ((argTypes == null) || (calledBy == null)) return false;
49 if (argTypes.Length != calledBy.Length) return false;
50 for (int i = argTypes.Length; -- i >= 0;) {
51 if (!TypeCast.IsAssignableFrom (argTypes[i], calledBy[i])) return false;
52 }
53 return true;
54 }
55
56 public override bool Equals (Object that)
57 {
58 if (that == null) return false;
59 if (that.GetType () != typeof (ArgTypes)) return false;
60 TokenType[] at = this.argTypes;
61 TokenType[] bt = ((ArgTypes)that).argTypes;
62 if ((at == null) && (bt == null)) return true;
63 if ((at == null) || (bt == null)) return false;
64 if (at.Length != bt.Length) return false;
65 for (int i = at.Length; -- i >= 0;) {
66 if (at[i].ToString () != bt[i].ToString ()) return false;
67 }
68 return true;
69 }
70
71 public override int GetHashCode ()
72 {
73 TokenType[] at = this.argTypes;
74 if (at == null) return -1;
75 int hc = 0;
76 for (int i = at.Length; -- i >= 0;) {
77 int c = (hc < 0) ? 1 : 0;
78 hc = hc * 2 + c;
79 hc ^= at[i].ToString ().GetHashCode ();
80 }
81 return hc;
82 }
83 }
84
85 private struct TDVEntry {
86 public int count;
87 public TokenDeclVar var;
88 }
89
90 private bool isFrozen = false;
91 private bool locals;
92 private Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master = new Dictionary<string, Dictionary<ArgTypes, TDVEntry>> ();
93 private int count = 0;
94 private VarDict frozenLocals = null;
95
96 /**
97 * @brief Constructor.
98 * @param locals = false: cannot be frozen, allows forward references
99 * true: can be frozen, thus forbidding forward references
100 */
101 public VarDict (bool locals)
102 {
103 this.locals = locals;
104 }
105
106 /**
107 * @brief Add new variable to the dictionary.
108 */
109 public bool AddEntry (TokenDeclVar var)
110 {
111 if (isFrozen) {
112 throw new Exception ("var dict is frozen");
113 }
114
115 /*
116 * Make sure we have a sub-dictionary based on the bare name (ie, no signature)
117 */
118 Dictionary<ArgTypes, TDVEntry> typedic;
119 if (!master.TryGetValue (var.name.val, out typedic)) {
120 typedic = new Dictionary<ArgTypes, TDVEntry> ();
121 master.Add (var.name.val, typedic);
122 }
123
124 /*
125 * See if there is an entry in the sub-dictionary that matches the argument signature.
126 * Note that fields have null argument lists.
127 * Methods always have a non-null argument list, even if only 0 entries long.
128 */
129 ArgTypes types;
130 types.argTypes = (var.argDecl == null) ? null : KeyTypesToStringTypes (var.argDecl.types);
131 if (typedic.ContainsKey (types)) return false;
132
133 /*
134 * It is unique, add to its name-specific sub-dictionary.
135 */
136 TDVEntry entry;
137 entry.count = ++ count;
138 entry.var = var;
139 typedic.Add (types, entry);
140 return true;
141 }
142
143 public int Count { get { return count; } }
144
145 /**
146 * @brief If this is not a local variable frame, just return the frame as is.
147 * If this is a local variable frame, return a version that is frozen,
148 * ie, one that does not contain any future additions.
149 */
150 public VarDict FreezeLocals ()
151 {
152 /*
153 * If not local var frame, return original frame as is.
154 * This will allow forward references as the future additions
155 * will be seen by lookups done in this dictionary.
156 */
157 if (!locals) return this;
158
159 /*
160 * If local var frame, return a copy frozen at this point.
161 * This disallows forward referenes as those future additions
162 * will not be seen by lookups done in the frozen dictionary.
163 */
164 if ((frozenLocals == null) || (frozenLocals.count != this.count)) {
165
166 /*
167 * Make a copy of the current var dictionary frame.
168 * We copy a reference to the dictionary, and though it may
169 * contain additions made after this point, those additions
170 * will have a count .gt. frozen count and will be ignored.
171 */
172 frozenLocals = new VarDict (true);
173
174 frozenLocals.outerVarDict = this.outerVarDict;
175 frozenLocals.thisClass = this.thisClass;
176 frozenLocals.master = this.master;
177 frozenLocals.count = this.count;
178 frozenLocals.frozenLocals = frozenLocals;
179
180 /*
181 * Mark it as being frozen.
182 * - assert fail if any attempt is made to add to it
183 * - ignore any additions to the dictionary with greater count
184 */
185 frozenLocals.isFrozen = true;
186 }
187 return frozenLocals;
188 }
189
190 /**
191 * @brief Find all functions/variables that are callable
192 * @param name = name of function/variable to look for
193 * @param argTypes = the argument types the function is being called with
194 * null to look for a variable
195 * @returns null: no matching function/variable found
196 * else: list of matching functions/variables
197 * for variables, always of length 1
198 */
199 private List<TokenDeclVar> found = new List<TokenDeclVar> ();
200 public TokenDeclVar[] FindCallables (string name, TokenType[] argTypes)
201 {
202 argTypes = KeyTypesToStringTypes (argTypes);
203 TokenDeclVar var = FindExact (name, argTypes);
204 if (var != null) return new TokenDeclVar[] { var };
205
206 Dictionary<ArgTypes, TDVEntry> typedic;
207 if (!master.TryGetValue (name, out typedic)) return null;
208
209 found.Clear ();
210 foreach (KeyValuePair<ArgTypes, TDVEntry> kvp in typedic) {
211 if ((kvp.Value.count <= this.count) && kvp.Key.CanBeCalledBy (argTypes)) {
212 found.Add (kvp.Value.var);
213 }
214 }
215 return (found.Count > 0) ? found.ToArray () : null;
216 }
217
218 /**
219 * @brief Find exact matching function/variable
220 * @param name = name of function to look for
221 * @param argTypes = argument types the function was declared with
222 * null to look for a variable
223 * @returns null: no matching function/variable found
224 * else: the matching function/variable
225 */
226 public TokenDeclVar FindExact (string name, TokenType[] argTypes)
227 {
228 /*
229 * Look for list of stuff that matches the given name.
230 */
231 Dictionary<ArgTypes, TDVEntry> typedic;
232 if (!master.TryGetValue (name, out typedic)) return null;
233
234 /*
235 * Loop through all fields/methods declared by that name, regardless of arg signature.
236 */
237 foreach (TDVEntry entry in typedic.Values) {
238 if (entry.count > this.count) continue;
239 TokenDeclVar var = entry.var;
240
241 /*
242 * Get argument types of declaration.
243 * fields are always null
244 * methods are always non-null, though may be zero-length
245 */
246 TokenType[] declArgs = (var.argDecl == null) ? null : var.argDecl.types;
247
248 /*
249 * Convert any key args to string args.
250 */
251 declArgs = KeyTypesToStringTypes (declArgs);
252
253 /*
254 * If both are null, they are signature-less (ie, both are fields), and so match.
255 */
256 if ((declArgs == null) && (argTypes == null)) return var;
257
258 /*
259 * If calling a delegate, it is a match, regardless of delegate arg types.
260 * If it turns out the arg types do not match, the compiler will give an error
261 * trying to cast the arguments to the delegate arg types.
262 * We don't allow overloading same field name with different delegate types.
263 */
264 if ((declArgs == null) && (argTypes != null)) {
265 TokenType fieldType = var.type;
266 if (fieldType is TokenTypeSDTypeDelegate) return var;
267 }
268
269 /*
270 * If not both null, no match, keep looking.
271 */
272 if ((declArgs == null) || (argTypes == null)) continue;
273
274 /*
275 * Both not null, match argument types to make sure we have correct overload.
276 */
277 int i = declArgs.Length;
278 if (i != argTypes.Length) continue;
279 while (-- i >= 0) {
280 string da = declArgs[i].ToString ();
281 string ga = argTypes[i].ToString ();
282 if (da == "key") da = "string";
283 if (ga == "key") ga = "string";
284 if (da != ga) break;
285 }
286 if (i < 0) return var;
287 }
288
289 /*
290 * No match.
291 */
292 return null;
293 }
294
295 /**
296 * @brief Replace any TokenTypeKey elements with TokenTypeStr so that
297 * it doesn't matter if functions are declared with key or string,
298 * they will accept either.
299 * @param argTypes = argument types as declared in source code
300 * @returns argTypes with any key replaced by string
301 */
302 private static TokenType[] KeyTypesToStringTypes (TokenType[] argTypes)
303 {
304 if (argTypes != null) {
305 int i;
306 int nats = argTypes.Length;
307 for (i = nats; -- i >= 0;) {
308 if (argTypes[i] is TokenTypeKey) break;
309 }
310 if (i >= 0) {
311 TokenType[] at = new TokenType[nats];
312 for (i = nats; -- i >= 0;) {
313 at[i] = argTypes[i];
314 if (argTypes[i] is TokenTypeKey) {
315 at[i] = new TokenTypeStr (argTypes[i]);
316 }
317 }
318 return at;
319 }
320 }
321 return argTypes;
322 }
323
324 // foreach goes through all the TokenDeclVars that were added
325
326 // IEnumerable
327 public IEnumerator GetEnumerator ()
328 {
329 return new VarDictEnumerator (this.master, this.count);
330 }
331
332 private class VarDictEnumerator : IEnumerator {
333 private IEnumerator masterEnum;
334 private IEnumerator typedicEnum;
335 private int count;
336
337 public VarDictEnumerator (Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master, int count)
338 {
339 masterEnum = master.Values.GetEnumerator ();
340 this.count = count;
341 }
342
343 // IEnumerator
344 public void Reset ()
345 {
346 masterEnum.Reset ();
347 typedicEnum = null;
348 }
349
350 // IEnumerator
351 public bool MoveNext ()
352 {
353 while (true) {
354 if (typedicEnum != null) {
355 while (typedicEnum.MoveNext ()) {
356 if (((TDVEntry)typedicEnum.Current).count <= this.count) return true;
357 }
358 typedicEnum = null;
359 }
360 if (!masterEnum.MoveNext ()) return false;
361 Dictionary<ArgTypes, TDVEntry> ctd;
362 ctd = (Dictionary<ArgTypes, TDVEntry>)masterEnum.Current;
363 typedicEnum = ctd.Values.GetEnumerator ();
364 }
365 }
366
367 // IEnumerator
368 public object Current { get { return ((TDVEntry)typedicEnum.Current).var; } }
369 }
370 }
371}