aboutsummaryrefslogtreecommitdiff
path: root/nextlang.c
blob: 333c45155d3574292fafb5e0dc18bac8f0d27f6d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <stdio.h>
#include <stdlib.h>
#include <gc.h>
#include <gc/cord.h>

#include "ast.h"
#include "parse.h"
#include "compile.h"

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);

    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;
}

// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0