aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-04-04 18:29:09 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-04-04 18:29:09 -0400
commit7b735ab6fc3e0bb368f1ca484168eaefbbe3ce9c (patch)
tree4a7c78bb0967b8fbc1042d901cf0346705d9d0d8 /src
parent0b8074154e2671691050bdb3bcb33245625a056c (diff)
Misc fixes
Diffstat (limited to 'src')
-rw-r--r--src/ast.c5
-rw-r--r--src/compile.c83
-rw-r--r--src/parse.c26
-rw-r--r--src/typecheck.c26
-rw-r--r--src/types.c8
5 files changed, 101 insertions, 47 deletions
diff --git a/src/ast.c b/src/ast.c
index 67b54f9a..8544ebad 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -134,12 +134,13 @@ CORD ast_to_xml(ast_t *ast)
T(Path, "<Path>%s</Path>", data.path)
T(Declare, "<Declare var=\"%r\">%r%r</Declare>", ast_to_xml(data.var), type_ast_to_xml(data.type), ast_to_xml(data.value))
T(Assign, "<Assign><targets>%r</targets><values>%r</values></Assign>", ast_list_to_xml(data.targets), ast_list_to_xml(data.values))
-#define BINOP(name) T(name, "<" #name ">%r %r</" #name ">", data.lhs, data.rhs)
+#define BINOP(name) T(name, "<" #name ">%r %r</" #name ">", ast_to_xml(data.lhs), ast_to_xml(data.rhs))
BINOP(Power) BINOP(PowerUpdate) BINOP(Multiply) BINOP(MultiplyUpdate) BINOP(Divide) BINOP(DivideUpdate) BINOP(Mod) BINOP(ModUpdate)
BINOP(Mod1) BINOP(Mod1Update) BINOP(Plus) BINOP(PlusUpdate) BINOP(Minus) BINOP(MinusUpdate) BINOP(Concat) BINOP(ConcatUpdate)
BINOP(LeftShift) BINOP(LeftShiftUpdate) BINOP(RightShift) BINOP(RightShiftUpdate) BINOP(UnsignedLeftShift) BINOP(UnsignedLeftShiftUpdate)
BINOP(UnsignedRightShift) BINOP(UnsignedRightShiftUpdate) BINOP(And) BINOP(AndUpdate) BINOP(Or) BINOP(OrUpdate)
- BINOP(Xor) BINOP(XorUpdate)
+ BINOP(Xor) BINOP(XorUpdate) BINOP(Compare)
+ BINOP(Equals) BINOP(NotEquals) BINOP(LessThan) BINOP(LessThanOrEquals) BINOP(GreaterThan) BINOP(GreaterThanOrEquals)
#undef BINOP
T(Negative, "<Negative>%r</Negative>", ast_to_xml(data.value))
T(Not, "<Not>%r</Not>", ast_to_xml(data.value))
diff --git a/src/compile.c b/src/compile.c
index d893c674..d618de71 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -552,7 +552,7 @@ static CORD compile_update_assignment(env_t *env, ast_t *ast)
binop->tag = binop_tag(binop->tag);
if (needs_idemotency_fix)
binop->__data.Plus.lhs = WrapAST(update.lhs, InlineCCode, .code="*lhs", .type=lhs_t);
- update_assignment = CORD_all(lhs, " = ", compile_to_type(env, binop, lhs_t));
+ update_assignment = CORD_all(lhs, " = ", compile_to_type(env, binop, lhs_t), ";");
}
if (needs_idemotency_fix)
@@ -1154,7 +1154,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
}
ast_t *update_var = new(ast_t);
- *update_var = *ast;
+ *update_var = *test->expr;
update_var->__data.PlusUpdate.lhs = WrapAST(update.lhs, InlineCCode, .code="(*expr)", .type=lhs_t); // UNSAFE
test_code = CORD_all("({",
compile_declaration(Type(PointerType, lhs_t), "expr"), " = &(", compile_lvalue(env, update.lhs), "); ",
@@ -1855,6 +1855,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
}
}
default:
+ // print("Is discardable: ", ast_to_xml_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 CORD_asprintf("(void)%r;", compile(env, ast));
@@ -1952,6 +1953,10 @@ CORD 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");
+ 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`");
return compile_none(t);
} else if (t->tag == PointerType && (ast->tag == HeapAllocate || ast->tag == StackReference)) {
return compile_typed_allocation(env, ast, t);
@@ -2377,9 +2382,15 @@ static bool string_literal_is_all_ascii(CORD literal)
CORD 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 == NULL)
+ compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
+
if (t == PATH_TYPE) return "NONE_PATH";
else if (t == PATH_TYPE_TYPE) return "((OptionalPathType_t){})";
@@ -2435,7 +2446,7 @@ CORD compile(env_t *env, ast_t *ast)
{
switch (ast->tag) {
case None: {
- code_err(ast, "This 'none' needs to specify what type it is using `none:Type` syntax");
+ code_err(ast, "I can't figure out what this `none`'s type is!");
}
case Bool: return Match(ast, Bool)->b ? "yes" : "no";
case Var: {
@@ -2535,30 +2546,43 @@ CORD compile(env_t *env, ast_t *ast)
type_t *lhs_t = get_type(env, binop.lhs);
type_t *rhs_t = get_type(env, binop.rhs);
type_t *operand_t;
- CORD lhs, rhs;
- if (can_compile_to_type(env, binop.rhs, lhs_t)) {
- lhs = compile(env, binop.lhs);
- rhs = compile_to_type(env, binop.rhs, lhs_t);
+ if (is_numeric_type(lhs_t) && binop.rhs->tag == Int) {
operand_t = lhs_t;
- } else if (can_compile_to_type(env, binop.lhs, rhs_t)) {
- rhs = compile(env, binop.rhs);
- lhs = compile_to_type(env, binop.lhs, rhs_t);
+ } else if (is_numeric_type(rhs_t) && binop.lhs->tag == Int) {
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));
+ switch (compare_precision(lhs_t, rhs_t)) {
+ case NUM_PRECISION_LESS: operand_t = rhs_t; break;
+ case NUM_PRECISION_MORE: operand_t = lhs_t; break;
+ case NUM_PRECISION_EQUAL: operand_t = lhs_t; break;
+ default: {
+ if (can_compile_to_type(env, binop.rhs, lhs_t)) {
+ operand_t = lhs_t;
+ } else if (can_compile_to_type(env, binop.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));
+ }
+ break;
+ }
+ }
}
+ CORD lhs, rhs;
+ lhs = compile_to_type(env, binop.lhs, operand_t);
+ rhs = compile_to_type(env, binop.rhs, operand_t);
+
switch (operand_t->tag) {
case BigIntType:
return CORD_all(ast->tag == Equals ? CORD_EMPTY : "!", "Int$equal_value(", lhs, ", ", rhs, ")");
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, ast->tag == Equals ? " == " : " != ", rhs, ")");
default:
- return CORD_asprintf(ast->tag == Equals ? CORD_EMPTY : "!",
- "generic_equal(stack(%r), stack(%r), %r)", lhs, rhs, compile_type_info(operand_t));
+ return CORD_all(ast->tag == Equals ? CORD_EMPTY : "!",
+ "generic_equal(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")");
}
}
- case LessThan: case LessThanOrEquals: case GreaterThan: case GreaterThanOrEquals: {
+ 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);
@@ -2577,6 +2601,10 @@ CORD compile(env_t *env, ast_t *ast)
code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
}
+ if (ast->tag == Compare)
+ return CORD_all("generic_compare(stack(", lhs, "), stack(", rhs, "), ",
+ compile_type_info(operand_t), ")");
+
const char *op = binop_operator(ast->tag);
switch (operand_t->tag) {
case BigIntType:
@@ -2584,7 +2612,8 @@ CORD compile(env_t *env, ast_t *ast)
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " ", op, " ", rhs, ")");
default:
- return CORD_all("(generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(Type(OptionalType, operand_t)), ") ", op, " 0)");
+ return CORD_all("(generic_compare(stack(", lhs, "), stack(", rhs, "), ",
+ compile_type_info(operand_t), ") ", op, " 0)");
}
}
case TextLiteral: {
@@ -2896,31 +2925,27 @@ CORD compile(env_t *env, ast_t *ast)
compile_type_info(self_value_t), ")");
} else if (streq(call->name, "sample")) {
type_t *random_num_type = parse_type_string(env, "func(->Num)?");
- ast_t *none_rng = parse_expression("none: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(ArrayType, .item_type=Type(NumType)),
+ .next=new(arg_t, .name="weights", .type=Type(ArrayType, .item_type=Type(NumType, .bits=TYPE_NBITS64)),
.default_val=FakeAST(None),
- .next=new(arg_t, .name="random", .type=random_num_type, .default_val=none_rng)));
+ .next=new(arg_t, .name="random", .type=random_num_type, .default_val=FakeAST(None))));
return CORD_all("Array$sample(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
padded_item_size, ")");
} else if (streq(call->name, "shuffle")) {
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
- ast_t *none_rng = parse_expression("none:func(min,max:Int64->Int64)");
EXPECT_POINTER("an", "array");
- arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=none_rng);
+ arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
return CORD_all("Array$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)?");
- ast_t *none_rng = parse_expression("none: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=none_rng);
+ arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
return CORD_all("Array$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)?");
- ast_t *none_rng = parse_expression("none: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=none_rng);
+ arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
return CORD_all("Array$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"))
@@ -3290,10 +3315,16 @@ CORD compile(env_t *env, ast_t *ast)
CORD condition_code;
if (condition->tag == Declare) {
- type_t *condition_type = get_type(env, Match(condition, Declare)->value);
+ auto decl = Match(condition, Declare);
+ 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));
+ 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);
@@ -3632,7 +3663,7 @@ CORD compile(env_t *env, ast_t *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 PrintStatement:
code_err(ast, "This is not a valid expression");
- default: case Unknown: code_err(ast, "Unknown AST");
+ default: case Unknown: code_err(ast, "Unknown AST: ", ast_to_xml_str(ast));
}
}
diff --git a/src/parse.c b/src/parse.c
index 0aa26002..9d4d35ee 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1685,19 +1685,19 @@ PARSER(parse_update) {
if (!lhs) return NULL;
spaces(&pos);
ast_e op;
- if (match(&pos, "+=")) op = Plus;
- else if (match(&pos, "++=")) op = Concat;
- else if (match(&pos, "-=")) op = Minus;
- else if (match(&pos, "*=")) op = Multiply;
- else if (match(&pos, "/=")) op = Divide;
- else if (match(&pos, "^=")) op = Power;
- else if (match(&pos, "<<=")) op = LeftShift;
- else if (match(&pos, "<<<=")) op = UnsignedLeftShift;
- else if (match(&pos, ">>=")) op = RightShift;
- else if (match(&pos, ">>>=")) op = UnsignedRightShift;
- else if (match(&pos, "and=")) op = And;
- else if (match(&pos, "or=")) op = Or;
- else if (match(&pos, "xor=")) op = Xor;
+ if (match(&pos, "+=")) op = PlusUpdate;
+ else if (match(&pos, "++=")) op = ConcatUpdate;
+ else if (match(&pos, "-=")) op = MinusUpdate;
+ else if (match(&pos, "*=")) op = MultiplyUpdate;
+ else if (match(&pos, "/=")) op = DivideUpdate;
+ else if (match(&pos, "^=")) op = PowerUpdate;
+ else if (match(&pos, "<<=")) op = LeftShiftUpdate;
+ else if (match(&pos, "<<<=")) op = UnsignedLeftShiftUpdate;
+ else if (match(&pos, ">>=")) op = RightShiftUpdate;
+ else if (match(&pos, ">>>=")) op = UnsignedRightShiftUpdate;
+ else if (match(&pos, "and=")) op = AndUpdate;
+ else if (match(&pos, "or=")) op = OrUpdate;
+ else if (match(&pos, "xor=")) op = XorUpdate;
else return NULL;
ast_t *rhs = expect(ctx, start, &pos, parse_extended_expr, "I expected an expression here");
return new(ast_t, .file=ctx->file, .start=start, .end=pos, .tag=op, .__data.PlusUpdate.lhs=lhs, .__data.PlusUpdate.rhs=rhs);
diff --git a/src/typecheck.c b/src/typecheck.c
index cd6ff1c2..8d4cc946 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -1163,6 +1163,26 @@ type_t *get_type(env_t *env, ast_t *ast)
code_err(binop.rhs, "I only know how to do bit shifting by integer amounts, not ", type_to_str(rhs_t));
}
+ if (is_numeric_type(lhs_t) && binop.rhs->tag == Int) {
+ return lhs_t;
+ } else if (is_numeric_type(rhs_t) && binop.lhs->tag == Int) {
+ return rhs_t;
+ } else {
+ switch (compare_precision(lhs_t, rhs_t)) {
+ case NUM_PRECISION_LESS: return rhs_t;
+ case NUM_PRECISION_MORE: return lhs_t;
+ case NUM_PRECISION_EQUAL: return lhs_t;
+ default: {
+ if (can_compile_to_type(env, binop.rhs, lhs_t)) {
+ return lhs_t;
+ } else if (can_compile_to_type(env, binop.lhs, rhs_t)) {
+ return rhs_t;
+ }
+ break;
+ }
+ }
+ }
+
type_t *overall_t = (can_promote(rhs_t, lhs_t) ? lhs_t : (can_promote(lhs_t, rhs_t) ? rhs_t : NULL));
if (ast->tag == Multiply || ast->tag == Divide) {
binding_t *b = is_numeric_type(lhs_t) ? get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, lhs_t)
@@ -1588,9 +1608,11 @@ PUREFUNC bool is_constant(env_t *env, ast_t *ast)
PUREFUNC bool can_compile_to_type(env_t *env, ast_t *ast, type_t *needed)
{
- if (needed->tag == OptionalType && ast->tag == None) {
+ if (is_incomplete_type(needed))
+ return false;
+
+ if (needed->tag == OptionalType && ast->tag == None)
return true;
- }
needed = non_optional(needed);
if (needed->tag == ArrayType && ast->tag == Array) {
diff --git a/src/types.c b/src/types.c
index 0b9bc72b..93326b17 100644
--- a/src/types.c
+++ b/src/types.c
@@ -111,6 +111,8 @@ PUREFUNC const char *get_type_name(type_t *t)
bool type_eq(type_t *a, type_t *b)
{
if (a == b) return true;
+ if (!a && !b) return true;
+ if (!a || !b) return false;
if (a->tag != b->tag) return false;
return (CORD_cmp(type_to_cord(a), type_to_cord(b)) == 0);
}
@@ -208,10 +210,8 @@ static PUREFUNC INLINE double type_max_magnitude(type_t *t)
PUREFUNC precision_cmp_e compare_precision(type_t *a, type_t *b)
{
- if (a->tag == OptionalType && Match(a, OptionalType)->type->tag == NumType)
- a = Match(a, OptionalType)->type;
- if (b->tag == OptionalType && Match(b, OptionalType)->type->tag == NumType)
- b = Match(b, OptionalType)->type;
+ if (a == NULL || b == NULL)
+ return NUM_PRECISION_INCOMPARABLE;
if (is_int_type(a) && b->tag == NumType)
return NUM_PRECISION_LESS;