Develop and Download Open Source Software

Browse CVS Repository

Contents of /netruby/netruby/NETRuby.cs

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1.1.1 - (show annotations) (download) (vendor branch)
Mon Apr 8 13:27:50 2002 UTC (22 years ago) by arton
Branch: MAIN, vendor
CVS Tags: start, HEAD
Changes since 1.1: +0 -0 lines
initial version 0.8

1 /*
2 Copyright(C) 2001-2002 arton
3
4 Permission is granted for use, copying, modification, distribution,
5 and distribution of modified versions of this work as long as the
6 above copyright notice is included.
7 */
8
9 using System;
10 using System.Diagnostics;
11 using System.Collections;
12 using System.IO;
13 using System.Text;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Threading;
17 using System.Security;
18
19 [assembly: AssemblyTitle("NETRuby")]
20 [assembly: AssemblyVersion("0.8.*")]
21 [assembly: AssemblyCopyright("NETRuby - Copyright (C) 2002 arton")]
22
23 namespace arton.NETRuby
24 {
25 public class st_table : Hashtable, ICloneable
26 {
27 public st_table()
28 {
29 }
30 public st_table(Hashtable h) : base(h)
31 {
32 }
33 public bool lookup(string name, out uint id)
34 {
35 object o = this[name];
36 if (o != null)
37 {
38 id = (uint)o;
39 return true;
40 }
41 id = 0;
42 return false;
43 }
44 public bool lookup(uint id, out string name)
45 {
46 object o = this[id];
47 if (o != null)
48 {
49 name = (string)o;
50 return true;
51 }
52 name = null;
53 return false;
54 }
55 public bool lookup(uint id, out object o)
56 {
57 o = this[id];
58 return (o != null) ? true : false;
59 }
60 public bool lookup(object key, out st_table o)
61 {
62 o = (st_table)this[key];
63 return (o != null) ? true : false;
64 }
65 public bool delete(uint id, out object o)
66 {
67 lock (SyncRoot)
68 {
69 bool ret = lookup(id, out o);
70 if (ret)
71 {
72 Remove(id);
73 }
74 return ret;
75 }
76 }
77 public override object Clone()
78 {
79 lock(SyncRoot)
80 {
81 return new st_table((Hashtable)base.Clone());
82 }
83 }
84 }
85
86 internal class trace_var
87 {
88 public trace_var()
89 {
90 removed = false;
91 data = null;
92 next = null;
93 }
94 internal bool removed;
95 internal delegate void func();
96 internal object data;
97 internal trace_var next;
98 }
99
100 //
101 // hold all global variables in a NetRuby instance
102 public class GlobalEntry
103 {
104 public GlobalEntry(uint i)
105 {
106 id = i;
107 data = null;
108 block_trace = false;
109 trace = null;
110 getMethod = new Getter(undef_getter);
111 setMethod = new Setter(undef_setter);
112 }
113 static private object undef_getter(uint i, GlobalEntry gb, NetRuby rb)
114 {
115 rb.warning("global variable `" + rb.id2name(i) + "' not initialized");
116 return null;
117 }
118 static private void undef_setter(object val, uint i, GlobalEntry gb, NetRuby rb)
119 {
120 gb.getMethod = new Getter(val_getter);
121 gb.setMethod = new Setter(val_setter);
122 gb.data = val;
123 }
124 static private object val_getter(uint i, GlobalEntry gb, NetRuby rb)
125 {
126 return gb.data;
127 }
128 static private void val_setter(object val, uint i, GlobalEntry gb, NetRuby rb)
129 {
130 gb.data = val;
131 }
132 static public void ReadonlySetter(object val, uint i, GlobalEntry gb, NetRuby rb)
133 {
134 throw new eNameError("can't set variable " + rb.id2name(i));
135 }
136
137 internal uint id;
138 internal object data;
139 public delegate object Getter(uint id, GlobalEntry gb, NetRuby rb);
140 public delegate void Setter(object val, uint id, GlobalEntry gb, NetRuby rb);
141 internal void ReplaceGetter(Getter gt)
142 {
143 if (gt == null)
144 getMethod = new Getter(val_getter);
145 else
146 getMethod = gt;
147 }
148 internal void ReplaceSetter(Setter st)
149 {
150 if (st == null)
151 setMethod = new Setter(val_setter);
152 else
153 setMethod = st;
154 }
155 public object GetValue(NetRuby rb)
156 {
157 return getMethod(id, this, rb);
158 }
159 public void SetValue(object val, NetRuby rb)
160 {
161 setMethod(val, id, this, rb);
162 }
163 private event Getter getMethod;
164 private event Setter setMethod;
165 internal bool block_trace;
166 internal trace_var trace;
167 }
168
169 internal class LocalVars : ICloneable
170 {
171 internal LocalVars(LocalVars p, int ct, int dl)
172 {
173 if (ct > 0)
174 tbl = new uint[ct + 2];
175 else
176 tbl = null;
177 prev = p;
178 dlev = dl;
179 }
180 internal uint[] tbl;
181 internal int dlev;
182 internal LocalVars prev;
183 internal int Length
184 {
185 get { return (tbl != null) ? tbl.Length : 0; }
186 }
187 public object Clone()
188 {
189 LocalVars o;
190 lock (this)
191 {
192 o = (LocalVars)MemberwiseClone();
193 o.tbl = (uint[])o.tbl.Clone();
194 }
195 if (o.prev != null)
196 {
197 o.prev = (LocalVars)o.prev.Clone();
198 }
199 return o;
200 }
201 internal int Count(uint id)
202 {
203 if (id == 0) return Length;
204 if (tbl != null)
205 {
206 int cnt = Array.IndexOf(tbl, id);
207 if (cnt >= 0) return cnt;
208 }
209 return Append(id);
210 }
211 internal int Append(uint id)
212 {
213 int idx = 2;
214 lock (this)
215 {
216 if (tbl == null) {
217 tbl = new uint[3];
218 tbl[0] = (uint)'_';
219 tbl[1] = (uint)'~';
220 if (id == '_') return 0;
221 if (id == '~') return 1;
222 }
223 else
224 {
225 idx = Length;
226 uint[] t = new uint[idx + 1];
227 Array.Copy(tbl, t, idx);
228 tbl = t;
229 }
230 tbl[idx] = id;
231 }
232 return idx;
233 }
234 internal void Init(int cnt, uint[] local, bool dlv)
235 {
236 lock (this)
237 {
238 if (cnt > 0) {
239 tbl = new uint[cnt + 2];
240 Array.Copy(local, tbl, cnt);
241 }
242 else {
243 tbl = null;
244 }
245 }
246 dlev = (dlv) ? 1 : 0;
247 }
248 }
249
250 public class RVarmap : RBasic
251 {
252 public RVarmap(NetRuby rb, uint i, object v, RVarmap prev) :
253 base(rb, null)
254 {
255 id = i;
256 val = v;
257 next = prev;
258 }
259 internal new uint id;
260 internal object val;
261 internal RVarmap next;
262 }
263
264 struct CacheEntry
265 {
266 internal uint mid; // method id
267 internal uint mid0;
268 internal RMetaObject klass;
269 internal RMetaObject origin;
270 internal RNode method;
271 internal NOEX noex;
272 internal const int SIZE = 0x800;
273 internal const int MASK = 0x7ff;
274 static internal int EXPR1(object o, uint mid)
275 {
276 return ((int)(((uint)o.GetHashCode()) ^ mid) & MASK);
277 }
278 internal void SetEmtptyInfo(RMetaObject o, uint id)
279 {
280 klass = origin = o;
281 mid = mid0 = id;
282 noex = NOEX.PUBLIC;
283 method = null;
284 }
285 internal void SetInfo(RMetaObject o, uint id, RNode body, RMetaObject org)
286 {
287 klass = o;
288 noex = body.noex;
289 body = body.body;
290 if (body is RNFBody)
291 {
292 mid = id;
293 origin = body.orig;
294 mid0 = body.mid;
295 method = body.head;
296 }
297 else
298 {
299 origin = org;
300 mid = mid0 = id;
301 method = body;
302 }
303 }
304 }
305
306 internal enum CALLSTAT
307 {
308 PUBLIC = 0,
309 PRIVATE = 1,
310 PROTECTED = 2,
311 VCALL = 4,
312 }
313
314 public class RBuiltinType
315 {
316 public readonly Type Type;
317 public readonly string Name;
318 static public RBuiltinType[] Table
319 {
320 get { return tbl; }
321 }
322 private RBuiltinType(Type t, string n)
323 {
324 Type = t;
325 Name = n;
326 }
327 static RBuiltinType[] tbl = new RBuiltinType[] {
328 new RBuiltinType(typeof(RNil), "nil"),
329 new RBuiltinType(typeof(RObject), "Object"),
330 new RBuiltinType(typeof(RClass), "Class"),
331 new RBuiltinType(typeof(RIncClass), "iClass"),
332 new RBuiltinType(typeof(RModule), "Module"),
333 new RBuiltinType(typeof(RFloat), "Float"),
334 new RBuiltinType(typeof(RString), "String"),
335 new RBuiltinType(typeof(RRegexp), "Regexp"),
336 new RBuiltinType(typeof(RArray), "Array"),
337 new RBuiltinType(typeof(RFixnum), "Fixnum"),
338 new RBuiltinType(typeof(RBignum), "Bignum"),
339 new RBuiltinType(typeof(RTrue), "true"),
340 new RBuiltinType(typeof(RFalse), "false"),
341 new RBuiltinType(typeof(Symbol), "Symbol"),
342 new RBuiltinType(typeof(RData), "Data"),
343 new RBuiltinType(typeof(RVarmap), "Varmap"),
344 new RBuiltinType(typeof(Scope), "Scope"),
345 new RBuiltinType(typeof(RNode), "Node"),
346 new RBuiltinType(typeof(QUndef), "undef"),
347 };
348 }
349
350 public class NetRuby : IDisposable
351 {
352 public NetRuby()
353 {
354 compiled = disposed = false;
355 sym_tbl = new st_table();
356 sym_rev_tbl = new st_table();
357 class_tbl = new st_table();
358 global_tbl = new st_table();
359 generic_iv_tbl = null;
360 last_id = Token.LAST_TOKEN;
361 cache = new CacheEntry[CacheEntry.SIZE];
362 threads = new Hashtable();
363 threadMain = new RThread(this);
364 InitEnvironment(threadMain);
365 last_defined_id = last_id;
366 }
367
368 public void Dispose()
369 {
370 Dispose(true);
371 GC.SuppressFinalize(this);
372 }
373
374 bool disposed;
375 ~NetRuby()
376 {
377 Dispose(false);
378 }
379 protected virtual void Dispose(bool disposing)
380 {
381 if (!disposed)
382 {
383 RThread th = GetCurrentContext();
384 th.PushTag(Tag.TAG.PROT_NONE);
385 if (endProcs != null)
386 {
387 while (endProcs.Count > 0)
388 {
389 try
390 {
391 EndProcData ed = (EndProcData)endProcs.Pop();
392 ed.Exec();
393 }
394 catch (Exception ex)
395 {
396 th.errorHandle(ex);
397 }
398 }
399 }
400 if (ephemeralEndProcs != null)
401 {
402 while (ephemeralEndProcs.Count > 0)
403 {
404 try
405 {
406 EndProcData ed = (EndProcData)ephemeralEndProcs.Pop();
407 ed.Exec();
408 }
409 catch (Exception ex)
410 {
411 th.errorHandle(ex);
412 }
413 }
414 }
415 th.PopTag(false);
416 disposed = true;
417 }
418 }
419 internal object[] CallArgs(RNode nd, object self)
420 {
421 RThread th = GetCurrentContext();
422 Block tempBlock = th.block;
423 if ((ITER)th.iter.Peek() == ITER.PRE)
424 {
425 th.block = th.block.prev;
426 }
427 th.iter.Push(ITER.NOT);
428 object[] ret = nd.SetupArgs(this, self, nd.args);
429 th.block = tempBlock;
430 th.iter.Pop();
431 return ret;
432 }
433 internal object[] CallArgs(RNCall nd, object self, out object receiver)
434 {
435 RThread th = GetCurrentContext();
436 Block tempBlock = th.block;
437 if ((ITER)th.iter.Peek() == ITER.PRE)
438 {
439 th.block = th.block.prev;
440 }
441 th.iter.Push(ITER.NOT);
442 object[] ret = nd.SetupArgs(this, self, out receiver);
443 th.block = tempBlock;
444 th.iter.Pop();
445 return ret;
446 }
447 internal object CallIter(RNode nd, object self)
448 {
449 RThread th = GetCurrentContext();
450 Block tempBlock = th.block;
451 if ((ITER)th.iter.Peek() == ITER.PRE)
452 {
453 th.block = th.block.prev;
454 }
455 th.iter.Push(ITER.NOT);
456 object ret = Eval(self, nd.iter);
457 th.block = tempBlock;
458 th.iter.Pop();
459 return ret;
460 }
461 //
462 private void InitEnvironment(RThread th)
463 {
464 Scope.ScopeMode oldvmode = th.PushScope();
465 th.PushTag(Tag.TAG.PROT_NONE);
466 try
467 {
468 missing = intern("method_missing");
469 idEq = intern("==");
470 idEql = intern("eql?");
471
472 cObject = new RClass(this, "Object", null);
473 class_tbl[intern("Object")] = cObject;
474 cModule = new RModule(this, "Module", cObject);
475 cClass = new RClass(this, "Class", cModule);
476 class_tbl[intern("Class")] = cClass;
477 cObject.klass = new RSingletonClass(cClass);
478 cObject.klass.AttachSingleton(cObject);
479 cModule.klass = new RSingletonClass(cObject.klass);
480 cModule.klass.AttachSingleton(cModule);
481 cClass.klass = new RSingletonClass(cModule.klass);
482 cClass.klass.AttachSingleton(cClass);
483 mKernel = new RKernel(this, "Kernel");
484 RMetaObject.IncludeModule(cObject, mKernel);
485 mKernel.Init(this);
486 REnumerable.Init(this);
487 evalInit();
488 RString.Init(this);
489 RException.Init(this);
490 RThreadClass.Init(this);
491 RThreadGroupClass.Init(this);
492 RNumeric.Init(this);
493 RInteger.Init(this);
494 RFixnum.Init(this);
495 RFloat.Init(this);
496 RBignum.Init(this);
497 RArray.Init(this);
498 RHashClass.Init(this);
499 RRegexpClass.Init(this);
500 RIOClass.Init(this);
501 RProcClass.Init(this);
502 RTimeClass.Init(this);
503 loader = Loader.Init(this);
504 RDotNetClass.Init(this);
505
506 versionInit();
507
508 threadMain.Init(this);
509
510 th.rClass = cObject;
511 topCRef = new RNCRef(cObject);
512 th.cRef = topCRef;
513 th.frame.self = topSelf;
514 th.frame.cBase = topCRef;
515
516 progInit();
517 }
518 catch (eTagJump)
519 {
520 errorPrint(th);
521 }
522 catch (Exception e)
523 {
524 errorPrint(th, e);
525 }
526 th.PopTag(true);
527 th.PopScope(oldvmode);
528 }
529
530 private void evalInit()
531 {
532 BindingFlags bf = BindingFlags.InvokeMethod
533 | BindingFlags.Static | BindingFlags.Public
534 | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy
535 | BindingFlags.Instance;
536 missing = intern("method_missing");
537 initialize = intern("initialize");
538
539 DefineVirtualVariable("$@",
540 new GlobalEntry.Getter(errAtGetter),
541 new GlobalEntry.Setter(errAtSetter));
542 DefineVariable("$!", null,
543 new GlobalEntry.Getter(errInfoGetter),
544 new GlobalEntry.Setter(errInfoSetter));
545
546 DefineGlobalFunction("eval", new RBasic.RMethod(ruby_eval), -1);
547 DefineGlobalFunction("iterator?", new RBasic.RMethod(ruby_block_given_p), 0);
548 DefineGlobalFunction("block_given?", new RBasic.RMethod(ruby_block_given_p), 0);
549 DefineGlobalFunction("method_missing", new RBasic.RMethod(RBasic.ruby_missing), -1);
550 DefineGlobalFunction("loop", new RBasic.RMethod(ruby_loop), 0);
551
552 DefineGlobalFunction("raise", new RBasic.RMethod(ruby_raise), -1);
553 DefineGlobalFunction("fail", new RBasic.RMethod(ruby_raise), -1);
554
555 DefineGlobalFunction("caller", new RBasic.RMethod(ruby_caller), -1);
556
557 DefineGlobalFunction("exit", new RBasic.RMethod(ruby_exit), -1);
558 DefineGlobalFunction("abort", new RBasic.RMethod(ruby_abort), -1);
559 DefineGlobalFunction("at_exit", new RBasic.RMethod(ruby_at_exit), 0);
560 /*
561 rb_define_global_function("catch", rb_f_catch, 1);
562 rb_define_global_function("throw", rb_f_throw, -1);
563 rb_define_global_function("global_variables", rb_f_global_variables, 0);
564 rb_define_global_function("local_variables", rb_f_local_variables, 0);
565 */
566 mKernel.evalInit();
567
568 Type obj = cModule.GetType();
569 cModule.DefinePrivateMethod("append_features", obj.GetMethod("AppendFeatures", bf));
570 cModule.DefinePrivateMethod("extend_object", new RBasic.RMethod(RMetaObject.extend_object), 1);
571 cModule.DefinePrivateMethod("include", obj.GetMethod("Include", bf));
572 cModule.DefinePrivateMethod("public", obj.GetMethod("Public", bf));
573 cModule.DefinePrivateMethod("protected", obj.GetMethod("Protected", bf));
574 cModule.DefinePrivateMethod("private", obj.GetMethod("Private", bf));
575 cModule.DefinePrivateMethod("module_function", obj.GetMethod("ModuleFunction", bf));
576 cClass.UndefMethod("module_function");
577
578 cModule.DefinePrivateMethod("remove_method", new RBasic.RMethod(RMetaObject.remove_method), 1);
579 cModule.DefinePrivateMethod("undef_method", new RBasic.RMethod(RMetaObject.undef_method), 1);
580 cModule.DefinePrivateMethod("alias_method", new RBasic.RMethod(RMetaObject.alias_method), 2);
581 cModule.DefinePrivateMethod("define_method", new RBasic.RMethod(RMetaObject.define_method), -1);
582
583 obj = topSelf.GetType();
584 topSelf.DefineSingletonMethod("include", obj.GetMethod("Include", bf));
585 topSelf.DefineSingletonMethod("public", obj.GetMethod("Public", bf));
586 topSelf.DefineSingletonMethod("private", obj.GetMethod("Private", bf));
587
588 mKernel.DefineMethod("extend", new RBasic.RMethod(mKernel.extend), -1);
589
590 DefineVariable("$SAFE", null, new GlobalEntry.Getter(safeGetter), new GlobalEntry.Setter(safeSetter));
591 }
592
593 private void versionInit()
594 {
595 Assembly asm = Assembly.GetAssembly(GetType());
596 FileVersionInfo finfo = FileVersionInfo.GetVersionInfo(
597 asm.Location);
598 RString s = new RString(this, finfo.FileVersion);
599 s.Freeze();
600 DefineGlobalConst("RUBY_VERSION", s);
601 s = new RString(this, "CommonLanguageRuntime");
602 s.Freeze();
603 DefineGlobalConst("RUBY_PLATFORM", s);
604 }
605 private void progInit()
606 {
607 DefineVirtualVariable("$VERBOSE", new GlobalEntry.Getter(verboseGetter), new GlobalEntry.Setter(verboseSetter));
608 DefineVariable("$-v", null, new GlobalEntry.Getter(verboseGetter), new GlobalEntry.Setter(verboseSetter));
609 DefineVariable("$-w", null, new GlobalEntry.Getter(verboseGetter), new GlobalEntry.Setter(verboseSetter));
610 DefineVariable("$DEBUG", null, new GlobalEntry.Getter(debugGetter), new GlobalEntry.Setter(debugSetter));
611 DefineVariable("$-d", null, new GlobalEntry.Getter(debugGetter), new GlobalEntry.Setter(debugSetter));
612 DefineReadonlyVariable("$-p", null, new GlobalEntry.Getter(printGetter));
613 DefineReadonlyVariable("$-l", null, new GlobalEntry.Getter(lineGetter));
614
615 progName = new RString(this, String.Empty, true);
616 #if RUBY_ARG0
617 DefineVariable("$0", progName, null, new GlobalEntry.Setter(SetArg0));
618 #else
619 DefineVariable("$0", progName);
620 #endif
621 argv = new RArray(this, true);
622 DefineReadonlyVariable("$*", argv, new GlobalEntry.Getter(argvGetter));
623 DefineGlobalConst("ARGV", argv);
624 DefineReadonlyVariable("$-a", argv, new GlobalEntry.Getter(splitGetter));
625
626 DefineVirtualVariable("$_", new GlobalEntry.Getter(lastLineGetter),new GlobalEntry.Setter(lastLineSetter));
627 }
628
629 // returns false if prog termination is required.
630 public bool ExecutiveOptions(string[] args)
631 {
632 bool f = false;
633 bool created;
634 RThread th = GetCurrentContext(out created);
635
636 th.PushTag(Tag.TAG.PROT_NONE);
637 try
638 {
639 f = ProcessOptions(th, args, true);
640 }
641 catch (eTagJump)
642 {
643 errorPrint(th);
644 }
645 catch (Exception e)
646 {
647 errorPrint(th, e);
648 }
649 th.PopTag(false);
650 // Keep ThreadContext because EvalTree was not yet evaluated.
651 return f;
652 }
653 public bool Options(string[] args)
654 {
655 bool f = false;
656 bool created;
657 RThread th = GetCurrentContext(out created);
658
659 th.PushTag(Tag.TAG.PROT_NONE);
660 try
661 {
662 f = ProcessOptions(th, args, false);
663 }
664 catch (eTagJump)
665 {
666 errorPrint(th);
667 }
668 catch (Exception e)
669 {
670 errorPrint(th, e);
671 }
672 th.PopTag(false);
673 // Keep ThreadContext because EvalTree was not yet evaluated.
674 return f;
675 }
676
677 internal bool ProcessOptions(RThread th, string[] args, bool compiled)
678 {
679 bool result = SetOptions(args, false, compiled);
680 if (doCheck && th.CompileFailed == false)
681 {
682 System.Console.Out.WriteLine("Syntax OK");
683 result = false;
684 }
685 if (doLoop)
686 {
687 }
688 return result;
689 }
690
691 internal bool SetOptions(string[] args, bool reent, bool compiled)
692 {
693 if (args.Length <= 0) return true;
694 bool vbose = false;
695 bool version = false;
696 bool copyright = false;
697 string e_script = null;
698 int idx = 0;
699 for (; idx < args.Length; idx++)
700 {
701 if (args[idx][0] != '-') break;
702 for (string s = args[idx].Substring(1); s.Length > 0; s = s.Substring(1))
703 {
704 switch (s[0])
705 {
706 case 'a':
707 doSplit = true;
708 break;
709 case 'p':
710 doPrint = true;
711 goto case 'n';
712 case 'n':
713 doLoop = true;
714 break;
715 case 'd':
716 debug = true;
717 verbose = true;
718 break;
719 case 'y':
720 yydebug = true;
721 break;
722 case 'v':
723 if (vbose)
724 break;
725 ShowVersion();
726 vbose = true;
727 goto case 'w';
728 case 'w':
729 verbose = true;
730 break;
731 case 'c':
732 doCheck = true;
733 break;
734 case 's':
735 warn("NETRuby doesn't support -s");
736 // not support sflag
737 break;
738 case 'h':
739 ShowUsage();
740 return false;
741 case 'l':
742 warn("NETRuby doesn't support -l");
743 // doLine = true;
744 break;
745 case 'S':
746 warn("NETRuby doesn't support -S");
747 break;
748 case 'e':
749 if (s.Length == 1)
750 {
751 idx++;
752 if (idx >= args.Length)
753 {
754 s = "";
755 }
756 else
757 {
758 s = args[idx];
759 }
760 }
761 else
762 {
763 s = s.Substring(1);
764 }
765 if (s.Length == 0)
766 {
767 System.Console.Error.WriteLine(args[idx - 1] + ": no code specified for -e");
768 return false;
769 }
770 if (e_script == null)
771 {
772 e_script = s;
773 script = "-e";
774 }
775 else
776 {
777 e_script += s + "\n";
778 }
779 goto next_argv;
780 case 'r':
781 warn("NETRuby doesn't support -r");
782 goto next_argv;
783 case 'i': // inplace mode
784 warn("NETRRuby doesn't support -i");
785 goto next_argv;
786 case 'C':
787 case 'X':
788 warn("NETRuby doesn't support -C -X");
789 break;
790 case 'F':
791 if (s.Length > 1)
792 fSep = s.Substring(1);
793 goto next_argv;
794 case 'K':
795 if (s.Length > 1)
796 {
797 SetKCode(s[1]);
798 s = s.Substring(1);
799 }
800 break;
801 case 'T':
802 {
803 int v = 1;
804 if (s.Length > 1)
805 {
806 v = Convert.ToInt32(s.Substring(1));
807 }
808 SafeLevel = v;
809 goto next_argv;
810 }
811 case 'I':
812 if (s.Length > 1)
813 {
814 loader.IncPush(s.Substring(1));
815 }
816 goto next_argv;
817 case '0':
818 break;
819 case '-':
820 if (s.Length <= 1)
821 {
822 idx++;
823 goto switch_end;
824 }
825 s = s.Substring(1);
826 if (s == "copyright")
827 {
828 copyright = true;
829 }
830 else if (s == "debug")
831 {
832 debug = true;
833 verbose = true;
834 }
835 else if (s == "version")
836 {
837 version = true;
838 }
839 else if (s == "verbose")
840 {
841 vbose = true;
842 verbose = true;
843 }
844 else if (s == "yydebug")
845 {
846 yydebug = true;
847 }
848 else if (s == "help")
849 {
850 ShowUsage();
851 return false;
852 }
853 else
854 {
855 System.Console.Error.WriteLine(args[idx] + ": invalid option -" + s[0] + " (-h will show valid options)\n");
856 return false;
857 }
858 goto next_argv;
859 }
860 }
861 next_argv:
862 ;
863 }
864 switch_end:
865 if (reent) return true;
866 if (version)
867 {
868 ShowVersion();
869 return false;
870 }
871 if (copyright)
872 {
873 ShowCopyright();
874 }
875
876 if (compiled == false)
877 {
878 if (e_script == null && idx >= args.Length)
879 {
880 if (vbose) return false;
881 script = "-";
882 }
883 else
884 {
885 if (e_script == null)
886 {
887 script = args[idx];
888 }
889 if (script.Length <= 0)
890 {
891 script = "-";
892 }
893 if (e_script == null)
894 {
895 idx++;
896 }
897 }
898 }
899 RubyScript(script);
900 SetArgv(args, idx);
901 //processSFlag();
902 //initLoadPath();
903 if (compiled) return true;
904
905 RThread th = GetCurrentContext();
906 th.file = AppDomain.CurrentDomain.FriendlyName;
907 th.evalTree = null;
908 if (e_script != null)
909 {
910 th.evalTree = CompileFile("-e", new StringReader(e_script), 1, th);
911 }
912 else
913 {
914 LoadFile(script, true);
915 }
916 //processSFlag();
917 return true;
918 }
919
920 private void ShowVersion()
921 {
922 Assembly asm = Assembly.GetAssembly(GetType());
923 FileVersionInfo finfo = FileVersionInfo.GetVersionInfo(
924 asm.Location);
925 string version = finfo.FileVersion;
926 string date = String.Empty;
927 string platform = String.Empty;
928 System.Console.Out.WriteLine("NETRuby {0} ({1}) [{2}]",
929 version, date, platform);
930 }
931 private void ShowCopyright()
932 {
933 System.Console.Out.WriteLine("ruby - Copyright (C) 1993-2002 Yukihiro Matsumoto");
934 System.Console.Out.WriteLine("NETRuby - Copyright (C) 2002 arton");
935 }
936 private void ShowUsage()
937 {
938 }
939 public void SetKCode(char c)
940 {
941 }
942 public void RubyScript(string name)
943 {
944 if (name != null)
945 {
946 progName.SetData(name);
947 SourceFile = name;
948 }
949 }
950 public RException ErrorInfo
951 {
952 get { return GetCurrentContext().errInfo; }
953 }
954 internal void SetArgv(string[] args, int start)
955 {
956 argv.Clear();
957 for (int i = start; i < args.Length; i++)
958 {
959 argv.Add(args[i]);
960 }
961 }
962 public bool Require(string path)
963 {
964 return loader.Require(path);
965 }
966 public void Load(object fobj, bool wrap)
967 {
968 RThread th = GetCurrentContext();
969 RMetaObject cls = th.rClass;
970 RObjectBase self = topSelf;
971
972 if (wrap && th.safeLevel >= 4)
973 {
974 CheckType(fobj, typeof(RString));
975 }
976 else
977 {
978 CheckSafeString(th, fobj);
979 }
980 string fname = loader.FindFile(fobj.ToString());
981 if (fname == null)
982 throw new eLoadError("No such file to load -- " + fobj.ToString());
983 th.errInfo = null;
984 RVarmap old = th.dyna_vars;
985 th.dyna_vars = null;
986 RModule old_wrapper = th.wrapper;
987 RNCRef saved_cRef = th.cRef;
988 th.cRef = topCRef;
989 if (wrap == false)
990 {
991 th.Secure(4);
992 th.rClass = cObject;
993 th.wrapper = null;
994 }
995 else
996 {
997 th.wrapper = new RModule(this);
998 th.rClass = th.wrapper;
999 self = (RObjectBase)topSelf.Clone();
1000 RMetaObject.ExtendObject(self, th.rClass);
1001 th.cRef = new RNCRef(th.wrapper, th.cRef);
1002 }
1003 Frame frm = th.PushFrame(false);
1004 frm.lastFunc = 0;
1005 frm.lastClass = null;
1006 frm.self = self;
1007 frm.cBase = new RNCRef(th.rClass);
1008 Scope.ScopeMode vm = th.PushScope();
1009 th.ScopeSet(Scope.ScopeMode.Private);
1010 th.PushTag(Tag.TAG.PROT_NONE);
1011 Tag.TAG state = Tag.TAG.EMPTY;
1012 try
1013 {
1014 th.EnterEval();
1015 LoadFile(fname);
1016 th.LeaveEval();
1017 RNode node = th.evalTree;
1018 if (th.CompileFailed == false)
1019 {
1020 EvalNode(self, node, th);
1021 }
1022 }
1023 catch (eTagJump e)
1024 {
1025 #if EXCEP_TRACE
1026 Console.WriteLine(e.StackTrace);
1027 #endif
1028 state = e.state;
1029 }
1030 catch (Exception ex)
1031 {
1032 #if EXCEP_TRACE
1033 Console.WriteLine(ex.StackTrace);
1034 #endif
1035 th.errInfo = new RException(this, ex);
1036 state = Tag.TAG.RAISE;
1037 }
1038 th.PopTag(true);
1039 th.cRef = saved_cRef;
1040 th.PopScope(vm);
1041 th.PopFrame();
1042 th.rClass = cls;
1043 th.dyna_vars = old;
1044 th.wrapper = old_wrapper;
1045 if (th.CompileFailed)
1046 {
1047 th.ClearCompileError();
1048 throw new eTagJump(th.errInfo);
1049 }
1050 if (state != Tag.TAG.EMPTY)
1051 {
1052 JumpTagButLocalJump(state & Tag.TAG.MASK);
1053 }
1054 if (th.errInfo != null)
1055 {
1056 throw new eTagJump(th.errInfo);
1057 }
1058 }
1059 public void LoadFile(string fname)
1060 {
1061 LoadFile(fname, false);
1062 }
1063 private void LoadFile(string fname, bool script)
1064 {
1065 TextReader tr;
1066 int line_start = 1;
1067 if (fname == "-")
1068 {
1069 tr = System.Console.In;
1070 }
1071 else
1072 {
1073 try
1074 {
1075 tr = new StreamReader(fname, Encoding.Default);
1076 }
1077 catch (FileNotFoundException)
1078 {
1079 tr = null;
1080 ruby_raise(null, eLoadError, "No such file to load -- " + fname);
1081 }
1082 catch (Exception e)
1083 {
1084 Exception en = new eTagJump(Tag.TAG.RAISE, e, e.Message + " -- " + fname);
1085 throw en;
1086 }
1087 }
1088 if (script)
1089 {
1090 int c = tr.Peek();
1091 if (c == '#')
1092 {
1093 string ln = tr.ReadLine();
1094 line_start++;
1095 if (ln != null && ln.Length > 2 && ln[1] == '!')
1096 {
1097 int r = ln.IndexOf("ruby");
1098 if (r < 0)
1099 {
1100 // execute non ruby program
1101 Process.GetCurrentProcess().Kill();
1102 }
1103
1104 ln = ln.Substring(r + 4);
1105 if ((r = ln.IndexOf(" -")) >= 0)
1106 {
1107 ln = ln.Substring(1);
1108 string[] argst = ln.Split(null);
1109 int n = 0;
1110 foreach (string x in argst)
1111 {
1112 if (x.Length > 1) n++;
1113 }
1114 string[] args = new string[n];
1115 n = 0;
1116 foreach (string x in argst)
1117 {
1118 if (x.Length > 1)
1119 {
1120 args[n++] = x;
1121 }
1122 }
1123 SetOptions(args, true, false);
1124 }
1125 }
1126 }
1127 }
1128 bool thCreated;
1129 RThread th = GetCurrentContext(out thCreated);
1130 th.evalTree = CompileFile(fname, tr, line_start, th);
1131 if (script && __end__seen)
1132 {
1133 DefineGlobalConst("DATA", tr);
1134 }
1135 else if (fname != "-")
1136 {
1137 tr.Close();
1138 }
1139 }
1140 private string MoreSwitches(string p)
1141 {
1142 string result = null;
1143 for (int i = 0; i < p.Length; i++)
1144 {
1145 if (Char.IsWhiteSpace(p[i]))
1146 {
1147 p = p.Substring(0, i);
1148 result = p.Substring(i);
1149 }
1150 }
1151 SetOptions(new string[] {p}, true, false);
1152 return (result == null) ? "" : result.TrimStart(null);
1153 }
1154 public RNode CompileFile(string fname, TextReader tr, int start, RThread th)
1155 {
1156 th.ClearCompileError();
1157 Parser parser = new Parser(this, th, th.IsInEval);
1158 try
1159 {
1160 yyParser.Scanner scanner =
1161 new yyParser.Scanner(parser, tr, fname, start, this, th);
1162 RNode node = (RNode)parser.Parse(scanner);
1163 if (doPrint)
1164 {
1165 node = ParserAppendPrint(th, node);
1166 }
1167 return node;
1168 }
1169 catch (IOException oe)
1170 {
1171 Console.Error.WriteLine(oe.Message);
1172 }
1173 return null;
1174 }
1175 private RNode ParserAppendPrint(RThread th, RNode node)
1176 {
1177 uint id = intern("$_");
1178 node = RNode.block_append(th,
1179 node,
1180 new RNFCall(null, intern("print"),
1181 new RNArray(null, new RNGVar(id, global_entry(id)))));
1182 return node;
1183
1184 }
1185 public void Run()
1186 {
1187 bool thCreated;
1188 RThread th = GetCurrentContext(out thCreated);
1189 if (th.CompileFailed) return;
1190
1191 Tag.TAG state = Tag.TAG.EMPTY;
1192 th.PushIter(ITER.NOT);
1193 th.PushTag(Tag.TAG.PROT_NONE);
1194 try
1195 {
1196 EvalNode(topSelf, th.evalTree, th);
1197 }
1198 catch (eTagJump tj)
1199 {
1200 #if _DEBUG
1201 System.Console.WriteLine(tj.StackTrace);
1202 #endif
1203 state = tj.state;
1204 if (th.CurrentTag.tag != Tag.TAG.EMPTY)
1205 errorPrint(th);
1206 }
1207 catch (Exception ex)
1208 {
1209 #if _DEBUG
1210 System.Console.WriteLine(ex.StackTrace);
1211 #endif
1212 state = Tag.TAG.RAISE;
1213 if (th.CurrentTag.tag != Tag.TAG.EMPTY)
1214 errorPrint(th, ex);
1215 }
1216 th.PopIter();
1217 th.PopTag(false);
1218
1219 if (thCreated) ClearContext(th);
1220 }
1221 public void RunWithMain(RMainObject main)
1222 {
1223 bool thCreated;
1224 compiled = true;
1225 RThread th = GetCurrentContext(out thCreated);
1226 if (th.CompileFailed) return;
1227
1228 Tag.TAG state = Tag.TAG.EMPTY;
1229 th.PushIter(ITER.NOT);
1230 th.PushTag(Tag.TAG.PROT_NONE);
1231 try
1232 {
1233 topSelf = main;
1234 main.Run();
1235 }
1236 catch (eTagJump tj)
1237 {
1238 #if _DEBUG
1239 System.Console.WriteLine(tj.StackTrace);
1240 #endif
1241 state = tj.state;
1242 if (th.CurrentTag.tag != Tag.TAG.EMPTY)
1243 errorPrint(th);
1244 }
1245 catch (Exception ex)
1246 {
1247 #if _DEBUG
1248 System.Console.WriteLine(ex.StackTrace);
1249 #endif
1250 state = Tag.TAG.RAISE;
1251 if (th.CurrentTag.tag != Tag.TAG.EMPTY)
1252 errorPrint(th, ex);
1253 }
1254 th.PopIter();
1255 th.PopTag(false);
1256
1257 if (thCreated) ClearContext(th);
1258 }
1259
1260 private void compile(RThread th, bool save)
1261 {
1262 if (dynAssembly == null)
1263 {
1264 dynName = new AssemblyName();
1265 int ix = progName.ToString().LastIndexOf('.');
1266 if (ix > 0)
1267 dynName.Name = progName.ToString().Substring(0, ix) + ".exe";
1268 else
1269 dynName.Name = progName + ".exe";
1270 dynAssembly = Thread.GetDomain().DefineDynamicAssembly(dynName,
1271 AssemblyBuilderAccess.RunAndSave);
1272 dynModule = dynAssembly.DefineDynamicModule(dynName.Name, dynName.Name, true);
1273 }
1274 string cname = "RubyMainClass";
1275 lock (this)
1276 {
1277 cname += dynModName.ToString();
1278 dynModName++;
1279 }
1280 TypeBuilder newMain = dynModule.DefineType(cname, TypeAttributes.Public,
1281 mainType);
1282 ConstructorBuilder cb = newMain.DefineConstructor(
1283 MethodAttributes.Assembly,
1284 CallingConventions.Standard,
1285 new Type[] {typeof(RObject)});
1286 ILGenerator cilg = cb.GetILGenerator();
1287 cilg.Emit(OpCodes.Ldarg_0);
1288 cilg.Emit(OpCodes.Ldarg_1);
1289 ConstructorInfo supctr = typeof(RMainObject).GetConstructor(
1290 BindingFlags.Instance | BindingFlags.Public, null,
1291 new Type[] {typeof(RObject)}, null);
1292 cilg.Emit(OpCodes.Call, supctr);
1293 cilg.Emit(OpCodes.Ret);
1294 MethodBuilder main = newMain.DefineMethod("Run",
1295 MethodAttributes.Public |
1296 MethodAttributes.Virtual,
1297 typeof(object), null);
1298 ArrayList methodList = null;
1299 using (ILParam pm = new TopLevelILParam(newMain, main))
1300 {
1301 pm.InitLocalTable(this, th.scope.local_tbl);
1302 CompileNode(pm, th.evalTree, true, th);
1303 methodList = pm.MethodList;
1304 }
1305
1306 MethodBuilder mtb = newMain.DefineMethod("Main",
1307 MethodAttributes.Public |
1308 MethodAttributes.Static,
1309 typeof(void), new Type[] {typeof(string[])});
1310 ILGenerator il = mtb.GetILGenerator();
1311 il.BeginScope();
1312 LocalBuilder r = il.DeclareLocal(typeof(NetRuby));
1313 r.SetLocalSymInfo("ruby");
1314 il.Emit(OpCodes.Newobj, typeof(NetRuby).GetConstructor(Type.EmptyTypes));
1315 il.Emit(OpCodes.Dup);
1316 il.Emit(OpCodes.Stloc, r);
1317 il.Emit(OpCodes.Ldarg_0);
1318 il.Emit(OpCodes.Call, typeof(NetRuby).GetMethod("ExecutiveOptions"));
1319 Label elab = il.DefineLabel();
1320 il.Emit(OpCodes.Brfalse, elab);
1321 il.Emit(OpCodes.Ldloc, r);
1322 foreach (DictionaryEntry de in sym_tbl)
1323 {
1324 uint id = (uint)de.Value;
1325 if ((id >> (int)Parser.ID.SCOPE_SHIFT) <= last_defined_id) continue;
1326 il.Emit(OpCodes.Dup);
1327 il.Emit(OpCodes.Ldc_I4, id);
1328 il.Emit(OpCodes.Ldstr, (string)de.Key);
1329 il.Emit(OpCodes.Call, typeof(NetRuby).GetMethod("_intern"));
1330 }
1331 if (methodList != null)
1332 {
1333 foreach (Type typ in methodList)
1334 {
1335 il.Emit(OpCodes.Dup);
1336 il.Emit(OpCodes.Ldfld, typeof(NetRuby).GetField("cObject"));
1337 il.Emit(OpCodes.Call, typ.GetMethod("Init", BindingFlags.Static | BindingFlags.Public));
1338 }
1339 }
1340 il.Emit(OpCodes.Dup);
1341 il.Emit(OpCodes.Ldfld, typeof(NetRuby).GetField("topSelf"));
1342 il.Emit(OpCodes.Newobj, cb);
1343 il.Emit(OpCodes.Call, typeof(NetRuby).GetMethod("RunWithMain"));
1344 il.MarkLabel(elab);
1345 il.Emit(OpCodes.Ldloc, r);
1346 il.Emit(OpCodes.Ldc_I4_0);
1347 il.Emit(OpCodes.Call, typeof(NetRuby).GetMethod("Exit"));
1348 il.EndScope();
1349 il.Emit(OpCodes.Ret);
1350
1351 Type tp = newMain.CreateType();
1352 mainType = tp;
1353
1354 dynModule.SetUserEntryPoint(mtb);
1355 dynAssembly.SetEntryPoint(mtb);
1356 if (save)
1357 {
1358 dynAssembly.Save(dynName.Name);
1359 }
1360 }
1361 public void Compile()
1362 {
1363 bool thCreated;
1364 RThread th = GetCurrentContext(out thCreated);
1365 if (th.CompileFailed) return;
1366
1367 Tag.TAG state = Tag.TAG.EMPTY;
1368 th.PushIter(ITER.NOT);
1369 th.PushTag(Tag.TAG.PROT_NONE);
1370 try
1371 {
1372 compile(th, true);
1373 }
1374 catch (eTagJump tj)
1375 {
1376 #if _DEBUG
1377 System.Console.WriteLine(tj.StackTrace);
1378 #endif
1379 state = tj.state;
1380 if (th.CurrentTag.tag != Tag.TAG.EMPTY)
1381 errorPrint(th);
1382 }
1383 catch (Exception ex)
1384 {
1385 #if _DEBUG
1386 System.Console.WriteLine(ex.StackTrace);
1387 #endif
1388 state = Tag.TAG.RAISE;
1389 if (th.CurrentTag.tag != Tag.TAG.EMPTY)
1390 errorPrint(th, ex);
1391 }
1392 th.PopIter();
1393 th.PopTag(false);
1394
1395 if (thCreated) ClearContext(th);
1396 }
1397 public void RunWithCompile()
1398 {
1399 bool thCreated;
1400 RThread th = GetCurrentContext(out thCreated);
1401 if (th.CompileFailed) return;
1402
1403 Tag.TAG state = Tag.TAG.EMPTY;
1404 th.PushIter(ITER.NOT);
1405 th.PushTag(Tag.TAG.PROT_NONE);
1406 try
1407 {
1408 compile(th, false);
1409 topSelf = (RObject)Activator.CreateInstance(mainType,
1410 BindingFlags.NonPublic | BindingFlags.Instance,
1411 null, new object[] { topSelf }, null);
1412 topSelf.Run();
1413 // save if completely ran
1414 dynAssembly.Save(dynName.Name);
1415 }
1416 catch (eTagJump tj)
1417 {
1418 #if _DEBUG
1419 System.Console.WriteLine(tj.StackTrace);
1420 #endif
1421 state = tj.state;
1422 if (th.CurrentTag.tag != Tag.TAG.EMPTY)
1423 errorPrint(th);
1424 }
1425 catch (Exception ex)
1426 {
1427 #if _DEBUG
1428 System.Console.WriteLine(ex.StackTrace);
1429 #endif
1430 state = Tag.TAG.RAISE;
1431 if (th.CurrentTag.tag != Tag.TAG.EMPTY)
1432 errorPrint(th, ex);
1433 }
1434 th.PopIter();
1435 th.PopTag(false);
1436
1437 if (thCreated) ClearContext(th);
1438 }
1439
1440 internal void errorPrint(RThread th)
1441 {
1442 if (th.errInfo == null) return;
1443 th.PushTag(Tag.TAG.PROT_NONE);
1444 RArray errat;
1445 try
1446 {
1447 errat = th.errInfo.Backtrace;
1448 }
1449 catch
1450 {
1451 errat = null;
1452 }
1453 th.PopTag(false);
1454
1455 if (errat == null)
1456 {
1457 if (th.file != null)
1458 System.Console.Error.Write(String.Format("{0}:{1}",
1459 th.file, th.line));
1460 else
1461 System.Console.Error.Write(String.Format("{0}", th.line));
1462 }
1463 else if (errat.Count == 0)
1464 {
1465 th.errorPos();
1466 }
1467 else
1468 {
1469 if (errat[0] == null)
1470 th.errorPos();
1471 else
1472 System.Console.Error.Write(errat[0].ToString());
1473 }
1474 string einfo = String.Empty;
1475 RMetaObject eClass = ClassOf(th.errInfo);
1476 th.PushTag(Tag.TAG.PROT_NONE);
1477 try
1478 {
1479 einfo = RString.AsString(this, th.errInfo);
1480 }
1481 catch
1482 {
1483 }
1484 Tag tag2 = th.PopTag(true);
1485 if (eClass == eRuntimeError && einfo.Length == 0)
1486 {
1487 System.Console.Error.WriteLine(": unhandled exception");
1488 }
1489 else
1490 {
1491 string epath = eClass.ClassPath;
1492 if (einfo.Length == 0)
1493 {
1494 System.Console.Error.WriteLine(": " + epath);
1495 }
1496 else
1497 {
1498 if (epath[0] == '#') epath = null;
1499 System.Console.Error.Write(": " + einfo);
1500 if (epath != null)
1501 {
1502 System.Console.Error.WriteLine(" (" + epath + ")");
1503 }
1504 }
1505 }
1506 printBacktrace(errat);
1507 }
1508 internal void errorPrint(RThread th, Exception errinfo)
1509 {
1510 if (errinfo is eTagJump)
1511 {
1512 errorPrint(th);
1513 return;
1514 }
1515 th.errorPos();
1516
1517 string tp = errinfo.GetType().ToString();
1518 int n = tp.LastIndexOf('.');
1519 if (n >= 0) tp = tp.Substring(n + 1);
1520 if (tp[0] == 'e') tp = tp.Substring(1);
1521 System.Console.Error.WriteLine(String.Format(": {0}: ({1})",
1522 errinfo.Message, tp));
1523 RArray ra = Backtrace(-1);
1524 printBacktrace(ra);
1525 #if EXCEP_TRACE
1526 warning(errinfo.StackTrace);
1527 #endif
1528 }
1529 void printBacktrace(RArray errat)
1530 {
1531 if (errat != null)
1532 {
1533 for (int i = 1; i < errat.Count; i++)
1534 {
1535 if (errat[i] is string || errat[i] is RString)
1536 {
1537 System.Console.Error.WriteLine(String.Format("\tfrom {0}", errat[i]));
1538 }
1539 if (i == 8 && errat.Count > 18)
1540 {
1541 System.Console.Error.WriteLine(String.Format("\t ... {0} levels...",
1542 errat.Count - 8 - 5));
1543 i = errat.Count - 5;
1544 }
1545 }
1546 }
1547 }
1548
1549 internal Frame topFrame;
1550 public RObject topSelf;
1551 private int exitStatus = 0;
1552 public RObjectBase TraceFunc;
1553 internal AssemblyBuilder dynAssembly = null;
1554 internal AssemblyName dynName = null;
1555 internal ModuleBuilder dynModule = null;
1556 private int dynModName = 0;
1557 private Type mainType = typeof(RMainObject);
1558 internal Loader loader;
1559 public RClass cObject;
1560 public RModule cModule;
1561 public RKernel mKernel;
1562 public REnumerable mEnumerable;
1563 public RClass cClass;
1564 public RClass cNilClass;
1565 public RClass cFalseClass;
1566 public RClass cTrueClass;
1567 public RClass cData;
1568 public RClass cSymbol;
1569 public RProcClass cProc;
1570 public RThreadClass cThread;
1571 public RThreadGroupClass cThreadGroup;
1572 public RTimeClass cTime;
1573 public RDotNetClass cDotNet;
1574 //
1575 public RClass cString;
1576 public RClass cArray;
1577 //
1578 public RClass cNumeric;
1579 public RClass cInteger;
1580 public RClass cFixnum;
1581 public RClass cBignum;
1582 public RClass cFloat;
1583 public RHashClass cHash;
1584 public RIOClass cIO;
1585 public RRegexpClass cRegexp;
1586 public RClass cMatch;
1587 //
1588 public RClass eException;
1589 public RClass eSystemExit;
1590 public RClass eFatal;
1591 public RClass eInterrupt;
1592 public RClass eSignal;
1593 public RClass eStandardError;
1594 public RClass eTypeError;
1595 public RClass eArgError;
1596 public RClass eIndexError;
1597 public RClass eRangeError;
1598 public RClass eScriptError;
1599 public RClass eSyntaxError;
1600 public RClass eNameError;
1601 public RClass eLoadError;
1602 public RClass eNotImpError;
1603 public RClass eRuntimeError;
1604 public RClass eSecurityError;
1605 public RClass eNoMemError;
1606 public RClass eThreadError;
1607 public RClass eRegexpError;
1608 //
1609 private uint last_id;
1610 private uint last_defined_id;
1611 internal uint idEq;
1612 internal uint idEql;
1613 private uint missing;
1614 private uint initialize;
1615 private uint inspect_key = 0;
1616 //
1617 internal RNil oNil;
1618 internal RTrue oTrue;
1619 internal RFalse oFalse;
1620 internal RFixnum oFixZero;
1621 internal RFixnum oFixnum;
1622 internal RFloat oFloat;
1623 internal RString oString;
1624 internal Symbol oSymbol;
1625 //
1626 internal RNCRef topCRef;
1627 //
1628 internal bool verbose = true;
1629 internal bool debug = true;
1630 internal bool yydebug = false;
1631 internal bool doLoop = false;
1632 internal bool doPrint = false;
1633 internal bool doLine = false;
1634 internal bool doSplit = false;
1635 internal bool doCheck = false;
1636 public bool __end__seen = false;
1637 internal bool compiled;
1638 internal string fSep = null;
1639 internal string outputFS = null;
1640 internal string recSep = "\n";
1641 internal string defaultRecSep = "\n";
1642 public string SourceFile
1643 {
1644 get { return GetCurrentContext().file; }
1645 set { GetCurrentContext().file = value; }
1646 }
1647 public int SourceLine
1648 {
1649 get { return GetCurrentContext().line; }
1650 set { GetCurrentContext().line = value; }
1651 }
1652 internal RString progName = null;
1653 internal RArray argv;
1654 private string script = null;
1655 internal Hashtable threads;
1656 internal RThread threadMain;
1657
1658 internal bool IsBlockGiven
1659 {
1660 get { return (GetCurrentContext().frame.iter != 0); }
1661 }
1662 internal RProc Lambda()
1663 {
1664 return new RProc(this);
1665 }
1666
1667 struct evalParam
1668 {
1669 internal evalParam(RBasic o, string s, string f, int l)
1670 {
1671 self = o;
1672 src = s;
1673 file = f;
1674 line = l;
1675 }
1676 public RBasic self;
1677 public string src;
1678 public string file;
1679 public int line;
1680 }
1681 delegate object ExecMethod(RThread th, object arg);
1682 private object EvalI(RThread th, object o)
1683 {
1684 evalParam param = (evalParam)o;
1685 return Eval(param.self, param.src, null, param.file, param.line);
1686 }
1687 private object Eval(RThread th, RMetaObject under, RBasic self, object src, string file, int line)
1688 {
1689 if (src is string == false)
1690 {
1691 if (th.safeLevel >= 4)
1692 {
1693 CheckType(src, typeof(RString));
1694 }
1695 else
1696 {
1697 CheckSafeString(th, src);
1698 }
1699 }
1700 evalParam param = new evalParam(self, src.ToString(), file, line);
1701 return ExecUnder(th, under, new ExecMethod(EvalI), param);
1702 }
1703 private object YieldI(RThread th, object o)
1704 {
1705 RBasic self = (RBasic)o;
1706 th.block.frame.cBase = th.frame.cBase;
1707 return Yield(self, self, th.rClass, false);
1708 }
1709 private object Yield(RThread th, RMetaObject under, RBasic self)
1710 {
1711 return ExecUnder(th, under, new ExecMethod(YieldI), self);
1712 }
1713 object ExecUnder(RThread th, RMetaObject under, ExecMethod func, object arg)
1714 {
1715 object val = null;
1716 RMetaObject cls = th.PushClass(under);
1717 th.PushFrame(false);
1718 th.CopyPrevFrame();
1719 RNode cbase = th.frame.cBase;
1720 if (cbase.clss != under)
1721 {
1722 th.frame.cBase = new RNCRef(under, cbase);
1723 }
1724 RNCRef old_cRef = th.cRef;
1725 Scope.ScopeMode vm = th.PushScope();
1726 th.PushTag(Tag.TAG.PROT_NONE);
1727
1728 Tag.TAG state = Tag.TAG.EMPTY;
1729 try
1730 {
1731 val = func(th, arg);
1732 }
1733 catch (eTagJump ex)
1734 {
1735 state = ex.state;
1736 }
1737 catch (Exception ex)
1738 {
1739 state = Tag.TAG.RAISE;
1740 th.errInfo = new RException(this, ex);
1741 }
1742 th.PopTag(true);
1743 th.cRef = old_cRef;
1744 th.PopScope(vm);
1745 th.PopFrame();
1746 th.PopClass(cls);
1747 if (state != Tag.TAG.EMPTY)
1748 th.TagJump(state);
1749 return val;
1750 }
1751
1752 internal object Yield(object o)
1753 {
1754 return Yield(o, null, null, false);
1755 }
1756 internal object Yield(object val, object self, object klass, bool acheck)
1757 {
1758 RThread th = GetCurrentContext();
1759
1760 string file = th.file;
1761 int line = th.line;
1762 Tag.TAG state = Tag.TAG.EMPTY;
1763 object result = null;
1764 if (th.IsBlockGiven == false)
1765 {
1766 throw new eLocalJumpError("no block given");
1767 }
1768 RVarmap old = th.dyna_vars;
1769 th.dyna_vars = null;
1770 RMetaObject cls = th.rClass;
1771 Frame _frame = (Frame)th.block.frame.Clone();
1772 _frame.prev = th.frame;
1773 th.frame = _frame;
1774 RNCRef old_cRef = th.cRef;
1775 th.cRef = _frame.cBase;
1776 RModule old_wrapper = th.wrapper;
1777 Block blk = th.block;
1778 th.wrapper = blk.wrapper;
1779 Scope old_scope = th.scope;
1780 th.scope = blk.scope;
1781 th.block = blk.prev;
1782 if (blk.DScope)
1783 {
1784 /* put place holder for dynamic (in-block) local variables */
1785 th.dyna_vars = th.new_dvar(0, null, blk.dyna_vars);
1786 }
1787 else
1788 {
1789 /* FOR does not introduce new scope */
1790 th.dyna_vars = blk.dyna_vars;
1791 }
1792 th.rClass = (klass == null) ? blk.klass : (RMetaObject)klass;
1793 if (klass == null) self = blk.self;
1794 RNode node = blk.body;
1795
1796 if (blk.var != null)
1797 {
1798 th.PushTag(Tag.TAG.PROT_NONE);
1799 state = Tag.TAG.EMPTY;
1800 try
1801 {
1802
1803 if (blk.var is RNBlockNoArg) // original = (NODE*)1
1804 {
1805 if (acheck && (val is QUndef == false) &&
1806 val is RArray && ((RArray)val).Count != 0)
1807 {
1808 throw new ArgumentException("wrong # of arguments ("
1809 + ((RArray)val).Count.ToString()
1810 + " for 0)");
1811 }
1812 }
1813 else
1814 {
1815 if (blk.var is RNMAsgn == false)
1816 {
1817 /* argument adjust for proc_call etc. */
1818 if (acheck && (val is QUndef == false))
1819 {
1820 if (val is RArray && ((RArray)val).Count == 1)
1821 {
1822 val = ((RArray)val)[0];
1823 }
1824 else if (val is object[] && ((object[])val).Length == 1)
1825 {
1826 val = ((object[])val)[0];
1827 }
1828 }
1829 }
1830 Assign(self, blk.var, val, acheck);
1831 }
1832 }
1833 catch (eTagJump e)
1834 {
1835 state = e.state;
1836 }
1837 catch (Exception e)
1838 {
1839 state = Tag.TAG.RAISE;
1840 th.errInfo = new RException(this, e);
1841 }
1842 th.PopTag(true);
1843 if (state != Tag.TAG.EMPTY) goto pop_state;
1844 }
1845 else
1846 {
1847 /* argument adjust for proc_call etc. */
1848 if (acheck && (val is QUndef == false))
1849 {
1850 if (val is RArray && ((RArray)val).Count == 1)
1851 {
1852 val = ((RArray)val)[0];
1853 }
1854 else if (val is object[] && ((object[])val).Length == 1)
1855 {
1856 val = ((object[])val)[0];
1857 }
1858 }
1859 }
1860
1861 th.PushIter(blk.iter);
1862 th.PushTag(Tag.TAG.PROT_NONE);
1863 redo:
1864 try
1865 {
1866 if (node == null)
1867 {
1868 result = null;
1869 }
1870 else if (node is RNCFunc)
1871 {
1872 result = ((RNCFunc)node).Funcall(ClassOf(self), self, 0, new object[]{self, val});
1873 }
1874 else if (node is RNIFunc)
1875 {
1876 result = ((RNIFunc)node).Call(val, self);
1877 }
1878 else
1879 {
1880 result = Eval(self, node);
1881 }
1882 }
1883 catch (eTagJump e)
1884 {
1885 state = e.state;
1886 }
1887 catch (Exception ex)
1888 {
1889 state = Tag.TAG.RAISE;
1890 th.errInfo = new RException(this, ex);
1891 }
1892 switch (state)
1893 {
1894 case Tag.TAG.REDO:
1895 state = Tag.TAG.EMPTY;
1896 goto redo;
1897 case Tag.TAG.NEXT:
1898 state = Tag.TAG.EMPTY;
1899 result = null;
1900 break;
1901 case Tag.TAG.BREAK:
1902 case Tag.TAG.RETURN:
1903 // state |= (serial++ << 8);
1904 // state |= 0x10;
1905 blk.DStatus = state;
1906 break;
1907 default:
1908 break;
1909 }
1910
1911 th.PopTag(true);
1912 pop_state:
1913 th.PopIter();
1914 th.rClass = cls;
1915 th.dyna_vars = old;
1916 th.block = blk;
1917 th.frame = th.frame.prev;
1918 th.cRef = old_cRef;
1919 th.wrapper = old_wrapper;
1920 th.file = file;
1921 th.line = line;
1922
1923 if (th.scope.DontRecycle)
1924 {
1925 old_scope.Dup();
1926 }
1927 th.scope = old_scope;
1928 if (state != Tag.TAG.EMPTY)
1929 {
1930 if (blk.IsTag == false)
1931 {
1932 switch (state & Tag.TAG.MASK)
1933 {
1934 case Tag.TAG.BREAK:
1935 case Tag.TAG.RETURN:
1936 JumpTagButLocalJump(state & Tag.TAG.MASK);
1937 break;
1938 }
1939 }
1940 th.TagJump(state);
1941 }
1942 return result;
1943 }
1944
1945 internal void JumpTagButLocalJump(Tag.TAG state)
1946 {
1947 switch (state) {
1948 case Tag.TAG.EMPTY:
1949 break;
1950 case Tag.TAG.RETURN:
1951 throw new eLocalJumpError("unexpected return");
1952 case Tag.TAG.NEXT:
1953 throw new eLocalJumpError("unexpected next");
1954 case Tag.TAG.BREAK:
1955 throw new eLocalJumpError("unexpected break");
1956 case Tag.TAG.REDO:
1957 throw new eLocalJumpError("unexpected redo");
1958 case Tag.TAG.RETRY:
1959 throw new eLocalJumpError("retry outside of rescue clause");
1960 default:
1961 // JUMP_TAG(state);
1962 break;
1963 }
1964 }
1965 internal int ScanArgs(object[] argv, string fmt, object[] args)
1966 {
1967 int i = 0;
1968 int dst = 0;
1969 int idx = 0;
1970 if (fmt[idx] == '*') goto rest_arg;
1971 if (Char.IsDigit(fmt[idx]))
1972 {
1973 int n = (int)Char.GetNumericValue(fmt[idx]);
1974 if (n > argv.Length)
1975 throw new ArgumentException(
1976 String.Format("wrong # of arguments ({0} for {1})", argv.Length, n));
1977 for (i = 0; i < n; i++)
1978 {
1979 args[dst++] = argv[i];
1980 }
1981 idx++;
1982 }
1983 if (idx < fmt.Length && Char.IsDigit(fmt[idx]))
1984 {
1985 int n = i + (int)Char.GetNumericValue(fmt[idx]);
1986 for (; i < n; i++)
1987 {
1988 args[dst++] = (argv.Length > i) ? argv[i] : null;
1989 }
1990 idx++;
1991 }
1992 rest_arg:
1993 int rs = i;
1994 if (idx < fmt.Length && fmt[idx] == '*')
1995 {
1996 object[] rest = new object[argv.Length - i];
1997 args[dst] = rest;
1998 for (; i < argv.Length; i++)
1999 {
2000 rest[i - rs] = argv[i];
2001 }
2002 dst++;
2003 idx++;
2004 }
2005 if (idx < fmt.Length && fmt[idx] == '&')
2006 {
2007 if (IsBlockGiven)
2008 {
2009 args[dst] = Lambda();
2010 }
2011 else
2012 {
2013 args[dst] = null;
2014 }
2015 }
2016 if (argv.Length > i)
2017 {
2018 throw new ArgumentException(
2019 String.Format("wrong # of arguments({0} for {1})", argv.Length, i));
2020 }
2021 return argv.Length;
2022
2023
2024 }
2025 public void Secure(int level)
2026 {
2027 RThread th = GetCurrentContext();
2028 th.Secure(level);
2029 }
2030 public int SafeLevel
2031 {
2032 get {
2033 RThread th = GetCurrentContext();
2034 return (th == null) ? 0 : th.safeLevel; }
2035 set {
2036 RThread th = GetCurrentContext();
2037 th.safeLevel = value; }
2038 }
2039 public void CheckSafeString(object x)
2040 {
2041 RThread th = GetCurrentContext();
2042 CheckSafeString(th, x);
2043 }
2044 internal void CheckSafeString(RThread th, object x)
2045 {
2046 if (x is RBasic)
2047 {
2048 RBasic r = (RBasic)x;
2049 if (th.safeLevel > 0 && r.IsTainted)
2050 {
2051 if (th.frame.lastFunc != 0)
2052 throw new SecurityException("Insecure operation - " + id2name(th.frame.lastFunc));
2053 else
2054 throw new SecurityException("Insecure operation: -r");
2055 }
2056 th.Secure(4);
2057 if (r is RString) return;
2058 }
2059 if (x is string == false)
2060 throw new eTypeError("wrong argument type " + ClassOf(InstanceOf(x)).Name + " (expected String)");
2061 }
2062 public void CheckType(object x, Type t)
2063 {
2064 if (x is QUndef)
2065 {
2066 bug("undef leaked to the Ruby space");
2067 }
2068 if (t.IsInstanceOfType(x) == false)
2069 {
2070 foreach (RBuiltinType ent in RBuiltinType.Table)
2071 {
2072 string etype;
2073 if (ent.Type == t)
2074 {
2075 if (x == null)
2076 {
2077 etype = "nil";
2078 }
2079 else if (x is int)
2080 {
2081 etype = "Fixnum";
2082 }
2083 else if (RBasic.IsSpecialConstType(x))
2084 {
2085 etype = RString.AsString(this, x);
2086 }
2087 else
2088 {
2089 etype = ClassOf(x).ClassName;
2090 }
2091 throw new eTypeError("wrong argument type " + etype +
2092 " (expected " + ent.Name + ")");
2093 }
2094 }
2095 bug("unknown type " + x.GetType().Name);
2096 }
2097 }
2098 internal void SecureVisibility(RBasic self)
2099 {
2100 RThread th = GetCurrentContext();
2101 if (th.safeLevel >= 4 && self.IsTainted == false)
2102 {
2103 throw new SecurityException("Insecure: can't change method visibility");
2104 }
2105 }
2106 public void ErrorFrozen(string what)
2107 {
2108 throw new eTypeError("can't modify frozen " + what);
2109 }
2110 static private object errAtGetter(uint id, GlobalEntry gb, NetRuby rb)
2111 {
2112 RThread th = rb.GetCurrentContext();
2113 if (th.errInfo != null)
2114 {
2115 return th.errInfo.Backtrace;
2116 }
2117 return null;
2118 }
2119 static private void errAtSetter(object val, uint id, GlobalEntry gb, NetRuby rb)
2120 {
2121 RThread th = rb.GetCurrentContext();
2122 if (th.errInfo == null)
2123 {
2124 throw new ArgumentException("$! not set");
2125 }
2126 RException.exc_set_backtrace(th.errInfo, val);
2127 }
2128 static private void errInfoSetter(object val, uint id, GlobalEntry gb, NetRuby rb)
2129 {
2130 RThread th = rb.GetCurrentContext();
2131 if (val != null)
2132 {
2133 RBasic b = rb.InstanceOf(val);
2134 if (b.IsKindOf(rb.eException) == false)
2135 throw new eTypeError("assigning non-exception to $!");
2136 }
2137 th.errInfo = (RException)val;
2138 }
2139 static private object errInfoGetter(uint i, GlobalEntry gb, NetRuby rb)
2140 {
2141 RThread th = rb.GetCurrentContext();
2142 return th.errInfo;
2143 }
2144 static private object safeGetter(uint i, GlobalEntry gb, NetRuby rb)
2145 {
2146 return rb.GetCurrentContext().safeLevel;
2147 }
2148 static private void safeSetter(object val, uint i, GlobalEntry gb, NetRuby rb)
2149 {
2150 int level = RInteger.ToInt(rb, val);
2151 RThread th = rb.GetCurrentContext();
2152 if (level < th.safeLevel)
2153 throw new SecurityException(String.Format("tried to downgrade safe level from {0} to {1}", th.safeLevel, level));
2154 th.safeLevel = level;
2155 }
2156 static private object verboseGetter(uint i, GlobalEntry gb, NetRuby rb)
2157 {
2158 return rb.verbose;
2159 }
2160 static private void verboseSetter(object val, uint i, GlobalEntry gb, NetRuby rb)
2161 {
2162 if (val == null) rb.verbose = false;
2163 else if (val is bool) rb.verbose = (bool)val;
2164 else rb.verbose = true;
2165 }
2166 static private object debugGetter(uint i, GlobalEntry gb, NetRuby rb)
2167 {
2168 return rb.debug;
2169 }
2170 static private void debugSetter(object val, uint i, GlobalEntry gb, NetRuby rb)
2171 {
2172 if (val == null) rb.debug = false;
2173 else if (val is bool) rb.debug = (bool)val;
2174 else rb.debug = true;
2175 }
2176
2177 static internal object lastLineGetter(uint i, GlobalEntry gb, NetRuby rb)
2178 {
2179 RThread th = rb.GetCurrentContext();
2180 if (th.scope.local_vars != null)
2181 {
2182 return th.scope.local_vars[0];
2183 }
2184 return null;
2185 }
2186 static private void lastLineSetter(object val, uint i, GlobalEntry gb, NetRuby rb)
2187 {
2188 RThread th = rb.GetCurrentContext();
2189 if (th.scope.local_vars != null)
2190 {
2191 th.scope.local_vars[0] = val.ToString();
2192 }
2193 else
2194 {
2195 }
2196 }
2197
2198 static private object printGetter(uint i, GlobalEntry gb, NetRuby rb)
2199 {
2200 return rb.doPrint;
2201 }
2202 static private object splitGetter(uint i, GlobalEntry gb, NetRuby rb)
2203 {
2204 return rb.doSplit;
2205 }
2206 static private object lineGetter(uint i, GlobalEntry gb, NetRuby rb)
2207 {
2208 return rb.doLine;
2209 }
2210 static private object argvGetter(uint i, GlobalEntry gb, NetRuby rb)
2211 {
2212 return rb.argv;
2213 }
2214 #if RUBY_ARG0
2215 static private void SetArg0(object val, uint i, GlobalEntry gb, NetRuby rb)
2216 {
2217 }
2218 #endif
2219 internal struct OPTBL {
2220 internal OPTBL(uint t, string s)
2221 {
2222 token = t;
2223 name = s;
2224 }
2225 internal uint token;
2226 internal string name;
2227 }
2228 internal static OPTBL[] op_tbl = new OPTBL[]{
2229 new OPTBL(Token.tDOT2, ".."),
2230 new OPTBL(Token.tDOT3, "..."),
2231 new OPTBL('+', "+"),
2232 new OPTBL('-', "-"),
2233 new OPTBL('+', "+(binary)"),
2234 new OPTBL('-', "-(binary)"),
2235 new OPTBL('*', "*"),
2236 new OPTBL('/', "/"),
2237 new OPTBL('%', "%"),
2238 new OPTBL(Token.tPOW, "**"),
2239 new OPTBL(Token.tUPLUS, "+@"),
2240 new OPTBL(Token.tUMINUS, "-@"),
2241 new OPTBL(Token.tUPLUS, "+(unary)"),
2242 new OPTBL(Token.tUMINUS, "-(unary)"),
2243 new OPTBL('|', "|"),
2244 new OPTBL('^', "^"),
2245 new OPTBL('&', "&"),
2246 new OPTBL(Token.tCMP, "<=>"),
2247 new OPTBL('>', ">"),
2248 new OPTBL(Token.tGEQ, ">="),
2249 new OPTBL('<', "<"),
2250 new OPTBL(Token.tLEQ, "<="),
2251 new OPTBL(Token.tEQ, "=="),
2252 new OPTBL(Token.tEQQ, "==="),
2253 new OPTBL(Token.tNEQ, "!="),
2254 new OPTBL(Token.tMATCH, "=~"),
2255 new OPTBL(Token.tNMATCH, "!~"),
2256 new OPTBL('!', "!"),
2257 new OPTBL('~', "~"),
2258 new OPTBL('!', "!(unary)"),
2259 new OPTBL('~', "~(unary)"),
2260 new OPTBL('!', "!@"),
2261 new OPTBL('~', "~@"),
2262 new OPTBL(Token.tAREF, "[]"),
2263 new OPTBL(Token.tASET, "[]="),
2264 new OPTBL(Token.tLSHFT, "<<"),
2265 new OPTBL(Token.tRSHFT, ">>"),
2266 new OPTBL(Token.tCOLON2, "::"),
2267 new OPTBL(Token.tCOLON3, "::"),
2268 new OPTBL('`', "`"),
2269 };
2270 internal st_table sym_tbl;
2271 internal st_table sym_rev_tbl;
2272 internal st_table global_tbl;
2273 internal st_table class_tbl;
2274 internal st_table autoload_tbl = null;
2275 internal st_table generic_iv_tbl;
2276 internal CacheEntry[] cache;
2277 internal Stack endProcs;
2278 internal Stack ephemeralEndProcs;
2279 internal class EndProcData
2280 {
2281 internal delegate void EndMethod(object o);
2282 private EndProcData(EndMethod fnc, object dat)
2283 {
2284 method = fnc;
2285 data = dat;
2286 }
2287 internal void Exec()
2288 {
2289 method(data);
2290 }
2291 private event EndMethod method;
2292 private object data;
2293 internal static void SetEndProc(NetRuby ruby, EndMethod mtd, object dt, bool ephemeral)
2294 {
2295 Stack stk;
2296 if (ephemeral)
2297 {
2298 if (ruby.ephemeralEndProcs == null)
2299 ruby.ephemeralEndProcs = new Stack();
2300 stk = ruby.ephemeralEndProcs;
2301 }
2302 else
2303 {
2304 if (ruby.endProcs == null)
2305 ruby.endProcs = new Stack();
2306 stk = ruby.endProcs;
2307 }
2308 lock (stk.SyncRoot)
2309 {
2310 stk.Push(new EndProcData(mtd, dt));
2311 }
2312 }
2313 }
2314
2315 internal void ClearCache()
2316 {
2317 lock (cache.SyncRoot)
2318 {
2319 for (int i = 0; i < cache.Length; i++)
2320 {
2321 cache[i].mid = 0;
2322 }
2323 }
2324 }
2325 internal void ClearCache(uint id)
2326 {
2327 lock (cache.SyncRoot)
2328 {
2329 for (int i = 0; i < cache.Length; i++)
2330 {
2331 if (cache[i].mid == id)
2332 cache[i].mid = 0;
2333 }
2334 }
2335 }
2336 internal void SetCache(RMetaObject o, uint id)
2337 {
2338 lock (cache.SyncRoot)
2339 {
2340 int idx = CacheEntry.EXPR1(o, id);
2341 cache[idx].SetEmtptyInfo(o, id);
2342 }
2343 }
2344 internal void SetCache(RMetaObject o, uint id, RNode body, RMetaObject org)
2345 {
2346 lock (cache.SyncRoot)
2347 {
2348 int idx = CacheEntry.EXPR1(o, id);
2349 cache[idx].SetInfo(o, id, body, org);
2350 }
2351 }
2352 //
2353 public uint intern(string name)
2354 {
2355 uint id;
2356 if (sym_tbl.lookup(name, out id) == true)
2357 return id;
2358 id = 0;
2359 switch (name[0])
2360 {
2361 case '$':
2362 id |= (uint)Parser.ID.GLOBAL;
2363 break;
2364 case '@':
2365 if (name[1] == '@')
2366 id |= (uint)Parser.ID.CLASS;
2367 else
2368 id |= (uint)Parser.ID.INSTANCE;
2369 break;
2370 default:
2371 if (name[0] != '_' && !Char.IsLetter(name[0]))
2372 {
2373 int i;
2374 for (i = 0; i < NetRuby.op_tbl.Length; i++)
2375 {
2376 if (NetRuby.op_tbl[i].name == name)
2377 {
2378 id = NetRuby.op_tbl[i].token;
2379 goto id_regist;
2380 }
2381 }
2382 }
2383
2384 int last = name.Length - 1;
2385 if (name[last] == '=')
2386 {
2387 string buf = name.Substring(0, last);
2388 id = intern(buf);
2389 if (id > (uint)Token.LAST_TOKEN && !Parser.is_attrset_id(id))
2390 {
2391 id = Parser.id_attrset(id);
2392 goto id_regist;
2393 }
2394 id = (uint)Parser.ID.ATTRSET;
2395 }
2396 else if (Char.IsUpper(name[0]))
2397 {
2398 id = (uint)Parser.ID.CONST;
2399 }
2400 else
2401 {
2402 id = (uint)Parser.ID.LOCAL;
2403 }
2404 break;
2405 }
2406 lock (this)
2407 {
2408 id |= ++last_id << (int)Parser.ID.SCOPE_SHIFT;
2409 }
2410 id_regist:
2411 lock (sym_tbl.SyncRoot)
2412 {
2413 sym_tbl[name] = id;
2414 sym_rev_tbl[id] = name;
2415 }
2416 return id;
2417 }
2418 public void _intern(uint id, string name)
2419 {
2420 lock (sym_tbl.SyncRoot)
2421 {
2422 sym_tbl[name] = id;
2423 sym_rev_tbl[id] = name;
2424 id >>= (int)Parser.ID.SCOPE_SHIFT;
2425 if (last_id < id)
2426 last_id = id;
2427 }
2428 }
2429 internal string id2name(uint id)
2430 {
2431 if (id < Token.LAST_TOKEN) {
2432 int i = 0;
2433
2434 for (i=0; i < op_tbl.Length; i++) {
2435 if (op_tbl[i].token == id)
2436 return op_tbl[i].name;
2437 }
2438 }
2439 string name = null;
2440
2441 if (sym_rev_tbl.lookup(id, out name))
2442 return name;
2443
2444 if (Parser.is_attrset_id(id)) {
2445 uint id2 = Parser.make_local_id(id);
2446
2447 again:
2448 name = id2name(id2);
2449 if (name != null) {
2450 string buf = name + "=";
2451 intern(name + "=");
2452 return id2name(id);
2453 }
2454 if (Parser.is_local_id(id2)) {
2455 id2 = Parser.make_const_id(id);
2456 goto again;
2457 }
2458 }
2459 return null;
2460 }
2461
2462 internal uint global_id(string s)
2463 {
2464 if (s[0] == '$') return intern(s);
2465 return intern("$" + s);
2466 }
2467 internal GlobalEntry global_entry(uint id)
2468 {
2469 object o;
2470 GlobalEntry ret = null;
2471 lock (global_tbl.SyncRoot)
2472 {
2473 if (global_tbl.lookup(id, out o))
2474 ret = (GlobalEntry)o;
2475 else
2476 {
2477 ret = new GlobalEntry(id);
2478 global_tbl.Add(id, ret);
2479 }
2480 }
2481 return ret;
2482 }
2483 internal void CloneGenericIVar(RBasic clone, RBasic obj)
2484 {
2485 if (generic_iv_tbl == null) return;
2486 lock (generic_iv_tbl.SyncRoot)
2487 {
2488 if (generic_iv_tbl.ContainsKey(obj))
2489 {
2490 st_table tbl = (st_table)generic_iv_tbl[obj];
2491 generic_iv_tbl[clone] = tbl.Clone();
2492 }
2493 }
2494 }
2495 internal bool IsGenericIVarDefined(RBasic obj, uint id)
2496 {
2497 if (generic_iv_tbl == null) return false;
2498 st_table tbl = null;
2499 if (generic_iv_tbl.lookup(obj, out tbl) == false) return false;
2500 object val;
2501 return tbl.lookup(id, out val);
2502 }
2503 internal object GenericIVarGet(RBasic obj, uint id)
2504 {
2505 if (generic_iv_tbl == null) return null;
2506 st_table tbl = null;
2507 if (generic_iv_tbl.lookup(obj, out tbl) == false) return null;
2508 object val;
2509 if (tbl.lookup(id, out val)) return val;
2510 return null;
2511 }
2512 internal void GenericIVarSet(RBasic obj, uint id, object val)
2513 {
2514 if (generic_iv_tbl == null)
2515 {
2516 lock (this)
2517 {
2518 if (generic_iv_tbl == null)
2519 {
2520 generic_iv_tbl = new st_table();
2521 }
2522 }
2523 }
2524 st_table tbl = null;
2525 lock (generic_iv_tbl.SyncRoot)
2526 {
2527 if (generic_iv_tbl.lookup(obj, out tbl) == false)
2528 {
2529 tbl = new st_table();
2530 generic_iv_tbl[obj] = tbl;
2531 }
2532 tbl[id] = val;
2533 }
2534 }
2535 internal object GenericIVarRemove(RBasic obj, uint id)
2536 {
2537 if (generic_iv_tbl == null) return null;
2538 st_table tbl;
2539 if (generic_iv_tbl.lookup(obj, out tbl) == false) return null;
2540 object val = tbl[id];
2541 lock (tbl.SyncRoot)
2542 {
2543 tbl.Remove(id);
2544 if (tbl.Count == 0)
2545 {
2546 generic_iv_tbl.Remove(obj);
2547 }
2548 }
2549 return val;
2550 }
2551
2552 public void DefineVariable(string name, object obj, GlobalEntry.Getter gtr, GlobalEntry.Setter str)
2553 {
2554 GlobalEntry ent = global_entry(global_id(name));
2555 lock (ent)
2556 {
2557 ent.data = obj;
2558 ent.ReplaceGetter(gtr);
2559 ent.ReplaceSetter(str);
2560 }
2561 }
2562 internal void DefineVirtualVariable(string name, GlobalEntry.Getter gtr, GlobalEntry.Setter str)
2563 {
2564 DefineVariable(name, null, gtr, str);
2565 }
2566 internal void DefineVariable(string name, object obj)
2567 {
2568 DefineVariable(name, obj, null, null);
2569 }
2570 internal void DefineReadonlyVariable(string name, object obj, GlobalEntry.Getter gtr)
2571 {
2572 GlobalEntry ent = global_entry(global_id(name));
2573 lock (ent)
2574 {
2575 ent.data = obj;
2576 ent.ReplaceGetter(gtr);
2577 ent.ReplaceSetter(new GlobalEntry.Setter(GlobalEntry.ReadonlySetter));
2578 }
2579 }
2580 internal void DefineGlobalConst(string name, object val)
2581 {
2582 DefineConst(cObject, name, val);
2583 }
2584 internal object GVarSet(GlobalEntry entry, object o)
2585 {
2586 RThread th = GetCurrentContext();
2587 if (th.safeLevel >= 4)
2588 {
2589 throw new SecurityException("Insecure: can't change global variable value");
2590 }
2591 lock (entry)
2592 {
2593 entry.SetValue(o, this);
2594 }
2595 // trace
2596 return o;
2597 }
2598 internal object GVarGet(GlobalEntry entry)
2599 {
2600 return entry.GetValue(this);
2601 }
2602 public void DefineConst(RMetaObject obj, string name, object val)
2603 {
2604 uint id = intern(name);
2605 if (Parser.is_const_id(id) == false)
2606 {
2607 throw new eNameError("wrong constant name " + name);
2608 }
2609 if (obj == cObject) Secure(4);
2610 obj.ConstSet(id, val);
2611 }
2612 public bool TopConstGet(uint id, out object val)
2613 {
2614 if (class_tbl.lookup(id, out val)) return true;
2615 if (autoload_tbl != null && autoload_tbl.ContainsKey(id))
2616 {
2617 AutoLoad(id);
2618 val = cObject.ConstGet(id);
2619 return true;
2620 }
2621 return false;
2622 }
2623 public object SearchConst(RThread th, object self, uint id)
2624 {
2625 RNode constBase = th.frame.cBase;
2626 while (constBase != null && constBase.next != null)
2627 {
2628 RMetaObject klass = constBase.clss;
2629 if (klass == null)
2630 {
2631 return ClassOf(self).ConstGet(id);
2632 }
2633 object result;
2634 if (klass.valGet(id, out result)) return result;
2635 constBase = constBase.next;
2636 }
2637 return th.frame.cBase.clss.ConstGet(id);
2638 }
2639 internal GlobalEntry Global(uint v)
2640 {
2641 return global_entry(v);
2642 }
2643 internal uint[] Locals
2644 {
2645 get { return GetCurrentContext().Locals; }
2646 }
2647 public void AutoLoad(uint id)
2648 {
2649 ; // to be filled
2650 }
2651 public bool IsAutoloadDefined(uint id)
2652 {
2653 return (autoload_tbl != null && autoload_tbl.ContainsKey(id));
2654 }
2655
2656 public string Inspect(Object o)
2657 {
2658 object x = Funcall(o, "inspect", null);
2659 return x.ToString();
2660 }
2661 public object ProtectInspect(RBasic obj, RBasic.InspectMethod method, object[] arg)
2662 {
2663 if (inspect_key == 0)
2664 inspect_key = intern("__inspect_key__");
2665 RThread th = GetCurrentContext();
2666 ArrayList inspect_tbl = (ArrayList)th.LocalARef(inspect_key);
2667 if (inspect_tbl == null)
2668 {
2669 inspect_tbl = new ArrayList();
2670 th.LocalASet(inspect_key, inspect_tbl);
2671 }
2672 int id = InstanceOf(obj).id;
2673 if (inspect_tbl.Contains(id))
2674 {
2675 return method(obj, arg);
2676 }
2677 return inspect_call(inspect_tbl, id, obj, method, arg);
2678 }
2679 private object inspect_call(ArrayList inspect_tbl, int id, RBasic obj, RBasic.InspectMethod method, object[] arg)
2680 {
2681 inspect_tbl.Add(id);
2682 object result = null;
2683 try
2684 {
2685 result = method(obj, arg);
2686 }
2687 finally
2688 {
2689 inspect_tbl.Remove(id);
2690 }
2691 return result;
2692 }
2693
2694 internal bool IsInspecting(object obj) // for avoiding eternal loop by inspect
2695 {
2696 if (inspect_key == 0)
2697 inspect_key = intern("__inspect_key__");
2698
2699 ArrayList inspect_tbl = (ArrayList)GetCurrentContext().LocalARef(inspect_key);
2700 if (inspect_tbl == null) return false;
2701 return inspect_tbl.Contains(InstanceOf(obj).id);
2702 }
2703 internal RArray ThreadList
2704 {
2705 get {
2706 RArray ary = new RArray(this, true);
2707 lock (threads.SyncRoot)
2708 {
2709 foreach (DictionaryEntry ent in threads)
2710 {
2711 RThread r = (RThread)ent.Value;
2712 if (r.IsAlive) ary.Add(r);
2713 }
2714 }
2715 ary.Add(threadMain);
2716 return ary;
2717 }
2718 }
2719 public RThread GetCurrentContext()
2720 {
2721 Thread t = Thread.CurrentThread;
2722 RThread th;
2723 lock (threads.SyncRoot) // Indexer will insert a new element if not found.
2724 {
2725 th = (RThread)threads[t];
2726 }
2727 return (th == null) ? threadMain : th;
2728 }
2729
2730 internal RThread GetCurrentContext(out bool created)
2731 {
2732 created = false;
2733 Thread t = Thread.CurrentThread;
2734 if (t == threadMain.Owner) return threadMain;
2735 RThread th;
2736 lock (threads.SyncRoot) // Indexer will insert a new element if not found.
2737 {
2738 th = (RThread)threads[t];
2739 }
2740 if (th == null)
2741 {
2742 lock (threadMain)
2743 {
2744 th = new RThread(this, threadMain);
2745 }
2746 threads[t] = th;
2747 created = true;
2748 }
2749 return th;
2750 }
2751 internal void AddContext(RThread th)
2752 {
2753 lock (threads.SyncRoot)
2754 {
2755 threads[th.thread] = th;
2756 }
2757 }
2758 internal void ClearContext(RThread th)
2759 {
2760 lock (threads.SyncRoot)
2761 {
2762 threads.Remove(th.Owner);
2763 }
2764 }
2765 //
2766 public RModule DefineModule(string name)
2767 {
2768 uint id = intern(name);
2769 if (cObject.IsConstDefined(id))
2770 {
2771 object o = cObject.ConstGet(id);
2772 if (o is RModule) return (RModule)o;
2773 throw new eTypeError(name + " is not a module");
2774 }
2775 RModule module = new RModule(this, name);
2776 return module;
2777 }
2778
2779 private void CallEndProc(object o)
2780 {
2781 RThread th = GetCurrentContext();
2782 th.PushIter(ITER.NOT);
2783 Frame frm = th.PushFrame(false);
2784 frm.self = frm.prev.self;
2785 frm.lastFunc = 0;
2786 frm.lastClass = null;
2787 try
2788 {
2789 ((RProc)o).Call();
2790 }
2791 catch (Exception e)
2792 {
2793 th.errorHandle(e);
2794 }
2795 th.PopFrame();
2796 th.PopIter();
2797 }
2798 internal void End()
2799 {
2800 RThread th = GetCurrentContext();
2801 Frame frm = th.PushFrame(false);
2802 frm.SetLastArgs(null, false);
2803 EndProcData.SetEndProc(this, new EndProcData.EndMethod(CallEndProc), Lambda(),
2804 th.wrapper != null);
2805 th.PopFrame();
2806 }
2807 object ruby_at_exit(RBasic r, params object[] args)
2808 {
2809 NetRuby ruby = r.ruby;
2810 object o = ruby.Lambda();
2811 EndProcData.SetEndProc(ruby, new EndProcData.EndMethod(ruby.CallEndProc), o,
2812 ruby.GetCurrentContext().wrapper != null);
2813 return o;
2814 }
2815
2816 internal object ScopedFuncall(RMetaObject klass, object recver, uint id, object[] argv, RNScope n)
2817 {
2818 RThread th = GetCurrentContext();
2819 #if LOCAL_TRACE
2820 System.Console.WriteLine("ScopedFuncall");
2821 for (int h = 0; h < argv.Length; h++)
2822 {
2823 System.Console.WriteLine("arg = " + ((argv[h]==null)?"null":argv[h].ToString()));
2824 }
2825 #endif
2826 object result = null;
2827 object[] local_vars = null;
2828 RNCRef savedCRef = null;
2829 Scope.ScopeMode vm = th.PushScope();
2830 if (n.rval != null)
2831 {
2832 savedCRef = th.cRef;
2833 th.cRef = (RNCRef)n.rval;
2834 th.frame.cBase = th.cRef;
2835 }
2836 if (n.tbl != null)
2837 {
2838 #if KEEP_ORIGINAL_NODE
2839 local_vars = new object[n.tbl.Length + 1];
2840 local_vars[0] = n;
2841 #else
2842 local_vars = new object[n.tbl.Length];
2843 th.scope.InitLocal(n.tbl, local_vars);
2844 #endif
2845 }
2846 RNode body = n.next;
2847 RNode b2 = body;
2848 #if LOCAL_TRACE
2849 System.Console.WriteLine("local_vars = " +
2850 ((local_vars == null)?"null":local_vars.Length.ToString()));
2851 #endif
2852 RVarmap old = th.dyna_vars;
2853 th.dyna_vars = null;
2854
2855 th.PushTag(Tag.TAG.PROT_FUNC);
2856 Tag.TAG state = Tag.TAG.EMPTY;
2857 try
2858 {
2859 bool fargset = false;
2860 RNode node = null;
2861 if (body is RNArgs)
2862 {
2863 node = body;
2864 body = null;
2865 }
2866 else if (body is RNBlock)
2867 {
2868 node = body.head;
2869 body = body.next;
2870 }
2871 int i = 0;
2872 if (node != null)
2873 {
2874 if (node is RNArgs == false)
2875 {
2876 bug("no argumenet-node");
2877 }
2878 i = node.cnt;
2879 if (i > argv.Length)
2880 {
2881 throw new ArgumentException(
2882 String.Format("wrong # of arguments({0} for {1})", argv.Length, i));
2883 }
2884 if (node.rest == -1)
2885 {
2886 int opt = i;
2887 RNode optnode = node.opt;
2888 while (optnode != null)
2889 {
2890 opt++;
2891 optnode = optnode.next;
2892 }
2893 if (opt < argv.Length)
2894 {
2895 throw new ArgumentException(
2896 String.Format("wrong # of arguments({0} for {1})",
2897 argv.Length, opt));
2898 }
2899 // index offset is 2, for $_ and $~
2900 fargset = true;
2901 }
2902 }
2903
2904 if (local_vars != null)
2905 {
2906 if (i > 0)
2907 {
2908 // +2 for $_ and $~
2909 Array.Copy(argv, 0, local_vars, 2, i);
2910 }
2911 #if LOCAL_TRACE
2912 for (int h = 0; h < i; h++)
2913 {
2914 System.Console.WriteLine("local = " +
2915 ((local_vars[2+h]==null)?"null":local_vars[2+h].ToString()));
2916 }
2917 #endif
2918 int argc = argv.Length - i;
2919 if (node.opt != null)
2920 {
2921 RNode opt = node.opt;
2922 while (opt != null && argc > 0)
2923 {
2924 Assign(recver, opt.head, argv[i], true);
2925 argc--;
2926 i++;
2927 opt = opt.next;
2928 }
2929 if (opt != null)
2930 {
2931 th.file = opt.file;
2932 th.line = opt.Line;
2933 Eval(recver, opt);
2934 }
2935 }
2936 if (node.rest >= 0)
2937 {
2938 ArrayList a = new ArrayList();
2939 if (argc > 0)
2940 {
2941 for (int ix = argc; ix < argv.Length; ix++)
2942 a.Add(argv[ix]);
2943 }
2944 th.scope.local_vars[node.rest] = new RArray(this, a);
2945 }
2946 }
2947 if (TraceFunc != null)
2948 {
2949 }
2950 if (fargset)
2951 {
2952 th.frame.SetLastArgs(local_vars, true);
2953 }
2954 result = Eval(recver, body);
2955 if (fargset)
2956 {
2957 ;
2958 }
2959 }
2960 catch (eTagJump e)
2961 {
2962 Tag etag = th.CurrentTag;
2963 if (e.state == Tag.TAG.RETURN)
2964 {
2965 result = etag.Result;
2966 state = Tag.TAG.EMPTY;
2967 }
2968 }
2969 catch (Exception e)
2970 {
2971 th.errInfo = new RException(this, e);
2972 state = Tag.TAG.RAISE;
2973 }
2974
2975 th.PopTag(true);
2976
2977 th.dyna_vars = old;
2978 th.PopScope(vm);
2979 th.cRef = savedCRef;
2980 if (TraceFunc != null)
2981 {
2982 }
2983 switch (state)
2984 {
2985 case Tag.TAG.EMPTY:
2986 ;
2987 break;
2988 case Tag.TAG.RETRY:
2989 goto default;
2990 case Tag.TAG.RAISE:
2991 throw new eTagJump(th.errInfo);
2992 default:
2993 break;
2994 }
2995 return result;
2996 }
2997
2998 internal void Assign(object self, RNode lhs, object val, bool check)
2999 {
3000 if (val is QUndef)
3001 {
3002 val = null;
3003 }
3004 if (val is string)
3005 {
3006 // create assignable object
3007 val = new RString(this, (string)val);
3008 }
3009 lhs.Assign(this, self, val, check);
3010 }
3011
3012 public delegate object IterationProc(RBasic ob);
3013 public delegate object BlockProc(object it, object data, object self);
3014 public object Iterate(IterationProc itProc, RBasic dat1, BlockProc blProc, object data)
3015 {
3016 Tag.TAG state;
3017 object result = null;
3018 RThread th = GetCurrentContext();
3019 RNode node = new RNIFunc(th, blProc, data);
3020 RObjectBase self = topSelf;
3021 iter_retry:
3022 th.PushIter(ITER.PRE);
3023 Block _block = new Block(th, null, node, self);
3024 th.block = _block;
3025 th.PushTag(Tag.TAG.PROT_NONE);
3026 state = Tag.TAG.EMPTY;
3027 try
3028 {
3029 result = itProc(dat1);
3030 }
3031 catch (eTagJump e)
3032 {
3033 state = e.state;
3034 if (_block.CheckTag(e.state))
3035 {
3036 state &= Tag.TAG.MASK;
3037 if (state == Tag.TAG.RETURN)
3038 {
3039 Tag etag = th.CurrentTag;
3040 result = etag.Result;
3041 }
3042 }
3043 }
3044 catch (Exception e)
3045 {
3046 th.errInfo = new RException(this, e);
3047 state = Tag.TAG.RAISE;
3048 }
3049 th.PopTag(true);
3050 th.block = _block.prev;
3051 th.PopIter();
3052 switch (state)
3053 {
3054 case Tag.TAG.EMPTY:
3055 break;
3056 case Tag.TAG.RETRY:
3057 goto iter_retry;
3058 case Tag.TAG.BREAK:
3059 result = null;
3060 break;
3061 case Tag.TAG.RETURN:
3062 Tag etag = (Tag)th.protTag.Peek();
3063 etag.Result = result;
3064 goto default;
3065 default:
3066 th.TagJump(state);
3067 break;
3068 }
3069 return result;
3070 }
3071
3072 internal object Iteration(RNode node, object self)
3073 {
3074 RThread th = GetCurrentContext();
3075 object result = null;
3076 for (;;)
3077 {
3078 Block _block = th.IterBlock(node.var, node.body, self);
3079 Tag.TAG state = Tag.TAG.EMPTY;
3080 try
3081 {
3082 th.PushIter(ITER.PRE);
3083 if (node is RNIter)
3084 {
3085 result = Eval(self, node.iter);
3086 }
3087 else if (node is RNFor)
3088 {
3089 string file = th.file;
3090 int line = th.line;
3091 _block.DScope = false;
3092 object recv = CallIter(node, self);
3093 th.file = file;
3094 th.line = line;
3095 result = Call(ClassOf(recv), recv, "each", null, 0);
3096 }
3097 else
3098 {
3099 bug("unknown node " + node.ToString() + " for Iteration");
3100 }
3101 th.PopIter();
3102 }
3103 catch (eTagJump e)
3104 {
3105 state = e.state;
3106 if (_block.CheckTag(e.state))
3107 {
3108 state &= Tag