Develop and Download Open Source Software

Browse CVS Repository

Contents of /netruby/netruby/Class.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:15 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
3 class.c -
4
5 $Author: matz $
6 $Date: 2001/12/18 08:40:30 $
7 created at: Tue Aug 10 15:05:44 JST 1993
8
9 Copyright (C) 1993-2000 Yukihiro Matsumoto
10
11 **********************************************************************/
12 /*
13 Copyright(C) 2001-2002 arton
14
15 Permission is granted for use, copying, modification, distribution,
16 and distribution of modified versions of this work as long as the
17 above copyright notice is included.
18 */
19
20 using System;
21 using System.Collections;
22 using System.Reflection;
23 using System.Security;
24
25 namespace arton.NETRuby
26 {
27 public abstract class RMetaObject : RObjectBase
28 {
29 internal RMetaObject(NetRuby rb, string name, RMetaObject sp, RMetaObject meta)
30 : base(rb, meta)
31 {
32 super = sp;
33 m_tbl = new st_table();
34 if (name != null)
35 {
36 uint id = rb.intern(name);
37 IVarSet("__classid__", Symbol.ID2SYM(id));
38 }
39 }
40 internal RMetaObject(RMetaObject o) :
41 base(o)
42 {
43 if (o.m_tbl != null)
44 {
45 m_tbl = (st_table)o.m_tbl.Clone();
46 }
47 }
48 internal RMetaObject super;
49 internal st_table m_tbl;
50
51 public override string ToString()
52 {
53 return ClassPath;
54 }
55
56 public void Attribute(uint id, bool read, bool write, bool ex)
57 {
58 string s = ruby.id2name(id);
59 if (s == null)
60 throw new eArgError("argument needs to be symbol or string");
61 Attribute(s, read, write, ex);
62 }
63 public void Attribute(string name, bool read, bool write, bool ex)
64 {
65 NOEX noex = NOEX.PUBLIC;
66 RThread th = ruby.GetCurrentContext();
67 if (ex)
68 {
69 if (th.ScopeTest(Scope.ScopeMode.Private))
70 {
71 noex = NOEX.PRIVATE;
72 ruby.warning((th.ScopeMode == Scope.ScopeMode.ModFunc) ?
73 "attribute accessor as module_function" :
74 "private attribute?");
75 }
76 else if (th.ScopeTest(Scope.ScopeMode.Protected))
77 {
78 noex = NOEX.PROTECTED;
79 }
80 }
81 uint id = ruby.ToID(name);
82 uint attriv = ruby.intern("@" + name);
83 if (read)
84 {
85 addMethod(id, new RNIVar(th, attriv), noex);
86 ruby.Funcall(this, "method_added", Symbol.ID2SYM(id));
87 }
88 if (write)
89 {
90 id = ruby.intern(name + "=");
91 addMethod(id, new RNAttrSet(th, attriv), noex);
92 ruby.Funcall(this, "method_added", Symbol.ID2SYM(id));
93 }
94 }
95 public void DefineConst(string name, object val)
96 {
97 uint id = ruby.intern(name);
98 if (this == ruby.cObject) ruby.Secure(4);
99 if (Parser.is_const_id(id) == false)
100 throw new eNameError("wrong constant name " + name);
101 ConstSet(id, val);
102 }
103 public object ConstSet(uint id, object val)
104 {
105 valSet(id, val, true);
106 return val;
107 }
108
109 public object ConstGet(uint id)
110 {
111 bool fretry = false;
112 RMetaObject klass = this;
113 retry:
114 while (klass != null)
115 {
116 object o;
117 if (klass.iv_tbl != null && klass.iv_tbl.lookup(id, out o))
118 {
119 return o;
120 }
121 if (klass == ruby.cObject && ruby.TopConstGet(id, out o))
122 {
123 return o;
124 }
125 klass = klass.super;
126 }
127 if (fretry == false && this is RModule)
128 {
129 fretry = true;
130 klass = ruby.cObject;
131 goto retry;
132 }
133 if (this != ruby.cObject)
134 {
135 string s = String.Format("uninitialized constant {0} at {1}",
136 ruby.id2name(id), ClassPath);
137 #if _DEBUG
138 System.Console.Error.WriteLine(s);
139 #endif
140 throw new eNameError(s);
141 }
142 throw new eNameError("uninitialized constant " + ruby.id2name(id));
143 }
144
145 public object ConstGetAt(uint id)
146 {
147 object o;
148 if (iv_tbl != null && iv_tbl.lookup(id, out o))
149 {
150 return o;
151 }
152 if (this == ruby.cObject && ruby.TopConstGet(id, out o))
153 {
154 return o;
155 }
156 throw new eNameError(String.Format("uninitialized constant {0}::{1}",
157 ClassPath, ruby.id2name(id)));
158 }
159
160 public bool IsConstDefinedAt(uint id)
161 {
162 if (iv_tbl != null && iv_tbl.ContainsKey(id))
163 return true;
164 if (this == ruby.cObject)
165 return IsConstDefined(id);
166 return false;
167 }
168 public bool IsConstDefined(uint id)
169 {
170 RMetaObject kclass = this;
171
172 while (kclass != null)
173 {
174 if (kclass.iv_tbl != null && kclass.iv_tbl.ContainsKey(id))
175 {
176 return true;
177 }
178 kclass = kclass.super;
179 }
180 if (this is RModule)
181 {
182 return ruby.cObject.IsConstDefined(id);
183 }
184 if (ruby.class_tbl.ContainsKey(id)) return true;
185 return ruby.IsAutoloadDefined(id);
186 }
187 public object RemoveConst(uint id)
188 {
189 if (Parser.is_const_id(id) == false)
190 throw new eNameError("wrong constant name " + ruby.id2name(id));
191 if (IsTainted == false && ruby.SafeLevel >= 4)
192 throw new SecurityException("Insecure: can't remove constant");
193 if (IsFrozen) ruby.ErrorFrozen("class/module");
194 object o;
195 if (iv_tbl != null && iv_tbl.delete(id, out o)) return o;
196 if (IsConstDefinedAt(id))
197 throw new eNameError(String.Format("cannot remove {0}::{1}",
198 Name, ruby.id2name(id)));
199 throw new eNameError(String.Format("constant {0}::{1} not defined",
200 Name, ruby.id2name(id)));
201 }
202 public void CVarDeclare(uint id, object val)
203 {
204 try
205 {
206 CVarSet(id, val);
207 }
208 catch (eNameError)
209 {
210 valSet(id, val, false);
211 }
212 }
213 public object CVarGet(uint id)
214 {
215 RMetaObject tmp = this;
216 object result = null;
217 while (tmp != null)
218 {
219 if (tmp.iv_tbl != null && tmp.iv_tbl.lookup(id, out result))
220 return result;
221 tmp = tmp.super;
222 }
223 throw new eNameError(String.Format("uninitialized class variable {0} in {1}",
224 ruby.id2name(id), ClassName));
225 }
226 public void CVarSet(uint id, object val)
227 {
228 RMetaObject tmp = this;
229 while (tmp != null)
230 {
231 lock (tmp.iv_tbl.SyncRoot)
232 {
233 if (tmp.iv_tbl != null && tmp.iv_tbl.ContainsKey(id))
234 {
235 tmp.CVarCheck("class variable");
236 tmp.iv_tbl[id] = val;
237 return;
238 }
239 }
240 tmp = tmp.super;
241 }
242 throw new eNameError("uninitialized class variable " + ruby.id2name(id) + " in " + ClassName);
243 }
244 void valSet(uint id, object val, bool isconst)
245 {
246 string dest = (isconst) ? "constant" : "class variable";
247 CVarCheck(dest);
248 lock (this)
249 {
250 if (iv_tbl == null)
251 {
252 iv_tbl = new st_table();
253 }
254 else if (isconst)
255 {
256 if (iv_tbl.ContainsKey(id) ||
257 (this == ruby.cObject && ruby.class_tbl.ContainsKey(id)))
258 {
259 if (ruby.compiled == false || iv_tbl[id] != null)
260 ruby.warn(String.Format("already initialized {0} {1}",
261 dest, ruby.id2name(id)));
262 }
263 }
264 iv_tbl[id] = val;
265 }
266 }
267 protected void CVarCheck(string dest)
268 {
269 if (IsTainted == false && ruby.SafeLevel >= 4)
270 {
271 throw new SecurityException("Insecure: can't set " + dest);
272 }
273 if (IsFrozen) ruby.ErrorFrozen("class/module");
274 }
275
276 public virtual string Name // class2name
277 {
278 get { return ClassPath; }
279 }
280 public string ModuleName
281 {
282 get {
283 string s = ClassPath;
284 if (s != null) return s;
285 return String.Empty;
286 }
287 }
288 public virtual RMetaObject ClassReal
289 {
290 get {
291 RMetaObject cl;
292 if (this is RIncClass)
293 {
294 cl = klass;
295 }
296 else
297 {
298 cl = this;
299 }
300 while (cl is RIncClass || cl is RSingletonClass)
301 {
302 cl = cl.super;
303 }
304 return cl;
305 }
306 }
307 public string ClassPath
308 {
309 get {
310 string s = ClassName;
311 if (s != null) return s;
312 s = "Class";
313 if (this is RModule) s = "Module";
314 return String.Format("#<{0} 0lx{1:x8}>", s, GetHashCode());
315 }
316 }
317 public string ClassName
318 {
319 get {
320 object path = null;
321 uint cp = ruby.intern("__classpath__");
322 RMetaObject klass = ClassReal;
323 if (klass == null) klass = ruby.cObject;
324 lock (klass)
325 {
326 if (klass.iv_tbl != null &&
327 klass.iv_tbl.lookup(cp, out path) == false)
328 {
329 uint cid = ruby.intern("__classid__");
330 if (klass.iv_tbl.lookup(cid, out path))
331 {
332 path = ruby.id2name(Symbol.SYM2ID((uint)path));
333 klass.iv_tbl[cp] = path;
334 klass.iv_tbl.Remove(cid);
335 }
336 }
337 }
338 if (path == null)
339 {
340 path = klass.FindClassPath();
341 if (path == null) return String.Empty;
342 return (string)path;
343 }
344 if (path is string == false)
345 {
346 ruby.bug("class path is not set properly");
347 }
348 return (string)path;
349 }
350 }
351
352 public void SetClassPath(RMetaObject under, string name)
353 {
354 string str = name;
355 if (under != ruby.cObject)
356 {
357 str = under.ClassPath;
358 str += "::" + name;
359 }
360 IVarSet("__classpath__", str);
361 }
362 private class fc_result
363 {
364 internal fc_result(uint key, RObjectBase kl, RObjectBase value, fc_result pv)
365 {
366 name = key;
367 path = null;
368 klass = kl;
369 track = value;
370 prev = pv;
371 }
372 internal bool end(RObjectBase o) { return (o == track); }
373 internal bool lookup(uint id, out string val)
374 {
375 val = null;
376 object o;
377 if (track.iv_tbl != null && track.iv_tbl.lookup(id, out o))
378 {
379 val = (string)o;
380 return true;
381 }
382 return false;
383 }
384 internal uint name;
385 internal RObjectBase klass;
386 internal string path;
387 RObjectBase track;
388 internal fc_result prev;
389 }
390 private string fc_path(fc_result fc, uint name)
391 {
392 string path = ruby.id2name(name);
393 string tmp;
394 uint cp = ruby.intern("__classpath__");
395 while (fc != null)
396 {
397 if (fc.end(ruby.cObject)) break;
398 if (fc.lookup(cp, out tmp))
399 {
400 return tmp + "::" + path;
401 }
402 tmp = ruby.id2name(fc.name);
403 path = tmp + "::" + path;
404 fc = fc.prev;
405 }
406 return path;
407 }
408 private bool fc_i(uint key, object value, fc_result res)
409 {
410 if (Parser.is_const_id(key)) return false;
411 if (value is RModule || value is RClass)
412 {
413 RMetaObject va = (RMetaObject)value;
414 if (va == res.klass)
415 {
416 res.path = fc_path(res, key);
417 return true;
418 }
419 if (va.iv_tbl == null) return false;
420 fc_result list = res;
421 while (list != null)
422 {
423 if (list.end(va)) return false;
424 list = list.prev;
425 }
426 fc_result arg = new fc_result(key, res.klass, va, res);
427 lock (va.iv_tbl.SyncRoot)
428 {
429 foreach (DictionaryEntry ent in va.iv_tbl)
430 {
431 if (fc_i((uint)ent.Key, ent.Value, arg))
432 {
433 res.path = arg.path;
434 return true;
435 }
436 }
437 }
438 }
439 return false;
440 }
441 internal object FindClassPath()
442 {
443 fc_result arg = new fc_result(0, this, ruby.cObject, null);
444 if (ruby.cObject.iv_tbl != null)
445 {
446 lock (ruby.cObject.iv_tbl.SyncRoot)
447 {
448 foreach (DictionaryEntry entry in ruby.cObject.iv_tbl)
449 {
450 if (fc_i((uint)entry.Key, entry.Value, arg)) break;
451 }
452 }
453 }
454 if (arg.path == null)
455 {
456 lock (ruby.class_tbl.SyncRoot)
457 {
458 foreach (DictionaryEntry entry in ruby.class_tbl)
459 {
460 if(fc_i((uint)entry.Key, entry.Value, arg)) break;
461 }
462 }
463 }
464 if (arg.path != null)
465 {
466 lock (this)
467 {
468 if (iv_tbl == null) iv_tbl = new st_table();
469 iv_tbl[ruby.intern("__classpath__")] = arg.path;
470 }
471 }
472 return (string)arg.path;
473 }
474
475 public static void ExtendObject(RBasic klass, RMetaObject module)
476 {
477 IncludeModule(SingletonClass(klass, klass.ruby), module);
478 }
479 internal static object extend_object(RBasic r, params object[] args)
480 {
481 ExtendObject((RMetaObject)args[0], (RMetaObject)r);
482 return r;
483 }
484 public static void IncludeModule(RMetaObject klass, RMetaObject module)
485 {
486 bool changed = false;
487 if (module == null) return;
488 if (module == klass) return;
489 // call Check_Type if need
490
491 // what is the syncroot ?
492 RMetaObject c = klass;
493 while (module != null)
494 {
495 for (RMetaObject r = klass.super; r != null; r = r.super)
496 {
497 if (r is RIncClass &&
498 r.m_tbl == module.m_tbl)
499 {
500 c = r;
501 goto skip;
502 }
503 }
504 c.super = new RIncClass(module, c.super);
505 c = c.super;
506 changed = true;
507 skip:
508 module = module.super;
509 }
510 if (changed) klass.ruby.ClearCache();
511 }
512
513 private class InsMethods
514 {
515 internal virtual string Inspect(NetRuby ruby, uint key, RNode body)
516 {
517 if ((body.noex & (NOEX.PRIVATE | NOEX.PROTECTED)) == 0)
518 {
519 if (body.body != null)
520 return ruby.id2name(key);
521 }
522 return null;
523 }
524 }
525 private class InsMethodsProtected : InsMethods
526 {
527 internal override string Inspect(NetRuby ruby, uint key, RNode body)
528 {
529 if (body.body != null && (body.noex & (NOEX.PROTECTED)) != 0)
530 {
531 return ruby.id2name(key);
532 }
533 return null;
534 }
535 }
536 private class InsMethodsPrivate : InsMethods
537 {
538 internal override string Inspect(NetRuby ruby, uint key, RNode body)
539 {
540 if (body.body != null && (body.noex & (NOEX.PRIVATE)) != 0)
541 {
542 return ruby.id2name(key);
543 }
544 return null;
545 }
546 }
547 public override RArray SingletonMethods
548 {
549 get {
550 ArrayList ary = new ArrayList();
551 RMetaObject klass = this;
552 InsMethods ins = new InsMethods();
553 while (klass != null && klass.Test(FL.SINGLETON))
554 {
555 lock (klass.m_tbl.SyncRoot)
556 {
557 foreach (DictionaryEntry ent in klass.m_tbl)
558 {
559 string s = ins.Inspect(ruby, (uint)ent.Key, (RNode)ent.Value);
560 if (s != null && ary.Contains(s) == false)
561 {
562 ary.Add(s);
563 }
564 }
565 }
566 klass = klass.super;
567 }
568 return new RArray(ruby, ary);
569 }
570 }
571 public virtual RArray ClassInstanceMethods(object[] argv)
572 {
573 object[] inherited_too = new object[1];
574 ruby.ScanArgs(argv, "01", inherited_too);
575 return MethodList(RTest(inherited_too[0]), new InsMethods());
576 }
577 public virtual RArray ClassProtectedInstanceMethods(object[] argv)
578 {
579 object[] inherited_too = new object[1];
580 ruby.ScanArgs(argv, "01", inherited_too);
581 return MethodList(RTest(inherited_too[0]), new InsMethodsProtected());
582 }
583 public virtual RArray ClassPrivateInstanceMethods(object[] argv)
584 {
585 object[] inherited_too = new object[1];
586 ruby.ScanArgs(argv, "01", inherited_too);
587 return MethodList(RTest(inherited_too[0]), new InsMethodsPrivate());
588
589 }
590 private RArray MethodList(bool inherited_too, InsMethods ins)
591 {
592 ArrayList ary = new ArrayList();
593 lock (this)
594 {
595 for (RMetaObject klass = this; klass != null; klass = klass.super)
596 {
597 foreach (DictionaryEntry entry in klass.m_tbl)
598 {
599 string s = ins.Inspect(ruby, (uint)entry.Key, (RNode)entry.Value);
600 if (s != null && ary.Contains(s) == false)
601 {
602 ary.Add(s);
603 }
604 }
605 if (inherited_too == false) break;
606 }
607 }
608 return new RArray(ruby, ary);
609 }
610 public object AppendFeatures(object o)
611 {
612 if (o is RMetaObject == false)
613 {
614 ruby.CheckType(o, typeof(RClass));
615 }
616 IncludeModule((RMetaObject)o, this);
617 return this;
618 }
619 public object Include(object[] args)
620 {
621 uint id = ruby.intern("append_features");
622 for (int i = 0; i < args.Length; i++)
623 {
624 ruby.CheckType(args[i], typeof(RModule));
625 ruby.Funcall(args[i], id, this);
626 }
627 return this;
628 }
629 private void ExportMethod(uint name, NOEX noex)
630 {
631 if (this == ruby.cObject)
632 {
633 ruby.Secure(4);
634 }
635 RMetaObject origin;
636 RNode body = SearchMethod(name, out origin);
637 if (body == null && this is RModule)
638 {
639 body = ruby.cObject.SearchMethod(name, out origin);
640 }
641 if (body == null)
642 {
643 printUndef(name);
644 }
645 if (body.noex != noex)
646 {
647 if (this == origin)
648 {
649 body.noex = noex;
650 }
651 else
652 {
653 ruby.ClearCache(name);
654 addMethod(name, new RNZSuper(ruby.GetCurrentContext(), ruby), noex);
655 }
656 }
657 }
658 private void SetMethodVisibility(object[] args, NOEX ex)
659 {
660 ruby.SecureVisibility(this);
661 for (int i = 0; i < args.Length; i++)
662 {
663 ExportMethod(ruby.ToID(args[i]), ex);
664 }
665 }
666 public object Public(params object[] args)
667 {
668 ruby.SecureVisibility(this);
669 RThread th = ruby.GetCurrentContext();
670 if (args == null || args.Length == 0)
671 {
672 th.ScopeSet(Scope.ScopeMode.Public);
673 }
674 else
675 {
676 SetMethodVisibility(args, NOEX.PUBLIC);
677 }
678 return this;
679 }
680 public object Protected(params object[] args)
681 {
682 ruby.SecureVisibility(this);
683 RThread th = ruby.GetCurrentContext();
684 if (args == null || args.Length == 0)
685 {
686 th.ScopeSet(Scope.ScopeMode.Protected);
687 }
688 else
689 {
690 SetMethodVisibility(args, NOEX.PROTECTED);
691 }
692 return this;
693 }
694 public object Private(params object[] args)
695 {
696 ruby.SecureVisibility(this);
697 RThread th = ruby.GetCurrentContext();
698 if (args == null || args.Length == 0)
699 {
700 th.ScopeSet(Scope.ScopeMode.Private);
701 }
702 else
703 {
704 SetMethodVisibility(args, NOEX.PRIVATE);
705 }
706 return this;
707 }
708 public RMetaObject ModuleFunction(params object[] argv)
709 {
710 if (this is RModule == false)
711 throw new eTypeError("module_function must be called for modules");
712 ruby.SecureVisibility(this);
713 RThread th = ruby.GetCurrentContext();
714 if (argv == null || argv.Length == 0)
715 {
716 th.ScopeSet(Scope.ScopeMode.ModFunc);
717 return this;
718 }
719 SetMethodVisibility(argv, NOEX.PRIVATE);
720 for (int i = 0; i < argv.Length; i++)
721 {
722 uint id = ruby.ToID(argv[i]);
723 RMetaObject origin;
724 RNode body = SearchMethod(id, out origin);
725 if (body == null || body.body == null)
726 {
727 ruby.bug(String.Format("undefined method `{0}'; can't happen",
728 ruby.id2name(id)));
729 }
730 SingletonClass(this, ruby).addMethod(id, body.body, NOEX.PUBLIC);
731 ruby.Funcall(this, "singleton_method_added", Symbol.ID2SYM(id));
732 }
733 return this;
734 }
735
736 public bool Eqq(object o)
737 {
738 return ruby.InstanceOf(o).IsKindOf(this);
739 }
740 private RMetaObject ModCheck(object o)
741 {
742 if (o is RMetaObject == false)
743 {
744 throw new eTypeError("<=> requires Class or Module (" +
745 ruby.ClassOf(o).ClassName + " given)");
746 }
747 return (RMetaObject)o;
748 }
749 public int CompareTo(object o)
750 {
751 if (this == o) return 0;
752 RMetaObject r = ModCheck(o);
753 if (le(r)) return -1;
754 return 1;
755 }
756 public bool le(object o)
757 {
758 RMetaObject arg = ModCheck(o);
759 RMetaObject mod = this;
760 while (mod != null)
761 {
762 if (mod.m_tbl == arg.m_tbl)
763 return true;
764 mod = mod.super;
765 }
766 return false;
767 }
768 public bool lt(object o)
769 {
770 if (this == o) return false;
771 return le(o);
772 }
773 public bool ge(object o)
774 {
775 RMetaObject arg = ModCheck(o);
776 return arg.le(this);
777 }
778 public bool gt(object o)
779 {
780 if (this == o) return false;
781 return ge(o);
782 }
783 public RArray IncludedModules()
784 {
785 ArrayList a = new ArrayList();
786 for (RMetaObject p = super; p != null; p = p.super)
787 {
788 if (p is RIncClass) a.Add(p.klass);
789 }
790 return new RArray(ruby, a);
791 }
792
793 public void DefineModuleFunction(string name, MethodInfo mi)
794 {
795 DefinePrivateMethod(name, mi);
796 DefineSingletonMethod(name, mi);
797 }
798 public void DefineModuleFunction(string name, RMethod rm, int argc)
799 {
800 DefinePrivateMethod(name, rm, argc);
801 DefineSingletonMethod(name, rm, argc);
802 }
803 public void DefinePrivateMethod(string name, MethodInfo mi)
804 {
805 addMethod(name, mi, NOEX.PRIVATE | NOEX.CFUNC);
806 }
807 public void DefinePrivateMethod(string name, RMethod rm, int argc)
808 {
809 addMethod(name, rm, argc, NOEX.PRIVATE | NOEX.CFUNC);
810 }
811 public void DefineProtectedMethod(string name, MethodInfo mi)
812 {
813 addMethod(name, mi, NOEX.PROTECTED | NOEX.CFUNC);
814 }
815 public void DefineProtectedMethod(string name, RMethod rm, int argc)
816 {
817 addMethod(name, rm, argc, NOEX.PROTECTED | NOEX.CFUNC);
818 }
819 public void DefineMethod(string name, MethodInfo mi)
820 {
821 addMethod(name, mi,
822 ((name == "initialize") ? NOEX.PRIVATE : NOEX.PUBLIC) | NOEX.CFUNC);
823 }
824 public void DefineMethod(string name, MethodInfo mi, NOEX ex)
825 {
826 AddMethodCheck();
827 addMethod(name, mi, ex);
828 }
829 public void DefineMethod(string name, RMethod rm, int argc)
830 {
831 AddMethodCheck();
832 NOEX accs = ((name == "initialize") ? NOEX.PRIVATE : NOEX.PUBLIC) | NOEX.CFUNC;
833 addMethod(name, rm, argc, accs);
834 }
835
836 public void RemoveMethod(uint id)
837 {
838 RThread th = ruby.GetCurrentContext();
839 if (this == ruby.cObject) th.Secure(4);
840 if (th.safeLevel >= 4 && IsTainted == false)
841 throw new SecurityException("Insecure: can't remove method");
842 if (IsFrozen) ruby.ErrorFrozen("class/module");
843 lock (m_tbl.SyncRoot)
844 {
845 if (m_tbl.ContainsKey(id) == false)
846 throw new eNameError(String.Format("method `{0}' not defined in {1}",
847 ruby.id2name(id), Name));
848 m_tbl.Remove(id);
849 }
850 ruby.ClearCache(id);
851 }
852 public void UndefMethod(string name)
853 {
854 AddMethodCheck();
855 lock (m_tbl.SyncRoot)
856 {
857 m_tbl[ruby.intern(name)] = new RNMethod(null, NOEX.UNDEF);
858 }
859 #if INIT_DEBUG
860 System.Console.WriteLine("Undef for " + ToString() + ", " + name);
861 #endif
862 }
863 public void DefineAlias(string name, string def)
864 {
865 DefineAlias(ruby.intern(name), ruby.intern(def));
866 }
867
868 public void DefineAlias(uint name, uint defid)
869 {
870 if (IsFrozen) ruby.ErrorFrozen("class/module");
871 if (name == defid) return;
872 if (this == ruby.cObject)
873 {
874 ruby.Secure(4);
875 }
876 RMetaObject origin;
877 RNode org = SearchMethod(defid, out origin);
878 if (org == null || org.body == null)
879 {
880 if (this is RModule)
881 {
882 org = ruby.cObject.SearchMethod(defid, out origin);
883 }
884 }
885 if (org == null || org.body == null)
886 {
887 printUndef(ruby.id2name(defid));
888 }
889 RNode body = org.body;
890 org.cnt++;
891 if (body is RNFBody)
892 {
893 defid = body.mid;
894 origin = body.orig;
895 body = body.head;
896 }
897 ruby.ClearCache(name);
898 lock (m_tbl.SyncRoot)
899 {
900 m_tbl[name] = new RNMethod(new RNFBody(body, defid, origin), org.noex);
901 }
902 }
903 protected void printUndef(uint id)
904 {
905 printUndef(ruby.id2name(id));
906 }
907 protected void printUndef(string name)
908 {
909 eNameError ex = new eNameError("undefned method '" + name +
910 "' for " + ((this is RModule) ? "module" : "class") + " '" + ToString());
911 throw ex;
912 }
913 internal RNode SearchMethod(uint id, out RMetaObject origin)
914 {
915 origin = null;
916 RMetaObject klass = this;
917 object o;
918 while (klass.m_tbl.lookup(id, out o) == false)
919 {
920 klass = klass.super;
921 if (klass == null) return null;
922 }
923 origin = klass;
924 return (RNode)o;
925 }
926 private void AddMethodCheck()
927 {
928 if (ruby.SafeLevel >= 4 && (this == ruby.cObject || IsTainted == false))
929 {
930 throw new SecurityException("Insecure: can't define method");
931 }
932 if (IsFrozen) ruby.ErrorFrozen("class/moodule");
933 }
934 internal void addMethod(string name, RMethod rm, int argc, NOEX noex)
935 {
936 addMethod(ruby.intern(name), rm, argc, noex);
937 }
938 internal void addMethod(uint name, RMethod rm, int argc, NOEX noex)
939 {
940 RNode func = new RNRFunc(ruby, rm, argc);
941 RNode body = new RNMethod(func, noex);
942 #if INIT_DEBUG
943 System.Console.WriteLine("AddMethod for " + ToString() + ", " + ruby.id2name(name) + "(" + name.ToString() + ")");
944 #endif
945 lock (m_tbl.SyncRoot)
946 {
947 m_tbl[name] = body;
948 }
949 }
950 internal void addMethod(uint mid, RNode defn, NOEX accs)
951 {
952 AddMethodCheck();
953 RNode body = new RNMethod(defn, accs);
954 lock (m_tbl.SyncRoot)
955 {
956 m_tbl[mid] = body;
957 }
958 }
959 internal void addMethod(string name, MethodInfo mi, NOEX accs)
960 {
961 addMethod(ruby.intern(name), mi, accs);
962 }
963 internal void addMethod(uint name, MethodInfo mi, NOEX accs)
964 {
965 if (mi == null)
966 {
967 ruby.warn("method '{0}' is missing", ruby.id2name(name));
968 }
969 AddMethodCheck();
970 RNode func = new RNCFunc(mi, ruby);
971 RNode body = new RNMethod(func, accs);
972 #if INIT_DEBUG
973 System.Console.WriteLine("AddMethod for " + ToString() + ", " + ruby.id2name(name) + "(" + name.ToString() + ")");
974 #endif
975 lock (m_tbl.SyncRoot)
976 {
977 m_tbl[name] = body;
978 }
979 }
980 internal RNode GetMethodBody(ref uint id, out RMetaObject klass, out NOEX noex)
981 {
982 noex = NOEX.PUBLIC;
983 klass = null;
984
985 RMetaObject org;
986 RNode body = SearchMethod(id, out org);
987 if (body == null || body.body == null)
988 {
989 ruby.SetCache(this, id);
990 return null;
991 }
992 ruby.SetCache(this, id, body, org);
993 noex = body.noex;
994 body = body.body;
995 if (body is RNFBody)
996 {
997 klass = body.orig;
998 id = body.mid;
999 body = body.head;
1000 }
1001 else
1002 {
1003 klass = org;
1004 }
1005 return body;
1006 }
1007 public RArray Constants
1008 {
1009 get {
1010 RArray ary = new RArray(ruby, true);
1011 for (RMetaObject mod = this; mod != null; mod = mod.super)
1012 {
1013 if (mod.iv_tbl == null) continue;
1014
1015 lock (mod.iv_tbl.SyncRoot)
1016 {
1017 foreach (DictionaryEntry ent in mod.iv_tbl)
1018 {
1019 if (Parser.is_const_id((uint)ent.Key))
1020 {
1021 string s = ruby.id2name((uint)ent.Key);
1022 if (ary.Contains(s) == false)
1023 ary.Add(s);
1024 }
1025 }
1026 }
1027 if (mod == ruby.cObject)
1028 {
1029 lock (ruby.class_tbl.SyncRoot)
1030 {
1031 foreach (DictionaryEntry ent in ruby.class_tbl)
1032 {
1033 if (Parser.is_const_id((uint)ent.Key))
1034 {
1035 string s = ruby.id2name((uint)ent.Key);
1036 if (ary.Contains(s) == false)
1037 ary.Add(s);
1038 }
1039 }
1040 }
1041 // autoload
1042 }
1043 }
1044 return ary;
1045 }
1046 }
1047
1048 internal object constants(RBasic r, params object[] args)
1049 {
1050 return ((RMetaObject)r).Constants;
1051 }
1052 internal object const_get(RBasic r, params object[] args)
1053 {
1054 uint id = ruby.ToID(args[0]);
1055 if (Parser.is_const_id(id) == false)
1056 throw new eNameError("wrong constant name " + ruby.id2name(id));
1057 return ConstGet(id);
1058 }
1059 internal object const_set(RBasic r, params object[] args)
1060 {
1061 uint id = ruby.ToID(args[0]);
1062 if (Parser.is_const_id(id) == false)
1063 throw new eNameError("wrong constant name " + ruby.id2name(id));
1064 ConstSet(id, args[1]);
1065 return args[1];
1066 }
1067 internal object is_const_defined(RBasic r, params object[] args)
1068 {
1069 uint id = ruby.ToID(args[0]);
1070 if (Parser.is_const_id(id) == false)
1071 throw new eNameError("wrong constant name " + ruby.id2name(id));
1072 return IsConstDefinedAt(id);
1073 }
1074 internal object remove_const(RBasic r, params object[] args)
1075 {
1076 uint id = ruby.ToID(args[0]);
1077 return RemoveConst(id);
1078 }
1079 internal static object remove_method(RBasic r, params object[] args)
1080 {
1081 ((RMetaObject)r).RemoveMethod(r.ruby.ToID(args[0]));
1082 return r;
1083 }
1084 internal static object undef_method(RBasic r, params object[] args)
1085 {
1086 ((RMetaObject)r).UndefMethod(args[0].ToString());
1087 return r;
1088 }
1089 internal static object alias_method(RBasic r, params object[] args)
1090 {
1091 NetRuby rb = r.ruby;
1092 ((RMetaObject)r).DefineAlias(rb.ToID(args[0]), rb.ToID(args[1]));
1093 return r;
1094 }
1095 internal static object define_method(RBasic r, params object[] args)
1096 {
1097 NetRuby ruby = r.ruby;
1098 uint id;
1099 object body;
1100 if (args.Length == 1)
1101 {
1102 id = ruby.ToID(args[0]);
1103 body = ruby.Lambda();
1104 }
1105 else if (args.Length == 2)
1106 {
1107 id = ruby.ToID(args[0]);
1108 body = ruby.InstanceOf(args[1]);
1109 ruby.bug("define_method(with 2 args) is not yet implemented");
1110 /*
1111 if (body.IsKindOf(ruby.cMethod))
1112 */
1113 }
1114 else
1115 {
1116 throw new eArgError(String.Format("worng # of arguments({0} for 1)",
1117 args.Length));
1118 }
1119 ruby.bug("Module::define_method is not yet implemented");
1120
1121 return null;
1122 }
1123 }
1124
1125 public class RModule : RMetaObject, ICloneable
1126 {
1127 public RModule(NetRuby rb)
1128 : base(rb, null, null, rb.cModule)
1129 {
1130 }
1131 public RModule(NetRuby rb, string name)
1132 : base(rb, name, null, rb.cModule)
1133 {
1134 if (name != null)
1135 {
1136 uint id = rb.intern(name);
1137 rb.class_tbl.Add(id, this);
1138 }
1139 }
1140 public RModule(NetRuby rb, string name, RMetaObject spr)
1141 : base(rb, name, spr, rb.cModule)
1142 {
1143 if (name != null)
1144 {
1145 uint id = rb.intern(name);
1146 rb.class_tbl.Add(id, this);
1147 }
1148 }
1149
1150 internal RModule(RModule o) :
1151 base(o)
1152 {
1153 }
1154
1155 public override object Clone()
1156 {
1157 return new RModule(this);
1158 }
1159
1160 static public RMetaObject CheckModule(NetRuby ruby, RThread th, uint cn)
1161 {
1162 RMetaObject rClass = th.OuterClass;
1163 if ((rClass == ruby.cObject) && ruby.IsAutoloadDefined(cn))
1164 {
1165 ruby.AutoLoad(cn);
1166 }
1167 RMetaObject module = null;
1168 if (rClass.IsConstDefinedAt(cn))
1169 {
1170 module = (RMetaObject)rClass.ConstGet(cn);
1171 }
1172 if (module != null)
1173 {
1174 if (module is RModule == false)
1175 {
1176 throw new eTypeError(ruby.id2name(cn) + " is not a module");
1177 }
1178 if (th.safeLevel >= 4)
1179 {
1180 throw new SecurityException("extending module prohibited");
1181 }
1182 }
1183 return module;
1184 }
1185 }
1186
1187 public class RClass : RMetaObject, ICloneable
1188 {
1189 public RClass(NetRuby rb, string name, RMetaObject spr)
1190 : base(rb, name, spr, rb.cClass)
1191 {
1192 }
1193 public RClass(NetRuby rb, RMetaObject spr)
1194 : base(rb, null, spr, rb.cClass)
1195 {
1196 }
1197 internal RClass(RClass o) :
1198 base(o)
1199 {
1200 }
1201 static public RClass CheckClass(NetRuby ruby, RThread th, uint cn, RMetaObject spr)
1202 {
1203 RMetaObject rc = th.OuterClass;
1204 if ((rc == ruby.cObject) && ruby.IsAutoloadDefined(cn))
1205 {
1206 ruby.AutoLoad(cn);
1207 }
1208 RBasic ks = null;
1209 RClass klass = null;
1210 if (rc.IsConstDefinedAt(cn))
1211 {
1212 ks = (RBasic)rc.ConstGet(cn);
1213 }
1214 bool ovrd = true;
1215 if (ks != null)
1216 {
1217 ovrd = false;
1218 if (ks is RClass == false)
1219 {
1220 throw new eTypeError(ruby.id2name(cn) + " is not a class");
1221 }
1222 klass = (RClass)ks;
1223 if (spr != null)
1224 {
1225 RBasic tmp = klass.super.ClassReal;
1226 if (tmp != spr)
1227 {
1228 ovrd = true;
1229 }
1230 }
1231 if (ovrd == false && th.safeLevel >= 4)
1232 {
1233 throw new SecurityException("extending class prohibited");
1234 }
1235 }
1236 if (ovrd)
1237 {
1238 klass = null;
1239 }
1240 return klass;
1241 }
1242
1243 public override object Clone()
1244 {
1245 return new RClass(this);
1246 }
1247
1248 public virtual RBasic NewInstance(object[] argv)
1249 {
1250 return NewInstance(argv, this);
1251 }
1252 static public RBasic NewInstance(object[] argv, RMetaObject meta)
1253 {
1254 if (meta is RSingletonClass)
1255 {
1256 throw new eTypeError("can't create instance of virtual class");
1257 }
1258 NetRuby ruby = meta.ruby;
1259 RObject obj = new RObject(ruby, meta);
1260 ruby.CallInit(obj, argv);
1261 return obj;
1262 }
1263
1264 public RClass DefineNewClass(uint cn, string name, RMetaObject spr, RMetaObject outer)
1265 {
1266 klass = new RSingletonClass(spr.klass);
1267 klass.AttachSingleton(this);
1268 ruby.Funcall(spr, "inherited", this);
1269 SetClassPath(outer, name);
1270 outer.ConstSet(cn, this);
1271 return this;
1272 }
1273
1274 public RClass DefineClass(string name, RMetaObject spr)
1275 {
1276 klass = new RSingletonClass(spr.klass);
1277 klass.AttachSingleton(this);
1278 ruby.Funcall(spr, "inherited", this);
1279 lock (ruby.class_tbl.SyncRoot)
1280 {
1281 ruby.class_tbl[ruby.intern(name)] = this;
1282 }
1283 return this;
1284 }
1285
1286 static public RClass ClassNew(NetRuby ruby, RMetaObject spr, object[] o)
1287 {
1288 if (spr == null)
1289 {
1290 spr = ruby.cObject;
1291 }
1292 else if (spr is RSingletonClass)
1293 {
1294 throw new eTypeError("can't make subclass of virtual class");
1295 }
1296 RClass klass = new RClass(ruby, spr);
1297 klass.klass = new RSingletonClass(spr.klass);
1298 klass.klass.AttachSingleton(klass);
1299 ruby.CallInit(klass, o);
1300 ruby.Funcall(spr, "inherited", new object[1] { klass });
1301 return klass;
1302 }
1303 public RMetaObject Superclass
1304 {
1305 get {
1306 RMetaObject spr = super;
1307 while (spr is RIncClass)
1308 {
1309 spr = spr.super;
1310 }
1311 if (spr == null)
1312 return null;
1313 return spr;
1314 }
1315 }
1316 internal static object Inherited(RBasic rb, params object[] o)
1317 {
1318 throw new eTypeError("can't make subclass of Class");
1319 }
1320 }
1321
1322 public class RSingletonClass : RClass
1323 {
1324 internal RSingletonClass(RMetaObject o)
1325 : base(o.ruby, o)
1326 {
1327 }
1328 public override bool IsSingleton
1329 {
1330 get { return true; }
1331 }
1332 public override void AttachSingleton(RObjectBase obj)
1333 {
1334 if (iv_tbl == null)
1335 {
1336 iv_tbl = new st_table();
1337 }
1338 iv_tbl[ruby.intern("__attached__")] = obj;
1339 }
1340 }
1341
1342 public class RIncClass : RClass
1343 {
1344 internal RIncClass(RMetaObject module, RMetaObject sp) :
1345 base(module.ruby, sp)
1346 {
1347 if (module.iv_tbl == null)
1348 {
1349 module.iv_tbl = new st_table();
1350 }
1351 iv_tbl = module.iv_tbl;
1352 m_tbl = module.m_tbl;
1353 if (module is RIncClass)
1354 {
1355 klass = module.klass;
1356 }
1357 else
1358 {
1359 klass = module;
1360 }
1361 }
1362 }
1363 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26