diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-02-15 13:43:46 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-02-15 13:43:46 -0500 |
| commit | 317b8f53193e5ec14c92e229c89bc84ca32b7810 (patch) | |
| tree | 481ea31ebfedf6915bb59a24fd6c9cb0506abd20 | |
| parent | 0577469f9c49473fe95eedfa27b0f282ac9ffdb6 (diff) | |
Progress towards environments
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | compile.c | 20 | ||||
| -rw-r--r-- | environment.c | 62 | ||||
| -rw-r--r-- | environment.h | 26 | ||||
| -rw-r--r-- | nextlang.c | 14 | ||||
| -rw-r--r-- | parse.c | 64 | ||||
| -rw-r--r-- | types.h | 4 | ||||
| -rw-r--r-- | util.h | 1 |
8 files changed, 150 insertions, 45 deletions
@@ -24,12 +24,12 @@ G=-ggdb O=-Og CFLAGS=$(CCONFIG) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) LDLIBS=-lgc -lgccjit -lcord -lm -lunistring -BUILTIN_OBJS=builtins/array.o builtins/bool.o builtins/builtins.o builtins/char.o builtins/floats.o builtins/functions.o builtins/integers.o \ +BUILTIN_OBJS=builtins/array.o builtins/bool.o builtins/builtins.o builtins/floats.o builtins/functions.o builtins/integers.o \ builtins/memory.o builtins/string.o builtins/table.o builtins/types.o all: nextlang libnext.so -nextlang: nextlang.c parse.o files.o util.o ast.o compile.o types.o SipHash/halfsiphash.o $(BUILTIN_OBJS) +nextlang: nextlang.c parse.o files.o util.o ast.o compile.o types.o environment.o SipHash/halfsiphash.o $(BUILTIN_OBJS) libnext.so: metamethods/cord.o util.o SipHash/halfsiphash.o $(CC) $^ $(CFLAGS) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) $(LDLIBS) -Wl,-soname,libnext.so -shared -o $@ @@ -303,13 +303,13 @@ CORD compile(env_t *env, ast_t *ast) CORD_appendf(&env->typedefs, "typedef struct %s_s %s_t;\n", def->name, def->name); CORD_appendf(&env->typedefs, "#define %s(...) ((%s_t){__VA_ARGS__})\n", def->name, def->name); - CORD_appendf(&env->types, "struct %s_s {\n", def->name); + CORD_appendf(&env->typecode, "struct %s_s {\n", def->name); for (arg_ast_t *field = def->fields; field; field = field->next) { CORD type = compile_type(env, field->type); - CORD_appendf(&env->types, "%r %s%s;\n", type, field->name, + CORD_appendf(&env->typecode, "%r %s%s;\n", type, field->name, CORD_cmp(type, "Bool_t") ? "" : ":1"); } - CORD_appendf(&env->types, "};\n"); + CORD_appendf(&env->typecode, "};\n"); CORD cord_func = CORD_asprintf("CORD %s$cord(%s_t *obj, bool use_color) {\n" "\tif (!obj) return \"%s\";\n", def->name, def->name, def->name); @@ -341,21 +341,21 @@ CORD compile(env_t *env, ast_t *ast) case EnumDef: { auto def = Match(ast, EnumDef); CORD_appendf(&env->typedefs, "typedef struct %s_s %s_t;\n", def->name, def->name); - CORD_appendf(&env->types, "struct %s_s {\nenum {", def->name); + CORD_appendf(&env->typecode, "struct %s_s {\nenum {", def->name); for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { - CORD_appendf(&env->types, "%s$%s = %ld, ", def->name, tag->name, tag->value); + CORD_appendf(&env->typecode, "%s$%s = %ld, ", def->name, tag->name, tag->value); } - env->types = CORD_cat(env->types, "} tag;\nunion {\n"); + env->typecode = CORD_cat(env->typecode, "} tag;\nunion {\n"); for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { - env->types = CORD_cat(env->types, "struct {\n"); + env->typecode = CORD_cat(env->typecode, "struct {\n"); for (arg_ast_t *field = tag->fields; field; field = field->next) { CORD type = compile_type(env, field->type); - CORD_appendf(&env->types, "%r %s%s;\n", type, field->name, + CORD_appendf(&env->typecode, "%r %s%s;\n", type, field->name, CORD_cmp(type, "Bool_t") ? "" : ":1"); } - CORD_appendf(&env->types, "} %s;\n", tag->name); + CORD_appendf(&env->typecode, "} %s;\n", tag->name); } - env->types = CORD_cat(env->types, "} $data;\n};\n"); + env->typecode = CORD_cat(env->typecode, "} $data;\n};\n"); return CORD_EMPTY; } case DocTest: { diff --git a/environment.c b/environment.c new file mode 100644 index 00000000..c3ecabc7 --- /dev/null +++ b/environment.c @@ -0,0 +1,62 @@ + +#include <stdlib.h> + +#include "environment.h" +#include "builtins/table.h" +#include "util.h" + +typedef struct { + const char *name; + binding_t binding; +} ns_entry_t; + +static type_t *namespace_type(table_t *ns) +{ + arg_t *fields = NULL; + for (int64_t i = Table_length(ns); i >= 1; i--) { + struct {const char *name; binding_t binding; } *entry = Table_entry(ns, i); + fields = new(arg_t, .next=fields, .name=entry->name, .type=entry->binding.type); + } + return Type(StructType, .fields=fields); +} + +env_t *new_environment(void) +{ + env_t *env = new(env_t); + + struct { + const char *name; + binding_t binding; + } global_vars[] = { + {"say", {.code="say", .type=Type(FunctionType, .args=new(arg_t, .name="text", .type=Type(StringType)), .ret=Type(VoidType))}}, + {"fail", {.code="fail", .type=Type(FunctionType, .args=new(arg_t, .name="message", .type=Type(StringType)), .ret=Type(AbortType))}}, + {"USE_COLOR", {.code="USE_COLOR", .type=Type(BoolType)}}, + }; + + for (size_t i = 0; i < sizeof(global_vars)/sizeof(global_vars[0]); i++) { + Table_str_set(&env->globals, global_vars[i].name, &global_vars[i].binding); + } + + struct { + const char *name; + type_t *type; + CORD typename; + CORD struct_val; + table_t namespace; + } global_types[] = { + {"Bool", Type(BoolType), "Bool_t", "Bool", {}}, + {"Int", Type(IntType, .bits=64), "Int_t", "Int", Table_from_entries(*(array_t*)ARRAY( + new(ns_entry_t, "min", {"Int.min", Type(IntType, .bits=64)}), + new(ns_entry_t, "max", {"Int.max", Type(IntType, .bits=64)}), + ), NULL)}, + }; + + for (size_t i = 0; i < sizeof(global_types)/sizeof(global_types[0]); i++) { + Table_str_set(&env->globals, global_types[i].name, namespace_type(&global_types[i].namespace)); + Table_str_set(&env->types, global_types[i].name, global_types[i].type); + } + + return env; +} + +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/environment.h b/environment.h new file mode 100644 index 00000000..a03ccd42 --- /dev/null +++ b/environment.h @@ -0,0 +1,26 @@ +#pragma once + +#include <gc/cord.h> + +#include "types.h" +#include "builtins/table.h" + +typedef struct { + table_t globals, types; + table_t *locals; + CORD imports; + CORD typedefs; + CORD typecode; + CORD staticdefs; + CORD funcs; + CORD main; +} env_t; + +typedef struct { + CORD code; + type_t *type; +} binding_t; + +env_t *new_environment(void); + +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 @@ -42,16 +42,16 @@ int main(int argc, char *argv[]) fclose(out); } - env_t env = {.bindings = new(table_t)}; + env_t *env = new_environment(); - CORD_appendf(&env.imports, "#include \"nextlang.h\"\n"); - CORD_appendf(&env.staticdefs, "static bool USE_COLOR = true;\n"); + CORD_appendf(&env->imports, "#include \"nextlang.h\"\n"); + CORD_appendf(&env->staticdefs, "static bool USE_COLOR = true;\n"); // Main body: for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { - CORD code = compile_statement(&env, stmt->ast); + CORD code = compile_statement(env, stmt->ast); if (code) - CORD_appendf(&env.main, "%r\n", code); + CORD_appendf(&env->main, "%r\n", code); } CORD program = CORD_asprintf( @@ -76,8 +76,8 @@ int main(int argc, char *argv[]) "return 0;\n" "}\n", f->filename, - env.imports, env.typedefs, env.types, env.staticdefs, - env.funcs, env.main); + env->imports, env->typedefs, env->types, env->staticdefs, + env->funcs, env->main); if (verbose) { FILE *out = popen(heap_strf("%s | bat -P --file-name=program.c", autofmt), "w"); @@ -570,6 +570,23 @@ PARSER(parse_num) { return NewAST(ctx->file, start, pos, Num, .n=d, .precision=precision); } +static inline bool match_separator(const char **pos) { // Either comma or newline + const char *p = *pos; + int separators = 0; + for (;;) { + if (some_of(&p, "\r\n,")) + ++separators; + else if (!comment(&p) && !some_of(&p, " \t")) + break; + } + if (separators > 0) { + *pos = p; + return true; + } else { + return false; + } +} + PARSER(parse_array) { const char *start = pos; if (!match(&pos, "[")) return NULL; @@ -581,15 +598,15 @@ PARSER(parse_array) { if (match(&pos, ":")) { whitespace(&pos); item_type = expect(ctx, pos-1, &pos, parse_type, "I couldn't parse a type for this array"); + whitespace(&pos); } for (;;) { - whitespace(&pos); ast_t *item = optional(ctx, &pos, parse_extended_expr); if (!item) break; items = new(ast_list_t, .ast=item, .next=items); - whitespace(&pos); - if (!match(&pos, ",")) break; + if (!match_separator(&pos)) + break; } whitespace(&pos); expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this array"); @@ -616,10 +633,10 @@ PARSER(parse_table) { if (!match(&pos, "=>")) parser_err(ctx, pos, pos, "I expected an '=>' for this table type"); value_type = expect(ctx, pos-1, &pos, parse_type, "I couldn't parse a value type for this table"); + whitespace(&pos); } for (;;) { - whitespace(&pos); const char *entry_start = pos; ast_t *key = optional(ctx, &pos, parse_extended_expr); if (!key) break; @@ -640,8 +657,8 @@ PARSER(parse_table) { pos = entry->end; entries = new(ast_list_t, .ast=entry, .next=entries); - whitespace(&pos); - if (!match(&pos, ",")) break; + if (!match_separator(&pos)) + break; } REVERSE_LIST(entries); @@ -1124,10 +1141,8 @@ ast_t *parse_fncall_suffix(parse_ctx_t *ctx, ast_t *fn, bool is_extern) { got_arg:; - whitespace(&pos); - if (!match(&pos, ",")) + if (!match_separator(&pos)) break; - whitespace(&pos); } whitespace(&pos); @@ -1413,15 +1428,15 @@ PARSER(parse_struct_def) { whitespace(&pos); bool secret = false; if (match(&pos, ";")) { // Extra flags - for (bool done = false; !done; done = true) { - whitespace(&pos); - if (match_word(&pos, "secret")) { + whitespace(&pos); + for (;;) { + if (match_word(&pos, "secret")) secret = true; - done = false; - } - whitespace(&pos); - match(&pos, ","); - match(&pos, ";"); + else + break; + + if (!match_separator(&pos)) + break; } } @@ -1487,14 +1502,10 @@ ast_t *parse_enum_def(parse_ctx_t *ctx, const char *pos) { } tags = new(tag_ast_t, .name=tag_name, .value=next_value, .fields=fields, .next=tags); + ++next_value; - const char *next_pos = pos; - whitespace(&next_pos); - if (!match(&next_pos, ",")) + if (!match_separator(&pos)) break; - whitespace(&next_pos); - pos = next_pos; - ++next_value; } whitespace(&pos); @@ -1566,8 +1577,9 @@ arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos, bool allow_unnamed) REVERSE_LIST(names); for (; names; names = names->next) args = new(arg_ast_t, .name=names->name, .type=type, .default_val=default_val, .next=args); - whitespace(pos); - match(pos, ","); + + if (!match_separator(pos)) + break; } REVERSE_LIST(args); @@ -1589,7 +1601,7 @@ PARSER(parse_func_def) { whitespace(&pos); bool is_inline = false; ast_t *cache_ast = NULL; - for (; whitespace(&pos), (match(&pos, ";") || match(&pos, ",")); ) { + for (bool specials = match(&pos, ";"); specials; specials = match_separator(&pos)) { const char *flag_start = pos; if (match_word(&pos, "inline")) { is_inline = true; @@ -37,6 +37,7 @@ struct type_s { BoolType, IntType, NumType, + StringType, ArrayType, TableType, FunctionType, @@ -57,6 +58,9 @@ struct type_s { int64_t bits; } NumType; struct { + const char *dsl; + } StringType; + struct { type_t *item_type; } ArrayType; struct { @@ -9,6 +9,7 @@ #define streq(a, b) (((a) == NULL && (b) == NULL) || (((a) == NULL) == ((b) == NULL) && strcmp(a, b) == 0)) #define new(t, ...) ((t*)memcpy(GC_MALLOC(sizeof(t)), &(t){__VA_ARGS__}, sizeof(t))) +#define copy(obj_ptr) ((__typeof(obj_ptr))memcpy(GC_MALLOC(sizeof(*(obj_ptr))), obj_ptr, sizeof(*(obj_ptr)))) #define grow(arr, new_size) ((typeof (arr))GC_REALLOC(arr, (sizeof(arr[0]))*(new_size))) #define Match(x, _tag) ((x)->tag == _tag ? &(x)->__data._tag : (errx(1, __FILE__ ":%d This was supposed to be a " # _tag "\n", __LINE__), &(x)->__data._tag)) #define Tagged(t, _tag, ...) new(t, .tag=_tag, .__data._tag={__VA_ARGS__}) |
