diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs | 666 |
1 files changed, 0 insertions, 666 deletions
diff --git a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs deleted file mode 100644 index fcb4b66..0000000 --- a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs +++ /dev/null | |||
@@ -1,666 +0,0 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Reflection.Emit; | ||
32 | using System.Text; | ||
33 | |||
34 | using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; | ||
35 | using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; | ||
36 | using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
37 | using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; | ||
38 | using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; | ||
39 | using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
40 | using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; | ||
41 | |||
42 | /** | ||
43 | * @brief Generate code for the backend API calls. | ||
44 | */ | ||
45 | namespace OpenSim.Region.ScriptEngine.XMREngine | ||
46 | { | ||
47 | public abstract class TokenDeclInline : TokenDeclVar { | ||
48 | public static VarDict inlineFunctions = CreateDictionary (); | ||
49 | |||
50 | public abstract void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args); | ||
51 | |||
52 | private static string[] noCheckRuns; | ||
53 | private static string[] keyReturns; | ||
54 | |||
55 | protected bool isTaggedCallsCheckRun; | ||
56 | |||
57 | /** | ||
58 | * @brief Create a dictionary of inline backend API functions. | ||
59 | */ | ||
60 | private static VarDict CreateDictionary () | ||
61 | { | ||
62 | /* | ||
63 | * For those listed in noCheckRun, we just generate the call (simple computations). | ||
64 | * For all others, we generate the call then a call to CheckRun(). | ||
65 | */ | ||
66 | noCheckRuns = new string[] { | ||
67 | "llBase64ToString", | ||
68 | "llCSV2List", | ||
69 | "llDeleteSubList", | ||
70 | "llDeleteSubString", | ||
71 | "llDumpList2String", | ||
72 | "llEscapeURL", | ||
73 | "llEuler2Rot", | ||
74 | "llGetListEntryType", | ||
75 | "llGetListLength", | ||
76 | "llGetSubString", | ||
77 | "llGetUnixTime", | ||
78 | "llInsertString", | ||
79 | "llList2CSV", | ||
80 | "llList2Float", | ||
81 | "llList2Integer", | ||
82 | "llList2Key", | ||
83 | "llList2List", | ||
84 | "llList2ListStrided", | ||
85 | "llList2Rot", | ||
86 | "llList2String", | ||
87 | "llList2Vector", | ||
88 | "llListFindList", | ||
89 | "llListInsertList", | ||
90 | "llListRandomize", | ||
91 | "llListReplaceList", | ||
92 | "llListSort", | ||
93 | "llListStatistics", | ||
94 | "llMD5String", | ||
95 | "llParseString2List", | ||
96 | "llParseStringKeepNulls", | ||
97 | "llRot2Euler", | ||
98 | "llStringLength", | ||
99 | "llStringToBase64", | ||
100 | "llStringTrim", | ||
101 | "llSubStringIndex", | ||
102 | "llUnescapeURL" | ||
103 | }; | ||
104 | |||
105 | /* | ||
106 | * These functions really return a 'key' even though we see them as | ||
107 | * returning 'string' because OpenSim has key and string as same type. | ||
108 | */ | ||
109 | keyReturns = new string[] { | ||
110 | "llAvatarOnLinkSitTarget", | ||
111 | "llAvatarOnSitTarget", | ||
112 | "llDetectedKey", | ||
113 | "llDetectedOwner", | ||
114 | "llGenerateKey", | ||
115 | "llGetCreator", | ||
116 | "llGetInventoryCreator", | ||
117 | "llGetInventoryKey", | ||
118 | "llGetKey", | ||
119 | "llGetLandOwnerAt", | ||
120 | "llGetLinkKey", | ||
121 | "llGetNotecardLine", | ||
122 | "llGetNumberOfNotecardLines", | ||
123 | "llGetOwner", | ||
124 | "llGetOwnerKey", | ||
125 | "llGetPermissionsKey", | ||
126 | "llHTTPRequest", | ||
127 | "llList2Key", | ||
128 | "llRequestAgentData", | ||
129 | "llRequestDisplayName", | ||
130 | "llRequestInventoryData", | ||
131 | "llRequestSecureURL", | ||
132 | "llRequestSimulatorData", | ||
133 | "llRequestURL", | ||
134 | "llRequestUsername", | ||
135 | "llSendRemoteData", | ||
136 | "llTransferLindenDollars" | ||
137 | }; | ||
138 | |||
139 | VarDict ifd = new VarDict (false); | ||
140 | |||
141 | Type[] oneDoub = new Type[] { typeof (double) }; | ||
142 | Type[] twoDoubs = new Type[] { typeof (double), typeof (double) }; | ||
143 | |||
144 | /* | ||
145 | * Mono generates an FPU instruction for many math calls. | ||
146 | */ | ||
147 | new TokenDeclInline_LLAbs (ifd); | ||
148 | new TokenDeclInline_Math (ifd, "llAcos(float)", "Acos", oneDoub); | ||
149 | new TokenDeclInline_Math (ifd, "llAsin(float)", "Asin", oneDoub); | ||
150 | new TokenDeclInline_Math (ifd, "llAtan2(float,float)", "Atan2", twoDoubs); | ||
151 | new TokenDeclInline_Math (ifd, "llCos(float)", "Cos", oneDoub); | ||
152 | new TokenDeclInline_Math (ifd, "llFabs(float)", "Abs", oneDoub); | ||
153 | new TokenDeclInline_Math (ifd, "llLog(float)", "Log", oneDoub); | ||
154 | new TokenDeclInline_Math (ifd, "llLog10(float)", "Log10", oneDoub); | ||
155 | new TokenDeclInline_Math (ifd, "llPow(float,float)", "Pow", twoDoubs); | ||
156 | new TokenDeclInline_LLRound (ifd); | ||
157 | new TokenDeclInline_Math (ifd, "llSin(float)", "Sin", oneDoub); | ||
158 | new TokenDeclInline_Math (ifd, "llSqrt(float)", "Sqrt", oneDoub); | ||
159 | new TokenDeclInline_Math (ifd, "llTan(float)", "Tan", oneDoub); | ||
160 | |||
161 | /* | ||
162 | * Something weird about the code generation for these calls, so they all have their own handwritten code generators. | ||
163 | */ | ||
164 | new TokenDeclInline_GetFreeMemory (ifd); | ||
165 | new TokenDeclInline_GetUsedMemory (ifd); | ||
166 | |||
167 | /* | ||
168 | * These are all the xmr...() calls directly in XMRInstAbstract. | ||
169 | * Includes the calls from ScriptBaseClass that has all the stubs | ||
170 | * which convert XMRInstAbstract to the various <NAME>_Api contexts. | ||
171 | */ | ||
172 | MethodInfo[] absmeths = typeof (XMRInstAbstract).GetMethods (); | ||
173 | AddInterfaceMethods (ifd, absmeths, null); | ||
174 | |||
175 | return ifd; | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * @brief Add API functions from the given interface to list of built-in functions. | ||
180 | * Only functions beginning with a lower-case letter are entered, all others ignored. | ||
181 | * @param ifd = internal function dictionary to add them to | ||
182 | * @param ifaceMethods = list of API functions | ||
183 | * @param acf = which field in XMRInstanceSuperType holds method's 'this' pointer | ||
184 | */ | ||
185 | // this one accepts only names beginning with a lower-case letter | ||
186 | public static void AddInterfaceMethods (VarDict ifd, MethodInfo[] ifaceMethods, FieldInfo acf) | ||
187 | { | ||
188 | List<MethodInfo> lcms = new List<MethodInfo> (ifaceMethods.Length); | ||
189 | foreach (MethodInfo meth in ifaceMethods) | ||
190 | { | ||
191 | string name = meth.Name; | ||
192 | if ((name[0] >= 'a') && (name[0] <= 'z')) { | ||
193 | lcms.Add (meth); | ||
194 | } | ||
195 | } | ||
196 | AddInterfaceMethods (ifd, lcms.GetEnumerator (), acf); | ||
197 | } | ||
198 | |||
199 | // this one accepts all methods given to it | ||
200 | public static void AddInterfaceMethods (VarDict ifd, IEnumerator<MethodInfo> ifaceMethods, FieldInfo acf) | ||
201 | { | ||
202 | if (ifd == null) ifd = inlineFunctions; | ||
203 | |||
204 | for (ifaceMethods.Reset (); ifaceMethods.MoveNext ();) { | ||
205 | MethodInfo ifaceMethod = ifaceMethods.Current; | ||
206 | string key = ifaceMethod.Name; | ||
207 | |||
208 | try { | ||
209 | /* | ||
210 | * See if we will generate a call to CheckRun() right | ||
211 | * after we generate a call to the function. | ||
212 | * If function begins with xmr, assume we will not call CheckRun() | ||
213 | * Otherwise, assume we will call CheckRun() | ||
214 | */ | ||
215 | bool dcr = !key.StartsWith ("xmr"); | ||
216 | foreach (string ncr in noCheckRuns) { | ||
217 | if (ncr == key) { | ||
218 | dcr = false; | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * Add function to dictionary. | ||
225 | */ | ||
226 | new TokenDeclInline_BEApi (ifd, dcr, ifaceMethod, acf); | ||
227 | } catch { | ||
228 | ///??? IGNORE ANY THAT FAIL - LIKE UNRECOGNIZED TYPE ???/// | ||
229 | ///??? and OVERLOADED NAMES ???/// | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /** | ||
235 | * @brief Add an inline function definition to the dictionary. | ||
236 | * @param ifd = dictionary to add inline definition to | ||
237 | * @param doCheckRun = true iff the generated code or the function itself can possibly call CheckRun() | ||
238 | * @param nameArgSig = inline function signature string, in form <name>(<arglsltypes>,...) | ||
239 | * @param retType = return type, use TokenTypeVoid if no return value | ||
240 | */ | ||
241 | protected TokenDeclInline (VarDict ifd, | ||
242 | bool doCheckRun, | ||
243 | string nameArgSig, | ||
244 | TokenType retType) | ||
245 | : base (null, null, null) | ||
246 | { | ||
247 | this.retType = retType; | ||
248 | this.triviality = doCheckRun ? Triviality.complex : Triviality.trivial; | ||
249 | |||
250 | int j = nameArgSig.IndexOf ('('); | ||
251 | this.name = new TokenName (null, nameArgSig.Substring (0, j ++)); | ||
252 | |||
253 | this.argDecl = new TokenArgDecl (null); | ||
254 | if (nameArgSig[j] != ')') { | ||
255 | int i; | ||
256 | TokenName name; | ||
257 | TokenType type; | ||
258 | |||
259 | for (i = j; nameArgSig[i] != ')'; i ++) { | ||
260 | if (nameArgSig[i] == ',') { | ||
261 | type = TokenType.FromLSLType (null, nameArgSig.Substring (j, i - j)); | ||
262 | name = new TokenName (null, "arg" + this.argDecl.varDict.Count); | ||
263 | this.argDecl.AddArg (type, name); | ||
264 | j = i + 1; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | type = TokenType.FromLSLType (null, nameArgSig.Substring (j, i - j)); | ||
269 | name = new TokenName (null, "arg" + this.argDecl.varDict.Count); | ||
270 | this.argDecl.AddArg (type, name); | ||
271 | } | ||
272 | |||
273 | this.location = new CompValuInline (this); | ||
274 | if (ifd == null) ifd = inlineFunctions; | ||
275 | ifd.AddEntry (this); | ||
276 | } | ||
277 | |||
278 | protected TokenDeclInline (VarDict ifd, | ||
279 | bool doCheckRun, | ||
280 | MethodInfo methInfo) | ||
281 | : base (null, null, null) | ||
282 | { | ||
283 | TokenType retType = TokenType.FromSysType (null, methInfo.ReturnType); | ||
284 | |||
285 | this.isTaggedCallsCheckRun = IsTaggedCallsCheckRun (methInfo); | ||
286 | this.name = new TokenName (null, methInfo.Name); | ||
287 | this.retType = GetRetType (methInfo, retType); | ||
288 | this.argDecl = GetArgDecl (methInfo.GetParameters ()); | ||
289 | this.triviality = (doCheckRun || this.isTaggedCallsCheckRun) ? Triviality.complex : Triviality.trivial; | ||
290 | this.location = new CompValuInline (this); | ||
291 | |||
292 | if (ifd == null) ifd = inlineFunctions; | ||
293 | ifd.AddEntry (this); | ||
294 | } | ||
295 | |||
296 | private static TokenArgDecl GetArgDecl (ParameterInfo[] parameters) | ||
297 | { | ||
298 | TokenArgDecl argDecl = new TokenArgDecl (null); | ||
299 | foreach (ParameterInfo pi in parameters) { | ||
300 | TokenType type = TokenType.FromSysType (null, pi.ParameterType); | ||
301 | TokenName name = new TokenName (null, pi.Name); | ||
302 | argDecl.AddArg (type, name); | ||
303 | } | ||
304 | return argDecl; | ||
305 | } | ||
306 | |||
307 | /** | ||
308 | * @brief The above code assumes all methods beginning with 'xmr' are trivial, ie, | ||
309 | * they do not call CheckRun() and also we do not generate a CheckRun() | ||
310 | * call after they return. So if an 'xmr' method does call CheckRun(), it | ||
311 | * must be tagged with attribute 'xmrMethodCallsCheckRunAttribute' so we know | ||
312 | * the method is not trivial. But in neither case do we emit our own call | ||
313 | * to CheckRun(), the 'xmr' method must do its own. We do however set up a | ||
314 | * call label before the call to the non-trivial 'xmr' method so when we are | ||
315 | * restoring the call stack, the restore will call directly in to the 'xmr' | ||
316 | * method without re-executing any code before the call to the 'xmr' method. | ||
317 | */ | ||
318 | private static bool IsTaggedCallsCheckRun (MethodInfo methInfo) | ||
319 | { | ||
320 | return (methInfo != null) && | ||
321 | Attribute.IsDefined (methInfo, typeof (xmrMethodCallsCheckRunAttribute)); | ||
322 | } | ||
323 | |||
324 | /** | ||
325 | * @brief The dumbass OpenSim has key and string as the same type so non-ll | ||
326 | * methods must be tagged with xmrMethodReturnsKeyAttribute if we | ||
327 | * are to think they return a key type, otherwise we will think they | ||
328 | * return string. | ||
329 | */ | ||
330 | private static TokenType GetRetType (MethodInfo methInfo, TokenType retType) | ||
331 | { | ||
332 | if ((methInfo != null) && (retType != null) && (retType is TokenTypeStr)) { | ||
333 | if (Attribute.IsDefined (methInfo, typeof (xmrMethodReturnsKeyAttribute))) { | ||
334 | return ChangeToKeyType (retType); | ||
335 | } | ||
336 | |||
337 | string mn = methInfo.Name; | ||
338 | foreach (string kr in keyReturns) { | ||
339 | if (kr == mn) return ChangeToKeyType (retType); | ||
340 | } | ||
341 | |||
342 | } | ||
343 | return retType; | ||
344 | } | ||
345 | private static TokenType ChangeToKeyType (TokenType retType) | ||
346 | { | ||
347 | if (retType is TokenTypeLSLString) { | ||
348 | retType = new TokenTypeLSLKey (null); | ||
349 | } else { | ||
350 | retType = new TokenTypeKey (null); | ||
351 | } | ||
352 | return retType; | ||
353 | } | ||
354 | |||
355 | public virtual MethodInfo GetMethodInfo () | ||
356 | { | ||
357 | return null; | ||
358 | } | ||
359 | |||
360 | /** | ||
361 | * @brief Print out a list of all the built-in functions and constants. | ||
362 | */ | ||
363 | public delegate void WriteLine (string str); | ||
364 | public static void PrintBuiltins (bool inclNoisyTag, WriteLine writeLine) | ||
365 | { | ||
366 | writeLine ("\nBuilt-in functions:\n"); | ||
367 | SortedDictionary<string, TokenDeclInline> bifs = new SortedDictionary<string, TokenDeclInline> (); | ||
368 | foreach (TokenDeclVar bif in TokenDeclInline.inlineFunctions) { | ||
369 | bifs.Add (bif.fullName, (TokenDeclInline)bif); | ||
370 | } | ||
371 | foreach (TokenDeclInline bif in bifs.Values) { | ||
372 | char noisy = (!inclNoisyTag || !IsTaggedNoisy (bif.GetMethodInfo ())) ? ' ' : (bif.retType is TokenTypeVoid) ? 'N' : 'R'; | ||
373 | writeLine (noisy + " " + bif.retType.ToString ().PadLeft (8) + " " + bif.fullName); | ||
374 | } | ||
375 | if (inclNoisyTag) { | ||
376 | writeLine ("\nN - stub that writes name and arguments to stdout"); | ||
377 | writeLine ("R - stub that writes name and arguments to stdout then reads return value from stdin"); | ||
378 | writeLine (" format is: function_name : return_value"); | ||
379 | writeLine (" example: llKey2Name:\"Kunta Kinte\""); | ||
380 | } | ||
381 | |||
382 | writeLine ("\nBuilt-in constants:\n"); | ||
383 | SortedDictionary<string, ScriptConst> scs = new SortedDictionary<string, ScriptConst> (); | ||
384 | int widest = 0; | ||
385 | foreach (ScriptConst sc in ScriptConst.scriptConstants.Values) { | ||
386 | if (widest < sc.name.Length) widest = sc.name.Length; | ||
387 | scs.Add (sc.name, sc); | ||
388 | } | ||
389 | foreach (ScriptConst sc in scs.Values) { | ||
390 | writeLine (" " + sc.rVal.type.ToString ().PadLeft (8) + " " + sc.name.PadRight (widest) + " = " + BuiltInConstVal (sc.rVal)); | ||
391 | } | ||
392 | } | ||
393 | |||
394 | public static bool IsTaggedNoisy (MethodInfo methInfo) | ||
395 | { | ||
396 | return (methInfo != null) && Attribute.IsDefined (methInfo, typeof (xmrMethodIsNoisyAttribute)); | ||
397 | } | ||
398 | |||
399 | public static string BuiltInConstVal (CompValu rVal) | ||
400 | { | ||
401 | if (rVal is CompValuInteger) { | ||
402 | int x = ((CompValuInteger)rVal).x; | ||
403 | return "0x" + x.ToString ("X8") + " = " + x.ToString ().PadLeft (11); | ||
404 | } | ||
405 | if (rVal is CompValuFloat) return ((CompValuFloat)rVal).x.ToString (); | ||
406 | if (rVal is CompValuString) { | ||
407 | StringBuilder sb = new StringBuilder (); | ||
408 | PrintParam (sb, ((CompValuString)rVal).x); | ||
409 | return sb.ToString (); | ||
410 | } | ||
411 | if (rVal is CompValuSField) { | ||
412 | FieldInfo fi = ((CompValuSField)rVal).field; | ||
413 | StringBuilder sb = new StringBuilder (); | ||
414 | PrintParam (sb, fi.GetValue (null)); | ||
415 | return sb.ToString (); | ||
416 | } | ||
417 | return rVal.ToString (); // just prints the type | ||
418 | } | ||
419 | |||
420 | public static void PrintParam (StringBuilder sb, object p) | ||
421 | { | ||
422 | if (p == null) { | ||
423 | sb.Append ("null"); | ||
424 | } else if (p is LSL_List) { | ||
425 | sb.Append ('['); | ||
426 | object[] d = ((LSL_List)p).Data; | ||
427 | for (int i = 0; i < d.Length; i ++) { | ||
428 | if (i > 0) sb.Append (','); | ||
429 | PrintParam (sb, d[i]); | ||
430 | } | ||
431 | sb.Append (']'); | ||
432 | } else if (p is LSL_Rotation) { | ||
433 | LSL_Rotation r = (LSL_Rotation)p; | ||
434 | sb.Append ('<'); | ||
435 | sb.Append (r.x); | ||
436 | sb.Append (','); | ||
437 | sb.Append (r.y); | ||
438 | sb.Append (','); | ||
439 | sb.Append (r.z); | ||
440 | sb.Append (','); | ||
441 | sb.Append (r.s); | ||
442 | sb.Append ('>'); | ||
443 | } else if (p is LSL_String) { | ||
444 | PrintParamString (sb, (string)(LSL_String)p); | ||
445 | } else if (p is LSL_Vector) { | ||
446 | LSL_Vector v = (LSL_Vector)p; | ||
447 | sb.Append ('<'); | ||
448 | sb.Append (v.x); | ||
449 | sb.Append (','); | ||
450 | sb.Append (v.y); | ||
451 | sb.Append (','); | ||
452 | sb.Append (v.z); | ||
453 | sb.Append ('>'); | ||
454 | } else if (p is string) { | ||
455 | PrintParamString (sb, (string)p); | ||
456 | } else { | ||
457 | sb.Append (p.ToString ()); | ||
458 | } | ||
459 | } | ||
460 | |||
461 | public static void PrintParamString (StringBuilder sb, string p) | ||
462 | { | ||
463 | sb.Append ('"'); | ||
464 | foreach (char c in p) { | ||
465 | if (c == '\b') { | ||
466 | sb.Append ("\\b"); | ||
467 | continue; | ||
468 | } | ||
469 | if (c == '\n') { | ||
470 | sb.Append ("\\n"); | ||
471 | continue; | ||
472 | } | ||
473 | if (c == '\r') { | ||
474 | sb.Append ("\\r"); | ||
475 | continue; | ||
476 | } | ||
477 | if (c == '\t') { | ||
478 | sb.Append ("\\t"); | ||
479 | continue; | ||
480 | } | ||
481 | if (c == '"') { | ||
482 | sb.Append ("\\\""); | ||
483 | continue; | ||
484 | } | ||
485 | if (c == '\\') { | ||
486 | sb.Append ("\\\\"); | ||
487 | continue; | ||
488 | } | ||
489 | sb.Append (c); | ||
490 | } | ||
491 | sb.Append ('"'); | ||
492 | } | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * @brief Code generators... | ||
497 | * @param scg = script we are generating code for | ||
498 | * @param result = type/location for result (type matches function definition) | ||
499 | * @param args = type/location of arguments (types match function definition) | ||
500 | */ | ||
501 | |||
502 | public class TokenDeclInline_LLAbs : TokenDeclInline { | ||
503 | public TokenDeclInline_LLAbs (VarDict ifd) | ||
504 | : base (ifd, false, "llAbs(integer)", new TokenTypeInt (null)) { } | ||
505 | |||
506 | public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args) | ||
507 | { | ||
508 | ScriptMyLabel itsPosLabel = scg.ilGen.DefineLabel ("llAbstemp"); | ||
509 | |||
510 | args[0].PushVal (scg, errorAt); | ||
511 | scg.ilGen.Emit (errorAt, OpCodes.Dup); | ||
512 | scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0); | ||
513 | scg.ilGen.Emit (errorAt, OpCodes.Bge_S, itsPosLabel); | ||
514 | scg.ilGen.Emit (errorAt, OpCodes.Neg); | ||
515 | scg.ilGen.MarkLabel (itsPosLabel); | ||
516 | result.Pop (scg, errorAt, retType); | ||
517 | } | ||
518 | } | ||
519 | |||
520 | public class TokenDeclInline_Math : TokenDeclInline { | ||
521 | private MethodInfo methInfo; | ||
522 | |||
523 | public TokenDeclInline_Math (VarDict ifd, string sig, string name, Type[] args) | ||
524 | : base (ifd, false, sig, new TokenTypeFloat (null)) | ||
525 | { | ||
526 | methInfo = ScriptCodeGen.GetStaticMethod (typeof (System.Math), name, args); | ||
527 | } | ||
528 | |||
529 | public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args) | ||
530 | { | ||
531 | for (int i = 0; i < args.Length; i ++) { | ||
532 | args[i].PushVal (scg, errorAt, argDecl.types[i]); | ||
533 | } | ||
534 | scg.ilGen.Emit (errorAt, OpCodes.Call, methInfo); | ||
535 | result.Pop (scg, errorAt, retType); | ||
536 | } | ||
537 | } | ||
538 | |||
539 | public class TokenDeclInline_LLRound : TokenDeclInline { | ||
540 | |||
541 | private static MethodInfo roundMethInfo = ScriptCodeGen.GetStaticMethod (typeof (System.Math), "Round", | ||
542 | new Type[] { typeof (double), typeof (MidpointRounding) }); | ||
543 | |||
544 | public TokenDeclInline_LLRound (VarDict ifd) | ||
545 | : base (ifd, false, "llRound(float)", new TokenTypeInt (null)) { } | ||
546 | |||
547 | public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args) | ||
548 | { | ||
549 | args[0].PushVal (scg, errorAt, new TokenTypeFloat (null)); | ||
550 | scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, (int)System.MidpointRounding.AwayFromZero); | ||
551 | scg.ilGen.Emit (errorAt, OpCodes.Call, roundMethInfo); | ||
552 | result.Pop (scg, errorAt, new TokenTypeFloat (null)); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | public class TokenDeclInline_GetFreeMemory : TokenDeclInline { | ||
557 | private static readonly MethodInfo getFreeMemMethInfo = typeof (XMRInstAbstract).GetMethod ("xmrHeapLeft", new Type[] { }); | ||
558 | |||
559 | public TokenDeclInline_GetFreeMemory (VarDict ifd) | ||
560 | : base (ifd, false, "llGetFreeMemory()", new TokenTypeInt (null)) { } | ||
561 | |||
562 | // appears as llGetFreeMemory() in script source code | ||
563 | // but actually calls xmrHeapLeft() | ||
564 | public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args) | ||
565 | { | ||
566 | scg.PushXMRInst (); | ||
567 | scg.ilGen.Emit (errorAt, OpCodes.Call, getFreeMemMethInfo); | ||
568 | result.Pop (scg, errorAt, new TokenTypeInt (null)); | ||
569 | } | ||
570 | } | ||
571 | |||
572 | public class TokenDeclInline_GetUsedMemory : TokenDeclInline { | ||
573 | private static readonly MethodInfo getUsedMemMethInfo = typeof (XMRInstAbstract).GetMethod ("xmrHeapUsed", new Type[] { }); | ||
574 | |||
575 | public TokenDeclInline_GetUsedMemory (VarDict ifd) | ||
576 | : base (ifd, false, "llGetUsedMemory()", new TokenTypeInt (null)) { } | ||
577 | |||
578 | // appears as llGetUsedMemory() in script source code | ||
579 | // but actually calls xmrHeapUsed() | ||
580 | public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args) | ||
581 | { | ||
582 | scg.PushXMRInst (); | ||
583 | scg.ilGen.Emit (errorAt, OpCodes.Call, getUsedMemMethInfo); | ||
584 | result.Pop (scg, errorAt, new TokenTypeInt (null)); | ||
585 | } | ||
586 | } | ||
587 | |||
588 | /** | ||
589 | * @brief Generate code for the usual ll...() functions. | ||
590 | */ | ||
591 | public class TokenDeclInline_BEApi : TokenDeclInline { | ||
592 | // private static readonly MethodInfo fixLLParcelMediaQuery = ScriptCodeGen.GetStaticMethod | ||
593 | // (typeof (XMRInstAbstract), "FixLLParcelMediaQuery", new Type[] { typeof (LSL_List) }); | ||
594 | |||
595 | // private static readonly MethodInfo fixLLParcelMediaCommandList = ScriptCodeGen.GetStaticMethod | ||
596 | // (typeof (XMRInstAbstract), "FixLLParcelMediaCommandList", new Type[] { typeof (LSL_List) }); | ||
597 | |||
598 | public bool doCheckRun; | ||
599 | private FieldInfo apiContextField; | ||
600 | private MethodInfo methInfo; | ||
601 | |||
602 | /** | ||
603 | * @brief Constructor | ||
604 | * @param ifd = dictionary to add the function to | ||
605 | * @param dcr = append a call to CheckRun() | ||
606 | * @param methInfo = ll...() method to be called | ||
607 | */ | ||
608 | public TokenDeclInline_BEApi (VarDict ifd, bool dcr, MethodInfo methInfo, FieldInfo acf) | ||
609 | : base (ifd, dcr, methInfo) | ||
610 | { | ||
611 | this.methInfo = methInfo; | ||
612 | doCheckRun = dcr; | ||
613 | apiContextField = acf; | ||
614 | } | ||
615 | |||
616 | public override MethodInfo GetMethodInfo () | ||
617 | { | ||
618 | return methInfo; | ||
619 | } | ||
620 | |||
621 | /** | ||
622 | * @brief Generate call to backend API function (eg llSay()) maybe followed by a call to CheckRun(). | ||
623 | * @param scg = script being compiled | ||
624 | * @param result = where to place result (might be void) | ||
625 | * @param args = script-visible arguments to pass to API function | ||
626 | */ | ||
627 | public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args) | ||
628 | { | ||
629 | if (isTaggedCallsCheckRun) | ||
630 | { // see if 'xmr' method that calls CheckRun() internally | ||
631 | new ScriptCodeGen.CallLabel (scg, errorAt); // if so, put a call label immediately before it | ||
632 | // .. so restoring the frame will jump immediately to the | ||
633 | // .. call without re-executing any code before this | ||
634 | } | ||
635 | if (!methInfo.IsStatic) | ||
636 | { | ||
637 | scg.PushXMRInst (); // XMRInstanceSuperType pointer | ||
638 | if (apiContextField != null) // 'this' pointer for API function | ||
639 | scg.ilGen.Emit (errorAt, OpCodes.Ldfld, apiContextField); | ||
640 | |||
641 | } | ||
642 | for (int i = 0; i < args.Length; i ++) // push arguments, boxing/unboxing as needed | ||
643 | args[i].PushVal (scg, errorAt, argDecl.types[i]); | ||
644 | |||
645 | // this should not be needed | ||
646 | // if (methInfo.Name == "llParcelMediaQuery") { | ||
647 | // scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaQuery); | ||
648 | // } | ||
649 | // this should not be needed | ||
650 | // if (methInfo.Name == "llParcelMediaCommandList") { | ||
651 | // scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaCommandList); | ||
652 | // } | ||
653 | if (methInfo.IsVirtual) // call API function | ||
654 | scg.ilGen.Emit (errorAt, OpCodes.Callvirt, methInfo); | ||
655 | else | ||
656 | scg.ilGen.Emit (errorAt, OpCodes.Call, methInfo); | ||
657 | |||
658 | result.Pop (scg, errorAt, retType); // pop result, boxing/unboxing as needed | ||
659 | if (isTaggedCallsCheckRun) | ||
660 | scg.openCallLabel = null; | ||
661 | |||
662 | if (doCheckRun) | ||
663 | scg.EmitCallCheckRun (errorAt, false); // maybe call CheckRun() | ||
664 | } | ||
665 | } | ||
666 | } | ||