MMRScriptInlines.cs 29 KB

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