| 219 | | |
| 220 | | |
| 221 | | #if 0 |
| 222 | | /** |
| 223 | | */ |
| 224 | | void orMakeContext( OContext* ctx, int size ) |
| 225 | | { |
| 226 | | ctx->wblkN = orBlockN( orMakeBlock( size ) ); |
| 227 | | orRefPush( OT_BLOCK, ctx->wblkN ); |
| 228 | | ctx->vblkN = orBlockN( orMakeBlock( size ) ); |
| 229 | | orRefPop( 1 ); |
| 230 | | } |
| 231 | | |
| 232 | | |
| 233 | | static void internSetWords( OContext* ctx, UCell* it, UCell* end ) |
| 234 | | { |
| 235 | | int wrdN; |
| 236 | | OBlock* wordBlk = orBlockPtr( ctx->wblkN ); |
| 237 | | |
| 238 | | while( it != end ) |
| 239 | | { |
| 240 | | if( it->type == OT_SETWORD ) |
| 241 | | { |
| 242 | | // Word might be redefined mulitple times so we have to |
| 243 | | // orLookup() first. |
| 244 | | wrdN = orLookup( ctx, it->word.atom ); |
| 245 | | if( wrdN < 0 ) |
| 246 | | wrdN = orInternA( wordBlk, it->word.atom ); |
| 247 | | } |
| 248 | | ++it; |
| 249 | | } |
| 250 | | } |
| 251 | | |
| 252 | | |
| 253 | | static void unsetValues( UCell* it, UCell* end ) |
| 254 | | { |
| 255 | | while( it != end ) |
| 256 | | { |
| 257 | | orSetTF( it, OT_UNSET ); |
| 258 | | ++it; |
| 259 | | } |
| 260 | | } |
| 261 | | |
| 262 | | |
| 263 | | /** |
| 264 | | Returns 0 if fails. |
| 265 | | */ |
| 266 | | int orMakeObject( OBlock* pblk, int blkI, OContext* ctx ) |
| 267 | | { |
| 268 | | OBlock* wblk; |
| 269 | | OBlock* vblk; |
| 270 | | UCell* it; |
| 271 | | UCell* end; |
| 272 | | OIndex blkN; |
| 273 | | int wcount; |
| 274 | | |
| 275 | | |
| 276 | | wcount = 0; |
| 277 | | it = pblk->values + blkI; |
| 278 | | end = pblk->values + pblk->used; |
| 279 | | while( it != end ) |
| 280 | | { |
| 281 | | // This could be optimized to not count duplicate words. |
| 282 | | if( it->type == OT_SETWORD ) |
| 283 | | ++wcount; |
| 284 | | ++it; |
| 285 | | } |
| 286 | | |
| 287 | | blkN = orBlockN( pblk ); |
| 288 | | orRefPush( OT_BLOCK, blkN ); |
| 289 | | orMakeContext( ctx, wcount + 1 ); |
| 290 | | |
| 291 | | // re-acquire |
| 292 | | wblk = orBlockPtr( ctx->wblkN ); |
| 293 | | vblk = orBlockPtr( ctx->vblkN ); |
| 294 | | pblk = orBlockPtr( blkN ); |
| 295 | | |
| 296 | | // Intern words. |
| 297 | | it = pblk->values + blkI; |
| 298 | | orInternA( wblk, orEnv->atom_self ); |
| 299 | | internSetWords( ctx, it, end ); |
| 300 | | |
| 301 | | vblk->used = wblk->used; |
| 302 | | it = vblk->values; |
| 303 | | orSetTF( it, OT_OBJECT ); |
| 304 | | it->ctx = *ctx; |
| 305 | | unsetValues( it + 1, it + vblk->used ); |
| 306 | | |
| 307 | | orRefPush( OT_BLOCK, ctx->wblkN ); |
| 308 | | orRefPush( OT_BLOCK, ctx->vblkN ); |
| 309 | | |
| 310 | | // Bind prototype block. |
| 311 | | orBind( pblk, ctx ); |
| 312 | | |
| 313 | | pblk = orBlockPtr( blkN ); // re-acquire |
| 314 | | orEvalBlock( pblk, blkI ); |
| 315 | | |
| 316 | | orRefPop( 3 ); |
| 317 | | |
| 318 | | if( orErrorThrown ) |
| 319 | | return 0; |
| 320 | | return 1; |
| 321 | | } |
| 322 | | |
| 323 | | |
| 324 | | /* |
| 325 | | Similar to deep orCopyBlock() but OT_FUNCTION bodies are also copied. |
| 326 | | */ |
| 327 | | static void copyObjectValues( UCell* copy, UCell* it, int n ) |
| 328 | | { |
| 329 | | UCell* end = it + n; |
| 330 | | while( it != end ) |
| 331 | | { |
| 332 | | orCopyV( copy, *it ); |
| 333 | | |
| 334 | | if( (it->type == OT_BLOCK) || (it->type == OT_PAREN) ) |
| 335 | | { |
| 336 | | OBlock* blk = orCopyBlock( it->index, it->series.index, 1 ); |
| 337 | | orSetSeries( copy, orBlockN(blk), 0 ); |
| 338 | | } |
| 339 | | else if( it->type == OT_FUNCTION ) |
| 340 | | { |
| 341 | | OBlock* blk = orCopyBlock( it->func.bodyBlk, 0, 1 ); |
| 342 | | copy->func.bodyBlk = orBlockN(blk); |
| 343 | | } |
| 344 | | |
| 345 | | ++copy; |
| 346 | | ++it; |
| 347 | | } |
| 348 | | } |
| 349 | | |
| 350 | | |
| 351 | | /** |
| 352 | | Orig & clone must not point to the same OContext. |
| 353 | | */ |
| 354 | | void orCloneObject( const OContext* orig, OContext* clone ) |
| 355 | | { |
| 356 | | int size; |
| 357 | | OBlock* cblk; |
| 358 | | OBlock* vblk; |
| 359 | | UCell* val; |
| 360 | | |
| 361 | | |
| 362 | | vblk = orBlockPtr( orig->vblkN ); |
| 363 | | size = vblk->used; |
| 364 | | cblk = orMakeBlock( size ); |
| 365 | | cblk->used = size; |
| 366 | | |
| 367 | | clone->wblkN = orig->wblkN; |
| 368 | | clone->vblkN = orBlockN( cblk ); |
| 369 | | |
| 370 | | // Point self to the new object. |
| 371 | | assert( cblk->avail ); |
| 372 | | val = cblk->values; |
| 373 | | orSetTF( val, OT_OBJECT ); |
| 374 | | val->ctx = *clone; |
| 375 | | |
| 376 | | // Must set cblk->used and clear values in case GC called in |
| 377 | | // copyObjectValues(). |
| 378 | | unsetValues( val + 1, val + size ); |
| 379 | | |
| 380 | | orRefPush( OT_BLOCK, clone->vblkN ); |
| 381 | | vblk = orBlockPtr( orig->vblkN ); // re-acquire |
| 382 | | copyObjectValues( cblk->values + 1, vblk->values + 1, size - 1 ); |
| 383 | | orRefPop( 1 ); |
| 384 | | |
| 385 | | cblk = orBlockPtr( clone->vblkN ); // re-acquire |
| 386 | | orBind( cblk, clone ); |
| 387 | | } |
| 388 | | |
| 389 | | |
| 390 | | /** |
| 391 | | Clones the orig context if no new members are added in the block. |
| 392 | | Returns new context number or -1 if fails. |
| 393 | | */ |
| 394 | | int orMakeClone( const OContext* orig, OContext* clone, |
| 395 | | OIndex blkN, OIndex blkI ) |
| 396 | | { |
| 397 | | OBlock* pblk; |
| 398 | | OBlock* vblk; |
| 399 | | OBlock* cblk; |
| 400 | | UCell* it; |
| 401 | | UCell* end; |
| 402 | | int wcount; |
| 403 | | int origUsed; |
| 404 | | |
| 405 | | |
| 406 | | orRefPush( OT_BLOCK, blkN ); |
| 407 | | |
| 408 | | vblk = orBlockPtr( orig->vblkN ); |
| 409 | | wcount = origUsed = vblk->used; |
| 410 | | |
| 411 | | pblk = orBlockPtr( blkN ); |
| 412 | | it = pblk->values + blkI; |
| 413 | | end = pblk->values + pblk->used; |
| 414 | | while( it != end ) |
| 415 | | { |
| 416 | | if( it->type == OT_SETWORD ) |
| 417 | | { |
| 418 | | if( orLookup( orig, it->word.atom ) < 0 ) |
| 419 | | ++wcount; |
| 420 | | } |
| 421 | | ++it; |
| 422 | | } |
| 423 | | |
| 424 | | if( wcount == origUsed ) |
| 425 | | { |
| 426 | | orCloneObject( orig, clone ); |
| 427 | | } |
| 428 | | else |
| 429 | | { |
| 430 | | orMakeContext( clone, wcount ); |
| 431 | | |
| 432 | | // Re-acquire. |
| 433 | | pblk = orBlockPtr( blkN ); |
| 434 | | cblk = orBlockPtr( clone->wblkN ); |
| 435 | | vblk = orBlockPtr( orig->wblkN ); |
| 436 | | |
| 437 | | assert( cblk->avail ); |
| 438 | | memCpy( cblk->values, vblk->values, sizeof(UCell) * origUsed ); |
| 439 | | cblk->used = origUsed; |
| 440 | | internSetWords( clone, pblk->values + blkI, end ); |
| 441 | | wcount = cblk->used; |
| 442 | | |
| 443 | | |
| 444 | | vblk = orBlockPtr( orig->vblkN ); |
| 445 | | cblk = orBlockPtr( clone->vblkN ); |
| 446 | | cblk->used = wcount; |
| 447 | | |
| 448 | | // Point self to the new object. |
| 449 | | it = cblk->values; |
| 450 | | orSetTF( it, OT_OBJECT ); |
| 451 | | it->ctx = *clone; |
| 452 | | |
| 453 | | unsetValues( it + 1, it + wcount ); |
| 454 | | |
| 455 | | orRefPush( OT_BLOCK, clone->wblkN ); |
| 456 | | orRefPush( OT_BLOCK, clone->vblkN ); |
| 457 | | copyObjectValues( it + 1, vblk->values + 1, origUsed - 1 ); |
| 458 | | orRefPop( 2 ); |
| 459 | | } |
| 460 | | |
| 461 | | orBind( orBlockPtr( blkN ), clone ); |
| 462 | | |
| 463 | | orRefPop( 1 ); |
| 464 | | |
| 465 | | orRefPush( OT_BLOCK, clone->wblkN ); |
| 466 | | orRefPush( OT_BLOCK, clone->vblkN ); |
| 467 | | orEvalBlock( orBlockPtr( blkN ), blkI ); |
| 468 | | orRefPop( 2 ); |
| 469 | | |
| 470 | | if( orErrorThrown ) |
| 471 | | return 0; |
| 472 | | |
| 473 | | return 1; |
| 474 | | } |
| 475 | | #endif |