| | 211 | } |
| | 212 | |
| | 213 | |
| | 214 | extern void ur_copyCells( UCell* src, UCell* srcEnd, UCell* dest ); |
| | 215 | |
| | 216 | |
| | 217 | /* |
| | 218 | Create context from initializer block. |
| | 219 | protoCtx may be zero. |
| | 220 | Caller must hold init and protoCtx (if non-zero) from GC. |
| | 221 | */ |
| | 222 | static void _makeContextProto( UContext* res, const UCell* init, |
| | 223 | const UCell* protoCtx ) |
| | 224 | { |
| | 225 | if( init && ur_is(init, UT_BLOCK) ) |
| | 226 | { |
| | 227 | int size = 0; |
| | 228 | UBlock* blk; |
| | 229 | UCell* it; |
| | 230 | UCell* start; |
| | 231 | UCell* end; |
| | 232 | |
| | 233 | blk = ur_blockPtr( init->series.n ); |
| | 234 | UR_ITER_BLOCK( start, end, blk, init ) |
| | 235 | |
| | 236 | it = start; |
| | 237 | |
| | 238 | if( protoCtx ) |
| | 239 | { |
| | 240 | // Check if prototype must be extended with new words. |
| | 241 | |
| | 242 | while( it != end ) |
| | 243 | { |
| | 244 | if( ur_is(it, UT_SETWORD) ) |
| | 245 | { |
| | 246 | if( ur_lookup(protoCtx, ur_atom(it)) < 0 ) |
| | 247 | ++size; |
| | 248 | } |
| | 249 | ++it; |
| | 250 | } |
| | 251 | |
| | 252 | if( size ) |
| | 253 | { |
| | 254 | UIndex pwN; |
| | 255 | UIndex pvN; |
| | 256 | UCell* rend; |
| | 257 | UBlock* rblk; |
| | 258 | |
| | 259 | // Keep indices in case protoCtx == res |
| | 260 | pwN = protoCtx->ctx.wordBlk; |
| | 261 | pvN = protoCtx->ctx.valBlk; |
| | 262 | |
| | 263 | blk = ur_blockPtr( pvN ); |
| | 264 | size += blk->used; |
| | 265 | |
| | 266 | ur_makeContext( res, size ); |
| | 267 | |
| | 268 | // Copy value block. |
| | 269 | |
| | 270 | blk = ur_blockPtr( pvN ); // re-acquire |
| | 271 | rblk = ur_blockPtr( res->ctx.valBlk ); |
| | 272 | rblk->used = size; |
| | 273 | ur_copyCells( blk->ptr.cells, |
| | 274 | blk->ptr.cells + blk->used, |
| | 275 | rblk->ptr.cells ); |
| | 276 | |
| | 277 | // Init new words to none. |
| | 278 | |
| | 279 | it = rblk->ptr.cells + blk->used; |
| | 280 | rend = rblk->ptr.cells + size; |
| | 281 | while( it != rend ) |
| | 282 | { |
| | 283 | ur_setType( it, UT_NONE ); |
| | 284 | ++it; |
| | 285 | } |
| | 286 | |
| | 287 | // Copy word block. |
| | 288 | |
| | 289 | blk = ur_blockPtr( pwN ); |
| | 290 | rblk = ur_blockPtr( res->ctx.wordBlk ); |
| | 291 | rblk->used = blk->used; |
| | 292 | ur_copyCells( blk->ptr.cells, |
| | 293 | blk->ptr.cells + blk->used, |
| | 294 | rblk->ptr.cells ); |
| | 295 | } |
| | 296 | else |
| | 297 | { |
| | 298 | // No new words in init block; clone to share word block. |
| | 299 | |
| | 300 | if( res != protoCtx ) |
| | 301 | { |
| | 302 | ur_copyCell( res, *protoCtx ); |
| | 303 | } |
| | 304 | ur_clone( res, size, 1 ); |
| | 305 | return; |
| | 306 | } |
| | 307 | } |
| | 308 | else |
| | 309 | { |
| | 310 | while( it != end ) |
| | 311 | { |
| | 312 | if( ur_is(it, UT_SETWORD) ) |
| | 313 | ++size; |
| | 314 | ++it; |
| | 315 | } |
| | 316 | |
| | 317 | ur_makeContext( res, size ); |
| | 318 | } |
| | 319 | |
| | 320 | it = start; |
| | 321 | while( it != end ) |
| | 322 | { |
| | 323 | if( ur_is(it, UT_SETWORD) ) |
| | 324 | ur_internWord( res, it->word.atom ); |
| | 325 | ++it; |
| | 326 | } |
| | 327 | } |
| 545 | | static void _makeContextProto( UContext* ctx, const UCell* proto ) |
| 546 | | { |
| 547 | | if( proto && ur_is(proto, UT_BLOCK) ) |
| 548 | | { |
| 549 | | int size = 0; |
| 550 | | UBlock* blk; |
| 551 | | UCell* it; |
| 552 | | UCell* start; |
| 553 | | UCell* end; |
| 554 | | |
| 555 | | blk = ur_blockPtr( proto->series.n ); |
| 556 | | UR_ITER_BLOCK( start, end, blk, proto ) |
| 557 | | |
| 558 | | it = start; |
| 559 | | while( it != end ) |
| 560 | | { |
| 561 | | if( ur_is(it, UT_SETWORD) ) |
| 562 | | ++size; |
| 563 | | ++it; |
| 564 | | } |
| 565 | | |
| 566 | | ur_makeContext( ctx, size ); |
| 567 | | |
| 568 | | it = start; |
| 569 | | while( it != end ) |
| 570 | | { |
| 571 | | if( ur_is(it, UT_SETWORD) ) |
| 572 | | ur_internWord( ctx, it->word.atom ); |
| 573 | | ++it; |
| 574 | | } |
| 575 | | } |
| 576 | | } |
| 577 | | |
| 578 | | |