2105 lines
46 KiB
C
2105 lines
46 KiB
C
/* n-list.c
|
|
|
|
Copyright (C) 2016 Lutz Mueller
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
#include "newlisp.h"
|
|
#include "protos.h"
|
|
|
|
extern SYMBOL * starSymbol;
|
|
extern SYMBOL * plusSymbol;
|
|
extern CELL * countCell;
|
|
|
|
extern CELL * firstFreeCell;
|
|
|
|
/* following used in count, difference, intersect, unique and sort 8.6.2 */
|
|
CELL * * listToSortedVector(CELL * list, ssize_t * length, CELL * func, int indexFlag);
|
|
CELL * resortVectorToList(CELL * * vector, ssize_t length);
|
|
void binsort(CELL * * x, ssize_t n, CELL * pCell);
|
|
|
|
|
|
CELL * p_map(CELL * params)
|
|
{
|
|
CELL * argsPtr;
|
|
CELL * arg;
|
|
CELL * argCell;
|
|
CELL * funcPtr;
|
|
CELL * cell;
|
|
CELL * expr;
|
|
CELL * results;
|
|
CELL * res;
|
|
CELL * cellIdx;
|
|
UINT * resultIdxSave;
|
|
|
|
funcPtr = evaluateExpression(params);
|
|
|
|
/* get first of argument lists */
|
|
params = getEvalDefault(params->next, &cell);
|
|
|
|
argsPtr = cell = (cell->type == CELL_ARRAY) ?
|
|
arrayList(cell, FALSE) : copyCell(cell);
|
|
|
|
if(!isList(cell->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, cell));
|
|
|
|
/* get rest of argument lists */
|
|
while (params != nilCell)
|
|
{
|
|
params = getEvalDefault(params, &results);
|
|
cell->next = (results->type == CELL_ARRAY) ?
|
|
arrayList(results, FALSE) : copyCell(results);
|
|
|
|
cell = cell->next;
|
|
if(!isList(cell->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, results));
|
|
}
|
|
|
|
results = getCell(CELL_EXPRESSION);
|
|
res = NULL;
|
|
|
|
cellIdx = initIteratorIndex();
|
|
|
|
expr = getCell(CELL_EXPRESSION);
|
|
cell = copyCell(funcPtr);
|
|
expr->contents = (UINT)cell;
|
|
|
|
/* prepeare for deletion now, in case of error
|
|
in mapped function execution */
|
|
|
|
pushResult(argsPtr);
|
|
pushResult(expr);
|
|
pushResult(results);
|
|
|
|
resultIdxSave = resultStackIdx;
|
|
|
|
while(argsPtr->contents != (UINT)nilCell) /* for all instances of a arg */
|
|
{
|
|
arg = argsPtr;
|
|
while(arg != nilCell) /* for all args */
|
|
{
|
|
argCell = (CELL *)arg->contents; /* pop out first */
|
|
if(argCell == nilCell) break;
|
|
arg->contents = (UINT)argCell->next;
|
|
argCell->next = nilCell; /* unlink */
|
|
if(isSelfEval(argCell->type))
|
|
cell = cell->next = argCell;
|
|
else
|
|
cell = cell->next = makeCell(CELL_QUOTE, (UINT)argCell);
|
|
arg = arg->next;
|
|
}
|
|
|
|
cell = evaluateExpression(expr);
|
|
cell = copyCell(cell);
|
|
while(resultStackIdx > resultIdxSave)
|
|
deleteList(popResult());
|
|
|
|
if(res == NULL)
|
|
results->contents = (UINT)cell;
|
|
else
|
|
res->next = cell;
|
|
res = cell;
|
|
if(cellIdx->type == CELL_LONG) cellIdx->contents += 1;
|
|
cell = (CELL *)expr->contents;
|
|
deleteList(cell->next);
|
|
}
|
|
|
|
cell->next = nilCell; /* decouple */
|
|
recoverIteratorIndex(cellIdx);
|
|
|
|
symbolCheck = NULL;
|
|
pushResultFlag = FALSE; /* results are already pushed */
|
|
return(results);
|
|
}
|
|
|
|
|
|
CELL * explodeList(CELL * list, CELL * params)
|
|
{
|
|
ssize_t len = 1;
|
|
ssize_t count = 1;
|
|
CELL * cell = NULL;
|
|
CELL * last = NULL;
|
|
CELL * result = NULL;
|
|
CELL * * lastChunk = NULL;
|
|
int flag = FALSE;
|
|
|
|
if(params != nilCell)
|
|
{
|
|
params = getInteger(params, (UINT*)&len);
|
|
flag = getFlag(params);
|
|
}
|
|
|
|
result = getCell(CELL_EXPRESSION);
|
|
|
|
if(len <= 0) return(result);
|
|
|
|
while(list != nilCell)
|
|
{
|
|
if(result->contents == (UINT)nilCell)
|
|
{
|
|
cell = getCell(CELL_EXPRESSION);
|
|
lastChunk = (CELL * *)&result->contents;
|
|
result->contents = (UINT)cell;
|
|
cell->contents = (UINT)copyCell(list);
|
|
last = (CELL*)cell->contents;
|
|
}
|
|
else
|
|
{
|
|
if(count < len)
|
|
{
|
|
last->next = copyCell(list);
|
|
last = last->next;
|
|
count++;
|
|
}
|
|
else
|
|
{
|
|
cell->next = getCell(CELL_EXPRESSION);
|
|
lastChunk = (CELL * *)&cell->next;
|
|
cell = cell->next;
|
|
cell->contents = (UINT)copyCell(list);
|
|
last = (CELL*)cell->contents;
|
|
count = 1;
|
|
}
|
|
|
|
}
|
|
list = list->next;
|
|
}
|
|
|
|
if(flag && count < len)
|
|
{
|
|
if(lastChunk)
|
|
{
|
|
deleteList(*lastChunk);
|
|
*lastChunk = nilCell;
|
|
}
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
|
|
/* ---------------------- set primitives --------------------------------- */
|
|
|
|
CELL * setInterDiff(CELL * params, int mode);
|
|
|
|
|
|
#define SET_INTER 0
|
|
#define SET_DIFF 1
|
|
#define SET_UNIQUE 2
|
|
|
|
CELL * p_intersect(CELL * params)
|
|
{
|
|
if(params->next == nilCell)
|
|
return(setInterDiff(params, SET_UNIQUE));
|
|
else
|
|
return(setInterDiff(params, SET_INTER));
|
|
}
|
|
|
|
CELL * p_difference(CELL * params)
|
|
{
|
|
return(setInterDiff(params, SET_DIFF));
|
|
}
|
|
|
|
|
|
CELL * p_union(CELL * params)
|
|
{
|
|
CELL * result;
|
|
CELL * appnd;
|
|
|
|
appnd = makeCell(CELL_QUOTE, (UINT)p_append(params));
|
|
result = setInterDiff(appnd, SET_UNIQUE);
|
|
deleteList(appnd);
|
|
|
|
return(result);
|
|
}
|
|
|
|
|
|
CELL * p_unique(CELL * params)
|
|
{
|
|
return(setInterDiff(params, SET_UNIQUE));
|
|
}
|
|
|
|
|
|
CELL * setInterDiff(CELL * params, int mode)
|
|
{
|
|
CELL * listA;
|
|
CELL * listB = NULL;
|
|
CELL * * vectorA;
|
|
CELL * * vectorB = NULL;
|
|
CELL * * vectorResult;
|
|
ssize_t lengthA, lengthB = 0;
|
|
ssize_t i = 0, j = 0, k = 0, top = 0;
|
|
CELL * cell = NULL;
|
|
CELL * result;
|
|
int listMode = FALSE;
|
|
int cmp, flag = FALSE;
|
|
|
|
params = getListHead(params, &listA);
|
|
if(listA == nilCell)
|
|
return(getCell(CELL_EXPRESSION));
|
|
|
|
if(mode != SET_UNIQUE)
|
|
{
|
|
params = getListHead(params, &listB);
|
|
listMode = getFlag(params);
|
|
|
|
if(listA == listB)
|
|
{
|
|
flag = TRUE;
|
|
listA = copyList(listB);
|
|
}
|
|
|
|
if(listB == nilCell)
|
|
{
|
|
if(mode == SET_INTER)
|
|
return(getCell(CELL_EXPRESSION));
|
|
listB = NULL;
|
|
}
|
|
}
|
|
|
|
vectorA = listToSortedVector(listA, &lengthA, NULL, TRUE);
|
|
|
|
vectorResult = callocMemory(lengthA * sizeof(CELL *));
|
|
|
|
if(listB)
|
|
vectorB = listToSortedVector(listB, &lengthB, NULL, 0);
|
|
|
|
result = getCell(CELL_EXPRESSION);
|
|
|
|
while(i < lengthA)
|
|
{
|
|
if(listB) switch(mode)
|
|
{
|
|
case SET_INTER:
|
|
cmp = compareCells(vectorA[i], vectorB[j]);
|
|
if(cmp == 0) break;
|
|
if(cmp < 0)
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
if(j < (lengthB - 1)) ++j;
|
|
else ++i;
|
|
continue;
|
|
|
|
case SET_DIFF:
|
|
cmp = compareCells(vectorA[i], vectorB[j]);
|
|
if(cmp == 0)
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
if(cmp < 0) break;
|
|
if(j < (lengthB - 1)) ++j;
|
|
else break;
|
|
|
|
continue;
|
|
|
|
case SET_UNIQUE:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* if not in result or if list mode is specified */
|
|
if( (k == 0) || (compareCells(vectorA[i], vectorResult[top]) != 0) || (listMode == TRUE) )
|
|
{
|
|
top = k;
|
|
vectorResult[k++] = vectorA[i];
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
|
|
if(k > 0)
|
|
{
|
|
binsort(vectorResult, k, (CELL*)0xFFFFFFFF);
|
|
cell = copyCell(vectorResult[0]);
|
|
result->contents = (UINT)cell;
|
|
|
|
/* relinking */
|
|
for(i = 1; i < k; i++)
|
|
{
|
|
cell->next = copyCell(vectorResult[i]);
|
|
cell = cell->next;
|
|
}
|
|
cell->next = nilCell;
|
|
}
|
|
|
|
free(vectorResult);
|
|
|
|
cell = resortVectorToList(vectorA, lengthA);
|
|
|
|
if(vectorB) free(vectorB);
|
|
|
|
if(flag) deleteList(listA);
|
|
|
|
return(result);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------- */
|
|
|
|
CELL * p_match(CELL * params)
|
|
{
|
|
CELL * cell;
|
|
CELL * next;
|
|
CELL * result;
|
|
|
|
params = getEvalDefault(params, &cell);
|
|
if(!isList(cell->type)) return(nilCell);
|
|
params = getEvalDefault(params, &next);
|
|
if(!isList(next->type)) return(nilCell);
|
|
|
|
result = patternMatchL((CELL *)cell->contents, (CELL *)next->contents, getFlag(params));
|
|
|
|
return(result ? result : getCell(CELL_EXPRESSION));
|
|
}
|
|
|
|
CELL * linkMatches(CELL * * matchList, CELL * matchPtr, CELL * elmnt)
|
|
{
|
|
if(*matchList == NULL)
|
|
{
|
|
*matchList = makeCell(CELL_EXPRESSION, (UINT)elmnt);
|
|
matchPtr = (CELL *)(*matchList)->contents;
|
|
}
|
|
else
|
|
{
|
|
matchPtr->next = elmnt;
|
|
}
|
|
|
|
while(matchPtr->next != nilCell)
|
|
matchPtr = matchPtr->next;
|
|
|
|
return(matchPtr);
|
|
}
|
|
|
|
|
|
CELL * patternMatchL(CELL * pattern, CELL * list, int flag)
|
|
{
|
|
CELL * match;
|
|
CELL * matchList = NULL;
|
|
CELL * matches = NULL;
|
|
CELL * starList = NULL;
|
|
CELL * stars = NULL;
|
|
|
|
MATCH_LIST:
|
|
switch(pattern->type)
|
|
{
|
|
case CELL_NIL:
|
|
/* end of pattern and list */
|
|
if(list->type == CELL_NIL)
|
|
{
|
|
if(starList) deleteList(starList);
|
|
return(matchList);
|
|
}
|
|
|
|
goto NO_MATCH_RETURN;
|
|
|
|
case CELL_QUOTE:
|
|
case CELL_EXPRESSION:
|
|
case CELL_FEXPR:
|
|
case CELL_LAMBDA:
|
|
/* compare subexpressions */
|
|
if(list->type == pattern->type)
|
|
{
|
|
if((match = patternMatchL((CELL*)pattern->contents, (CELL*)list->contents, flag)) != nilCell)
|
|
{
|
|
if(match != NULL)
|
|
{
|
|
if(flag)
|
|
matches = linkMatches(&matchList, matches, match);
|
|
else
|
|
{
|
|
matches = linkMatches(&matchList, matches, (CELL*)match->contents);
|
|
match->contents = (UINT)nilCell;
|
|
deleteList(match);
|
|
}
|
|
}
|
|
pattern = pattern->next;
|
|
list = list->next;
|
|
goto MATCH_LIST;
|
|
}
|
|
}
|
|
|
|
goto NO_MATCH_RETURN;
|
|
|
|
case CELL_SYMBOL:
|
|
if(pattern->contents == (UINT)questionSymbol) /* '?' */
|
|
{
|
|
if(list == nilCell) goto NO_MATCH_RETURN;
|
|
if(!flag) matches = linkMatches(&matchList, matches, copyCell(list));
|
|
break;
|
|
}
|
|
|
|
if(pattern->contents == (UINT)starSymbol ||
|
|
pattern->contents == (UINT)plusSymbol) /* '*' and '+' */
|
|
{
|
|
if(starList == NULL)
|
|
{
|
|
starList = getCell(CELL_EXPRESSION);
|
|
}
|
|
|
|
if(stars == NULL && pattern->contents == (UINT)plusSymbol)
|
|
goto WILD_CARD_GREP;
|
|
|
|
if(pattern->next == nilCell)
|
|
{
|
|
if(stars == NULL)
|
|
starList->contents = (UINT)copyList(list);
|
|
else
|
|
stars->next = copyList(list);
|
|
|
|
linkMatches(&matchList, matches, starList);
|
|
return(matchList);
|
|
}
|
|
|
|
if((match = patternMatchL(pattern->next, list, flag)) != nilCell)
|
|
{
|
|
matches = linkMatches(&matchList, matches, starList);
|
|
if(match != NULL)
|
|
{
|
|
matches->next = (CELL*)match->contents;
|
|
match->contents = (UINT)nilCell;
|
|
deleteList(match);
|
|
}
|
|
return(matchList);
|
|
}
|
|
|
|
if(list->next == nilCell)
|
|
goto NO_MATCH_RETURN;
|
|
|
|
WILD_CARD_GREP:
|
|
if(pattern->contents == (UINT)plusSymbol)
|
|
if(list == nilCell) goto NO_MATCH_RETURN;
|
|
|
|
if(stars == NULL)
|
|
{
|
|
starList->contents = (UINT)copyCell(list);
|
|
stars = (CELL*)starList->contents;
|
|
}
|
|
else
|
|
{
|
|
stars->next = copyCell(list);
|
|
stars = stars->next;
|
|
}
|
|
|
|
list = list->next;
|
|
goto MATCH_LIST;
|
|
}
|
|
default:
|
|
if(compareCells(pattern, list) != 0)
|
|
goto NO_MATCH_RETURN;
|
|
|
|
break;
|
|
}
|
|
|
|
if(flag) matches = linkMatches(&matchList, matches, copyCell(list));
|
|
|
|
|
|
pattern = pattern->next;
|
|
list = list->next;
|
|
goto MATCH_LIST;
|
|
|
|
NO_MATCH_RETURN:
|
|
if(starList != NULL) deleteList(starList);
|
|
if(matchList != NULL) deleteList(matchList);
|
|
return(nilCell);
|
|
}
|
|
|
|
|
|
CELL * p_assoc(CELL * params)
|
|
{
|
|
CELL * key;
|
|
CELL * list;
|
|
int listMode;
|
|
|
|
key = evaluateExpression(params);
|
|
if((listMode = isList(key->type)))
|
|
key = (CELL *)key->contents;
|
|
|
|
if(key == nilCell) key = copyCell(nilCell);
|
|
|
|
getEvalDefault(params->next, &list);
|
|
if(!isList(list->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, list));
|
|
|
|
list = (CELL *)list->contents;
|
|
|
|
while(key != nilCell)
|
|
{
|
|
while(list != nilCell)
|
|
{
|
|
if(isList(list->type))
|
|
{
|
|
if(compareCells(key, (CELL *)list->contents) == 0)
|
|
break;
|
|
}
|
|
list = list->next;
|
|
}
|
|
|
|
if(!listMode || (key = key->next) == nilCell) break;
|
|
list = ((CELL *)list->contents)->next;
|
|
}
|
|
|
|
if(list == nilCell) return(nilCell);
|
|
|
|
pushResultFlag = FALSE;
|
|
return(list);
|
|
}
|
|
|
|
|
|
CELL * p_lookup(CELL * params)
|
|
{
|
|
CELL * key;
|
|
CELL * list;
|
|
int listMode;
|
|
ssize_t index;
|
|
CELL * deflt = nilCell;
|
|
SYMBOL * symbolRef;
|
|
|
|
key = evaluateExpression(params);
|
|
if((listMode = isList(key->type)))
|
|
key = (CELL *)key->contents;
|
|
|
|
if(key == nilCell) key = copyCell(nilCell);
|
|
|
|
params = getEvalDefault(params->next, &list);
|
|
symbolRef = symbolCheck;
|
|
|
|
if(!isList(list->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, list));
|
|
|
|
list = (CELL *)list->contents;
|
|
|
|
if(params != nilCell)
|
|
deflt = getInteger(params, (UINT *)&index);
|
|
else index = -1;
|
|
|
|
while(key != nilCell)
|
|
{
|
|
while(list != nilCell)
|
|
{
|
|
if(isList(list->type))
|
|
if(compareCells(key, (CELL *)list->contents) == 0) break;
|
|
list = list->next;
|
|
}
|
|
|
|
if(!listMode || (key = key->next) == nilCell) break;
|
|
list = ((CELL *)list->contents)->next;
|
|
}
|
|
|
|
if(list == nilCell)
|
|
return(copyCell(evaluateExpression(deflt)));
|
|
|
|
list = (CELL*)list->contents;
|
|
|
|
if(index < 0) index = convertNegativeOffset(index, list);
|
|
|
|
while(index--)
|
|
{
|
|
if(list->next == nilCell) break;
|
|
list = list->next;
|
|
}
|
|
|
|
symbolCheck = symbolRef;
|
|
pushResultFlag = FALSE;
|
|
return(list);
|
|
}
|
|
|
|
|
|
/* bind an association list, works like:
|
|
(define (bind L) (dolist (i L) (apply set i)))
|
|
L => ((x 1) (y 2) (z 3))
|
|
*/
|
|
|
|
CELL * p_bind(CELL * params)
|
|
{
|
|
CELL * list;
|
|
|
|
params = getListHead(params, &list);
|
|
|
|
return(copyCell(bindList(list, getFlag(params))));
|
|
}
|
|
|
|
|
|
CELL * bindList(CELL * params, int evalFlag)
|
|
{
|
|
SYMBOL * lref = NULL;
|
|
CELL * cell;
|
|
CELL * old;
|
|
|
|
while(params != nilCell)
|
|
{
|
|
if(params->type != CELL_EXPRESSION)
|
|
return(errorProcExt(ERR_LIST_EXPECTED, params));
|
|
|
|
cell = (CELL *)params->contents;
|
|
lref = getSymbolCheckProtected(cell);
|
|
old = (CELL *)lref->contents;
|
|
if(evalFlag)
|
|
lref->contents = (UINT)copyCell(evaluateExpression(cell->next));
|
|
else
|
|
lref->contents = (UINT)copyCell(cell->next);
|
|
deleteList(old);
|
|
params = params->next;
|
|
}
|
|
|
|
if(lref == NULL)
|
|
return(nilCell);
|
|
|
|
return((CELL *)lref->contents);
|
|
}
|
|
|
|
|
|
CELL * p_count(CELL * params)
|
|
{
|
|
CELL * items;
|
|
CELL * list;
|
|
CELL * result;
|
|
CELL * * vectorItems;
|
|
CELL * * vectorList;
|
|
ssize_t lengthItems, lengthList;
|
|
ssize_t i = 0, j = 0, idx;
|
|
int cmp;
|
|
int flag = FALSE;
|
|
CELL * cell;
|
|
ssize_t * counts;
|
|
|
|
params = getListHead(params, &items);
|
|
getListHead(params, &list);
|
|
|
|
result = getCell(CELL_EXPRESSION);
|
|
|
|
if(items == nilCell)
|
|
return(result);
|
|
|
|
if(items == list)
|
|
{
|
|
flag = TRUE;
|
|
items = copyList(list);
|
|
}
|
|
|
|
vectorItems = listToSortedVector(items, &lengthItems, NULL, TRUE);
|
|
vectorList = listToSortedVector(list, &lengthList, NULL, TRUE);
|
|
|
|
counts = (ssize_t *)callocMemory(lengthItems * sizeof(ssize_t));
|
|
|
|
if(vectorList)
|
|
while(i < lengthList)
|
|
{
|
|
cmp = compareCells(vectorList[i], vectorItems[j]);
|
|
if(cmp == 0)
|
|
{
|
|
idx = (ssize_t)vectorItems[j]->next;
|
|
counts[idx] += 1;
|
|
++i;
|
|
continue;
|
|
}
|
|
if(cmp < 0)
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
if(j < (lengthItems - 1)) j++;
|
|
else i++;
|
|
}
|
|
|
|
|
|
cell = stuffInteger(counts[0]);
|
|
result->contents = (UINT)cell;
|
|
for(i = 1; i < lengthItems; i++)
|
|
{
|
|
cell->next = stuffInteger(counts[i]);
|
|
cell = cell->next;
|
|
}
|
|
freeMemory(counts);
|
|
|
|
cell = resortVectorToList(vectorItems, lengthItems);
|
|
if(vectorList) cell = resortVectorToList(vectorList, lengthList);
|
|
|
|
if(flag) deleteList(items);
|
|
|
|
return(result);
|
|
}
|
|
|
|
|
|
CELL * p_popAssoc(CELL * params)
|
|
{
|
|
CELL * key;
|
|
CELL * list;
|
|
CELL * original = NULL;
|
|
CELL * previous = NULL;
|
|
int listMode;
|
|
|
|
key = evaluateExpression(params);
|
|
if((listMode = isList(key->type)))
|
|
key = (CELL *)key->contents;
|
|
|
|
if(key == nilCell) key = copyCell(nilCell);
|
|
|
|
getEvalDefault(params->next, &list);
|
|
|
|
if(!isList(list->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, list));
|
|
if(symbolCheck && isProtected(symbolCheck->flags))
|
|
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(symbolCheck)));
|
|
|
|
list->aux = (UINT)nilCell; /* undo last element optimization */
|
|
original = list;
|
|
list = (CELL *)list->contents;
|
|
|
|
while(key != nilCell)
|
|
{
|
|
while(list != nilCell)
|
|
{
|
|
if(isList(list->type))
|
|
{
|
|
list->aux = (UINT)nilCell; /* undo last element optimization */
|
|
if(compareCells(key, (CELL *)list->contents) == 0) break;
|
|
}
|
|
previous = list;
|
|
list = list->next;
|
|
}
|
|
|
|
if(!listMode || (key = key->next) == nilCell) break;
|
|
previous = (CELL *)list->contents;
|
|
list = ((CELL *)list->contents)->next;
|
|
}
|
|
|
|
if(list == nilCell) return(nilCell); /* key not found */
|
|
|
|
if(previous == NULL)
|
|
original->contents = (UINT)list->next;
|
|
else
|
|
previous->next = list->next;
|
|
|
|
/* unlink */
|
|
list->next = nilCell;
|
|
return(list);
|
|
}
|
|
|
|
void binsort(CELL * * x, ssize_t n, CELL * pCell)
|
|
{
|
|
ssize_t i,j,k,l,m,kf,lf;
|
|
CELL * expr;
|
|
CELL * cell;
|
|
UINT * resultIndexSave;
|
|
jmp_buf errorJumpSave;
|
|
int errNo;
|
|
CELL * * y;
|
|
|
|
y = allocMemory(n * sizeof(CELL *));
|
|
|
|
m = 1;
|
|
while(m < n)
|
|
{
|
|
for(i = 0; i < n; i += 2*m)
|
|
{
|
|
k = i; l = i + m;
|
|
if(l >= n)
|
|
{
|
|
kf = lf = n;
|
|
l = lf + 1;
|
|
}
|
|
else
|
|
{
|
|
kf = k + m - 1;
|
|
lf = l + m - 1;
|
|
}
|
|
|
|
if(lf >= n) lf = n - 1;
|
|
|
|
for(j = i; j <= lf; j++)
|
|
{
|
|
if(k > kf)
|
|
{
|
|
y[j] = x[l++];
|
|
continue;
|
|
}
|
|
if(l > lf)
|
|
{
|
|
y[j] = x[k++];
|
|
continue;
|
|
}
|
|
|
|
if(pCell == NULL)
|
|
{
|
|
if(compareCells((CELL*)x[k], (CELL*)x[l]) <= 0)
|
|
y[j] = x[k++];
|
|
else
|
|
y[j] = x[l++];
|
|
continue;
|
|
}
|
|
if(pCell == (CELL*)0xFFFFFFFF)
|
|
{
|
|
if(((CELL*)x[k])->next <= ((CELL*)x[l])->next)
|
|
y[j] = x[k++];
|
|
else
|
|
y[j] = x[l++];
|
|
continue;
|
|
}
|
|
|
|
resultIndexSave = resultStackIdx;
|
|
expr = makeCell(CELL_EXPRESSION, (UINT)copyCell(pCell));
|
|
|
|
cell = (CELL *)expr->contents;
|
|
cell->next = makeCell(CELL_QUOTE, (UINT)copyCell((CELL*)x[k]));
|
|
cell = cell->next;
|
|
|
|
cell->next = makeCell(CELL_QUOTE, (UINT)copyCell((CELL*)x[l]));
|
|
|
|
/* do result stack cleanup, and free memory under
|
|
error conditions */
|
|
memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
|
|
if((errNo = setjmp(errorJump)) != 0)
|
|
{
|
|
memcpy(errorJump, errorJumpSave, (sizeof(jmp_buf)));
|
|
deleteList(expr);
|
|
cleanupResults(resultIndexSave);
|
|
free(x); /* allocates by parent routine */
|
|
free(y);
|
|
longjmp(errorJump, errNo);
|
|
}
|
|
|
|
cell = evaluateExpression(expr);
|
|
|
|
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
|
|
if(!isNil(cell) && !isEmpty(cell))
|
|
y[j] = x[k++];
|
|
else
|
|
y[j] = x[l++];
|
|
|
|
deleteList(expr);
|
|
cleanupResults(resultIndexSave);
|
|
}
|
|
}
|
|
|
|
for(i = 0; i < n; i++) x[i] = y[i];
|
|
m = m * 2;
|
|
}
|
|
|
|
free(y);
|
|
}
|
|
|
|
CELL * * listToSortedVector(CELL * list, ssize_t * length, CELL * func, int indexFlag);
|
|
|
|
CELL * p_sort(CELL * params)
|
|
{
|
|
CELL * list;
|
|
CELL * cell;
|
|
CELL * * vector;
|
|
ssize_t length, i;
|
|
SYMBOL * refSymbol;
|
|
|
|
list = params;
|
|
|
|
getEvalDefault(params, &cell);
|
|
refSymbol = symbolCheck;
|
|
|
|
if(symbolCheck && isProtected(symbolCheck->flags))
|
|
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(symbolCheck)));
|
|
|
|
if(isList(cell->type))
|
|
{
|
|
if(cell->contents == (UINT)nilCell)
|
|
return(getCell(CELL_EXPRESSION));
|
|
|
|
cell->aux = (UINT)nilCell; /* undo last element optimization */
|
|
|
|
vector = listToSortedVector((CELL *)cell->contents, &length, list->next, 0);
|
|
|
|
/* relink cells */
|
|
list = vector[0];
|
|
--length;
|
|
i = 1;
|
|
while(length--)
|
|
{
|
|
list->next = vector[i];
|
|
list = list->next;
|
|
i++;
|
|
}
|
|
list->next = nilCell;
|
|
|
|
cell->contents = (UINT)vector[0];
|
|
freeMemory(vector);
|
|
}
|
|
else if(cell->type == CELL_ARRAY)
|
|
{
|
|
vector = (CELL **)cell->contents;
|
|
length = (cell->aux - 1) / sizeof(UINT);
|
|
if(list->next == nilCell)
|
|
binsort(vector, length, NULL);
|
|
else
|
|
binsort(vector, length, list->next);
|
|
}
|
|
else
|
|
return(errorProcExt(ERR_LIST_OR_ARRAY_EXPECTED, list));
|
|
|
|
symbolCheck = refSymbol;
|
|
pushResultFlag = FALSE;
|
|
return(cell);
|
|
}
|
|
|
|
|
|
CELL * * listToSortedVector(CELL * list, ssize_t * length, CELL * func, int indexFlag)
|
|
{
|
|
CELL * * vector;
|
|
CELL * prev;
|
|
ssize_t i;
|
|
|
|
if((*length = listlen(list)) == 0) return(NULL);
|
|
|
|
/* build vector */
|
|
vector = allocMemory(*length * sizeof(CELL *));
|
|
for(i = 0; i < *length; i++)
|
|
{
|
|
vector[i] = prev = list;
|
|
list = list->next;
|
|
if(indexFlag) prev->next = (void *)i;
|
|
}
|
|
if(func != nilCell && func != NULL)
|
|
{
|
|
func = evaluateExpression(func);
|
|
if(func->type == CELL_SYMBOL)
|
|
func = (CELL*)((SYMBOL *)func->contents)->contents;
|
|
func = copyCell(func);
|
|
binsort(vector, *length, func);
|
|
deleteList(func);
|
|
}
|
|
else
|
|
binsort(vector, *length, NULL);
|
|
|
|
return(vector);
|
|
}
|
|
|
|
|
|
CELL * resortVectorToList(CELL * * vector, ssize_t length)
|
|
{
|
|
CELL * list;
|
|
ssize_t i;
|
|
|
|
binsort(vector, length, (CELL*)0xFFFFFFFF);
|
|
list = vector[0];
|
|
for(i = 1; i < length; i++)
|
|
{
|
|
list->next = vector[i];
|
|
list = list->next;
|
|
}
|
|
list->next = nilCell;
|
|
list = vector[0];
|
|
free(vector);
|
|
|
|
return(list);
|
|
}
|
|
|
|
/* called with params containing the indices
|
|
or list of indices */
|
|
|
|
CELL * implicitIndexList (CELL * list, CELL * params)
|
|
{
|
|
CELL * cell;
|
|
ssize_t index;
|
|
int evalFlag;
|
|
|
|
cell = evaluateExpression(params);
|
|
|
|
if(isNumber(cell->type))
|
|
{
|
|
getIntegerExt(cell, (UINT *)&index, FALSE);
|
|
params = params->next;
|
|
evalFlag = TRUE;
|
|
}
|
|
else if(isList(cell->type))
|
|
{
|
|
params = (CELL*)cell->contents;
|
|
if(params == nilCell) return(list);
|
|
params = getIntegerExt(params, (UINT *)&index, FALSE);
|
|
evalFlag = FALSE;
|
|
}
|
|
else return(errorProcExt(ERR_LIST_INDEX_INVALID, params));
|
|
|
|
while(isList(list->type))
|
|
{
|
|
/* 10.3.1 catch changes in the list to be indexed
|
|
caused by circular reference in index expression
|
|
e.g (lst (set 'lst foo)) , when foo is a vector
|
|
*/
|
|
if(list->type == 255)
|
|
return(errorProc(ERR_LIST_REFERENCE_CHANGED));
|
|
|
|
/* last element optimization */
|
|
if(index == -1 && list->aux != (UINT)nilCell)
|
|
list = (CELL *)list->aux;
|
|
else
|
|
{
|
|
list = (CELL *)list->contents;
|
|
if(index < 0)
|
|
index = convertNegativeOffset(index, list);
|
|
|
|
while(index--) list = list->next;
|
|
|
|
if(list == nilCell)
|
|
errorProc(ERR_LIST_INDEX_INVALID);
|
|
}
|
|
|
|
if(params == nilCell || !isList(list->type)) break;
|
|
params = getIntegerExt(params, (UINT *)&index, evalFlag);
|
|
}
|
|
|
|
return(list);
|
|
}
|
|
|
|
|
|
CELL * p_sequence(CELL * params)
|
|
{
|
|
double fromFlt, toFlt, interval, step, cntFlt;
|
|
INT64 fromInt64 = 0, toInt64 = 0, stepCnt, i;
|
|
CELL * sequence;
|
|
CELL * cell;
|
|
int intFlag;
|
|
|
|
if((intFlag = (((CELL*)params->next)->next == nilCell)))
|
|
{
|
|
params = getInteger64Ext(params, &fromInt64, TRUE);
|
|
getInteger64Ext(params, &toInt64, TRUE);
|
|
stepCnt = (fromInt64 > toInt64) ? fromInt64 - toInt64 : toInt64 - fromInt64;
|
|
cell = stuffInteger64(fromInt64);
|
|
}
|
|
else
|
|
{
|
|
params = getFloat(params, &fromFlt);
|
|
params = getFloat(params, &toFlt);
|
|
getFloat(params, &step);
|
|
|
|
if(isnan(fromFlt) || isnan(toFlt) || isnan(step))
|
|
return(errorProc(ERR_INVALID_PARAMETER_NAN));
|
|
|
|
step = (step < 0) ? -step : step;
|
|
step = (fromFlt > toFlt) ? -step : step;
|
|
cntFlt = (fromFlt < toFlt) ? (toFlt - fromFlt)/step : (fromFlt - toFlt)/step;
|
|
stepCnt = (cntFlt > 0.0) ? floor(cntFlt + 0.0000000001) : floor(-cntFlt + 0.0000000001);
|
|
cell = stuffFloat(fromFlt);
|
|
}
|
|
sequence = makeCell(CELL_EXPRESSION, (UINT)cell);
|
|
|
|
for(i = 1; i <= stepCnt; i++)
|
|
{
|
|
if(intFlag)
|
|
{
|
|
if(fromInt64 > toInt64)
|
|
cell->next = stuffInteger(fromInt64 - i);
|
|
else
|
|
cell->next = stuffInteger(fromInt64 + i);
|
|
}
|
|
else
|
|
{
|
|
interval = fromFlt + i * step;
|
|
cell->next = stuffFloat(interval);
|
|
}
|
|
cell = cell->next;
|
|
}
|
|
|
|
sequence->aux = (UINT)cell; /* last element optimization */
|
|
return(sequence);
|
|
}
|
|
|
|
|
|
#define FILTER_FILTER 0
|
|
#define FILTER_INDEX 1
|
|
#define FILTER_CLEAN 2
|
|
#define FILTER_FOR_ALL 3
|
|
#define FILTER_EXISTS 4
|
|
|
|
/* on EMSCRIPTEN, when compiling with -O1 or -O2, this is necessary
|
|
optimization messes up setjmp/longjmp
|
|
*/
|
|
|
|
#ifdef EMSCRIPTEN
|
|
CELL * filterIndex(CELL * pCell, CELL * args, int mode);
|
|
#else
|
|
CELL * filterIndex(CELL * params, int mode);
|
|
#endif
|
|
|
|
|
|
CELL * p_filter(CELL * params)
|
|
{
|
|
#ifdef EMSCRIPTEN
|
|
CELL * pCell;
|
|
CELL * args;
|
|
pCell = evaluateExpression(params);
|
|
getEvalDefault(params->next, &args);
|
|
if(!isList(args->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, params->next));
|
|
return filterIndex(pCell, args, FILTER_FILTER);
|
|
#else
|
|
return filterIndex(params, FILTER_FILTER);
|
|
#endif
|
|
}
|
|
|
|
CELL * p_index(CELL * params)
|
|
{
|
|
#ifdef EMSCRIPTEN
|
|
CELL * pCell;
|
|
CELL * args;
|
|
pCell = evaluateExpression(params);
|
|
getEvalDefault(params->next, &args);
|
|
if(!isList(args->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, params->next));
|
|
return filterIndex(pCell, args, FILTER_INDEX);
|
|
#else
|
|
return filterIndex(params, FILTER_INDEX);
|
|
#endif
|
|
}
|
|
|
|
CELL * p_clean(CELL * params)
|
|
{
|
|
#ifdef EMSCRIPTEN
|
|
CELL * pCell;
|
|
CELL * args;
|
|
pCell = evaluateExpression(params);
|
|
getEvalDefault(params->next, &args);
|
|
if(!isList(args->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, params->next));
|
|
return filterIndex(pCell, args, FILTER_CLEAN);
|
|
#else
|
|
return filterIndex(params, FILTER_CLEAN);
|
|
#endif
|
|
}
|
|
|
|
CELL * p_exists(CELL * params)
|
|
{
|
|
#ifdef EMSCRIPTEN
|
|
CELL * pCell;
|
|
CELL * args;
|
|
pCell = evaluateExpression(params);
|
|
getEvalDefault(params->next, &args);
|
|
if(!isList(args->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, params->next));
|
|
return filterIndex(pCell, args, FILTER_EXISTS);
|
|
#else
|
|
return filterIndex(params, FILTER_EXISTS);
|
|
#endif
|
|
}
|
|
|
|
CELL * p_forAll(CELL * params)
|
|
{
|
|
#ifdef EMSCRIPTEN
|
|
CELL * pCell;
|
|
CELL * args;
|
|
pCell = evaluateExpression(params);
|
|
getEvalDefault(params->next, &args);
|
|
if(!isList(args->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, params->next));
|
|
return filterIndex(pCell, args, FILTER_FOR_ALL);
|
|
#else
|
|
return filterIndex(params, FILTER_FOR_ALL);
|
|
#endif
|
|
}
|
|
|
|
#ifdef EMSCRIPTEN
|
|
CELL * filterIndex(CELL * pCell, CELL * args, int mode)
|
|
#else
|
|
CELL * filterIndex(CELL * params, int mode)
|
|
#endif
|
|
{
|
|
CELL * expr;
|
|
#ifndef EMSCRIPTEN
|
|
CELL * pCell;
|
|
CELL * args;
|
|
#endif
|
|
CELL * resultList = NULL;
|
|
CELL * result;
|
|
CELL * cell;
|
|
UINT * resultIndexSave;
|
|
jmp_buf errorJumpSave;
|
|
ssize_t count;
|
|
int errNo, trueFlag;
|
|
|
|
#ifndef EMSCRIPTEN
|
|
pCell = evaluateExpression(params);
|
|
getEvalDefault(params->next, &args);
|
|
|
|
if(!isList(args->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, params->next));
|
|
#endif
|
|
|
|
args = (CELL *)args->contents;
|
|
|
|
result = NULL;
|
|
count = 0;
|
|
resultIndexSave = resultStackIdx;
|
|
|
|
memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
|
|
if((errNo = setjmp(errorJump)) != 0)
|
|
{
|
|
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
|
|
if(resultList) deleteList(resultList);
|
|
longjmp(errorJump, errNo);
|
|
}
|
|
|
|
while(args != nilCell)
|
|
{
|
|
expr = makeCell(CELL_EXPRESSION, (UINT)copyCell(pCell));
|
|
cell = (CELL *)expr->contents;
|
|
cell->next = makeCell(CELL_QUOTE, (UINT)copyCell(args));
|
|
|
|
pushResult(expr);
|
|
|
|
cell = evaluateExpression(expr);
|
|
|
|
trueFlag = !isNil(cell) && !isEmpty(cell);
|
|
|
|
cleanupResults(resultIndexSave);
|
|
|
|
if(mode == FILTER_EXISTS && trueFlag)
|
|
{
|
|
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
|
|
return(copyCell(args));
|
|
}
|
|
|
|
else if (mode == FILTER_FOR_ALL)
|
|
{
|
|
if(trueFlag) goto CONTINUE_FOR_ALL;
|
|
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
|
|
return(nilCell);
|
|
}
|
|
|
|
if((trueFlag && mode != FILTER_CLEAN) || (!trueFlag && mode == FILTER_CLEAN))
|
|
{
|
|
if(result == NULL)
|
|
{
|
|
resultList = makeCell(CELL_EXPRESSION, (mode == FILTER_INDEX) ?
|
|
(UINT)stuffInteger((UINT)count): (UINT)copyCell(args));
|
|
result = (CELL*)resultList->contents;
|
|
}
|
|
else
|
|
{
|
|
result->next = (mode == FILTER_INDEX) ?
|
|
stuffInteger(count): copyCell(args);
|
|
result = result->next;
|
|
}
|
|
}
|
|
|
|
CONTINUE_FOR_ALL:
|
|
args = args->next;
|
|
count++;
|
|
}
|
|
|
|
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
|
|
|
|
if(mode == FILTER_EXISTS)
|
|
return(nilCell);
|
|
|
|
if(mode == FILTER_FOR_ALL)
|
|
return(trueCell);
|
|
|
|
if(resultList == NULL)
|
|
return(getCell(CELL_EXPRESSION));
|
|
|
|
return(resultList);
|
|
}
|
|
|
|
|
|
#define MAX_REF_STACK 256
|
|
typedef struct {
|
|
size_t * base;
|
|
size_t idx;
|
|
} REFSTACK;
|
|
|
|
#define pushRef(A) (refStack->base[refStack->idx++] = (UINT)(A))
|
|
#define popRef() (--refStack->idx)
|
|
|
|
CELL * makeIndexVector(REFSTACK * refStack)
|
|
{
|
|
CELL * vector;
|
|
CELL * next;
|
|
int i;
|
|
|
|
next = stuffInteger(refStack->base[0]);
|
|
|
|
vector = makeCell(CELL_EXPRESSION, (UINT)next);
|
|
|
|
for(i = 1; i < refStack->idx; i++)
|
|
{
|
|
next->next = stuffInteger(refStack->base[i]);
|
|
next = next->next;
|
|
}
|
|
|
|
return(vector);
|
|
}
|
|
|
|
#define REF_SINGLE 0
|
|
#define REF_ALL 1
|
|
|
|
#define REF_INDEX 0
|
|
#define REF_CONTENTS 1
|
|
|
|
void ref(CELL * keyCell, CELL * list, CELL * funcCell, CELL * * head,
|
|
CELL * * next, REFSTACK * refStack, int mode)
|
|
{
|
|
size_t idx = 0;
|
|
UINT * resultIdxSave = resultStackIdx;
|
|
CELL * item;
|
|
|
|
while(list != nilCell)
|
|
{
|
|
if(compareFunc(keyCell, list, funcCell) == 0)
|
|
{
|
|
if(refStack->base)
|
|
{
|
|
if(refStack->idx < MAX_REF_STACK) pushRef(idx);
|
|
else errorProc(ERR_NESTING_TOO_DEEP);
|
|
item = makeIndexVector(refStack);
|
|
popRef();
|
|
}
|
|
else
|
|
{
|
|
if(mode == REF_SINGLE)
|
|
item = list;
|
|
else
|
|
item = copyCell(list);
|
|
}
|
|
|
|
if(*next == NULL)
|
|
*next = *head = item;
|
|
else
|
|
{
|
|
(*next)->next = item;
|
|
*next = (*next)->next;
|
|
}
|
|
|
|
if(mode == REF_SINGLE) return;
|
|
countCell->contents++;
|
|
}
|
|
|
|
if(isList(list->type))
|
|
{
|
|
if(refStack->base)
|
|
{
|
|
if(refStack->idx < MAX_REF_STACK) pushRef(idx);
|
|
else errorProc(ERR_NESTING_TOO_DEEP);
|
|
}
|
|
ref(keyCell, (CELL*)list->contents, funcCell, head, next, refStack, mode);
|
|
if(refStack->base) popRef();
|
|
if(mode == REF_SINGLE && *head != NULL)
|
|
return;
|
|
}
|
|
|
|
idx++;
|
|
cleanupResults(resultIdxSave);
|
|
list = list->next;
|
|
}
|
|
}
|
|
|
|
|
|
CELL * reference(CELL * params, int mode)
|
|
{
|
|
CELL * head = NULL;
|
|
CELL * keyCell;
|
|
CELL * list;
|
|
CELL * funcCell = NULL;
|
|
CELL * next = NULL;
|
|
REFSTACK refStack = {NULL, 0};
|
|
int flag = 0;
|
|
SYMBOL * symbolRef;
|
|
|
|
keyCell = evaluateExpression(params);
|
|
params = getEvalDefault(params->next, &list);
|
|
symbolRef = symbolCheck;
|
|
|
|
if(params != nilCell)
|
|
{
|
|
funcCell = evaluateExpression(params);
|
|
flag = getFlag(params->next);
|
|
}
|
|
|
|
if(!flag)
|
|
refStack.base = alloca((MAX_REF_STACK + 2) * sizeof(size_t));
|
|
|
|
if(!isList(list->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, list));
|
|
|
|
ref(keyCell, (CELL *)list->contents, funcCell, &head, &next, &refStack, mode);
|
|
|
|
if(mode == REF_SINGLE)
|
|
{
|
|
if(head == NULL) return(nilCell);
|
|
if(flag)
|
|
{
|
|
symbolCheck = symbolRef;
|
|
pushResultFlag = FALSE;
|
|
}
|
|
return(head);
|
|
}
|
|
|
|
list = getCell(CELL_EXPRESSION);
|
|
|
|
list->contents = (UINT)((head == NULL) ? nilCell : head);
|
|
|
|
return(list);
|
|
}
|
|
|
|
CELL * p_ref(CELL * params)
|
|
{
|
|
return(reference(params, REF_SINGLE));
|
|
}
|
|
|
|
CELL * p_refAll(CELL * params)
|
|
{
|
|
countCell->contents = 0;
|
|
return(reference(params, REF_ALL));
|
|
}
|
|
|
|
|
|
#define SETREF_SINGLE 1
|
|
#define SETREF_ALL 2
|
|
|
|
CELL * modRef(CELL * key, CELL * list, CELL * func, CELL * new, int mode, int * count)
|
|
{
|
|
CELL * result;
|
|
UINT * resultIdxSave = resultStackIdx;
|
|
|
|
while(list != nilCell)
|
|
{
|
|
if(compareFunc(key, list, func) == 0)
|
|
{
|
|
*count += 1;
|
|
updateCell(list, new);
|
|
if(mode == SETREF_SINGLE) return(list);
|
|
countCell->contents++;
|
|
}
|
|
else if(isList(list->type))
|
|
{
|
|
result = modRef(key, (CELL *)list->contents, func, new, mode, count);
|
|
if(result != nilCell) return(result);
|
|
}
|
|
|
|
cleanupResults(resultIdxSave);
|
|
list = list->next;
|
|
}
|
|
|
|
return(nilCell);
|
|
}
|
|
|
|
|
|
CELL * setRef(CELL * params, int mode)
|
|
{
|
|
CELL * key;
|
|
CELL * list;
|
|
CELL * new = NULL;
|
|
CELL * funcCell = NULL;
|
|
SYMBOL * refSymbol;
|
|
int count = 0;
|
|
|
|
key = evaluateExpression(params);
|
|
new = getEvalDefault(params->next, &list);
|
|
refSymbol = symbolCheck;
|
|
if(!isList(list->type))
|
|
return(errorProcExt(ERR_LIST_EXPECTED, list));
|
|
|
|
if(symbolCheck && isProtected(symbolCheck->flags))
|
|
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(symbolCheck)));
|
|
|
|
if(new->next != nilCell)
|
|
funcCell = evaluateExpression(new->next);
|
|
|
|
modRef(key, (CELL *)list->contents, funcCell, new, mode, &count);
|
|
|
|
if(count == 0)
|
|
return(nilCell);
|
|
|
|
symbolCheck = refSymbol;
|
|
pushResultFlag = FALSE;
|
|
return(list);
|
|
}
|
|
|
|
|
|
CELL * p_setRef(CELL * params)
|
|
{
|
|
return(setRef(params, SETREF_SINGLE));
|
|
}
|
|
|
|
CELL * p_setRefAll(CELL * params)
|
|
{
|
|
countCell->contents = 0;
|
|
return(setRef(params, SETREF_ALL));
|
|
}
|
|
|
|
|
|
/* update a cell in-place and put a copy of previous content
|
|
in $it to be used in replacement expressions.
|
|
Now only used in modeRef(), could be inlined.
|
|
*/
|
|
void updateCell(CELL * cell, CELL * val)
|
|
{
|
|
CELL * new;
|
|
|
|
itSymbol->contents = (UINT)cell;
|
|
|
|
if(val != nilCell)
|
|
{
|
|
new = copyCell(evaluateExpression(val));
|
|
|
|
/* delete contents of original cell */
|
|
if(isEnvelope(cell->type))
|
|
{
|
|
if(cell->type == CELL_ARRAY)
|
|
deleteArray(cell);
|
|
else
|
|
deleteList((CELL *)cell->contents);
|
|
}
|
|
else if(cell->type == CELL_STRING || cell->type == CELL_DYN_SYMBOL
|
|
#ifdef BIGINT
|
|
|| cell->type == CELL_BIGINT
|
|
#endif
|
|
)
|
|
freeMemory( (void *)cell->contents);
|
|
|
|
cell->type = new->type;
|
|
cell->aux = new->aux;
|
|
cell->contents = new->contents;
|
|
|
|
/* free the cell */
|
|
new->type = CELL_FREE;
|
|
new->aux = 0;
|
|
new->contents = 0;
|
|
new->next = firstFreeCell;
|
|
firstFreeCell = new;
|
|
--cellCount;
|
|
}
|
|
|
|
itSymbol->contents = (UINT)nilCell;
|
|
}
|
|
|
|
void flat(CELL * list, CELL * result, CELL * * next, UINT recursion)
|
|
{
|
|
while(list != nilCell)
|
|
{
|
|
if(isList(list->type) && recursion != 0)
|
|
flat((CELL*)list->contents, result, next, recursion - 1);
|
|
else
|
|
{
|
|
if(*next == NULL)
|
|
{
|
|
*next = copyCell(list);
|
|
result->contents = (UINT)*next;
|
|
}
|
|
else
|
|
{
|
|
(*next)->next = copyCell(list);
|
|
*next = (*next)->next;
|
|
}
|
|
}
|
|
|
|
list = list->next;
|
|
}
|
|
}
|
|
|
|
|
|
CELL * p_flat(CELL * params)
|
|
{
|
|
CELL * list;
|
|
CELL * result;
|
|
CELL * next = NULL;
|
|
UINT recursion = -1;
|
|
|
|
params = getListHead(params, &list);
|
|
if(params != nilCell)
|
|
getInteger(params, &recursion);
|
|
|
|
result = getCell(CELL_EXPRESSION);
|
|
|
|
flat(list, result, &next, recursion);
|
|
|
|
return(result);
|
|
}
|
|
|
|
/*
|
|
(collect <expr> [int-max-count])
|
|
collect results of evaluating <expr> while not nil
|
|
and optional max count is not reached
|
|
*/
|
|
CELL * p_collect(CELL * params)
|
|
{
|
|
CELL * result;
|
|
CELL * cell;
|
|
UINT * resultIdxSave = resultStackIdx;
|
|
UINT count = MAX_LONG;
|
|
|
|
result = getCell(CELL_EXPRESSION);
|
|
if(params->next != nilCell)
|
|
getInteger(params->next, &count);
|
|
|
|
while(count > 0)
|
|
{
|
|
cell = evaluateExpression(params);
|
|
if(isNil(cell)) break;
|
|
addList(result, copyCell(cell));
|
|
--count;
|
|
cleanupResults(resultIdxSave);
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
|
|
/* --------------------------------- array routines ------------------------- */
|
|
|
|
|
|
CELL * initArray(CELL * array, CELL * list, CELL * * next);
|
|
|
|
CELL * p_array(CELL * params)
|
|
{
|
|
ssize_t index[17];
|
|
int p = 0;
|
|
CELL * array = NULL;
|
|
CELL * list = nilCell;
|
|
CELL * next = NULL;
|
|
SYMBOL * sPtr;
|
|
|
|
while(params != nilCell && p < 17)
|
|
{
|
|
list = evaluateExpression(params);
|
|
if(isNumber(list->type))
|
|
{
|
|
getIntegerExt(list, (UINT*)&index[p], FALSE);
|
|
if(index[p] < 1)
|
|
return(errorProcExt(ERR_WRONG_DIMENSIONS, list));
|
|
else p++;
|
|
}
|
|
else if(list->type == CELL_CONTEXT)
|
|
{
|
|
sPtr = translateCreateSymbol( ((SYMBOL*)list->contents)->name, CELL_NIL,
|
|
(SYMBOL*)list->contents, TRUE);
|
|
list = (CELL *)sPtr->contents;
|
|
}
|
|
else if(isList(list->type)) break;
|
|
else return(errorProcExt(ERR_NUMBER_EXPECTED, list));
|
|
params = params->next;
|
|
}
|
|
|
|
if(p == 0)
|
|
return(errorProc(ERR_MISSING_ARGUMENT));
|
|
|
|
index[p] = 0;
|
|
if(!isList(list->type)) list = nilCell;
|
|
|
|
array = makeArray(index, 0);
|
|
|
|
if(list != nilCell)
|
|
array = initArray(array, list, &next);
|
|
|
|
return(array);
|
|
}
|
|
|
|
|
|
CELL * makeArray(ssize_t * index, int p)
|
|
{
|
|
CELL * array;
|
|
CELL * list;
|
|
CELL * * addr;
|
|
ssize_t size;
|
|
|
|
array = getCell(CELL_ARRAY);
|
|
size = index[p];
|
|
array->contents = (UINT)callocMemory(size * sizeof(UINT) + 1);
|
|
array->aux = size * sizeof(UINT) + 1;
|
|
addr = (CELL * *)array->contents;
|
|
|
|
p++;
|
|
if(index[p] > 0)
|
|
{
|
|
list = makeArray(index, p);
|
|
while(size--) *(addr++) = copyCell(list);
|
|
deleteList(list);
|
|
return(array);
|
|
}
|
|
else
|
|
while(size--) *(addr++) = copyCell(nilCell);
|
|
|
|
return(array);
|
|
}
|
|
|
|
|
|
CELL * initArray(CELL * array, CELL * list, CELL * * next)
|
|
{
|
|
CELL * * addr;
|
|
int size;
|
|
|
|
size = (array->aux - 1) / sizeof(UINT);
|
|
addr = (CELL * *)array->contents;
|
|
|
|
while(size--)
|
|
{
|
|
if((*addr)->type == CELL_ARRAY)
|
|
{
|
|
*(addr) = initArray(*addr, list, next);
|
|
addr++;
|
|
continue;
|
|
}
|
|
|
|
if(*next == NULL || *next == nilCell)
|
|
{
|
|
deleteList(*addr);
|
|
*(addr++) = copyCell((CELL *)list->contents);
|
|
*next = (CELL*)list->contents;
|
|
*next = (*next)->next;
|
|
}
|
|
else
|
|
{
|
|
deleteList(*addr);
|
|
*(addr++) = copyCell(*next);
|
|
*next = (*next)->next;
|
|
}
|
|
}
|
|
|
|
return(array);
|
|
}
|
|
|
|
CELL * p_arrayList(CELL * params)
|
|
{
|
|
CELL * array;
|
|
|
|
getEvalDefault(params, &array);
|
|
|
|
if(array->type != CELL_ARRAY)
|
|
return(errorProcExt(ERR_ARRAY_EXPECTED, params));
|
|
|
|
return(arrayList(array, TRUE));
|
|
}
|
|
|
|
CELL * arrayList(CELL * array, int flag)
|
|
{
|
|
CELL * list = NULL;
|
|
CELL * * addr;
|
|
CELL * new;
|
|
CELL * cell;
|
|
ssize_t size;
|
|
|
|
addr = (CELL * *)array->contents;
|
|
size = (array->aux - 1) / sizeof(UINT);
|
|
|
|
while(size--)
|
|
{
|
|
cell = *(addr++);
|
|
if((cell->type == CELL_ARRAY) && flag)
|
|
new = arrayList(cell, flag);
|
|
else
|
|
new = copyCell(cell);
|
|
if(list == NULL)
|
|
{
|
|
array = list = makeCell(CELL_EXPRESSION, (UINT)new);
|
|
list = new;
|
|
}
|
|
else
|
|
{
|
|
list->next = new;
|
|
list = new;
|
|
}
|
|
}
|
|
|
|
return(array);
|
|
}
|
|
|
|
CELL * arrayTranspose(CELL * array)
|
|
{
|
|
ssize_t n, m, i, j;
|
|
CELL * cell;
|
|
CELL * * addr;
|
|
CELL * * newAddr;
|
|
CELL * * row;
|
|
CELL * * newRow;
|
|
CELL * newArray;
|
|
|
|
addr = (CELL * *)array->contents;
|
|
n = (array->aux - 1) / sizeof(CELL *);
|
|
|
|
cell = *addr;
|
|
if(cell->type != CELL_ARRAY)
|
|
return(errorProcExt(ERR_WRONG_DIMENSIONS, array));
|
|
m = (cell->aux - 1) / sizeof(CELL *);
|
|
|
|
newArray = getCell(CELL_ARRAY);
|
|
newArray->aux = m * sizeof(CELL *) + 1;
|
|
newAddr = (CELL * *)callocMemory(newArray->aux);
|
|
newArray->contents = (UINT)newAddr;
|
|
|
|
for(j = 0; j < m; j++)
|
|
{
|
|
/* create new row vector */
|
|
cell = getCell(CELL_ARRAY);
|
|
cell->aux = n * sizeof(CELL *) + 1;
|
|
newRow = (CELL * *)callocMemory(cell->aux);
|
|
cell->contents = (UINT)newRow;
|
|
*(newAddr + j) = cell;
|
|
for( i = 0; i < n; i++)
|
|
{
|
|
cell = *(addr + i);
|
|
if(cell->type != CELL_ARRAY)
|
|
*(newRow + i) = copyCell(cell);
|
|
else
|
|
{
|
|
row = (CELL * *)cell->contents;
|
|
if( (cell->aux - 1) / sizeof(CELL *) < (j + 1))
|
|
*(newRow + i) = nilCell;
|
|
else
|
|
*(newRow + i) = copyCell(*(row + j));
|
|
}
|
|
}
|
|
}
|
|
|
|
return(newArray);
|
|
}
|
|
|
|
|
|
CELL * subarray(CELL * array, ssize_t offset, ssize_t length)
|
|
{
|
|
CELL * newArray;
|
|
ssize_t size, i;
|
|
CELL * * newAddr;
|
|
CELL * * addr;
|
|
|
|
size = (array->aux - 1) / sizeof(CELL *);
|
|
if(offset < 0) offset = offset + size;
|
|
if(offset >= size || offset < 0)
|
|
return(errorProcExt2(ERR_ARRAY_INDEX_OUTOF_BOUNDS, stuffInteger(offset)));
|
|
|
|
if(length < 0)
|
|
{
|
|
length = size - offset + length;
|
|
if(length < 0) length = 0;
|
|
}
|
|
|
|
if(length == MAX_LONG && length > (size - offset))
|
|
length = size - offset;
|
|
|
|
if(length == 0 || length > (size - offset))
|
|
return(errorProcExt2(ERR_ARRAY_INDEX_OUTOF_BOUNDS, stuffInteger(length)));
|
|
|
|
addr = (CELL * *)array->contents;
|
|
newArray = getCell(CELL_ARRAY);
|
|
newArray->aux = length * sizeof(CELL *) + 1;
|
|
newAddr = (CELL * *)callocMemory(newArray->aux);
|
|
newArray->contents = (UINT)newAddr;
|
|
|
|
for(i = 0; i < length; i++)
|
|
*(newAddr + i) = copyCell(*(addr + offset + i));
|
|
|
|
return(newArray);
|
|
}
|
|
|
|
|
|
/* copies an array */
|
|
UINT * copyArray(CELL * array)
|
|
{
|
|
CELL * * newAddr;
|
|
CELL * * orgAddr;
|
|
CELL * * addr;
|
|
ssize_t size;
|
|
|
|
addr = newAddr = (CELL * *)callocMemory(array->aux);
|
|
|
|
size = (array->aux - 1) / sizeof(UINT);
|
|
orgAddr = (CELL * *)array->contents;
|
|
|
|
while(size--)
|
|
*(newAddr++) = copyCell(*(orgAddr++));
|
|
|
|
return((UINT*)addr);
|
|
}
|
|
|
|
|
|
CELL * appendArray(CELL * array, CELL * params)
|
|
{
|
|
CELL * cell;
|
|
CELL * * addr;
|
|
ssize_t size, sizeCell;
|
|
ssize_t i;
|
|
CELL * * newAddr;
|
|
int deleteFlag = 0;
|
|
|
|
if(params == nilCell)
|
|
return(copyCell(array));
|
|
|
|
START_APPEND_ARRAYS:
|
|
size = (array->aux - 1) / sizeof(CELL *);
|
|
addr = (CELL * *)array->contents;
|
|
cell = evaluateExpression(params);
|
|
if(cell->type != CELL_ARRAY)
|
|
return(errorProcExt(ERR_ARRAY_EXPECTED, params));
|
|
sizeCell = (cell->aux - 1) / sizeof(CELL *);
|
|
|
|
newAddr = allocMemory(array->aux + cell->aux -1);
|
|
|
|
for(i = 0; i < size; i++)
|
|
*(newAddr + i) = copyCell(*(addr + i));
|
|
|
|
addr = (CELL * *)cell->contents;
|
|
|
|
for(i = 0; i < sizeCell; i++)
|
|
*(newAddr + size + i) = copyCell(*(addr + i));
|
|
|
|
cell = getCell(CELL_ARRAY);
|
|
cell->aux = (size + sizeCell) * sizeof(CELL *) + 1;
|
|
cell->contents = (UINT)newAddr;
|
|
|
|
if( (params = params->next) != nilCell)
|
|
{
|
|
if(deleteFlag)
|
|
deleteList(array);
|
|
deleteFlag = 1;
|
|
array = cell;
|
|
goto START_APPEND_ARRAYS;
|
|
}
|
|
|
|
if(deleteFlag)
|
|
deleteList(array);
|
|
|
|
symbolCheck = NULL;
|
|
|
|
return(cell);
|
|
}
|
|
|
|
|
|
void deleteArray(CELL * array)
|
|
{
|
|
CELL * * addr;
|
|
CELL * * mem;
|
|
ssize_t size;
|
|
|
|
mem = addr = (CELL * *)array->contents;
|
|
size = (array->aux - 1) / sizeof(UINT);
|
|
while(size--)
|
|
deleteList(*(addr++));
|
|
|
|
freeMemory((char *)mem);
|
|
}
|
|
|
|
void printArray(CELL * array, UINT device)
|
|
{
|
|
CELL * list;
|
|
|
|
list = arrayList(array, TRUE);
|
|
|
|
printExpression(list, device);
|
|
|
|
deleteList(list);
|
|
}
|
|
|
|
void printArrayDimensions(CELL * array, UINT device)
|
|
{
|
|
CELL * * addr;
|
|
|
|
while(array->type == CELL_ARRAY)
|
|
{
|
|
varPrintf(device, "%d ", (array->aux - 1)/sizeof(CELL *));
|
|
addr = (CELL **)array->contents;
|
|
array = *addr;
|
|
}
|
|
}
|
|
|
|
|
|
CELL * implicitIndexArray(CELL * cell, CELL * params)
|
|
{
|
|
CELL * * addr;
|
|
CELL * list;
|
|
ssize_t size, index;
|
|
int evalFlag;
|
|
|
|
list = evaluateExpression(params);
|
|
|
|
if(isNumber(list->type))
|
|
{
|
|
getIntegerExt(list, (UINT *)&index, FALSE);
|
|
params = params->next;
|
|
evalFlag = TRUE;
|
|
}
|
|
else if(isList(list->type))
|
|
{
|
|
params = (CELL*)list->contents;
|
|
if(params == nilCell) return(cell);
|
|
params = getIntegerExt(params, (UINT *)&index, FALSE);
|
|
evalFlag = FALSE;
|
|
}
|
|
else return(errorProcExt(ERR_ARRAY_INDEX_OUTOF_BOUNDS, params));
|
|
|
|
while(cell->type == CELL_ARRAY)
|
|
{
|
|
addr = (CELL * *)cell->contents;
|
|
size = (cell->aux - 1) / sizeof(UINT);
|
|
if(index < 0) index = index + size;
|
|
if(index >= size || index < 0)
|
|
return(errorProcExt2(ERR_ARRAY_INDEX_OUTOF_BOUNDS, stuffInteger(index)));
|
|
cell = *(addr + index);
|
|
if(params == nilCell || cell->type != CELL_ARRAY) break;
|
|
params = getIntegerExt(params, (UINT *)&index, evalFlag);
|
|
}
|
|
|
|
return(cell);
|
|
}
|
|
|
|
|
|
int compareArrays(CELL * left, CELL * right)
|
|
{
|
|
CELL * * leftAddr;
|
|
CELL * * rightAddr;
|
|
ssize_t leftS, rightS;
|
|
ssize_t result;
|
|
|
|
leftAddr = (CELL * *)left->contents;
|
|
rightAddr = (CELL * *)right->contents;
|
|
leftS = (left->aux - 1) / sizeof(UINT);
|
|
rightS = (right->aux - 1) / sizeof(UINT);
|
|
|
|
if(leftS < rightS) return(-1);
|
|
if(leftS > rightS) return(1);
|
|
|
|
result = 0;
|
|
while(leftS && result == 0)
|
|
{
|
|
result = compareCells(*(leftAddr++), *(rightAddr++));
|
|
leftS--;
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
|
|
int compareFunc(CELL * left, CELL * right, CELL * func)
|
|
{
|
|
CELL * cell;
|
|
CELL * expr;
|
|
|
|
if(func == NULL)
|
|
return(compareCells(left, right));
|
|
|
|
expr = makeCell(CELL_EXPRESSION, (UINT)copyCell(func));
|
|
|
|
pushResult(expr);
|
|
|
|
cell = (CELL *)expr->contents;
|
|
cell->next = makeCell(CELL_QUOTE, (UINT)copyCell((CELL*)left));
|
|
cell = cell->next;
|
|
cell->next = makeCell(CELL_QUOTE, (UINT)copyCell((CELL*)right));
|
|
|
|
cell = evaluateExpression(expr);
|
|
|
|
return(isNil(cell));
|
|
}
|
|
|
|
/* eof */
|
|
|