diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c734050..b3ce7d1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,6 +60,9 @@ functionaltest("map") functionaltest("deconstruct") functionaltest("shadowing") functionaltest("mathops") +functionaltest("len") +functionaltest("not") +functionaltest("type") install(TARGETS apfl DESTINATION lib) install(TARGETS apfl-bin DESTINATION bin) diff --git a/src/functional-tests/len.at b/src/functional-tests/len.at new file mode 100644 index 0000000..070c54a --- /dev/null +++ b/src/functional-tests/len.at @@ -0,0 +1,17 @@ +===== script ===== +print (len "") +print (len "Hello") +print (len []) +print (len [1 2 3 4]) +print (len [[]]) +print (len [->]) +print (len ['a -> 'b, 'c-> 'd]) + +===== output ===== +0 +5 +0 +4 +1 +0 +2 diff --git a/src/functional-tests/not.at b/src/functional-tests/not.at new file mode 100644 index 0000000..d61850f --- /dev/null +++ b/src/functional-tests/not.at @@ -0,0 +1,35 @@ +===== script ===== +print (not true) +print (not false) +print (not nil) +print (not 0) +print (not 1) +print (not -1) +print (not 42) +print (not "") +print (not "foo") +print (not []) +print (not [1]) +print (not [true]) +print (not [false]) +print (not [->]) +print (not ['x -> 'y]) +print (not {}) + +===== output ===== +false +true +true +false +false +false +false +false +false +false +false +false +false +false +false +false diff --git a/src/functional-tests/type.at b/src/functional-tests/type.at new file mode 100644 index 0000000..4fab599 --- /dev/null +++ b/src/functional-tests/type.at @@ -0,0 +1,21 @@ +===== script ===== +print (type true) +print (type false) +print (type nil) +print (type "test") +print (type []) +print (type ["test"]) +print (type [1->2]) +print (type {x->x}) +print (type type) + +===== output ===== +bool +bool +nil +string +list +list +dict +function +function diff --git a/src/globals.c b/src/globals.c index 55172ff..c977162 100644 --- a/src/globals.c +++ b/src/globals.c @@ -206,18 +206,74 @@ disasm(apfl_ctx ctx) } static void -tostring(apfl_ctx ctx) +require_exactly_one_arg(apfl_ctx ctx, const char *error) { size_t len = apfl_len(ctx, 0); if (len != 1) { - apfl_raise_const_error(ctx, APFL_RESULT_ERR, "tostring needs exactly 1 argument"); + apfl_raise_const_error(ctx, APFL_RESULT_ERR, error); } apfl_get_list_member_by_index(ctx, 0, 0); apfl_drop(ctx, 0); +} + +#define ONE_ARG(ctx, name) require_exactly_one_arg((ctx), name " needs exactly 1 argument") + +static void +tostring(apfl_ctx ctx) +{ + ONE_ARG(ctx, "tostring"); apfl_tostring(ctx, -1); } +static void +not(apfl_ctx ctx) +{ + ONE_ARG(ctx, "not"); + bool b = apfl_is_truthy(ctx, -1); + apfl_push_bool(ctx, !b); +} + +static void +len(apfl_ctx ctx) +{ + ONE_ARG(ctx, "len"); + size_t l = apfl_len(ctx, -1); + apfl_push_number(ctx, (apfl_number)l); +} + +static const char * +typestr(enum apfl_value_type type) +{ + switch (type) { + case APFL_VALUE_NIL: + return "nil"; + case APFL_VALUE_BOOLEAN: + return "bool"; + case APFL_VALUE_NUMBER: + return "number"; + case APFL_VALUE_STRING: + return "string"; + case APFL_VALUE_LIST: + return "list"; + case APFL_VALUE_DICT: + return "dict"; + case APFL_VALUE_FUNC: + return "function"; + case APFL_VALUE_USERDATA: + return "userdata"; + } + + return "?"; +} + +static void +type(apfl_ctx ctx) +{ + ONE_ARG(ctx, "type"); + apfl_push_const_string(ctx, typestr(apfl_get_type(ctx, -1))); +} + static const struct global_def globals[] = { {"if", impl_if}, {"==", impl_eq}, @@ -229,6 +285,9 @@ static const struct global_def globals[] = { {"dump", dump}, {"disasm", disasm}, {"tostring", tostring}, + {"not", not}, + {"len", len}, + {"type", type}, {NULL, NULL}, };