| 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 |
} |