aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs1882
1 files changed, 1882 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs
new file mode 100644
index 0000000..17bc3ec
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs
@@ -0,0 +1,1882 @@
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 OpenSim.Region.ScriptEngine.Shared.ScriptBase;
29using OpenSim.Region.ScriptEngine.Yengine;
30using System;
31using System.Collections.Generic;
32using System.IO;
33using System.Reflection;
34using System.Reflection.Emit;
35
36using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
37using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
38using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
39using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
40using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
41using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
42using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
43
44/**
45 * @brief Compute values used during code generation to keep track of where computed values are stored.
46 *
47 * Conceptually holds the memory address and type of the value
48 * such as that used for a local variable, global variable, temporary variable.
49 * Also used for things like constants and function/method entrypoints,
50 * they are basically treated as read-only variables.
51 *
52 * cv.type - type of the value
53 *
54 * cv.PushVal() - pushes the value on the CIL stack
55 * cv.PushRef() - pushes address of the value on the CIL stack
56 *
57 * cv.PopPre() - gets ready to pop from the CIL stack
58 * ...by possibly pushing something
59 * <push value to be popped>
60 * cv.PushPre() - pops value from the CIL stack
61 *
62 * If the type is a TokenTypeSDTypeDelegate, the location is callable,
63 * so you get these additional functions:
64 *
65 * cv.GetRetType() - gets function/method's return value type
66 * TokenTypeVoid if void
67 * null if not a delegate
68 * cv.GetArgTypes() - gets array of argument types
69 * as seen by script level, ie,
70 * does not include any hidden 'this' type
71 * cv.GetArgSig() - gets argument signature eg, "(integer,list)"
72 * null if not a delegate
73 *
74 * cv.CallPre() - gets ready to call the function/method
75 * ...by possibly pushing something
76 * such as a 'this' pointer
77 * <push call args left-to-right>
78 * cv.CallPost() - calls the function/method
79 */
80
81namespace OpenSim.Region.ScriptEngine.Yengine
82{
83
84 /**
85 * @brief Location of a value
86 * Includes constants, expressions and temp variables.
87 */
88 public abstract class CompValu
89 {
90 protected static readonly MethodInfo gsmdMethodInfo =
91 typeof(XMRInstAbstract).GetMethod("GetScriptMethodDelegate",
92 new Type[] { typeof(string), typeof(string), typeof(object) });
93
94 private static readonly MethodInfo avpmListMethInfo = typeof(XMRInstArrays).GetMethod("PopList", new Type[] { typeof(int), typeof(LSL_List) });
95 private static readonly MethodInfo avpmObjectMethInfo = typeof(XMRInstArrays).GetMethod("PopObject", new Type[] { typeof(int), typeof(object) });
96 private static readonly MethodInfo avpmStringMethInfo = typeof(XMRInstArrays).GetMethod("PopString", new Type[] { typeof(int), typeof(string) });
97
98 public TokenType type; // type of the value and where in the source it was used
99
100 public CompValu(TokenType type)
101 {
102 this.type = type;
103 }
104
105 public Type ToSysType()
106 {
107 return (type.ToLSLWrapType() != null) ? type.ToLSLWrapType() : type.ToSysType();
108 }
109
110 // if a field of an XMRInstArrays array cannot be directly written,
111 // get the method that can write it
112 private static MethodInfo ArrVarPopMeth(FieldInfo fi)
113 {
114 if(fi.Name == "iarLists")
115 return avpmListMethInfo;
116 if(fi.Name == "iarObjects")
117 return avpmObjectMethInfo;
118 if(fi.Name == "iarStrings")
119 return avpmStringMethInfo;
120 return null;
121 }
122
123 // emit code to push value onto stack
124 public void PushVal(ScriptCodeGen scg, Token errorAt, TokenType stackType)
125 {
126 this.PushVal(scg, errorAt, stackType, false);
127 }
128 public void PushVal(ScriptCodeGen scg, Token errorAt, TokenType stackType, bool explicitAllowed)
129 {
130 this.PushVal(scg, errorAt);
131 TypeCast.CastTopOfStack(scg, errorAt, this.type, stackType, explicitAllowed);
132 }
133 public abstract void PushVal(ScriptCodeGen scg, Token errorAt);
134 public abstract void PushRef(ScriptCodeGen scg, Token errorAt);
135
136 // emit code to pop value from stack
137 public void PopPost(ScriptCodeGen scg, Token errorAt, TokenType stackType)
138 {
139 TypeCast.CastTopOfStack(scg, errorAt, stackType, this.type, false);
140 this.PopPost(scg, errorAt);
141 }
142 public virtual void PopPre(ScriptCodeGen scg, Token errorAt)
143 {
144 } // call this before pushing value to be popped
145 public abstract void PopPost(ScriptCodeGen scg, Token errorAt); // call this after pushing value to be popped
146
147 // return true: doing a PushVal() does not involve CheckRun()
148 // false: otherwise
149 public virtual bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
150 {
151 return true;
152 }
153
154 /*
155 * These additional functions are available if the type is a delegate
156 */
157 public TokenType GetRetType()
158 {
159 if(!(type is TokenTypeSDTypeDelegate))
160 return null;
161 return ((TokenTypeSDTypeDelegate)type).decl.GetRetType();
162 }
163 public TokenType[] GetArgTypes()
164 {
165 if(!(type is TokenTypeSDTypeDelegate))
166 return null;
167 return ((TokenTypeSDTypeDelegate)type).decl.GetArgTypes();
168 }
169 public string GetArgSig()
170 {
171 if(!(type is TokenTypeSDTypeDelegate))
172 return null;
173 return ((TokenTypeSDTypeDelegate)type).decl.GetArgSig();
174 }
175
176 // These are used only if type is a delegate too
177 // - but it is a real delegate pointer in a global or local variable or a field, etc
178 // ie, PushVal() pushes a delegate pointer
179 // - so we must have CallPre() push the delegate pointer as a 'this' for this.Invoke(...)
180 // - and CallPost() call the delegate's Invoke() method
181 // - we assume the target function is non-trivial so we always use a call label
182 public virtual void CallPre(ScriptCodeGen scg, Token errorAt) // call this before pushing arguments
183 {
184 new ScriptCodeGen.CallLabel(scg, errorAt);
185 this.PushVal(scg, errorAt);
186 }
187 public virtual void CallPost(ScriptCodeGen scg, Token errorAt) // call this after pushing arguments
188 {
189 TokenTypeSDTypeDelegate ttd = (TokenTypeSDTypeDelegate)type;
190 MethodInfo invokeMethodInfo = ttd.decl.GetInvokerInfo();
191 scg.ilGen.Emit(errorAt, OpCodes.Callvirt, invokeMethodInfo);
192 scg.openCallLabel = null;
193 }
194
195 /*
196 * Utilities used by CompValuGlobalVar and CompValuInstField
197 * where the value is located in a type-dependent array.
198 */
199 protected void EmitFieldPushVal(ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
200 {
201 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, var.vTableArray); // which array
202 scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, var.vTableIndex); // which array element
203 if(type is TokenTypeFloat)
204 {
205 scg.ilGen.Emit(errorAt, OpCodes.Ldelem_R8);
206 }
207 else if(type is TokenTypeInt)
208 {
209 scg.ilGen.Emit(errorAt, OpCodes.Ldelem_I4);
210 }
211 else if(type is TokenTypeSDTypeDelegate)
212 {
213 scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(object));
214 scg.ilGen.Emit(errorAt, OpCodes.Castclass, ToSysType());
215 }
216 else
217 {
218 scg.ilGen.Emit(errorAt, OpCodes.Ldelem, ToSysType());
219 }
220 }
221
222 protected void EmitFieldPushRef(ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
223 {
224 if(ArrVarPopMeth(var.vTableArray) != null)
225 {
226 scg.ErrorMsg(errorAt, "can't take address of this variable");
227 }
228 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, var.vTableArray);
229 scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, var.vTableIndex);
230 scg.ilGen.Emit(errorAt, OpCodes.Ldelema, ToSysType());
231 }
232
233 protected void EmitFieldPopPre(ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
234 {
235 if(ArrVarPopMeth(var.vTableArray) != null)
236 {
237 scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, var.vTableIndex);
238 }
239 else
240 {
241 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, var.vTableArray);
242 scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, var.vTableIndex);
243 }
244 }
245
246 protected void EmitFieldPopPost(ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
247 {
248 if(ArrVarPopMeth(var.vTableArray) != null)
249 {
250 scg.ilGen.Emit(errorAt, OpCodes.Call, ArrVarPopMeth(var.vTableArray));
251 }
252 else if(type is TokenTypeFloat)
253 {
254 scg.ilGen.Emit(errorAt, OpCodes.Stelem_R8);
255 }
256 else if(type is TokenTypeInt)
257 {
258 scg.ilGen.Emit(errorAt, OpCodes.Stelem_I4);
259 }
260 else if(type is TokenTypeSDTypeDelegate)
261 {
262 scg.ilGen.Emit(errorAt, OpCodes.Stelem, typeof(object));
263 }
264 else
265 {
266 scg.ilGen.Emit(errorAt, OpCodes.Stelem, ToSysType());
267 }
268 }
269
270 /**
271 * @brief With value pushed on stack, emit code to set a property by calling its setter() method.
272 * @param scg = which script is being compiled
273 * @param errorAt = for error messages
274 * @param type = property type
275 * @param setProp = setter() method
276 */
277 protected void EmitPopPostProp(ScriptCodeGen scg, Token errorAt, TokenType type, CompValu setProp)
278 {
279 ScriptMyLocal temp = scg.ilGen.DeclareLocal(type.ToSysType(), "__spr_" + errorAt.Unique);
280 scg.ilGen.Emit(errorAt, OpCodes.Stloc, temp);
281 setProp.CallPre(scg, errorAt);
282 scg.ilGen.Emit(errorAt, OpCodes.Ldloc, temp);
283 setProp.CallPost(scg, errorAt);
284 }
285 }
286
287 // The value is kept in an (XMR_Array) array element
288 public class CompValuArEle: CompValu
289 {
290 public CompValu arr;
291 private CompValu idx;
292 private TokenTypeObject tto;
293
294 private static readonly MethodInfo getByKeyMethodInfo = typeof(XMR_Array).GetMethod("GetByKey",
295 new Type[] { typeof(object) });
296 private static readonly MethodInfo setByKeyMethodInfo = typeof(XMR_Array).GetMethod("SetByKey",
297 new Type[] { typeof (object),
298 typeof (object) });
299
300 // type = TokenTypeObject always, as our array elements are always of type 'object'
301 // arr = where the array object itself is stored
302 // idx = where the index value is stored
303 public CompValuArEle(TokenType type, CompValu arr, CompValu idx) : base(type)
304 {
305 this.arr = arr;
306 this.idx = idx;
307 this.tto = new TokenTypeObject(this.type);
308 }
309 public override void PushVal(ScriptCodeGen scg, Token errorAt)
310 {
311 arr.PushVal(scg, errorAt); // array
312 idx.PushVal(scg, errorAt, this.tto); // key
313 scg.ilGen.Emit(errorAt, OpCodes.Call, getByKeyMethodInfo);
314 }
315 public override void PushRef(ScriptCodeGen scg, Token errorAt)
316 {
317 scg.ErrorMsg(errorAt, "array element not allowed here");
318 scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
319 }
320 public override void PopPre(ScriptCodeGen scg, Token errorAt)
321 {
322 arr.PushVal(scg, errorAt); // array
323 idx.PushVal(scg, errorAt, this.tto); // key
324 }
325 public override void PopPost(ScriptCodeGen scg, Token errorAt)
326 {
327 scg.ilGen.Emit(errorAt, OpCodes.Call, setByKeyMethodInfo);
328 }
329
330 // non-trivial because it needs to be copied into a temp
331 // in case the idiot does dumb-ass side effects tricks
332 // eg, (x = 0) + x + 2
333 // should read old value of x not 0
334 // but if 'xmroption norighttoleft;' in effect,
335 // we can read it in any order so reading an
336 // XMR_Array element is trivial
337 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
338 {
339 return readAt.nr2l;
340 }
341 }
342
343 // The value is kept in the current function's argument list
344 public class CompValuArg: CompValu
345 {
346 public int index;
347 public bool readOnly;
348
349 private static OpCode[] ldargs = { OpCodes.Ldarg_0, OpCodes.Ldarg_1,
350 OpCodes.Ldarg_2, OpCodes.Ldarg_3 };
351
352 public CompValuArg(TokenType type, int index) : base(type)
353 {
354 this.index = index;
355 }
356 public CompValuArg(TokenType type, int index, bool ro) : base(type)
357 {
358 this.index = index;
359 this.readOnly = ro;
360 }
361 public override void PushVal(ScriptCodeGen scg, Token errorAt)
362 {
363 if(index < ldargs.Length)
364 scg.ilGen.Emit(errorAt, ldargs[index]);
365 else if(index <= 255)
366 scg.ilGen.Emit(errorAt, OpCodes.Ldarg_S, index);
367 else
368 scg.ilGen.Emit(errorAt, OpCodes.Ldarg, index);
369 }
370 public override void PushRef(ScriptCodeGen scg, Token errorAt)
371 {
372 if(readOnly)
373 {
374 scg.ErrorMsg(errorAt, "location cannot be written to");
375 }
376 if(index <= 255)
377 scg.ilGen.Emit(errorAt, OpCodes.Ldarga_S, index);
378 else
379 scg.ilGen.Emit(errorAt, OpCodes.Ldarga, index);
380 }
381 public override void PopPost(ScriptCodeGen scg, Token errorAt)
382 {
383 if(readOnly)
384 {
385 scg.ErrorMsg(errorAt, "location cannot be written to");
386 }
387 scg.ilGen.Emit(errorAt, OpCodes.Starg, index);
388 }
389
390 // non-trivial because it needs to be copied into a temp
391 // in case the idiot does dumb-ass side effects tricks
392 // eg, (x = 0) + x + 2
393 // should read old value of x not 0
394 // but if 'xmroption norighttoleft;' in effect,
395 // we can read it in any order so reading an
396 // argument is trivial
397 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
398 {
399 return readAt.nr2l;
400 }
401 }
402
403 // The value is a character constant
404 public class CompValuChar: CompValu
405 {
406 public char x;
407
408 public CompValuChar(TokenType type, char x) : base(type)
409 {
410 if(!(this.type is TokenTypeChar))
411 {
412 this.type = new TokenTypeChar(this.type);
413 }
414 this.x = x;
415 }
416 public override void PushVal(ScriptCodeGen scg, Token errorAt)
417 {
418 scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, (int)x);
419 }
420 public override void PushRef(ScriptCodeGen scg, Token errorAt)
421 {
422 throw new Exception("cannot get constant's address");
423 }
424 public override void PopPost(ScriptCodeGen scg, Token errorAt)
425 {
426 throw new Exception("cannot store into contant");
427 }
428 }
429
430 // The value is kept in a struct/class field of an internal struct/class
431 public class CompValuField: CompValu
432 {
433 CompValu obj;
434 FieldInfo field;
435
436 public CompValuField(TokenType type, CompValu obj, FieldInfo field) : base(type)
437 {
438 this.obj = obj;
439 this.field = field;
440 }
441 public override void PushVal(ScriptCodeGen scg, Token errorAt)
442 {
443 if(field.ReflectedType.IsValueType)
444 {
445 obj.PushRef(scg, errorAt);
446 }
447 else
448 {
449 obj.PushVal(scg, errorAt);
450 }
451 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, field);
452 }
453 public override void PushRef(ScriptCodeGen scg, Token errorAt)
454 {
455 if(field.ReflectedType.IsValueType)
456 {
457 obj.PushRef(scg, errorAt);
458 }
459 else
460 {
461 obj.PushVal(scg, errorAt);
462 }
463 scg.ilGen.Emit(errorAt, OpCodes.Ldflda, field);
464 }
465 public override void PopPre(ScriptCodeGen scg, Token errorAt)
466 {
467 if(field.ReflectedType.IsValueType)
468 {
469 obj.PushRef(scg, errorAt);
470 }
471 else
472 {
473 obj.PushVal(scg, errorAt);
474 }
475 }
476 public override void PopPost(ScriptCodeGen scg, Token errorAt)
477 {
478 scg.ilGen.Emit(errorAt, OpCodes.Stfld, field);
479 }
480
481 // non-trivial because it needs to be copied into a temp
482 // in case the idiot does dumb-ass side effects tricks
483 // eg, (x = 0) + x + 2
484 // should read old value of x not 0
485 // but if 'xmroption norighttoleft;' in effect,
486 // we can read it in any order so reading an
487 // field of a class/struct is trivial
488 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
489 {
490 return readAt.nr2l;
491 }
492 }
493
494 // Accessing an element of a fixed-dimension array
495 public class CompValuFixArEl: CompValu
496 {
497 private CompValu baseRVal;
498 private CompValu[] subRVals;
499
500 private int nSubs;
501 private TokenDeclVar getFunc;
502 private TokenDeclVar setFunc;
503 private TokenTypeInt tokenTypeInt;
504
505 /**
506 * @brief Set up to access an element of an array.
507 * @param scg = what script we are compiling
508 * @param baseRVal = what array we are accessing
509 * @param subRVals = the subscripts being applied
510 */
511 public CompValuFixArEl(ScriptCodeGen scg, CompValu baseRVal, CompValu[] subRVals) : base(GetElementType(scg, baseRVal, subRVals))
512 {
513 this.baseRVal = baseRVal; // location of the array itself
514 this.subRVals = subRVals; // subscript values
515 this.nSubs = subRVals.Length;
516
517 TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseRVal.type;
518 TokenDeclSDTypeClass sdtDecl = sdtType.decl;
519 tokenTypeInt = new TokenTypeInt(sdtType);
520
521 TokenName name = new TokenName(sdtType, "Get");
522 TokenType[] argsig = new TokenType[nSubs];
523 for(int i = 0; i < nSubs; i++)
524 {
525 argsig[i] = tokenTypeInt;
526 }
527 getFunc = scg.FindThisMember(sdtDecl, name, argsig);
528
529 name = new TokenName(sdtType, "Set");
530 argsig = new TokenType[nSubs + 1];
531 for(int i = 0; i < nSubs; i++)
532 {
533 argsig[i] = tokenTypeInt;
534 }
535 argsig[nSubs] = getFunc.retType;
536 setFunc = scg.FindThisMember(sdtDecl, name, argsig);
537 }
538
539 /**
540 * @brief Read array element and push value on stack.
541 */
542 public override void PushVal(ScriptCodeGen scg, Token errorAt)
543 {
544 // call script-defined class' Get() method to fetch the value
545 baseRVal.PushVal(scg, errorAt);
546 for(int i = 0; i < nSubs; i++)
547 {
548 subRVals[i].PushVal(scg, errorAt, tokenTypeInt);
549 }
550 scg.ilGen.Emit(errorAt, OpCodes.Call, getFunc.ilGen);
551 }
552
553 /**
554 * @brief Push address of array element on stack.
555 */
556 public override void PushRef(ScriptCodeGen scg, Token errorAt)
557 {
558 throw new Exception("tu stOOpid to get array element address");
559 }
560
561 /**
562 * @brief Prepare to write array element.
563 */
564 public override void PopPre(ScriptCodeGen scg, Token errorAt)
565 {
566 // set up call to script-defined class' Set() method to write the value
567 baseRVal.PushVal(scg, errorAt);
568 for(int i = 0; i < nSubs; i++)
569 {
570 subRVals[i].PushVal(scg, errorAt, tokenTypeInt);
571 }
572 }
573
574 /**
575 * @brief Pop value from stack and write array element.
576 */
577 public override void PopPost(ScriptCodeGen scg, Token errorAt)
578 {
579 // call script-defined class' Set() method to write the value
580 scg.ilGen.Emit(errorAt, OpCodes.Call, setFunc.ilGen);
581 }
582
583 /**
584 * @brief Get the array element type by getting the Get() functions return type.
585 * Crude but effective.
586 * @param scg = what script we are compiling
587 * @param baseRVal = what array we are accessing
588 * @param subRVals = the subscripts being applied
589 * @returns array element type
590 */
591 private static TokenType GetElementType(ScriptCodeGen scg, CompValu baseRVal, CompValu[] subRVals)
592 {
593 TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseRVal.type;
594 TokenDeclSDTypeClass sdtDecl = sdtType.decl;
595 TokenName name = new TokenName(sdtType, "Get");
596 int nSubs = subRVals.Length;
597 TokenType[] argsig = new TokenType[nSubs];
598 argsig[0] = new TokenTypeInt(sdtType);
599 for(int i = 0; ++i < nSubs;)
600 {
601 argsig[i] = argsig[0];
602 }
603 TokenDeclVar getFunc = scg.FindThisMember(sdtDecl, name, argsig);
604 return getFunc.retType;
605 }
606
607 // non-trivial because it needs to be copied into a temp
608 // in case the idiot does dumb-ass side effects tricks
609 // eg, (x = 0) + x + 2
610 // should read old value of x not 0
611 // but if 'xmroption norighttoleft;' in effect,
612 // we can read it in any order so reading an
613 // fixed-dimension array element is trivial
614 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
615 {
616 return readAt.nr2l;
617 }
618 }
619
620 // The value is a float constant
621 public class CompValuFloat: CompValu
622 {
623 public double x;
624
625 public CompValuFloat(TokenType type, double x) : base(type)
626 {
627 if(!(this.type is TokenTypeFloat))
628 {
629 this.type = new TokenTypeFloat(this.type);
630 }
631 this.x = x;
632 }
633 public override void PushVal(ScriptCodeGen scg, Token errorAt)
634 {
635 scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, x);
636 }
637 public override void PushRef(ScriptCodeGen scg, Token errorAt)
638 {
639 throw new Exception("cannot get constant's address");
640 }
641 public override void PopPost(ScriptCodeGen scg, Token errorAt)
642 {
643 throw new Exception("cannot store into constant");
644 }
645 }
646
647 // The value is the entrypoint of a script-defined global function.
648 // These are also used for script-defined type static methods as the calling convention is the same,
649 // ie, the XMRInstance pointer is a hidden first argument.
650 // There is just one of these created when the function is being compiled as there is only one value
651 // of the function.
652 public class CompValuGlobalMeth: CompValu
653 {
654 private TokenDeclVar func;
655
656 public CompValuGlobalMeth(TokenDeclVar declFunc) : base(declFunc.GetDelType())
657 {
658 this.func = declFunc;
659 }
660
661 /**
662 * @brief PushVal for a function/method means push a delegate on the stack.
663 * We build a call to the DynamicMethod's CreateDelegate() function
664 * to create the delegate. Slip the scriptinstance pointer as the
665 * function's arg 0 so it will get passed to the function when called.
666 */
667 public override void PushVal(ScriptCodeGen scg, Token errorAt)
668 {
669 string dtn = type.ToString();
670 if(dtn.StartsWith("delegate "))
671 dtn = dtn.Substring(9);
672
673 // delegateinstance = (signature)scriptinstance.GetScriptMethodDelegate (methName, signature, arg0);
674 // where methName = [<sdtclass>.]<methname>(<argtypes>)
675 // signature = <rettype>(<argtypes>)
676 // arg0 = scriptinstance (XMRInstance)
677 scg.PushXMRInst(); // [0] scriptinstance
678 scg.ilGen.Emit(errorAt, OpCodes.Ldstr, func.ilGen.methName); // [1] method name
679 scg.ilGen.Emit(errorAt, OpCodes.Ldstr, dtn); // [2] delegate type name
680 scg.PushXMRInst(); // [3] scriptinstance
681 scg.ilGen.Emit(errorAt, OpCodes.Callvirt, gsmdMethodInfo); // [0] delegate instance
682 scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType()); // [0] cast to correct delegate class
683 }
684 public override void PushRef(ScriptCodeGen scg, Token errorAt)
685 {
686 throw new Exception("cannot get ref to global method");
687 }
688 public override void PopPost(ScriptCodeGen scg, Token errorAt)
689 {
690 throw new Exception("cannot store into global method");
691 }
692
693 /**
694 * @brief A direct call is much simpler than pushing a delegate.
695 * Just push the XMRInstance pointer, push the args and finally call the function.
696 */
697 public override void CallPre(ScriptCodeGen scg, Token errorAt)
698 {
699 if(!this.func.IsFuncTrivial(scg))
700 new ScriptCodeGen.CallLabel(scg, errorAt);
701
702 // all script-defined global functions are static methods created by DynamicMethod()
703 // and the first argument is always the XMR_Instance pointer
704 scg.PushXMRInst();
705 }
706 public override void CallPost(ScriptCodeGen scg, Token errorAt)
707 {
708 scg.ilGen.Emit(errorAt, OpCodes.Call, func.ilGen);
709 if(!this.func.IsFuncTrivial(scg))
710 scg.openCallLabel = null;
711 }
712 }
713
714 // The value is in a script-global variable = ScriptModule instance variable
715 // It could also be a script-global property
716 public class CompValuGlobalVar: CompValu
717 {
718 private static readonly FieldInfo glblVarsFieldInfo = typeof(XMRInstAbstract).GetField("glblVars");
719
720 private TokenDeclVar declVar;
721
722 public CompValuGlobalVar(TokenDeclVar declVar, XMRInstArSizes glblSizes) : base(declVar.type)
723 {
724 this.declVar = declVar;
725 if((declVar.getProp == null) && (declVar.setProp == null))
726 {
727 declVar.type.AssignVarSlot(declVar, glblSizes);
728 }
729 }
730 public override void PushVal(ScriptCodeGen scg, Token errorAt)
731 {
732 if((declVar.getProp == null) && (declVar.setProp == null))
733 {
734 scg.PushXMRInst();
735 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, glblVarsFieldInfo);
736 EmitFieldPushVal(scg, errorAt, declVar);
737 }
738 else if(declVar.getProp != null)
739 {
740 declVar.getProp.location.CallPre(scg, errorAt);
741 declVar.getProp.location.CallPost(scg, errorAt);
742 }
743 else
744 {
745 scg.ErrorMsg(errorAt, "property not readable");
746 scg.PushDefaultValue(declVar.type);
747 }
748 }
749 public override void PushRef(ScriptCodeGen scg, Token errorAt)
750 {
751 if((declVar.getProp == null) && (declVar.setProp == null))
752 {
753 scg.PushXMRInst();
754 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, glblVarsFieldInfo);
755 EmitFieldPushRef(scg, errorAt, declVar);
756 }
757 else
758 {
759 scg.ErrorMsg(errorAt, "cannot get address of property");
760 }
761 }
762 public override void PopPre(ScriptCodeGen scg, Token errorAt)
763 {
764 if((declVar.getProp == null) && (declVar.setProp == null))
765 {
766 scg.PushXMRInst();
767 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, glblVarsFieldInfo);
768 EmitFieldPopPre(scg, errorAt, declVar);
769 }
770 else if(declVar.setProp == null)
771 {
772 scg.ErrorMsg(errorAt, "property not writable");
773 }
774 }
775 public override void PopPost(ScriptCodeGen scg, Token errorAt)
776 {
777 if((declVar.getProp == null) && (declVar.setProp == null))
778 {
779 EmitFieldPopPost(scg, errorAt, declVar);
780 }
781 else if(declVar.setProp != null)
782 {
783 EmitPopPostProp(scg, errorAt, declVar.type, declVar.setProp.location);
784 }
785 else
786 {
787 scg.ilGen.Emit(errorAt, OpCodes.Pop);
788 }
789 }
790
791 // non-trivial because it needs to be copied into a temp
792 // in case the idiot does dumb-ass side effects tricks
793 // eg, (x = 0) + x + 2
794 // should read old value of x not 0
795 // but if 'xmroption norighttoleft;' in effect,
796 // we can read it in any order so reading an
797 // global variable is trivial provided it is
798 // not a property or the property function is
799 // trivial.
800 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
801 {
802 return readAt.nr2l && ((declVar.getProp == null) || declVar.getProp.IsFuncTrivial(scg));
803 }
804 }
805
806 // The value is in an $idxprop property of a script-defined type class or interface instance.
807 // Reading and writing is via a method call.
808 public class CompValuIdxProp: CompValu
809 {
810 private TokenDeclVar idxProp; // $idxprop property within baseRVal
811 private CompValu baseRVal; // pointer to class or interface object containing property
812 private TokenType[] argTypes; // argument types as required by $idxprop declaration
813 private CompValu[] indices; // actual index values to pass to getter/setter method
814 private CompValu setProp; // location of setter method
815
816 public CompValuIdxProp(TokenDeclVar idxProp, CompValu baseRVal, TokenType[] argTypes, CompValu[] indices) : base(idxProp.type)
817 {
818 this.idxProp = idxProp;
819 this.baseRVal = baseRVal;
820 this.argTypes = argTypes;
821 this.indices = indices;
822 }
823
824 /**
825 * @brief Pushing the property's value is a matter of calling the getter method
826 * with the supplied argument list as is.
827 */
828 public override void PushVal(ScriptCodeGen scg, Token errorAt)
829 {
830 if(idxProp.getProp != null)
831 {
832 if(!idxProp.getProp.IsFuncTrivial(scg))
833 {
834 for(int i = indices.Length; --i >= 0;)
835 {
836 indices[i] = scg.Trivialize(indices[i], errorAt);
837 }
838 }
839 CompValu getProp = GetIdxPropMeth(idxProp.getProp);
840 getProp.CallPre(scg, errorAt);
841 for(int i = 0; i < indices.Length; i++)
842 {
843 indices[i].PushVal(scg, errorAt, argTypes[i]);
844 }
845 getProp.CallPost(scg, errorAt);
846 }
847 else
848 {
849 // write-only property
850 scg.ErrorMsg(errorAt, "member not readable");
851 scg.PushDefaultValue(idxProp.type);
852 }
853 }
854
855 /**
856 * @brief A property does not have a memory address.
857 */
858 public override void PushRef(ScriptCodeGen scg, Token errorAt)
859 {
860 scg.ErrorMsg(errorAt, "member has no address");
861 scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
862 }
863
864 /**
865 * @brief Preparing to write a property consists of preparing to call the setter method
866 * then pushing the index arguments.
867 */
868 public override void PopPre(ScriptCodeGen scg, Token errorAt)
869 {
870 if(idxProp.setProp != null)
871 {
872 if(!idxProp.setProp.IsFuncTrivial(scg))
873 {
874 for(int i = indices.Length; --i >= 0;)
875 {
876 indices[i] = scg.Trivialize(indices[i], errorAt);
877 }
878 }
879 this.setProp = GetIdxPropMeth(idxProp.setProp);
880 this.setProp.CallPre(scg, errorAt);
881 for(int i = 0; i < indices.Length; i++)
882 {
883 indices[i].PushVal(scg, errorAt, argTypes[i]);
884 }
885 }
886 else
887 {
888 // read-only property
889 scg.ErrorMsg(errorAt, "member not writable");
890 }
891 }
892
893 /**
894 * @brief Finishing writing a property consists of finishing the call to the setter method
895 * now that the value to be written has been pushed by our caller.
896 */
897 public override void PopPost(ScriptCodeGen scg, Token errorAt)
898 {
899 if(idxProp.setProp != null)
900 {
901 this.setProp.CallPost(scg, errorAt);
902 }
903 else
904 {
905 scg.ilGen.Emit(errorAt, OpCodes.Pop);
906 }
907 }
908
909 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
910 {
911 // if no getter, reading would throw an error, so doesn't really matter what we say
912 if(idxProp.getProp == null)
913 return true;
914
915 // assume interface methods are always non-trivial because we don't know anything about the actual implementation
916 if(baseRVal.type is TokenTypeSDTypeInterface)
917 return false;
918
919 // accessing it in any way can't be trivial if reading the pointer isn't trivial
920 if(!baseRVal.IsReadTrivial(scg, readAt))
921 return false;
922
923 // likewise with the indices
924 foreach(CompValu idx in indices)
925 {
926 if(!idx.IsReadTrivial(scg, readAt))
927 return false;
928 }
929
930 // now the only way it can be non-trivial to read is if the getter() method itself is non-trivial.
931 return idxProp.getProp.IsFuncTrivial(scg);
932 }
933
934 /**
935 * @brief Get how to call the getter or setter method.
936 */
937 private CompValu GetIdxPropMeth(TokenDeclVar meth)
938 {
939 if(baseRVal.type is TokenTypeSDTypeClass)
940 {
941 return new CompValuInstMember(meth, baseRVal, false);
942 }
943 return new CompValuIntfMember(meth, baseRVal);
944 }
945 }
946
947 // This represents the type and location of an internally-defined function
948 // that a script can call
949 public class CompValuInline: CompValu
950 {
951 public TokenDeclInline declInline;
952
953 public CompValuInline(TokenDeclInline declInline) : base(declInline.GetDelType())
954 {
955 this.declInline = declInline;
956 }
957
958 public override void PushVal(ScriptCodeGen scg, Token errorAt)
959 {
960 scg.ErrorMsg(errorAt, "cannot use built-in for delegate, wrap it");
961 scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
962 }
963 public override void PushRef(ScriptCodeGen scg, Token errorAt)
964 {
965 scg.ErrorMsg(errorAt, "cannot use built-in for delegate, wrap it");
966 scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
967 }
968 public override void PopPre(ScriptCodeGen scg, Token errorAt)
969 {
970 scg.ErrorMsg(errorAt, "cannot use built-in for delegate, wrap it");
971 }
972 public override void PopPost(ScriptCodeGen scg, Token errorAt)
973 {
974 scg.ErrorMsg(errorAt, "cannot use built-in for delegate, wrap it");
975 scg.ilGen.Emit(errorAt, OpCodes.Pop);
976 }
977 }
978
979 // The value is the entrypoint of a script-defined type's interface method combined with
980 // the pointer used to access the method. Thus there is one of these per call site.
981 // They also handle accessing interface properties.
982 public class CompValuIntfMember: CompValu
983 {
984 private TokenDeclVar declVar;
985 private CompValu baseRVal;
986
987 public CompValuIntfMember(TokenDeclVar declVar, CompValu baseRVal) : base(declVar.type)
988 {
989 if(this.type == null)
990 throw new Exception("interface member type is null");
991 this.declVar = declVar; // which element of the baseRVal vector to be accessed
992 this.baseRVal = baseRVal; // the vector of delegates implementing the interface
993 }
994
995 /**
996 * @brief Reading a method's value means getting a delegate to that method.
997 * Reading a property's value means calling the getter method for that property.
998 */
999 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1000 {
1001 if(declVar.retType != null)
1002 {
1003 baseRVal.PushVal(scg, errorAt); // push pointer to delegate array on stack
1004 scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, declVar.vTableIndex); // select which delegate to access
1005 scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(Delegate)); // push delegate on stack
1006 scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType()); // cast to correct delegate class
1007 }
1008 else if(declVar.getProp != null)
1009 {
1010 CompValu getProp = new CompValuIntfMember(declVar.getProp, baseRVal);
1011 getProp.CallPre(scg, errorAt); // reading property, call its getter
1012 getProp.CallPost(scg, errorAt); // ... with no arguments
1013 }
1014 else
1015 {
1016 scg.ErrorMsg(errorAt, "member not readable");
1017 scg.PushDefaultValue(declVar.type);
1018 }
1019 }
1020
1021 /**
1022 * @brief Can't get the address of either a method or a property.
1023 */
1024 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1025 {
1026 scg.ErrorMsg(errorAt, "member has no address");
1027 scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
1028 }
1029
1030 /**
1031 * @brief Can't write a method.
1032 * For property, it means calling the setter method for that property.
1033 */
1034 public override void PopPre(ScriptCodeGen scg, Token errorAt)
1035 {
1036 if(declVar.setProp == null)
1037 {
1038 // read-only property
1039 scg.ErrorMsg(errorAt, "member not writable");
1040 }
1041 }
1042 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1043 {
1044 if(declVar.setProp != null)
1045 {
1046 CompValu setProp = new CompValuIntfMember(declVar.setProp, baseRVal);
1047 EmitPopPostProp(scg, errorAt, declVar.type, setProp);
1048 }
1049 else
1050 {
1051 scg.ilGen.Emit(errorAt, OpCodes.Pop);
1052 }
1053 }
1054
1055 /**
1056 * @brief Reading a method (ie, it's delegate) is always trivial, it's just retrieving
1057 * an element from the delegate array that make up the interface object.
1058 *
1059 * Reading a property is always non-trivial because we don't know which implementation
1060 * the interface is pointing to, so we don't know if it's trivial or not, so assume
1061 * the worst, ie, that it is non-trivial and might call CheckRun().
1062 *
1063 * But all that assumes that locating the interface object in the first place is
1064 * trivial, ie, baseRVal.PushVal() must not call CheckRun() either.
1065 */
1066 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
1067 {
1068 return baseRVal.IsReadTrivial(scg, readAt) && (declVar.getProp == null);
1069 }
1070
1071 /**
1072 * @brief We just defer to the default CallPre() and CallPost() methods.
1073 * They expect this.PushVal() to push a delegate to the method to be called.
1074 * If this member is a method, our PushVal() will read the correct element
1075 * of the iTable array and push it on the stack, ready for Invoke() to be
1076 * called. If this member is a property, the only way it can be called is
1077 * if the property is a delegate, in which case PushVal() will retrieve the
1078 * delegate by calling the property's getter method.
1079 */
1080 }
1081
1082 // The value is the entrypoint of an internal instance method
1083 // such as XMR_Array.index()
1084 public class CompValuIntInstMeth: CompValu
1085 {
1086 private TokenTypeSDTypeDelegate delType;
1087 private CompValu baseRVal;
1088 private MethodInfo methInfo;
1089
1090 public CompValuIntInstMeth(TokenTypeSDTypeDelegate delType, CompValu baseRVal, MethodInfo methInfo) : base(delType)
1091 {
1092 this.delType = delType;
1093 this.baseRVal = baseRVal;
1094 this.methInfo = methInfo;
1095 }
1096
1097 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1098 {
1099 // its value, ie, without applying the (arglist), is a delegate...
1100 baseRVal.PushVal(scg, errorAt);
1101 scg.ilGen.Emit(errorAt, OpCodes.Ldftn, methInfo);
1102 scg.ilGen.Emit(errorAt, OpCodes.Newobj, delType.decl.GetConstructorInfo());
1103 }
1104 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1105 {
1106 throw new Exception("cannot get ref to instance method");
1107 }
1108 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1109 {
1110 throw new Exception("cannot store into instance method");
1111 }
1112
1113 public override void CallPre(ScriptCodeGen scg, Token errorAt)
1114 {
1115 // internal instance methods are always trivial so never need a CallLabel.
1116 baseRVal.PushVal(scg, errorAt);
1117 }
1118 public override void CallPost(ScriptCodeGen scg, Token errorAt)
1119 {
1120 scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
1121 }
1122 }
1123
1124 // The value is fetched by calling an internal instance method
1125 // such as XMR_Array.count
1126 public class CompValuIntInstROProp: CompValu
1127 {
1128 private CompValu baseRVal;
1129 private MethodInfo methInfo;
1130
1131 public CompValuIntInstROProp(TokenType valType, CompValu baseRVal, MethodInfo methInfo) : base(valType)
1132 {
1133 this.baseRVal = baseRVal;
1134 this.methInfo = methInfo;
1135 }
1136
1137 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1138 {
1139 baseRVal.PushVal(scg, errorAt);
1140 scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
1141 }
1142 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1143 {
1144 scg.ErrorMsg(errorAt, "cannot get ref to read-only property");
1145 scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
1146 }
1147 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1148 {
1149 scg.ErrorMsg(errorAt, "cannot store into read-only property");
1150 scg.ilGen.Emit(errorAt, OpCodes.Pop);
1151 }
1152 }
1153
1154 // The value is in a member of a script-defined type class instance.
1155 // field: value is in one of the arrays contained within XMRSDTypeClObj.instVars
1156 // method: value is a delegate; can be called
1157 // property: reading and writing is via a method call
1158 public class CompValuInstMember: CompValu
1159 {
1160 private static readonly FieldInfo instVarsFieldInfo = typeof(XMRSDTypeClObj).GetField("instVars");
1161 private static readonly FieldInfo vTableFieldInfo = typeof(XMRSDTypeClObj).GetField("sdtcVTable");
1162
1163 private TokenDeclVar declVar; // member being accessed
1164 private CompValu baseRVal; // pointer to particular object instance
1165 private bool ignoreVirt; // ignore virtual attribute; use declVar's non-virtual method/property
1166
1167 public CompValuInstMember(TokenDeclVar declVar, CompValu baseRVal, bool ignoreVirt) : base(declVar.type)
1168 {
1169 this.declVar = declVar;
1170 this.baseRVal = baseRVal;
1171 this.ignoreVirt = ignoreVirt;
1172 }
1173
1174 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1175 {
1176 if(declVar.retType != null)
1177 {
1178 // a method's value, ie, without applying the (arglist), is a delegate...
1179 PushValMethod(scg, errorAt);
1180 }
1181 else if(declVar.vTableArray != null)
1182 {
1183 // a field's value is its XMRSDTypeClObj.instVars array element
1184 baseRVal.PushVal(scg, errorAt);
1185 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, instVarsFieldInfo);
1186 EmitFieldPushVal(scg, errorAt, declVar);
1187 }
1188 else if(declVar.getProp != null)
1189 {
1190 // a property's value is calling its get method with no arguments
1191 CompValu getProp = new CompValuInstMember(declVar.getProp, baseRVal, ignoreVirt);
1192 getProp.CallPre(scg, errorAt);
1193 getProp.CallPost(scg, errorAt);
1194 }
1195 else
1196 {
1197 // write-only property
1198 scg.ErrorMsg(errorAt, "member not readable");
1199 scg.PushDefaultValue(declVar.type);
1200 }
1201 }
1202 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1203 {
1204 if(declVar.vTableArray != null)
1205 {
1206 // a field's value is its XMRSDTypeClObj.instVars array element
1207 baseRVal.PushVal(scg, errorAt);
1208 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, instVarsFieldInfo);
1209 EmitFieldPushRef(scg, errorAt, declVar);
1210 }
1211 else
1212 {
1213 scg.ErrorMsg(errorAt, "member has no address");
1214 scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
1215 }
1216 }
1217 public override void PopPre(ScriptCodeGen scg, Token errorAt)
1218 {
1219 if(declVar.vTableArray != null)
1220 {
1221 // a field's value is its XMRSDTypeClObj.instVars array element
1222 baseRVal.PushVal(scg, errorAt);
1223 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, instVarsFieldInfo);
1224 EmitFieldPopPre(scg, errorAt, declVar);
1225 }
1226 else if(declVar.setProp == null)
1227 {
1228 // read-only property
1229 scg.ErrorMsg(errorAt, "member not writable");
1230 }
1231 }
1232 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1233 {
1234 if(declVar.vTableArray != null)
1235 {
1236 EmitFieldPopPost(scg, errorAt, declVar);
1237 }
1238 else if(declVar.setProp != null)
1239 {
1240 CompValu setProp = new CompValuInstMember(declVar.setProp, baseRVal, ignoreVirt);
1241 EmitPopPostProp(scg, errorAt, declVar.type, setProp);
1242 }
1243 else
1244 {
1245 scg.ilGen.Emit(errorAt, OpCodes.Pop);
1246 }
1247 }
1248
1249 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
1250 {
1251 // accessing it in any way can't be trivial if reading the pointer isn't trivial.
1252 // this also handles strict right-to-left mode detection as the side-effect can
1253 // only apply to the pointer (it can't change which field or method we access).
1254 if(!baseRVal.IsReadTrivial(scg, readAt))
1255 return false;
1256
1257 // now the only way it can be non-trivial to read is if it is a property and the
1258 // getter() method is non-trivial. reading a method means getting a delegate
1259 // which is always trivial, and reading a simple field is always trivial, ie, no
1260 // CheckRun() call can possibly be involved.
1261 if(declVar.retType != null)
1262 {
1263 // a method's value, ie, without applying the (arglist), is a delegate...
1264 return true;
1265 }
1266 if(declVar.vTableArray != null)
1267 {
1268 // a field's value is its XMRSDTypeClObj.instVars array element
1269 return true;
1270 }
1271 if(declVar.getProp != null)
1272 {
1273 // a property's value is calling its get method with no arguments
1274 return declVar.getProp.IsFuncTrivial(scg);
1275 }
1276
1277 // write-only property
1278 return true;
1279 }
1280
1281 public override void CallPre(ScriptCodeGen scg, Token errorAt)
1282 {
1283 if(declVar.retType != null)
1284 {
1285 CallPreMethod(scg, errorAt);
1286 }
1287 else
1288 {
1289 base.CallPre(scg, errorAt);
1290 }
1291 }
1292 public override void CallPost(ScriptCodeGen scg, Token errorAt)
1293 {
1294 if(declVar.retType != null)
1295 {
1296 CallPostMethod(scg, errorAt);
1297 }
1298 else
1299 {
1300 base.CallPost(scg, errorAt);
1301 }
1302 }
1303
1304 /**
1305 * @brief A PushVal() for a method means to push a delegate for the method on the stack.
1306 */
1307 private void PushValMethod(ScriptCodeGen scg, Token errorAt)
1308 {
1309 if((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0)
1310 throw new Exception("dont use for statics");
1311
1312 if(ignoreVirt || (declVar.vTableIndex < 0))
1313 {
1314
1315 /*
1316 * Non-virtual instance method, create a delegate that references the method.
1317 */
1318 string dtn = type.ToString();
1319
1320 // delegateinstance = (signature)scriptinstance.GetScriptMethodDelegate (methName, signature, arg0);
1321 // where methName = <sdtclass>.<methname>(<argtypes>)
1322 // signature = <rettype>(<argtypes>)
1323 // arg0 = sdt istance (XMRSDTypeClObj) 'this' value
1324 scg.PushXMRInst(); // [0] scriptinstance
1325 scg.ilGen.Emit(errorAt, OpCodes.Ldstr, declVar.ilGen.methName); // [1] method name
1326 scg.ilGen.Emit(errorAt, OpCodes.Ldstr, dtn); // [2] delegate type name
1327 baseRVal.PushVal(scg, errorAt); // [3] sdtinstance
1328 scg.ilGen.Emit(errorAt, OpCodes.Callvirt, gsmdMethodInfo); // [0] delegate instance
1329 scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType()); // [0] cast to correct delegate class
1330 }
1331 else
1332 {
1333
1334 /*
1335 * Virtual instance method, get the delegate from the vtable.
1336 */
1337 baseRVal.PushVal(scg, errorAt); // 'this' selecting the instance
1338 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, vTableFieldInfo); // get pointer to instance's vtable array
1339 scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, declVar.vTableIndex); // select vtable element
1340 scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(Delegate)); // get delegate pointer = 'this' for 'Invoke()'
1341 scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType()); // cast to correct delegate class
1342 }
1343 }
1344
1345 private void CallPreMethod(ScriptCodeGen scg, Token errorAt)
1346 {
1347 if((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0)
1348 throw new Exception("dont use for statics");
1349
1350 if(!this.declVar.IsFuncTrivial(scg))
1351 new ScriptCodeGen.CallLabel(scg, errorAt);
1352
1353 if(ignoreVirt || (declVar.vTableIndex < 0))
1354 {
1355 baseRVal.PushVal(scg, errorAt); // 'this' being passed directly to method
1356 }
1357 else
1358 {
1359 baseRVal.PushVal(scg, errorAt); // 'this' selecting the instance
1360 scg.ilGen.Emit(errorAt, OpCodes.Ldfld, vTableFieldInfo); // get pointer to instance's vtable array
1361 scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, declVar.vTableIndex); // select vtable element
1362 scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(Delegate)); // get delegate pointer = 'this' for 'Invoke()'
1363 scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType()); // cast to correct delegate class
1364 }
1365 }
1366 private void CallPostMethod(ScriptCodeGen scg, Token errorAt)
1367 {
1368 if(ignoreVirt || (declVar.vTableIndex < 0))
1369 {
1370 // non-virt instance, just call function directly
1371 scg.ilGen.Emit(errorAt, OpCodes.Call, declVar.ilGen);
1372 }
1373 else
1374 {
1375 // virtual, call via delegate Invoke(...) method
1376 TokenTypeSDTypeDelegate ttd = (TokenTypeSDTypeDelegate)type;
1377 MethodInfo invokeMethodInfo = ttd.decl.GetInvokerInfo();
1378 scg.ilGen.Emit(errorAt, OpCodes.Callvirt, invokeMethodInfo);
1379 }
1380
1381 if(!this.declVar.IsFuncTrivial(scg))
1382 scg.openCallLabel = null;
1383 }
1384 }
1385
1386 // The value is an integer constant
1387 public class CompValuInteger: CompValu
1388 {
1389 public int x;
1390
1391 public CompValuInteger(TokenType type, int x) : base(type)
1392 {
1393 if(!(this.type is TokenTypeInt))
1394 {
1395 this.type = new TokenTypeInt(this.type);
1396 }
1397 this.x = x;
1398 }
1399 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1400 {
1401 scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, x);
1402 }
1403 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1404 {
1405 throw new Exception("cannot get constant's address");
1406 }
1407 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1408 {
1409 throw new Exception("cannot store into constant");
1410 }
1411 }
1412
1413 // The value is an element of a list
1414 public class CompValuListEl: CompValu
1415 {
1416 private static readonly MethodInfo getElementFromListMethodInfo =
1417 typeof(CompValuListEl).GetMethod("GetElementFromList", new Type[] { typeof(LSL_List), typeof(int) });
1418
1419 private CompValu theList;
1420 private CompValu subscript;
1421
1422 public CompValuListEl(TokenType type, CompValu theList, CompValu subscript) : base(type)
1423 {
1424 this.theList = theList;
1425 this.subscript = subscript;
1426 }
1427 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1428 {
1429 theList.PushVal(scg, errorAt, new TokenTypeList(type));
1430 subscript.PushVal(scg, errorAt, new TokenTypeInt(type));
1431 scg.ilGen.Emit(errorAt, OpCodes.Call, getElementFromListMethodInfo);
1432 }
1433 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1434 {
1435 throw new Exception("cannot get list element's address");
1436 }
1437 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1438 {
1439 scg.ErrorMsg(errorAt, "cannot store into list element");
1440 scg.ilGen.Emit(errorAt, OpCodes.Pop);
1441 }
1442
1443 public static object GetElementFromList(LSL_List lis, int idx)
1444 {
1445 object element = lis.Data[idx];
1446 if(element is LSL_Float)
1447 return TypeCast.EHArgUnwrapFloat(element);
1448 if(element is LSL_Integer)
1449 return TypeCast.EHArgUnwrapInteger(element);
1450 if(element is LSL_String)
1451 return TypeCast.EHArgUnwrapString(element);
1452 if(element is OpenMetaverse.Quaternion)
1453 return TypeCast.EHArgUnwrapRotation(element);
1454 if(element is OpenMetaverse.Vector3)
1455 return TypeCast.EHArgUnwrapVector(element);
1456 return element;
1457 }
1458 }
1459
1460 // The value is kept in a script-addressable local variable
1461 public class CompValuLocalVar: CompValu
1462 {
1463 private static int htpopseq = 0;
1464
1465 private ScriptMyLocal localBuilder;
1466
1467 public CompValuLocalVar(TokenType type, string name, ScriptCodeGen scg) : base(type)
1468 {
1469 if(type.ToHeapTrackerType() != null)
1470 {
1471 this.localBuilder = scg.ilGen.DeclareLocal(type.ToHeapTrackerType(), name);
1472 scg.PushXMRInst();
1473 scg.ilGen.Emit(type, OpCodes.Newobj, type.GetHeapTrackerCtor());
1474 scg.ilGen.Emit(type, OpCodes.Stloc, localBuilder);
1475 }
1476 else
1477 {
1478 this.localBuilder = scg.ilGen.DeclareLocal(ToSysType(), name);
1479 }
1480 }
1481
1482 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1483 {
1484 scg.ilGen.Emit(errorAt, OpCodes.Ldloc, localBuilder);
1485 if(type.ToHeapTrackerType() != null)
1486 {
1487 type.CallHeapTrackerPushMeth(errorAt, scg.ilGen);
1488 }
1489 }
1490 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1491 {
1492 if(type.ToHeapTrackerType() != null)
1493 {
1494 scg.ErrorMsg(errorAt, "can't take ref of heap-tracked type " + type.ToString());
1495 scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
1496 }
1497 else
1498 {
1499 scg.ilGen.Emit(errorAt, OpCodes.Ldloca, localBuilder);
1500 }
1501 }
1502
1503 public override void PopPre(ScriptCodeGen scg, Token errorAt)
1504 {
1505 if(type.ToHeapTrackerType() != null)
1506 {
1507 scg.ilGen.Emit(errorAt, OpCodes.Ldloc, localBuilder);
1508 }
1509 }
1510 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1511 {
1512 if(type.ToHeapTrackerType() != null)
1513 {
1514 type.CallHeapTrackerPopMeth(errorAt, scg.ilGen);
1515 }
1516 else
1517 {
1518 scg.ilGen.Emit(errorAt, OpCodes.Stloc, localBuilder);
1519 }
1520 }
1521
1522 public void Pop(ScriptCodeGen scg, Token errorAt)
1523 {
1524 if(type.ToHeapTrackerType() != null)
1525 {
1526 /*
1527 * Popping into a heap tracker wrapped local variable.
1528 * First pop value into a temp var, then call the heap tracker's pop method.
1529 */
1530 ScriptMyLocal htpop = scg.ilGen.DeclareLocal(type.ToSysType(), "htpop$" + (++htpopseq).ToString());
1531 scg.ilGen.Emit(errorAt, OpCodes.Stloc, htpop);
1532 scg.ilGen.Emit(errorAt, OpCodes.Ldloc, localBuilder);
1533 scg.ilGen.Emit(errorAt, OpCodes.Ldloc, htpop);
1534 type.CallHeapTrackerPopMeth(errorAt, scg.ilGen);
1535 }
1536 else
1537 {
1538
1539 /*
1540 * Not a heap-tracked local var, just pop directly into it.
1541 */
1542 scg.ilGen.Emit(errorAt, OpCodes.Stloc, localBuilder);
1543 }
1544 }
1545
1546 // non-trivial because it needs to be copied into a temp
1547 // in case the idiot does dumb-ass side effects tricks
1548 // eg, (x = 0) + x + 2
1549 // should read old value of x not 0
1550 // but if 'xmroption norighttoleft;' in effect,
1551 // we can read it in any order so reading a
1552 // local variable is trivial.
1553 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
1554 {
1555 return readAt.nr2l;
1556 }
1557 }
1558
1559 // The value is a null
1560 public class CompValuNull: CompValu
1561 {
1562 public CompValuNull(TokenType type) : base(type) { }
1563 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1564 {
1565 scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
1566 }
1567 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1568 {
1569 throw new Exception("cannot get null's address");
1570 }
1571 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1572 {
1573 throw new Exception("cannot store into null");
1574 }
1575 }
1576
1577 // The value is a rotation
1578 public class CompValuRot: CompValu
1579 {
1580 public CompValu x;
1581 public CompValu y;
1582 public CompValu z;
1583 public CompValu w;
1584
1585 private static readonly ConstructorInfo lslRotConstructorInfo =
1586 typeof(LSL_Rotation).GetConstructor(new Type[] { typeof (double),
1587 typeof (double),
1588 typeof (double),
1589 typeof (double) });
1590
1591 public CompValuRot(TokenType type, CompValu x, CompValu y, CompValu z, CompValu w) :
1592 base(type)
1593 {
1594 if(!(type is TokenTypeRot))
1595 {
1596 this.type = new TokenTypeRot(type);
1597 }
1598 this.x = x;
1599 this.y = y;
1600 this.z = z;
1601 this.w = w;
1602 }
1603 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1604 {
1605 this.x.PushVal(scg, errorAt, new TokenTypeFloat(this.x.type));
1606 this.y.PushVal(scg, errorAt, new TokenTypeFloat(this.y.type));
1607 this.z.PushVal(scg, errorAt, new TokenTypeFloat(this.z.type));
1608 this.w.PushVal(scg, errorAt, new TokenTypeFloat(this.w.type));
1609 scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslRotConstructorInfo);
1610 }
1611 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1612 {
1613 throw new Exception("cannot get constant's address");
1614 }
1615 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1616 {
1617 throw new Exception("cannot store into constant");
1618 }
1619
1620 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
1621 {
1622 // the supplied values must be trivial because when we call their PushVal()s
1623 // there will be stuff on the stack for all but the first PushVal() and so
1624 // they would have a non-empty stack at their call label.
1625 if(!this.w.IsReadTrivial(scg, readAt) ||
1626 !this.x.IsReadTrivial(scg, readAt) ||
1627 !this.y.IsReadTrivial(scg, readAt) ||
1628 !this.z.IsReadTrivial(scg, readAt))
1629 {
1630 throw new Exception("rotation values must be trivial");
1631 }
1632
1633 return true;
1634 }
1635 }
1636
1637 // The value is in a static field of an internally defined struct/class
1638 public class CompValuSField: CompValu
1639 {
1640 public FieldInfo field;
1641
1642 public CompValuSField(TokenType type, FieldInfo field) : base(type)
1643 {
1644 this.field = field;
1645 }
1646 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1647 {
1648 if((field.Attributes & FieldAttributes.Literal) == 0)
1649 {
1650 scg.ilGen.Emit(errorAt, OpCodes.Ldsfld, field);
1651 return;
1652 }
1653 if(field.FieldType == typeof(LSL_Rotation))
1654 {
1655 LSL_Rotation rot = (LSL_Rotation)field.GetValue(null);
1656 scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, rot.x);
1657 scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, rot.y);
1658 scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, rot.z);
1659 scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, rot.s);
1660 scg.ilGen.Emit(errorAt, OpCodes.Newobj, ScriptCodeGen.lslRotationConstructorInfo);
1661 return;
1662 }
1663 if(field.FieldType == typeof(LSL_Vector))
1664 {
1665 LSL_Vector vec = (LSL_Vector)field.GetValue(null);
1666 scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, vec.x);
1667 scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, vec.y);
1668 scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, vec.z);
1669 scg.ilGen.Emit(errorAt, OpCodes.Newobj, ScriptCodeGen.lslRotationConstructorInfo);
1670 return;
1671 }
1672 if(field.FieldType == typeof(string))
1673 {
1674 string str = (string)field.GetValue(null);
1675 scg.ilGen.Emit(errorAt, OpCodes.Ldstr, str);
1676 return;
1677 }
1678 throw new Exception("unsupported literal type " + field.FieldType.Name);
1679 }
1680 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1681 {
1682 if((field.Attributes & FieldAttributes.Literal) != 0)
1683 {
1684 throw new Exception("can't write a constant");
1685 }
1686 scg.ilGen.Emit(errorAt, OpCodes.Ldflda, field);
1687 }
1688 public override void PopPre(ScriptCodeGen scg, Token errorAt)
1689 {
1690 }
1691 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1692 {
1693 if((field.Attributes & FieldAttributes.Literal) != 0)
1694 {
1695 throw new Exception("can't write a constant");
1696 }
1697 scg.ilGen.Emit(errorAt, OpCodes.Stsfld, field);
1698 }
1699
1700 // non-trivial because it needs to be copied into a temp
1701 // in case the idiot does dumb-ass side effects tricks
1702 // eg, (x = 0) + x + 2
1703 // should read old value of x not 0
1704 // but if 'xmroption norighttoleft;' in effect,
1705 // we can read it in any order so reading a
1706 // local variable is trivial.
1707 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
1708 {
1709 return readAt.nr2l;
1710 }
1711 }
1712
1713 // The value is a character within a string
1714 public class CompValuStrChr: CompValu
1715 {
1716 private static readonly MethodInfo getCharFromStringMethodInfo =
1717 typeof(CompValuStrChr).GetMethod("GetCharFromString", new Type[] { typeof(string), typeof(int) });
1718
1719 private CompValu theString;
1720 private CompValu subscript;
1721
1722 public CompValuStrChr(TokenType type, CompValu theString, CompValu subscript) : base(type)
1723 {
1724 this.theString = theString;
1725 this.subscript = subscript;
1726 }
1727 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1728 {
1729 theString.PushVal(scg, errorAt, new TokenTypeStr(type));
1730 subscript.PushVal(scg, errorAt, new TokenTypeInt(type));
1731 scg.ilGen.Emit(errorAt, OpCodes.Call, getCharFromStringMethodInfo);
1732 }
1733 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1734 {
1735 throw new Exception("cannot get string character's address");
1736 }
1737 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1738 {
1739 scg.ErrorMsg(errorAt, "cannot store into string character");
1740 scg.ilGen.Emit(errorAt, OpCodes.Pop);
1741 }
1742
1743 public static char GetCharFromString(string s, int i)
1744 {
1745 return s[i];
1746 }
1747 }
1748
1749 // The value is a key or string constant
1750 public class CompValuString: CompValu
1751 {
1752 public string x;
1753
1754 public CompValuString(TokenType type, string x) : base(type)
1755 {
1756 if(!(type is TokenTypeKey) && !(this.type is TokenTypeStr))
1757 {
1758 throw new Exception("bad type " + type.ToString());
1759 }
1760 this.x = x;
1761 }
1762 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1763 {
1764 scg.ilGen.Emit(errorAt, OpCodes.Ldstr, x);
1765 }
1766 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1767 {
1768 throw new Exception("cannot get constant's address");
1769 }
1770 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1771 {
1772 throw new Exception("cannot store into constant");
1773 }
1774 }
1775
1776 // The value is kept in a temp local variable
1777 public class CompValuTemp: CompValu
1778 {
1779 public ScriptMyLocal localBuilder;
1780
1781 public CompValuTemp(TokenType type, ScriptCodeGen scg) : base(type)
1782 {
1783 string name = "tmp$" + (++scg.tempCompValuNum);
1784 this.localBuilder = scg.ilGen.DeclareLocal(ToSysType(), name);
1785 }
1786 protected CompValuTemp(TokenType type) : base(type) { } // CompValuVoid uses this
1787
1788 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1789 {
1790 scg.ilGen.Emit(errorAt, OpCodes.Ldloc, localBuilder);
1791 }
1792 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1793 {
1794 scg.ilGen.Emit(errorAt, OpCodes.Ldloca, localBuilder);
1795 }
1796 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1797 {
1798 scg.ilGen.Emit(errorAt, OpCodes.Stloc, localBuilder);
1799 }
1800 public void Pop(ScriptCodeGen scg, Token errorAt, TokenType stackType)
1801 {
1802 TypeCast.CastTopOfStack(scg, errorAt, stackType, this.type, false);
1803 this.PopPost(scg, errorAt); // in case PopPost() overridden eg by CompValuVoid
1804 }
1805 public void Pop(ScriptCodeGen scg, Token errorAt)
1806 {
1807 this.PopPost(scg, errorAt); // in case PopPost() overridden eg by CompValuVoid
1808 }
1809 }
1810
1811 // The value is a vector
1812 public class CompValuVec: CompValu
1813 {
1814 public CompValu x;
1815 public CompValu y;
1816 public CompValu z;
1817
1818 private static readonly ConstructorInfo lslVecConstructorInfo =
1819 typeof(LSL_Vector).GetConstructor(new Type[] { typeof (double),
1820 typeof (double),
1821 typeof (double) });
1822
1823 public CompValuVec(TokenType type, CompValu x, CompValu y, CompValu z) : base(type)
1824 {
1825 if(!(type is TokenTypeVec))
1826 {
1827 this.type = new TokenTypeVec(type);
1828 }
1829 this.x = x;
1830 this.y = y;
1831 this.z = z;
1832 }
1833 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1834 {
1835 this.x.PushVal(scg, errorAt, new TokenTypeFloat(this.x.type));
1836 this.y.PushVal(scg, errorAt, new TokenTypeFloat(this.y.type));
1837 this.z.PushVal(scg, errorAt, new TokenTypeFloat(this.z.type));
1838 scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslVecConstructorInfo);
1839 }
1840 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1841 {
1842 throw new Exception("cannot get constant's address");
1843 }
1844 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1845 {
1846 throw new Exception("cannot store into constant");
1847 }
1848
1849 public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
1850 {
1851 // the supplied values must be trivial because when we call their PushVal()s
1852 // there will be stuff on the stack for all but the first PushVal() and so
1853 // they would have a non-empty stack at their call label.
1854 if(!this.x.IsReadTrivial(scg, readAt) ||
1855 !this.y.IsReadTrivial(scg, readAt) ||
1856 !this.z.IsReadTrivial(scg, readAt))
1857 {
1858 throw new Exception("vector values must be trivial");
1859 }
1860
1861 return true;
1862 }
1863 }
1864
1865 // Used to indicate value will be discarded (eg, where to put return value from a call)
1866 public class CompValuVoid: CompValuTemp
1867 {
1868 public CompValuVoid(Token token) : base((token is TokenTypeVoid) ? (TokenTypeVoid)token : new TokenTypeVoid(token))
1869 {
1870 }
1871 public override void PushVal(ScriptCodeGen scg, Token errorAt)
1872 {
1873 }
1874 public override void PushRef(ScriptCodeGen scg, Token errorAt)
1875 {
1876 throw new Exception("cannot get void address");
1877 }
1878 public override void PopPost(ScriptCodeGen scg, Token errorAt)
1879 {
1880 }
1881 }
1882}