2024-02-04 12:23:59 -08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <gc.h>
|
|
|
|
#include <gc/cord.h>
|
2024-02-07 21:52:18 -08:00
|
|
|
#include <printf.h>
|
2024-02-04 12:23:59 -08:00
|
|
|
|
|
|
|
#include "ast.h"
|
2024-03-03 15:15:45 -08:00
|
|
|
#include "builtins/text.h"
|
2024-02-04 12:23:59 -08:00
|
|
|
#include "compile.h"
|
2024-02-17 20:23:37 -08:00
|
|
|
#include "parse.h"
|
2024-02-17 17:07:04 -08:00
|
|
|
#include "typecheck.h"
|
2024-02-07 21:52:18 -08:00
|
|
|
#include "types.h"
|
2024-02-04 12:23:59 -08:00
|
|
|
|
2024-03-06 21:30:52 -08:00
|
|
|
typedef enum { MODE_RUN, MODE_COMPILE, MODE_TRANSPILE, MODE_EXPANDED_TRANSPILE } mode_e;
|
2024-03-03 11:36:09 -08:00
|
|
|
|
2024-02-04 12:23:59 -08:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2024-03-03 11:36:09 -08:00
|
|
|
mode_e mode = MODE_RUN;
|
|
|
|
const char *filename = NULL;
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
if (streq(argv[i], "-t")) {
|
|
|
|
mode = MODE_TRANSPILE;
|
2024-03-06 21:30:52 -08:00
|
|
|
} else if (streq(argv[i], "-c")) {
|
|
|
|
mode = MODE_COMPILE;
|
2024-03-03 11:36:09 -08:00
|
|
|
} else if (streq(argv[i], "-E")) {
|
|
|
|
mode = MODE_EXPANDED_TRANSPILE;
|
|
|
|
} else {
|
|
|
|
filename = argv[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filename == NULL)
|
|
|
|
errx(1, "No file provided");
|
2024-02-04 12:23:59 -08:00
|
|
|
|
2024-02-07 21:52:18 -08:00
|
|
|
// register_printf_modifier(L"p");
|
|
|
|
if (register_printf_specifier('T', printf_type, printf_pointer_size))
|
|
|
|
errx(1, "Couldn't set printf specifier");
|
|
|
|
if (register_printf_specifier('W', printf_ast, printf_pointer_size))
|
|
|
|
errx(1, "Couldn't set printf specifier");
|
|
|
|
|
2024-02-04 15:04:41 -08:00
|
|
|
const char *autofmt = getenv("AUTOFMT");
|
2024-02-13 20:03:58 -08:00
|
|
|
if (!autofmt) autofmt = "indent -kr -l100 -nbbo -nut -sob";
|
2024-03-09 21:42:17 -08:00
|
|
|
if (!autofmt[0]) autofmt = "cat";
|
2024-02-04 15:04:41 -08:00
|
|
|
|
2024-03-03 11:36:09 -08:00
|
|
|
file_t *f = load_file(filename);
|
|
|
|
if (!f)
|
|
|
|
errx(1, "No such file: %s", filename);
|
2024-02-04 15:04:41 -08:00
|
|
|
|
2024-02-04 12:23:59 -08:00
|
|
|
ast_t *ast = parse_file(f, NULL);
|
2024-02-04 15:04:41 -08:00
|
|
|
|
|
|
|
if (!ast)
|
|
|
|
errx(1, "Could not compile!");
|
|
|
|
|
2024-02-11 11:02:00 -08:00
|
|
|
bool verbose = (getenv("VERBOSE") && strcmp(getenv("VERBOSE"), "1") == 0);
|
|
|
|
if (verbose) {
|
2024-03-03 11:36:09 -08:00
|
|
|
FILE *out = popen(heap_strf("bat -P --file-name='%s'", filename), "w");
|
2024-02-10 12:36:35 -08:00
|
|
|
fputs(f->text, out);
|
2024-03-03 11:36:09 -08:00
|
|
|
pclose(out);
|
2024-02-10 12:36:35 -08:00
|
|
|
}
|
|
|
|
|
2024-02-11 11:02:00 -08:00
|
|
|
if (verbose) {
|
2024-02-11 23:10:45 -08:00
|
|
|
FILE *out = popen("bat -P --file-name=AST", "w");
|
2024-02-04 15:04:41 -08:00
|
|
|
fputs(ast_to_str(ast), out);
|
2024-03-03 11:36:09 -08:00
|
|
|
pclose(out);
|
2024-02-04 15:04:41 -08:00
|
|
|
}
|
|
|
|
|
2024-02-17 23:22:31 -08:00
|
|
|
module_code_t module = compile_file(ast);
|
2024-02-04 15:04:41 -08:00
|
|
|
|
2024-03-09 15:22:12 -08:00
|
|
|
if (verbose && mode != MODE_RUN) {
|
2024-03-03 11:45:36 -08:00
|
|
|
FILE *out = popen(heap_strf("%s | bat -P --file-name=%s.h", autofmt, f->filename), "w");
|
|
|
|
CORD_put(module.header, out);
|
|
|
|
pclose(out);
|
|
|
|
out = popen(heap_strf("%s | bat -P --file-name=%s.c", autofmt, f->filename), "w");
|
|
|
|
CORD_put(CORD_all("#include \"", f->filename, "\"\n\n", module.c_file), out);
|
2024-03-03 11:36:09 -08:00
|
|
|
pclose(out);
|
2024-02-04 15:04:41 -08:00
|
|
|
}
|
|
|
|
|
2024-03-03 13:08:38 -08:00
|
|
|
const char *cconfig = getenv("CCONFIG");
|
|
|
|
if (!cconfig)
|
|
|
|
cconfig = "-std=c11 -fdollars-in-identifiers -fsanitize=signed-integer-overflow -fno-sanitize-recover -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE";
|
|
|
|
|
2024-02-11 19:12:21 -08:00
|
|
|
const char *cflags = getenv("CFLAGS");
|
|
|
|
if (!cflags)
|
2024-03-03 13:08:38 -08:00
|
|
|
cflags = heap_strf("%s -I. -D_DEFAULT_SOURCE", cconfig);
|
2024-02-11 19:12:21 -08:00
|
|
|
|
2024-02-24 13:06:49 -08:00
|
|
|
const char *ldlibs = "-lgc -lcord -lm -L. -ltomo";
|
2024-02-11 19:12:21 -08:00
|
|
|
if (getenv("LDLIBS"))
|
|
|
|
ldlibs = heap_strf("%s %s", ldlibs, getenv("LDLIBS"));
|
|
|
|
|
2024-03-09 21:05:32 -08:00
|
|
|
const char *ldflags = "-Wl,-rpath '-Wl,$ORIGIN' -L/usr/local/lib";
|
2024-02-13 22:24:04 -08:00
|
|
|
|
2024-02-24 12:31:26 -08:00
|
|
|
const char *cc = getenv("CC");
|
|
|
|
if (!cc) cc = "tcc";
|
2024-03-03 11:36:09 -08:00
|
|
|
|
|
|
|
switch (mode) {
|
2024-03-06 21:30:52 -08:00
|
|
|
case MODE_COMPILE: {
|
2024-03-17 18:42:38 -07:00
|
|
|
FILE *prog = popen(heap_strf("%s > %s.h", autofmt, f->filename), "w");
|
|
|
|
CORD_put("#pragma once\n", prog);
|
|
|
|
CORD_put(module.header, prog);
|
|
|
|
int status = pclose(prog);
|
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
|
|
|
printf("Transpiled to %s.h\n", f->filename);
|
|
|
|
else
|
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
|
|
|
|
|
|
|
prog = popen(heap_strf("%s > %s.c", autofmt, f->filename), "w");
|
|
|
|
CORD_put(CORD_all("#include \"", module.module_name, ".tm.h\"\n\n", module.c_file), prog);
|
|
|
|
status = pclose(prog);
|
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
|
|
|
printf("Transpiled to %s.c\n", f->filename);
|
|
|
|
else
|
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
|
|
|
|
|
|
|
const char *cmd = heap_strf("%s %s -c %s.c -o %s.o", cc, cflags, f->filename, f->filename);
|
|
|
|
if (verbose)
|
|
|
|
printf("Running: %s\n", cmd);
|
|
|
|
prog = popen(cmd, "w");
|
|
|
|
status = pclose(prog);
|
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
|
|
|
printf("Compiled to %s.o\n", f->filename);
|
2024-03-06 21:30:52 -08:00
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
|
|
|
}
|
2024-03-03 11:36:09 -08:00
|
|
|
case MODE_RUN: {
|
2024-03-09 21:42:17 -08:00
|
|
|
const char *run = streq(cc, "tcc") ? heap_strf("%s | tcc -run %s %s %s -", autofmt, cflags, ldflags, ldlibs)
|
|
|
|
: heap_strf("%s | gcc -x c %s %s %s - -o program && ./program", autofmt, cflags, ldflags, ldlibs);
|
2024-03-03 11:36:09 -08:00
|
|
|
FILE *runner = popen(run, "w");
|
2024-03-03 11:45:36 -08:00
|
|
|
|
|
|
|
CORD program = CORD_all(
|
|
|
|
"// File: ", f->filename, ".h\n",
|
|
|
|
module.header,
|
|
|
|
"\n",
|
|
|
|
"// File: ", f->filename, ".c\n",
|
|
|
|
module.c_file,
|
|
|
|
"\n",
|
|
|
|
"int main(int argc, const char *argv[]) {\n"
|
|
|
|
"(void)argc;\n"
|
|
|
|
"(void)argv;\n"
|
|
|
|
"GC_INIT();\n"
|
2024-03-17 18:47:24 -07:00
|
|
|
"detect_color();\n",
|
|
|
|
module.module_name, "$use();\n"
|
2024-03-03 11:45:36 -08:00
|
|
|
"return 0;\n"
|
|
|
|
"}\n"
|
|
|
|
);
|
2024-03-09 15:22:12 -08:00
|
|
|
if (verbose) {
|
|
|
|
FILE *out = popen(heap_strf("%s | bat -P --file-name=%s.c", autofmt, f->filename), "w");
|
|
|
|
CORD_put(program, out);
|
|
|
|
pclose(out);
|
|
|
|
}
|
2024-03-03 11:45:36 -08:00
|
|
|
|
2024-03-03 11:36:09 -08:00
|
|
|
CORD_put(program, runner);
|
|
|
|
int status = pclose(runner);
|
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
case MODE_TRANSPILE: {
|
2024-03-03 11:45:36 -08:00
|
|
|
FILE *prog = popen(heap_strf("%s > %s.h", autofmt, f->filename), "w");
|
2024-03-03 12:22:22 -08:00
|
|
|
CORD_put("#pragma once\n", prog);
|
2024-03-03 11:45:36 -08:00
|
|
|
CORD_put(module.header, prog);
|
2024-03-03 11:36:09 -08:00
|
|
|
int status = pclose(prog);
|
2024-03-03 11:45:36 -08:00
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
|
|
|
printf("Transpiled to %s.h\n", f->filename);
|
|
|
|
else
|
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
|
|
|
|
|
|
|
prog = popen(heap_strf("%s > %s.c", autofmt, f->filename), "w");
|
2024-03-03 13:08:38 -08:00
|
|
|
CORD_put(CORD_all("#include \"", module.module_name, ".tm.h\"\n\n", module.c_file), prog);
|
2024-03-03 11:45:36 -08:00
|
|
|
status = pclose(prog);
|
2024-03-03 11:36:09 -08:00
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
|
|
|
printf("Transpiled to %s.c\n", f->filename);
|
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
case MODE_EXPANDED_TRANSPILE: {
|
2024-03-03 11:45:36 -08:00
|
|
|
FILE *prog = popen(heap_strf("%s -x c %s -E - | %s > %s.h", cc, cflags, autofmt, f->filename), "w");
|
2024-03-03 12:22:22 -08:00
|
|
|
CORD_put("#pragma once\n", prog);
|
2024-03-03 11:45:36 -08:00
|
|
|
CORD_put(module.header, prog);
|
2024-03-03 11:36:09 -08:00
|
|
|
int status = pclose(prog);
|
2024-03-03 11:45:36 -08:00
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
|
|
|
printf("Transpiled to %s.h\n", f->filename);
|
|
|
|
else
|
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
|
|
|
|
|
|
|
prog = popen(heap_strf("%s -x c %s -E - | %s > %s.c", cc, cflags, autofmt, f->filename), "w");
|
2024-03-03 13:08:38 -08:00
|
|
|
CORD_put(CORD_all("#include \"", module.module_name, ".tm.h\"\n\n", module.c_file), prog);
|
2024-03-03 11:45:36 -08:00
|
|
|
status = pclose(prog);
|
2024-03-03 11:36:09 -08:00
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
|
|
|
printf("Transpiled to %s.c\n", f->filename);
|
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2024-02-04 12:23:59 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|