aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--ast.c9
-rw-r--r--ast.h2
-rw-r--r--compile.c104
-rw-r--r--compile.h1
-rw-r--r--foo.c26
-rw-r--r--nextlang.c79
-rw-r--r--nextlang.h40
-rw-r--r--parse.c28
9 files changed, 218 insertions, 74 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..0c13ec34
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.o
+nextlang
+tags
diff --git a/ast.c b/ast.c
index b62a058c..a8d411fb 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 0d90d4b5..e9c35986 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 e4ae0a48..b686f8f9 100644
--- a/compile.c
+++ b/compile.c
@@ -5,16 +5,28 @@
#include <stdio.h>
#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 790b33a4..2b56a1a8 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 0d78c720..80b88cfb 100644
--- a/foo.c
+++ b/foo.c
@@ -1,12 +1,18 @@
-#include <stdio.h>
-
-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))
+#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));
+
return 0;
}
diff --git a/nextlang.c b/nextlang.c
index 617adc98..333c4515 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 00000000..2dd65704
--- /dev/null
+++ b/nextlang.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <gc.h>
+#include <gc/cord.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 845b3ca0..1b405142 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, ",");
}