diff options
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | README.md | 55 | ||||
-rw-r--r-- | include/builtins.h | 10 | ||||
-rw-r--r-- | src/builtins.c | 67 | ||||
-rw-r--r-- | src/main.c | 4 | ||||
-rw-r--r-- | src/stem.c | 6 |
6 files changed, 91 insertions, 53 deletions
@@ -1,4 +1,4 @@ -Copyright 2023 Preston Pan +Copyright 2024 Preston Pan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: @@ -8,48 +8,13 @@ and FLI library maintainers. Therefore, the end user does not need to worry about memory allocation while the implementation remains extremely simple. # Installation -`make` and `sudo make install`. To generate the html documentation, one must first -install `doxygen` as an optional dependency. If you are on a BSD or MacOS, you -must use `gmake`. - -# Documentation -Builtin function definitions and the C API in general are documented [here](https://stemdoc.nullring.xyz). - -# Quickstart -Because this is a stack based language, all operations are done in reverse polish. For example, to add two numbers together: -``` -3 4 + -``` -would return the result `7`. `3` and `4` get pushed onto the stack when they are written out as literals in the language, and `+` is a builtin -that adds the top two elements of the stack. In this language, there are two kinds of objects: literals -(strings, ints, floats, words, and literals of type `VERROR` are built in), and quotes that contain these literals (arrays of valid statements that can be evaluated). -Words might be new to you if you're coming from another language. If you're coming from lisp, a words are analogous to symbols. If you're coming from another -language, a word is a literal that has the special property that they can be bound to functions. For example, the `+` symbol is a word, which is bound -to the action of adding two numbers when called. - -Let's look at a real example of a REPL implementation in this language: -``` -repl [ "> " . read strquote eval repl ] def -repl -``` -`repl` is a word, which means it is a literal, and everything that is a literal gets pushed onto the stack. -Everything between the `[` and `]` is an element in a quote. Then, we see the `def` word. If a word is already bound to a function, -the function gets called instead of getting pushed to the stack, so the `def` function gets called, which takes the top two -elements off the stack, and creates a function called `repl` where now every time `repl` is called in the future, the quote is evaluated -instead. - -Let's take a closer look at the quote: -``` -"> " . read strquote eval repl -``` -`.` takes the first thing off the stack and prints it. In this case, it would print a prompt `> ` every REPL loop. `read` reads a value from stdin, -then `strquote` turns that string into a quote. `eval` pops the first thing off the stack and evaluates the quote in the same way calling a function -does, and then finally `repl` gets called again at the end so we can loop forever. - -## Factorial -Let's take a closer look at the factorial function: -``` -factorial [ dup 0 <= [ 1 + ] [ dup 1 - factorial * ] if ] def -``` -we check if the input is less than or equal to zero, and if it is, we add one to the input and it is our output. -Otherwise, we multiply that input by itself minus one. +In the terminal: +``` sh +git clone https://github.com/ret2pop/stem +cd stem/ +make +sudo make install +``` +To generate the html documentation, one must first install `doxygen` as an optional dependency. +If you are on a BSD or MacOS, you must use `gmake`. Also, you obviously need `git` to clone this +repository. diff --git a/include/builtins.h b/include/builtins.h index 3b87aff..a21b436 100644 --- a/include/builtins.h +++ b/include/builtins.h @@ -3,21 +3,27 @@ #include <stem.h> /*! @brief adds two numbers together, pushes result on the stack */ +/*! call in stem with num1 num2 + => num */ void stemadd(value_t *v); /*! @brief subtracts two numbers together, pushes result on the stack */ +/*! call in stem with num1 num2 - => num */ void stemsub(value_t *v); /*! @brief multiplies two numbers together, pushes result on the stack */ +/*! call in stem with num1 num2 * => num */ void stemmul(value_t *v); /*! @brief divides two numbers together, pushes result on the stack */ +/*! call in stem with num1 num2 / => num */ void stemdiv(value_t *v); -/*! @brief [word] [quote] func, creates function with name [word] and value - * [quote] */ +/*! @brief creates function with name [word] and value [quote] */ +/*! call with `word value def`. */ void stemfunc(value_t *v); +/* @brief Inserts a value into a string or quote. */ +/* call with `[quote/string] value index insert` */ void steminsert(value_t *v); /*! @brief takes first number to the power of the second, pushes result on the diff --git a/src/builtins.c b/src/builtins.c index f3497b3..0bb3662 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -195,6 +195,62 @@ void stemdiv(value_t *v) { value_free(v2); } +void stemand(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error("EMPTY STACK"); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error("EMPTY STACK"); + return; + } + if (v1->type != VINT && v1->type != VFLOAT && v2->type != VINT && + v2->type != VFLOAT) { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error("INCORRECT TYPE ARGUMENT"); + return; + } + + v1->int_float = v1->int_float && v2->int_float; + if (v2->type == VFLOAT) + v1->type = VFLOAT; + + array_append(STACK, v1); + value_free(v2); +} + +void stemor(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error("EMPTY STACK"); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error("EMPTY STACK"); + return; + } + if (v1->type != VINT && v1->type != VFLOAT && v2->type != VINT && + v2->type != VFLOAT) { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error("INCORRECT TYPE ARGUMENT"); + return; + } + + v1->int_float = v1->int_float || v2->int_float; + if (v2->type == VFLOAT) + v1->type = VFLOAT; + + array_append(STACK, v1); + value_free(v2); +} + void stemfunc(value_t *v) { value_t *v2 = array_pop(STACK); if (v2 == NULL) { @@ -1206,6 +1262,7 @@ void stemcut(value_t *v) { for (int i = v1->int_float; i < v2->str_word->length; i++) { string_append(r2->str_word, v2->str_word->value[i]); } + value_free(v2); break; case VQUOTE: if (v1->int_float >= v2->quote->size || v1->int_float < 0) { @@ -1218,13 +1275,16 @@ void stemcut(value_t *v) { r1->quote = init_array(10); r2 = init_value(VQUOTE); r2->quote = init_array(10); - for (int i = 0; i < v1->int_float; i++) { + for (int i = 0; i < v1->int_float + 1; i++) { array_append(r1->quote, v2->quote->items[i]); } - for (int i = v1->int_float; i < v2->quote->size; i++) { + for (int i = v1->int_float + 1; i < v2->quote->size; i++) { array_append(r2->quote, v2->quote->items[i]); } /* [ a b c ] 1 cut => [ a ] [ b c ] */ + free(v2->quote->items); + free(v2->quote); + free(v2); break; default: array_append(STACK, v2); @@ -1235,7 +1295,6 @@ void stemcut(value_t *v) { array_append(STACK, r1); array_append(STACK, r2); value_free(v1); - value_free(v2); } void undef(value_t *v) { @@ -1323,4 +1382,6 @@ void add_funcs() { add_func(FLIT, stemcut, "cut"); add_func(FLIT, steminsert, "insert"); add_func(FLIT, unglue, "unglue"); + add_func(FLIT, stemand, "and"); + add_func(FLIT, stemor, "or"); } @@ -22,8 +22,8 @@ void usage() { /*! prints version and exits */ void version() { - printf("Author: Preston Pan, MIT License 2023\n"); - printf("stem, version 1.2 alpha\n"); + printf("Author: Preston Pan, MIT License 2024\n"); + printf("stem, version 1.3 alpha\n"); exit(0); } @@ -447,16 +447,22 @@ ht_t *init_ht(size_t size) { } void ht_add(ht_t *h, string_t *key, void *v, void (*freefunc)(void *)) { + if (key == NULL) + return; sll_add(h->buckets[hash(h, key->value)], key, v, freefunc); } void *ht_get(ht_t *h, string_t *key) { + if (key == NULL) + return NULL; return sll_get(h->buckets[hash(h, key->value)], key); } bool ht_exists(ht_t *h, string_t *key) { return ht_get(h, key) != NULL; } void ht_delete(ht_t *h, string_t *key, void (*freefunc)(void *)) { + if (key == NULL) + return; sll_delete(h->buckets[hash(h, key->value)], key, freefunc); } |