aboutsummaryrefslogtreecommitdiff
path: root/src/compile.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-08-23 19:28:08 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-08-23 19:28:08 -0400
commitfcda36561d668f43bac91ea31cd55cbbd605d330 (patch)
treeeb74c0b17df584af0fd8154422ad924e04c96cc2 /src/compile.c
parent414b0c7472c87c5a013029aefef49e2dbc41e700 (diff)
Autoformat everything with clang-format
Diffstat (limited to 'src/compile.c')
-rw-r--r--src/compile.c2824
1 files changed, 1419 insertions, 1405 deletions
diff --git a/src/compile.c b/src/compile.c
index a747b870..438e6cce 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -1,14 +1,14 @@
// Compilation logic
#include <ctype.h>
-#include <glob.h>
#include <gc.h>
+#include <glob.h>
#include <gmp.h>
#include <stdio.h>
#include <uninorm.h>
#include "ast.h"
-#include "config.h"
#include "compile.h"
+#include "config.h"
#include "enums.h"
#include "environment.h"
#include "modules.h"
@@ -22,7 +22,7 @@
#include "structs.h"
#include "typecheck.h"
-typedef ast_t* (*comprehension_body_t)(ast_t*, ast_t*);
+typedef ast_t *(*comprehension_body_t)(ast_t *, ast_t *);
static Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref);
static Text_t compile_text(env_t *env, ast_t *ast, Text_t color);
@@ -47,16 +47,11 @@ static ast_t *add_to_table_comprehension(ast_t *entry, ast_t *subject);
static ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject);
static Text_t compile_lvalue(env_t *env, ast_t *ast);
-static Text_t quoted_str(const char *str) {
- return Text$quoted(Text$from_str(str), false, Text("\""));
-}
+static Text_t quoted_str(const char *str) { return Text$quoted(Text$from_str(str), false, Text("\"")); }
-static inline Text_t quoted_text(Text_t text) {
- return Text$quoted(text, false, Text("\""));
-}
+static inline Text_t quoted_text(Text_t text) { return Text$quoted(text, false, Text("\"")); }
-Text_t promote_to_optional(type_t *t, Text_t code)
-{
+Text_t promote_to_optional(type_t *t, Text_t code) {
if (t == PATH_TYPE || t == PATH_TYPE_TYPE) {
return code;
} else if (t->tag == IntType) {
@@ -71,27 +66,23 @@ Text_t promote_to_optional(type_t *t, Text_t code)
} else if (t->tag == ByteType) {
return Texts("((OptionalByte_t){.value=", code, "})");
} else if (t->tag == StructType) {
- return Texts("({ ", compile_type(Type(OptionalType, .type=t)), " nonnull = {.value=", code, "}; nonnull.is_none = false; nonnull; })");
+ return Texts("({ ", compile_type(Type(OptionalType, .type = t)), " nonnull = {.value=", code,
+ "}; nonnull.is_none = false; nonnull; })");
} else {
return code;
}
}
-static Text_t with_source_info(env_t *env, ast_t *ast, Text_t code)
-{
- if (code.length == 0 || !ast || !ast->file || !env->do_source_mapping)
- return code;
+static Text_t with_source_info(env_t *env, ast_t *ast, Text_t code) {
+ if (code.length == 0 || !ast || !ast->file || !env->do_source_mapping) return code;
int64_t line = get_line_number(ast->file, ast->start);
return Texts("\n#line ", String(line), "\n", code);
}
-static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t *needed)
-{
- if (type_eq(actual, needed))
- return true;
+static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t *needed) {
+ if (type_eq(actual, needed)) return true;
- if (!can_promote(actual, needed))
- return false;
+ if (!can_promote(actual, needed)) return false;
if (needed->tag == ClosureType && actual->tag == FunctionType) {
*code = Texts("((Closure_t){", *code, ", NULL})");
@@ -100,8 +91,7 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
// Empty promotion:
type_t *more_complete = most_complete_type(actual, needed);
- if (more_complete)
- return true;
+ if (more_complete) return true;
// Optional promotion:
if (needed->tag == OptionalType && type_eq(actual, Match(needed, OptionalType)->type)) {
@@ -116,28 +106,25 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
}
// Lang to Text_t:
- if (actual->tag == TextType && needed->tag == TextType && streq(Match(needed, TextType)->lang, "Text"))
- return true;
+ if (actual->tag == TextType && needed->tag == TextType && streq(Match(needed, TextType)->lang, "Text")) return true;
// Automatic optional checking for nums:
if (needed->tag == NumType && actual->tag == OptionalType && Match(actual, OptionalType)->type->tag == NumType) {
int64_t line = get_line_number(ast->file, ast->start);
- *code = Texts("({ ", compile_declaration(actual, Text("opt")), " = ", *code, "; ",
- "if unlikely (", check_none(actual, Text("opt")), ")\n",
- "#line ", String(line), "\n",
- "fail_source(", quoted_str(ast->file->filename), ", ",
- String((int64_t)(ast->start - ast->file->text)), ", ",
- String((int64_t)(ast->end - ast->file->text)), ", ",
- "\"This was expected to be a value, but it's none\");\n",
- optional_into_nonnone(actual, Text("opt")), "; })");
+ *code = Texts("({ ", compile_declaration(actual, Text("opt")), " = ", *code, "; ", "if unlikely (",
+ check_none(actual, Text("opt")), ")\n", "#line ", String(line), "\n", "fail_source(",
+ quoted_str(ast->file->filename), ", ", String((int64_t)(ast->start - ast->file->text)), ", ",
+ String((int64_t)(ast->end - ast->file->text)), ", ",
+ "\"This was expected to be a value, but it's none\");\n",
+ optional_into_nonnone(actual, Text("opt")), "; })");
return true;
}
// Numeric promotions/demotions
if ((is_numeric_type(actual) || actual->tag == BoolType) && (is_numeric_type(needed) || needed->tag == BoolType)) {
- arg_ast_t *args = new(arg_ast_t, .value=LiteralCode(*code, .type=actual));
- binding_t *constructor = get_constructor(env, needed, args,
- env->current_type != NULL && type_eq(env->current_type, value_type(needed)));
+ arg_ast_t *args = new (arg_ast_t, .value = LiteralCode(*code, .type = actual));
+ binding_t *constructor = get_constructor(
+ env, needed, args, env->current_type != NULL && type_eq(env->current_type, value_type(needed)));
if (constructor) {
DeclareMatch(fn, constructor->type, FunctionType);
if (fn->args->next == NULL) {
@@ -152,8 +139,7 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
binding_t *b = get_binding(Match(needed, EnumType)->env, tag);
assert(b && b->type->tag == FunctionType);
// Single-value enum constructor:
- if (!promote(env, ast, code, actual, Match(b->type, FunctionType)->args->type))
- return false;
+ if (!promote(env, ast, code, actual, Match(b->type, FunctionType)->args->type)) return false;
*code = Texts(b->code, "(", *code, ")");
return true;
}
@@ -165,22 +151,18 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
}
// Automatic dereferencing:
- if (actual->tag == PointerType
- && can_promote(Match(actual, PointerType)->pointed, needed)) {
+ if (actual->tag == PointerType && can_promote(Match(actual, PointerType)->pointed, needed)) {
*code = Texts("*(", *code, ")");
return promote(env, ast, code, Match(actual, PointerType)->pointed, needed);
}
// Stack ref promotion:
- if (actual->tag == PointerType && needed->tag == PointerType)
- return true;
+ if (actual->tag == PointerType && needed->tag == PointerType) return true;
// Cross-promotion between tables with default values and without
- if (needed->tag == TableType && actual->tag == TableType)
- return true;
+ if (needed->tag == TableType && actual->tag == TableType) return true;
- if (needed->tag == ClosureType && actual->tag == ClosureType)
- return true;
+ if (needed->tag == ClosureType && actual->tag == ClosureType) return true;
if (needed->tag == FunctionType && actual->tag == FunctionType) {
*code = Texts("(", compile_type(needed), ")", *code);
@@ -197,29 +179,24 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
return false;
}
-Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t)
-{
+Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t) {
if (is_idempotent(ast) && can_be_mutated(env, ast)) {
- if (t->tag == ListType)
- return Texts("LIST_COPY(", compile_to_type(env, ast, t), ")");
+ if (t->tag == ListType) return Texts("LIST_COPY(", compile_to_type(env, ast, t), ")");
else if (t->tag == TableType || t->tag == SetType)
return Texts("TABLE_COPY(", compile_to_type(env, ast, t), ")");
}
return compile_to_type(env, ast, t);
}
-static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t *env, ast_t *ast)
-{
- if (ast == NULL)
- return;
+static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t *env, ast_t *ast) {
+ if (ast == NULL) return;
switch (ast->tag) {
case Var: {
binding_t *b = get_binding(enclosing_scope, Match(ast, Var)->name);
if (b) {
binding_t *shadow = get_binding(env, Match(ast, Var)->name);
- if (!shadow || shadow == b)
- Table$str_set(closed_vars, Match(ast, Var)->name, b);
+ if (!shadow || shadow == b) Table$str_set(closed_vars, Match(ast, Var)->name, b);
}
break;
}
@@ -247,7 +224,10 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
add_closed_vars(closed_vars, enclosing_scope, env, binop.rhs);
break;
}
- case Not: case Negative: case HeapAllocate: case StackReference: {
+ case Not:
+ case Negative:
+ case HeapAllocate:
+ case StackReference: {
// UNSAFE:
ast_t *value = ast->__data.Not.value;
// END UNSAFE
@@ -291,16 +271,15 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
case Comprehension: {
DeclareMatch(comp, ast, Comprehension);
if (comp->expr->tag == Comprehension) { // Nested comprehension
- ast_t *body = comp->filter ? WrapAST(ast, If, .condition=comp->filter, .body=comp->expr) : comp->expr;
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ ast_t *body = comp->filter ? WrapAST(ast, If, .condition = comp->filter, .body = comp->expr) : comp->expr;
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
return add_closed_vars(closed_vars, enclosing_scope, env, loop);
}
// List/Set/Table comprehension:
ast_t *body = comp->expr;
- if (comp->filter)
- body = WrapAST(comp->expr, If, .condition=comp->filter, .body=body);
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ if (comp->filter) body = WrapAST(comp->expr, If, .condition = comp->filter, .body = body);
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
add_closed_vars(closed_vars, enclosing_scope, env, loop);
break;
}
@@ -356,8 +335,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
ast_t *var = Match(condition, Declare)->var;
type_t *cond_t = get_type(truthy_scope, var);
if (cond_t->tag == OptionalType) {
- set_binding(truthy_scope, Match(var, Var)->name,
- Match(cond_t, OptionalType)->type, EMPTY_TEXT);
+ set_binding(truthy_scope, Match(var, Var)->name, Match(cond_t, OptionalType)->type, EMPTY_TEXT);
}
add_closed_vars(closed_vars, enclosing_scope, truthy_scope, if_->body);
add_closed_vars(closed_vars, enclosing_scope, env, if_->else_body);
@@ -367,8 +345,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
type_t *cond_t = get_type(env, condition);
if (condition->tag == Var && cond_t->tag == OptionalType) {
truthy_scope = fresh_scope(env);
- set_binding(truthy_scope, Match(condition, Var)->name,
- Match(cond_t, OptionalType)->type, EMPTY_TEXT);
+ set_binding(truthy_scope, Match(condition, Var)->name, Match(cond_t, OptionalType)->type, EMPTY_TEXT);
}
add_closed_vars(closed_vars, enclosing_scope, truthy_scope, if_->body);
add_closed_vars(closed_vars, enclosing_scope, env, if_->else_body);
@@ -386,20 +363,17 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
add_closed_vars(closed_vars, enclosing_scope, env, clause->body);
}
- if (when->else_body)
- add_closed_vars(closed_vars, enclosing_scope, env, when->else_body);
+ if (when->else_body) add_closed_vars(closed_vars, enclosing_scope, env, when->else_body);
return;
}
DeclareMatch(enum_t, subject_t, EnumType);
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
const char *clause_tag_name;
- if (clause->pattern->tag == Var)
- clause_tag_name = Match(clause->pattern, Var)->name;
+ if (clause->pattern->tag == Var) clause_tag_name = Match(clause->pattern, Var)->name;
else if (clause->pattern->tag == FunctionCall && Match(clause->pattern, FunctionCall)->fn->tag == Var)
clause_tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name;
- else
- code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum");
+ else code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum");
type_t *tag_type = NULL;
for (tag_t *tag = enum_t->tags; tag; tag = tag->next) {
@@ -412,8 +386,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
env_t *scope = when_clause_scope(env, subject_t, clause);
add_closed_vars(closed_vars, enclosing_scope, scope, clause->body);
}
- if (when->else_body)
- add_closed_vars(closed_vars, enclosing_scope, env, when->else_body);
+ if (when->else_body) add_closed_vars(closed_vars, enclosing_scope, env, when->else_body);
break;
}
case Repeat: {
@@ -424,7 +397,8 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
DeclareMatch(reduction, ast, Reduction);
static int64_t next_id = 1;
ast_t *item = FakeAST(Var, String("$it", next_id++));
- ast_t *loop = FakeAST(For, .vars=new(ast_list_t, .ast=item), .iter=reduction->iter, .body=FakeAST(Pass));
+ ast_t *loop =
+ FakeAST(For, .vars = new (ast_list_t, .ast = item), .iter = reduction->iter, .body = FakeAST(Pass));
env_t *scope = for_scope(env, loop);
add_closed_vars(closed_vars, enclosing_scope, scope, reduction->key ? reduction->key : item);
break;
@@ -472,16 +446,20 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, ExplicitlyTyped)->ast);
break;
}
- case Use: case FunctionDef: case ConvertDef: case StructDef: case EnumDef: case LangDef: case Extend: {
+ case Use:
+ case FunctionDef:
+ case ConvertDef:
+ case StructDef:
+ case EnumDef:
+ case LangDef:
+ case Extend: {
errx(1, "Definitions should not be reachable in a closure.");
}
- default:
- break;
+ default: break;
}
}
-static Table_t get_closed_vars(env_t *env, arg_ast_t *args, ast_t *block)
-{
+static Table_t get_closed_vars(env_t *env, arg_ast_t *args, ast_t *block) {
env_t *body_scope = fresh_scope(env);
for (arg_ast_t *arg = args; arg; arg = arg->next) {
type_t *arg_type = get_arg_ast_type(env, arg);
@@ -493,8 +471,7 @@ static Table_t get_closed_vars(env_t *env, arg_ast_t *args, ast_t *block)
return closed_vars;
}
-Text_t compile_declaration(type_t *t, Text_t name)
-{
+Text_t compile_declaration(type_t *t, Text_t name) {
if (t->tag == FunctionType) {
DeclareMatch(fn, t, FunctionType);
Text_t code = Texts(compile_type(fn->ret), " (*", name, ")(");
@@ -511,10 +488,8 @@ Text_t compile_declaration(type_t *t, Text_t name)
}
}
-static Text_t compile_update_assignment(env_t *env, ast_t *ast)
-{
- if (!is_update_assignment(ast))
- code_err(ast, "This is not an update assignment");
+static Text_t compile_update_assignment(env_t *env, ast_t *ast) {
+ if (!is_update_assignment(ast)) code_err(ast, "This is not an update assignment");
binary_operands_t update = UPDATE_OPERANDS(ast);
@@ -557,35 +532,34 @@ static Text_t compile_update_assignment(env_t *env, ast_t *ast)
}
case AndUpdate: {
if (lhs_t->tag == BoolType)
- update_assignment = Texts("if (", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";");
+ update_assignment =
+ Texts("if (", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";");
break;
}
case OrUpdate: {
if (lhs_t->tag == BoolType)
- update_assignment = Texts("if (!", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";");
+ update_assignment =
+ Texts("if (!", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";");
break;
}
default: break;
}
if (update_assignment.length == 0) {
- ast_t *binop = new(ast_t);
+ ast_t *binop = new (ast_t);
*binop = *ast;
binop->tag = binop_tag(binop->tag);
- if (needs_idemotency_fix)
- binop->__data.Plus.lhs = LiteralCode(Text("*lhs"), .type=lhs_t);
+ if (needs_idemotency_fix) binop->__data.Plus.lhs = LiteralCode(Text("*lhs"), .type = lhs_t);
update_assignment = Texts(lhs, " = ", compile_to_type(env, binop, lhs_t), ";");
}
-
+
if (needs_idemotency_fix)
- return Texts("{ ", compile_declaration(Type(PointerType, .pointed=lhs_t), Text("lhs")), " = &", compile_lvalue(env, update.lhs), "; ",
- update_assignment, "; }");
- else
- return update_assignment;
+ return Texts("{ ", compile_declaration(Type(PointerType, .pointed = lhs_t), Text("lhs")), " = &",
+ compile_lvalue(env, update.lhs), "; ", update_assignment, "; }");
+ else return update_assignment;
}
-static Text_t compile_binary_op(env_t *env, ast_t *ast)
-{
+static Text_t compile_binary_op(env_t *env, ast_t *ast) {
binary_operands_t binop = BINARY_OPERANDS(ast);
type_t *lhs_t = get_type(env, binop.lhs);
type_t *rhs_t = get_type(env, binop.rhs);
@@ -594,7 +568,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, overall_t);
if (!b) b = get_metamethod_binding(env, ast->tag, binop.rhs, binop.lhs, overall_t);
if (b) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
DeclareMatch(fn, b->type, FunctionType);
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -604,7 +578,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, rhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.rhs, .next=new(arg_ast_t, .value=binop.lhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.rhs, .next = new (arg_ast_t, .value = binop.lhs));
if (is_valid_call(env, fn->args, args, true))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -614,7 +588,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
if (is_valid_call(env, fn->args, args, true))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -624,7 +598,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
if (is_valid_call(env, fn->args, args, true))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -634,7 +608,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
if (is_valid_call(env, fn->args, args, true))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -643,29 +617,31 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (ast->tag == Or && lhs_t->tag == OptionalType) {
if (rhs_t->tag == AbortType || rhs_t->tag == ReturnType) {
- return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ",
- "if (", check_none(lhs_t, Text("lhs")), ") ", compile_statement(env, binop.rhs), " ",
- optional_into_nonnone(lhs_t, Text("lhs")), "; })");
+ return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ", "if (",
+ check_none(lhs_t, Text("lhs")), ") ", compile_statement(env, binop.rhs), " ",
+ optional_into_nonnone(lhs_t, Text("lhs")), "; })");
}
if (is_incomplete_type(rhs_t)) {
type_t *complete = most_complete_type(rhs_t, Match(lhs_t, OptionalType)->type);
if (complete == NULL)
- code_err(binop.rhs, "I don't know how to convert a ", type_to_str(rhs_t), " to a ", type_to_str(Match(lhs_t, OptionalType)->type));
+ code_err(binop.rhs, "I don't know how to convert a ", type_to_str(rhs_t), " to a ",
+ type_to_str(Match(lhs_t, OptionalType)->type));
rhs_t = complete;
}
if (rhs_t->tag == OptionalType && type_eq(lhs_t, rhs_t)) {
return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ",
- check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : lhs; })");
+ check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : lhs; })");
} else if (rhs_t->tag != OptionalType && type_eq(Match(lhs_t, OptionalType)->type, rhs_t)) {
return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ",
- check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : ",
- optional_into_nonnone(lhs_t, Text("lhs")), "; })");
+ check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : ",
+ optional_into_nonnone(lhs_t, Text("lhs")), "; })");
} else if (rhs_t->tag == BoolType) {
return Texts("((!", check_none(lhs_t, compile(env, binop.lhs)), ") || ", compile(env, binop.rhs), ")");
} else {
- code_err(ast, "I don't know how to do an 'or' operation between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast, "I don't know how to do an 'or' operation between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t));
}
}
@@ -678,70 +654,98 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
code_err(ast, "Exponentiation is only supported for Num types, not ", type_to_str(overall_t));
if (overall_t->tag == NumType && Match(overall_t, NumType)->bits == TYPE_NBITS32)
return Texts("powf(", lhs, ", ", rhs, ")");
- else
- return Texts("pow(", lhs, ", ", rhs, ")");
+ else return Texts("pow(", lhs, ", ", rhs, ")");
}
case Multiply: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " * ", rhs, ")");
}
case Divide: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " / ", rhs, ")");
}
case Mod: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " % ", rhs, ")");
}
case Mod1: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("((((", lhs, ")-1) % (", rhs, ")) + 1)");
}
case Plus: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " + ", rhs, ")");
}
case Minus: {
if (overall_t->tag == SetType)
return Texts("Table$without(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " - ", rhs, ")");
}
case LeftShift: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " << ", rhs, ")");
}
case RightShift: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " >> ", rhs, ")");
}
case UnsignedLeftShift: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " << ", rhs, ")");
}
case UnsignedRightShift: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " >> ", rhs, ")");
}
case And: {
- if (overall_t->tag == BoolType)
- return Texts("(", lhs, " && ", rhs, ")");
- else if (overall_t->tag == IntType || overall_t->tag == ByteType)
- return Texts("(", lhs, " & ", rhs, ")");
+ if (overall_t->tag == BoolType) return Texts("(", lhs, " && ", rhs, ")");
+ else if (overall_t->tag == IntType || overall_t->tag == ByteType) return Texts("(", lhs, " & ", rhs, ")");
else if (overall_t->tag == SetType)
return Texts("Table$overlap(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
else
- code_err(ast, "The 'and' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values");
+ code_err(ast, "The 'and' operator isn't supported between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t), " values");
}
case Compare: {
return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(overall_t), ")");
@@ -754,7 +758,8 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
} else if (overall_t->tag == SetType) {
return Texts("Table$with(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
} else {
- code_err(ast, "The 'or' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values");
+ code_err(ast, "The 'or' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t),
+ " values");
}
}
case Xor: {
@@ -764,20 +769,22 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
else if (overall_t->tag == SetType)
return Texts("Table$xor(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
else
- code_err(ast, "The 'xor' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values");
+ code_err(ast, "The 'xor' operator isn't supported between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t), " values");
}
case Concat: {
- if (overall_t == PATH_TYPE)
- return Texts("Path$concat(", lhs, ", ", rhs, ")");
+ if (overall_t == PATH_TYPE) return Texts("Path$concat(", lhs, ", ", rhs, ")");
switch (overall_t->tag) {
case TextType: {
return Texts("Text$concat(", lhs, ", ", rhs, ")");
}
case ListType: {
- return Texts("List$concat(", lhs, ", ", rhs, ", sizeof(", compile_type(Match(overall_t, ListType)->item_type), "))");
+ return Texts("List$concat(", lhs, ", ", rhs, ", sizeof(",
+ compile_type(Match(overall_t, ListType)->item_type), "))");
}
default:
- code_err(ast, "Concatenation isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values");
+ code_err(ast, "Concatenation isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t),
+ " values");
}
}
default: errx(1, "Not a valid binary operation: %s", ast_to_sexp_str(ast));
@@ -785,10 +792,8 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
return EMPTY_TEXT;
}
-PUREFUNC Text_t compile_unsigned_type(type_t *t)
-{
- if (t->tag != IntType)
- errx(1, "Not an int type, so unsigned doesn't make sense!");
+PUREFUNC Text_t compile_unsigned_type(type_t *t) {
+ if (t->tag != IntType) errx(1, "Not an int type, so unsigned doesn't make sense!");
switch (Match(t, IntType)->bits) {
case TYPE_IBITS8: return Text("uint8_t");
case TYPE_IBITS16: return Text("uint16_t");
@@ -799,8 +804,7 @@ PUREFUNC Text_t compile_unsigned_type(type_t *t)
return EMPTY_TEXT;
}
-Text_t compile_type(type_t *t)
-{
+Text_t compile_type(type_t *t) {
if (t == PATH_TYPE) return Text("Path_t");
else if (t == PATH_TYPE_TYPE) return Text("PathType_t");
@@ -814,13 +818,13 @@ Text_t compile_type(type_t *t)
case CStringType: return Text("const char*");
case BigIntType: return Text("Int_t");
case IntType: return Texts("Int", String(Match(t, IntType)->bits), "_t");
- case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? Text("Num_t") : Texts("Num", String(Match(t, NumType)->bits), "_t");
+ case NumType:
+ return Match(t, NumType)->bits == TYPE_NBITS64 ? Text("Num_t")
+ : Texts("Num", String(Match(t, NumType)->bits), "_t");
case TextType: {
DeclareMatch(text, t, TextType);
- if (!text->lang || streq(text->lang, "Text"))
- return Text("Text_t");
- else
- return namespace_name(text->env, text->env->namespace, Text("$type"));
+ if (!text->lang || streq(text->lang, "Text")) return Text("Text_t");
+ else return namespace_name(text->env, text->env->namespace, Text("$type"));
}
case ListType: return Text("List_t");
case SetType: return Text("Table_t");
@@ -832,8 +836,7 @@ Text_t compile_type(type_t *t)
code = Texts(code, compile_type(arg->type));
if (arg->next) code = Texts(code, ", ");
}
- if (!fn->args)
- code = Texts(code, "void");
+ if (!fn->args) code = Texts(code, "void");
return Texts(code, ")");
}
case ClosureType: return Text("Closure_t");
@@ -850,24 +853,27 @@ Text_t compile_type(type_t *t)
case OptionalType: {
type_t *nonnull = Match(t, OptionalType)->type;
switch (nonnull->tag) {
- case CStringType: case FunctionType: case ClosureType:
- case PointerType: case EnumType:
- return compile_type(nonnull);
- case TextType:
- return Match(nonnull, TextType)->lang ? compile_type(nonnull) : Text("OptionalText_t");
- case IntType: case BigIntType: case NumType: case BoolType: case ByteType:
- case ListType: case TableType: case SetType:
- return Texts("Optional", compile_type(nonnull));
+ case CStringType:
+ case FunctionType:
+ case ClosureType:
+ case PointerType:
+ case EnumType: return compile_type(nonnull);
+ case TextType: return Match(nonnull, TextType)->lang ? compile_type(nonnull) : Text("OptionalText_t");
+ case IntType:
+ case BigIntType:
+ case NumType:
+ case BoolType:
+ case ByteType:
+ case ListType:
+ case TableType:
+ case SetType: return Texts("Optional", compile_type(nonnull));
case StructType: {
- if (nonnull == PATH_TYPE)
- return Text("OptionalPath_t");
- if (nonnull == PATH_TYPE_TYPE)
- return Text("OptionalPathType_t");
+ if (nonnull == PATH_TYPE) return Text("OptionalPath_t");
+ if (nonnull == PATH_TYPE_TYPE) return Text("OptionalPathType_t");
DeclareMatch(s, nonnull, StructType);
return namespace_name(s->env, s->env->namespace->parent, Texts("$Optional", s->name, "$$type"));
}
- default:
- compiler_err(NULL, NULL, NULL, "Optional types are not supported for: ", type_to_str(t));
+ default: compiler_err(NULL, NULL, NULL, "Optional types are not supported for: ", type_to_str(t));
}
}
case TypeInfoType: return Text("TypeInfo_t");
@@ -876,18 +882,19 @@ Text_t compile_type(type_t *t)
return EMPTY_TEXT;
}
-Text_t compile_lvalue(env_t *env, ast_t *ast)
-{
+Text_t compile_lvalue(env_t *env, ast_t *ast) {
if (!can_be_mutated(env, ast)) {
if (ast->tag == Index) {
ast_t *subject = Match(ast, Index)->indexed;
- code_err(subject, "This is an immutable value, you can't mutate its contents");
+ code_err(subject, "This is an immutable value, you can't mutate "
+ "its contents");
} else if (ast->tag == FieldAccess) {
ast_t *subject = Match(ast, FieldAccess)->fielded;
type_t *t = get_type(env, subject);
code_err(subject, "This is an immutable ", type_to_str(t), " value, you can't assign to its fields");
} else {
- code_err(ast, "This is a value of type ", type_to_str(get_type(env, ast)), " and can't be used as an assignment target");
+ code_err(ast, "This is a value of type ", type_to_str(get_type(env, ast)),
+ " and can't be used as an assignment target");
}
}
@@ -895,47 +902,44 @@ Text_t compile_lvalue(env_t *env, ast_t *ast)
DeclareMatch(index, ast, Index);
type_t *container_t = get_type(env, index->indexed);
if (container_t->tag == OptionalType)
- code_err(index->indexed, "This value might be none, so it can't be safely used as an assignment target");
+ code_err(index->indexed, "This value might be none, so it can't be "
+ "safely used as an assignment target");
- if (!index->index && container_t->tag == PointerType)
- return compile(env, ast);
+ if (!index->index && container_t->tag == PointerType) return compile(env, ast);
container_t = value_type(container_t);
type_t *index_t = get_type(env, index->index);
if (container_t->tag == ListType) {
Text_t target_code = compile_to_pointer_depth(env, index->indexed, 1, false);
type_t *item_type = Match(container_t, ListType)->item_type;
- Text_t index_code = index->index->tag == Int
- ? compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64))
- : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, index->index), ", no)")
- : Texts("(Int64_t)(", compile(env, index->index), ")"));
+ Text_t index_code =
+ index->index->tag == Int
+ ? compile_int_to_type(env, index->index, Type(IntType, .bits = TYPE_IBITS64))
+ : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, index->index), ", no)")
+ : Texts("(Int64_t)(", compile(env, index->index), ")"));
if (index->unchecked) {
- return Texts("List_lvalue_unchecked(", compile_type(item_type), ", ", target_code, ", ",
- index_code, ")");
+ return Texts("List_lvalue_unchecked(", compile_type(item_type), ", ", target_code, ", ", index_code,
+ ")");
} else {
- return Texts("List_lvalue(", compile_type(item_type), ", ", target_code, ", ",
- index_code,
- ", ", String((int)(ast->start - ast->file->text)),
- ", ", String((int)(ast->end - ast->file->text)), ")");
+ return Texts("List_lvalue(", compile_type(item_type), ", ", target_code, ", ", index_code, ", ",
+ String((int)(ast->start - ast->file->text)), ", ",
+ String((int)(ast->end - ast->file->text)), ")");
}
} else if (container_t->tag == TableType) {
DeclareMatch(table_type, container_t, TableType);
if (table_type->default_value) {
type_t *value_type = get_type(env, table_type->default_value);
- return Texts("*Table$get_or_setdefault(",
- compile_to_pointer_depth(env, index->indexed, 1, false), ", ",
- compile_type(table_type->key_type), ", ",
- compile_type(value_type), ", ",
- compile_to_type(env, index->index, table_type->key_type), ", ",
- compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
- compile_type_info(container_t), ")");
+ return Texts("*Table$get_or_setdefault(", compile_to_pointer_depth(env, index->indexed, 1, false), ", ",
+ compile_type(table_type->key_type), ", ", compile_type(value_type), ", ",
+ compile_to_type(env, index->index, table_type->key_type), ", ",
+ compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
+ compile_type_info(container_t), ")");
}
- if (index->unchecked)
- code_err(ast, "Table indexes cannot be unchecked");
+ if (index->unchecked) code_err(ast, "Table indexes cannot be unchecked");
return Texts("*(", compile_type(Type(PointerType, table_type->value_type)), ")Table$reserve(",
- compile_to_pointer_depth(env, index->indexed, 1, false), ", ",
- compile_to_type(env, index->index, Type(PointerType, table_type->key_type, .is_stack=true)), ", NULL,",
- compile_type_info(container_t), ")");
+ compile_to_pointer_depth(env, index->indexed, 1, false), ", ",
+ compile_to_type(env, index->index, Type(PointerType, table_type->key_type, .is_stack = true)),
+ ", NULL,", compile_type_info(container_t), ")");
} else {
code_err(ast, "I don't know how to assign to this target");
}
@@ -947,15 +951,12 @@ Text_t compile_lvalue(env_t *env, ast_t *ast)
return EMPTY_TEXT;
}
-static Text_t compile_assignment(env_t *env, ast_t *target, Text_t value)
-{
+static Text_t compile_assignment(env_t *env, ast_t *target, Text_t value) {
return Texts(compile_lvalue(env, target), " = ", value);
}
-static Text_t compile_inline_block(env_t *env, ast_t *ast)
-{
- if (ast->tag != Block)
- return compile_statement(env, ast);
+static Text_t compile_inline_block(env_t *env, ast_t *ast) {
+ if (ast->tag != Block) return compile_statement(env, ast);
Text_t code = EMPTY_TEXT;
ast_list_t *stmts = Match(ast, Block)->statements;
@@ -973,60 +974,44 @@ static Text_t compile_inline_block(env_t *env, ast_t *ast)
return code;
}
-Text_t optional_into_nonnone(type_t *t, Text_t value)
-{
+Text_t optional_into_nonnone(type_t *t, Text_t value) {
if (t->tag == OptionalType) t = Match(t, OptionalType)->type;
switch (t->tag) {
- case IntType: case ByteType:
- return Texts(value, ".value");
+ case IntType:
+ case ByteType: return Texts(value, ".value");
case StructType:
- if (t == PATH_TYPE || t == PATH_TYPE_TYPE)
- return value;
+ if (t == PATH_TYPE || t == PATH_TYPE_TYPE) return value;
return Texts(value, ".value");
- default:
- return value;
+ default: return value;
}
}
-Text_t check_none(type_t *t, Text_t value)
-{
+Text_t check_none(type_t *t, Text_t value) {
t = Match(t, OptionalType)->type;
// NOTE: these use statement expressions ({...;}) because some compilers
// complain about excessive parens around equality comparisons
if (t->tag == PointerType || t->tag == FunctionType || t->tag == CStringType)
return Texts("({", value, " == NULL;})");
- else if (t == PATH_TYPE)
- return Texts("({(", value, ").type.$tag == PATH_NONE;})");
- else if (t == PATH_TYPE_TYPE)
- return Texts("({(", value, ").$tag == PATH_NONE;})");
- else if (t->tag == BigIntType)
- return Texts("({(", value, ").small == 0;})");
- else if (t->tag == ClosureType)
- return Texts("({(", value, ").fn == NULL;})");
+ else if (t == PATH_TYPE) return Texts("({(", value, ").type.$tag == PATH_NONE;})");
+ else if (t == PATH_TYPE_TYPE) return Texts("({(", value, ").$tag == PATH_NONE;})");
+ else if (t->tag == BigIntType) return Texts("({(", value, ").small == 0;})");
+ else if (t->tag == ClosureType) return Texts("({(", value, ").fn == NULL;})");
else if (t->tag == NumType)
return Texts(Match(t, NumType)->bits == TYPE_NBITS64 ? "Num$isnan(" : "Num32$isnan(", value, ")");
- else if (t->tag == ListType)
- return Texts("({(", value, ").length < 0;})");
- else if (t->tag == TableType || t->tag == SetType)
- return Texts("({(", value, ").entries.length < 0;})");
- else if (t->tag == BoolType)
- return Texts("({(", value, ") == NONE_BOOL;})");
- else if (t->tag == TextType)
- return Texts("({(", value, ").length < 0;})");
- else if (t->tag == IntType || t->tag == ByteType || t->tag == StructType)
- return Texts("(", value, ").is_none");
+ else if (t->tag == ListType) return Texts("({(", value, ").length < 0;})");
+ else if (t->tag == TableType || t->tag == SetType) return Texts("({(", value, ").entries.length < 0;})");
+ else if (t->tag == BoolType) return Texts("({(", value, ") == NONE_BOOL;})");
+ else if (t->tag == TextType) return Texts("({(", value, ").length < 0;})");
+ else if (t->tag == IntType || t->tag == ByteType || t->tag == StructType) return Texts("(", value, ").is_none");
else if (t->tag == EnumType) {
- if (enum_has_fields(t))
- return Texts("({(", value, ").$tag == 0;})");
- else
- return Texts("((", value, ") == 0)");
+ if (enum_has_fields(t)) return Texts("({(", value, ").$tag == 0;})");
+ else return Texts("((", value, ") == 0)");
}
print_err("Optional check not implemented for: ", type_to_str(t));
return EMPTY_TEXT;
}
-static Text_t compile_condition(env_t *env, ast_t *ast)
-{
+static Text_t compile_condition(env_t *env, ast_t *ast) {
type_t *t = get_type(env, ast);
if (t->tag == BoolType) {
return compile(env, ast);
@@ -1039,15 +1024,15 @@ static Text_t compile_condition(env_t *env, ast_t *ast)
} else if (t->tag == OptionalType) {
return Texts("!", check_none(t, compile(env, ast)));
} else if (t->tag == PointerType) {
- code_err(ast, "This pointer will always be non-none, so it should not be used in a conditional.");
+ code_err(ast, "This pointer will always be non-none, so it should not be "
+ "used in a conditional.");
} else {
code_err(ast, type_to_str(t), " values cannot be used for conditionals");
}
return EMPTY_TEXT;
}
-static Text_t _compile_statement(env_t *env, ast_t *ast)
-{
+static Text_t _compile_statement(env_t *env, ast_t *ast) {
switch (ast->tag) {
case When: {
// Typecheck to verify exhaustiveness:
@@ -1061,21 +1046,20 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
Text_t prefix = EMPTY_TEXT, suffix = EMPTY_TEXT;
ast_t *subject = when->subject;
if (!is_idempotent(when->subject)) {
- prefix = Texts("{\n", compile_declaration(subject_t, Text("_when_subject")), " = ", compile(env, subject), ";\n");
+ prefix = Texts("{\n", compile_declaration(subject_t, Text("_when_subject")), " = ",
+ compile(env, subject), ";\n");
suffix = Text("}\n");
- subject = LiteralCode(Text("_when_subject"), .type=subject_t);
+ subject = LiteralCode(Text("_when_subject"), .type = subject_t);
}
Text_t code = EMPTY_TEXT;
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
- ast_t *comparison = WrapAST(clause->pattern, Equals, .lhs=subject, .rhs=clause->pattern);
+ ast_t *comparison = WrapAST(clause->pattern, Equals, .lhs = subject, .rhs = clause->pattern);
(void)get_type(env, comparison);
- if (code.length > 0)
- code = Texts(code, "else ");
+ if (code.length > 0) code = Texts(code, "else ");
code = Texts(code, "if (", compile(env, comparison), ")", compile_statement(env, clause->body));
}
- if (when->else_body)
- code = Texts(code, "else ", compile_statement(env, when->else_body));
+ if (when->else_body) code = Texts(code, "else ", compile_statement(env, when->else_body));
code = Texts(prefix, code, suffix);
return code;
}
@@ -1085,17 +1069,17 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
Text_t code;
if (enum_has_fields(subject_t))
code = Texts("WHEN(", compile_type(subject_t), ", ", compile(env, when->subject), ", _when_subject, {\n");
- else
- code = Texts("switch(", compile(env, when->subject), ") {\n");
+ else code = Texts("switch(", compile(env, when->subject), ") {\n");
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
if (clause->pattern->tag == Var) {
const char *clause_tag_name = Match(clause->pattern, Var)->name;
type_t *clause_type = clause->body ? get_type(env, clause->body) : Type(VoidType);
- code = Texts(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)), ": {\n",
- compile_inline_block(env, clause->body),
- (clause_type->tag == ReturnType || clause_type->tag == AbortType) ? EMPTY_TEXT : Text("break;\n"),
- "}\n");
+ code = Texts(
+ code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)),
+ ": {\n", compile_inline_block(env, clause->body),
+ (clause_type->tag == ReturnType || clause_type->tag == AbortType) ? EMPTY_TEXT : Text("break;\n"),
+ "}\n");
continue;
}
@@ -1103,7 +1087,8 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum type");
const char *clause_tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name;
- code = Texts(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)), ": {\n");
+ code = Texts(code, "case ",
+ namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)), ": {\n");
type_t *tag_type = NULL;
for (tag_t *tag = enum_t->tags; tag; tag = tag->next) {
if (streq(tag->name, clause_tag_name)) {
@@ -1117,12 +1102,12 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
DeclareMatch(tag_struct, tag_type, StructType);
arg_ast_t *args = Match(clause->pattern, FunctionCall)->args;
if (args && !args->next && tag_struct->fields && tag_struct->fields->next) {
- if (args->value->tag != Var)
- code_err(args->value, "This is not a valid variable to bind to");
+ if (args->value->tag != Var) code_err(args->value, "This is not a valid variable to bind to");
const char *var_name = Match(args->value, Var)->name;
if (!streq(var_name, "_")) {
Text_t var = Texts("_$", var_name);
- code = Texts(code, compile_declaration(tag_type, var), " = _when_subject.", valid_c_name(clause_tag_name), ";\n");
+ code = Texts(code, compile_declaration(tag_type, var), " = _when_subject.",
+ valid_c_name(clause_tag_name), ";\n");
scope = fresh_scope(scope);
set_binding(scope, Match(args->value, Var)->name, tag_type, EMPTY_TEXT);
}
@@ -1131,11 +1116,10 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
arg_t *field = tag_struct->fields;
for (arg_ast_t *arg = args; arg || field; arg = arg->next) {
if (!arg)
- code_err(ast, "The field ", type_to_str(subject_t), ".", clause_tag_name, ".", field->name, " wasn't accounted for");
- if (!field)
- code_err(arg->value, "This is one more field than ", type_to_str(subject_t), " has");
- if (arg->name)
- code_err(arg->value, "Named arguments are not currently supported");
+ code_err(ast, "The field ", type_to_str(subject_t), ".", clause_tag_name, ".", field->name,
+ " wasn't accounted for");
+ if (!field) code_err(arg->value, "This is one more field than ", type_to_str(subject_t), " has");
+ if (arg->name) code_err(arg->value, "Named arguments are not currently supported");
const char *var_name = Match(arg->value, Var)->name;
if (!streq(var_name, "_")) {
@@ -1151,8 +1135,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
ast_list_t *statements = Match(clause->body, Block)->statements;
if (!statements || (statements->ast->tag == Pass && !statements->next))
code = Texts(code, "break;\n}\n");
- else
- code = Texts(code, compile_inline_block(scope, clause->body), "\nbreak;\n}\n");
+ else code = Texts(code, compile_inline_block(scope, clause->body), "\nbreak;\n}\n");
} else {
code = Texts(code, compile_statement(scope, clause->body), "\nbreak;\n}\n");
}
@@ -1162,8 +1145,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
ast_list_t *statements = Match(when->else_body, Block)->statements;
if (!statements || (statements->ast->tag == Pass && !statements->next))
code = Texts(code, "default: break;");
- else
- code = Texts(code, "default: {\n", compile_inline_block(env, when->else_body), "\nbreak;\n}\n");
+ else code = Texts(code, "default: {\n", compile_inline_block(env, when->else_body), "\nbreak;\n}\n");
} else {
code = Texts(code, "default: {\n", compile_statement(env, when->else_body), "\nbreak;\n}\n");
}
@@ -1176,8 +1158,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
case DocTest: {
DeclareMatch(test, ast, DocTest);
type_t *expr_t = get_type(env, test->expr);
- if (!expr_t)
- code_err(test->expr, "I couldn't figure out the type of this expression");
+ if (!expr_t) code_err(test->expr, "I couldn't figure out the type of this expression");
Text_t setup = EMPTY_TEXT;
Text_t test_code;
@@ -1199,28 +1180,37 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
&& value_type(get_type(env, Match(assign->targets->ast, Index)->indexed))->tag == TableType)
lhs_t = Match(lhs_t, OptionalType)->type;
if (has_stack_memory(lhs_t))
- code_err(test->expr, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
+ code_err(test->expr, "Stack references cannot be assigned "
+ "to variables because the "
+ "variable's scope may outlive the "
+ "scope of the stack memory.");
env_t *val_scope = with_enum_scope(env, lhs_t);
Text_t value = compile_to_type(val_scope, assign->values->ast, lhs_t);
test_code = Texts("(", compile_assignment(env, assign->targets->ast, value), ")");
expr_t = lhs_t;
} else {
- // Multi-assign or assignment to potentially non-idempotent targets
+ // Multi-assign or assignment to potentially non-idempotent
+ // targets
if (test->expected && assign->targets->next)
- code_err(ast, "Sorry, but doctesting with '=' is not supported for multi-assignments");
+ code_err(ast, "Sorry, but doctesting with '=' is not "
+ "supported for "
+ "multi-assignments");
test_code = Text("({ // Assignment\n");
int64_t i = 1;
- for (ast_list_t *target = assign->targets, *value = assign->values; target && value; target = target->next, value = value->next) {
+ for (ast_list_t *target = assign->targets, *value = assign->values; target && value;
+ target = target->next, value = value->next) {
type_t *lhs_t = get_type(env, target->ast);
if (target->ast->tag == Index && lhs_t->tag == OptionalType
&& value_type(get_type(env, Match(target->ast, Index)->indexed))->tag == TableType)
lhs_t = Match(lhs_t, OptionalType)->type;
if (has_stack_memory(lhs_t))
- code_err(ast, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
- if (target == assign->targets)
- expr_t = lhs_t;
+ code_err(ast, "Stack references cannot be assigned to "
+ "variables because the "
+ "variable's scope may outlive the scope "
+ "of the stack memory.");
+ if (target == assign->targets) expr_t = lhs_t;
env_t *val_scope = with_enum_scope(env, lhs_t);
Text_t val_code = compile_to_type(val_scope, value->ast, lhs_t);
test_code = Texts(test_code, compile_type(lhs_t), " $", String(i), " = ", val_code, ";\n");
@@ -1240,15 +1230,16 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (update.lhs->tag == Index) {
type_t *indexed = value_type(get_type(env, Match(update.lhs, Index)->indexed));
if (indexed->tag == TableType && Match(indexed, TableType)->default_value == NULL)
- code_err(update.lhs, "Update assignments are not currently supported for tables");
+ code_err(update.lhs, "Update assignments are not currently "
+ "supported for tables");
}
- ast_t *update_var = new(ast_t);
+ ast_t *update_var = new (ast_t);
*update_var = *test->expr;
- update_var->__data.PlusUpdate.lhs = LiteralCode(Text("(*expr)"), .type=lhs_t); // UNSAFE
- test_code = Texts("({",
- compile_declaration(Type(PointerType, lhs_t), Text("expr")), " = &(", compile_lvalue(env, update.lhs), "); ",
- compile_statement(env, update_var), "; *expr; })");
+ update_var->__data.PlusUpdate.lhs = LiteralCode(Text("(*expr)"), .type = lhs_t); // UNSAFE
+ test_code =
+ Texts("({", compile_declaration(Type(PointerType, lhs_t), Text("expr")), " = &(",
+ compile_lvalue(env, update.lhs), "); ", compile_statement(env, update_var), "; *expr; })");
expr_t = lhs_t;
} else if (expr_t->tag == VoidType || expr_t->tag == AbortType || expr_t->tag == ReturnType) {
test_code = Texts("({", compile_statement(env, test->expr), " NULL;})");
@@ -1256,27 +1247,19 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
test_code = compile(env, test->expr);
}
if (test->expected) {
- return Texts(
- setup,
- "test(", compile_type(expr_t), ", ", test_code, ", ",
- compile_to_type(env, test->expected, expr_t), ", ",
- compile_type_info(expr_t), ", ",
- String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
- String((int64_t)(test->expr->end - test->expr->file->text)), ");");
+ return Texts(setup, "test(", compile_type(expr_t), ", ", test_code, ", ",
+ compile_to_type(env, test->expected, expr_t), ", ", compile_type_info(expr_t), ", ",
+ String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
+ String((int64_t)(test->expr->end - test->expr->file->text)), ");");
} else {
if (expr_t->tag == VoidType || expr_t->tag == AbortType) {
- return Texts(
- setup,
- "inspect_void(", test_code, ", ", compile_type_info(expr_t), ", ",
- String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
- String((int64_t)(test->expr->end - test->expr->file->text)), ");");
+ return Texts(setup, "inspect_void(", test_code, ", ", compile_type_info(expr_t), ", ",
+ String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
+ String((int64_t)(test->expr->end - test->expr->file->text)), ");");
}
- return Texts(
- setup,
- "inspect(", compile_type(expr_t), ", ", test_code, ", ",
- compile_type_info(expr_t), ", ",
- String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
- String((int64_t)(test->expr->end - test->expr->file->text)), ");");
+ return Texts(setup, "inspect(", compile_type(expr_t), ", ", test_code, ", ", compile_type_info(expr_t),
+ ", ", String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
+ String((int64_t)(test->expr->end - test->expr->file->text)), ");");
}
}
case Assert: {
@@ -1286,67 +1269,69 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
switch (expr->tag) {
case And: {
DeclareMatch(and_, ast, And);
- return Texts(
- compile_statement(env, WrapAST(ast, Assert, .expr=and_->lhs, .message=message)),
- compile_statement(env, WrapAST(ast, Assert, .expr=and_->rhs, .message=message)));
+ return Texts(compile_statement(env, WrapAST(ast, Assert, .expr = and_->lhs, .message = message)),
+ compile_statement(env, WrapAST(ast, Assert, .expr = and_->rhs, .message = message)));
}
case Equals: failure = "!="; goto assert_comparison;
case NotEquals: failure = "=="; goto assert_comparison;
case LessThan: failure = ">="; goto assert_comparison;
case LessThanOrEquals: failure = ">"; goto assert_comparison;
case GreaterThan: failure = "<="; goto assert_comparison;
- case GreaterThanOrEquals: failure = "<"; goto assert_comparison; {
- assert_comparison:;
- binary_operands_t cmp = BINARY_OPERANDS(expr);
- type_t *lhs_t = get_type(env, cmp.lhs);
- type_t *rhs_t = get_type(env, cmp.rhs);
- type_t *operand_t;
- if (cmp.lhs->tag == Int && is_numeric_type(rhs_t)) {
- operand_t = rhs_t;
- } else if (cmp.rhs->tag == Int && is_numeric_type(lhs_t)) {
- operand_t = lhs_t;
- } else if (can_compile_to_type(env, cmp.rhs, lhs_t)) {
- operand_t = lhs_t;
- } else if (can_compile_to_type(env, cmp.lhs, rhs_t)) {
- operand_t = rhs_t;
- } else {
- code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
- }
-
- ast_t *lhs_var = FakeAST(InlineCCode, .chunks=new(ast_list_t, .ast=FakeAST(TextLiteral, Text("_lhs"))), .type=operand_t);
- ast_t *rhs_var = FakeAST(InlineCCode, .chunks=new(ast_list_t, .ast=FakeAST(TextLiteral, Text("_rhs"))), .type=operand_t);
- ast_t *var_comparison = new(ast_t, .file=expr->file, .start=expr->start, .end=expr->end, .tag=expr->tag,
- .__data.Equals={.lhs=lhs_var, .rhs=rhs_var});
- int64_t line = get_line_number(ast->file, ast->start);
- return Texts("{ // assertion\n",
- compile_declaration(operand_t, Text("_lhs")), " = ", compile_to_type(env, cmp.lhs, operand_t), ";\n",
- "\n#line ", String(line), "\n",
- compile_declaration(operand_t, Text("_rhs")), " = ", compile_to_type(env, cmp.rhs, operand_t), ";\n",
- "\n#line ", String(line), "\n",
- "if (!(", compile_condition(env, var_comparison), "))\n",
- "#line ", String(line), "\n",
- Texts(
- "fail_source(", quoted_str(ast->file->filename), ", ",
- String((int64_t)(expr->start - expr->file->text)), ", ",
- String((int64_t)(expr->end - expr->file->text)), ", ",
- message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
- : Text("\"This assertion failed!\""), ", ",
- "\" (\", ", expr_as_text(Text("_lhs"), operand_t, Text("no")), ", "
- "\" ", failure, " \", ", expr_as_text(Text("_rhs"), operand_t, Text("no")), ", \")\");\n"),
- "}\n");
+ case GreaterThanOrEquals:
+ failure = "<";
+ goto assert_comparison;
+ {
+ assert_comparison:;
+ binary_operands_t cmp = BINARY_OPERANDS(expr);
+ type_t *lhs_t = get_type(env, cmp.lhs);
+ type_t *rhs_t = get_type(env, cmp.rhs);
+ type_t *operand_t;
+ if (cmp.lhs->tag == Int && is_numeric_type(rhs_t)) {
+ operand_t = rhs_t;
+ } else if (cmp.rhs->tag == Int && is_numeric_type(lhs_t)) {
+ operand_t = lhs_t;
+ } else if (can_compile_to_type(env, cmp.rhs, lhs_t)) {
+ operand_t = lhs_t;
+ } else if (can_compile_to_type(env, cmp.lhs, rhs_t)) {
+ operand_t = rhs_t;
+ } else {
+ code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ }
- }
+ ast_t *lhs_var =
+ FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_lhs"))),
+ .type = operand_t);
+ ast_t *rhs_var =
+ FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_rhs"))),
+ .type = operand_t);
+ ast_t *var_comparison = new (ast_t, .file = expr->file, .start = expr->start, .end = expr->end,
+ .tag = expr->tag, .__data.Equals = {.lhs = lhs_var, .rhs = rhs_var});
+ int64_t line = get_line_number(ast->file, ast->start);
+ return Texts("{ // assertion\n", compile_declaration(operand_t, Text("_lhs")), " = ",
+ compile_to_type(env, cmp.lhs, operand_t), ";\n", "\n#line ", String(line), "\n",
+ compile_declaration(operand_t, Text("_rhs")), " = ",
+ compile_to_type(env, cmp.rhs, operand_t), ";\n", "\n#line ", String(line), "\n", "if (!(",
+ compile_condition(env, var_comparison), "))\n", "#line ", String(line), "\n",
+ Texts("fail_source(", quoted_str(ast->file->filename), ", ",
+ String((int64_t)(expr->start - expr->file->text)), ", ",
+ String((int64_t)(expr->end - expr->file->text)), ", ",
+ message
+ ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
+ : Text("\"This assertion failed!\""),
+ ", ", "\" (\", ", expr_as_text(Text("_lhs"), operand_t, Text("no")),
+ ", "
+ "\" ",
+ failure, " \", ", expr_as_text(Text("_rhs"), operand_t, Text("no")), ", \")\");\n"),
+ "}\n");
+ }
default: {
int64_t line = get_line_number(ast->file, ast->start);
- return Texts(
- "if (!(", compile_condition(env, expr), "))\n",
- "#line ", String(line), "\n",
- "fail_source(", quoted_str(ast->file->filename), ", ",
- String((int64_t)(expr->start - expr->file->text)), ", ",
- String((int64_t)(expr->end - expr->file->text)), ", ",
- message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
- : Text("\"This assertion failed!\""),
- ");\n");
+ return Texts("if (!(", compile_condition(env, expr), "))\n", "#line ", String(line), "\n", "fail_source(",
+ quoted_str(ast->file->filename), ", ", String((int64_t)(expr->start - expr->file->text)), ", ",
+ String((int64_t)(expr->end - expr->file->text)), ", ",
+ message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
+ : Text("\"This assertion failed!\""),
+ ");\n");
}
}
}
@@ -1354,10 +1339,8 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
DeclareMatch(decl, ast, Declare);
const char *name = Match(decl->var, Var)->name;
if (streq(name, "_")) { // Explicit discard
- if (decl->value)
- return Texts("(void)", compile(env, decl->value), ";");
- else
- return EMPTY_TEXT;
+ if (decl->value) return Texts("(void)", compile(env, decl->value), ";");
+ else return EMPTY_TEXT;
} else {
type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
if (t->tag == FunctionType) t = Type(ClosureType, t);
@@ -1377,7 +1360,10 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
&& value_type(get_type(env, Match(assign->targets->ast, Index)->indexed))->tag == TableType)
lhs_t = Match(lhs_t, OptionalType)->type;
if (has_stack_memory(lhs_t))
- code_err(ast, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
+ code_err(ast, "Stack references cannot be assigned to "
+ "variables because the "
+ "variable's scope may outlive the scope of the "
+ "stack memory.");
env_t *val_env = with_enum_scope(env, lhs_t);
Text_t val = compile_to_type(val_env, assign->values->ast, lhs_t);
return Texts(compile_assignment(env, assign->targets->ast, val), ";\n");
@@ -1385,13 +1371,17 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
Text_t code = Text("{ // Assignment\n");
int64_t i = 1;
- for (ast_list_t *value = assign->values, *target = assign->targets; value && target; value = value->next, target = target->next) {
+ for (ast_list_t *value = assign->values, *target = assign->targets; value && target;
+ value = value->next, target = target->next) {
type_t *lhs_t = get_type(env, target->ast);
if (target->ast->tag == Index && lhs_t->tag == OptionalType
&& value_type(get_type(env, Match(target->ast, Index)->indexed))->tag == TableType)
lhs_t = Match(lhs_t, OptionalType)->type;
if (has_stack_memory(lhs_t))
- code_err(ast, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
+ code_err(ast, "Stack references cannot be assigned to "
+ "variables because the "
+ "variable's scope may outlive the scope of the "
+ "stack memory.");
env_t *val_env = with_enum_scope(env, lhs_t);
Text_t val = compile_to_type(val_env, value->ast, lhs_t);
code = Texts(code, compile_type(lhs_t), " $", String(i), " = ", val, ";\n");
@@ -1439,11 +1429,24 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
return Texts(compile_lvalue(env, update->lhs), " %= ", compile_to_type(env, update->rhs, lhs_t), ";");
return compile_update_assignment(env, ast);
}
- case PowerUpdate: case Mod1Update: case ConcatUpdate: case LeftShiftUpdate: case UnsignedLeftShiftUpdate:
- case RightShiftUpdate: case UnsignedRightShiftUpdate: case AndUpdate: case OrUpdate: case XorUpdate: {
+ case PowerUpdate:
+ case Mod1Update:
+ case ConcatUpdate:
+ case LeftShiftUpdate:
+ case UnsignedLeftShiftUpdate:
+ case RightShiftUpdate:
+ case UnsignedRightShiftUpdate:
+ case AndUpdate:
+ case OrUpdate:
+ case XorUpdate: {
return compile_update_assignment(env, ast);
}
- case StructDef: case EnumDef: case LangDef: case Extend: case FunctionDef: case ConvertDef: {
+ case StructDef:
+ case EnumDef:
+ case LangDef:
+ case Extend:
+ case FunctionDef:
+ case ConvertDef: {
return EMPTY_TEXT;
}
case Skip: {
@@ -1460,20 +1463,16 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
++skip_label_count;
}
Text_t code = EMPTY_TEXT;
- for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred; deferred = deferred->next)
+ for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred;
+ deferred = deferred->next)
code = Texts(code, compile_statement(deferred->defer_env, deferred->block));
- if (code.length > 0)
- return Texts("{\n", code, "goto ", ctx->skip_label, ";\n}\n");
- else
- return Texts("goto ", ctx->skip_label, ";");
+ if (code.length > 0) return Texts("{\n", code, "goto ", ctx->skip_label, ";\n}\n");
+ else return Texts("goto ", ctx->skip_label, ";");
}
}
- if (env->loop_ctx)
- code_err(ast, "This is not inside any loop");
- else if (target)
- code_err(ast, "No loop target named '", target, "' was found");
- else
- return Text("continue;");
+ if (env->loop_ctx) code_err(ast, "This is not inside any loop");
+ else if (target) code_err(ast, "No loop target named '", target, "' was found");
+ else return Text("continue;");
}
case Stop: {
const char *target = Match(ast, Stop)->target;
@@ -1489,20 +1488,16 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
++stop_label_count;
}
Text_t code = EMPTY_TEXT;
- for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred; deferred = deferred->next)
+ for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred;
+ deferred = deferred->next)
code = Texts(code, compile_statement(deferred->defer_env, deferred->block));
- if (code.length > 0)
- return Texts("{\n", code, "goto ", ctx->stop_label, ";\n}\n");
- else
- return Texts("goto ", ctx->stop_label, ";");
+ if (code.length > 0) return Texts("{\n", code, "goto ", ctx->stop_label, ";\n}\n");
+ else return Texts("goto ", ctx->stop_label, ";");
}
}
- if (env->loop_ctx)
- code_err(ast, "This is not inside any loop");
- else if (target)
- code_err(ast, "No loop target named '", target, "' was found");
- else
- return Text("break;");
+ if (env->loop_ctx) code_err(ast, "This is not inside any loop");
+ else if (target) code_err(ast, "No loop target named '", target, "' was found");
+ else return Text("break;");
}
case Pass: return Text(";");
case Defer: {
@@ -1513,20 +1508,21 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
env_t *defer_env = fresh_scope(env);
Text_t code = EMPTY_TEXT;
for (int64_t i = 0; i < closed_vars.entries.length; i++) {
- struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i;
- if (entry->b->type->tag == ModuleType)
- continue;
+ struct {
+ const char *name;
+ binding_t *b;
+ } *entry = closed_vars.entries.data + closed_vars.entries.stride * i;
+ if (entry->b->type->tag == ModuleType) continue;
if (Text$starts_with(entry->b->code, Text("userdata->"), NULL)) {
Table$str_set(defer_env->locals, entry->name, entry->b);
} else {
Text_t defer_name = Texts("defer$", String(++defer_id), "$", entry->name);
defer_id += 1;
- code = Texts(
- code, compile_declaration(entry->b->type, defer_name), " = ", entry->b->code, ";\n");
+ code = Texts(code, compile_declaration(entry->b->type, defer_name), " = ", entry->b->code, ";\n");
set_binding(defer_env, entry->name, entry->b->type, defer_name);
}
}
- env->deferred = new(deferral_t, .defer_env=defer_env, .block=body, .next=env->deferred);
+ env->deferred = new (deferral_t, .defer_env = defer_env, .block = body, .next = env->deferred);
return code;
}
case Return: {
@@ -1540,7 +1536,8 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (ret) {
if (env->fn_ret->tag == VoidType || env->fn_ret->tag == AbortType)
- code_err(ast, "This function is not supposed to return any values, according to its type signature");
+ code_err(ast, "This function is not supposed to return any values, "
+ "according to its type signature");
env = with_enum_scope(env, env->fn_ret);
Text_t value = compile_to_type(env, ret, env->fn_ret);
@@ -1560,34 +1557,31 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
DeclareMatch(while_, ast, While);
env_t *scope = fresh_scope(env);
loop_ctx_t loop_ctx = (loop_ctx_t){
- .loop_name="while",
- .deferred=scope->deferred,
- .next=env->loop_ctx,
+ .loop_name = "while",
+ .deferred = scope->deferred,
+ .next = env->loop_ctx,
};
scope->loop_ctx = &loop_ctx;
Text_t body = compile_statement(scope, while_->body);
- if (loop_ctx.skip_label.length > 0)
- body = Texts(body, "\n", loop_ctx.skip_label, ": continue;");
- Text_t loop = Texts("while (", while_->condition ? compile(scope, while_->condition) : Text("yes"), ") {\n\t", body, "\n}");
- if (loop_ctx.stop_label.length > 0)
- loop = Texts(loop, "\n", loop_ctx.stop_label, ":;");
+ if (loop_ctx.skip_label.length > 0) body = Texts(body, "\n", loop_ctx.skip_label, ": continue;");
+ Text_t loop = Texts("while (", while_->condition ? compile(scope, while_->condition) : Text("yes"), ") {\n\t",
+ body, "\n}");
+ if (loop_ctx.stop_label.length > 0) loop = Texts(loop, "\n", loop_ctx.stop_label, ":;");
return loop;
}
case Repeat: {
ast_t *body = Match(ast, Repeat)->body;
env_t *scope = fresh_scope(env);
loop_ctx_t loop_ctx = (loop_ctx_t){
- .loop_name="repeat",
- .deferred=scope->deferred,
- .next=env->loop_ctx,
+ .loop_name = "repeat",
+ .deferred = scope->deferred,
+ .next = env->loop_ctx,
};
scope->loop_ctx = &loop_ctx;
Text_t body_code = compile_statement(scope, body);
- if (loop_ctx.skip_label.length > 0)
- body_code = Texts(body_code, "\n", loop_ctx.skip_label, ": continue;");
+ if (loop_ctx.skip_label.length > 0) body_code = Texts(body_code, "\n", loop_ctx.skip_label, ": continue;");
Text_t loop = Texts("for (;;) {\n\t", body_code, "\n}");
- if (loop_ctx.stop_label.length > 0)
- loop = Texts(loop, "\n", loop_ctx.stop_label, ":;");
+ if (loop_ctx.stop_label.length > 0) loop = Texts(loop, "\n", loop_ctx.stop_label, ":;");
return loop;
}
case For: {
@@ -1595,50 +1589,48 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
// If we're iterating over a comprehension, that's actually just doing
// one loop, we don't need to compile the comprehension as a list
- // comprehension. This is a common case for reducers like `(+: i*2 for i in 5)`
- // or `(and) x.is_good() for x in xs`
+ // comprehension. This is a common case for reducers like `(+: i*2 for i
+ // in 5)` or `(and) x.is_good() for x in xs`
if (for_->iter->tag == Comprehension) {
DeclareMatch(comp, for_->iter, Comprehension);
ast_t *body = for_->body;
if (for_->vars) {
- if (for_->vars->next)
- code_err(for_->vars->next->ast, "This is too many variables for iteration");
+ if (for_->vars->next) code_err(for_->vars->next->ast, "This is too many variables for iteration");
body = WrapAST(
ast, Block,
- .statements=new(ast_list_t, .ast=WrapAST(ast, Declare, .var=for_->vars->ast, .value=comp->expr),
- .next=body->tag == Block ? Match(body, Block)->statements : new(ast_list_t, .ast=body)));
+ .statements = new (
+ ast_list_t, .ast = WrapAST(ast, Declare, .var = for_->vars->ast, .value = comp->expr),
+ .next = body->tag == Block ? Match(body, Block)->statements : new (ast_list_t, .ast = body)));
}
- if (comp->filter)
- body = WrapAST(for_->body, If, .condition=comp->filter, .body=body);
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ if (comp->filter) body = WrapAST(for_->body, If, .condition = comp->filter, .body = body);
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
return compile_statement(env, loop);
}
env_t *body_scope = for_scope(env, ast);
loop_ctx_t loop_ctx = (loop_ctx_t){
- .loop_name="for",
- .loop_vars=for_->vars,
- .deferred=body_scope->deferred,
- .next=body_scope->loop_ctx,
+ .loop_name = "for",
+ .loop_vars = for_->vars,
+ .deferred = body_scope->deferred,
+ .next = body_scope->loop_ctx,
};
body_scope->loop_ctx = &loop_ctx;
// Naked means no enclosing braces:
Text_t naked_body = compile_inline_block(body_scope, for_->body);
- if (loop_ctx.skip_label.length > 0)
- naked_body = Texts(naked_body, "\n", loop_ctx.skip_label, ": continue;");
+ if (loop_ctx.skip_label.length > 0) naked_body = Texts(naked_body, "\n", loop_ctx.skip_label, ": continue;");
Text_t stop = loop_ctx.stop_label.length > 0 ? Texts("\n", loop_ctx.stop_label, ":;") : EMPTY_TEXT;
// Special case for improving performance for numeric iteration:
- if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "to") &&
- is_int_type(get_type(env, Match(for_->iter, MethodCall)->self))) {
+ if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "to")
+ && is_int_type(get_type(env, Match(for_->iter, MethodCall)->self))) {
// TODO: support other integer types
arg_ast_t *args = Match(for_->iter, MethodCall)->args;
if (!args) code_err(for_->iter, "to() needs at least one argument");
type_t *int_type = get_type(env, Match(for_->iter, MethodCall)->self);
- type_t *step_type = int_type->tag == ByteType ? Type(IntType, .bits=TYPE_IBITS8) : int_type;
+ type_t *step_type = int_type->tag == ByteType ? Type(IntType, .bits = TYPE_IBITS8) : int_type;
Text_t last = EMPTY_TEXT, step = EMPTY_TEXT, optional_step = EMPTY_TEXT;
if (!args->name || streq(args->name, "last")) {
@@ -1648,14 +1640,12 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
code_err(args->next->value, "Invalid argument name: ", args->next->name);
if (get_type(env, args->next->value)->tag == OptionalType)
optional_step = compile_to_type(env, args->next->value, Type(OptionalType, step_type));
- else
- step = compile_to_type(env, args->next->value, step_type);
+ else step = compile_to_type(env, args->next->value, step_type);
}
} else if (streq(args->name, "step")) {
if (get_type(env, args->value)->tag == OptionalType)
optional_step = compile_to_type(env, args->value, Type(OptionalType, step_type));
- else
- step = compile_to_type(env, args->value, step_type);
+ else step = compile_to_type(env, args->value, step_type);
if (args->next) {
if (args->next->name && !streq(args->next->name, "last"))
code_err(args->next->value, "Invalid argument name: ", args->next->name);
@@ -1663,52 +1653,57 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
}
}
- if (last.length == 0)
- code_err(for_->iter, "No `last` argument was given");
-
+ if (last.length == 0) code_err(for_->iter, "No `last` argument was given");
+
Text_t type_code = compile_type(int_type);
Text_t value = for_->vars ? compile(body_scope, for_->vars->ast) : Text("i");
if (int_type->tag == BigIntType) {
if (optional_step.length > 0)
- step = Texts("({ OptionalInt_t maybe_step = ", optional_step, "; maybe_step->small == 0 ? (Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)) : (Int_t)maybe_step; })");
+ step = Texts("({ OptionalInt_t maybe_step = ", optional_step,
+ "; maybe_step->small == 0 ? "
+ "(Int$compare_value(last, first) >= 0 "
+ "? I_small(1) : I_small(-1)) : (Int_t)maybe_step; "
+ "})");
else if (step.length == 0)
- step = Text("Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)");
- return Texts(
- "for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
- value, " = first, last = ", last, ", step = ", step, "; "
- "Int$compare_value(", value, ", last) != Int$compare_value(step, I_small(0)); ",
- value, " = Int$plus(", value, ", step)) {\n"
- "\t", naked_body,
- "}",
- stop);
+ step = Text("Int$compare_value(last, first) >= 0 ? "
+ "I_small(1) : I_small(-1)");
+ return Texts("for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
+ value, " = first, last = ", last, ", step = ", step,
+ "; "
+ "Int$compare_value(",
+ value, ", last) != Int$compare_value(step, I_small(0)); ", value, " = Int$plus(", value,
+ ", step)) {\n"
+ "\t",
+ naked_body, "}", stop);
} else {
if (optional_step.length > 0)
- step = Texts("({ ", compile_type(Type(OptionalType, step_type)), " maybe_step = ", optional_step, "; "
- "maybe_step.is_none ? (", type_code, ")(last >= first ? 1 : -1) : maybe_step.value; })");
- else if (step.length == 0)
- step = Texts("(", type_code, ")(last >= first ? 1 : -1)");
- return Texts(
- "for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
- value, " = first, last = ", last, ", step = ", step, "; "
- "step > 0 ? ", value, " <= last : ", value, " >= last; ",
- value, " += step) {\n"
- "\t", naked_body,
- "}",
- stop);
+ step = Texts("({ ", compile_type(Type(OptionalType, step_type)), " maybe_step = ", optional_step,
+ "; "
+ "maybe_step.is_none ? (",
+ type_code, ")(last >= first ? 1 : -1) : maybe_step.value; })");
+ else if (step.length == 0) step = Texts("(", type_code, ")(last >= first ? 1 : -1)");
+ return Texts("for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
+ value, " = first, last = ", last, ", step = ", step,
+ "; "
+ "step > 0 ? ",
+ value, " <= last : ", value, " >= last; ", value,
+ " += step) {\n"
+ "\t",
+ naked_body, "}", stop);
}
- } else if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "onward") &&
- get_type(env, Match(for_->iter, MethodCall)->self)->tag == BigIntType) {
+ } else if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "onward")
+ && get_type(env, Match(for_->iter, MethodCall)->self)->tag == BigIntType) {
// Special case for Int.onward()
arg_ast_t *args = Match(for_->iter, MethodCall)->args;
- arg_t *arg_spec = new(arg_t, .name="step", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1"), .next=NULL);
+ arg_t *arg_spec =
+ new (arg_t, .name = "step", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "1"), .next = NULL);
Text_t step = compile_arguments(env, for_->iter, arg_spec, args);
Text_t value = for_->vars ? compile(body_scope, for_->vars->ast) : Text("i");
- return Texts(
- "for (Int_t ", value, " = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
- "step = ", step, "; ; ", value, " = Int$plus(", value, ", step)) {\n"
- "\t", naked_body,
- "}",
- stop);
+ return Texts("for (Int_t ", value, " = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
+ "step = ", step, "; ; ", value, " = Int$plus(", value,
+ ", step)) {\n"
+ "\t",
+ naked_body, "}", stop);
}
type_t *iter_t = get_type(env, for_->iter);
@@ -1734,14 +1729,11 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
Text_t loop = EMPTY_TEXT;
loop = Texts(loop, "for (int64_t i = 1; i <= iterating.length; ++i)");
- if (index.length > 0)
- naked_body = Texts("Int_t ", index, " = I(i);\n", naked_body);
+ if (index.length > 0) naked_body = Texts("Int_t ", index, " = I(i);\n", naked_body);
if (value.length > 0) {
- loop = Texts(loop, "{\n",
- compile_declaration(item_t, value),
- " = *(", compile_type(item_t), "*)(iterating.data + (i-1)*iterating.stride);\n",
- naked_body, "\n}");
+ loop = Texts(loop, "{\n", compile_declaration(item_t, value), " = *(", compile_type(item_t),
+ "*)(iterating.data + (i-1)*iterating.stride);\n", naked_body, "\n}");
} else {
loop = Texts(loop, "{\n", naked_body, "\n}");
}
@@ -1751,38 +1743,37 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (iter_t->tag == PointerType) {
loop = Texts("{\n"
- "List_t *ptr = ", compile_to_pointer_depth(env, for_->iter, 1, false), ";\n"
- "\nLIST_INCREF(*ptr);\n"
- "List_t iterating = *ptr;\n",
- loop,
- stop,
- "\nLIST_DECREF(*ptr);\n"
- "}\n");
+ "List_t *ptr = ",
+ compile_to_pointer_depth(env, for_->iter, 1, false),
+ ";\n"
+ "\nLIST_INCREF(*ptr);\n"
+ "List_t iterating = *ptr;\n",
+ loop, stop,
+ "\nLIST_DECREF(*ptr);\n"
+ "}\n");
} else {
loop = Texts("{\n"
- "List_t iterating = ", compile_to_pointer_depth(env, for_->iter, 0, false), ";\n",
- loop,
- stop,
- "}\n");
+ "List_t iterating = ",
+ compile_to_pointer_depth(env, for_->iter, 0, false), ";\n", loop, stop, "}\n");
}
return loop;
}
- case SetType: case TableType: {
+ case SetType:
+ case TableType: {
Text_t loop = Text("for (int64_t i = 0; i < iterating.length; ++i) {\n");
if (for_->vars) {
if (iter_value_t->tag == SetType) {
- if (for_->vars->next)
- code_err(for_->vars->next->ast, "This is too many variables for this loop");
+ if (for_->vars->next) code_err(for_->vars->next->ast, "This is too many variables for this loop");
Text_t item = compile(body_scope, for_->vars->ast);
type_t *item_type = Match(iter_value_t, SetType)->item_type;
loop = Texts(loop, compile_declaration(item_type, item), " = *(", compile_type(item_type), "*)(",
- "iterating.data + i*iterating.stride);\n");
+ "iterating.data + i*iterating.stride);\n");
} else {
Text_t key = compile(body_scope, for_->vars->ast);
type_t *key_t = Match(iter_value_t, TableType)->key_type;
loop = Texts(loop, compile_declaration(key_t, key), " = *(", compile_type(key_t), "*)(",
- "iterating.data + i*iterating.stride);\n");
+ "iterating.data + i*iterating.stride);\n");
if (for_->vars->next) {
if (for_->vars->next->next)
@@ -1790,9 +1781,10 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
type_t *value_t = Match(iter_value_t, TableType)->value_type;
Text_t value = compile(body_scope, for_->vars->next->ast);
- Text_t value_offset = Texts("offsetof(struct { ", compile_declaration(key_t, Text("k")), "; ", compile_declaration(value_t, Text("v")), "; }, v)");
+ Text_t value_offset = Texts("offsetof(struct { ", compile_declaration(key_t, Text("k")), "; ",
+ compile_declaration(value_t, Text("v")), "; }, v)");
loop = Texts(loop, compile_declaration(value_t, value), " = *(", compile_type(value_t), "*)(",
- "iterating.data + i*iterating.stride + ", value_offset, ");\n");
+ "iterating.data + i*iterating.stride + ", value_offset, ");\n");
}
}
}
@@ -1804,20 +1796,16 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
}
if (iter_t->tag == PointerType) {
- loop = Texts(
- "{\n",
- "Table_t *t = ", compile_to_pointer_depth(env, for_->iter, 1, false), ";\n"
- "LIST_INCREF(t->entries);\n"
- "List_t iterating = t->entries;\n",
- loop,
- "LIST_DECREF(t->entries);\n"
- "}\n");
+ loop = Texts("{\n", "Table_t *t = ", compile_to_pointer_depth(env, for_->iter, 1, false),
+ ";\n"
+ "LIST_INCREF(t->entries);\n"
+ "List_t iterating = t->entries;\n",
+ loop,
+ "LIST_DECREF(t->entries);\n"
+ "}\n");
} else {
- loop = Texts(
- "{\n",
- "List_t iterating = (", compile_to_pointer_depth(env, for_->iter, 0, false), ").entries;\n",
- loop,
- "}\n");
+ loop = Texts("{\n", "List_t iterating = (", compile_to_pointer_depth(env, for_->iter, 0, false),
+ ").entries;\n", loop, "}\n");
}
return loop;
}
@@ -1826,52 +1814,50 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (for_->iter->tag == Int) {
const char *str = Match(for_->iter, Int)->str;
Int_t int_val = Int$from_str(str);
- if (int_val.small == 0)
- code_err(for_->iter, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(for_->iter, "Failed to parse this integer");
mpz_t i;
mpz_init_set_int(i, int_val);
- if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0)
- n = Text$from_str(mpz_get_str(NULL, 10, i));
- else
- goto big_n;
-
+ if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) n = Text$from_str(mpz_get_str(NULL, 10, i));
+ else goto big_n;
if (for_->empty && mpz_cmp_si(i, 0) <= 0) {
return compile_statement(env, for_->empty);
} else {
- return Texts(
- "for (int64_t i = 1; i <= ", n, "; ++i) {\n",
- for_->vars ? Texts("\tInt_t ", compile(body_scope, for_->vars->ast), " = I_small(i);\n") : EMPTY_TEXT,
- "\t", naked_body,
- "}\n",
- stop, "\n");
+ return Texts("for (int64_t i = 1; i <= ", n, "; ++i) {\n",
+ for_->vars
+ ? Texts("\tInt_t ", compile(body_scope, for_->vars->ast), " = I_small(i);\n")
+ : EMPTY_TEXT,
+ "\t", naked_body, "}\n", stop, "\n");
}
}
- big_n:
+ big_n:
n = compile_to_pointer_depth(env, for_->iter, 0, false);
Text_t i = for_->vars ? compile(body_scope, for_->vars->ast) : Text("i");
Text_t n_var = for_->vars ? Texts("max", i) : Text("n");
if (for_->empty) {
- return Texts(
- "{\n"
- "Int_t ", n_var, " = ", n, ";\n"
- "if (Int$compare_value(", n_var, ", I(0)) > 0) {\n"
- "for (Int_t ", i, " = I(1); Int$compare_value(", i, ", ", n_var, ") <= 0; ", i, " = Int$plus(", i, ", I(1))) {\n",
- "\t", naked_body,
- "}\n"
- "} else ", compile_statement(env, for_->empty),
- stop, "\n"
- "}\n");
+ return Texts("{\n"
+ "Int_t ",
+ n_var, " = ", n,
+ ";\n"
+ "if (Int$compare_value(",
+ n_var,
+ ", I(0)) > 0) {\n"
+ "for (Int_t ",
+ i, " = I(1); Int$compare_value(", i, ", ", n_var, ") <= 0; ", i, " = Int$plus(", i,
+ ", I(1))) {\n", "\t", naked_body,
+ "}\n"
+ "} else ",
+ compile_statement(env, for_->empty), stop,
+ "\n"
+ "}\n");
} else {
- return Texts(
- "for (Int_t ", i, " = I(1), ", n_var, " = ", n, "; Int$compare_value(", i, ", ", n_var, ") <= 0; ", i, " = Int$plus(", i, ", I(1))) {\n",
- "\t", naked_body,
- "}\n",
- stop, "\n");
+ return Texts("for (Int_t ", i, " = I(1), ", n_var, " = ", n, "; Int$compare_value(", i, ", ", n_var,
+ ") <= 0; ", i, " = Int$plus(", i, ", I(1))) {\n", "\t", naked_body, "}\n", stop, "\n");
}
}
- case FunctionType: case ClosureType: {
+ case FunctionType:
+ case ClosureType: {
// Iterator function:
Text_t code = Text("{\n");
@@ -1879,53 +1865,63 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (is_idempotent(for_->iter)) {
next_fn = compile_to_pointer_depth(env, for_->iter, 0, false);
} else {
- code = Texts(code, compile_declaration(iter_value_t, Text("next")), " = ", compile_to_pointer_depth(env, for_->iter, 0, false), ";\n");
+ code = Texts(code, compile_declaration(iter_value_t, Text("next")), " = ",
+ compile_to_pointer_depth(env, for_->iter, 0, false), ";\n");
next_fn = Text("next");
}
- __typeof(iter_value_t->__data.FunctionType) *fn = iter_value_t->tag == ClosureType ? Match(Match(iter_value_t, ClosureType)->fn, FunctionType) : Match(iter_value_t, FunctionType);
+ __typeof(iter_value_t->__data.FunctionType) *fn =
+ iter_value_t->tag == ClosureType ? Match(Match(iter_value_t, ClosureType)->fn, FunctionType)
+ : Match(iter_value_t, FunctionType);
Text_t get_next;
if (iter_value_t->tag == ClosureType) {
type_t *fn_t = Match(iter_value_t, ClosureType)->fn;
arg_t *closure_fn_args = NULL;
for (arg_t *arg = Match(fn_t, FunctionType)->args; arg; arg = arg->next)
- closure_fn_args = new(arg_t, .name=arg->name, .type=arg->type, .default_val=arg->default_val, .next=closure_fn_args);
- closure_fn_args = new(arg_t, .name="userdata", .type=Type(PointerType, .pointed=Type(MemoryType)), .next=closure_fn_args);
+ closure_fn_args = new (arg_t, .name = arg->name, .type = arg->type, .default_val = arg->default_val,
+ .next = closure_fn_args);
+ closure_fn_args = new (arg_t, .name = "userdata",
+ .type = Type(PointerType, .pointed = Type(MemoryType)), .next = closure_fn_args);
REVERSE_LIST(closure_fn_args);
- Text_t fn_type_code = compile_type(Type(FunctionType, .args=closure_fn_args, .ret=Match(fn_t, FunctionType)->ret));
+ Text_t fn_type_code =
+ compile_type(Type(FunctionType, .args = closure_fn_args, .ret = Match(fn_t, FunctionType)->ret));
get_next = Texts("((", fn_type_code, ")", next_fn, ".fn)(", next_fn, ".userdata)");
} else {
get_next = Texts(next_fn, "()");
}
if (fn->ret->tag == OptionalType) {
- // Use an optional variable `cur` for each iteration step, which will be checked for none
+ // Use an optional variable `cur` for each iteration step, which
+ // will be checked for none
code = Texts(code, compile_declaration(fn->ret, Text("cur")), ";\n");
get_next = Texts("(cur=", get_next, ", !", check_none(fn->ret, Text("cur")), ")");
if (for_->vars) {
- naked_body = Texts(
- compile_declaration(Match(fn->ret, OptionalType)->type, Texts("_$", Match(for_->vars->ast, Var)->name)),
- " = ", optional_into_nonnone(fn->ret, Text("cur")), ";\n",
- naked_body);
+ naked_body = Texts(compile_declaration(Match(fn->ret, OptionalType)->type,
+ Texts("_$", Match(for_->vars->ast, Var)->name)),
+ " = ", optional_into_nonnone(fn->ret, Text("cur")), ";\n", naked_body);
}
if (for_->empty) {
- code = Texts(code, "if (", get_next, ") {\n"
- "\tdo{\n\t\t", naked_body, "\t} while(", get_next, ");\n"
- "} else {\n\t", compile_statement(env, for_->empty), "}", stop, "\n}\n");
+ code = Texts(code, "if (", get_next,
+ ") {\n"
+ "\tdo{\n\t\t",
+ naked_body, "\t} while(", get_next,
+ ");\n"
+ "} else {\n\t",
+ compile_statement(env, for_->empty), "}", stop, "\n}\n");
} else {
code = Texts(code, "while(", get_next, ") {\n\t", naked_body, "}\n", stop, "\n}\n");
}
} else {
if (for_->vars) {
- naked_body = Texts(
- compile_declaration(fn->ret, Texts("_$", Match(for_->vars->ast, Var)->name)),
- " = ", get_next, ";\n", naked_body);
+ naked_body = Texts(compile_declaration(fn->ret, Texts("_$", Match(for_->vars->ast, Var)->name)),
+ " = ", get_next, ";\n", naked_body);
} else {
naked_body = Texts(get_next, ";\n", naked_body);
}
if (for_->empty)
- code_err(for_->empty, "This iteration loop will always have values, so this block will never run");
+ code_err(for_->empty, "This iteration loop will always have values, "
+ "so this block will never run");
code = Texts(code, "for (;;) {\n\t", naked_body, "}\n", stop, "\n}\n");
}
@@ -1938,8 +1934,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
DeclareMatch(if_, ast, If);
ast_t *condition = if_->condition;
if (condition->tag == Declare) {
- if (Match(condition, Declare)->value == NULL)
- code_err(condition, "This declaration must have a value");
+ if (Match(condition, Declare)->value == NULL) code_err(condition, "This declaration must have a value");
env_t *truthy_scope = fresh_scope(env);
Text_t code = Texts("IF_DECLARE(", compile_statement(truthy_scope, condition), ", ");
bind_statement(truthy_scope, condition);
@@ -1947,13 +1942,11 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
code = Texts(code, compile_condition(truthy_scope, var), ", ");
type_t *cond_t = get_type(truthy_scope, var);
if (cond_t->tag == OptionalType) {
- set_binding(truthy_scope, Match(var, Var)->name,
- Match(cond_t, OptionalType)->type,
+ set_binding(truthy_scope, Match(var, Var)->name, Match(cond_t, OptionalType)->type,
optional_into_nonnone(cond_t, compile(truthy_scope, var)));
}
code = Texts(code, compile_statement(truthy_scope, if_->body), ")");
- if (if_->else_body)
- code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
+ if (if_->else_body) code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
return code;
} else {
Text_t code = Texts("if (", compile_condition(env, condition), ")");
@@ -1961,13 +1954,11 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
type_t *cond_t = get_type(env, condition);
if (condition->tag == Var && cond_t->tag == OptionalType) {
truthy_scope = fresh_scope(env);
- set_binding(truthy_scope, Match(condition, Var)->name,
- Match(cond_t, OptionalType)->type,
+ set_binding(truthy_scope, Match(condition, Var)->name, Match(cond_t, OptionalType)->type,
optional_into_nonnone(cond_t, compile(truthy_scope, condition)));
}
code = Texts(code, compile_statement(truthy_scope, if_->body));
- if (if_->else_body)
- code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
+ if (if_->else_body) code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
return code;
}
}
@@ -1975,21 +1966,19 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
return Texts("{\n", compile_inline_block(env, ast), "}\n");
}
case Comprehension: {
- if (!env->comprehension_action)
- code_err(ast, "I don't know what to do with this comprehension!");
+ if (!env->comprehension_action) code_err(ast, "I don't know what to do with this comprehension!");
DeclareMatch(comp, ast, Comprehension);
if (comp->expr->tag == Comprehension) { // Nested comprehension
- ast_t *body = comp->filter ? WrapAST(ast, If, .condition=comp->filter, .body=comp->expr) : comp->expr;
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ ast_t *body = comp->filter ? WrapAST(ast, If, .condition = comp->filter, .body = comp->expr) : comp->expr;
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
return compile_statement(env, loop);
}
// List/Set/Table comprehension:
- comprehension_body_t get_body = (void*)env->comprehension_action->fn;
+ comprehension_body_t get_body = (void *)env->comprehension_action->fn;
ast_t *body = get_body(comp->expr, env->comprehension_action->userdata);
- if (comp->filter)
- body = WrapAST(comp->expr, If, .condition=comp->filter, .body=body);
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ if (comp->filter) body = WrapAST(comp->expr, If, .condition = comp->filter, .body = body);
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
return compile_statement(env, loop);
}
case Extern: return EMPTY_TEXT;
@@ -2017,9 +2006,10 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
module_info_t mod = get_module_info(ast);
glob_t tm_files;
const char *folder = mod.version ? String(mod.name, "_", mod.version) : mod.name;
- if (glob(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0) {
- if (!try_install_module(mod))
- code_err(ast, "Could not find library");
+ if (glob(String(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE,
+ NULL, &tm_files)
+ != 0) {
+ if (!try_install_module(mod)) code_err(ast, "Could not find library");
}
Text_t initialization = EMPTY_TEXT;
@@ -2027,8 +2017,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
for (size_t i = 0; i < tm_files.gl_pathc; i++) {
const char *filename = tm_files.gl_pathv[i];
initialization = Texts(
- initialization,
- with_source_info(env, ast, Texts("$initialize", get_id_suffix(filename), "();\n")));
+ initialization, with_source_info(env, ast, Texts("$initialize", get_id_suffix(filename), "();\n")));
}
globfree(&tm_files);
return initialization;
@@ -2037,7 +2026,8 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
}
}
default:
- // print("Is discardable: ", ast_to_sexp_str(ast), " ==> ", is_discardable(env, ast));
+ // print("Is discardable: ", ast_to_sexp_str(ast), " ==> ",
+ // is_discardable(env, ast));
if (!is_discardable(env, ast))
code_err(ast, "The ", type_to_str(get_type(env, ast)), " result of this statement cannot be discarded");
return Texts("(void)", compile(env, ast), ";");
@@ -2049,15 +2039,18 @@ Text_t compile_statement(env_t *env, ast_t *ast) {
return with_source_info(env, ast, stmt);
}
-Text_t expr_as_text(Text_t expr, type_t *t, Text_t color)
-{
+Text_t expr_as_text(Text_t expr, type_t *t, Text_t color) {
switch (t->tag) {
case MemoryType: return Texts("Memory$as_text(stack(", expr, "), ", color, ", &Memory$info)");
case BoolType:
- // NOTE: this cannot use stack(), since bools may actually be bit fields:
- return Texts("Bool$as_text((Bool_t[1]){", expr, "}, ", color, ", &Bool$info)");
+ // NOTE: this cannot use stack(), since bools may actually be bit
+ // fields:
+ return Texts("Bool$as_text((Bool_t[1]){", expr, "}, ", color, ", &Bool$info)");
case CStringType: return Texts("CString$as_text(stack(", expr, "), ", color, ", &CString$info)");
- case BigIntType: case IntType: case ByteType: case NumType: {
+ case BigIntType:
+ case IntType:
+ case ByteType:
+ case NumType: {
Text_t name = type_to_text(t);
return Texts(name, "$as_text(stack(", expr, "), ", color, ", &", name, "$info)");
}
@@ -2065,25 +2058,24 @@ Text_t expr_as_text(Text_t expr, type_t *t, Text_t color)
case ListType: return Texts("List$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
case SetType: return Texts("Table$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
case TableType: return Texts("Table$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
- case FunctionType: case ClosureType: return Texts("Func$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
+ case FunctionType:
+ case ClosureType: return Texts("Func$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
case PointerType: return Texts("Pointer$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
case OptionalType: return Texts("Optional$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
- case StructType: case EnumType:
- return Texts("generic_as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
+ case StructType:
+ case EnumType: return Texts("generic_as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for ", type_to_str(t));
}
return EMPTY_TEXT;
}
-Text_t compile_text(env_t *env, ast_t *ast, Text_t color)
-{
+Text_t compile_text(env_t *env, ast_t *ast, Text_t color) {
type_t *t = get_type(env, ast);
Text_t expr = compile(env, ast);
return expr_as_text(expr, t, color);
}
-Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref)
-{
+Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) {
Text_t val = compile(env, ast);
type_t *t = get_type(env, ast);
int64_t depth = 0;
@@ -2092,16 +2084,13 @@ Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bo
// Passing a literal value won't trigger an incref, because it's ephemeral,
// e.g. [10, 20].reversed()
- if (t->tag != PointerType && needs_incref && !can_be_mutated(env, ast))
- needs_incref = false;
+ if (t->tag != PointerType && needs_incref && !can_be_mutated(env, ast)) needs_incref = false;
while (depth != target_depth) {
if (depth < target_depth) {
- if (ast->tag == Var && target_depth == 1)
- val = Texts("(&", val, ")");
- else
- code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast)));
- t = Type(PointerType, .pointed=t, .is_stack=true);
+ if (ast->tag == Var && target_depth == 1) val = Texts("(&", val, ")");
+ else code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast)));
+ t = Type(PointerType, .pointed = t, .is_stack = true);
++depth;
} else {
DeclareMatch(ptr, t, PointerType);
@@ -2116,16 +2105,13 @@ Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bo
t = ptr->pointed;
}
- if (needs_incref && t->tag == ListType)
- val = Texts("LIST_COPY(", val, ")");
- else if (needs_incref && (t->tag == TableType || t->tag == SetType))
- val = Texts("TABLE_COPY(", val, ")");
+ if (needs_incref && t->tag == ListType) val = Texts("LIST_COPY(", val, ")");
+ else if (needs_incref && (t->tag == TableType || t->tag == SetType)) val = Texts("TABLE_COPY(", val, ")");
return val;
}
-Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
-{
+Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t) {
assert(!is_incomplete_type(t));
if (ast->tag == Int && is_numeric_type(non_optional(t))) {
return compile_int_to_type(env, ast, t);
@@ -2137,10 +2123,11 @@ Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
default: code_err(ast, "This is not a valid number bit width");
}
} else if (ast->tag == None) {
- if (t->tag != OptionalType)
- code_err(ast, "This is not supposed to be an optional type");
+ if (t->tag != OptionalType) code_err(ast, "This is not supposed to be an optional type");
else if (Match(t, OptionalType)->type == NULL)
- code_err(ast, "I don't know what kind of `none` this is supposed to be!\nPlease tell me by declaring a variable like `foo : Type = none`");
+ code_err(ast, "I don't know what kind of `none` this is supposed to "
+ "be!\nPlease "
+ "tell me by declaring a variable like `foo : Type = none`");
return compile_none(t);
} else if (t->tag == PointerType && (ast->tag == HeapAllocate || ast->tag == StackReference)) {
return compile_typed_allocation(env, ast, t);
@@ -2166,15 +2153,17 @@ Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
if (ast->tag == MethodCall) {
DeclareMatch(methodcall, ast, MethodCall);
type_t *self_type = get_type(env, methodcall->self);
- // Currently, this is only implemented for cases where you have the return type
- // and the self type equal to each other, because that's the main case I care
- // about with list and set methods (e.g. `List.sorted()`)
+ // Currently, this is only implemented for cases where you have the
+ // return type and the self type equal to each other, because that's the
+ // main case I care about with list and set methods (e.g.
+ // `List.sorted()`)
if (is_incomplete_type(self_type) && type_eq(self_type, actual)) {
type_t *completed_self = most_complete_type(self_type, t);
if (completed_self) {
- ast_t *explicit_self = WrapAST(methodcall->self, ExplicitlyTyped, .ast=methodcall->self, .type=completed_self);
- ast_t *new_methodcall = WrapAST(ast, MethodCall, .self=explicit_self,
- .name=methodcall->name, .args=methodcall->args);
+ ast_t *explicit_self =
+ WrapAST(methodcall->self, ExplicitlyTyped, .ast = methodcall->self, .type = completed_self);
+ ast_t *new_methodcall =
+ WrapAST(ast, MethodCall, .self = explicit_self, .name = methodcall->name, .args = methodcall->args);
return compile_to_type(env, new_methodcall, t);
}
}
@@ -2186,11 +2175,10 @@ Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
if (!is_incomplete_type(actual)) {
Text_t code = compile(env, ast);
- if (promote(env, ast, &code, actual, t))
- return code;
+ if (promote(env, ast, &code, actual, t)) return code;
}
- arg_ast_t *constructor_args = new(arg_ast_t, .value=ast);
+ arg_ast_t *constructor_args = new (arg_ast_t, .value = ast);
binding_t *constructor = get_constructor(env, t, constructor_args, true);
if (constructor) {
arg_t *arg_spec = Match(constructor->type, FunctionType)->args;
@@ -2200,25 +2188,21 @@ Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
code_err(ast, "I expected a ", type_to_str(t), " here, but this is a ", type_to_str(actual));
}
-Text_t compile_typed_list(env_t *env, ast_t *ast, type_t *list_type)
-{
+Text_t compile_typed_list(env_t *env, ast_t *ast, type_t *list_type) {
DeclareMatch(list, ast, List);
- if (!list->items)
- return Text("(List_t){.length=0}");
+ if (!list->items) return Text("(List_t){.length=0}");
type_t *item_type = Match(list_type, ListType)->item_type;
int64_t n = 0;
for (ast_list_t *item = list->items; item; item = item->next) {
++n;
- if (item->ast->tag == Comprehension)
- goto list_comprehension;
+ if (item->ast->tag == Comprehension) goto list_comprehension;
}
{
env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : env;
- if (is_incomplete_type(item_type))
- code_err(ast, "This list's type can't be inferred!");
+ if (is_incomplete_type(item_type)) code_err(ast, "This list's type can't be inferred!");
Text_t code = Texts("TypedListN(", compile_type(item_type), ", ", String(n));
for (ast_list_t *item = list->items; item; item = item->next) {
code = Texts(code, ", ", compile_to_type(scope, item->ast, item_type));
@@ -2226,48 +2210,39 @@ Text_t compile_typed_list(env_t *env, ast_t *ast, type_t *list_type)
return Texts(code, ")");
}
- list_comprehension:
- {
- env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env);
- static int64_t comp_num = 1;
- const char *comprehension_name = String("list$", comp_num++);
- ast_t *comprehension_var = LiteralCode(Texts("&", comprehension_name),
- .type=Type(PointerType, .pointed=list_type, .is_stack=true));
- Closure_t comp_action = {.fn=add_to_list_comprehension, .userdata=comprehension_var};
- scope->comprehension_action = &comp_action;
- Text_t code = Texts("({ List_t ", comprehension_name, " = {};");
- // set_binding(scope, comprehension_name, list_type, comprehension_name);
- for (ast_list_t *item = list->items; item; item = item->next) {
- if (item->ast->tag == Comprehension)
- code = Texts(code, "\n", compile_statement(scope, item->ast));
- else
- code = Texts(code, compile_statement(env, add_to_list_comprehension(item->ast, comprehension_var)));
- }
- code = Texts(code, " ", comprehension_name, "; })");
- return code;
+list_comprehension: {
+ env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env);
+ static int64_t comp_num = 1;
+ const char *comprehension_name = String("list$", comp_num++);
+ ast_t *comprehension_var =
+ LiteralCode(Texts("&", comprehension_name), .type = Type(PointerType, .pointed = list_type, .is_stack = true));
+ Closure_t comp_action = {.fn = add_to_list_comprehension, .userdata = comprehension_var};
+ scope->comprehension_action = &comp_action;
+ Text_t code = Texts("({ List_t ", comprehension_name, " = {};");
+ // set_binding(scope, comprehension_name, list_type, comprehension_name);
+ for (ast_list_t *item = list->items; item; item = item->next) {
+ if (item->ast->tag == Comprehension) code = Texts(code, "\n", compile_statement(scope, item->ast));
+ else code = Texts(code, compile_statement(env, add_to_list_comprehension(item->ast, comprehension_var)));
}
+ code = Texts(code, " ", comprehension_name, "; })");
+ return code;
+}
}
-Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type)
-{
+Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type) {
DeclareMatch(set, ast, Set);
- if (!set->items)
- return Text("((Table_t){})");
+ if (!set->items) return Text("((Table_t){})");
type_t *item_type = Match(set_type, SetType)->item_type;
int64_t n = 0;
for (ast_list_t *item = set->items; item; item = item->next) {
++n;
- if (item->ast->tag == Comprehension)
- goto set_comprehension;
+ if (item->ast->tag == Comprehension) goto set_comprehension;
}
-
+
{ // No comprehension:
- Text_t code = Texts("Set(",
- compile_type(item_type), ", ",
- compile_type_info(item_type), ", ",
- String(n));
+ Text_t code = Texts("Set(", compile_type(item_type), ", ", compile_type_info(item_type), ", ", String(n));
env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : env;
for (ast_list_t *item = set->items; item; item = item->next) {
code = Texts(code, ", ", compile_to_type(scope, item->ast, item_type));
@@ -2275,34 +2250,29 @@ Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type)
return Texts(code, ")");
}
- set_comprehension:
- {
- static int64_t comp_num = 1;
- env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env);
- const char *comprehension_name = String("set$", comp_num++);
- ast_t *comprehension_var = LiteralCode(Texts("&", comprehension_name),
- .type=Type(PointerType, .pointed=set_type, .is_stack=true));
- Text_t code = Texts("({ Table_t ", comprehension_name, " = {};");
- Closure_t comp_action = {.fn=add_to_set_comprehension, .userdata=comprehension_var};
- scope->comprehension_action = &comp_action;
- for (ast_list_t *item = set->items; item; item = item->next) {
- if (item->ast->tag == Comprehension)
- code = Texts(code, "\n", compile_statement(scope, item->ast));
- else
- code = Texts(code, compile_statement(env, add_to_set_comprehension(item->ast, comprehension_var)));
- }
- code = Texts(code, " ", comprehension_name, "; })");
- return code;
+set_comprehension: {
+ static int64_t comp_num = 1;
+ env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env);
+ const char *comprehension_name = String("set$", comp_num++);
+ ast_t *comprehension_var =
+ LiteralCode(Texts("&", comprehension_name), .type = Type(PointerType, .pointed = set_type, .is_stack = true));
+ Text_t code = Texts("({ Table_t ", comprehension_name, " = {};");
+ Closure_t comp_action = {.fn = add_to_set_comprehension, .userdata = comprehension_var};
+ scope->comprehension_action = &comp_action;
+ for (ast_list_t *item = set->items; item; item = item->next) {
+ if (item->ast->tag == Comprehension) code = Texts(code, "\n", compile_statement(scope, item->ast));
+ else code = Texts(code, compile_statement(env, add_to_set_comprehension(item->ast, comprehension_var)));
}
+ code = Texts(code, " ", comprehension_name, "; })");
+ return code;
+}
}
-Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type)
-{
+Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) {
DeclareMatch(table, ast, Table);
if (!table->entries) {
Text_t code = Text("((Table_t){");
- if (table->fallback)
- code = Texts(code, ".fallback=heap(", compile(env, table->fallback),")");
+ if (table->fallback) code = Texts(code, ".fallback=heap(", compile(env, table->fallback), ")");
return Texts(code, "})");
}
@@ -2313,22 +2283,16 @@ Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type)
code_err(ast, "Tables whose values are optional (", type_to_str(value_t), ") are not currently supported.");
for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
- if (entry->ast->tag == Comprehension)
- goto table_comprehension;
+ if (entry->ast->tag == Comprehension) goto table_comprehension;
}
{ // No comprehension:
env_t *key_scope = key_t->tag == EnumType ? with_enum_scope(env, key_t) : env;
env_t *value_scope = value_t->tag == EnumType ? with_enum_scope(env, value_t) : env;
- Text_t code = Texts("Table(",
- compile_type(key_t), ", ",
- compile_type(value_t), ", ",
- compile_type_info(key_t), ", ",
- compile_type_info(value_t));
- if (table->fallback)
- code = Texts(code, ", /*fallback:*/ heap(", compile(env, table->fallback), ")");
- else
- code = Texts(code, ", /*fallback:*/ NULL");
+ Text_t code = Texts("Table(", compile_type(key_t), ", ", compile_type(value_t), ", ", compile_type_info(key_t),
+ ", ", compile_type_info(value_t));
+ if (table->fallback) code = Texts(code, ", /*fallback:*/ heap(", compile(env, table->fallback), ")");
+ else code = Texts(code, ", /*fallback:*/ NULL");
size_t n = 0;
for (ast_list_t *entry = table->entries; entry; entry = entry->next)
@@ -2338,40 +2302,35 @@ Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type)
for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
DeclareMatch(e, entry->ast, TableEntry);
code = Texts(code, ",\n\t{", compile_to_type(key_scope, e->key, key_t), ", ",
- compile_to_type(value_scope, e->value, value_t), "}");
+ compile_to_type(value_scope, e->value, value_t), "}");
}
return Texts(code, ")");
}
- table_comprehension:
- {
- static int64_t comp_num = 1;
- env_t *scope = fresh_scope(env);
- const char *comprehension_name = String("table$", comp_num++);
- ast_t *comprehension_var = LiteralCode(Texts("&", comprehension_name),
- .type=Type(PointerType, .pointed=table_type, .is_stack=true));
+table_comprehension: {
+ static int64_t comp_num = 1;
+ env_t *scope = fresh_scope(env);
+ const char *comprehension_name = String("table$", comp_num++);
+ ast_t *comprehension_var =
+ LiteralCode(Texts("&", comprehension_name), .type = Type(PointerType, .pointed = table_type, .is_stack = true));
- Text_t code = Texts("({ Table_t ", comprehension_name, " = {");
- if (table->fallback)
- code = Texts(code, ".fallback=heap(", compile(env, table->fallback), "), ");
+ Text_t code = Texts("({ Table_t ", comprehension_name, " = {");
+ if (table->fallback) code = Texts(code, ".fallback=heap(", compile(env, table->fallback), "), ");
- code = Texts(code, "};");
+ code = Texts(code, "};");
- Closure_t comp_action = {.fn=add_to_table_comprehension, .userdata=comprehension_var};
- scope->comprehension_action = &comp_action;
- for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
- if (entry->ast->tag == Comprehension)
- code = Texts(code, "\n", compile_statement(scope, entry->ast));
- else
- code = Texts(code, compile_statement(env, add_to_table_comprehension(entry->ast, comprehension_var)));
- }
- code = Texts(code, " ", comprehension_name, "; })");
- return code;
+ Closure_t comp_action = {.fn = add_to_table_comprehension, .userdata = comprehension_var};
+ scope->comprehension_action = &comp_action;
+ for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
+ if (entry->ast->tag == Comprehension) code = Texts(code, "\n", compile_statement(scope, entry->ast));
+ else code = Texts(code, compile_statement(env, add_to_table_comprehension(entry->ast, comprehension_var)));
}
+ code = Texts(code, " ", comprehension_name, "; })");
+ return code;
+}
}
-Text_t compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type)
-{
+Text_t compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type) {
// TODO: for constructors, do new(T, ...) instead of heap((T){...})
type_t *pointed = Match(pointer_type, PointerType)->pointed;
switch (ast->tag) {
@@ -2382,16 +2341,14 @@ Text_t compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type)
ast_t *subject = Match(ast, StackReference)->value;
if (can_be_mutated(env, subject) && type_eq(pointed, get_type(env, subject)))
return Texts("(&", compile_lvalue(env, subject), ")");
- else
- return Texts("stack(", compile_to_type(env, subject, pointed), ")");
+ else return Texts("stack(", compile_to_type(env, subject, pointed), ")");
}
default: code_err(ast, "Not an allocation!");
}
return EMPTY_TEXT;
}
-Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
-{
+Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) {
if (ast->tag != Int) {
Text_t code = compile(env, ast);
type_t *actual_type = get_type(env, ast);
@@ -2400,16 +2357,14 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
return code;
}
- if (target->tag == BigIntType)
- return compile(env, ast);
+ if (target->tag == BigIntType) return compile(env, ast);
if (target->tag == OptionalType && Match(target, OptionalType)->type)
return compile_int_to_type(env, ast, Match(target, OptionalType)->type);
const char *literal = Match(ast, Int)->str;
OptionalInt_t int_val = Int$from_str(literal);
- if (int_val.small == 0)
- code_err(ast, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(ast, "Failed to parse this integer");
mpz_t i;
mpz_init_set_int(i, int_val);
@@ -2424,8 +2379,7 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
}
if (target->tag == ByteType) {
- if (mpz_cmp_si(i, UINT8_MAX) <= 0 && mpz_cmp_si(i, 0) >= 0)
- return Texts("(Byte_t)(", c_literal, ")");
+ if (mpz_cmp_si(i, UINT8_MAX) <= 0 && mpz_cmp_si(i, 0) >= 0) return Texts("(Byte_t)(", c_literal, ")");
code_err(ast, "This integer cannot fit in a byte");
} else if (target->tag == NumType) {
if (Match(target, NumType)->bits == TYPE_NBITS64) {
@@ -2437,22 +2391,17 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
int64_t target_bits = (int64_t)Match(target, IntType)->bits;
switch (target_bits) {
case TYPE_IBITS64:
- if (mpz_cmp_si(i, INT64_MIN) == 0)
- return Text("I64(INT64_MIN)");
- if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0)
- return Texts("I64(", c_literal, "L)");
+ if (mpz_cmp_si(i, INT64_MIN) == 0) return Text("I64(INT64_MIN)");
+ if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) return Texts("I64(", c_literal, "L)");
break;
case TYPE_IBITS32:
- if (mpz_cmp_si(i, INT32_MAX) <= 0 && mpz_cmp_si(i, INT32_MIN) >= 0)
- return Texts("I32(", c_literal, ")");
+ if (mpz_cmp_si(i, INT32_MAX) <= 0 && mpz_cmp_si(i, INT32_MIN) >= 0) return Texts("I32(", c_literal, ")");
break;
case TYPE_IBITS16:
- if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0)
- return Texts("I16(", c_literal, ")");
+ if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0) return Texts("I16(", c_literal, ")");
break;
case TYPE_IBITS8:
- if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0)
- return Texts("I8(", c_literal, ")");
+ if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0) return Texts("I8(", c_literal, ")");
break;
default: break;
}
@@ -2463,13 +2412,12 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
return EMPTY_TEXT;
}
-Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args)
-{
+Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args) {
Table_t used_args = {};
Text_t code = EMPTY_TEXT;
- env_t *default_scope = new(env_t);
+ env_t *default_scope = new (env_t);
*default_scope = *env;
- default_scope->locals = new(Table_t, .fallback=env->namespace_bindings ? env->namespace_bindings : env->globals);
+ default_scope->locals = new (Table_t, .fallback = env->namespace_bindings ? env->namespace_bindings : env->globals);
for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
int64_t i = 1;
// Find keyword:
@@ -2481,12 +2429,10 @@ Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_
value = compile_int_to_type(env, call_arg->value, spec_arg->type);
} else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) {
OptionalInt_t int_val = Int$from_str(Match(call_arg->value, Int)->str);
- if (int_val.small == 0)
- code_err(call_arg->value, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(call_arg->value, "Failed to parse this integer");
if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64)
value = Text$from_str(String(hex_double(Num$from_int(int_val, false))));
- else
- value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f"));
+ else value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f"));
} else {
env_t *arg_env = with_enum_scope(env, spec_arg->type);
value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type);
@@ -2508,12 +2454,10 @@ Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_
value = compile_int_to_type(env, call_arg->value, spec_arg->type);
} else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) {
OptionalInt_t int_val = Int$from_str(Match(call_arg->value, Int)->str);
- if (int_val.small == 0)
- code_err(call_arg->value, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(call_arg->value, "Failed to parse this integer");
if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64)
value = Text$from_str(String(hex_double(Num$from_int(int_val, false))));
- else
- value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f"));
+ else value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f"));
} else {
env_t *arg_env = with_enum_scope(env, spec_arg->type);
value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type);
@@ -2534,7 +2478,8 @@ Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_
assert(spec_arg->name);
code_err(call_ast, "The required argument '", spec_arg->name, "' was not provided");
- found_it: continue;
+ found_it:
+ continue;
}
int64_t i = 1;
@@ -2544,15 +2489,13 @@ Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_
code_err(call_arg->value, "There is no argument with the name '", call_arg->name, "'");
} else {
const char *pseudoname = String(i++);
- if (!Table$str_get(used_args, pseudoname))
- code_err(call_arg->value, "This is one argument too many!");
+ if (!Table$str_get(used_args, pseudoname)) code_err(call_arg->value, "This is one argument too many!");
}
}
return code;
}
-Text_t compile_text_literal(Text_t literal)
-{
+Text_t compile_text_literal(Text_t literal) {
Text_t code = Text("\"");
const char *utf8 = Text$as_c_string(literal);
for (const char *p = utf8; *p; p++) {
@@ -2569,8 +2512,8 @@ Text_t compile_text_literal(Text_t literal)
if (isprint(*p)) {
code = Texts(code, Text$from_strn(p, 1));
} else {
- uint8_t byte = *(uint8_t*)p;
- code = Texts(code, "\\x", String(hex(byte, .no_prefix=true, .uppercase=true, .digits=2)), "\"\"");
+ uint8_t byte = *(uint8_t *)p;
+ code = Texts(code, "\\x", String(hex(byte, .no_prefix = true, .uppercase = true, .digits = 2)), "\"\"");
}
break;
}
@@ -2579,27 +2522,21 @@ Text_t compile_text_literal(Text_t literal)
return Texts(code, "\"");
}
-PUREFUNC static bool string_literal_is_all_ascii(Text_t literal)
-{
+PUREFUNC static bool string_literal_is_all_ascii(Text_t literal) {
TextIter_t state = NEW_TEXT_ITER_STATE(literal);
for (int64_t i = 0; i < literal.length; i++) {
int32_t g = Text$get_grapheme_fast(&state, i);
- if (g < 0 || g > 127 || !isascii(g))
- return false;
+ if (g < 0 || g > 127 || !isascii(g)) return false;
}
return true;
}
-Text_t compile_none(type_t *t)
-{
- if (t == NULL)
- compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
+Text_t compile_none(type_t *t) {
+ if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
- if (t->tag == OptionalType)
- t = Match(t, OptionalType)->type;
+ if (t->tag == OptionalType) t = Match(t, OptionalType)->type;
- if (t == NULL)
- compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
+ if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
if (t == PATH_TYPE) return Text("NONE_PATH");
else if (t == PATH_TYPE_TYPE) return Text("((OptionalPathType_t){})");
@@ -2626,7 +2563,7 @@ Text_t compile_none(type_t *t)
case PointerType: return Texts("((", compile_type(t), ")NULL)");
case ClosureType: return Text("NONE_CLOSURE");
case NumType: return Text("nan(\"none\")");
- case StructType: return Texts("((", compile_type(Type(OptionalType, .type=t)), "){.is_none=true})");
+ case StructType: return Texts("((", compile_type(Type(OptionalType, .type = t)), "){.is_none=true})");
case EnumType: {
env_t *enum_env = Match(t, EnumType)->env;
return Texts("((", compile_type(t), "){", namespace_name(enum_env, enum_env->namespace, Text("none")), "})");
@@ -2636,13 +2573,10 @@ Text_t compile_none(type_t *t)
return EMPTY_TEXT;
}
-Text_t compile_empty(type_t *t)
-{
- if (t == NULL)
- compiler_err(NULL, NULL, NULL, "I can't compile a value with no type");
+Text_t compile_empty(type_t *t) {
+ if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a value with no type");
- if (t->tag == OptionalType)
- return compile_none(t);
+ if (t->tag == OptionalType) return compile_none(t);
if (t == PATH_TYPE) return Text("NONE_PATH");
else if (t == PATH_TYPE_TYPE) return Text("((OptionalPathType_t){})");
@@ -2662,13 +2596,15 @@ Text_t compile_empty(type_t *t)
case ByteType: return Text("((Byte_t)0)");
case BoolType: return Text("((Bool_t)no)");
case ListType: return Text("((List_t){})");
- case TableType: case SetType: return Text("((Table_t){})");
+ case TableType:
+ case SetType: return Text("((Table_t){})");
case TextType: return Text("Text(\"\")");
case CStringType: return Text("\"\"");
case PointerType: {
DeclareMatch(ptr, t, PointerType);
Text_t empty_pointed = compile_empty(ptr->pointed);
- return empty_pointed.length == 0 ? EMPTY_TEXT : Texts(ptr->is_stack ? Text("stack(") : Text("heap("), empty_pointed, ")");
+ return empty_pointed.length == 0 ? EMPTY_TEXT
+ : Texts(ptr->is_stack ? Text("stack(") : Text("heap("), empty_pointed, ")");
}
case NumType: {
return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("N32(0.0f)") : Text("N64(0.0)");
@@ -2677,15 +2613,12 @@ Text_t compile_empty(type_t *t)
DeclareMatch(struct_, t, StructType);
Text_t code = Texts("((", compile_type(t), "){");
for (arg_t *field = struct_->fields; field; field = field->next) {
- Text_t empty_field = field->default_val
- ? compile(struct_->env, field->default_val)
- : compile_empty(field->type);
- if (empty_field.length == 0)
- return EMPTY_TEXT;
+ Text_t empty_field =
+ field->default_val ? compile(struct_->env, field->default_val) : compile_empty(field->type);
+ if (empty_field.length == 0) return EMPTY_TEXT;
code = Texts(code, empty_field);
- if (field->next)
- code = Texts(code, ", ");
+ if (field->next) code = Texts(code, ", ");
}
return Texts(code, "})");
}
@@ -2695,19 +2628,17 @@ Text_t compile_empty(type_t *t)
assert(tag);
assert(tag->type);
if (Match(tag->type, StructType)->fields)
- return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=", compile_empty(tag->type), "})");
- else if (enum_has_fields(t))
- return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})");
- else
- return Texts("((", compile_type(t), ")", String(tag->tag_value), ")");
+ return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=",
+ compile_empty(tag->type), "})");
+ else if (enum_has_fields(t)) return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})");
+ else return Texts("((", compile_type(t), ")", String(tag->tag_value), ")");
}
default: return EMPTY_TEXT;
}
return EMPTY_TEXT;
}
-static Text_t compile_declared_value(env_t *env, ast_t *declare_ast)
-{
+static Text_t compile_declared_value(env_t *env, ast_t *declare_ast) {
DeclareMatch(decl, declare_ast, Declare);
type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
@@ -2724,30 +2655,27 @@ static Text_t compile_declared_value(env_t *env, ast_t *declare_ast)
} else {
Text_t val_code = compile_empty(t);
if (val_code.length == 0)
- code_err(declare_ast, "This type (", type_to_str(t), ") cannot be uninitialized. You must provide a value.");
+ code_err(declare_ast, "This type (", type_to_str(t),
+ ") cannot be uninitialized. You must provide a value.");
return val_code;
}
}
-ast_t *add_to_table_comprehension(ast_t *entry, ast_t *subject)
-{
+ast_t *add_to_table_comprehension(ast_t *entry, ast_t *subject) {
DeclareMatch(e, entry, TableEntry);
- return WrapAST(entry, MethodCall, .name="set", .self=subject,
- .args=new(arg_ast_t, .value=e->key, .next=new(arg_ast_t, .value=e->value)));
+ return WrapAST(entry, MethodCall, .name = "set", .self = subject,
+ .args = new (arg_ast_t, .value = e->key, .next = new (arg_ast_t, .value = e->value)));
}
-ast_t *add_to_list_comprehension(ast_t *item, ast_t *subject)
-{
- return WrapAST(item, MethodCall, .name="insert", .self=subject, .args=new(arg_ast_t, .value=item));
+ast_t *add_to_list_comprehension(ast_t *item, ast_t *subject) {
+ return WrapAST(item, MethodCall, .name = "insert", .self = subject, .args = new (arg_ast_t, .value = item));
}
-ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject)
-{
- return WrapAST(item, MethodCall, .name="add", .self=subject, .args=new(arg_ast_t, .value=item));
+ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject) {
+ return WrapAST(item, MethodCall, .name = "add", .self = subject, .args = new (arg_ast_t, .value = item));
}
-Text_t compile(env_t *env, ast_t *ast)
-{
+Text_t compile(env_t *env, ast_t *ast) {
switch (ast->tag) {
case None: {
code_err(ast, "I can't figure out what this `none`'s type is!");
@@ -2755,16 +2683,14 @@ Text_t compile(env_t *env, ast_t *ast)
case Bool: return Match(ast, Bool)->b ? Text("yes") : Text("no");
case Var: {
binding_t *b = get_binding(env, Match(ast, Var)->name);
- if (b)
- return b->code.length > 0 ? b->code : Texts("_$", Match(ast, Var)->name);
+ if (b) return b->code.length > 0 ? b->code : Texts("_$", Match(ast, Var)->name);
// return Texts("_$", Match(ast, Var)->name);
code_err(ast, "I don't know of any variable by this name");
}
case Int: {
const char *str = Match(ast, Int)->str;
OptionalInt_t int_val = Int$from_str(str);
- if (int_val.small == 0)
- code_err(ast, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(ast, "Failed to parse this integer");
mpz_t i;
mpz_init_set_int(i, int_val);
if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) {
@@ -2786,21 +2712,16 @@ Text_t compile(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (fn->args && can_compile_to_type(env, value, get_arg_type(env, fn->args)))
- return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new(arg_ast_t, .value=value)), ")");
+ return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new (arg_ast_t, .value = value)), ")");
}
- if (t->tag == BoolType)
- return Texts("!(", compile(env, value), ")");
- else if (t->tag == IntType || t->tag == ByteType)
- return Texts("~(", compile(env, value), ")");
- else if (t->tag == ListType)
- return Texts("((", compile(env, value), ").length == 0)");
+ if (t->tag == BoolType) return Texts("!(", compile(env, value), ")");
+ else if (t->tag == IntType || t->tag == ByteType) return Texts("~(", compile(env, value), ")");
+ else if (t->tag == ListType) return Texts("((", compile(env, value), ").length == 0)");
else if (t->tag == SetType || t->tag == TableType)
return Texts("((", compile(env, value), ").entries.length == 0)");
- else if (t->tag == TextType)
- return Texts("(", compile(env, value), ".length == 0)");
- else if (t->tag == OptionalType)
- return check_none(t, compile(env, value));
+ else if (t->tag == TextType) return Texts("(", compile(env, value), ".length == 0)");
+ else if (t->tag == OptionalType) return check_none(t, compile(env, value));
code_err(ast, "I don't know how to negate values of type ", type_to_str(t));
}
@@ -2811,16 +2732,15 @@ Text_t compile(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (fn->args && can_compile_to_type(env, value, get_arg_type(env, fn->args)))
- return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new(arg_ast_t, .value=value)), ")");
+ return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new (arg_ast_t, .value = value)), ")");
}
- if (t->tag == IntType || t->tag == NumType)
- return Texts("-(", compile(env, value), ")");
+ if (t->tag == IntType || t->tag == NumType) return Texts("-(", compile(env, value), ")");
code_err(ast, "I don't know how to get the negative value of type ", type_to_str(t));
-
}
- case HeapAllocate: case StackReference: {
+ case HeapAllocate:
+ case StackReference: {
return compile_typed_allocation(env, ast, get_type(env, ast));
}
case Optional: {
@@ -2833,20 +2753,32 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *t = get_type(env, value);
Text_t value_code = compile(env, value);
int64_t line = get_line_number(ast->file, ast->start);
- return Texts("({ ", compile_declaration(t, Text("opt")), " = ", value_code, "; ",
- "if unlikely (", check_none(t, Text("opt")), ")\n",
- "#line ", String(line), "\n",
- "fail_source(", quoted_str(ast->file->filename), ", ",
- String((int64_t)(value->start - value->file->text)), ", ",
- String((int64_t)(value->end - value->file->text)), ", ",
- "\"This was expected to be a value, but it's none\");\n",
- optional_into_nonnone(t, Text("opt")), "; })");
- }
- case Power: case Multiply: case Divide: case Mod: case Mod1: case Plus: case Minus: case Concat:
- case LeftShift: case UnsignedLeftShift: case RightShift: case UnsignedRightShift: case And: case Or: case Xor: {
+ return Texts("({ ", compile_declaration(t, Text("opt")), " = ", value_code, "; ", "if unlikely (",
+ check_none(t, Text("opt")), ")\n", "#line ", String(line), "\n", "fail_source(",
+ quoted_str(ast->file->filename), ", ", String((int64_t)(value->start - value->file->text)), ", ",
+ String((int64_t)(value->end - value->file->text)), ", ",
+ "\"This was expected to be a value, but it's none\");\n", optional_into_nonnone(t, Text("opt")),
+ "; })");
+ }
+ case Power:
+ case Multiply:
+ case Divide:
+ case Mod:
+ case Mod1:
+ case Plus:
+ case Minus:
+ case Concat:
+ case LeftShift:
+ case UnsignedLeftShift:
+ case RightShift:
+ case UnsignedRightShift:
+ case And:
+ case Or:
+ case Xor: {
return compile_binary_op(env, ast);
}
- case Equals: case NotEquals: {
+ case Equals:
+ case NotEquals: {
binary_operands_t binop = BINARY_OPERANDS(ast);
type_t *lhs_t = get_type(env, binop.lhs);
@@ -2871,14 +2803,22 @@ Text_t compile(env_t *env, ast_t *ast)
switch (operand_t->tag) {
case BigIntType:
return Texts(ast->tag == Equals ? EMPTY_TEXT : Text("!"), "Int$equal_value(", lhs, ", ", rhs, ")");
- case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
- return Texts("(", lhs, ast->tag == Equals ? " == " : " != ", rhs, ")");
+ case BoolType:
+ case ByteType:
+ case IntType:
+ case NumType:
+ case PointerType:
+ case FunctionType: return Texts("(", lhs, ast->tag == Equals ? " == " : " != ", rhs, ")");
default:
- return Texts(ast->tag == Equals ? EMPTY_TEXT : Text("!"),
- "generic_equal(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")");
+ return Texts(ast->tag == Equals ? EMPTY_TEXT : Text("!"), "generic_equal(stack(", lhs, "), stack(", rhs,
+ "), ", compile_type_info(operand_t), ")");
}
}
- case LessThan: case LessThanOrEquals: case GreaterThan: case GreaterThanOrEquals: case Compare: {
+ case LessThan:
+ case LessThanOrEquals:
+ case GreaterThan:
+ case GreaterThanOrEquals:
+ case Compare: {
binary_operands_t cmp = BINARY_OPERANDS(ast);
type_t *lhs_t = get_type(env, cmp.lhs);
@@ -2900,49 +2840,47 @@ Text_t compile(env_t *env, ast_t *ast)
Text_t rhs = compile_to_type(env, cmp.rhs, operand_t);
if (ast->tag == Compare)
- return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ",
- compile_type_info(operand_t), ")");
+ return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")");
const char *op = binop_operator(ast->tag);
switch (operand_t->tag) {
- case BigIntType:
- return Texts("(Int$compare_value(", lhs, ", ", rhs, ") ", op, " 0)");
- case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
- return Texts("(", lhs, " ", op, " ", rhs, ")");
+ case BigIntType: return Texts("(Int$compare_value(", lhs, ", ", rhs, ") ", op, " 0)");
+ case BoolType:
+ case ByteType:
+ case IntType:
+ case NumType:
+ case PointerType:
+ case FunctionType: return Texts("(", lhs, " ", op, " ", rhs, ")");
default:
- return Texts("(generic_compare(stack(", lhs, "), stack(", rhs, "), ",
- compile_type_info(operand_t), ") ", op, " 0)");
+ return Texts("(generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ") ",
+ op, " 0)");
}
}
case TextLiteral: {
- Text_t literal = Match(ast, TextLiteral)->text;
- if (literal.length == 0)
- return Text("EMPTY_TEXT");
+ Text_t literal = Match(ast, TextLiteral)->text;
+ if (literal.length == 0) return Text("EMPTY_TEXT");
- if (string_literal_is_all_ascii(literal))
- return Texts("Text(", compile_text_literal(literal), ")");
- else
- return Texts("Text$from_str(", compile_text_literal(literal), ")");
+ if (string_literal_is_all_ascii(literal)) return Texts("Text(", compile_text_literal(literal), ")");
+ else return Texts("Text$from_str(", compile_text_literal(literal), ")");
}
case TextJoin: {
const char *lang = Match(ast, TextJoin)->lang;
Text_t colorize = Match(ast, TextJoin)->colorize ? Text("yes") : Text("no");
type_t *text_t = lang ? Table$str_get(*env->types, lang) : TEXT_TYPE;
- if (!text_t || text_t->tag != TextType)
- code_err(ast, quoted(lang), " is not a valid text language name");
+ if (!text_t || text_t->tag != TextType) code_err(ast, quoted(lang), " is not a valid text language name");
Text_t lang_constructor;
- if (!lang || streq(lang, "Text"))
- lang_constructor = Text("Text");
+ if (!lang || streq(lang, "Text")) lang_constructor = Text("Text");
else
- lang_constructor = namespace_name(Match(text_t, TextType)->env, Match(text_t, TextType)->env->namespace->parent, Text$from_str(lang));
+ lang_constructor = namespace_name(Match(text_t, TextType)->env,
+ Match(text_t, TextType)->env->namespace->parent, Text$from_str(lang));
ast_list_t *chunks = Match(ast, TextJoin)->children;
if (!chunks) {
return Texts(lang_constructor, "(\"\")");
} else if (!chunks->next && chunks->ast->tag == TextLiteral) {
- Text_t literal = Match(chunks->ast, TextLiteral)->text;
+ Text_t literal = Match(chunks->ast, TextLiteral)->text;
if (string_literal_is_all_ascii(literal))
return Texts(lang_constructor, "(", compile_text_literal(literal), ")");
return Texts("((", compile_type(text_t), ")", compile(env, chunks->ast), ")");
@@ -2954,28 +2892,26 @@ Text_t compile(env_t *env, ast_t *ast)
if (chunk->ast->tag == TextLiteral || type_eq(chunk_t, text_t)) {
chunk_code = compile(env, chunk->ast);
} else {
- binding_t *constructor = get_constructor(env, text_t, new(arg_ast_t, .value=chunk->ast),
- env->current_type != NULL && type_eq(env->current_type, text_t));
+ binding_t *constructor =
+ get_constructor(env, text_t, new (arg_ast_t, .value = chunk->ast),
+ env->current_type != NULL && type_eq(env->current_type, text_t));
if (constructor) {
arg_t *arg_spec = Match(constructor->type, FunctionType)->args;
- arg_ast_t *args = new(arg_ast_t, .value=chunk->ast);
+ arg_ast_t *args = new (arg_ast_t, .value = chunk->ast);
chunk_code = Texts(constructor->code, "(", compile_arguments(env, ast, arg_spec, args), ")");
} else if (type_eq(text_t, TEXT_TYPE)) {
- if (chunk_t->tag == TextType)
- chunk_code = compile(env, chunk->ast);
- else
- chunk_code = compile_text(env, chunk->ast, colorize);
+ if (chunk_t->tag == TextType) chunk_code = compile(env, chunk->ast);
+ else chunk_code = compile_text(env, chunk->ast, colorize);
} else {
- code_err(chunk->ast, "I don't know how to convert ", type_to_str(chunk_t), " to ", type_to_str(text_t));
+ code_err(chunk->ast, "I don't know how to convert ", type_to_str(chunk_t), " to ",
+ type_to_str(text_t));
}
}
code = Texts(code, chunk_code);
if (chunk->next) code = Texts(code, ", ");
}
- if (chunks->next)
- return Texts(lang_constructor, "s(", code, ")");
- else
- return code;
+ if (chunks->next) return Texts(lang_constructor, "s(", code, ")");
+ else return code;
}
}
case Path: {
@@ -2983,8 +2919,7 @@ Text_t compile(env_t *env, ast_t *ast)
}
case Block: {
ast_list_t *stmts = Match(ast, Block)->statements;
- if (stmts && !stmts->next)
- return compile(env, stmts->ast);
+ if (stmts && !stmts->next) return compile(env, stmts->ast);
Text_t code = Text("({\n");
deferral_t *prev_deferred = env->deferred;
@@ -2996,7 +2931,8 @@ Text_t compile(env_t *env, ast_t *ast)
code = Texts(code, compile_statement(env, stmt->ast), "\n");
} else {
// TODO: put defer after evaluating block expression
- for (deferral_t *deferred = env->deferred; deferred && deferred != prev_deferred; deferred = deferred->next) {
+ for (deferral_t *deferred = env->deferred; deferred && deferred != prev_deferred;
+ deferred = deferred->next) {
code = Texts(code, compile_statement(deferred->defer_env, deferred->block));
}
code = Texts(code, compile(env, stmt->ast), ";\n");
@@ -3006,7 +2942,8 @@ Text_t compile(env_t *env, ast_t *ast)
return Texts(code, "})");
}
- case Min: case Max: {
+ case Min:
+ case Max: {
type_t *t = get_type(env, ast);
ast_t *key = ast->tag == Min ? Match(ast, Min)->key : Match(ast, Max)->key;
ast_t *lhs = ast->tag == Min ? Match(ast, Min)->lhs : Match(ast, Max)->lhs;
@@ -3024,23 +2961,23 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *key_t = get_type(expr_env, key);
Text_t comparison;
if (key_t->tag == BigIntType)
- comparison = Texts("(Int$compare_value(", lhs_key, ", ", rhs_key, ")", (ast->tag == Min ? "<=" : ">="), "0)");
- else if (key_t->tag == IntType || key_t->tag == NumType || key_t->tag == BoolType || key_t->tag == PointerType || key_t->tag == ByteType)
+ comparison =
+ Texts("(Int$compare_value(", lhs_key, ", ", rhs_key, ")", (ast->tag == Min ? "<=" : ">="), "0)");
+ else if (key_t->tag == IntType || key_t->tag == NumType || key_t->tag == BoolType || key_t->tag == PointerType
+ || key_t->tag == ByteType)
comparison = Texts("((", lhs_key, ")", (ast->tag == Min ? "<=" : ">="), "(", rhs_key, "))");
else
- comparison = Texts("generic_compare(stack(", lhs_key, "), stack(", rhs_key, "), ", compile_type_info(key_t), ")",
- (ast->tag == Min ? "<=" : ">="), "0");
+ comparison = Texts("generic_compare(stack(", lhs_key, "), stack(", rhs_key, "), ", compile_type_info(key_t),
+ ")", (ast->tag == Min ? "<=" : ">="), "0");
- return Texts(
- "({\n",
- compile_type(t), " ternary$lhs = ", compile(env, lhs), ", ternary$rhs = ", compile(env, rhs), ";\n",
- comparison, " ? ternary$lhs : ternary$rhs;\n"
- "})");
+ return Texts("({\n", compile_type(t), " ternary$lhs = ", compile(env, lhs),
+ ", ternary$rhs = ", compile(env, rhs), ";\n", comparison,
+ " ? ternary$lhs : ternary$rhs;\n"
+ "})");
}
case List: {
DeclareMatch(list, ast, List);
- if (!list->items)
- return Text("(List_t){.length=0}");
+ if (!list->items) return Text("(List_t){.length=0}");
type_t *list_type = get_type(env, ast);
return compile_typed_list(env, ast, list_type);
@@ -3049,8 +2986,7 @@ Text_t compile(env_t *env, ast_t *ast)
DeclareMatch(table, ast, Table);
if (!table->entries) {
Text_t code = Text("((Table_t){");
- if (table->fallback)
- code = Texts(code, ".fallback=heap(", compile(env, table->fallback),")");
+ if (table->fallback) code = Texts(code, ".fallback=heap(", compile(env, table->fallback), ")");
return Texts(code, "})");
}
@@ -3059,8 +2995,7 @@ Text_t compile(env_t *env, ast_t *ast)
}
case Set: {
DeclareMatch(set, ast, Set);
- if (!set->items)
- return Text("((Table_t){})");
+ if (!set->items) return Text("((Table_t){})");
type_t *set_type = get_type(env, ast);
return compile_typed_set(env, ast, set_type);
@@ -3069,10 +3004,8 @@ Text_t compile(env_t *env, ast_t *ast)
ast_t *base = Match(ast, Comprehension)->expr;
while (base->tag == Comprehension)
base = Match(ast, Comprehension)->expr;
- if (base->tag == TableEntry)
- return compile(env, WrapAST(ast, Table, .entries=new(ast_list_t, .ast=ast)));
- else
- return compile(env, WrapAST(ast, List, .items=new(ast_list_t, .ast=ast)));
+ if (base->tag == TableEntry) return compile(env, WrapAST(ast, Table, .entries = new (ast_list_t, .ast = ast)));
+ else return compile(env, WrapAST(ast, List, .items = new (ast_list_t, .ast = ast)));
}
case Lambda: {
DeclareMatch(lambda, ast, Lambda);
@@ -3086,13 +3019,11 @@ Text_t compile(env_t *env, ast_t *ast)
}
type_t *ret_t = get_type(body_scope, lambda->body);
- if (ret_t->tag == ReturnType)
- ret_t = Match(ret_t, ReturnType)->ret;
+ if (ret_t->tag == ReturnType) ret_t = Match(ret_t, ReturnType)->ret;
if (lambda->ret_type) {
type_t *declared = parse_type_ast(env, lambda->ret_type);
- if (can_promote(ret_t, declared))
- ret_t = declared;
+ if (can_promote(ret_t, declared)) ret_t = declared;
else
code_err(ast, "This function was declared to return a value of type ", type_to_str(declared),
", but actually returns a value of type ", type_to_str(ret_t));
@@ -3104,12 +3035,15 @@ Text_t compile(env_t *env, ast_t *ast)
if (Table$length(closed_vars) > 0) { // Create a typedef for the lambda's closure userdata
Text_t def = Text("typedef struct {");
for (int64_t i = 0; i < closed_vars.entries.length; i++) {
- struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i;
+ struct {
+ const char *name;
+ binding_t *b;
+ } *entry = closed_vars.entries.data + closed_vars.entries.stride * i;
if (has_stack_memory(entry->b->type))
code_err(ast, "This function is holding onto a reference to ", type_to_str(entry->b->type),
- " stack memory in the variable `", entry->name, "`, but the function may outlive the stack memory");
- if (entry->b->type->tag == ModuleType)
- continue;
+ " stack memory in the variable `", entry->name,
+ "`, but the function may outlive the stack memory");
+ if (entry->b->type->tag == ModuleType) continue;
set_binding(body_scope, entry->name, entry->b->type, Texts("userdata->", entry->name));
def = Texts(def, compile_declaration(entry->b->type, Text$from_str(entry->name)), "; ");
}
@@ -3130,18 +3064,18 @@ Text_t compile(env_t *env, ast_t *ast)
} else {
userdata = Texts("new(", name, "$userdata_t");
for (int64_t i = 0; i < closed_vars.entries.length; i++) {
- struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i;
- if (entry->b->type->tag == ModuleType)
- continue;
+ struct {
+ const char *name;
+ binding_t *b;
+ } *entry = closed_vars.entries.data + closed_vars.entries.stride * i;
+ if (entry->b->type->tag == ModuleType) continue;
binding_t *b = get_binding(env, entry->name);
assert(b);
Text_t binding_code = b->code;
- if (entry->b->type->tag == ListType)
- userdata = Texts(userdata, ", LIST_COPY(", binding_code, ")");
+ if (entry->b->type->tag == ListType) userdata = Texts(userdata, ", LIST_COPY(", binding_code, ")");
else if (entry->b->type->tag == TableType || entry->b->type->tag == SetType)
userdata = Texts(userdata, ", TABLE_COPY(", binding_code, ")");
- else
- userdata = Texts(userdata, ", ", binding_code);
+ else userdata = Texts(userdata, ", ", binding_code);
}
userdata = Texts(userdata, ")");
code = Texts(code, name, "$userdata_t *userdata)");
@@ -3149,10 +3083,10 @@ Text_t compile(env_t *env, ast_t *ast)
Text_t body = EMPTY_TEXT;
for (ast_list_t *stmt = Match(lambda->body, Block)->statements; stmt; stmt = stmt->next) {
- if (stmt->next || ret_t->tag == VoidType || ret_t->tag == AbortType || get_type(body_scope, stmt->ast)->tag == ReturnType)
+ if (stmt->next || ret_t->tag == VoidType || ret_t->tag == AbortType
+ || get_type(body_scope, stmt->ast)->tag == ReturnType)
body = Texts(body, compile_statement(body_scope, stmt->ast), "\n");
- else
- body = Texts(body, compile_statement(body_scope, FakeAST(Return, stmt->ast)), "\n");
+ else body = Texts(body, compile_statement(body_scope, FakeAST(Return, stmt->ast)), "\n");
bind_statement(body_scope, stmt->ast);
}
if ((ret_t->tag == VoidType || ret_t->tag == AbortType) && body_scope->deferred)
@@ -3166,10 +3100,9 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *self_t = get_type(env, call->self);
if (streq(call->name, "serialized")) {
- if (call->args)
- code_err(ast, ".serialized() doesn't take any arguments");
+ if (call->args) code_err(ast, ".serialized() doesn't take any arguments");
return Texts("generic_serialize((", compile_declaration(self_t, Text("[1]")), "){",
- compile(env, call->self), "}, ", compile_type_info(self_t), ")");
+ compile(env, call->self), "}, ", compile_type_info(self_t), ")");
}
int64_t pointer_depth = 0;
@@ -3178,23 +3111,29 @@ Text_t compile(env_t *env, ast_t *ast)
pointer_depth += 1;
if (self_value_t->tag == TypeInfoType || self_value_t->tag == ModuleType) {
- return compile(env, WrapAST(ast, FunctionCall, .fn=WrapAST(call->self, FieldAccess, .fielded=call->self, .field=call->name),
- .args=call->args));
+ return compile(env,
+ WrapAST(ast, FunctionCall,
+ .fn = WrapAST(call->self, FieldAccess, .fielded = call->self, .field = call->name),
+ .args = call->args));
}
type_t *field_type = get_field_type(self_value_t, call->name);
- if (field_type && field_type->tag == ClosureType)
- field_type = Match(field_type, ClosureType)->fn;
+ if (field_type && field_type->tag == ClosureType) field_type = Match(field_type, ClosureType)->fn;
if (field_type && field_type->tag == FunctionType)
- return compile(env, WrapAST(ast, FunctionCall, .fn=WrapAST(call->self, FieldAccess, .fielded=call->self, .field=call->name),
- .args=call->args));
+ return compile(env,
+ WrapAST(ast, FunctionCall,
+ .fn = WrapAST(call->self, FieldAccess, .fielded = call->self, .field = call->name),
+ .args = call->args));
Text_t self = compile(env, call->self);
-#define EXPECT_POINTER(article, name) do { \
- if (pointer_depth < 1) code_err(call->self, "I expected "article" "name" pointer here, not "article" "name" value"); \
- else if (pointer_depth > 1) code_err(call->self, "I expected "article" "name" pointer here, not a nested "name" pointer"); \
-} while (0)
+#define EXPECT_POINTER(article, name) \
+ do { \
+ if (pointer_depth < 1) \
+ code_err(call->self, "I expected " article " " name " pointer here, not " article " " name " value"); \
+ else if (pointer_depth > 1) \
+ code_err(call->self, "I expected " article " " name " pointer here, not a nested " name " pointer"); \
+ } while (0)
switch (self_value_t->tag) {
case ListType: {
type_t *item_t = Match(self_value_t, ListType)->item_type;
@@ -3202,116 +3141,141 @@ Text_t compile(env_t *env, ast_t *ast)
if (streq(call->name, "insert")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
- .next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0")));
+ arg_t *arg_spec =
+ new (arg_t, .name = "item", .type = item_t,
+ .next = new (arg_t, .name = "at", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "0")));
return Texts("List$insert_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
+ padded_item_size, ")");
} else if (streq(call->name, "insert_all")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="items", .type=self_value_t,
- .next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0")));
+ arg_t *arg_spec =
+ new (arg_t, .name = "items", .type = self_value_t,
+ .next = new (arg_t, .name = "at", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "0")));
return Texts("List$insert_all(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
+ padded_item_size, ")");
} else if (streq(call->name, "remove_at")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="index", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1"),
- .next=new(arg_t, .name="count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1")));
+ arg_t *arg_spec = new (
+ arg_t, .name = "index", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "-1"),
+ .next = new (arg_t, .name = "count", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "1")));
return Texts("List$remove_at(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
+ padded_item_size, ")");
} else if (streq(call->name, "remove_item")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
- .next=new(arg_t, .name="max_count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1")));
- return Texts("List$remove_item_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t,
+ .next = new (arg_t, .name = "max_count", .type = INT_TYPE,
+ .default_val = FakeAST(Int, .str = "-1")));
+ return Texts("List$remove_item_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ", ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "has")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t);
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t);
return Texts("List$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "sample")) {
type_t *random_num_type = parse_type_string(env, "func(->Num)?");
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="count", .type=INT_TYPE,
- .next=new(arg_t, .name="weights", .type=Type(ListType, .item_type=Type(NumType, .bits=TYPE_NBITS64)),
- .default_val=FakeAST(None),
- .next=new(arg_t, .name="random", .type=random_num_type, .default_val=FakeAST(None))));
+ arg_t *arg_spec =
+ new (arg_t, .name = "count", .type = INT_TYPE,
+ .next = new (arg_t, .name = "weights",
+ .type = Type(ListType, .item_type = Type(NumType, .bits = TYPE_NBITS64)),
+ .default_val = FakeAST(None),
+ .next = new (arg_t, .name = "random", .type = random_num_type,
+ .default_val = FakeAST(None))));
return Texts("List$sample(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
+ padded_item_size, ")");
} else if (streq(call->name, "shuffle")) {
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
- return Texts("List$shuffle(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")");
+ arg_t *arg_spec =
+ new (arg_t, .name = "random", .type = random_int64_type, .default_val = FakeAST(None));
+ return Texts("List$shuffle(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ padded_item_size, ")");
} else if (streq(call->name, "shuffled")) {
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
- return Texts("List$shuffled(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")");
+ arg_t *arg_spec =
+ new (arg_t, .name = "random", .type = random_int64_type, .default_val = FakeAST(None));
+ return Texts("List$shuffled(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ padded_item_size, ")");
} else if (streq(call->name, "random")) {
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
- return Texts("List$random_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type(item_t), ")");
+ arg_t *arg_spec =
+ new (arg_t, .name = "random", .type = random_int64_type, .default_val = FakeAST(None));
+ return Texts("List$random_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type(item_t), ")");
} else if (streq(call->name, "sort") || streq(call->name, "sorted")) {
- if (streq(call->name, "sort"))
- EXPECT_POINTER("a", "list");
- else
- self = compile_to_pointer_depth(env, call->self, 0, false);
+ if (streq(call->name, "sort")) EXPECT_POINTER("a", "list");
+ else self = compile_to_pointer_depth(env, call->self, 0, false);
Text_t comparison;
if (call->args) {
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t));
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ arg_t *arg_spec = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t));
comparison = compile_arguments(env, ast, arg_spec, call->args);
} else {
- comparison = Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})");
+ comparison = Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})");
}
return Texts("List$", call->name, "(", self, ", ", comparison, ", ", padded_item_size, ")");
} else if (streq(call->name, "heapify")) {
EXPECT_POINTER("a", "list");
Text_t comparison;
if (call->args) {
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t));
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ arg_t *arg_spec = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t));
comparison = compile_arguments(env, ast, arg_spec, call->args);
} else {
- comparison = Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})");
+ comparison = Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})");
}
return Texts("List$heapify(", self, ", ", comparison, ", ", padded_item_size, ")");
} else if (streq(call->name, "heap_push")) {
EXPECT_POINTER("a", "list");
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)",
- compile_type_info(item_t), "})"),
- .type=Type(ClosureType, .fn=fn_t));
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
- .next=new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp));
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})"),
+ .type = Type(ClosureType, .fn = fn_t));
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t,
+ .next = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t),
+ .default_val = default_cmp));
Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args);
return Texts("List$heap_push_value(", self, ", ", arg_code, ", ", padded_item_size, ")");
} else if (streq(call->name, "heap_pop")) {
EXPECT_POINTER("a", "list");
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)",
- compile_type_info(item_t), "})"),
- .type=Type(ClosureType, .fn=fn_t));
- arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp);
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})"),
+ .type = Type(ClosureType, .fn = fn_t));
+ arg_t *arg_spec =
+ new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t), .default_val = default_cmp);
Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args);
return Texts("List$heap_pop_value(", self, ", ", arg_code, ", ", compile_type(item_t), ", _, ",
- promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")");
+ promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")");
} else if (streq(call->name, "binary_search")) {
self = compile_to_pointer_depth(env, call->self, 0, call->args != NULL);
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- ast_t *default_cmp = LiteralCode(
- Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)",
- compile_type_info(item_t), "})"),
- .type=Type(ClosureType, .fn=fn_t));
- arg_t *arg_spec = new(arg_t, .name="target", .type=item_t,
- .next=new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp));
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})"),
+ .type = Type(ClosureType, .fn = fn_t));
+ arg_t *arg_spec = new (arg_t, .name = "target", .type = item_t,
+ .next = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t),
+ .default_val = default_cmp));
Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args);
return Texts("List$binary_search_value(", self, ", ", arg_code, ")");
} else if (streq(call->name, "clear")) {
@@ -3320,32 +3284,34 @@ Text_t compile(env_t *env, ast_t *ast)
return Texts("List$clear(", self, ")");
} else if (streq(call->name, "find")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t);
- return Texts("List$find_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t);
+ return Texts("List$find_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "where")) {
self = compile_to_pointer_depth(env, call->self, 0, call->args != NULL);
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *predicate_type = Type(
- ClosureType, .fn=NewFunctionType(Type(BoolType), {.name="item", .type=item_ptr}));
- arg_t *arg_spec = new(arg_t, .name="predicate", .type=predicate_type);
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *predicate_type =
+ Type(ClosureType, .fn = NewFunctionType(Type(BoolType), {.name = "item", .type = item_ptr}));
+ arg_t *arg_spec = new (arg_t, .name = "predicate", .type = predicate_type);
return Texts("List$first(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
} else if (streq(call->name, "from")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new(arg_t, .name="first", .type=INT_TYPE);
+ arg_t *arg_spec = new (arg_t, .name = "first", .type = INT_TYPE);
return Texts("List$from(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
} else if (streq(call->name, "to")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new(arg_t, .name="last", .type=INT_TYPE);
+ arg_t *arg_spec = new (arg_t, .name = "last", .type = INT_TYPE);
return Texts("List$to(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
} else if (streq(call->name, "slice")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new(arg_t, .name="first", .type=INT_TYPE, .next=new(arg_t, .name="last", .type=INT_TYPE));
+ arg_t *arg_spec = new (arg_t, .name = "first", .type = INT_TYPE,
+ .next = new (arg_t, .name = "last", .type = INT_TYPE));
return Texts("List$slice(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
} else if (streq(call->name, "by")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new(arg_t, .name="stride", .type=INT_TYPE);
- return Texts("List$by(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")");
+ arg_t *arg_spec = new (arg_t, .name = "stride", .type = INT_TYPE);
+ return Texts("List$by(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ padded_item_size, ")");
} else if (streq(call->name, "reversed")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
(void)compile_arguments(env, ast, NULL, call->args);
@@ -3356,7 +3322,7 @@ Text_t compile(env_t *env, ast_t *ast)
return Texts("Table$from_entries(", self, ", Set$info(", compile_type_info(item_t), "))");
} else if (streq(call->name, "pop")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="index", .type=INT_TYPE, .default_val=FakeAST(Int, "-1"));
+ arg_t *arg_spec = new (arg_t, .name = "index", .type = INT_TYPE, .default_val = FakeAST(Int, "-1"));
Text_t index = compile_arguments(env, ast, arg_spec, call->args);
return Texts("List$pop(", self, ", ", index, ", ", compile_type(item_t), ", _, ",
promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")");
@@ -3370,103 +3336,105 @@ Text_t compile(env_t *env, ast_t *ast)
DeclareMatch(set, self_value_t, SetType);
if (streq(call->name, "has")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="key", .type=set->item_type);
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = set->item_type);
return Texts("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "add")) {
EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new(arg_t, .name="item", .type=set->item_type);
- return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", NULL, ",
- compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = set->item_type);
+ return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ", NULL, ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "add_all")) {
EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new(arg_t, .name="items", .type=Type(ListType, .item_type=Match(self_value_t, SetType)->item_type));
+ arg_t *arg_spec = new (arg_t, .name = "items",
+ .type = Type(ListType, .item_type = Match(self_value_t, SetType)->item_type));
return Texts("({ Table_t *set = ", self, "; ",
- "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
- "for (int64_t i = 0; i < to_add.length; i++)\n"
- "Table$set(set, to_add.data + i*to_add.stride, NULL, ", compile_type_info(self_value_t), ");\n",
- "(void)0; })");
+ "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
+ "for (int64_t i = 0; i < to_add.length; i++)\n"
+ "Table$set(set, to_add.data + i*to_add.stride, NULL, ",
+ compile_type_info(self_value_t), ");\n", "(void)0; })");
} else if (streq(call->name, "remove")) {
EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new(arg_t, .name="item", .type=set->item_type);
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = set->item_type);
return Texts("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "remove_all")) {
EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new(arg_t, .name="items", .type=Type(ListType, .item_type=Match(self_value_t, SetType)->item_type));
+ arg_t *arg_spec = new (arg_t, .name = "items",
+ .type = Type(ListType, .item_type = Match(self_value_t, SetType)->item_type));
return Texts("({ Table_t *set = ", self, "; ",
- "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
- "for (int64_t i = 0; i < to_add.length; i++)\n"
- "Table$remove(set, to_add.data + i*to_add.stride, ", compile_type_info(self_value_t), ");\n",
- "(void)0; })");
+ "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
+ "for (int64_t i = 0; i < to_add.length; i++)\n"
+ "Table$remove(set, to_add.data + i*to_add.stride, ",
+ compile_type_info(self_value_t), ");\n", "(void)0; })");
} else if (streq(call->name, "clear")) {
EXPECT_POINTER("a", "set");
(void)compile_arguments(env, ast, NULL, call->args);
return Texts("Table$clear(", self, ")");
} else if (streq(call->name, "with")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t);
- return Texts("Table$with(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "other", .type = self_value_t);
+ return Texts("Table$with(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "overlap")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t);
- return Texts("Table$overlap(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "other", .type = self_value_t);
+ return Texts("Table$overlap(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "without")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t);
- return Texts("Table$without(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "other", .type = self_value_t);
+ return Texts("Table$without(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "is_subset_of")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t,
- .next=new(arg_t, .name="strict", .type=Type(BoolType), .default_val=FakeAST(Bool, false)));
- return Texts("Table$is_subset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (
+ arg_t, .name = "other", .type = self_value_t,
+ .next = new (arg_t, .name = "strict", .type = Type(BoolType), .default_val = FakeAST(Bool, false)));
+ return Texts("Table$is_subset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "is_superset_of")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t,
- .next=new(arg_t, .name="strict", .type=Type(BoolType), .default_val=FakeAST(Bool, false)));
+ arg_t *arg_spec = new (
+ arg_t, .name = "other", .type = self_value_t,
+ .next = new (arg_t, .name = "strict", .type = Type(BoolType), .default_val = FakeAST(Bool, false)));
return Texts("Table$is_superset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ ", ", compile_type_info(self_value_t), ")");
} else code_err(ast, "There is no '", call->name, "' method for tables");
}
case TableType: {
DeclareMatch(table, self_value_t, TableType);
if (streq(call->name, "get")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type);
- return Texts(
- "Table$get_optional(", self, ", ", compile_type(table->key_type), ", ",
- compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- "_, ", optional_into_nonnone(table->value_type, Text("(*_)")), ", ", compile_none(table->value_type), ", ",
- compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type);
+ return Texts("Table$get_optional(", self, ", ", compile_type(table->key_type), ", ",
+ compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ", ", "_, ", optional_into_nonnone(table->value_type, Text("(*_)")), ", ",
+ compile_none(table->value_type), ", ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "get_or_set")) {
self = compile_to_pointer_depth(env, call->self, 1, false);
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type,
- .next=new(arg_t, .name="default", .type=table->value_type, .default_val=table->default_value));
- return Texts("*Table$get_or_setdefault(",
- self, ", ", compile_type(table->key_type), ", ",
- compile_type(table->value_type), ", ",
- compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type,
+ .next = new (arg_t, .name = "default", .type = table->value_type,
+ .default_val = table->default_value));
+ return Texts("*Table$get_or_setdefault(", self, ", ", compile_type(table->key_type), ", ",
+ compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ", ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "has")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type);
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type);
return Texts("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "set")) {
EXPECT_POINTER("a", "table");
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type,
- .next=new(arg_t, .name="value", .type=table->value_type));
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type,
+ .next = new (arg_t, .name = "value", .type = table->value_type));
return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "remove")) {
EXPECT_POINTER("a", "table");
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type);
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type);
return Texts("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "clear")) {
EXPECT_POINTER("a", "table");
(void)compile_arguments(env, ast, NULL, call->args);
@@ -3477,14 +3445,15 @@ Text_t compile(env_t *env, ast_t *ast)
return Texts("Table$sorted(", self, ", ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "with_fallback")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="fallback", .type=Type(OptionalType, self_value_t));
- return Texts("Table$with_fallback(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
+ arg_t *arg_spec = new (arg_t, .name = "fallback", .type = Type(OptionalType, self_value_t));
+ return Texts("Table$with_fallback(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ")");
} else code_err(ast, "There is no '", call->name, "' method for tables");
}
default: {
DeclareMatch(methodcall, ast, MethodCall);
type_t *fn_t = get_method_type(env, methodcall->self, methodcall->name);
- arg_ast_t *args = new(arg_ast_t, .value=methodcall->self, .next=methodcall->args);
+ arg_ast_t *args = new (arg_ast_t, .value = methodcall->self, .next = methodcall->args);
binding_t *b = get_namespace_binding(env, methodcall->self, methodcall->name);
if (!b) code_err(ast, "No such method");
return Texts(b->code, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, args), ")");
@@ -3501,14 +3470,15 @@ Text_t compile(env_t *env, ast_t *ast)
} else if (fn_t->tag == TypeInfoType) {
type_t *t = Match(fn_t, TypeInfoType)->type;
- // Literal constructors for numeric types like `Byte(123)` should not go through any conversion, just a cast:
+ // Literal constructors for numeric types like `Byte(123)` should
+ // not go through any conversion, just a cast:
if (is_numeric_type(t) && call->args && !call->args->next && call->args->value->tag == Int)
return compile_to_type(env, call->args->value, t);
else if (t->tag == NumType && call->args && !call->args->next && call->args->value->tag == Num)
return compile_to_type(env, call->args->value, t);
- binding_t *constructor = get_constructor(env, t, call->args,
- env->current_type != NULL && type_eq(env->current_type, t));
+ binding_t *constructor =
+ get_constructor(env, t, call->args, env->current_type != NULL && type_eq(env->current_type, t));
if (constructor) {
arg_t *arg_spec = Match(constructor->type, FunctionType)->args;
return Texts(constructor->code, "(", compile_arguments(env, ast, arg_spec, call->args), ")");
@@ -3518,49 +3488,61 @@ Text_t compile(env_t *env, ast_t *ast)
if (t->tag == TextType) {
if (!call->args) code_err(ast, "This constructor needs a value");
if (!type_eq(t, TEXT_TYPE))
- code_err(call->fn, "I don't have a constructor defined for these arguments");
+ code_err(call->fn, "I don't have a constructor defined for "
+ "these arguments");
// Text constructor:
- if (!call->args || call->args->next)
- code_err(call->fn, "This constructor takes exactly 1 argument");
- if (type_eq(actual, t))
- return compile(env, call->args->value);
+ if (!call->args || call->args->next) code_err(call->fn, "This constructor takes exactly 1 argument");
+ if (type_eq(actual, t)) return compile(env, call->args->value);
return expr_as_text(compile(env, call->args->value), actual, Text("no"));
} else if (t->tag == CStringType) {
// C String constructor:
- if (!call->args || call->args->next)
- code_err(call->fn, "This constructor takes exactly 1 argument");
+ if (!call->args || call->args->next) code_err(call->fn, "This constructor takes exactly 1 argument");
if (call->args->value->tag == TextLiteral)
return compile_text_literal(Match(call->args->value, TextLiteral)->text);
else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children == NULL)
return Text("\"\"");
- else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children->next == NULL)
- return compile_text_literal(Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->text);
- return Texts("Text$as_c_string(", expr_as_text(compile(env, call->args->value), actual, Text("no")), ")");
+ else if (call->args->value->tag == TextJoin
+ && Match(call->args->value, TextJoin)->children->next == NULL)
+ return compile_text_literal(
+ Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->text);
+ return Texts("Text$as_c_string(", expr_as_text(compile(env, call->args->value), actual, Text("no")),
+ ")");
} else if (t->tag == StructType) {
DeclareMatch(struct_, t, StructType);
if (!struct_->opaque && is_valid_call(env, struct_->fields, call->args, true)) {
if (env->current_type == NULL || !type_eq(env->current_type, t)) {
for (arg_t *field = struct_->fields; field; field = field->next) {
if (field->name[0] == '_')
- code_err(ast, "This struct can't be initialized directly because it has private fields (starting with underscore).\n"
- "Use a `convert` or `func` to instantiate the type instead.");
+ code_err(ast, "This struct can't be "
+ "initialized directly because it "
+ "has private fields (starting "
+ "with underscore).\n"
+ "Use a `convert` or `func` to "
+ "instantiate the type "
+ "instead.");
}
}
- return Texts("((", compile_type(t), "){",
- compile_arguments(env, ast, struct_->fields, call->args), "})");
+ return Texts("((", compile_type(t), "){", compile_arguments(env, ast, struct_->fields, call->args),
+ "})");
}
}
- code_err(ast, "I could not find a constructor matching these arguments for ", type_to_str(t));
+ code_err(ast,
+ "I could not find a constructor matching these arguments "
+ "for ",
+ type_to_str(t));
} else if (fn_t->tag == ClosureType) {
fn_t = Match(fn_t, ClosureType)->fn;
arg_t *type_args = Match(fn_t, FunctionType)->args;
arg_t *closure_fn_args = NULL;
for (arg_t *arg = Match(fn_t, FunctionType)->args; arg; arg = arg->next)
- closure_fn_args = new(arg_t, .name=arg->name, .type=arg->type, .default_val=arg->default_val, .next=closure_fn_args);
- closure_fn_args = new(arg_t, .name="userdata", .type=Type(PointerType, .pointed=Type(MemoryType)), .next=closure_fn_args);
+ closure_fn_args = new (arg_t, .name = arg->name, .type = arg->type, .default_val = arg->default_val,
+ .next = closure_fn_args);
+ closure_fn_args = new (arg_t, .name = "userdata", .type = Type(PointerType, .pointed = Type(MemoryType)),
+ .next = closure_fn_args);
REVERSE_LIST(closure_fn_args);
- Text_t fn_type_code = compile_type(Type(FunctionType, .args=closure_fn_args, .ret=Match(fn_t, FunctionType)->ret));
+ Text_t fn_type_code =
+ compile_type(Type(FunctionType, .args = closure_fn_args, .ret = Match(fn_t, FunctionType)->ret));
Text_t closure = compile(env, call->fn);
Text_t arg_code = compile_arguments(env, ast, type_args, call->args);
@@ -3568,8 +3550,8 @@ Text_t compile(env_t *env, ast_t *ast)
if (call->fn->tag == Var) {
return Texts("((", fn_type_code, ")", closure, ".fn)(", arg_code, closure, ".userdata)");
} else {
- return Texts("({ Closure_t closure = ", closure, "; ((", fn_type_code, ")closure.fn)(",
- arg_code, "closure.userdata); })");
+ return Texts("({ Closure_t closure = ", closure, "; ((", fn_type_code, ")closure.fn)(", arg_code,
+ "closure.userdata); })");
}
} else {
code_err(call->fn, "This is not a function, it's a ", type_to_str(fn_t));
@@ -3581,27 +3563,30 @@ Text_t compile(env_t *env, ast_t *ast)
if (!type_eq(value_type, Type(ListType, Type(ByteType))))
code_err(value, "This value should be a list of bytes, not a ", type_to_str(value_type));
type_t *t = parse_type_ast(env, Match(ast, Deserialize)->type);
- return Texts("({ ", compile_declaration(t, Text("deserialized")), ";\n"
- "generic_deserialize(", compile(env, value), ", &deserialized, ", compile_type_info(t), ");\n"
- "deserialized; })");
+ return Texts("({ ", compile_declaration(t, Text("deserialized")),
+ ";\n"
+ "generic_deserialize(",
+ compile(env, value), ", &deserialized, ", compile_type_info(t),
+ ");\n"
+ "deserialized; })");
}
case ExplicitlyTyped: {
return compile_to_type(env, Match(ast, ExplicitlyTyped)->ast, get_type(env, ast));
}
case When: {
DeclareMatch(original, ast, When);
- ast_t *when_var = WrapAST(ast, Var, .name="when");
+ ast_t *when_var = WrapAST(ast, Var, .name = "when");
when_clause_t *new_clauses = NULL;
type_t *subject_t = get_type(env, original->subject);
for (when_clause_t *clause = original->clauses; clause; clause = clause->next) {
type_t *clause_type = get_clause_type(env, subject_t, clause);
if (clause_type->tag == AbortType || clause_type->tag == ReturnType) {
- new_clauses = new(when_clause_t, .pattern=clause->pattern, .body=clause->body, .next=new_clauses);
+ new_clauses =
+ new (when_clause_t, .pattern = clause->pattern, .body = clause->body, .next = new_clauses);
} else {
- ast_t *assign = WrapAST(clause->body, Assign,
- .targets=new(ast_list_t, .ast=when_var),
- .values=new(ast_list_t, .ast=clause->body));
- new_clauses = new(when_clause_t, .pattern=clause->pattern, .body=assign, .next=new_clauses);
+ ast_t *assign = WrapAST(clause->body, Assign, .targets = new (ast_list_t, .ast = when_var),
+ .values = new (ast_list_t, .ast = clause->body));
+ new_clauses = new (when_clause_t, .pattern = clause->pattern, .body = assign, .next = new_clauses);
}
}
REVERSE_LIST(new_clauses);
@@ -3609,19 +3594,18 @@ Text_t compile(env_t *env, ast_t *ast)
if (else_body) {
type_t *clause_type = get_type(env, else_body);
if (clause_type->tag != AbortType && clause_type->tag != ReturnType) {
- else_body = WrapAST(else_body, Assign,
- .targets=new(ast_list_t, .ast=when_var),
- .values=new(ast_list_t, .ast=else_body));
+ else_body = WrapAST(else_body, Assign, .targets = new (ast_list_t, .ast = when_var),
+ .values = new (ast_list_t, .ast = else_body));
}
}
type_t *t = get_type(env, ast);
env_t *when_env = fresh_scope(env);
set_binding(when_env, "when", t, Text("when"));
- return Texts(
- "({ ", compile_declaration(t, Text("when")), ";\n",
- compile_statement(when_env, WrapAST(ast, When, .subject=original->subject, .clauses=new_clauses, .else_body=else_body)),
- "when; })");
+ return Texts("({ ", compile_declaration(t, Text("when")), ";\n",
+ compile_statement(when_env, WrapAST(ast, When, .subject = original->subject,
+ .clauses = new_clauses, .else_body = else_body)),
+ "when; })");
}
case If: {
DeclareMatch(if_, ast, If);
@@ -3632,32 +3616,31 @@ Text_t compile(env_t *env, ast_t *ast)
Text_t condition_code;
if (condition->tag == Declare) {
DeclareMatch(decl, condition, Declare);
- if (decl->value == NULL)
- code_err(condition, "This declaration must have a value");
- type_t *condition_type =
- decl->type ? parse_type_ast(env, decl->type)
- : get_type(env, Match(condition, Declare)->value);
+ if (decl->value == NULL) code_err(condition, "This declaration must have a value");
+ type_t *condition_type =
+ decl->type ? parse_type_ast(env, decl->type) : get_type(env, Match(condition, Declare)->value);
if (condition_type->tag != OptionalType)
- code_err(condition, "This `if var := ...:` declaration should be an optional type, not ", type_to_str(condition_type));
+ code_err(condition,
+ "This `if var := ...:` declaration should be an "
+ "optional "
+ "type, not ",
+ type_to_str(condition_type));
- if (is_incomplete_type(condition_type))
- code_err(condition, "This type is incomplete!");
+ if (is_incomplete_type(condition_type)) code_err(condition, "This type is incomplete!");
decl_code = compile_statement(env, condition);
ast_t *var = Match(condition, Declare)->var;
truthy_scope = fresh_scope(env);
bind_statement(truthy_scope, condition);
condition_code = compile_condition(truthy_scope, var);
- set_binding(truthy_scope, Match(var, Var)->name,
- Match(condition_type, OptionalType)->type,
+ set_binding(truthy_scope, Match(var, Var)->name, Match(condition_type, OptionalType)->type,
optional_into_nonnone(condition_type, compile(truthy_scope, var)));
} else if (condition->tag == Var) {
type_t *condition_type = get_type(env, condition);
condition_code = compile_condition(env, condition);
if (condition_type->tag == OptionalType) {
truthy_scope = fresh_scope(env);
- set_binding(truthy_scope, Match(condition, Var)->name,
- Match(condition_type, OptionalType)->type,
+ set_binding(truthy_scope, Match(condition, Var)->name, Match(condition_type, OptionalType)->type,
optional_into_nonnone(condition_type, compile(truthy_scope, condition)));
}
} else {
@@ -3668,16 +3651,17 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *false_type = get_type(falsey_scope, if_->else_body);
if (true_type->tag == AbortType || true_type->tag == ReturnType)
return Texts("({ ", decl_code, "if (", condition_code, ") ", compile_statement(truthy_scope, if_->body),
- "\n", compile(falsey_scope, if_->else_body), "; })");
+ "\n", compile(falsey_scope, if_->else_body), "; })");
else if (false_type->tag == AbortType || false_type->tag == ReturnType)
- return Texts("({ ", decl_code, "if (!(", condition_code, ")) ", compile_statement(falsey_scope, if_->else_body),
- "\n", compile(truthy_scope, if_->body), "; })");
+ return Texts("({ ", decl_code, "if (!(", condition_code, ")) ",
+ compile_statement(falsey_scope, if_->else_body), "\n", compile(truthy_scope, if_->body),
+ "; })");
else if (decl_code.length > 0)
return Texts("({ ", decl_code, "(", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ",
- compile(falsey_scope, if_->else_body), ";})");
+ compile(falsey_scope, if_->else_body), ";})");
else
- return Texts("((", condition_code, ") ? ",
- compile(truthy_scope, if_->body), " : ", compile(falsey_scope, if_->else_body), ")");
+ return Texts("((", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ",
+ compile(falsey_scope, if_->else_body), ")");
}
case Reduction: {
DeclareMatch(reduction, ast, Reduction);
@@ -3685,14 +3669,16 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *iter_t = get_type(env, reduction->iter);
type_t *item_t = get_iterated_type(iter_t);
- if (!item_t) code_err(reduction->iter, "I couldn't figure out how to iterate over this type: ", type_to_str(iter_t));
+ if (!item_t)
+ code_err(reduction->iter, "I couldn't figure out how to iterate over this type: ", type_to_str(iter_t));
static int64_t next_id = 1;
ast_t *item = FakeAST(Var, String("$it", next_id++));
ast_t *body = LiteralCode(Text("{}")); // placeholder
- ast_t *loop = FakeAST(For, .vars=new(ast_list_t, .ast=item), .iter=reduction->iter, .body=body);
+ ast_t *loop = FakeAST(For, .vars = new (ast_list_t, .ast = item), .iter = reduction->iter, .body = body);
env_t *body_scope = for_scope(env, loop);
- if (op == Equals || op == NotEquals || op == LessThan || op == LessThanOrEquals || op == GreaterThan || op == GreaterThanOrEquals) {
+ if (op == Equals || op == NotEquals || op == LessThan || op == LessThanOrEquals || op == GreaterThan
+ || op == GreaterThanOrEquals) {
// Chained comparisons like ==, <, etc.
type_t *item_value_type = item_t;
ast_t *item_value = item;
@@ -3702,36 +3688,34 @@ Text_t compile(env_t *env, ast_t *ast)
item_value_type = get_type(body_scope, reduction->key);
}
- Text_t code = Texts(
- "({ // Reduction:\n",
- compile_declaration(item_value_type, Text("prev")), ";\n"
- "OptionalBool_t result = NONE_BOOL;\n"
- );
-
- ast_t *comparison = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end,
- .tag=op, .__data.Plus.lhs=LiteralCode(Text("prev"), .type=item_value_type), .__data.Plus.rhs=item_value);
- body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts(
- "if (result == NONE_BOOL) {\n"
- " prev = ", compile(body_scope, item_value), ";\n"
- " result = yes;\n"
- "} else {\n"
- " if (", compile(body_scope, comparison), ") {\n",
- " prev = ", compile(body_scope, item_value), ";\n",
- " } else {\n"
- " result = no;\n",
- " break;\n",
- " }\n",
- "}\n")));
+ Text_t code = Texts("({ // Reduction:\n", compile_declaration(item_value_type, Text("prev")),
+ ";\n"
+ "OptionalBool_t result = NONE_BOOL;\n");
+
+ ast_t *comparison = new (ast_t, .file = ast->file, .start = ast->start, .end = ast->end, .tag = op,
+ .__data.Plus.lhs = LiteralCode(Text("prev"), .type = item_value_type),
+ .__data.Plus.rhs = item_value);
+ body->__data.InlineCCode.chunks = new (
+ ast_list_t, .ast = FakeAST(TextLiteral, Texts("if (result == NONE_BOOL) {\n"
+ " prev = ",
+ compile(body_scope, item_value),
+ ";\n"
+ " result = yes;\n"
+ "} else {\n"
+ " if (",
+ compile(body_scope, comparison), ") {\n",
+ " prev = ", compile(body_scope, item_value), ";\n",
+ " } else {\n"
+ " result = no;\n",
+ " break;\n", " }\n", "}\n")));
code = Texts(code, compile_statement(env, loop), "\nresult;})");
return code;
} else if (op == Min || op == Max) {
// Min/max:
Text_t superlative = op == Min ? Text("min") : Text("max");
- Text_t code = Texts(
- "({ // Reduction:\n",
- compile_declaration(item_t, superlative), ";\n"
- "Bool_t has_value = no;\n"
- );
+ Text_t code = Texts("({ // Reduction:\n", compile_declaration(item_t, superlative),
+ ";\n"
+ "Bool_t has_value = no;\n");
Text_t item_code = compile(body_scope, item);
ast_e cmp_op = op == Min ? LessThan : GreaterThan;
@@ -3742,31 +3726,39 @@ Text_t compile(env_t *env, ast_t *ast)
Text_t superlative_key = op == Min ? Text("min_key") : Text("max_key");
code = Texts(code, compile_declaration(key_type, superlative_key), ";\n");
- ast_t *comparison = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end,
- .tag=cmp_op, .__data.Plus.lhs=LiteralCode(Text("key"), .type=key_type),
- .__data.Plus.rhs=LiteralCode(superlative_key, .type=key_type));
-
- body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts(
- compile_declaration(key_type, Text("key")), " = ", compile(key_scope, reduction->key), ";\n",
- "if (!has_value || ", compile(body_scope, comparison), ") {\n"
- " ", superlative, " = ", compile(body_scope, item), ";\n"
- " ", superlative_key, " = key;\n"
- " has_value = yes;\n"
- "}\n")));
+ ast_t *comparison = new (ast_t, .file = ast->file, .start = ast->start, .end = ast->end, .tag = cmp_op,
+ .__data.Plus.lhs = LiteralCode(Text("key"), .type = key_type),
+ .__data.Plus.rhs = LiteralCode(superlative_key, .type = key_type));
+
+ body->__data.InlineCCode.chunks = new (
+ ast_list_t, .ast = FakeAST(TextLiteral, Texts(compile_declaration(key_type, Text("key")), " = ",
+ compile(key_scope, reduction->key), ";\n",
+ "if (!has_value || ", compile(body_scope, comparison),
+ ") {\n"
+ " ",
+ superlative, " = ", compile(body_scope, item),
+ ";\n"
+ " ",
+ superlative_key,
+ " = key;\n"
+ " has_value = yes;\n"
+ "}\n")));
} else {
- ast_t *comparison = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end,
- .tag=cmp_op, .__data.Plus.lhs=item,
- .__data.Plus.rhs=LiteralCode(superlative, .type=item_t));
- body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts(
- "if (!has_value || ", compile(body_scope, comparison), ") {\n"
- " ", superlative, " = ", compile(body_scope, item), ";\n"
- " has_value = yes;\n"
- "}\n")));
+ ast_t *comparison =
+ new (ast_t, .file = ast->file, .start = ast->start, .end = ast->end, .tag = cmp_op,
+ .__data.Plus.lhs = item, .__data.Plus.rhs = LiteralCode(superlative, .type = item_t));
+ body->__data.InlineCCode.chunks = new (
+ ast_list_t, .ast = FakeAST(TextLiteral, Texts("if (!has_value || ", compile(body_scope, comparison),
+ ") {\n"
+ " ",
+ superlative, " = ", compile(body_scope, item),
+ ";\n"
+ " has_value = yes;\n"
+ "}\n")));
}
-
code = Texts(code, compile_statement(env, loop), "\nhas_value ? ", promote_to_optional(item_t, superlative),
- " : ", compile_none(item_t), ";})");
+ " : ", compile_none(item_t), ";})");
return code;
} else {
// Accumulator-style reductions like +, ++, *, etc.
@@ -3777,43 +3769,44 @@ Text_t compile(env_t *env, ast_t *ast)
item_value = reduction->key;
}
- Text_t code = Texts(
- "({ // Reduction:\n",
- compile_declaration(reduction_type, Text("reduction")), ";\n"
- "Bool_t has_value = no;\n"
- );
+ Text_t code = Texts("({ // Reduction:\n", compile_declaration(reduction_type, Text("reduction")),
+ ";\n"
+ "Bool_t has_value = no;\n");
- // For the special case of (or)/(and), we need to early out if we can:
+ // For the special case of (or)/(and), we need to early out if we
+ // can:
Text_t early_out = EMPTY_TEXT;
if (op == Compare) {
if (reduction_type->tag != IntType || Match(reduction_type, IntType)->bits != TYPE_IBITS32)
- code_err(ast, "<> reductions are only supported for Int32 values");
+ code_err(ast, "<> reductions are only supported for Int32 "
+ "values");
} else if (op == And) {
- if (reduction_type->tag == BoolType)
- early_out = Text("if (!reduction) break;");
+ if (reduction_type->tag == BoolType) early_out = Text("if (!reduction) break;");
else if (reduction_type->tag == OptionalType)
early_out = Texts("if (", check_none(reduction_type, Text("reduction")), ") break;");
} else if (op == Or) {
- if (reduction_type->tag == BoolType)
- early_out = Text("if (reduction) break;");
+ if (reduction_type->tag == BoolType) early_out = Text("if (reduction) break;");
else if (reduction_type->tag == OptionalType)
early_out = Texts("if (!", check_none(reduction_type, Text("reduction")), ") break;");
}
- ast_t *combination = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end,
- .tag=op, .__data.Plus.lhs=LiteralCode(Text("reduction"), .type=reduction_type),
- .__data.Plus.rhs=item_value);
- body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts(
- "if (!has_value) {\n"
- " reduction = ", compile(body_scope, item_value), ";\n"
- " has_value = yes;\n"
- "} else {\n"
- " reduction = ", compile(body_scope, combination), ";\n",
- early_out,
- "}\n")));
-
- code = Texts(code, compile_statement(env, loop), "\nhas_value ? ", promote_to_optional(reduction_type, Text("reduction")),
- " : ", compile_none(reduction_type), ";})");
+ ast_t *combination = new (ast_t, .file = ast->file, .start = ast->start, .end = ast->end, .tag = op,
+ .__data.Plus.lhs = LiteralCode(Text("reduction"), .type = reduction_type),
+ .__data.Plus.rhs = item_value);
+ body->__data.InlineCCode.chunks =
+ new (ast_list_t,
+ .ast = FakeAST(TextLiteral, Texts("if (!has_value) {\n"
+ " reduction = ",
+ compile(body_scope, item_value),
+ ";\n"
+ " has_value = yes;\n"
+ "} else {\n"
+ " reduction = ",
+ compile(body_scope, combination), ";\n", early_out, "}\n")));
+
+ code = Texts(code, compile_statement(env, loop), "\nhas_value ? ",
+ promote_to_optional(reduction_type, Text("reduction")), " : ", compile_none(reduction_type),
+ ";})");
return code;
}
}
@@ -3826,7 +3819,9 @@ Text_t compile(env_t *env, ast_t *ast)
DeclareMatch(info, value_t, TypeInfoType);
if (f->field[0] == '_') {
if (!type_eq(env->current_type, info->type))
- code_err(ast, "Fields that start with underscores are not accessible on types outside of the type definition.");
+ code_err(ast, "Fields that start with underscores are not "
+ "accessible "
+ "on types outside of the type definition.");
}
binding_t *b = get_binding(info->env, f->field);
if (!b) code_err(ast, "I couldn't find the field '", f->field, "' on this type");
@@ -3834,7 +3829,7 @@ Text_t compile(env_t *env, ast_t *ast)
return b->code;
}
case TextType: {
- const char *lang = Match(value_t, TextType)->lang;
+ const char *lang = Match(value_t, TextType)->lang;
if (lang && streq(f->field, "text")) {
Text_t text = compile_to_pointer_depth(env, f->fielded, 0, false);
return Texts("((Text_t)", text, ")");
@@ -3885,24 +3880,31 @@ Text_t compile(env_t *env, ast_t *ast)
if (streq(f->field, "items"))
return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
else if (streq(f->field, "length"))
- return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
+ return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").entries.length)");
code_err(ast, "There is no '", f->field, "' field on sets");
}
case TableType: {
if (streq(f->field, "length")) {
- return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
+ return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").entries.length)");
} else if (streq(f->field, "keys")) {
return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
} else if (streq(f->field, "values")) {
DeclareMatch(table, value_t, TableType);
- Text_t offset = Texts("offsetof(struct { ", compile_declaration(table->key_type, Text("k")), "; ", compile_declaration(table->value_type, Text("v")), "; }, v)");
- return Texts("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries;\n"
- "LIST_INCREF(*entries);\n"
- "List_t values = *entries;\n"
- "values.data += ", offset, ";\n"
- "values; })");
+ Text_t offset = Texts("offsetof(struct { ", compile_declaration(table->key_type, Text("k")), "; ",
+ compile_declaration(table->value_type, Text("v")), "; }, v)");
+ return Texts("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").entries;\n"
+ "LIST_INCREF(*entries);\n"
+ "List_t values = *entries;\n"
+ "values.data += ",
+ offset,
+ ";\n"
+ "values; })");
} else if (streq(f->field, "fallback")) {
- return Texts("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false), ").fallback; _fallback ? *_fallback : NONE_TABLE; })");
+ return Texts("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").fallback; _fallback ? *_fallback : NONE_TABLE; })");
}
code_err(ast, "There is no '", f->field, "' field on tables");
}
@@ -3911,8 +3913,7 @@ Text_t compile(env_t *env, ast_t *ast)
env_t *module_env = Table$str_get(*env->imports, name);
return compile(module_env, WrapAST(ast, Var, f->field));
}
- default:
- code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values");
+ default: code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values");
}
}
case Index: {
@@ -3920,7 +3921,9 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *indexed_type = get_type(env, indexing->indexed);
if (!indexing->index) {
if (indexed_type->tag != PointerType)
- code_err(ast, "Only pointers can use the '[]' operator to dereference the entire value.");
+ code_err(ast, "Only pointers can use the '[]' operator to "
+ "dereference "
+ "the entire value.");
DeclareMatch(ptr, indexed_type, PointerType);
if (ptr->pointed->tag == ListType) {
return Texts("*({ List_t *list = ", compile(env, indexing->indexed), "; LIST_INCREF(*list); list; })");
@@ -3939,77 +3942,90 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *item_type = Match(container_t, ListType)->item_type;
Text_t list = compile_to_pointer_depth(env, indexing->indexed, 0, false);
file_t *f = indexing->index->file;
- Text_t index_code = indexing->index->tag == Int
- ? compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64))
- : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, indexing->index), ", no)")
- : Texts("(Int64_t)(", compile(env, indexing->index), ")"));
+ Text_t index_code =
+ indexing->index->tag == Int
+ ? compile_int_to_type(env, indexing->index, Type(IntType, .bits = TYPE_IBITS64))
+ : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, indexing->index), ", no)")
+ : Texts("(Int64_t)(", compile(env, indexing->index), ")"));
if (indexing->unchecked)
return Texts("List_get_unchecked(", compile_type(item_type), ", ", list, ", ", index_code, ")");
else
return Texts("List_get(", compile_type(item_type), ", ", list, ", ", index_code, ", ",
- String((int64_t)(indexing->index->start - f->text)), ", ",
- String((int64_t)(indexing->index->end - f->text)),
- ")");
+ String((int64_t)(indexing->index->start - f->text)), ", ",
+ String((int64_t)(indexing->index->end - f->text)), ")");
} else if (container_t->tag == TableType) {
DeclareMatch(table_type, container_t, TableType);
- if (indexing->unchecked)
- code_err(ast, "Table indexes cannot be unchecked");
+ if (indexing->unchecked) code_err(ast, "Table indexes cannot be unchecked");
if (table_type->default_value) {
- return Texts("Table$get_or_default(",
- compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
- compile_type(table_type->key_type), ", ",
- compile_type(table_type->value_type), ", ",
- compile(env, indexing->index), ", ",
- compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
- compile_type_info(container_t), ")");
+ return Texts("Table$get_or_default(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
+ compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
+ compile(env, indexing->index), ", ",
+ compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
+ compile_type_info(container_t), ")");
} else {
- return Texts("Table$get_optional(",
- compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
- compile_type(table_type->key_type), ", ",
- compile_type(table_type->value_type), ", ",
- compile(env, indexing->index), ", "
- "_, ", promote_to_optional(table_type->value_type, Text("(*_)")), ", ",
- compile_none(table_type->value_type), ", ",
- compile_type_info(container_t), ")");
+ return Texts("Table$get_optional(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
+ compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
+ compile(env, indexing->index),
+ ", "
+ "_, ",
+ promote_to_optional(table_type->value_type, Text("(*_)")), ", ",
+ compile_none(table_type->value_type), ", ", compile_type_info(container_t), ")");
}
} else if (container_t->tag == TextType) {
- return Texts("Text$cluster(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ", compile_to_type(env, indexing->index, Type(BigIntType)), ")");
+ return Texts("Text$cluster(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
+ compile_to_type(env, indexing->index, Type(BigIntType)), ")");
} else {
code_err(ast, "Indexing is not supported for type: ", type_to_str(container_t));
}
}
case InlineCCode: {
type_t *t = get_type(env, ast);
- if (t->tag == VoidType)
- return Texts("{\n", compile_statement(env, ast), "\n}");
- else
- return compile_statement(env, ast);
+ if (t->tag == VoidType) return Texts("{\n", compile_statement(env, ast), "\n}");
+ else return compile_statement(env, ast);
}
case Use: code_err(ast, "Compiling 'use' as expression!");
case Defer: code_err(ast, "Compiling 'defer' as expression!");
case Extern: code_err(ast, "Externs are not supported as expressions");
case TableEntry: code_err(ast, "Table entries should not be compiled directly");
- case Declare: case Assign: case UPDATE_CASES: case For: case While: case Repeat: case StructDef: case LangDef: case Extend:
- case EnumDef: case FunctionDef: case ConvertDef: case Skip: case Stop: case Pass: case Return: case DocTest: case Assert:
- code_err(ast, "This is not a valid expression");
- default: case Unknown: code_err(ast, "Unknown AST: ", ast_to_sexp_str(ast));
+ case Declare:
+ case Assign:
+ case UPDATE_CASES:
+ case For:
+ case While:
+ case Repeat:
+ case StructDef:
+ case LangDef:
+ case Extend:
+ case EnumDef:
+ case FunctionDef:
+ case ConvertDef:
+ case Skip:
+ case Stop:
+ case Pass:
+ case Return:
+ case DocTest:
+ case Assert: code_err(ast, "This is not a valid expression");
+ default:
+ case Unknown: code_err(ast, "Unknown AST: ", ast_to_sexp_str(ast));
}
return EMPTY_TEXT;
}
-Text_t compile_type_info(type_t *t)
-{
+Text_t compile_type_info(type_t *t) {
if (t == NULL) compiler_err(NULL, NULL, NULL, "Attempt to compile a NULL type");
if (t == PATH_TYPE) return Text("&Path$info");
else if (t == PATH_TYPE_TYPE) return Text("&PathType$info");
switch (t->tag) {
- case BoolType: case ByteType: case IntType: case BigIntType: case NumType: case CStringType:
- return Texts("&", type_to_text(t), "$info");
+ case BoolType:
+ case ByteType:
+ case IntType:
+ case BigIntType:
+ case NumType:
+ case CStringType: return Texts("&", type_to_text(t), "$info");
case TextType: {
DeclareMatch(text, t, TextType);
- if (!text->lang || streq(text->lang, "Text"))
- return Text("&Text$info");
+ if (!text->lang || streq(text->lang, "Text")) return Text("&Text$info");
return Texts("(&", namespace_name(text->env, text->env->namespace, Text("$info")), ")");
}
case StructType: {
@@ -4047,20 +4063,18 @@ Text_t compile_type_info(type_t *t)
}
case OptionalType: {
type_t *non_optional = Match(t, OptionalType)->type;
- return Texts("Optional$info(sizeof(", compile_type(non_optional),
- "), __alignof__(", compile_type(non_optional), "), ", compile_type_info(non_optional), ")");
+ return Texts("Optional$info(sizeof(", compile_type(non_optional), "), __alignof__(", compile_type(non_optional),
+ "), ", compile_type_info(non_optional), ")");
}
case TypeInfoType: return Texts("Type$info(", quoted_text(type_to_text(Match(t, TypeInfoType)->type)), ")");
case MemoryType: return Text("&Memory$info");
case VoidType: return Text("&Void$info");
- default:
- compiler_err(NULL, 0, 0, "I couldn't convert to a type info: ", type_to_str(t));
+ default: compiler_err(NULL, 0, 0, "I couldn't convert to a type info: ", type_to_str(t));
}
return EMPTY_TEXT;
}
-static Text_t get_flag_options(type_t *t, const char *separator)
-{
+static Text_t get_flag_options(type_t *t, const char *separator) {
if (t->tag == BoolType) {
return Text("yes|no");
} else if (t->tag == EnumType) {
@@ -4077,8 +4091,7 @@ static Text_t get_flag_options(type_t *t, const char *separator)
}
}
-Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version)
-{
+Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version) {
DeclareMatch(fn_info, fn_type, FunctionType);
env_t *main_env = fresh_scope(env);
@@ -4106,39 +4119,32 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c
if (strlen(arg->name) == 1) {
if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
usage = Texts(usage, "[-", flag, "]");
- else
- usage = Texts(usage, "[-", flag, " ", get_flag_options(t, "|"), "]");
+ else usage = Texts(usage, "[-", flag, " ", get_flag_options(t, "|"), "]");
} else {
if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
usage = Texts(usage, "[--", flag, "]");
- else if (t->tag == ListType)
- usage = Texts(usage, "[--", flag, " ", get_flag_options(t, "|"), "]");
- else
- usage = Texts(usage, "[--", flag, "=", get_flag_options(t, "|"), "]");
+ else if (t->tag == ListType) usage = Texts(usage, "[--", flag, " ", get_flag_options(t, "|"), "]");
+ else usage = Texts(usage, "[--", flag, "=", get_flag_options(t, "|"), "]");
}
} else {
- if (t->tag == BoolType)
- usage = Texts(usage, "<--", flag, "|--no-", flag, ">");
- else if (t->tag == EnumType)
- usage = Texts(usage, get_flag_options(t, "|"));
- else if (t->tag == ListType)
- usage = Texts(usage, "[", flag, "...]");
- else
- usage = Texts(usage, "<", flag, ">");
+ if (t->tag == BoolType) usage = Texts(usage, "<--", flag, "|--no-", flag, ">");
+ else if (t->tag == EnumType) usage = Texts(usage, get_flag_options(t, "|"));
+ else if (t->tag == ListType) usage = Texts(usage, "[", flag, "...]");
+ else usage = Texts(usage, "<", flag, ">");
}
}
- code = Texts(code, "Text_t usage = Texts(Text(\"Usage: \"), Text$from_str(argv[0])",
- usage.length == 0 ? EMPTY_TEXT : Texts(", Text(", quoted_text(usage), ")"), ");\n");
+ code = Texts(code,
+ "Text_t usage = Texts(Text(\"Usage: \"), "
+ "Text$from_str(argv[0])",
+ usage.length == 0 ? EMPTY_TEXT : Texts(", Text(", quoted_text(usage), ")"), ");\n");
}
-
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- type_t *opt_type = arg->type->tag == OptionalType ? arg->type : Type(OptionalType, .type=arg->type);
+ type_t *opt_type = arg->type->tag == OptionalType ? arg->type : Type(OptionalType, .type = arg->type);
code = Texts(code, compile_declaration(opt_type, Texts("_$", arg->name)));
if (arg->default_val) {
Text_t default_val = compile(env, arg->default_val);
- if (arg->type->tag != OptionalType)
- default_val = promote_to_optional(arg->type, default_val);
+ if (arg->type->tag != OptionalType) default_val = promote_to_optional(arg->type, default_val);
code = Texts(code, " = ", default_val);
} else {
code = Texts(code, " = ", compile_none(arg->type));
@@ -4150,17 +4156,15 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c
code = Texts(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code, ", ", version_code);
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
code = Texts(code, ",\n{", quoted_text(Text$replace(Text$from_str(arg->name), Text("_"), Text("-"))), ", ",
- (arg->default_val || arg->type->tag == OptionalType) ? "false" : "true", ", ",
- compile_type_info(arg->type),
- ", &", Texts("_$", arg->name), "}");
+ (arg->default_val || arg->type->tag == OptionalType) ? "false" : "true", ", ",
+ compile_type_info(arg->type), ", &", Texts("_$", arg->name), "}");
}
code = Texts(code, ");\n");
code = Texts(code, fn_name, "(");
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
Text_t arg_code = Texts("_$", arg->name);
- if (arg->type->tag != OptionalType)
- arg_code = optional_into_nonnone(arg->type, arg_code);
+ if (arg->type->tag != OptionalType) arg_code = optional_into_nonnone(arg->type, arg_code);
code = Texts(code, arg_code);
if (arg->next) code = Texts(code, ", ");
@@ -4169,8 +4173,7 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c
return code;
}
-Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *staticdefs)
-{
+Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *staticdefs) {
bool is_private = false;
const char *function_name;
arg_ast_t *args;
@@ -4193,7 +4196,10 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
ret_t = convertdef->ret_type ? parse_type_ast(env, convertdef->ret_type) : Type(VoidType);
function_name = get_type_name(ret_t);
if (!function_name)
- code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t));
+ code_err(ast,
+ "Conversions are only supported for text, struct, and enum "
+ "types, not ",
+ type_to_str(ret_t));
body = convertdef->body;
cache = convertdef->cache;
is_inline = convertdef->is_inline;
@@ -4212,21 +4218,17 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
arg_signature = Texts(arg_signature, ")");
Text_t ret_type_code = compile_type(ret_t);
- if (ret_t->tag == AbortType)
- ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
+ if (ret_t->tag == AbortType) ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
- if (is_private)
- *staticdefs = Texts(*staticdefs, "static ", ret_type_code, " ", name_code, arg_signature, ";\n");
+ if (is_private) *staticdefs = Texts(*staticdefs, "static ", ret_type_code, " ", name_code, arg_signature, ";\n");
Text_t code;
if (cache) {
code = Texts("static ", ret_type_code, " ", name_code, "$uncached", arg_signature);
} else {
code = Texts(ret_type_code, " ", name_code, arg_signature);
- if (is_inline)
- code = Texts("INLINE ", code);
- if (!is_private)
- code = Texts("public ", code);
+ if (is_inline) code = Texts("INLINE ", code);
+ if (!is_private) code = Texts("public ", code);
}
env_t *body_scope = fresh_scope(env);
@@ -4245,72 +4247,92 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
type_t *body_type = get_type(body_scope, body);
if (ret_t->tag == AbortType) {
- if (body_type->tag != AbortType)
- code_err(ast, "This function can reach the end without aborting!");
+ if (body_type->tag != AbortType) code_err(ast, "This function can reach the end without aborting!");
} else if (ret_t->tag == VoidType) {
if (body_type->tag == AbortType)
- code_err(ast, "This function will always abort before it reaches the end, but it's declared as having a Void return. It should be declared as an Abort return instead.");
+ code_err(ast, "This function will always abort before it reaches the "
+ "end, but it's declared as having a Void return. It should "
+ "be declared as an Abort return instead.");
} else {
if (body_type->tag != ReturnType && body_type->tag != AbortType)
- code_err(ast, "This function looks like it can reach the end without returning a ", type_to_str(ret_t), " value! \n "
- "If this is not the case, please add a call to `fail(\"Unreachable\")` at the end of the function to help the compiler out.");
+ code_err(ast,
+ "This function looks like it can reach the end without "
+ "returning a ",
+ type_to_str(ret_t),
+ " value! \n "
+ "If this is not the case, please add a call to "
+ "`fail(\"Unreachable\")` at the end of the function to "
+ "help the "
+ "compiler out.");
}
Text_t body_code = Texts("{\n", compile_inline_block(body_scope, body), "}\n");
Text_t definition = with_source_info(env, ast, Texts(code, " ", body_code, "\n"));
if (cache && args == NULL) { // no-args cache just uses a static var
- Text_t wrapper = Texts(
- is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, "(void) {\n"
- "static ", compile_declaration(ret_t, Text("cached_result")), ";\n",
- "static bool initialized = false;\n",
- "if (!initialized) {\n"
- "\tcached_result = ", name_code, "$uncached();\n",
- "\tinitialized = true;\n",
- "}\n",
- "return cached_result;\n"
- "}\n");
+ Text_t wrapper =
+ Texts(is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code,
+ "(void) {\n"
+ "static ",
+ compile_declaration(ret_t, Text("cached_result")), ";\n", "static bool initialized = false;\n",
+ "if (!initialized) {\n"
+ "\tcached_result = ",
+ name_code, "$uncached();\n", "\tinitialized = true;\n", "}\n",
+ "return cached_result;\n"
+ "}\n");
definition = Texts(definition, wrapper);
} else if (cache && cache->tag == Int) {
assert(args);
OptionalInt64_t cache_size = Int64$parse(Text$from_str(Match(cache, Int)->str), NULL);
Text_t pop_code = EMPTY_TEXT;
if (cache->tag == Int && !cache_size.is_none && cache_size.value > 0) {
- // FIXME: this currently just deletes the first entry, but this should be more like a
- // least-recently-used cache eviction policy or least-frequently-used
+ // FIXME: this currently just deletes the first entry, but this
+ // should be more like a least-recently-used cache eviction policy
+ // or least-frequently-used
pop_code = Texts("if (cache.entries.length > ", String(cache_size.value),
- ") Table$remove(&cache, cache.entries.data + cache.entries.stride*0, table_type);\n");
+ ") Table$remove(&cache, cache.entries.data + "
+ "cache.entries.stride*0, table_type);\n");
}
if (!args->next) {
// Single-argument functions have simplified caching logic
type_t *arg_type = get_arg_ast_type(env, args);
- Text_t wrapper = Texts(
- is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature, "{\n"
- "static Table_t cache = {};\n",
- "const TypeInfo_t *table_type = Table$info(", compile_type_info(arg_type), ", ", compile_type_info(ret_t), ");\n",
- compile_declaration(Type(PointerType, .pointed=ret_t), Text("cached")), " = Table$get_raw(cache, &_$", args->name, ", table_type);\n"
- "if (cached) return *cached;\n",
- compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(_$", args->name, ");\n",
- pop_code,
- "Table$set(&cache, &_$", args->name, ", &ret, table_type);\n"
- "return ret;\n"
- "}\n");
+ Text_t wrapper =
+ Texts(is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature,
+ "{\n"
+ "static Table_t cache = {};\n",
+ "const TypeInfo_t *table_type = Table$info(", compile_type_info(arg_type), ", ",
+ compile_type_info(ret_t), ");\n",
+ compile_declaration(Type(PointerType, .pointed = ret_t), Text("cached")),
+ " = Table$get_raw(cache, &_$", args->name,
+ ", table_type);\n"
+ "if (cached) return *cached;\n",
+ compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(_$", args->name, ");\n",
+ pop_code, "Table$set(&cache, &_$", args->name,
+ ", &ret, table_type);\n"
+ "return ret;\n"
+ "}\n");
definition = Texts(definition, wrapper);
} else {
- // Multi-argument functions use a custom struct type (only defined internally) as a cache key:
+ // Multi-argument functions use a custom struct type (only defined
+ // internally) as a cache key:
arg_t *fields = NULL;
for (arg_ast_t *arg = args; arg; arg = arg->next)
- fields = new(arg_t, .name=arg->name, .type=get_arg_ast_type(env, arg), .next=fields);
+ fields = new (arg_t, .name = arg->name, .type = get_arg_ast_type(env, arg), .next = fields);
REVERSE_LIST(fields);
- type_t *t = Type(StructType, .name=String("func$", get_line_number(ast->file, ast->start), "$args"), .fields=fields, .env=env);
+ type_t *t = Type(StructType, .name = String("func$", get_line_number(ast->file, ast->start), "$args"),
+ .fields = fields, .env = env);
int64_t num_fields = used_names.entries.length;
const char *metamethods = is_packed_data(t) ? "PackedData$metamethods" : "Struct$metamethods";
- Text_t args_typeinfo = Texts("((TypeInfo_t[1]){{.size=sizeof(args), .align=__alignof__(args), .metamethods=", metamethods,
- ", .tag=StructInfo, .StructInfo.name=\"FunctionArguments\", "
- ".StructInfo.num_fields=", String(num_fields),
- ", .StructInfo.fields=(NamedType_t[", String(num_fields), "]){");
+ Text_t args_typeinfo =
+ Texts("((TypeInfo_t[1]){{.size=sizeof(args), "
+ ".align=__alignof__(args), .metamethods=",
+ metamethods,
+ ", .tag=StructInfo, "
+ ".StructInfo.name=\"FunctionArguments\", "
+ ".StructInfo.num_fields=",
+ String(num_fields), ", .StructInfo.fields=(NamedType_t[", String(num_fields), "]){");
Text_t args_type = Text("struct { ");
for (arg_t *f = fields; f; f = f->next) {
args_typeinfo = Texts(args_typeinfo, "{\"", f->name, "\", ", compile_type_info(f->type), "}");
@@ -4325,14 +4347,17 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
all_args = Texts(all_args, "_$", arg->name, arg->next ? Text(", ") : EMPTY_TEXT);
Text_t wrapper = Texts(
- is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature, "{\n"
+ is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature,
+ "{\n"
"static Table_t cache = {};\n",
- args_type, " args = {", all_args, "};\n"
- "const TypeInfo_t *table_type = Table$info(", args_typeinfo, ", ", compile_type_info(ret_t), ");\n",
- compile_declaration(Type(PointerType, .pointed=ret_t), Text("cached")), " = Table$get_raw(cache, &args, table_type);\n"
+ args_type, " args = {", all_args,
+ "};\n"
+ "const TypeInfo_t *table_type = Table$info(",
+ args_typeinfo, ", ", compile_type_info(ret_t), ");\n",
+ compile_declaration(Type(PointerType, .pointed = ret_t), Text("cached")),
+ " = Table$get_raw(cache, &args, table_type);\n"
"if (cached) return *cached;\n",
- compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(", all_args, ");\n",
- pop_code,
+ compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(", all_args, ");\n", pop_code,
"Table$set(&cache, &args, &ret, table_type);\n"
"return ret;\n"
"}\n");
@@ -4348,22 +4373,22 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
text = Texts(text, type_to_text(get_arg_ast_type(env, arg)));
if (arg->next) text = Texts(text, ", ");
}
- if (ret_t && ret_t->tag != VoidType)
- text = Texts(text, "->", type_to_text(ret_t));
+ if (ret_t && ret_t->tag != VoidType) text = Texts(text, "->", type_to_text(ret_t));
text = Texts(text, ")");
return definition;
}
-Text_t compile_top_level_code(env_t *env, ast_t *ast)
-{
+Text_t compile_top_level_code(env_t *env, ast_t *ast) {
if (!ast) return EMPTY_TEXT;
switch (ast->tag) {
case Use: {
// DeclareMatch(use, ast, Use);
// if (use->what == USE_C_CODE) {
- // Path_t path = Path$relative_to(Path$from_str(use->path), Path(".build"));
- // return Texts("#include \"", Path$as_c_string(path), "\"\n");
+ // Path_t path = Path$relative_to(Path$from_str(use->path),
+ // Path(".build")); return Texts("#include \"",
+ // Path$as_c_string(path),
+ // "\"\n");
// }
return EMPTY_TEXT;
}
@@ -4377,31 +4402,32 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast)
bool is_private = decl_name[0] == '_';
if ((decl->value && is_constant(env, decl->value)) || (!decl->value && !has_heap_memory(t))) {
set_binding(env, decl_name, t, full_name);
- return Texts(
- is_private ? "static " : "public ",
- compile_declaration(t, full_name), " = ", val_code, ";\n");
+ return Texts(is_private ? "static " : "public ", compile_declaration(t, full_name), " = ", val_code, ";\n");
} else {
Text_t init_var = namespace_name(env, env->namespace, Texts(decl_name, "$$initialized"));
Text_t checked_access = Texts("check_initialized(", full_name, ", ", init_var, ", \"", decl_name, "\")");
set_binding(env, decl_name, t, checked_access);
Text_t initialized_name = namespace_name(env, env->namespace, Texts(decl_name, "$$initialized"));
- return Texts(
- "static bool ", initialized_name, " = false;\n",
- is_private ? "static " : "public ",
- compile_declaration(t, full_name), ";\n");
+ return Texts("static bool ", initialized_name, " = false;\n", is_private ? "static " : "public ",
+ compile_declaration(t, full_name), ";\n");
}
}
case FunctionDef: {
- Text_t name_code = namespace_name(env, env->namespace, Text$from_str(Match(Match(ast, FunctionDef)->name, Var)->name));
+ Text_t name_code =
+ namespace_name(env, env->namespace, Text$from_str(Match(Match(ast, FunctionDef)->name, Var)->name));
return compile_function(env, name_code, ast, &env->code->staticdefs);
}
case ConvertDef: {
type_t *type = get_function_def_type(env, ast);
const char *name = get_type_name(Match(type, FunctionType)->ret);
if (!name)
- code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(Match(type, FunctionType)->ret));
- Text_t name_code = namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
+ code_err(ast,
+ "Conversions are only supported for text, struct, and enum "
+ "types, not ",
+ type_to_str(Match(type, FunctionType)->ret));
+ Text_t name_code =
+ namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
return compile_function(env, name_code, ast, &env->code->staticdefs);
}
case StructDef: {
@@ -4421,9 +4447,10 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast)
}
case LangDef: {
DeclareMatch(def, ast, LangDef);
- Text_t code = Texts("public const TypeInfo_t ", namespace_name(env, env->namespace, Texts(def->name, "$$info")),
- " = {", String((int64_t)sizeof(Text_t)), ", ", String((int64_t)__alignof__(Text_t)),
- ", .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={", quoted_str(def->name), "}};\n");
+ Text_t code =
+ Texts("public const TypeInfo_t ", namespace_name(env, env->namespace, Texts(def->name, "$$info")), " = {",
+ String((int64_t)sizeof(Text_t)), ", ", String((int64_t)__alignof__(Text_t)),
+ ", .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={", quoted_str(def->name), "}};\n");
env_t *ns_env = namespace_env(env, def->name);
return Texts(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : EMPTY_TEXT);
}
@@ -4433,10 +4460,10 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast)
if (!b || b->type->tag != TypeInfoType)
code_err(ast, "'", extend->name, "' is not the name of any type I recognize.");
env_t *ns_env = Match(b->type, TypeInfoType)->env;
- env_t *extended = new(env_t);
+ env_t *extended = new (env_t);
*extended = *ns_env;
- extended->locals = new(Table_t, .fallback=env->locals);
- extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
+ extended->locals = new (Table_t, .fallback = env->locals);
+ extended->namespace_bindings = new (Table_t, .fallback = env->namespace_bindings);
extended->id_suffix = env->id_suffix;
return compile_top_level_code(extended, extend->body);
}
@@ -4452,8 +4479,7 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast)
}
}
-static void initialize_vars_and_statics(env_t *env, ast_t *ast)
-{
+static void initialize_vars_and_statics(env_t *env, ast_t *ast) {
if (!ast) return;
for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
@@ -4469,13 +4495,10 @@ static void initialize_vars_and_statics(env_t *env, ast_t *ast)
Text_t val_code = compile_declared_value(env, stmt->ast);
if ((decl->value && !is_constant(env, decl->value)) || (!decl->value && has_heap_memory(t))) {
Text_t initialized_name = namespace_name(env, env->namespace, Texts(decl_name, "$$initialized"));
- env->code->variable_initializers = Texts(
- env->code->variable_initializers,
- with_source_info(
- env, stmt->ast,
- Texts(
- full_name, " = ", val_code, ",\n",
- initialized_name, " = true;\n")));
+ env->code->variable_initializers =
+ Texts(env->code->variable_initializers,
+ with_source_info(env, stmt->ast,
+ Texts(full_name, " = ", val_code, ",\n", initialized_name, " = true;\n")));
}
} else if (stmt->ast->tag == StructDef) {
initialize_vars_and_statics(namespace_env(env, Match(stmt->ast, StructDef)->name),
@@ -4498,8 +4521,7 @@ static void initialize_vars_and_statics(env_t *env, ast_t *ast)
}
}
-Text_t compile_file(env_t *env, ast_t *ast)
-{
+Text_t compile_file(env_t *env, ast_t *ast) {
Text_t top_level_code = compile_top_level_code(env, ast);
Text_t includes = EMPTY_TEXT;
Text_t use_imports = EMPTY_TEXT;
@@ -4520,27 +4542,18 @@ Text_t compile_file(env_t *env, ast_t *ast)
initialize_vars_and_statics(env, ast);
const char *name = file_base_name(ast->file->filename);
- return Texts(
- env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
- "#define __SOURCE_FILE__ ", quoted_str(ast->file->filename), "\n",
- "#include <tomo_"TOMO_VERSION"/tomo.h>\n"
- "#include \"", name, ".tm.h\"\n\n",
- includes,
- env->code->local_typedefs, "\n",
- env->code->lambdas, "\n",
- env->code->staticdefs, "\n",
- top_level_code,
- "public void ", namespace_name(env, env->namespace, Text("$initialize")), "(void) {\n",
- "static bool initialized = false;\n",
- "if (initialized) return;\n",
- "initialized = true;\n",
- use_imports,
- env->code->variable_initializers,
- "}\n");
+ return Texts(env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
+ "#define __SOURCE_FILE__ ", quoted_str(ast->file->filename), "\n",
+ "#include <tomo_" TOMO_VERSION "/tomo.h>\n"
+ "#include \"",
+ name, ".tm.h\"\n\n", includes, env->code->local_typedefs, "\n", env->code->lambdas, "\n",
+ env->code->staticdefs, "\n", top_level_code, "public void ",
+ namespace_name(env, env->namespace, Text("$initialize")), "(void) {\n",
+ "static bool initialized = false;\n", "if (initialized) return;\n", "initialized = true;\n",
+ use_imports, env->code->variable_initializers, "}\n");
}
-Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
-{
+Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) {
switch (ast->tag) {
case Use: {
DeclareMatch(use, ast, Use);
@@ -4552,9 +4565,10 @@ Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
module_info_t mod = get_module_info(ast);
glob_t tm_files;
const char *folder = mod.version ? String(mod.name, "_", mod.version) : mod.name;
- if (glob(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0) {
- if (!try_install_module(mod))
- code_err(ast, "Could not find library");
+ if (glob(String(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE,
+ NULL, &tm_files)
+ != 0) {
+ if (!try_install_module(mod)) code_err(ast, "Could not find library");
}
Text_t includes = EMPTY_TEXT;
@@ -4581,8 +4595,7 @@ Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir);
return Texts("#include \"", Path$as_c_string(Path$relative_to(used_path, build_dir)), "\"\n");
}
- default:
- return EMPTY_TEXT;
+ default: return EMPTY_TEXT;
}
}
case StructDef: {
@@ -4595,23 +4608,25 @@ Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
DeclareMatch(def, ast, LangDef);
return Texts(
// Constructor macro:
- "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)),
- "(text) ((", namespace_name(env, env->namespace, Texts(def->name, "$$type")), "){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n"
- "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)),
- "s(...) ((", namespace_name(env, env->namespace, Texts(def->name, "$$type")), ")Texts(__VA_ARGS__))\n"
- "extern const TypeInfo_t ", namespace_name(env, env->namespace, Texts(def->name, Text("$$info"))), ";\n"
- );
+ "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)), "(text) ((",
+ namespace_name(env, env->namespace, Texts(def->name, "$$type")),
+ "){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" "
+ "text})\n"
+ "#define ",
+ namespace_name(env, env->namespace, Text$from_str(def->name)), "s(...) ((",
+ namespace_name(env, env->namespace, Texts(def->name, "$$type")),
+ ")Texts(__VA_ARGS__))\n"
+ "extern const TypeInfo_t ",
+ namespace_name(env, env->namespace, Texts(def->name, Text("$$info"))), ";\n");
}
case Extend: {
return EMPTY_TEXT;
}
- default:
- return EMPTY_TEXT;
+ default: return EMPTY_TEXT;
}
}
-Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast)
-{
+Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast) {
env_t *ns_env = NULL;
ast_t *block = NULL;
switch (ast->tag) {
@@ -4625,10 +4640,10 @@ Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t
DeclareMatch(extend, ast, Extend);
ns_env = namespace_env(env, extend->name);
- env_t *extended = new(env_t);
+ env_t *extended = new (env_t);
*extended = *ns_env;
- extended->locals = new(Table_t, .fallback=env->locals);
- extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
+ extended->locals = new (Table_t, .fallback = env->locals);
+ extended->namespace_bindings = new (Table_t, .fallback = env->namespace_bindings);
extended->id_suffix = env->id_suffix;
ns_env = extended;
@@ -4669,19 +4684,16 @@ Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t
DeclareMatch(decl, ast, Declare);
const char *decl_name = Match(decl->var, Var)->name;
bool is_private = (decl_name[0] == '_');
- if (is_private)
- return EMPTY_TEXT;
+ if (is_private) return EMPTY_TEXT;
type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
- if (t->tag == FunctionType)
- t = Type(ClosureType, t);
+ if (t->tag == FunctionType) t = Type(ClosureType, t);
assert(t->tag != ModuleType);
if (t->tag == AbortType || t->tag == VoidType || t->tag == ReturnType)
code_err(ast, "You can't declare a variable with a ", type_to_str(t), " value");
- return Texts(
- decl->value ? compile_statement_type_header(env, header_path, decl->value) : EMPTY_TEXT,
- "extern ", compile_declaration(t, namespace_name(env, env->namespace, Text$from_str(decl_name))), ";\n");
+ return Texts(decl->value ? compile_statement_type_header(env, header_path, decl->value) : EMPTY_TEXT, "extern ",
+ compile_declaration(t, namespace_name(env, env->namespace, Text$from_str(decl_name))), ";\n");
}
case FunctionDef: {
DeclareMatch(fndef, ast, FunctionDef);
@@ -4698,8 +4710,7 @@ Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t
type_t *ret_t = fndef->ret_type ? parse_type_ast(env, fndef->ret_type) : Type(VoidType);
Text_t ret_type_code = compile_type(ret_t);
- if (ret_t->tag == AbortType)
- ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
+ if (ret_t->tag == AbortType) ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
Text_t name = namespace_name(env, env->namespace, Text$from_str(decl_name));
if (env->namespace && env->namespace->parent && env->namespace->name && streq(decl_name, env->namespace->name))
name = namespace_name(env, env->namespace, Text$from_str(String(get_line_number(ast->file, ast->start))));
@@ -4720,8 +4731,12 @@ Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t
Text_t ret_type_code = compile_type(ret_t);
Text_t name = Text$from_str(get_type_name(ret_t));
if (name.length == 0)
- code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t));
- Text_t name_code = namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
+ code_err(ast,
+ "Conversions are only supported for text, struct, and enum "
+ "types, not ",
+ type_to_str(ret_t));
+ Text_t name_code =
+ namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
return Texts(ret_type_code, " ", name_code, arg_signature, ";\n");
}
default: return EMPTY_TEXT;
@@ -4740,8 +4755,7 @@ typedef struct {
Path_t header_path;
} compile_typedef_info_t;
-static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast)
-{
+static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast) {
if (ast->tag == StructDef) {
DeclareMatch(def, ast, StructDef);
if (def->external) return;
@@ -4762,8 +4776,10 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast)
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
if (!tag->fields) continue;
- Text_t tag_struct = namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$struct"));
- Text_t tag_type = namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$type"));
+ Text_t tag_struct =
+ namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$struct"));
+ Text_t tag_type =
+ namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$type"));
*info->header = Texts(*info->header, "typedef struct ", tag_struct, " ", tag_type, ";\n");
}
} else {
@@ -4773,27 +4789,25 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast)
}
} else if (ast->tag == LangDef) {
DeclareMatch(def, ast, LangDef);
- *info->header = Texts(*info->header, "typedef Text_t ", namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")), ";\n");
+ *info->header = Texts(*info->header, "typedef Text_t ",
+ namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")), ";\n");
}
}
-static void _define_types_and_funcs(compile_typedef_info_t *info, ast_t *ast)
-{
- *info->header = Texts(*info->header,
- compile_statement_type_header(info->env, info->header_path, ast),
- compile_statement_namespace_header(info->env, info->header_path, ast));
+static void _define_types_and_funcs(compile_typedef_info_t *info, ast_t *ast) {
+ *info->header = Texts(*info->header, compile_statement_type_header(info->env, info->header_path, ast),
+ compile_statement_namespace_header(info->env, info->header_path, ast));
}
-Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast)
-{
- Text_t header = Texts(
- "#pragma once\n",
- env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
- "#include <tomo_"TOMO_VERSION"/tomo.h>\n");
+Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast) {
+ Text_t header =
+ Texts("#pragma once\n",
+ env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
+ "#include <tomo_" TOMO_VERSION "/tomo.h>\n");
- compile_typedef_info_t info = {.env=env, .header=&header, .header_path=header_path};
- visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn=(void*)_make_typedefs, &info});
- visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn=(void*)_define_types_and_funcs, &info});
+ compile_typedef_info_t info = {.env = env, .header = &header, .header_path = header_path};
+ visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn = (void *)_make_typedefs, &info});
+ visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn = (void *)_define_types_and_funcs, &info});
header = Texts(header, "void ", namespace_name(env, env->namespace, Text("$initialize")), "(void);\n");
return header;