diff options
Diffstat (limited to 'src/compiler.c')
| -rw-r--r-- | src/compiler.c | 150 |
1 files changed, 144 insertions, 6 deletions
diff --git a/src/compiler.c b/src/compiler.c index b8f5823..b222c2e 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -2,6 +2,8 @@ #include <string.h> #include <unistd.h> #include <ctype.h> +#include <stdlib.h> +#include <regex.h> #include <errno.h> #include <ct/compiler.h> @@ -10,6 +12,34 @@ #include <ct/path.h> #include <ct/res.h> +const char *import_regex = +"^[[:space:]]*(pub[[:space:]]+)?" +"import[[:space:]]+" +"([[:alnum:]/.]+)" +"[[:space:]]*;" +"[[:space:]]*$"; + +const char *define_regex = +"^[[:space:]]*(pub[[:space:]]+)?" +"define[[:space:]]+" +"([[:alnum:]]+)[[:space:]]*" +"\\((.*)\\)" +"[[:space:]]*" +"\\{(.*)\\}" +"[[:space:]]*$"; + +regex_t import_re; +regex_t define_re; + +/* this could maybe be moved to a utility file or something */ +static char *get_regerror(int errcode, regex_t *compiled) +{ + size_t len = regerror(errcode, compiled, NULL, 0); + char *buf = malloc(len); + regerror(errcode, compiled, buf, len); + return buf; +} + static int read_element(FILE *f, struct string *element) { if (feof(f)) @@ -85,7 +115,69 @@ static struct string *read_block(FILE *f, size_t *lines) return block; } -static int process(struct res *r, const char *file) +static bool detect_pub(struct string *block, regmatch_t rm) +{ + const char *start = block->buf + rm.rm_so; + const size_t len = rm.rm_eo - rm.rm_so; + const size_t min = len < 3 ? len : 3; + return strncmp(start, "pub", min); +} + +static char *extract_match(struct string *block, regmatch_t rm) +{ + const char *start = block->buf + rm.rm_so; + const size_t len = rm.rm_eo - rm.rm_so; + char *match = strndup(start, len); + if (!match) + error("couldn't extract match: %s\n", strerror(errno)); + + return match; +} + +static bool detect_import(struct string *block, bool *pub, char **file) +{ + int ret = 0; + const size_t captures = 3; + regmatch_t rm[captures]; + ret = regexec(&import_re, block->buf, captures, rm, 0); + + switch (ret) { + case REG_ESPACE: error("import regex ran out of memory: %s\n", + strerror(errno)); + /* fallthrough */ + case REG_NOMATCH: return false; + } + + *pub = detect_pub(block, rm[1]); + *file = extract_match(block, rm[2]); + return true; +} + +static bool detect_define(struct string *block, bool *pub, + char **name, char **args, char **content) +{ + int ret = 0; + const size_t captures = 5; + regmatch_t rm[captures]; + ret = regexec(&define_re, block->buf, captures, rm, 0); + + switch (ret) { + case REG_ESPACE: error("define regex ran out of memory: %s\n", + strerror(errno)); + /* fallthrough */ + case REG_NOMATCH: return false; + } + + *pub = detect_pub(block, rm[1]); + *name = extract_match(block, rm[2]); + *args = extract_match(block, rm[3]); + *content = extract_match(block, rm[4]); + return true; +} + +static void process_file(const char *file); + +static int process(const char *file) { FILE *f = fopen(file, "r"); if (!f) { @@ -100,6 +192,28 @@ static int process(struct res *r, const char *file) lines - prev_lines, block->buf); prev_lines = lines + 1; + bool pub = false; + char *file = NULL; + if (detect_import(block, &pub, &file)) { + debug("detected %s import block for file (%s)\n", + pub ? "public" : "private", + file); + process_file(file); + free(file); + goto next; + } + + char *name = NULL, *args = NULL, *content = NULL; + if (detect_define(block, &pub, &name, &args, &content)) { + debug("detected %s define block %s (%s) {%s}\n", + pub ? "public" : "private", + name, args, content); + free(name); + free(args); + free(content); + goto next; + } + /* with each block, * A) Detect if it is an import block and what kind, * in which case process the file that it refers to. @@ -132,6 +246,7 @@ static int process(struct res *r, const char *file) * processing upwards. And probably detecting a main block as * well? */ +next: destroy_string(block); } @@ -139,9 +254,9 @@ static int process(struct res *r, const char *file) return 0; } -void compile(const char *file) { +void process_file(const char *file) +{ struct res *r = res_create(); - res_add(r, (void *)(file = strdup(file))); const char *base = ct_basename(file); res_add(r, (void *)base); @@ -160,12 +275,12 @@ void compile(const char *file) { debug("(cwd:%s)(dir:%s)(base:%s)\n", cwd, dir, base); - if (chdir(dir)) { + if (*dir != 0 && chdir(dir)) { error("couldn't change to directory %s: %s\n", dir, strerror(errno)); goto out; } - if (process(r, base)) + if (process(base)) goto out; if (chdir(cwd)) { @@ -173,7 +288,30 @@ void compile(const char *file) { goto out; } - out: res_destroy(r); } + +void compile(const char *file) { + int err = 0; + if ((err = regcomp(&import_re, import_regex, REG_EXTENDED)) != 0) { + char *err_str = get_regerror(err, &import_re); + error("failed compiling import regex: %s\n", err_str); + free(err_str); + goto out; + } + + if ((err = regcomp(&define_re, define_regex, REG_EXTENDED)) != 0) { + char *err_str = get_regerror(err, &define_re); + error("failed compiling define regex: %s\n", err_str); + free(err_str); + goto define_out; + } + + process_file(file); + + regfree(&define_re); +define_out: + regfree(&import_re); +out: +} |
