Add langs to the language
This commit is contained in:
parent
1b8f7307a9
commit
2b83ab279d
3
ast.c
3
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(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(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(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(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(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))
|
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(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(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(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(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(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))
|
T(DocTest, "(expr=%r, output=%r)", ast_to_cord(data.expr), Text__quoted(data.output, true))
|
||||||
|
9
ast.h
9
ast.h
@ -105,8 +105,7 @@ typedef enum {
|
|||||||
Skip, Stop, Pass,
|
Skip, Stop, Pass,
|
||||||
Return,
|
Return,
|
||||||
Extern,
|
Extern,
|
||||||
StructDef,
|
StructDef, EnumDef, LangDef,
|
||||||
EnumDef,
|
|
||||||
Index, FieldAccess,
|
Index, FieldAccess,
|
||||||
DocTest,
|
DocTest,
|
||||||
Use,
|
Use,
|
||||||
@ -141,6 +140,7 @@ struct ast_s {
|
|||||||
CORD cord;
|
CORD cord;
|
||||||
} TextLiteral;
|
} TextLiteral;
|
||||||
struct {
|
struct {
|
||||||
|
const char *lang;
|
||||||
ast_list_t *children;
|
ast_list_t *children;
|
||||||
} TextJoin;
|
} TextJoin;
|
||||||
struct {
|
struct {
|
||||||
@ -238,6 +238,11 @@ struct ast_s {
|
|||||||
tag_ast_t *tags;
|
tag_ast_t *tags;
|
||||||
ast_t *namespace;
|
ast_t *namespace;
|
||||||
} EnumDef;
|
} EnumDef;
|
||||||
|
struct {
|
||||||
|
const char *name;
|
||||||
|
ast_t *namespace;
|
||||||
|
bool secret:1;
|
||||||
|
} LangDef;
|
||||||
struct {
|
struct {
|
||||||
ast_t *indexed, *index;
|
ast_t *indexed, *index;
|
||||||
bool unchecked;
|
bool unchecked;
|
||||||
|
@ -57,6 +57,7 @@ public uint32_t generic_hash(const void *obj, const TypeInfo *type)
|
|||||||
{
|
{
|
||||||
switch (type->tag) {
|
switch (type->tag) {
|
||||||
case PointerInfo: case FunctionInfo: return Pointer__hash(obj, type);
|
case PointerInfo: case FunctionInfo: return Pointer__hash(obj, type);
|
||||||
|
case TextInfo: return Text__hash(obj);
|
||||||
case ArrayInfo: return Array__hash(obj, type);
|
case ArrayInfo: return Array__hash(obj, type);
|
||||||
case TableInfo: return Table_hash(obj, type);
|
case TableInfo: return Table_hash(obj, type);
|
||||||
case CustomInfo:
|
case CustomInfo:
|
||||||
@ -76,6 +77,7 @@ public int32_t generic_compare(const void *x, const void *y, const TypeInfo *typ
|
|||||||
{
|
{
|
||||||
switch (type->tag) {
|
switch (type->tag) {
|
||||||
case PointerInfo: case FunctionInfo: return Pointer__compare(x, y, type);
|
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 ArrayInfo: return Array__compare(x, y, type);
|
||||||
case TableInfo: return Table_compare(x, y, type);
|
case TableInfo: return Table_compare(x, y, type);
|
||||||
case CustomInfo:
|
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);
|
return type->CustomInfo.compare(x, y, type);
|
||||||
default:
|
default:
|
||||||
compare_data:
|
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);
|
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) {
|
switch (type->tag) {
|
||||||
case PointerInfo: case FunctionInfo: return Pointer__equal(x, y, type);
|
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 ArrayInfo: return Array__equal(x, y, type);
|
||||||
case TableInfo: return Table_equal(x, y, type);
|
case TableInfo: return Table_equal(x, y, type);
|
||||||
case CustomInfo:
|
case CustomInfo:
|
||||||
@ -113,6 +112,7 @@ public CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type
|
|||||||
switch (type->tag) {
|
switch (type->tag) {
|
||||||
case PointerInfo: return Pointer__as_text(obj, colorize, type);
|
case PointerInfo: return Pointer__as_text(obj, colorize, type);
|
||||||
case FunctionInfo: return Func__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 ArrayInfo: return Array__as_text(obj, colorize, type);
|
||||||
case TableInfo: return Table_as_text(obj, colorize, type);
|
case TableInfo: return Table_as_text(obj, colorize, type);
|
||||||
case TypeInfoInfo: return Type__as_text(obj, colorize, type);
|
case TypeInfoInfo: return Type__as_text(obj, colorize, type);
|
||||||
|
@ -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 *xx = (uint8_t*)CORD_to_const_char_star(*x);
|
||||||
uint8_t *yy = (uint8_t*)CORD_to_const_char_star(*y);
|
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;
|
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;
|
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;
|
if (!*cord) return 0;
|
||||||
|
|
||||||
@ -384,13 +384,8 @@ public array_t Text__character_names(CORD text)
|
|||||||
public const TypeInfo Text = {
|
public const TypeInfo Text = {
|
||||||
.size=sizeof(CORD),
|
.size=sizeof(CORD),
|
||||||
.align=__alignof__(CORD),
|
.align=__alignof__(CORD),
|
||||||
.tag=CustomInfo,
|
.tag=TextInfo,
|
||||||
.CustomInfo={
|
.TextInfo={.lang="Text"},
|
||||||
.as_text=(void*)Text__as_text,
|
|
||||||
.compare=(void*)Text__compare,
|
|
||||||
.equal=(void*)Text__equal,
|
|
||||||
.hash=(void*)Text__hash,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||||
|
@ -16,9 +16,9 @@ typedef struct {
|
|||||||
|
|
||||||
CORD Text__as_text(const void *str, bool colorize, const TypeInfo *info);
|
CORD Text__as_text(const void *str, bool colorize, const TypeInfo *info);
|
||||||
CORD Text__quoted(CORD str, bool colorize);
|
CORD Text__quoted(CORD str, bool colorize);
|
||||||
int Text__compare(CORD *x, CORD *y);
|
int Text__compare(const CORD *x, const CORD *y);
|
||||||
bool Text__equal(CORD *x, CORD *y);
|
bool Text__equal(const CORD *x, const CORD *y);
|
||||||
uint32_t Text__hash(CORD *cord);
|
uint32_t Text__hash(const CORD *cord);
|
||||||
CORD Text__upper(CORD str);
|
CORD Text__upper(CORD str);
|
||||||
CORD Text__lower(CORD str);
|
CORD Text__lower(CORD str);
|
||||||
CORD Text__title(CORD str);
|
CORD Text__title(CORD str);
|
||||||
|
@ -15,7 +15,7 @@ typedef CORD (*str_fn_t)(const void*, bool, const struct TypeInfo*);
|
|||||||
typedef struct TypeInfo {
|
typedef struct TypeInfo {
|
||||||
int64_t size, align;
|
int64_t size, align;
|
||||||
struct { // Anonymous tagged union for convenience
|
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 {
|
union {
|
||||||
struct {
|
struct {
|
||||||
equal_fn_t equal;
|
equal_fn_t equal;
|
||||||
@ -27,6 +27,9 @@ typedef struct TypeInfo {
|
|||||||
const char *sigil;
|
const char *sigil;
|
||||||
const struct TypeInfo *pointed;
|
const struct TypeInfo *pointed;
|
||||||
} PointerInfo;
|
} PointerInfo;
|
||||||
|
struct {
|
||||||
|
const char *lang;
|
||||||
|
} TextInfo;
|
||||||
struct {
|
struct {
|
||||||
const struct TypeInfo *item;
|
const struct TypeInfo *item;
|
||||||
} ArrayInfo;
|
} ArrayInfo;
|
||||||
|
62
compile.c
62
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 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 NumType: return Match(t, NumType)->bits == 64 ? "Num_t" : CORD_asprintf("Num%ld_t", Match(t, NumType)->bits);
|
||||||
case TextType: {
|
case TextType: {
|
||||||
const char *dsl = Match(t, TextType)->dsl;
|
const char *dsl = Match(t, TextType)->lang;
|
||||||
return dsl ? CORD_cat(dsl, "_t") : "Text_t";
|
return dsl ? CORD_cat(dsl, "_t") : "Text_t";
|
||||||
}
|
}
|
||||||
case ArrayType: return "array_t";
|
case ArrayType: return "array_t";
|
||||||
@ -109,7 +109,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
|
|||||||
{
|
{
|
||||||
CORD stmt;
|
CORD stmt;
|
||||||
switch (ast->tag) {
|
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:
|
case Declare: case Assign: case UpdateAssign: case DocTest: case Block:
|
||||||
stmt = compile(env, ast);
|
stmt = compile(env, ast);
|
||||||
break;
|
break;
|
||||||
@ -578,21 +578,45 @@ CORD compile(env_t *env, ast_t *ast)
|
|||||||
return CORD_cat_char(code, '"');
|
return CORD_cat_char(code, '"');
|
||||||
}
|
}
|
||||||
case TextJoin: {
|
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;
|
ast_list_t *chunks = Match(ast, TextJoin)->children;
|
||||||
if (!chunks) {
|
if (!chunks) {
|
||||||
return "(CORD)CORD_EMPTY";
|
return "(CORD)CORD_EMPTY";
|
||||||
} else if (!chunks->next) {
|
} else if (!chunks->next && chunks->ast->tag == TextLiteral) {
|
||||||
type_t *t = get_type(env, chunks->ast);
|
return compile(env, chunks->ast);
|
||||||
if (t->tag == TextType)
|
|
||||||
return compile(env, chunks->ast);
|
|
||||||
return compile_string(env, chunks->ast, "no");
|
|
||||||
} else {
|
} else {
|
||||||
CORD code = "CORD_all(";
|
CORD code = "CORD_all(";
|
||||||
for (ast_list_t *chunk = chunks; chunk; chunk = chunk->next) {
|
for (ast_list_t *chunk = chunks; chunk; chunk = chunk->next) {
|
||||||
|
CORD chunk_code;
|
||||||
type_t *chunk_t = get_type(env, chunk->ast);
|
type_t *chunk_t = get_type(env, chunk->ast);
|
||||||
CORD chunk_str = (chunk_t->tag == TextType) ?
|
if (chunk->ast->tag == TextLiteral) {
|
||||||
compile(env, chunk->ast) : compile_string(env, chunk->ast, "no");
|
chunk_code = compile(env, chunk->ast);
|
||||||
code = CORD_cat(code, chunk_str);
|
} 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, ", ");
|
if (chunk->next) code = CORD_cat(code, ", ");
|
||||||
}
|
}
|
||||||
return 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);
|
CORD body = compile(body_scope, fndef->body);
|
||||||
if (CORD_fetch(body, 0) != '{')
|
if (CORD_fetch(body, 0) != '{')
|
||||||
body = CORD_asprintf("{\n%r\n}", body);
|
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) {
|
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));
|
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,
|
pop_code,
|
||||||
"Table_set(&$cache, &$args, &$ret, $table_type);\n"
|
"Table_set(&$cache, &$args, &$ret, $table_type);\n"
|
||||||
"return $ret;\n"
|
"return $ret;\n"
|
||||||
"}");
|
"}\n");
|
||||||
env->code->funcs = CORD_cat(env->code->funcs, wrapper);
|
env->code->funcs = CORD_cat(env->code->funcs, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1197,7 +1221,6 @@ CORD compile(env_t *env, ast_t *ast)
|
|||||||
return "return;";
|
return "return;";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Extern,
|
|
||||||
case StructDef: {
|
case StructDef: {
|
||||||
compile_struct_def(env, ast);
|
compile_struct_def(env, ast);
|
||||||
return CORD_EMPTY;
|
return CORD_EMPTY;
|
||||||
@ -1206,6 +1229,17 @@ CORD compile(env_t *env, ast_t *ast)
|
|||||||
compile_enum_def(env, ast);
|
compile_enum_def(env, ast);
|
||||||
return CORD_EMPTY;
|
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: {
|
case DocTest: {
|
||||||
auto test = Match(ast, DocTest);
|
auto test = Match(ast, DocTest);
|
||||||
CORD src = heap_strn(test->expr->start, (size_t)(test->expr->end - test->expr->start));
|
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) {
|
switch (t->tag) {
|
||||||
case BoolType: case IntType: case NumType: return CORD_asprintf("&%r", type_to_cord(t));
|
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 StructType: return CORD_all("(&", Match(t, StructType)->name, ")");
|
||||||
case EnumType: return CORD_all("(&", Match(t, EnumType)->name, ")");
|
case EnumType: return CORD_all("(&", Match(t, EnumType)->name, ")");
|
||||||
case ArrayType: {
|
case ArrayType: {
|
||||||
|
56
parse.c
56
parse.c
@ -44,7 +44,7 @@ int op_tightness[] = {
|
|||||||
|
|
||||||
static const char *keywords[] = {
|
static const char *keywords[] = {
|
||||||
"yes", "xor", "while", "when", "use", "then", "struct", "stop", "skip", "return",
|
"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_",
|
"enum", "else", "do", "and", "_mix_", "_min_", "_max_",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
@ -84,7 +84,8 @@ static PARSER(parse_opt_indented_block);
|
|||||||
static PARSER(parse_var);
|
static PARSER(parse_var);
|
||||||
static PARSER(parse_enum_def);
|
static PARSER(parse_enum_def);
|
||||||
static PARSER(parse_struct_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_func_def);
|
||||||
static PARSER(parse_extern);
|
static PARSER(parse_extern);
|
||||||
static PARSER(parse_declaration);
|
static PARSER(parse_declaration);
|
||||||
@ -944,9 +945,10 @@ PARSER(parse_bool) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PARSER(parse_string) {
|
PARSER(parse_text) {
|
||||||
// ["$" [interp-char [closing-interp-char]]] ('"' ... '"' / "'" ... "'")
|
// ["$" [name] [interp-char [closing-interp-char]]] ('"' ... '"' / "'" ... "'")
|
||||||
const char *start = pos;
|
const char *start = pos;
|
||||||
|
const char *lang = NULL;
|
||||||
|
|
||||||
// Escape sequence, e.g. \r\n
|
// Escape sequence, e.g. \r\n
|
||||||
if (*pos == '\\') {
|
if (*pos == '\\') {
|
||||||
@ -965,7 +967,8 @@ PARSER(parse_string) {
|
|||||||
} else if (match(&pos, "'")) {
|
} else if (match(&pos, "'")) {
|
||||||
open_quote = '\'', close_quote = '\'';
|
open_quote = '\'', close_quote = '\'';
|
||||||
} else if (match(&pos, "$")) {
|
} 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`
|
// Disable interp using a double opener: $;;...; or $``text`
|
||||||
open_quote = *pos;
|
open_quote = *pos;
|
||||||
pos += 2;
|
pos += 2;
|
||||||
@ -1061,7 +1064,7 @@ PARSER(parse_string) {
|
|||||||
|
|
||||||
REVERSE_LIST(chunks);
|
REVERSE_LIST(chunks);
|
||||||
expect_closing(ctx, &pos, (char[]){close_quote, 0}, "I was expecting a '%c' to finish this string", close_quote);
|
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) {
|
PARSER(parse_skip) {
|
||||||
@ -1139,7 +1142,7 @@ PARSER(parse_term_no_suffix) {
|
|||||||
|| (term=parse_heap_alloc(ctx, pos))
|
|| (term=parse_heap_alloc(ctx, pos))
|
||||||
|| (term=parse_stack_reference(ctx, pos))
|
|| (term=parse_stack_reference(ctx, pos))
|
||||||
|| (term=parse_bool(ctx, pos))
|
|| (term=parse_bool(ctx, pos))
|
||||||
|| (term=parse_string(ctx, pos))
|
|| (term=parse_text(ctx, pos))
|
||||||
|| (term=parse_lambda(ctx, pos))
|
|| (term=parse_lambda(ctx, pos))
|
||||||
|| (term=parse_parens(ctx, pos))
|
|| (term=parse_parens(ctx, pos))
|
||||||
|| (term=parse_table(ctx, pos))
|
|| (term=parse_table(ctx, pos))
|
||||||
@ -1496,6 +1499,7 @@ PARSER(parse_namespace) {
|
|||||||
ast_t *stmt;
|
ast_t *stmt;
|
||||||
if ((stmt=optional(ctx, &pos, parse_struct_def))
|
if ((stmt=optional(ctx, &pos, parse_struct_def))
|
||||||
||(stmt=optional(ctx, &pos, parse_enum_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_func_def))
|
||||||
||(stmt=optional(ctx, &pos, parse_use))
|
||(stmt=optional(ctx, &pos, parse_use))
|
||||||
||(stmt=optional(ctx, &pos, parse_linker))
|
||(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);
|
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 *parse_args(parse_ctx_t *ctx, const char **pos, bool allow_unnamed)
|
||||||
{
|
{
|
||||||
arg_ast_t *args = NULL;
|
arg_ast_t *args = NULL;
|
||||||
|
@ -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"]
|
= ["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()
|
>> 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"]
|
= ["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"
|
||||||
|
7
tomo.c
7
tomo.c
@ -66,7 +66,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
module_code_t module = compile_file(ast);
|
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");
|
FILE *out = popen(heap_strf("%s | bat -P --file-name=%s.h", autofmt, f->filename), "w");
|
||||||
CORD_put(module.header, out);
|
CORD_put(module.header, out);
|
||||||
pclose(out);
|
pclose(out);
|
||||||
@ -130,6 +130,11 @@ int main(int argc, char *argv[])
|
|||||||
"return 0;\n"
|
"return 0;\n"
|
||||||
"}\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);
|
CORD_put(program, runner);
|
||||||
int status = pclose(runner);
|
int status = pclose(runner);
|
||||||
|
29
typecheck.c
29
typecheck.c
@ -179,6 +179,24 @@ void bind_statement(env_t *env, ast_t *statement)
|
|||||||
|
|
||||||
break;
|
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;
|
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");
|
code_err(ast, "'&' stack references can only be used on variables or fields of variables");
|
||||||
}
|
}
|
||||||
case TextJoin: case TextLiteral: {
|
case TextLiteral: return Type(TextType);
|
||||||
return Type(TextType);
|
case TextJoin: {
|
||||||
|
return Type(TextType, .lang=Match(ast, TextJoin)->lang);
|
||||||
}
|
}
|
||||||
case Var: {
|
case Var: {
|
||||||
auto var = Match(ast, 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:
|
// Early out if the type is knowable without any context from the block:
|
||||||
switch (last->ast->tag) {
|
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);
|
return Type(VoidType);
|
||||||
default: break;
|
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));
|
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);
|
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)
|
bool is_discardable(env_t *env, ast_t *ast)
|
||||||
{
|
{
|
||||||
switch (ast->tag) {
|
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;
|
return true;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
2
types.c
2
types.c
@ -16,7 +16,7 @@ CORD type_to_cord(type_t *t) {
|
|||||||
case VoidType: return "Void";
|
case VoidType: return "Void";
|
||||||
case MemoryType: return "Memory";
|
case MemoryType: return "Memory";
|
||||||
case BoolType: return "Bool";
|
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 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 NumType: return Match(t, NumType)->bits == 64 ? "Num" : CORD_asprintf("Num%ld", Match(t, NumType)->bits);
|
||||||
case ArrayType: {
|
case ArrayType: {
|
||||||
|
Loading…
Reference in New Issue
Block a user