mirror of
https://github.com/antirez/aocla
synced 2024-12-27 09:58:32 +01:00
uplevel + get@ for strings, tuples.
This commit is contained in:
parent
c7f94dd886
commit
430dee9961
2 changed files with 62 additions and 17 deletions
71
aocla.c
71
aocla.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue