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