diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | examples/CMakeLists.txt | 7 | ||||
-rw-r--r-- | examples/exception-handler.c | 100 | ||||
-rw-r--r-- | examples/execute-file.c | 118 | ||||
-rw-r--r-- | examples/execute-string.c | 128 | ||||
-rw-r--r-- | examples/native-function.c | 104 | ||||
-rw-r--r-- | examples/state-reset.c | 94 | ||||
-rw-r--r-- | examples/state-reuse.c | 98 |
8 files changed, 651 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 83b029e..c77ecec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,3 +135,5 @@ INSTALL(TARGETS ${LIBRARIES} LIBRARY DESTINATION lib/ucode) FILE(GLOB UCODE_HEADERS "include/ucode/*.h") INSTALL(FILES ${UCODE_HEADERS} DESTINATION include/ucode) + +ADD_SUBDIRECTORY(examples) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..12d32ba --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,7 @@ +FILE(GLOB examples "*.c") +FOREACH(example ${examples}) + GET_FILENAME_COMPONENT(example ${example} NAME_WE) + SET(CLI_SOURCES main.c) + ADD_EXECUTABLE(${example} ${example}.c) + TARGET_LINK_LIBRARIES(${example} libucode ${json}) +ENDFOREACH(example) diff --git a/examples/exception-handler.c b/examples/exception-handler.c new file mode 100644 index 0000000..e2b1058 --- /dev/null +++ b/examples/exception-handler.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> + +#include <ucode/compiler.h> +#include <ucode/lib.h> +#include <ucode/vm.h> + + +#define MULTILINE_STRING(...) #__VA_ARGS__ + +static const char *program = MULTILINE_STRING( + {% + function fail() { + /* invoke not existing function to raise runtime error */ + doesnotexist(); + } + + fail(); + %} +); + +static uc_parse_config_t config = { + .strict_declarations = false, + .lstrip_blocks = true, + .trim_blocks = true +}; + +static void +log_exception(uc_vm_t *vm, uc_exception_t *ex) +{ + char *trace = ucv_to_jsonstring_formatted(vm, ex->stacktrace, ' ', 2); + + printf("Program raised an exception:\n"); + printf(" type=%d\n", ex->type); + printf(" message=%s\n", ex->message); + printf(" stacktrace=%s\n", trace); + + free(trace); +} + +int main(int argc, char **argv) +{ + int exit_code = 0; + + /* create a source buffer containing the program code */ + uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + + /* compile source buffer into function */ + char *syntax_error = NULL; + uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + + /* release source buffer */ + uc_source_put(src); + + /* check if compilation failed */ + if (!progfunc) { + fprintf(stderr, "Failed to compile program: %s\n", syntax_error); + + return 1; + } + + /* initialize VM context */ + uc_vm_t vm = { 0 }; + uc_vm_init(&vm, &config); + + /* load standard library into global VM scope */ + uc_load_stdlib(uc_vm_scope_get(&vm)); + + /* register custom exception handler */ + uc_vm_exception_handler_set(&vm, log_exception); + + /* execute program function */ + int return_code = uc_vm_execute(&vm, progfunc, NULL); + + /* handle return status */ + if (return_code == ERROR_COMPILE || return_code == ERROR_RUNTIME) { + printf("An error occurred while running the program\n"); + exit_code = 1; + } + + /* free VM context */ + uc_vm_free(&vm); + + return exit_code; +} diff --git a/examples/execute-file.c b/examples/execute-file.c new file mode 100644 index 0000000..2e86f7d --- /dev/null +++ b/examples/execute-file.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> + +#include <ucode/compiler.h> +#include <ucode/lib.h> +#include <ucode/vm.h> + + +static uc_parse_config_t config = { + .strict_declarations = false, + .lstrip_blocks = true, + .trim_blocks = true +}; + +int main(int argc, char **argv) +{ + int exit_code = 0; + + if (argc != 2) { + fprintf(stderr, "Usage: %s sourcefile.uc\n", argv[0]); + + return 1; + } + + /* create a source buffer from the given input file */ + uc_source_t *src = uc_source_new_file(argv[1]); + + /* check if source file could be opened */ + if (!src) { + fprintf(stderr, "Unable to open source file %s\n", argv[1]); + + return 1; + } + + /* compile source buffer into function */ + char *syntax_error = NULL; + uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + + /* release source buffer */ + uc_source_put(src); + + /* check if compilation failed */ + if (!progfunc) { + fprintf(stderr, "Failed to compile program: %s\n", syntax_error); + + return 1; + } + + /* initialize VM context */ + uc_vm_t vm = { 0 }; + uc_vm_init(&vm, &config); + + /* load standard library into global VM scope */ + uc_load_stdlib(uc_vm_scope_get(&vm)); + + /* add global variables x and y to VM scope */ + ucv_object_add(uc_vm_scope_get(&vm), "x", ucv_int64_new(123)); + ucv_object_add(uc_vm_scope_get(&vm), "y", ucv_int64_new(456)); + + /* execute compiled program function */ + uc_value_t *last_expression_result = NULL; + int return_code = uc_vm_execute(&vm, progfunc, &last_expression_result); + + /* handle return status */ + switch (return_code) { + case STATUS_OK: + exit_code = 0; + + char *s = ucv_to_string(&vm, last_expression_result); + + printf("Program finished successfully.\n"); + printf("Function return value is %s\n", s); + free(s); + break; + + case STATUS_EXIT: + exit_code = (int)ucv_int64_get(last_expression_result); + + printf("The invoked program called exit().\n"); + printf("Exit code is %d\n", exit_code); + break; + + case ERROR_COMPILE: + exit_code = 1; + + printf("A compilation error occurred while running the program\n"); + break; + + case ERROR_RUNTIME: + exit_code = 2; + + printf("A runtime error occurred while running the program\n"); + break; + } + + /* free last expression result */ + ucv_put(last_expression_result); + + /* free VM context */ + uc_vm_free(&vm); + + return exit_code; +} diff --git a/examples/execute-string.c b/examples/execute-string.c new file mode 100644 index 0000000..c51a600 --- /dev/null +++ b/examples/execute-string.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Example to compile a C string into an ucode program. + * Build with gcc -o execute-string -lucode execute-string.c + */ + +#include <stdio.h> + +#include <ucode/compiler.h> +#include <ucode/lib.h> +#include <ucode/vm.h> + + +#define MULTILINE_STRING(...) #__VA_ARGS__ + +static const char *program = MULTILINE_STRING( + {% + function add(a, b) { + c = a + b; + + return c; + } + + result = add(x, y); + + printf('%d + %d is %d\n', x, y, result); + + return result; + %} +); + +static uc_parse_config_t config = { + .strict_declarations = false, + .lstrip_blocks = true, + .trim_blocks = true +}; + +int main(int argc, char **argv) +{ + int exit_code = 0; + + /* create a source buffer containing the program code */ + uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + + /* compile source buffer into function */ + char *syntax_error = NULL; + uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + + /* release source buffer */ + uc_source_put(src); + + /* check if compilation failed */ + if (!progfunc) { + fprintf(stderr, "Failed to compile program: %s\n", syntax_error); + + return 1; + } + + /* initialize VM context */ + uc_vm_t vm = { 0 }; + uc_vm_init(&vm, &config); + + /* load standard library into global VM scope */ + uc_load_stdlib(uc_vm_scope_get(&vm)); + + /* add global variables x and y to VM scope */ + ucv_object_add(uc_vm_scope_get(&vm), "x", ucv_int64_new(123)); + ucv_object_add(uc_vm_scope_get(&vm), "y", ucv_int64_new(456)); + + /* execute compiled program function */ + uc_value_t *last_expression_result = NULL; + int return_code = uc_vm_execute(&vm, progfunc, &last_expression_result); + + /* handle return status */ + switch (return_code) { + case STATUS_OK: + exit_code = 0; + + char *s = ucv_to_string(&vm, last_expression_result); + + printf("Program finished successfully.\n"); + printf("Function return value is %s\n", s); + free(s); + break; + + case STATUS_EXIT: + exit_code = (int)ucv_int64_get(last_expression_result); + + printf("The invoked program called exit().\n"); + printf("Exit code is %d\n", exit_code); + break; + + case ERROR_COMPILE: + exit_code = 1; + + printf("A compilation error occurred while running the program\n"); + break; + + case ERROR_RUNTIME: + exit_code = 2; + + printf("A runtime error occurred while running the program\n"); + break; + } + + /* free last expression result */ + ucv_put(last_expression_result); + + /* free VM context */ + uc_vm_free(&vm); + + return exit_code; +} diff --git a/examples/native-function.c b/examples/native-function.c new file mode 100644 index 0000000..89b3d15 --- /dev/null +++ b/examples/native-function.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> + +#include <ucode/compiler.h> +#include <ucode/lib.h> +#include <ucode/vm.h> + + +#define MULTILINE_STRING(...) #__VA_ARGS__ + +static const char *program = MULTILINE_STRING( + {% + print("add() = " + add(5, 3.1, 2) + "\n"); + print("multiply() = " + multiply(7.3, 5) + "\n"); + %} +); + +static uc_parse_config_t config = { + .strict_declarations = false, + .lstrip_blocks = true, + .trim_blocks = true +}; + +static uc_value_t * +multiply_two_numbers(uc_vm_t *vm, size_t nargs) +{ + uc_value_t *x = uc_get_arg(0); + uc_value_t *y = uc_get_arg(1); + + return ucv_double_new(ucv_to_double(x) * ucv_to_double(y)); +} + +static uc_value_t * +add_all_numbers(uc_vm_t *vm, size_t nargs) +{ + double res = 0.0; + + for (size_t n = 0; n < nargs; n++) + res += ucv_to_double(uc_get_arg(n)); + + return ucv_double_new(res); +} + +int main(int argc, char **argv) +{ + int exit_code = 0; + + /* create a source buffer containing the program code */ + uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + + /* compile source buffer into function */ + char *syntax_error = NULL; + uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + + /* release source buffer */ + uc_source_put(src); + + /* check if compilation failed */ + if (!progfunc) { + fprintf(stderr, "Failed to compile program: %s\n", syntax_error); + + return 1; + } + + /* initialize VM context */ + uc_vm_t vm = { 0 }; + uc_vm_init(&vm, &config); + + /* load standard library into global VM scope */ + uc_load_stdlib(uc_vm_scope_get(&vm)); + + /* register our native functions as "add" and "multiply" */ + uc_add_function(uc_vm_scope_get(&vm), "add", add_all_numbers); + uc_add_function(uc_vm_scope_get(&vm), "multiply", multiply_two_numbers); + + /* execute program function */ + int return_code = uc_vm_execute(&vm, progfunc, NULL); + + /* handle return status */ + if (return_code == ERROR_COMPILE || return_code == ERROR_RUNTIME) { + printf("An error occurred while running the program\n"); + exit_code = 1; + } + + /* free VM context */ + uc_vm_free(&vm); + + return exit_code; +} diff --git a/examples/state-reset.c b/examples/state-reset.c new file mode 100644 index 0000000..893ea26 --- /dev/null +++ b/examples/state-reset.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> + +#include <ucode/compiler.h> +#include <ucode/lib.h> +#include <ucode/vm.h> + + +#define MULTILINE_STRING(...) #__VA_ARGS__ + +static const char *program = MULTILINE_STRING( + {% + /* the global test variable should've been reset since the previous run */ + print("Global variable is null? " + (global.test == null) + "\n"); + + global.test = true; + %} +); + +static uc_parse_config_t config = { + .strict_declarations = false, + .lstrip_blocks = true, + .trim_blocks = true +}; + +int main(int argc, char **argv) +{ + int exit_code = 0; + + /* create a source buffer containing the program code */ + uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + + /* compile source buffer into function */ + char *syntax_error = NULL; + uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + + /* release source buffer */ + uc_source_put(src); + + /* check if compilation failed */ + if (!progfunc) { + fprintf(stderr, "Failed to compile program: %s\n", syntax_error); + + return 1; + } + + /* execute compiled program function five times */ + for (int i = 0; i < 5; i++) { + /* initialize VM context */ + uc_vm_t vm = { 0 }; + uc_vm_init(&vm, &config); + + /* load standard library into global VM scope */ + uc_load_stdlib(uc_vm_scope_get(&vm)); + + printf("Iteration %d: ", i + 1); + + /* take additional reference to progfunc to avoid freeing it after execution */ + ucv_get(&progfunc->header); + + /* execute program function */ + int return_code = uc_vm_execute(&vm, progfunc, NULL); + + /* handle return status */ + if (return_code == ERROR_COMPILE || return_code == ERROR_RUNTIME) { + printf("An error occurred while running the program\n"); + exit_code = 1; + break; + } + + /* free VM context */ + uc_vm_free(&vm); + } + + /* release program function */ + ucv_put(&progfunc->header); + + return exit_code; +} diff --git a/examples/state-reuse.c b/examples/state-reuse.c new file mode 100644 index 0000000..4ebf556 --- /dev/null +++ b/examples/state-reuse.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> + +#include <ucode/compiler.h> +#include <ucode/lib.h> +#include <ucode/vm.h> + + +#define MULTILINE_STRING(...) #__VA_ARGS__ + +static const char *program = MULTILINE_STRING( + {% + let n = global.value || 1; + + print("Current value is " + n + "\n"); + + global.value = n * 2; + %} +); + +static uc_parse_config_t config = { + .strict_declarations = false, + .lstrip_blocks = true, + .trim_blocks = true +}; + +int main(int argc, char **argv) +{ + int exit_code = 0; + + /* create a source buffer containing the program code */ + uc_source_t *src = uc_source_new_buffer("my program", strdup(program), strlen(program)); + + /* compile source buffer into function */ + char *syntax_error = NULL; + uc_function_t *progfunc = uc_compile(&config, src, &syntax_error); + + /* release source buffer */ + uc_source_put(src); + + /* check if compilation failed */ + if (!progfunc) { + fprintf(stderr, "Failed to compile program: %s\n", syntax_error); + + return 1; + } + + /* initialize VM context */ + uc_vm_t vm = { 0 }; + uc_vm_init(&vm, &config); + + /* load standard library into global VM scope */ + uc_load_stdlib(uc_vm_scope_get(&vm)); + + /* execute compiled program function five times */ + for (int i = 0; i < 5; i++) { + printf("Iteration %d: ", i + 1); + + /* take additional reference to progfunc to avoid freeing it after execution */ + ucv_get(&progfunc->header); + + /* execute program function */ + int return_code = uc_vm_execute(&vm, progfunc, NULL); + + /* handle return status */ + if (return_code == ERROR_COMPILE || return_code == ERROR_RUNTIME) { + printf("An error occurred while running the program\n"); + exit_code = 1; + break; + } + + /* perform GC step */ + ucv_gc(&vm); + } + + /* release program function */ + ucv_put(&progfunc->header); + + /* free VM context */ + uc_vm_free(&vm); + + return exit_code; +} |