| | 1208 | /* |
| | 1209 | 'variables [word! block!] |
| | 1210 | series [series!] |
| | 1211 | body [block!] |
| | 1212 | */ |
| | 1213 | //see orForeachNative |
| | 1214 | |
| | 1215 | void orRemoveEachNative( OValue* a1 ) |
| | 1216 | { |
| | 1217 | int rlen; |
| | 1218 | int vlen; |
| | 1219 | OBlock* blk; |
| | 1220 | OValue* wval; |
| | 1221 | OContext ctx; |
| | 1222 | OValue* a2 = a1 + 1; |
| | 1223 | OIndex serN = a2->index; |
| | 1224 | OIndex si = a2->series.it; |
| | 1225 | //: |
| | 1226 | OIndex sdest = 0;//in second buffer |
| | 1227 | OIndex sorig = si; |
| | 1228 | OIndex ssrc; |
| | 1229 | |
| | 1230 | OIndex send; |
| | 1231 | OIndex body = (a1 + 2)->index; |
| | 1232 | OIndex bi = (a1 + 2)->series.it; |
| | 1233 | |
| | 1234 | // Binding a copy of the body to a private context is horribly |
| | 1235 | // expensive but what choice do we have? |
| | 1236 | // Still, 'foreach is faster than 'forall (probably because using paths |
| | 1237 | // is so slow). |
| | 1238 | |
| | 1239 | orRefAvailErr( 4 ) |
| | 1240 | |
| | 1241 | // Must hold body & a2 in case orMakeContext() or orCopyBlock() trigger |
| | 1242 | // recycle. |
| | 1243 | orRefPush( OT_BLOCK, body ); |
| | 1244 | orRefPush( a2->type, a2->index ); |
| | 1245 | |
| | 1246 | if( a1->type == OT_BLOCK ) |
| | 1247 | { |
| | 1248 | OValue* it; |
| | 1249 | OValue* end; |
| | 1250 | |
| | 1251 | blk = orBLOCK(a1); |
| | 1252 | |
| | 1253 | orRefPush( OT_BLOCK, a1->index ); |
| | 1254 | orMakeContext( &ctx, blk->used - a1->series.it ); |
| | 1255 | orRefPop( 1 ); |
| | 1256 | |
| | 1257 | it = blk->values + a1->series.it; |
| | 1258 | end = blk->values + blk->used; |
| | 1259 | |
| | 1260 | blk = orBlockPtr( ctx.wblkN ); |
| | 1261 | while( it != end ) |
| | 1262 | { |
| | 1263 | if( it->type == OT_WORD ) |
| | 1264 | { |
| | 1265 | orInternA( blk, it->word.atom ); |
| | 1266 | } |
| | 1267 | else |
| | 1268 | { |
| | 1269 | orError( "Invalid foreach argument" ); |
| | 1270 | orRefPop( 2 ); |
| | 1271 | return; |
| | 1272 | } |
| | 1273 | ++it; |
| | 1274 | } |
| | 1275 | |
| | 1276 | } |
| | 1277 | else |
| | 1278 | { |
| | 1279 | orMakeContext( &ctx, 1 ); |
| | 1280 | orInternA( orBlockPtr( ctx.wblkN ), a1->word.atom ); |
| | 1281 | } |
| | 1282 | |
| | 1283 | orRefPush( OT_BLOCK, ctx.wblkN ); |
| | 1284 | orRefPush( OT_BLOCK, ctx.vblkN ); |
| | 1285 | |
| | 1286 | blk = orBlockPtr( ctx.vblkN ); |
| | 1287 | wval = blk->values; |
| | 1288 | vlen = blk->avail; |
| | 1289 | |
| | 1290 | blk = orCopyBlock( body, bi, 1 ); |
| | 1291 | body = orBlockN( blk ); |
| | 1292 | bi = 0; |
| | 1293 | orBind( blk, &ctx ); |
| | 1294 | |
| | 1295 | // |
| | 1296 | // the real loop |
| | 1297 | // |
| | 1298 | |
| | 1299 | switch( a2->type ) |
| | 1300 | { |
| | 1301 | case OT_BLOCK: |
| | 1302 | case OT_PAREN: |
| | 1303 | case OT_PATH: |
| | 1304 | { |
| | 1305 | blk = orBlockPtr( serN ); |
| | 1306 | OValue *keept = calloc(blk->used,sizeof(OValue)); |
| | 1307 | send = blk->used; |
| | 1308 | |
| | 1309 | if( vlen > 1 ) |
| | 1310 | send -= vlen - 1; |
| | 1311 | |
| | 1312 | while( si < send ) |
| | 1313 | { |
| | 1314 | memCpy( wval, blk->values + si, vlen * sizeof(OValue) ); |
| | 1315 | |
| | 1316 | //: |
| | 1317 | orEvalBlock( orBlockPtr( body ), bi ); |
| | 1318 | if( orErrorThrown ) |
| | 1319 | goto error; |
| | 1320 | blk = orBlockPtr( serN ); // Reacquire. |
| | 1321 | //: |
| | 1322 | if( !orIfTrue(orRESULT)){ |
| | 1323 | memCpy( keept + sdest, blk->values + si, vlen * sizeof(OValue) ); |
| | 1324 | sdest += vlen; |
| | 1325 | } |
| | 1326 | si += vlen; //:moved |
| | 1327 | } |
| | 1328 | |
| | 1329 | //handle rest, if less values then loopvars |
| | 1330 | |
| | 1331 | if( si < blk->used ) |
| | 1332 | { |
| | 1333 | rlen = blk->used - si; |
| | 1334 | |
| | 1335 | memCpy( wval, blk->values + si, rlen * sizeof(OValue) ); |
| | 1336 | wval += rlen; |
| | 1337 | |
| | 1338 | while( rlen < vlen ) |
| | 1339 | { |
| | 1340 | orSetTF( wval, OT_NONE ); |
| | 1341 | ++wval; |
| | 1342 | ++rlen; |
| | 1343 | } |
| | 1344 | |
| | 1345 | orEvalBlock( orBlockPtr( body ), bi ); |
| | 1346 | if( orErrorThrown ) |
| | 1347 | goto error; |
| | 1348 | //: |
| | 1349 | blk = orBlockPtr( serN ); // Reacquire. |
| | 1350 | if( !orIfTrue(orRESULT)){ |
| | 1351 | memCpy( keept + sdest, blk->values + si, (blk->used - si) * sizeof(OValue) ); |
| | 1352 | sdest += blk->used - si; |
| | 1353 | } |
| | 1354 | } |
| | 1355 | |
| | 1356 | //: return block |
| | 1357 | orResultBLOCK( serN ); |
| | 1358 | blk->used = sorig + sdest; |
| | 1359 | orRESULT->series.it = sorig; |
| | 1360 | memCpy( blk->values + sorig, keept, sdest * sizeof(OValue)); |
| | 1361 | free(keept); |
| | 1362 | } |
| | 1363 | break; |
| | 1364 | |
| | 1365 | case OT_STRING: |
| | 1366 | case OT_FILE: |
| | 1367 | case OT_ISSUE: |
| | 1368 | case OT_TAG: |
| | 1369 | { |
| | 1370 | OString* str = orStringPtr( serN ); |
| | 1371 | char *keept = malloc(str->used); |
| | 1372 | send = str->used; |
| | 1373 | |
| | 1374 | orSetTF( wval, OT_CHAR ); |
| | 1375 | |
| | 1376 | if( vlen > 1 ) |
| | 1377 | { |
| | 1378 | send -= vlen - 1; |
| | 1379 | |
| | 1380 | for( rlen = 1; rlen < vlen; ++rlen ) |
| | 1381 | orSetTF( (wval + rlen), OT_CHAR ); |
| | 1382 | } |
| | 1383 | |
| | 1384 | while( si < send ) |
| | 1385 | { |
| | 1386 | ssrc = si; |
| | 1387 | for( rlen = 0; rlen < vlen; ++rlen ) |
| | 1388 | (wval + rlen)->integer = str->charArray[ si++ ]; |
| | 1389 | |
| | 1390 | orEvalBlock( orBlockPtr( body ), bi ); |
| | 1391 | if( orErrorThrown ) |
| | 1392 | goto error; |
| | 1393 | str = orStringPtr( serN ); // Reacquire. |
| | 1394 | //: |
| | 1395 | if( !orIfTrue(orRESULT)){ |
| | 1396 | strNCpy( keept + sdest, str->charArray + ssrc, vlen ); |
| | 1397 | sdest += vlen; |
| | 1398 | } |
| | 1399 | } |
| | 1400 | |
| | 1401 | if( si < str->used ) |
| | 1402 | { |
| | 1403 | rlen = str->used - si; |
| | 1404 | ssrc = si; |
| | 1405 | |
| | 1406 | while( si < str->used ) |
| | 1407 | { |
| | 1408 | wval->integer = str->charArray[ si++ ]; |
| | 1409 | ++wval; |
| | 1410 | } |
| | 1411 | |
| | 1412 | while( rlen < vlen ) |
| | 1413 | { |
| | 1414 | orSetTF( wval, OT_NONE ); |
| | 1415 | ++wval; |
| | 1416 | ++rlen; |
| | 1417 | } |
| | 1418 | |
| | 1419 | orEvalBlock( orBlockPtr( body ), bi ); |
| | 1420 | if( orErrorThrown ) |
| | 1421 | goto error; |
| | 1422 | //: |
| | 1423 | str = orStringPtr( serN ); // Reacquire. |
| | 1424 | if( !orIfTrue(orRESULT)){ |
| | 1425 | strNCpy( keept + sdest, str->charArray + ssrc, (str->used - ssrc) ); |
| | 1426 | sdest += str->used - ssrc; |
| | 1427 | } |
| | 1428 | } |
| | 1429 | //: return string |
| | 1430 | orResultSTRING( serN ); |
| | 1431 | str->used = sorig + sdest; |
| | 1432 | orRESULT->series.it = sorig; |
| | 1433 | strNCpy( str->charArray + sorig, keept, str->used ); |
| | 1434 | free(keept); |
| | 1435 | } |
| | 1436 | break; |
| | 1437 | |
| | 1438 | default: |
| | 1439 | orError("remove-each for this type not implemented"); |
| | 1440 | |
| | 1441 | |
| | 1442 | /* case OT_LIST: */ |
| | 1443 | /* if( a1->type == OT_BLOCK ) */ |
| | 1444 | /* { */ |
| | 1445 | /* orError( "foreach block! list! not implemented" ); */ |
| | 1446 | /* break; */ |
| | 1447 | /* } */ |
| | 1448 | |
| | 1449 | /* orResultNONE; */ |
| | 1450 | |
| | 1451 | /* if( a2->series.index ) */ |
| | 1452 | /* { */ |
| | 1453 | /* OValue* begin; */ |
| | 1454 | /* OValue* it; */ |
| | 1455 | |
| | 1456 | /* blk = orBLOCK(a2); */ |
| | 1457 | /* begin = blk->values; */ |
| | 1458 | /* it = begin + a2->series.index; */ |
| | 1459 | |
| | 1460 | /* while( it->LIST_NEXT > 0 ) */ |
| | 1461 | /* { */ |
| | 1462 | /* orCopyV( wval, it[1] ); */ |
| | 1463 | |
| | 1464 | /* orEvalBlock( orBlockPtr( body ), bi ); */ |
| | 1465 | /* if( orErrorThrown ) */ |
| | 1466 | /* goto error; */ |
| | 1467 | |
| | 1468 | /* //blk = orBlockPtr( serN ); // Reacquire. */ |
| | 1469 | /* //orListNextNode( blk, it ); */ |
| | 1470 | /* it = begin + it->LIST_NEXT; */ |
| | 1471 | /* } */ |
| | 1472 | /* } */ |
| | 1473 | /* break; */ |
| | 1474 | } |
| | 1475 | |
| | 1476 | free_private: |
| | 1477 | |
| | 1478 | orFreeBlock( body ); |
| | 1479 | orFreeBlock( ctx.wblkN ); |
| | 1480 | orFreeBlock( ctx.vblkN ); |
| | 1481 | goto pop; |
| | 1482 | |
| | 1483 | error: |
| | 1484 | |
| | 1485 | if( orErrorIsType(OR_ERROR_BREAK) ) |
| | 1486 | { |
| | 1487 | orErrorClear; |
| | 1488 | orSetTF( a1, OT_UNSET ); |
| | 1489 | goto free_private; |
| | 1490 | } |
| | 1491 | |
| | 1492 | // Cannot free body block if error is thrown and orError->block == body. |
| | 1493 | |
| | 1494 | pop: |
| | 1495 | |
| | 1496 | orRefPop( 4 ); |
| | 1497 | } |
| | 1498 | |