uplevel + get@ for strings, tuples.

This commit is contained in:
antirez 2022-12-22 18:30:57 +01:00
parent c7f94dd886
commit 430dee9961
2 changed files with 62 additions and 17 deletions

71
aocla.c
View file

@ -446,6 +446,17 @@ obj *newBool(int b) {
return o; return o;
} }
/* Allocate a string object initialized with the content at 's' for
* 'len' bytes. */
obj *newString(const char *s, size_t len) {
obj *o = newObject(OBJ_TYPE_STRING);
o->str.len = len;
o->str.ptr = myalloc(len+1);
memcpy(o->str.ptr,s,len);
o->str.ptr[len] = 0;
return o;
}
/* Deep copy the passed object. Return an object with refcount = 1. */ /* Deep copy the passed object. Return an object with refcount = 1. */
obj *deepCopy(obj *o) { obj *deepCopy(obj *o) {
if (o == NULL) return NULL; if (o == NULL) return NULL;
@ -879,6 +890,22 @@ int procEval(aoclactx *ctx) {
return retval; return retval;
} }
/* Like eval, but the code is evaluated in the stack frame of the calling
* procedure, if any. */
int procUpeval(aoclactx *ctx) {
if (checkStackType(ctx,1,OBJ_TYPE_LIST)) return 1;
obj *l = stackPop(ctx);
stackframe *saved = NULL;
if (ctx->frame->prev) {
saved = ctx->frame;
ctx->frame = ctx->frame->prev;
}
int retval = eval(ctx,l);
if (saved) ctx->frame = saved;
release(l);
return retval;
}
/* Print the top object to stdout, consuming it */ /* Print the top object to stdout, consuming it */
int procPrint(aoclactx *ctx) { int procPrint(aoclactx *ctx) {
if (checkStackLen(ctx,1)) return 1; if (checkStackLen(ctx,1)) return 1;
@ -888,6 +915,13 @@ int procPrint(aoclactx *ctx) {
return 0; return 0;
} }
/* Like print but also prints a newline at the end. */
int procPrintnl(aoclactx *ctx) {
if (checkStackLen(ctx,1)) return 1;
int ret = procPrint(ctx); printf("\n");
return ret;
}
/* Len -- gets object len. Works with many types. /* Len -- gets object len. Works with many types.
* (object) => (len) */ * (object) => (len) */
int procLen(aoclactx *ctx) { int procLen(aoclactx *ctx) {
@ -927,24 +961,28 @@ int procListAppend(aoclactx *ctx) {
return 0; return 0;
} }
/* @idx -- get element at index: /* @idx -- get element at index. Works for lists, strings, tuples.
* (list index) => (element) * (object index) => (element). */
*
* TODO: this should work for strings as well. */
int procListGetAt(aoclactx *ctx) { int procListGetAt(aoclactx *ctx) {
if (checkStackType(ctx,2,OBJ_TYPE_LIST,OBJ_TYPE_INT)) return 1; if (checkStackType(ctx,2,OBJ_TYPE_LIST|OBJ_TYPE_STRING|OBJ_TYPE_TUPLE,
OBJ_TYPE_INT)) return 1;
obj *idx = stackPop(ctx); obj *idx = stackPop(ctx);
obj *list = stackPop(ctx); obj *o = stackPop(ctx);
int i = idx->i; int i = idx->i;
if (i < 0) i = list->l.len+i; /* -1 is last element, and so forth. */ size_t len = o->type == OBJ_TYPE_STRING ? o->str.len : o->l.len;
if (i < 0) i = len+i; /* -1 is last element, and so forth. */
release(idx); release(idx);
if (i < 0 || (size_t)i >= list->l.len) { if (i < 0 || (size_t)i >= len) {
stackPush(ctx,newBool(0)); // Out of index? Just push false. stackPush(ctx,newBool(0)); // Out of index? Just push false.
} else { } else {
stackPush(ctx,list->l.ele[i]); if (o->type == OBJ_TYPE_STRING) {
retain(list->l.ele[i]); stackPush(ctx,newString(o->str.ptr+i,1));
} else {
stackPush(ctx,o->l.ele[i]);
retain(o->l.ele[i]);
}
} }
release(list); release(o);
return 0; return 0;
} }
@ -954,6 +992,7 @@ int procShowStack(aoclactx *ctx) {
return 0; return 0;
} }
/* Load the "standard library" of Aocla in the specified context. */
void loadLibrary(aoclactx *ctx) { void loadLibrary(aoclactx *ctx) {
addProc(ctx,"+",procBasicMath,NULL); addProc(ctx,"+",procBasicMath,NULL);
addProc(ctx,"-",procBasicMath,NULL); addProc(ctx,"-",procBasicMath,NULL);
@ -971,16 +1010,22 @@ void loadLibrary(aoclactx *ctx) {
addProc(ctx,"ifelse",procIf,NULL); addProc(ctx,"ifelse",procIf,NULL);
addProc(ctx,"while",procIf,NULL); addProc(ctx,"while",procIf,NULL);
addProc(ctx,"eval",procEval,NULL); addProc(ctx,"eval",procEval,NULL);
addProc(ctx,"upeval",procUpeval,NULL);
addProc(ctx,"print",procPrint,NULL); addProc(ctx,"print",procPrint,NULL);
addProc(ctx,"printnl",procPrintnl,NULL);
addProc(ctx,"len",procLen,NULL); addProc(ctx,"len",procLen,NULL);
addProc(ctx,"->",procListAppend,NULL); addProc(ctx,"->",procListAppend,NULL);
addProc(ctx,"<-",procListAppend,NULL); addProc(ctx,"<-",procListAppend,NULL);
addProc(ctx,"get@",procListGetAt,NULL); addProc(ctx,"get@",procListGetAt,NULL);
addProc(ctx,"showstack",procShowStack,NULL); addProc(ctx,"showstack",procShowStack,NULL);
/* Since the point of this interpreter to be a short and understandable
* programming example, we implement as much as possible in Aocla itself
* without caring much about performances. */
addProcString(ctx,"dup","[(x) $x $x]"); addProcString(ctx,"dup","[(x) $x $x]");
addProcString(ctx,"swap","[(x y) $y $x]"); addProcString(ctx,"swap","[(x y) $y $x]");
addProcString(ctx,"drop","[(_)]"); addProcString(ctx,"drop","[(_)]");
addProcString(ctx,"map", "[(l f) $l len (e) 0 (j) [] [$j $e <] [ $l $j get@ $f eval swap -> $j 1 + (j)] while]"); addProcString(ctx,"map", "[(l f) $l len (e) 0 (j) [] [$j $e <] [ $l $j get@ $f upeval swap -> $j 1 + (j)] while]");
} }
/* ================================ CLI ===================================== */ /* ================================ CLI ===================================== */
@ -1080,7 +1125,7 @@ int main(int argc, char **argv) {
if (argc == 1) { if (argc == 1) {
repl(); repl();
} else if (argc >= 2) { } else if (argc >= 2) {
if (evalFile(argv[1],argv+1,argc-1)) return 1; if (evalFile(argv[1],argv+2,argc-2)) return 1;
} }
return 0; return 0;
} }

View file

@ -1,5 +1,5 @@
// This is an implementation of map. There is already one inside // This is a commented version of the implementation of 'map' inside
// Aocla, but this will redefine it. // the standard library.
[(l f) // list and function to apply [(l f) // list and function to apply
$l len (e) // Get list len in "e" $l len (e) // Get list len in "e"
@ -7,11 +7,11 @@
[] // We will populate this empty list [] // We will populate this empty list
[$j $e <] [ [$j $e <] [
$l $j get@ $l $j get@
$f eval $f upeval
swap -> swap ->
$j 1 + (j) $j 1 + (j)
] while ] while
] 'map def ] 'map def
[1 2 3] [dup *] map [1 2 3] [dup *] map
print printnl