diff options
| -rw-r--r-- | builtins/bool.c | 6 | ||||
| -rw-r--r-- | builtins/functions.c | 29 | ||||
| -rw-r--r-- | builtins/functions.h | 1 | ||||
| -rw-r--r-- | builtins/text.c | 2 | ||||
| -rw-r--r-- | compile.c | 185 | ||||
| -rw-r--r-- | environment.h | 1 | ||||
| -rw-r--r-- | parse.c | 43 | ||||
| -rw-r--r-- | test/arrays.tm | 189 | ||||
| -rw-r--r-- | test/corecursive_func.tm | 5 | ||||
| -rw-r--r-- | test/enums.tm | 63 | ||||
| -rw-r--r-- | test/extern.tm | 6 | ||||
| -rw-r--r-- | test/for.tm | 37 | ||||
| -rw-r--r-- | test/functions.tm | 15 | ||||
| -rw-r--r-- | test/integers.tm | 84 | ||||
| -rw-r--r-- | test/lambdas.tm | 47 | ||||
| -rw-r--r-- | test/lang.tm | 27 | ||||
| -rw-r--r-- | test/minmax.tm | 33 | ||||
| -rw-r--r-- | test/nums.tm | 73 | ||||
| -rw-r--r-- | test/reductions.tm | 28 | ||||
| -rw-r--r-- | test/structs.tm | 26 | ||||
| -rw-r--r-- | test/tables.tm | 116 | ||||
| -rw-r--r-- | test/text.tm | 99 | ||||
| -rw-r--r-- | tomo.c | 32 |
23 files changed, 692 insertions, 455 deletions
diff --git a/builtins/bool.c b/builtins/bool.c index ff5d0ec4..1e741be1 100644 --- a/builtins/bool.c +++ b/builtins/bool.c @@ -26,10 +26,12 @@ public CORD Bool$as_text(const bool *b, bool colorize, const TypeInfo *type) public Bool_t Bool$from_text(CORD text, bool *success) { CORD lower = Text$lower(text); - if (CORD_cmp(lower, "yes") == 0 || CORD_cmp(lower, "on") == 0 || CORD_cmp(lower, "true") == 0) { + if (CORD_cmp(lower, "yes") == 0 || CORD_cmp(lower, "on") == 0 + || CORD_cmp(lower, "true") == 0 || CORD_cmp(lower, "1") == 0) { if (success) *success = yes; return yes; - } else if (CORD_cmp(lower, "no") == 0 || CORD_cmp(lower, "off") == 0 || CORD_cmp(lower, "false") == 0) { + } else if (CORD_cmp(lower, "no") == 0 || CORD_cmp(lower, "off") == 0 + || CORD_cmp(lower, "false") == 0 || CORD_cmp(lower, "0") == 0) { if (success) *success = yes; return no; } else { diff --git a/builtins/functions.c b/builtins/functions.c index acc0c758..4ff7a1a5 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -8,9 +8,9 @@ #include <sys/param.h> #include <uninorm.h> -#include "files.h" -#include "util.h" #include "array.h" +#include "bool.h" +#include "files.h" #include "functions.h" #include "halfsiphash.h" #include "pointer.h" @@ -18,6 +18,7 @@ #include "table.h" #include "text.h" #include "types.h" +#include "util.h" extern bool USE_COLOR; @@ -186,4 +187,28 @@ public void say(CORD text) } } +public bool pop_flag(char **argv, int *i, const char *flag, CORD *result) +{ + if (argv[*i][0] != '-' || argv[*i][1] != '-') { + return false; + } else if (streq(argv[*i] + 2, flag)) { + *result = CORD_EMPTY; + argv[*i] = NULL; + *i += 1; + return true; + } else if (strncmp(argv[*i] + 2, "no-", 3) == 0 && streq(argv[*i] + 5, flag)) { + *result = "no"; + argv[*i] = NULL; + *i += 1; + return true; + } else if (strncmp(argv[*i] + 2, flag, strlen(flag)) == 0 && argv[*i][2 + strlen(flag)] == '=') { + *result = CORD_from_char_star(argv[*i] + 2 + strlen(flag) + 1); + argv[*i] = NULL; + *i += 1; + return true; + } else { + return false; + } +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/functions.h b/builtins/functions.h index 7deaf2b0..53a6de2f 100644 --- a/builtins/functions.h +++ b/builtins/functions.h @@ -20,5 +20,6 @@ uint32_t generic_hash(const void *obj, const TypeInfo *type); int32_t generic_compare(const void *x, const void *y, const TypeInfo *type); bool generic_equal(const void *x, const void *y, const TypeInfo *type); CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type); +bool pop_flag(char **argv, int *i, const char *flag, CORD *result); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/text.c b/builtins/text.c index 0450e9b2..096c3447 100644 --- a/builtins/text.c +++ b/builtins/text.c @@ -225,7 +225,7 @@ public CORD Text$replace(CORD text, CORD pat, CORD replacement, int64_t limit) if (!text || !pat) return text; CORD ret = CORD_EMPTY; size_t pos = 0, pat_len = CORD_len(pat); - for (size_t found; limit > 0 && (found=CORD_str(text, pos, pat)) != CORD_NOT_FOUND; --limit) { + for (size_t found; limit != 0 && (found=CORD_str(text, pos, pat)) != CORD_NOT_FOUND; --limit) { ret = CORD_all(ret, CORD_substr(text, pos, found - pos), replacement); pos = found + pat_len; } @@ -294,7 +294,7 @@ CORD compile_statement(env_t *env, ast_t *ast) env->code->imports = CORD_all(env->code->imports, "#include <", path, ".h>\n"); env->code->object_files = CORD_all(env->code->object_files, "-l", name, " "); } - return CORD_all(name, "$use();\n"); + return CORD_EMPTY; } else { type_t *t = get_type(env, decl->value); if (t->tag == AbortType || t->tag == VoidType) @@ -917,7 +917,10 @@ static CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg CORD compile(env_t *env, ast_t *ast) { switch (ast->tag) { - case Nil: return CORD_asprintf("$Null(%r)", compile_type_ast(env, Match(ast, Nil)->type)); + case Nil: { + type_t *t = parse_type_ast(env, Match(ast, Nil)->type); + return CORD_all("((", compile_type(env, t), "*)NULL)"); + } case Bool: return Match(ast, Bool)->b ? "yes" : "no"; case Var: { binding_t *b = get_binding(env, Match(ast, Var)->name); @@ -1816,18 +1819,17 @@ void compile_namespace(env_t *env, const char *ns_name, ast_t *block) auto decl = Match(ast, Declare); type_t *t = get_type(ns_env, decl->value); - CORD var_decl = CORD_all(compile_type(env, t), " ", compile(ns_env, decl->var), ";\n"); + if (!is_constant(decl->value)) + code_err(decl->value, "This value is supposed to be a compile-time constant, but I can't figure out how to make it one"); + CORD var_decl = CORD_all(compile_type(env, t), " ", compile(ns_env, decl->var), " = ", compile(ns_env, decl->value), ";\n"); env->code->staticdefs = CORD_cat(env->code->staticdefs, var_decl); - CORD init = CORD_all(compile(ns_env, decl->var), " = ", compile(ns_env, decl->value), ";\n"); - env->code->main = CORD_cat(env->code->main, init); - env->code->fndefs = CORD_all(env->code->fndefs, "extern ", compile_type(env, t), " ", compile(ns_env, decl->var), ";\n"); break; } default: { CORD code = compile_statement(ns_env, ast); - env->code->main = CORD_cat(env->code->main, code); + assert(!code); break; } } @@ -1877,6 +1879,144 @@ CORD compile_type_info(env_t *env, type_t *t) } } +static CORD compile_main_arg_parser(env_t *env, const char *module_name, type_t *main_fn_type) +{ + CORD code = CORD_all("void ", module_name, "$main$run(int argc, char *argv[]) {\n"); + auto fn_info = Match(main_fn_type, FunctionType); + env_t *main_env = fresh_scope(env); + + CORD usage = CORD_EMPTY; + for (arg_t *arg = fn_info->args; arg; arg = arg->next) { + usage = CORD_cat(usage, " "); + type_t *t = get_arg_type(main_env, arg); + CORD flag = Text$replace(arg->name, "_", "-", INT64_MAX); + if (arg->default_val) { + if (t->tag == BoolType) + usage = CORD_all(usage, "[--", flag, "]"); + else + usage = CORD_all(usage, "[--", flag, "=...]"); + } else { + if (t->tag == BoolType) + usage = CORD_all(usage, "[--", flag, "|--no-", flag, "]"); + else + usage = CORD_all(usage, "<", flag, ">"); + } + } + code = CORD_all(code, "CORD $usage = CORD_all(\"Usage: \", argv[0], ", Text$quoted(usage, false), ");\n", + "#define $USAGE_ERR(...) errx(1, CORD_to_const_char_star(CORD_all(__VA_ARGS__)))\n" + "#define $IS_FLAG(str, flag) (strncmp(str, flag, strlen(flag) == 0 && (str[strlen(flag)] == 0 || str[strlen(flag)] == '=')) == 0)\n"); + + // Declare args: + for (arg_t *arg = fn_info->args; arg; arg = arg->next) { + type_t *t = get_arg_type(main_env, arg); + assert(arg->name); + code = CORD_all( + code, compile_declaration(env, t, arg->name), ";\n", + "bool ", arg->name, "$is_set = no;\n"); + set_binding(env, arg->name, new(binding_t, .type=t, .code=arg->name)); + } + // Provide --flags: + code = CORD_all(code, "CORD $flag;\n" + "for (int i = 1; i < argc; ) {\n" + "if (streq(argv[i], \"--\")) {\n" + "argv[i] = NULL;\n" + "break;\n" + "}\n" + "if (strncmp(argv[i], \"--\", 2) != 0) {\n++i;\ncontinue;\n}\n"); + for (arg_t *arg = fn_info->args; arg; arg = arg->next) { + type_t *t = get_arg_type(main_env, arg); + CORD flag = Text$replace(arg->name, "_", "-", INT64_MAX); + switch (t->tag) { + case BoolType: { + code = CORD_all(code, "else if (pop_flag(argv, &i, \"", flag, "\", &$flag)) {\n" + "if ($flag) {\n", + arg->name, " = Bool$from_text($flag, &", arg->name, "$is_set", ");\n" + "if (!", arg->name, "$is_set) \n" + "$USAGE_ERR(\"Invalid argument for '--", flag, "'\\n\", $usage);\n", + "} else {\n", + arg->name, " = yes;\n", + arg->name, "$is_set = yes;\n" + "}\n" + "}\n"); + break; + } + case TextType: { + code = CORD_all(code, "else if (pop_flag(argv, &i, \"", flag, "\", &$flag)) {\n", + arg->name, " = CORD_to_const_char_star($flag);\n", + arg->name, "$is_set = yes;\n" + "}\n"); + break; + } + case IntType: case NumType: { + CORD type_name = type_to_cord(t); + code = CORD_all(code, "else if (pop_flag(argv, &i, \"", flag, "\", &$flag)) {\n", + "if ($flag == CORD_EMPTY)\n" + "$USAGE_ERR(\"No value provided for '--", flag, "'\\n\", $usage);\n" + "CORD $invalid = CORD_EMPTY;\n", + arg->name, " = ", type_name, "$from_text($flag, &$invalid);\n" + "if ($invalid != CORD_EMPTY)\n" + "$USAGE_ERR(\"Invalid value provided for '--", flag, "'\\n\", $usage);\n", + arg->name, "$is_set = yes;\n" + "}\n"); + break; + } + default: + compiler_err(NULL, NULL, NULL, "Main function has unsupported argument type: %T", t); + } + } + + code = CORD_all( + code, "else {\n" + "$USAGE_ERR(\"Unrecognized argument: \", argv[i], \"\\n\", $usage);\n" + "}\n" + "}\n" + "int i = 1;\n" + "while (i < argc && argv[i] == NULL)\n" + "++i;\n"); + + for (arg_t *arg = fn_info->args; arg; arg = arg->next) { + code = CORD_all(code, "if (!", arg->name, "$is_set) {\n"); + type_t *t = get_arg_type(env, arg); + if (arg->default_val) { + code = CORD_all(code, arg->name, " = ", compile(env, arg->default_val), ";\n"); + } else { + code = CORD_all( + code, + "if (i < argc) {"); + if (t->tag == TextType) { + code = CORD_all(code, arg->name, " = CORD_from_char_star(argv[i]);\n"); + } else { + code = CORD_all( + code, + "CORD $invalid;\n", + arg->name, " = ", type_to_cord(t), "$from_text(argv[i], &$invalid)", ";\n" + "if ($invalid != CORD_EMPTY)\n" + "$USAGE_ERR(\"Unable to parse this argument as a ", type_to_cord(t), ": \", CORD_from_char_star(argv[i]));\n"); + } + code = CORD_all( + code, + "argv[i++] = NULL;\n" + "while (i < argc && argv[i] == NULL)\n" + "++i;\n} else {\n" + "$USAGE_ERR(\"Required argument '", arg->name, "' was not provided!\\n\", $usage);\n", + "}\n"); + } + code = CORD_all(code, "}\n"); + } + + + code = CORD_all(code, "for (; i < argc; i++) {\n" + "if (argv[i])\n$USAGE_ERR(\"Unexpected argument: \", Text$quoted(argv[i], false), \"\\n\", $usage);\n}\n"); + + code = CORD_all(code, module_name, "$main("); + for (arg_t *arg = fn_info->args; arg; arg = arg->next) { + code = CORD_all(code, arg->name); + if (arg->next) code = CORD_all(code, ", "); + } + code = CORD_all(code, ");\n}\n"); + return code; +} + module_code_t compile_file(ast_t *ast) { env_t *env = new_compilation_unit(); @@ -1905,11 +2045,26 @@ module_code_t compile_file(ast_t *ast) compile(env, decl->value), ";\n"); } else { CORD code = compile_statement(env, stmt->ast); - if (code) - CORD_appendf(&env->code->main, "%r\n", code); + assert(!code); + // if (code) + // env->code->main = CORD_all(env->code->main, code, "\n"); } } + env->code->fndefs = CORD_all(env->code->fndefs, "void ", name, "$main$run(int argc, char *argv[]);\n"); + + binding_t *main_fn = get_binding(env, "main"); + if (!main_fn) { + env->code->funcs = CORD_all(env->code->funcs, "public void ", name, "$main$run(int argc, char *argv[]) {\n" + "(void)argc;\n" + "(void)argv;\n" + "}\n"); + } else if (main_fn->type->tag != FunctionType) { + compiler_err(NULL, NULL, NULL, "The name 'main' is bound to something that isn't a function, it's %T", main_fn->type); + } else { + env->code->funcs = CORD_all(env->code->funcs, compile_main_arg_parser(env, name, main_fn->type)); + } + return (module_code_t){ .module_name=name, .object_files=env->code->object_files, @@ -1918,22 +2073,14 @@ module_code_t compile_file(ast_t *ast) "#include <tomo/tomo.h>\n", env->code->typedefs, "\n", env->code->typecode, "\n", - env->code->fndefs, "\n", - "public void ", env->file_prefix, "use(void);\n" + env->code->fndefs, "\n" ), .c_file=CORD_all( // CORD_asprintf("#line 0 %r\n", Text$quoted(ast->file->filename, false)), env->code->imports, "\n", env->code->staticdefs, "\n", env->code->funcs, "\n", - env->code->typeinfos, "\n", - "\n" - "public void ", env->file_prefix, "use(void) {\n" - "static bool $loaded = no;\n" - "if ($loaded) return;\n" - "$loaded = yes;\n\n", - env->code->main, - "}\n" + env->code->typeinfos, "\n" ), }; } diff --git a/environment.h b/environment.h index dc7f527c..301ffbb5 100644 --- a/environment.h +++ b/environment.h @@ -15,7 +15,6 @@ typedef struct { CORD staticdefs; CORD funcs; CORD typeinfos; - CORD main; CORD object_files; } compilation_unit_t; @@ -96,6 +96,7 @@ static PARSER(parse_doctest); static PARSER(parse_use); static PARSER(parse_linker); static PARSER(parse_namespace); +static PARSER(parse_file_body); static type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos); @@ -509,7 +510,7 @@ type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos) { bool is_readonly = match(&pos, "%"); spaces(&pos); type_ast_t *type = expect(ctx, start, &pos, parse_type, - "I couldn't parse a pointer type after this point"); + "I couldn't parse a pointer type after this point"); return NewTypeAST(ctx->file, start, pos, PointerTypeAST, .pointed=type, .is_optional=optional, .is_stack=is_stack, .is_readonly=is_readonly); } @@ -1548,7 +1549,8 @@ PARSER(parse_namespace) { ||(stmt=optional(ctx, &pos, parse_func_def)) ||(stmt=optional(ctx, &pos, parse_use)) ||(stmt=optional(ctx, &pos, parse_linker)) - ||(stmt=optional(ctx, &pos, parse_statement))) + ||(stmt=optional(ctx, &pos, parse_extern)) + ||(stmt=optional(ctx, &pos, parse_declaration))) { statements = new(ast_list_t, .ast=stmt, .next=statements); pos = stmt->end; @@ -1559,7 +1561,7 @@ PARSER(parse_namespace) { // } } else { if (get_indent(ctx->file, next) > indent && next < strchrnul(next, '\n')) - parser_err(ctx, next, strchrnul(next, '\n'), "I couldn't parse this namespace statement"); + parser_err(ctx, next, strchrnul(next, '\n'), "I couldn't parse this namespace declaration"); break; } } @@ -1567,6 +1569,39 @@ PARSER(parse_namespace) { return NewAST(ctx->file, start, pos, Block, .statements=statements); } +PARSER(parse_file_body) { + const char *start = pos; + whitespace(&pos); + ast_list_t *statements = NULL; + for (;;) { + const char *next = pos; + whitespace(&next); + if (get_indent(ctx->file, next) != 0) break; + ast_t *stmt; + if ((stmt=optional(ctx, &pos, parse_struct_def)) + ||(stmt=optional(ctx, &pos, parse_enum_def)) + ||(stmt=optional(ctx, &pos, parse_lang_def)) + ||(stmt=optional(ctx, &pos, parse_func_def)) + ||(stmt=optional(ctx, &pos, parse_use)) + ||(stmt=optional(ctx, &pos, parse_linker)) + ||(stmt=optional(ctx, &pos, parse_extern)) + ||(stmt=optional(ctx, &pos, parse_declaration))) + { + statements = new(ast_list_t, .ast=stmt, .next=statements); + pos = stmt->end; + whitespace(&pos); // TODO: check for newline + } else { + break; + } + } + whitespace(&pos); + if (pos < ctx->file->text + ctx->file->len && *pos != '\0') { + parser_err(ctx, pos, strchrnul(pos, '\n'), "I expect all top-level statements to be declarations of some kind"); + } + REVERSE_LIST(statements); + return NewAST(ctx->file, start, pos, Block, .statements=statements); +} + PARSER(parse_struct_def) { // struct Foo(...) \n body const char *start = pos; @@ -1902,7 +1937,7 @@ ast_t *parse_file(file_t *file, jmp_buf *on_err) { some_not(&pos, "\r\n"); whitespace(&pos); - ast_t *ast = parse_namespace(&ctx, pos); + ast_t *ast = parse_file_body(&ctx, pos); pos = ast->end; whitespace(&pos); if (pos < file->text + file->len && *pos != '\0') { diff --git a/test/arrays.tm b/test/arrays.tm index 17aeee53..c8e34af4 100644 --- a/test/arrays.tm +++ b/test/arrays.tm @@ -1,96 +1,97 @@ -if yes - >> [:Num32] - = [] : [Num32] - -if yes - >> arr := [10, 20, 30] - = [10, 20, 30] - - >> arr[1] - = 10 - >> arr[-1] - = 30 - - >> #arr - = 3 - - sum := 0 - for x in arr - sum += x - >> sum - = 60 - - str := "" - for i,x in arr - str ++= "({i},{x})" - >> str - = "(1,10)(2,20)(3,30)" - -if yes - >> arr := [10, 20] ++ [30, 40] - = [10, 20, 30, 40] - - >> arr ++= [50, 60] - >> arr - = [10, 20, 30, 40, 50, 60] - - >> arr ++= 70 - >> arr - = [10, 20, 30, 40, 50, 60, 70] - -if yes - >> arr := [10, 20] - >> copy := arr - >> arr ++= 30 - >> arr - = [10, 20, 30] - >> copy - = [10, 20] - -if yes - >> [10*i for i in 5] +func main() + if yes + >> [:Num32] + = [] : [Num32] + + if yes + >> arr := [10, 20, 30] + = [10, 20, 30] + + >> arr[1] + = 10 + >> arr[-1] + = 30 + + >> #arr + = 3 + + sum := 0 + for x in arr + sum += x + >> sum + = 60 + + str := "" + for i,x in arr + str ++= "({i},{x})" + >> str + = "(1,10)(2,20)(3,30)" + + if yes + >> arr := [10, 20] ++ [30, 40] + = [10, 20, 30, 40] + + >> arr ++= [50, 60] + >> arr + = [10, 20, 30, 40, 50, 60] + + >> arr ++= 70 + >> arr + = [10, 20, 30, 40, 50, 60, 70] + + if yes + >> arr := [10, 20] + >> copy := arr + >> arr ++= 30 + >> arr + = [10, 20, 30] + >> copy + = [10, 20] + + if yes + >> [10*i for i in 5] + = [10, 20, 30, 40, 50] + + >> [i*10 for i in 5] = [10, 20, 30, 40, 50] ->> [i*10 for i in 5] -= [10, 20, 30, 40, 50] - ->> [i*10 for i in 5 if i mod 2 != 0] -= [10, 30, 50] - ->> [x for x in y if x > 1 for y in [3, 4, 5] if y < 5] -= [2, 3, 2, 3, 4] - -if yes - >> arr := @[10, 20] - >> copy := arr[] - >> arr:insert(30) - >> arr - = @[10, 20, 30] - >> copy - = [10, 20] - -if yes - >> arr := [10, 20, 30] - >> arr:reversed() - = [30, 20, 10] - -if yes - >> nums := [10, -20, 30] - // Sorted function doesn't mutate original: - >> nums:sorted() - = [-20, 10, 30] - >> nums - = [10, -20, 30] - // Sort function does mutate in place: - >> nums:sort() - >> nums - = [-20, 10, 30] - // Custom sort functions: - >> nums:sort(func(x:&%Int,y:&%Int) x:abs() <> y:abs()) - >> nums - = [10, -20, 30] - >> nums:sort(func(x:&%Int,y:&%Int) y[] <> x[]) - >> nums - = [30, 10, -20] - ->> ["A", "B", "C"]:sample(10, [1.0, 0.5, 0.0]) + >> [i*10 for i in 5 if i mod 2 != 0] + = [10, 30, 50] + + >> [x for x in y if x > 1 for y in [3, 4, 5] if y < 5] + = [2, 3, 2, 3, 4] + + if yes + >> arr := @[10, 20] + >> copy := arr[] + >> arr:insert(30) + >> arr + = @[10, 20, 30] + >> copy + = [10, 20] + + if yes + >> arr := [10, 20, 30] + >> arr:reversed() + = [30, 20, 10] + + if yes + >> nums := [10, -20, 30] + // Sorted function doesn't mutate original: + >> nums:sorted() + = [-20, 10, 30] + >> nums + = [10, -20, 30] + // Sort function does mutate in place: + >> nums:sort() + >> nums + = [-20, 10, 30] + // Custom sort functions: + >> nums:sort(func(x:&%Int,y:&%Int) x:abs() <> y:abs()) + >> nums + = [10, -20, 30] + >> nums:sort(func(x:&%Int,y:&%Int) y[] <> x[]) + >> nums + = [30, 10, -20] + + >> ["A", "B", "C"]:sample(10, [1.0, 0.5, 0.0]) diff --git a/test/corecursive_func.tm b/test/corecursive_func.tm index 0ff92e53..22ffd627 100644 --- a/test/corecursive_func.tm +++ b/test/corecursive_func.tm @@ -10,5 +10,6 @@ func pong(x:Int)->[Text] else return ["pong: {x}"] ->> ping(3) -= ["ping: 3", "pong: 2", "ping: 1", "pong: 0"] +func main() + >> ping(3) + = ["ping: 3", "pong: 2", "ping: 1", "pong: 0"] diff --git a/test/enums.tm b/test/enums.tm index aea18948..f321af8c 100644 --- a/test/enums.tm +++ b/test/enums.tm @@ -1,34 +1,35 @@ enum Foo(Zero, One(x:Int), Two(x,y:Int)) ->> Foo.Zero -= Foo.Zero ->> Foo.One(123) -= Foo.One(x=123) ->> Foo.Two(123, 456) -= Foo.Two(x=123, y=456) - ->> Foo.One(10) == Foo.One(10) -= yes - ->> Foo.One(10) == Foo.Zero -= no - ->> Foo.One(10) == Foo.One(-1) -= no - ->> Foo.One(10) < Foo.Two(1, 2) -= yes - ->> x := Foo.One(123) ->> t := {x=>"found"; default="missing"} ->> t[x] -= "found" ->> t[Foo.Zero] -= "missing" - -when x is o:One - >> o.x - = 123 -else - fail("Oops") +func main() + >> Foo.Zero + = Foo.Zero + >> Foo.One(123) + = Foo.One(x=123) + >> Foo.Two(123, 456) + = Foo.Two(x=123, y=456) + + >> Foo.One(10) == Foo.One(10) + = yes + + >> Foo.One(10) == Foo.Zero + = no + + >> Foo.One(10) == Foo.One(-1) + = no + + >> Foo.One(10) < Foo.Two(1, 2) + = yes + + >> x := Foo.One(123) + >> t := {x=>"found"; default="missing"} + >> t[x] + = "found" + >> t[Foo.Zero] + = "missing" + + when x is o:One + >> o.x + = 123 + else + fail("Oops") diff --git a/test/extern.tm b/test/extern.tm index a02a6a85..896c5730 100644 --- a/test/extern.tm +++ b/test/extern.tm @@ -1,3 +1,5 @@ extern CORD_cat:func(a:Text, b:Text)->Text ->> CORD_cat("hello ", "world") -= "hello world" + +func main() + >> CORD_cat("hello ", "world") + = "hello world" diff --git a/test/for.tm b/test/for.tm index 05990d37..51940973 100644 --- a/test/for.tm +++ b/test/for.tm @@ -7,11 +7,6 @@ func all_nums(nums:[Int])->Text return "EMPTY" return result ->> all_nums([10,20,30]) -= "10,20,30," ->> all_nums([:Int]) -= "EMPTY" - func labeled_nums(nums:[Int])->Text result := "" for i,num in nums @@ -20,11 +15,6 @@ func labeled_nums(nums:[Int])->Text return "EMPTY" return result ->> labeled_nums([10,20,30]) -= "1:10,2:20,3:30," ->> labeled_nums([:Int]) -= "EMPTY" - func table_str(t:{Text=>Text})->Text str := "" for k,v in t @@ -32,12 +22,6 @@ func table_str(t:{Text=>Text})->Text else return "EMPTY" return str ->> t := {"key1"=>"value1", "key2"=>"value2"} ->> table_str(t) -= "key1=>value1,key2=>value2," ->> table_str({:Text=>Text}) -= "EMPTY" - func table_key_str(t:{Text=>Text})->Text str := "" for k in t @@ -45,5 +29,22 @@ func table_key_str(t:{Text=>Text})->Text else return "EMPTY" return str ->> table_key_str(t) -= "key1,key2," +func main() + >> all_nums([10,20,30]) + = "10,20,30," + >> all_nums([:Int]) + = "EMPTY" + + >> labeled_nums([10,20,30]) + = "1:10,2:20,3:30," + >> labeled_nums([:Int]) + = "EMPTY" + + >> t := {"key1"=>"value1", "key2"=>"value2"} + >> table_str(t) + = "key1=>value1,key2=>value2," + >> table_str({:Text=>Text}) + = "EMPTY" + + >> table_key_str(t) + = "key1,key2," diff --git a/test/functions.tm b/test/functions.tm index 487e9467..13cdee55 100644 --- a/test/functions.tm +++ b/test/functions.tm @@ -1,14 +1,15 @@ func add(x:Int, y:Int)->Int return x + y ->> add(3, 5) -= 8 - func cached_heap(x:Int; cached)->@Int return @x ->> cached_heap(1) == cached_heap(1) -= yes ->> cached_heap(1) == cached_heap(2) -= no +func main() + >> add(3, 5) + = 8 + + >> cached_heap(1) == cached_heap(1) + = yes + >> cached_heap(1) == cached_heap(2) + = no diff --git a/test/integers.tm b/test/integers.tm index a3ec7fe2..376e0319 100644 --- a/test/integers.tm +++ b/test/integers.tm @@ -1,55 +1,55 @@ +func main() + >> 2 + 3 + = 5 ->> 2 + 3 -= 5 + >> 2 * 3 + = 6 ->> 2 * 3 -= 6 + >> 2 + 3 * 4 + = 14 ->> 2 + 3 * 4 -= 14 + >> 2 * 3 + 4 + = 10 ->> 2 * 3 + 4 -= 10 + >> 1i8 + 2i16 + = 3_i16 ->> 1i8 + 2i16 -= 3_i16 + >> 2 ^ 10 + = 1024 : Num ->> 2 ^ 10 -= 1024 : Num + >> 3 and 2 + = 2 ->> 3 and 2 -= 2 + >> 3 or 4 + = 7 ->> 3 or 4 -= 7 + >> 3 xor 2 + = 1 ->> 3 xor 2 -= 1 + nums := "" + for x in 5 + nums ++= "{x}," + >> nums + = "1,2,3,4,5," -nums := "" -for x in 5 - nums ++= "{x}," ->> nums -= "1,2,3,4,5," + >> x := 123 + >> x:format(digits=5) + = "00123" + >> x:hex() + = "0x7B" + >> x:octal() + = "0o173" ->> x := 123 ->> x:format(digits=5) -= "00123" ->> x:hex() -= "0x7B" ->> x:octal() -= "0o173" + >> Int.random() + >> Int.min + = -9223372036854775808 + >> Int.max + = 9223372036854775807 ->> Int.random() ->> Int.min -= -9223372036854775808 ->> Int.max -= 9223372036854775807 - ->> 123_i32:hex() -= "0x7B" ->> 123_i16:hex() -= "0x7B" ->> 123_i8:hex() -= "0x7B" + >> 123_i32:hex() + = "0x7B" + >> 123_i16:hex() + = "0x7B" + >> 123_i8:hex() + = "0x7B" diff --git a/test/lambdas.tm b/test/lambdas.tm index ca2acb5d..a445540b 100644 --- a/test/lambdas.tm +++ b/test/lambdas.tm @@ -1,33 +1,32 @@ ->> add_one := func(x:Int) x + 1 ->> add_one(10) -= 11 - ->> shout := func(msg:Text) say("{msg:upper()}!") ->> shout("hello") - ->> asdf := add_one ->> asdf(99) -= 100 - - func make_adder(x:Int)-> func(y:Int)->Int return func(y:Int) x + y ->> add_100 := make_adder(100) ->> add_100(5) -= 105 - - func suffix_fn(fn:func(t:Text)->Text, suffix:Text)->func(t:Text)->Text return func(t:Text) fn(t)++suffix ->> shout2 := suffix_fn(Text.upper, "!") ->> shout2("hello") -= "HELLO!" - func mul_func(n:Int, fn:func(x:Int)->Int)-> func(x:Int)->Int return func(x:Int) n*fn(x) ->> abs100 := mul_func(100, Int.abs) ->> abs100(-5) -= 500 +func main() + >> add_one := func(x:Int) x + 1 + >> add_one(10) + = 11 + + >> shout := func(msg:Text) say("{msg:upper()}!") + >> shout("hello") + + >> asdf := add_one + >> asdf(99) + = 100 + + >> add_100 := make_adder(100) + >> add_100(5) + = 105 + + >> shout2 := suffix_fn(Text.upper, "!") + >> shout2("hello") + = "HELLO!" + + >> abs100 := mul_func(100, Int.abs) + >> abs100(-5) + = 500 diff --git a/test/lang.tm b/test/lang.tm index 509a4ec6..ad09b605 100644 --- a/test/lang.tm +++ b/test/lang.tm @@ -14,20 +14,21 @@ lang HTML func paragraph(content:HTML)->HTML return $HTML{}"<p>{content}</p>" ->> HTML.HEADER -= $HTML"<!DOCTYPE HTML>" +func main() + >> HTML.HEADER + = $HTML"<!DOCTYPE HTML>" ->> user := "I <3 hax" ->> html := $HTML{}"Hello {user}!" -= $HTML"Hello I <3 hax!" ->> html ++ $HTML{}"<br>" -= $HTML"Hello I <3 hax!<br>" + >> user := "I <3 hax" + >> html := $HTML{}"Hello {user}!" + = $HTML"Hello I <3 hax!" + >> html ++ $HTML{}"<br>" + = $HTML"Hello I <3 hax!<br>" ->> $HTML{}"{1 + 2}" -= $HTML"3" + >> $HTML{}"{1 + 2}" + = $HTML"3" ->> $HTML{}"{3_i8}" -= $HTML"3" + >> $HTML{}"{3_i8}" + = $HTML"3" ->> html:paragraph() -= $HTML"<p>Hello I <3 hax!</p>" + >> html:paragraph() + = $HTML"<p>Hello I <3 hax!</p>" diff --git a/test/minmax.tm b/test/minmax.tm index 58d9661d..c3af68d6 100644 --- a/test/minmax.tm +++ b/test/minmax.tm @@ -1,26 +1,27 @@ ->> 3 _min_ 5 -= 3 ->> 5 _min_ 3 -= 3 - struct Foo(x:Int, y:Int) func len(f:Foo)->Num return Num.sqrt(f.x*f.x + f.y*f.y) ->> Foo(5, 1) _min_ Foo(5, 999) -= Foo(x=5, y=1) +func main() + >> 3 _min_ 5 + = 3 + >> 5 _min_ 3 + = 3 + + >> Foo(5, 1) _min_ Foo(5, 999) + = Foo(x=5, y=1) ->> Foo(5, 999) _min_.x Foo(5, 1) -= Foo(x=5, y=999) + >> Foo(5, 999) _min_.x Foo(5, 1) + = Foo(x=5, y=999) ->> Foo(999, 1) _min_.y Foo(1, 10) -= Foo(x=999, y=1) + >> Foo(999, 1) _min_.y Foo(1, 10) + = Foo(x=999, y=1) ->> Foo(-999, -999) _max_:len() Foo(10, 10) -= Foo(x=-999, y=-999) + >> Foo(-999, -999) _max_:len() Foo(10, 10) + = Foo(x=-999, y=-999) ->> foos := [Foo(5, 1), Foo(5, 99), Foo(-999, -999)] ->> (_max_) foos -= Foo(x=5, y=99) + >> foos := [Foo(5, 1), Foo(5, 99), Foo(-999, -999)] + >> (_max_) foos + = Foo(x=5, y=99) diff --git a/test/nums.tm b/test/nums.tm index 14926aa0..766cfb48 100644 --- a/test/nums.tm +++ b/test/nums.tm @@ -1,49 +1,50 @@ ->> n := 1.5 -= 1.5 +func main() + >> n := 1.5 + = 1.5 ->> n + n -= 3 + >> n + n + = 3 ->> n * 2 -= 3 + >> n * 2 + = 3 ->> n - n -= 0 + >> n - n + = 0 ->> Num.PI -= 3.14159 + >> Num.PI + = 3.14159 ->> Num.PI:format(precision=10) -= "3.1415926536" + >> Num.PI:format(precision=10) + = "3.1415926536" ->> Num.random() + >> Num.random() ->> Num.INF -= inf ->> Num.INF:isinf() -= yes + >> Num.INF + = inf + >> Num.INF:isinf() + = yes ->> Num.nan() -= nan ->> nan := Num.nan() ->> nan:isnan() -= yes ->> nan == nan -= no + >> Num.nan() + = nan + >> nan := Num.nan() + >> nan:isnan() + = yes + >> nan == nan + = no ->> Num.PI:cos():near(-1) -= yes ->> Num.PI:sin():near(0) -= yes + >> Num.PI:cos():near(-1) + = yes + >> Num.PI:sin():near(0) + = yes ->> 10.0:pow(3) -= 1000 + >> 10.0:pow(3) + = 1000 ->> Num.nan():near(Num.nan()) -= no + >> Num.nan():near(Num.nan()) + = no ->> Num.INF:near(-Num.INF) -= no + >> Num.INF:near(-Num.INF) + = no ->> Num32.sqrt(16f32) -= 4_f32 + >> Num32.sqrt(16f32) + = 4_f32 diff --git a/test/reductions.tm b/test/reductions.tm index e6b78539..6ed7823f 100644 --- a/test/reductions.tm +++ b/test/reductions.tm @@ -1,16 +1,18 @@ ->> (+) [10, 20, 30] -= 60 +struct Foo(x,y:Int) ->> (_max_) [3, 5, 2, 1, 4] -= 5 +func main() + >> (+) [10, 20, 30] + = 60 ->> (_max_:abs()) [1, -10, 5] -= -10 + >> (_max_) [3, 5, 2, 1, 4] + = 5 -struct Foo(x,y:Int) ->> (_max_) [Foo(0, 0), Foo(1, 0), Foo(0, 10)] -= Foo(x=1, y=0) ->> (_max_.y) [Foo(0, 0), Foo(1, 0), Foo(0, 10)] -= Foo(x=0, y=10) ->> (_max_.y:abs()) [Foo(0, 0), Foo(1, 0), Foo(0, 10), Foo(0, -999)] -= Foo(x=0, y=-999) + >> (_max_:abs()) [1, -10, 5] + = -10 + + >> (_max_) [Foo(0, 0), Foo(1, 0), Foo(0, 10)] + = Foo(x=1, y=0) + >> (_max_.y) [Foo(0, 0), Foo(1, 0), Foo(0, 10)] + = Foo(x=0, y=10) + >> (_max_.y:abs()) [Foo(0, 0), Foo(1, 0), Foo(0, 10), Foo(0, -999)] + = Foo(x=0, y=-999) diff --git a/test/structs.tm b/test/structs.tm index c038bd07..1d9de8d0 100644 --- a/test/structs.tm +++ b/test/structs.tm @@ -1,6 +1,8 @@ struct Pair(x,y:Int) struct Mixed(x:Int, text:Text) +struct LinkedList(x:Int, next=!LinkedList) +struct Password(text:Text; secret) func test_literals() >> x := Pair(10, 20) @@ -11,7 +13,6 @@ func test_literals() = yes >> x == Pair(-1, -2) = no -test_literals() func test_metamethods() >> x := Pair(10, 20) @@ -30,7 +31,6 @@ func test_metamethods() = "found" >> t2[y] = "missing" -test_metamethods() func test_mixed() >> x := Mixed(10, "Hello") @@ -48,16 +48,18 @@ func test_mixed() = "found" >> t[y] = "missing" -test_mixed() -struct LinkedList(x:Int, next=!LinkedList) ->> @LinkedList(10, @LinkedList(20)) +func main() + test_literals() + test_metamethods() + test_mixed() -struct Password(text:Text; secret) ->> my_pass := Password("Swordfish") -= Password(...) ->> users_by_password := {my_pass=> "User1", Password("xxx")=>"User2"} -= {Password(...)=>"User1", Password(...)=>"User2"} ->> users_by_password[my_pass] -= "User1" + >> @LinkedList(10, @LinkedList(20)) + + >> my_pass := Password("Swordfish") + = Password(...) + >> users_by_password := {my_pass=> "User1", Password("xxx")=>"User2"} + = {Password(...)=>"User1", Password(...)=>"User2"} + >> users_by_password[my_pass] + = "User1" diff --git a/test/tables.tm b/test/tables.tm index 74123f88..a55e4238 100644 --- a/test/tables.tm +++ b/test/tables.tm @@ -1,58 +1,58 @@ - ->> t := {"one"=>1, "two"=>2; default=999} -= {"one"=>1, "two"=>2; default=999} - ->> t["one"] -= 1 ->> t["two"] -= 2 ->> t["???"] -= 999 - -t_str := "" -for k,v in t - t_str ++= "({k}=>{v})" ->> t_str -= "(one=>1)(two=>2)" - ->> #t -= 2 ->> t.default -= ?%999 ->> t.fallback -= !{Text=>Int} - ->> t.keys -= ["one", "two"] ->> t.values -= [1, 2] - ->> t2 := {"three"=>3; fallback=t} -= {"three"=>3; fallback={"one"=>1, "two"=>2; default=999}} - ->> t2["one"] -= 1 ->> t2["three"] -= 3 ->> t2["???"] -= 999 - ->> #t2 -= 1 ->> t2.default -= !Int ->> t2.fallback -= ?%{"one"=>1, "two"=>2; default=999} - -t2_str := "" -for k,v in t2 - t2_str ++= "({k}=>{v})" ->> t2_str -= "(three=>3)" - ->> {i=>10*i for i in 5} -= {1=>10, 2=>20, 3=>30, 4=>40, 5=>50} ->> {i=>10*i for i in 5 if i mod 2 != 0} -= {1=>10, 3=>30, 5=>50} ->> {x=>10*x for x in y if x > 1 for y in [3, 4, 5] if y < 5} -= {2=>20, 3=>30, 4=>40} +func main() + >> t := {"one"=>1, "two"=>2; default=999} + = {"one"=>1, "two"=>2; default=999} + + >> t["one"] + = 1 + >> t["two"] + = 2 + >> t["???"] + = 999 + + t_str := "" + for k,v in t + t_str ++= "({k}=>{v})" + >> t_str + = "(one=>1)(two=>2)" + + >> #t + = 2 + >> t.default + = ?%999 + >> t.fallback + = !{Text=>Int} + + >> t.keys + = ["one", "two"] + >> t.values + = [1, 2] + + >> t2 := {"three"=>3; fallback=t} + = {"three"=>3; fallback={"one"=>1, "two"=>2; default=999}} + + >> t2["one"] + = 1 + >> t2["three"] + = 3 + >> t2["???"] + = 999 + + >> #t2 + = 1 + >> t2.default + = !Int + >> t2.fallback + = ?%{"one"=>1, "two"=>2; default=999} + + t2_str := "" + for k,v in t2 + t2_str ++= "({k}=>{v})" + >> t2_str + = "(three=>3)" + + >> {i=>10*i for i in 5} + = {1=>10, 2=>20, 3=>30, 4=>40, 5=>50} + >> {i=>10*i for i in 5 if i mod 2 != 0} + = {1=>10, 3=>30, 5=>50} + >> {x=>10*x for x in y if x > 1 for y in [3, 4, 5] if y < 5} + = {2=>20, 3=>30, 4=>40} diff --git a/test/text.tm b/test/text.tm index fee7e563..bb2cc14a 100644 --- a/test/text.tm +++ b/test/text.tm @@ -1,56 +1,57 @@ ->> str := "Hello Amélie!" ->> str:upper() -= "HELLO AMÉLIE!" ->> str:lower() -= "hello amélie!" ->> str:lower():title() -= "Hello Amélie!" +func main() + >> str := "Hello Amélie!" + >> str:upper() + = "HELLO AMÉLIE!" + >> str:lower() + = "hello amélie!" + >> str:lower():title() + = "Hello Amélie!" ->> \UE9 -= "é" + >> \UE9 + = "é" ->> \U65\U301 -= "é" + >> \U65\U301 + = "é" ->> \UE9 == \U65\U301 -= yes + >> \UE9 == \U65\U301 + = yes ->> amelie := "Am{\UE9}lie" ->> amelie:clusters() -= ["A", "m", "é", "l", "i", "e"] : [Text] ->> amelie:codepoints() -= [65_i32, 109_i32, 101_i32, 769_i32, 108_i32, 105_i32, 101_i32] : [Int32] ->> amelie:bytes() -= [65_i8, 109_i8, 101_i8, -52_i8, -127_i8, 108_i8, 105_i8, 101_i8] : [Int8] ->> #amelie -= 6 ->> amelie:num_clusters() -= 6 ->> amelie:num_codepoints() -= 7 ->> amelie:num_bytes() -= 8 + >> amelie := "Am{\UE9}lie" + >> amelie:clusters() + = ["A", "m", "é", "l", "i", "e"] : [Text] + >> amelie:codepoints() + = [65_i32, 109_i32, 101_i32, 769_i32, 108_i32, 105_i32, 101_i32] : [Int32] + >> amelie:bytes() + = [65_i8, 109_i8, 101_i8, -52_i8, -127_i8, 108_i8, 105_i8, 101_i8] : [Int8] + >> #amelie + = 6 + >> amelie:num_clusters() + = 6 + >> amelie:num_codepoints() + = 7 + >> amelie:num_bytes() + = 8 ->> amelie2 := "Am{\U65\U301}lie" ->> amelie2:clusters() -= ["A", "m", "é", "l", "i", "e"] : [Text] ->> amelie2:codepoints() -= [65_i32, 109_i32, 101_i32, 769_i32, 108_i32, 105_i32, 101_i32] : [Int32] ->> amelie2:bytes() -= [65_i8, 109_i8, 101_i8, -52_i8, -127_i8, 108_i8, 105_i8, 101_i8] : [Int8] ->> #amelie -= 6 ->> amelie2:num_clusters() -= 6 ->> amelie2:num_codepoints() -= 7 ->> amelie2:num_bytes() -= 8 + >> amelie2 := "Am{\U65\U301}lie" + >> amelie2:clusters() + = ["A", "m", "é", "l", "i", "e"] : [Text] + >> amelie2:codepoints() + = [65_i32, 109_i32, 101_i32, 769_i32, 108_i32, 105_i32, 101_i32] : [Int32] + >> amelie2:bytes() + = [65_i8, 109_i8, 101_i8, -52_i8, -127_i8, 108_i8, 105_i8, 101_i8] : [Int8] + >> #amelie + = 6 + >> amelie2:num_clusters() + = 6 + >> amelie2:num_codepoints() + = 7 + >> amelie2:num_bytes() + = 8 ->> amelie:character_names() -= ["LATIN CAPITAL LETTER A", "LATIN SMALL LETTER M", "LATIN SMALL LETTER E", "COMBINING ACUTE ACCENT", "LATIN SMALL LETTER L", "LATIN SMALL LETTER I", "LATIN SMALL LETTER E"] ->> amelie2:character_names() -= ["LATIN CAPITAL LETTER A", "LATIN SMALL LETTER M", "LATIN SMALL LETTER E", "COMBINING ACUTE ACCENT", "LATIN SMALL LETTER L", "LATIN SMALL LETTER I", "LATIN SMALL LETTER E"] + >> amelie:character_names() + = ["LATIN CAPITAL LETTER A", "LATIN SMALL LETTER M", "LATIN SMALL LETTER E", "COMBINING ACUTE ACCENT", "LATIN SMALL LETTER L", "LATIN SMALL LETTER I", "LATIN SMALL LETTER E"] + >> amelie2:character_names() + = ["LATIN CAPITAL LETTER A", "LATIN SMALL LETTER M", "LATIN SMALL LETTER E", "COMBINING ACUTE ACCENT", "LATIN SMALL LETTER L", "LATIN SMALL LETTER I", "LATIN SMALL LETTER E"] ->> "Hello":replace("e", "X") -= "HXllo" + >> "Hello":replace("e", "X") + = "HXllo" @@ -31,12 +31,13 @@ static const char *cc; static array_t get_file_dependencies(const char *filename); static int transpile(const char *filename, bool force_retranspile); static int compile_object_file(const char *filename, bool force_recompile); -static int run_program(const char *filename, const char *object_files); +static int compile_executable(const char *filename, const char *object_files); int main(int argc, char *argv[]) { mode_e mode = MODE_RUN; const char *filename = NULL; + int program_arg_index = argc + 1; for (int i = 1; i < argc; i++) { if (streq(argv[i], "-t")) { mode = MODE_TRANSPILE; @@ -52,6 +53,7 @@ int main(int argc, char *argv[]) setenv(argv[i], eq + 1, 1); } else { filename = argv[i]; + program_arg_index = i + 1; break; } } @@ -107,11 +109,23 @@ int main(int argc, char *argv[]) object_files_cord = object_files_cord ? CORD_all(object_files_cord, " ", dep, ".o") : CORD_cat(dep, ".o"); } + const char *object_files = CORD_to_const_char_star(object_files_cord); + assert(object_files); + int executable_status = compile_executable(filename, object_files); + if (executable_status != 0) + return executable_status; + if (mode == MODE_RUN) { - const char *object_files = CORD_to_const_char_star(object_files_cord); - assert(object_files); - return run_program(filename, object_files); + char *exe_name = file_base_name(filename); + int num_args = argc - program_arg_index; + char *prog_args[num_args + 2]; + prog_args[0] = exe_name; + for (int i = 0; i < num_args; i++) + prog_args[i+1] = argv[program_arg_index+i]; + prog_args[num_args+1] = NULL; + execv(exe_name, prog_args); } + return 0; } @@ -280,11 +294,10 @@ int compile_object_file(const char *filename, bool force_recompile) return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE; } -int run_program(const char *filename, const char *object_files) +int compile_executable(const char *filename, const char *object_files) { const char *bin_name = file_base_name(filename); - const char *run = streq(cc, "tcc") ? heap_strf("%s | tcc %s %s %s %s -run -", autofmt, cflags, ldflags, ldlibs, object_files) - : heap_strf("%s | %s %s %s %s %s -x c - -o %s && ./%s", autofmt, cc, cflags, ldflags, ldlibs, object_files, bin_name, bin_name); + const char *run = heap_strf("%s | %s %s %s %s %s -x c - -o %s", autofmt, cc, cflags, ldflags, ldlibs, object_files, bin_name); if (verbose) printf("%s\n", run); FILE *runner = popen(run, "w"); @@ -294,17 +307,18 @@ int run_program(const char *filename, const char *object_files) "#include <tomo/tomo.h>\n" "#include \"", filename, ".h\"\n" "\n" - "int main(int argc, const char *argv[]) {\n" + "int main(int argc, char *argv[]) {\n" "(void)argc;\n" "(void)argv;\n" "GC_INIT();\n" "srand(arc4random_uniform(UINT32_MAX));\n" "srand48(arc4random_uniform(UINT32_MAX));\n" "detect_color();\n", - module_name, "$use();\n" + module_name, "$main$run(argc, argv);\n", "return 0;\n" "}\n" ); + if (verbose) { FILE *out = popen(heap_strf("%s | bat -P --file-name=run.c", autofmt), "w"); CORD_put(program, out); |
