From 2b83ab279dbfb77cfd699d6da944c51c2353e64a Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sat, 9 Mar 2024 18:22:12 -0500 Subject: Add langs to the language --- ast.c | 3 ++- ast.h | 9 ++++++-- builtins/functions.c | 8 +++---- builtins/text.c | 15 +++++-------- builtins/text.h | 6 ++--- builtins/types.h | 5 ++++- compile.c | 62 ++++++++++++++++++++++++++++++++++++++++------------ parse.c | 56 +++++++++++++++++++++++++++++++++++++++++------ test/text.tm | 3 +++ tomo.c | 7 +++++- typecheck.c | 29 +++++++++++++++++++----- types.c | 2 +- types.h | 2 +- 13 files changed, 157 insertions(+), 50 deletions(-) diff --git a/ast.c b/ast.c index 71317e93..97e5bb64 100644 --- a/ast.c +++ b/ast.c @@ -98,7 +98,7 @@ CORD ast_to_cord(ast_t *ast) T(Int, "(\x1b[35m%ld\x1b[m, bits=\x1b[35m%ld\x1b[m)", data.i, data.bits) T(Num, "(\x1b[35m%ld\x1b[m, bits=\x1b[35m%ld\x1b[m)", data.n, data.bits) T(TextLiteral, "%r", Text__quoted(data.cord, true)) - T(TextJoin, "(%r)", ast_list_to_cord(data.children)) + T(TextJoin, "(%s, %r)", data.lang ? data.lang : "Text", ast_list_to_cord(data.children)) T(Declare, "(var=%s, value=%r)", ast_to_cord(data.var), ast_to_cord(data.value)) T(Assign, "(targets=%r, values=%r)", ast_list_to_cord(data.targets), ast_list_to_cord(data.values)) T(BinaryOp, "(%r, %s, %r)", ast_to_cord(data.lhs), OP_NAMES[data.op], ast_to_cord(data.rhs)) @@ -135,6 +135,7 @@ CORD ast_to_cord(ast_t *ast) T(Extern, "(name=%s, type=%r)", data.name, type_ast_to_cord(data.type)) T(StructDef, "(%s, fields=%r, namespace=%r)", data.name, arg_list_to_cord(data.fields), ast_to_cord(data.namespace)) T(EnumDef, "(%s, tags=%r, namespace=%r)", data.name, tags_to_cord(data.tags), ast_to_cord(data.namespace)) + T(LangDef, "(%s, secret=%s, namespace=%r)", data.name, data.secret ? "yes" : "no", ast_to_cord(data.namespace)) T(Index, "(indexed=%r, index=%r)", ast_to_cord(data.indexed), ast_to_cord(data.index)) T(FieldAccess, "(fielded=%r, field=%s)", ast_to_cord(data.fielded), data.field) T(DocTest, "(expr=%r, output=%r)", ast_to_cord(data.expr), Text__quoted(data.output, true)) diff --git a/ast.h b/ast.h index 93d279d7..5da66255 100644 --- a/ast.h +++ b/ast.h @@ -105,8 +105,7 @@ typedef enum { Skip, Stop, Pass, Return, Extern, - StructDef, - EnumDef, + StructDef, EnumDef, LangDef, Index, FieldAccess, DocTest, Use, @@ -141,6 +140,7 @@ struct ast_s { CORD cord; } TextLiteral; struct { + const char *lang; ast_list_t *children; } TextJoin; struct { @@ -238,6 +238,11 @@ struct ast_s { tag_ast_t *tags; ast_t *namespace; } EnumDef; + struct { + const char *name; + ast_t *namespace; + bool secret:1; + } LangDef; struct { ast_t *indexed, *index; bool unchecked; diff --git a/builtins/functions.c b/builtins/functions.c index 9cf05fe0..815e8ff2 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -57,6 +57,7 @@ public uint32_t generic_hash(const void *obj, const TypeInfo *type) { switch (type->tag) { case PointerInfo: case FunctionInfo: return Pointer__hash(obj, type); + case TextInfo: return Text__hash(obj); case ArrayInfo: return Array__hash(obj, type); case TableInfo: return Table_hash(obj, type); case CustomInfo: @@ -76,6 +77,7 @@ public int32_t generic_compare(const void *x, const void *y, const TypeInfo *typ { switch (type->tag) { case PointerInfo: case FunctionInfo: return Pointer__compare(x, y, type); + case TextInfo: return Text__compare(x, y); case ArrayInfo: return Array__compare(x, y, type); case TableInfo: return Table_compare(x, y, type); case CustomInfo: @@ -84,10 +86,6 @@ public int32_t generic_compare(const void *x, const void *y, const TypeInfo *typ return type->CustomInfo.compare(x, y, type); default: compare_data: - { - int diff = memcmp((void*)x, (void*)y, type->size); - printf("GOT DIFF: %d\n", diff); - } return (int32_t)memcmp((void*)x, (void*)y, type->size); } } @@ -96,6 +94,7 @@ public bool generic_equal(const void *x, const void *y, const TypeInfo *type) { switch (type->tag) { case PointerInfo: case FunctionInfo: return Pointer__equal(x, y, type); + case TextInfo: return Text__equal(x, y); case ArrayInfo: return Array__equal(x, y, type); case TableInfo: return Table_equal(x, y, type); case CustomInfo: @@ -113,6 +112,7 @@ public CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type switch (type->tag) { case PointerInfo: return Pointer__as_text(obj, colorize, type); case FunctionInfo: return Func__as_text(obj, colorize, type); + case TextInfo: return obj ? Text__quoted(*(CORD*)obj, colorize) :type->TextInfo.lang; case ArrayInfo: return Array__as_text(obj, colorize, type); case TableInfo: return Table_as_text(obj, colorize, type); case TypeInfoInfo: return Type__as_text(obj, colorize, type); diff --git a/builtins/text.c b/builtins/text.c index 3f926001..f9eb6a27 100644 --- a/builtins/text.c +++ b/builtins/text.c @@ -88,7 +88,7 @@ public CORD Text__quoted(CORD str, bool colorize) } } -public int Text__compare(CORD *x, CORD *y) +public int Text__compare(const CORD *x, const CORD *y) { uint8_t *xx = (uint8_t*)CORD_to_const_char_star(*x); uint8_t *yy = (uint8_t*)CORD_to_const_char_star(*y); @@ -98,12 +98,12 @@ public int Text__compare(CORD *x, CORD *y) return result; } -public bool Text__equal(CORD *x, CORD *y) +public bool Text__equal(const CORD *x, const CORD *y) { return Text__compare(x, y) == 0; } -public uint32_t Text__hash(CORD *cord) +public uint32_t Text__hash(const CORD *cord) { if (!*cord) return 0; @@ -384,13 +384,8 @@ public array_t Text__character_names(CORD text) public const TypeInfo Text = { .size=sizeof(CORD), .align=__alignof__(CORD), - .tag=CustomInfo, - .CustomInfo={ - .as_text=(void*)Text__as_text, - .compare=(void*)Text__compare, - .equal=(void*)Text__equal, - .hash=(void*)Text__hash, - }, + .tag=TextInfo, + .TextInfo={.lang="Text"}, }; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/text.h b/builtins/text.h index f2fc47cd..4c206cbb 100644 --- a/builtins/text.h +++ b/builtins/text.h @@ -16,9 +16,9 @@ typedef struct { CORD Text__as_text(const void *str, bool colorize, const TypeInfo *info); CORD Text__quoted(CORD str, bool colorize); -int Text__compare(CORD *x, CORD *y); -bool Text__equal(CORD *x, CORD *y); -uint32_t Text__hash(CORD *cord); +int Text__compare(const CORD *x, const CORD *y); +bool Text__equal(const CORD *x, const CORD *y); +uint32_t Text__hash(const CORD *cord); CORD Text__upper(CORD str); CORD Text__lower(CORD str); CORD Text__title(CORD str); diff --git a/builtins/types.h b/builtins/types.h index 533ffb86..d26c86be 100644 --- a/builtins/types.h +++ b/builtins/types.h @@ -15,7 +15,7 @@ typedef CORD (*str_fn_t)(const void*, bool, const struct TypeInfo*); typedef struct TypeInfo { int64_t size, align; struct { // Anonymous tagged union for convenience - enum { CustomInfo, PointerInfo, ArrayInfo, TableInfo, FunctionInfo, TypeInfoInfo, OpaqueInfo, } tag; + enum { CustomInfo, PointerInfo, TextInfo, ArrayInfo, TableInfo, FunctionInfo, TypeInfoInfo, OpaqueInfo, } tag; union { struct { equal_fn_t equal; @@ -27,6 +27,9 @@ typedef struct TypeInfo { const char *sigil; const struct TypeInfo *pointed; } PointerInfo; + struct { + const char *lang; + } TextInfo; struct { const struct TypeInfo *item; } ArrayInfo; diff --git a/compile.c b/compile.c index 41323128..83927cab 100644 --- a/compile.c +++ b/compile.c @@ -82,7 +82,7 @@ CORD compile_type(type_t *t) case IntType: return Match(t, IntType)->bits == 64 ? "Int_t" : CORD_asprintf("Int%ld_t", Match(t, IntType)->bits); case NumType: return Match(t, NumType)->bits == 64 ? "Num_t" : CORD_asprintf("Num%ld_t", Match(t, NumType)->bits); case TextType: { - const char *dsl = Match(t, TextType)->dsl; + const char *dsl = Match(t, TextType)->lang; return dsl ? CORD_cat(dsl, "_t") : "Text_t"; } case ArrayType: return "array_t"; @@ -109,7 +109,7 @@ CORD compile_statement(env_t *env, ast_t *ast) { CORD stmt; switch (ast->tag) { - case If: case When: case For: case While: case FunctionDef: case Return: case StructDef: case EnumDef: + case If: case When: case For: case While: case FunctionDef: case Return: case StructDef: case EnumDef: case LangDef: case Declare: case Assign: case UpdateAssign: case DocTest: case Block: stmt = compile(env, ast); break; @@ -578,21 +578,45 @@ CORD compile(env_t *env, ast_t *ast) return CORD_cat_char(code, '"'); } case TextJoin: { + const char *lang = Match(ast, TextJoin)->lang; + type_t *text_t = Type(TextType, .lang=lang); + table_t *lang_ns = lang ? Table_str_get(*env->type_namespaces, lang) : NULL; ast_list_t *chunks = Match(ast, TextJoin)->children; if (!chunks) { return "(CORD)CORD_EMPTY"; - } else if (!chunks->next) { - type_t *t = get_type(env, chunks->ast); - if (t->tag == TextType) - return compile(env, chunks->ast); - return compile_string(env, chunks->ast, "no"); + } else if (!chunks->next && chunks->ast->tag == TextLiteral) { + return compile(env, chunks->ast); } else { CORD code = "CORD_all("; for (ast_list_t *chunk = chunks; chunk; chunk = chunk->next) { + CORD chunk_code; type_t *chunk_t = get_type(env, chunk->ast); - CORD chunk_str = (chunk_t->tag == TextType) ? - compile(env, chunk->ast) : compile_string(env, chunk->ast, "no"); - code = CORD_cat(code, chunk_str); + if (chunk->ast->tag == TextLiteral) { + chunk_code = compile(env, chunk->ast); + } else if (chunk_t->tag == TextType && streq(Match(chunk_t, TextType)->lang, lang)) { + chunk_code = compile(env, chunk->ast); + } else if (lang && lang_ns) { + // Get conversion function: + chunk_code = compile(env, chunk->ast); + for (int64_t i = 1; i <= Table_length(*lang_ns); i++) { + struct {const char *name; binding_t *b; } *entry = Table_entry(*lang_ns, i); + if (entry->b->type->tag != FunctionType) continue; + if (strncmp(entry->name, "escape_", strlen("escape_")) != 0) continue; + auto fn = Match(entry->b->type, FunctionType); + if (!fn->args || fn->args->next) continue; + if (fn->ret->tag != TextType || !streq(Match(fn->ret, TextType)->lang, lang)) + continue; + if (!promote(env, &chunk_code, chunk_t, fn->args->type)) + continue; + chunk_code = CORD_all(entry->b->code, "(", chunk_code, ")"); + goto found_conversion; + } + code_err(chunk->ast, "I don't know how to convert a %T to a %T", chunk_t, text_t); + found_conversion:; + } else { + chunk_code = compile_string(env, chunk->ast, "no"); + } + code = CORD_cat(code, chunk_code); if (chunk->next) code = CORD_cat(code, ", "); } return CORD_cat(code, ")"); @@ -767,7 +791,7 @@ CORD compile(env_t *env, ast_t *ast) CORD body = compile(body_scope, fndef->body); if (CORD_fetch(body, 0) != '{') body = CORD_asprintf("{\n%r\n}", body); - env->code->funcs = CORD_all(env->code->funcs, code, " ", body); + env->code->funcs = CORD_all(env->code->funcs, code, " ", body, "\n"); if (fndef->cache && fndef->cache->tag == Int && Match(fndef->cache, Int)->i > 0) { const char *arg_type_name = heap_strf("%s$args", CORD_to_const_char_star(name)); @@ -798,7 +822,7 @@ CORD compile(env_t *env, ast_t *ast) pop_code, "Table_set(&$cache, &$args, &$ret, $table_type);\n" "return $ret;\n" - "}"); + "}\n"); env->code->funcs = CORD_cat(env->code->funcs, wrapper); } @@ -1197,7 +1221,6 @@ CORD compile(env_t *env, ast_t *ast) return "return;"; } } - // Extern, case StructDef: { compile_struct_def(env, ast); return CORD_EMPTY; @@ -1206,6 +1229,17 @@ CORD compile(env_t *env, ast_t *ast) compile_enum_def(env, ast); return CORD_EMPTY; } + case LangDef: { + // TODO: implement + auto def = Match(ast, LangDef); + CORD_appendf(&env->code->typedefs, "typedef CORD %s_t;\n", def->name); + CORD_appendf(&env->code->typedefs, "extern const TypeInfo %s;\n", def->name); + CORD_appendf(&env->code->typeinfos, "public const TypeInfo %s = {%zu, %zu, {.tag=TextInfo, .TextInfo={%s}}};\n", + def->name, sizeof(CORD), __alignof__(CORD), + Text__quoted(def->name, false), "}}};\n"); + compile_namespace(env, def->name, def->namespace); + return CORD_EMPTY; + } case DocTest: { auto test = Match(ast, DocTest); CORD src = heap_strn(test->expr->start, (size_t)(test->expr->end - test->expr->start)); @@ -1444,7 +1478,7 @@ CORD compile_type_info(env_t *env, type_t *t) { switch (t->tag) { case BoolType: case IntType: case NumType: return CORD_asprintf("&%r", type_to_cord(t)); - case TextType: return CORD_all("(&", Match(t, TextType)->dsl ? Match(t, TextType)->dsl : "Text", ")"); + case TextType: return CORD_all("(&", Match(t, TextType)->lang ? Match(t, TextType)->lang : "Text", ")"); case StructType: return CORD_all("(&", Match(t, StructType)->name, ")"); case EnumType: return CORD_all("(&", Match(t, EnumType)->name, ")"); case ArrayType: { diff --git a/parse.c b/parse.c index de33439d..9851d009 100644 --- a/parse.c +++ b/parse.c @@ -44,7 +44,7 @@ int op_tightness[] = { static const char *keywords[] = { "yes", "xor", "while", "when", "use", "then", "struct", "stop", "skip", "return", - "or", "not", "no", "mod1", "mod", "in", "if", "func", "for", "extern", + "or", "not", "no", "mod1", "mod", "lang", "in", "if", "func", "for", "extern", "enum", "else", "do", "and", "_mix_", "_min_", "_max_", NULL, }; @@ -84,7 +84,8 @@ static PARSER(parse_opt_indented_block); static PARSER(parse_var); static PARSER(parse_enum_def); static PARSER(parse_struct_def); -static PARSER(parse_string); +static PARSER(parse_lang_def); +static PARSER(parse_text); static PARSER(parse_func_def); static PARSER(parse_extern); static PARSER(parse_declaration); @@ -944,9 +945,10 @@ PARSER(parse_bool) { return NULL; } -PARSER(parse_string) { - // ["$" [interp-char [closing-interp-char]]] ('"' ... '"' / "'" ... "'") +PARSER(parse_text) { + // ["$" [name] [interp-char [closing-interp-char]]] ('"' ... '"' / "'" ... "'") const char *start = pos; + const char *lang = NULL; // Escape sequence, e.g. \r\n if (*pos == '\\') { @@ -965,7 +967,8 @@ PARSER(parse_string) { } else if (match(&pos, "'")) { open_quote = '\'', close_quote = '\''; } else if (match(&pos, "$")) { - if (strspn(pos, (char[]){*pos, 0}) >= 2) { + lang = get_id(&pos); + if (pos[1] == pos[0]) { // Disable interp using a double opener: $;;...; or $``text` open_quote = *pos; pos += 2; @@ -1061,7 +1064,7 @@ PARSER(parse_string) { REVERSE_LIST(chunks); expect_closing(ctx, &pos, (char[]){close_quote, 0}, "I was expecting a '%c' to finish this string", close_quote); - return NewAST(ctx->file, start, pos, TextJoin, .children=chunks); + return NewAST(ctx->file, start, pos, TextJoin, .lang=lang, .children=chunks); } PARSER(parse_skip) { @@ -1139,7 +1142,7 @@ PARSER(parse_term_no_suffix) { || (term=parse_heap_alloc(ctx, pos)) || (term=parse_stack_reference(ctx, pos)) || (term=parse_bool(ctx, pos)) - || (term=parse_string(ctx, pos)) + || (term=parse_text(ctx, pos)) || (term=parse_lambda(ctx, pos)) || (term=parse_parens(ctx, pos)) || (term=parse_table(ctx, pos)) @@ -1496,6 +1499,7 @@ PARSER(parse_namespace) { ast_t *stmt; if ((stmt=optional(ctx, &pos, parse_struct_def)) ||(stmt=optional(ctx, &pos, parse_enum_def)) + ||(stmt=optional(ctx, &pos, parse_lang_def)) ||(stmt=optional(ctx, &pos, parse_func_def)) ||(stmt=optional(ctx, &pos, parse_use)) ||(stmt=optional(ctx, &pos, parse_linker)) @@ -1639,6 +1643,44 @@ ast_t *parse_enum_def(parse_ctx_t *ctx, const char *pos) { return NewAST(ctx->file, start, pos, EnumDef, .name=name, .tags=tags, .namespace=namespace); } +PARSER(parse_lang_def) { + const char *start = pos; + // lang Name + // lang Name(secret) + + if (!match_word(&pos, "lang")) return NULL; + int64_t starting_indent = get_indent(ctx->file, pos); + spaces(&pos); + const char *name = get_id(&pos); + if (!name) + parser_err(ctx, start, pos, "I expected a name for this lang"); + spaces(&pos); + + bool secret = false; + if (match(&pos, "(")) { + whitespace(&pos); + if (match_word(&pos, "secret")) { + secret = true; + whitespace(&pos); + match(&pos, ","); + } + expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this lang definition"); + } + + const char *ns_pos = pos; + whitespace(&ns_pos); + int64_t ns_indent = get_indent(ctx->file, ns_pos); + ast_t *namespace = NULL; + if (ns_indent > starting_indent) { + pos = ns_pos; + namespace = optional(ctx, &pos, parse_namespace); + } + if (!namespace) + namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL); + + return NewAST(ctx->file, start, pos, LangDef, .name=name, .secret=secret, .namespace=namespace); +} + arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos, bool allow_unnamed) { arg_ast_t *args = NULL; diff --git a/test/text.tm b/test/text.tm index c842a36d..fee7e563 100644 --- a/test/text.tm +++ b/test/text.tm @@ -51,3 +51,6 @@ = ["LATIN CAPITAL LETTER A", "LATIN SMALL LETTER M", "LATIN SMALL LETTER E", "COMBINING ACUTE ACCENT", "LATIN SMALL LETTER L", "LATIN SMALL LETTER I", "LATIN SMALL LETTER E"] >> amelie2:character_names() = ["LATIN CAPITAL LETTER A", "LATIN SMALL LETTER M", "LATIN SMALL LETTER E", "COMBINING ACUTE ACCENT", "LATIN SMALL LETTER L", "LATIN SMALL LETTER I", "LATIN SMALL LETTER E"] + +>> "Hello":replace("e", "X") += "HXllo" diff --git a/tomo.c b/tomo.c index 1e55c856..631e081f 100644 --- a/tomo.c +++ b/tomo.c @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) module_code_t module = compile_file(ast); - if (verbose) { + if (verbose && mode != MODE_RUN) { FILE *out = popen(heap_strf("%s | bat -P --file-name=%s.h", autofmt, f->filename), "w"); CORD_put(module.header, out); pclose(out); @@ -130,6 +130,11 @@ int main(int argc, char *argv[]) "return 0;\n" "}\n" ); + if (verbose) { + FILE *out = popen(heap_strf("%s | bat -P --file-name=%s.c", autofmt, f->filename), "w"); + CORD_put(program, out); + pclose(out); + } CORD_put(program, runner); int status = pclose(runner); diff --git a/typecheck.c b/typecheck.c index 671326d0..bab1920b 100644 --- a/typecheck.c +++ b/typecheck.c @@ -179,6 +179,24 @@ void bind_statement(env_t *env, ast_t *statement) break; } + case LangDef: { + auto def = Match(statement, LangDef); + + type_t *type = Type(TextType, .lang=def->name); + Table_str_set(env->types, def->name, type); + env_t *ns_env = namespace_env(env, def->name); + + set_binding(ns_env, "from_unsafe_text", + new(binding_t, .type=Type(FunctionType, .args=new(arg_t, .name="text", .type=Type(TextType)), .ret=type), + .code=CORD_all("(", def->name, "_t)"))); + + for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) + bind_statement(ns_env, stmt->ast); + + type_t *typeinfo_type = Type(TypeInfoType, .name=def->name, .type=type); + Table_str_set(env->globals, def->name, new(binding_t, .type=typeinfo_type)); + break; + } default: break; } } @@ -269,8 +287,9 @@ type_t *get_type(env_t *env, ast_t *ast) code_err(ast, "'&' stack references can only be used on variables or fields of variables"); } - case TextJoin: case TextLiteral: { - return Type(TextType); + case TextLiteral: return Type(TextType); + case TextJoin: { + return Type(TextType, .lang=Match(ast, TextJoin)->lang); } case Var: { auto var = Match(ast, Var); @@ -448,7 +467,7 @@ type_t *get_type(env_t *env, ast_t *ast) // Early out if the type is knowable without any context from the block: switch (last->ast->tag) { - case UpdateAssign: case Assign: case Declare: case FunctionDef: case StructDef: case EnumDef: + case UpdateAssign: case Assign: case Declare: case FunctionDef: case StructDef: case EnumDef: case LangDef: return Type(VoidType); default: break; } @@ -624,7 +643,7 @@ type_t *get_type(env_t *env, ast_t *ast) return Type(ClosureType, Type(FunctionType, .args=args, .ret=ret)); } - case FunctionDef: case StructDef: case EnumDef: { + case FunctionDef: case StructDef: case EnumDef: case LangDef: { return Type(VoidType); } @@ -749,7 +768,7 @@ type_t *get_type(env_t *env, ast_t *ast) bool is_discardable(env_t *env, ast_t *ast) { switch (ast->tag) { - case UpdateAssign: case Assign: case Declare: case FunctionDef: case StructDef: case EnumDef: case Use: + case UpdateAssign: case Assign: case Declare: case FunctionDef: case StructDef: case EnumDef: case LangDef: case Use: return true; default: break; } diff --git a/types.c b/types.c index 10a5a7a8..ba6c1b62 100644 --- a/types.c +++ b/types.c @@ -16,7 +16,7 @@ CORD type_to_cord(type_t *t) { case VoidType: return "Void"; case MemoryType: return "Memory"; case BoolType: return "Bool"; - case TextType: return "Text"; + case TextType: return Match(t, TextType)->lang ? Match(t, TextType)->lang : "Text"; case IntType: return Match(t, IntType)->bits == 64 ? "Int" : CORD_asprintf("Int%ld", Match(t, IntType)->bits); case NumType: return Match(t, NumType)->bits == 64 ? "Num" : CORD_asprintf("Num%ld", Match(t, NumType)->bits); case ArrayType: { diff --git a/types.h b/types.h index 40cb448e..50e69778 100644 --- a/types.h +++ b/types.h @@ -64,7 +64,7 @@ struct type_s { int64_t bits; } NumType; struct { - const char *dsl; + const char *lang; } TextType; struct { type_t *item_type; -- cgit v1.2.3