diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c13ec3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +nextlang +tags diff --git a/ast.c b/ast.c index b62a058..a8d411f 100644 --- a/ast.c +++ b/ast.c @@ -9,6 +9,7 @@ static const char *OP_NAMES[] = { [BINOP_UNKNOWN]="unknown", [UNOP_NOT]="not", [UNOP_NEGATIVE]="negative", + [UNOP_HEAP_ALLOCATE]="@", [UNOP_STACK_REFERENCE]="&", [BINOP_POWER]="^", [BINOP_MULT]="*", [BINOP_DIVIDE]="/", [BINOP_MOD]="mod", [BINOP_MOD1]="mod1", [BINOP_PLUS]="+", [BINOP_MINUS]="minus", [BINOP_CONCAT]="++", [BINOP_LSHIFT]="<<", [BINOP_RSHIFT]=">>", [BINOP_MIN]="min", @@ -52,8 +53,8 @@ CORD ast_list_to_cord(ast_list_t *asts) CORD arg_list_to_cord(arg_list_t *args) { CORD c = "Args("; for (; args; args = args->next) { - if (args->var && args->var->name) - c = CORD_cat(c, args->var->name); + if (args->var.name) + c = CORD_cat(c, args->var.name); if (args->type) CORD_sprintf(&c, "%r:%s", c, type_ast_to_cord(args->type)); if (args->default_val) @@ -86,8 +87,8 @@ CORD ast_to_cord(ast_t *ast) T(Nil, "(%r)", type_ast_to_cord(data.type)) T(Bool, "(\x1b[35m%s\x1b[m)", data.b ? "yes" : "no") T(Var, "(\x1b[36;1m%s\x1b[m)", data.var.name) - T(Int, "(\x1b[35m%ld\x1b[m, precision=%ld)", data.i, data.precision) - T(Num, "(\x1b[35m%ld\x1b[m, precision=%ld)", data.n, data.precision) + T(Int, "(\x1b[35m%ld\x1b[m, precision=\x1b[35m%ld\x1b[m)", data.i, data.precision) + T(Num, "(\x1b[35m%ld\x1b[m, precision=\x1b[35m%ld\x1b[m)", data.n, data.precision) T(Char, "(\x1b[35m'%c'\x1b[m)", data.c) T(StringLiteral, "\x1b[35m\"%s\"\x1b[m", data.str) T(StringJoin, "(%r)", ast_list_to_cord(data.children)) diff --git a/ast.h b/ast.h index 0d90d4b..e9c3598 100644 --- a/ast.h +++ b/ast.h @@ -30,7 +30,7 @@ typedef struct ast_list_s { } ast_list_t; typedef struct arg_list_s { - var_t *var; + var_t var; type_ast_t *type; ast_t *default_val; struct arg_list_s *next; diff --git a/compile.c b/compile.c index e4ae0a4..b686f8f 100644 --- a/compile.c +++ b/compile.c @@ -5,16 +5,28 @@ #include #include "ast.h" +#include "compile.h" #include "util.h" -static CORD compile_type(type_ast_t *t) +CORD compile_type(type_ast_t *t) { switch (t->tag) { - case TypeVar: return Match(t, TypeVar)->var.name; + case TypeVar: return CORD_cat(Match(t, TypeVar)->var.name, "_t"); default: errx(1, "Not implemented"); } } +static inline CORD compile_statement(ast_t *ast) +{ + CORD code = compile(ast); + switch (ast->tag) { + case If: case For: case While: case FunctionDef: + return code; + default: + return CORD_cat(code, ";"); + } +} + CORD compile(ast_t *ast) { switch (ast->tag) { @@ -86,86 +98,96 @@ CORD compile(ast_t *ast) } case StringLiteral: { const char *str = Match(ast, StringLiteral)->str; - CORD c = "\""; + CORD code = "\""; for (; *str; ++str) { switch (*str) { - case '\\': c = CORD_cat(c, "\\\\"); break; - case '"': c = CORD_cat(c, "\\\""); break; - case '\a': c = CORD_cat(c, "\\a"); break; - case '\b': c = CORD_cat(c, "\\b"); break; - case '\n': c = CORD_cat(c, "\\n"); break; - case '\r': c = CORD_cat(c, "\\r"); break; - case '\t': c = CORD_cat(c, "\\t"); break; - case '\v': c = CORD_cat(c, "\\v"); break; + case '\\': code = CORD_cat(code, "\\\\"); break; + case '"': code = CORD_cat(code, "\\\""); break; + case '\a': code = CORD_cat(code, "\\a"); break; + case '\b': code = CORD_cat(code, "\\b"); break; + case '\n': code = CORD_cat(code, "\\n"); break; + case '\r': code = CORD_cat(code, "\\r"); break; + case '\t': code = CORD_cat(code, "\\t"); break; + case '\v': code = CORD_cat(code, "\\v"); break; default: { if (isprint(*str)) - c = CORD_cat_char(c, *str); + code = CORD_cat_char(code, *str); else - CORD_sprintf(&c, "%r\\x%02X", *str); + CORD_sprintf(&code, "%r\\x%02X", *str); break; } } } - return CORD_cat_char(c, '"'); + return CORD_cat_char(code, '"'); } case StringJoin: { - CORD c = NULL; + CORD code = NULL; for (ast_list_t *chunk = Match(ast, StringJoin)->children; chunk; chunk = chunk->next) { - if (c) CORD_sprintf(&c, "CORD_cat(%r, %r)", c, compile(chunk->ast)); - else c = compile(chunk->ast); + if (code) CORD_sprintf(&code, "CORD_cat(%r, %r)", code, compile(chunk->ast)); + else code = compile(chunk->ast); } - return c; + return code; } case Interp: { return CORD_asprintf("__cord(%r)", compile(Match(ast, Interp)->value)); } case Block: { - CORD c = NULL; - for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { - c = CORD_cat(c, compile(stmt->ast)); - c = CORD_cat(c, ";\n"); + ast_list_t *stmts = Match(ast, Block)->statements; + if (stmts && !stmts->next) + return compile_statement(stmts->ast); + + CORD code = "{\n"; + for (ast_list_t *stmt = stmts; stmt; stmt = stmt->next) { + code = CORD_cat(code, compile_statement(stmt->ast)); + code = CORD_cat(code, "\n"); } - return c; + return CORD_cat(code, "}"); } case Declare: { auto decl = Match(ast, Declare); - return CORD_asprintf("auto %r = %r", decl->var, decl->value); + return CORD_asprintf("__declare(%r, %r)", compile(decl->var), compile(decl->value)); } case Assign: { auto assign = Match(ast, Assign); - CORD c = NULL; + CORD code = NULL; for (ast_list_t *target = assign->targets, *value = assign->values; target && value; target = target->next, value = value->next) { - CORD_sprintf(&c, "%r = %r", compile(target->ast), compile(value->ast)); - if (target->next) c = CORD_cat(c, ", "); + CORD_sprintf(&code, "%r = %r", compile(target->ast), compile(value->ast)); + if (target->next) code = CORD_cat(code, ", "); } - return c; + return code; } // Min, Max, // Array, Table, TableEntry, case FunctionDef: { auto fndef = Match(ast, FunctionDef); - CORD c = CORD_asprintf("%r %r(", fndef->ret_type ? compile_type(fndef->ret_type) : "void", compile(fndef->name)); + CORD code = CORD_asprintf("%r %r(", fndef->ret_type ? compile_type(fndef->ret_type) : "void", compile(fndef->name)); for (arg_list_t *arg = fndef->args; arg; arg = arg->next) { - CORD_sprintf(&c, "%r%r %s", c, compile_type(arg->type), arg->var->name); - if (arg->next) c = CORD_cat(c, ", "); + CORD_sprintf(&code, "%r%r %s", code, compile_type(arg->type), arg->var.name); + if (arg->next) code = CORD_cat(code, ", "); } - c = CORD_cat(c, ") {\n"); - c = CORD_cat(c, compile(fndef->body)); - c = CORD_cat(c, "}"); - return c; + code = CORD_cat(code, ") "); + code = CORD_cat(code, compile(fndef->body)); + return code; } case FunctionCall: { auto call = Match(ast, FunctionCall); - CORD c = CORD_cat_char(compile(call->fn), '('); + CORD code = CORD_cat_char(compile(call->fn), '('); for (ast_list_t *arg = call->args; arg; arg = arg->next) { - c = CORD_cat(c, compile(arg->ast)); - if (arg->next) c = CORD_cat(c, ", "); + code = CORD_cat(code, compile(arg->ast)); + if (arg->next) code = CORD_cat(code, ", "); } - return CORD_cat_char(c, ')'); + return CORD_cat_char(code, ')'); } // Lambda, - // FunctionCall, KeywordArg, - // Block, + // KeywordArg, + case If: { + auto if_ = Match(ast, If); + CORD code; + CORD_sprintf(&code, "if (%r) %r", compile(if_->condition), compile(if_->body)); + if (if_->else_body) + CORD_sprintf(&code, "%r\nelse %r", code, compile(if_->else_body)); + return code; + } // For, While, If, // Reduction, // Skip, Stop, Pass, diff --git a/compile.h b/compile.h index 790b33a..2b56a1a 100644 --- a/compile.h +++ b/compile.h @@ -6,6 +6,7 @@ #include "util.h" +CORD compile_type(type_ast_t *t); CORD compile(ast_t *ast); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/foo.c b/foo.c index 0d78c72..80b88cf 100644 --- a/foo.c +++ b/foo.c @@ -1,12 +1,18 @@ -#include +#include "nextlang.h" + +static void foo(Int64 x); + + +void foo(Int64 x) +{ + say("Hello world!"); +} + +int main(int argc, const char *argv[]) +{ + (void) argc; + (void) argv; + foo(((Int64_t) 5)); -int main(void) { - int x = 23; - const char *s = "Hi"; -#define say(x) _Generic(x, int: printf("%d\n", x), char *: puts(s), default: puts("???")) - say(x); - say(s); -#define all(...) { __VA_ARGS__; } - all(say("one"); say(2)) return 0; } diff --git a/nextlang.c b/nextlang.c index 617adc9..333c451 100644 --- a/nextlang.c +++ b/nextlang.c @@ -11,12 +11,83 @@ int main(int argc, char *argv[]) { if (argc < 2) return 1; + const char *autofmt = getenv("AUTOFMT"); + if (!autofmt) autofmt = "indent -kr -nut | bat --file-name=out.c"; + + setenv("SSSPATH", ".", 0); + sss_file_t *f = sss_load_file(argv[1]); + ast_t *ast = parse_file(f, NULL); - const char *s = ast_to_str(ast); - puts(s); - CORD c = compile(ast); - CORD_put(c, stdout); + + if (!ast) + errx(1, "Could not compile!"); + + if (getenv("VERBOSE")) { + FILE *out = popen("bat --file-name=AST", "w"); + fputs(ast_to_str(ast), out); + fclose(out); + } + + // Predeclare funcs: + CORD code = "#include \"nextlang.h\"\n\n"; + for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { + switch (stmt->ast->tag) { + case FunctionDef: { + auto fndef = Match(stmt->ast, FunctionDef); + CORD_sprintf(&code, "%rstatic %r %r(", code, fndef->ret_type ? compile_type(fndef->ret_type) : "void", compile(fndef->name)); + for (arg_list_t *arg = fndef->args; arg; arg = arg->next) { + CORD_sprintf(&code, "%r%r %s", code, compile_type(arg->type), arg->var.name); + if (arg->next) code = CORD_cat(code, ", "); + } + code = CORD_cat(code, ");\n"); + break; + } + default: break; + } + } + + // Declare funcs: + for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { + switch (stmt->ast->tag) { + case FunctionDef: { + CORD_sprintf(&code, "%r\n\n%r", code, compile(stmt->ast)); + break; + } + default: break; + } + } + + // Main body: + code = CORD_cat(code, "\n\nint main(int argc, const char *argv[]) {\n" + "(void)argc;\n" + "(void)argv;\n" + "GC_INIT();\n\n"); + for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { + switch (stmt->ast->tag) { + case FunctionDef: break; + default: { + code = CORD_cat(code, compile(stmt->ast)); + code = CORD_cat(code, ";\n"); + break; + } + } + } + code = CORD_cat(code, "\nreturn 0;\n}\n"); + + if (getenv("VERBOSE")) { + FILE *out = popen(autofmt, "w"); + CORD_put(code, out); + fclose(out); + } + + const char *flags = getenv("CFLAGS"); + if (!flags) flags = "-std=c11 -lm -lgc -lcord"; + const char *run = heap_strf(getenv("VERBOSE") ? "tcc %s -run - | bat --file-name=output.txt" : "tcc %s -run -", flags); + FILE *cc = popen(run, "w"); + CORD_put(code, cc); + fclose(cc); + return 0; } diff --git a/nextlang.h b/nextlang.h new file mode 100644 index 0000000..2dd6570 --- /dev/null +++ b/nextlang.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#define Int64_t int64_t +#define Int32_t int32_t +#define Int16_t int16_t +#define Int8_t int8_t + +#define Num64_t double +#define Num32_t float + +#define String_t CORD + +#define Char_t char + +#define Bool_t bool + +#define Void_t void + +#ifndef auto +#define auto __auto_type +#endif + +#define CORD_asprintf(...) ({ CORD __c; CORD_sprintf(&__c, __VA_ARGS__); __c; }) +#define __declare(var, val) __typeof(val) var = val +#define __cord(x) _Generic(x, bool: x ? "yes" : "no", \ + int16_t: CORD_asprintf("%d", x), int32_t: CORD_asprintf("%d", x), int64_t: CORD_asprintf("%ld", x), \ + double: CORD_asprintf("%g", x), float: CORD_asprintf("%g", x), \ + CORD: x, \ + default: "???") +#define __heap(x) (__typeof(x)*)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x)) +#define __stack(x) (&(__typeof(x)){x}) + +#define say(str) puts(CORD_to_const_char_star(str)) diff --git a/parse.c b/parse.c index 845b3ca..1b40514 100644 --- a/parse.c +++ b/parse.c @@ -1529,12 +1529,12 @@ arg_list_t *parse_args(parse_ctx_t *ctx, const char **pos, bool allow_unnamed) ast_t *default_val = NULL; type_ast_t *type = NULL; - typedef struct var_list_s { - var_t *var; - struct var_list_s *next; - } var_list_t; + typedef struct name_list_s { + const char *name; + struct name_list_s *next; + } name_list_t; - var_list_t *vars = NULL; + name_list_t *names = NULL; for (;;) { whitespace(pos); const char *name_start = *pos; @@ -1543,34 +1543,34 @@ arg_list_t *parse_args(parse_ctx_t *ctx, const char **pos, bool allow_unnamed) whitespace(pos); if (strncmp(*pos, "==", 2) != 0 && match(pos, "=")) { default_val = expect(ctx, *pos-1, pos, parse_term, "I expected a value after this '='"); - vars = new(var_list_t, .var=new(var_t, .name=name), .next=vars); + names = new(name_list_t, .name=name, .next=names); break; } else if (match(pos, ":")) { type = expect(ctx, *pos-1, pos, parse_type, "I expected a type here"); - vars = new(var_list_t, .var=new(var_t, .name=name), .next=vars); + names = new(name_list_t, .name=name, .next=names); break; } else if (allow_unnamed) { *pos = name_start; type = optional(ctx, pos, parse_type); if (type) - vars = new(var_list_t, .var=NULL, .next=vars); + names = new(name_list_t, .name=NULL, .next=names); break; } else if (name) { - vars = new(var_list_t, .var=new(var_t, .name=name), .next=vars); + names = new(name_list_t, .name=name, .next=names); spaces(pos); if (!match(pos, ",")) break; } else { break; } } - if (!vars) break; + if (!names) break; if (!default_val && !type) parser_err(ctx, batch_start, *pos, "I expected a ':' and type, or '=' and a default value after this parameter (%s)", - vars->var->name); + names->name); - REVERSE_LIST(vars); - for (; vars; vars = vars->next) - args = new(arg_list_t, .var=vars->var, .type=type, .default_val=default_val); + REVERSE_LIST(names); + for (; names; names = names->next) + args = new(arg_list_t, .var.name=names->name, .type=type, .default_val=default_val); whitespace(pos); match(pos, ","); }