diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ast.c | 5 | ||||
| -rw-r--r-- | src/compile.c | 83 | ||||
| -rw-r--r-- | src/parse.c | 26 | ||||
| -rw-r--r-- | src/typecheck.c | 26 | ||||
| -rw-r--r-- | src/types.c | 8 |
5 files changed, 101 insertions, 47 deletions
@@ -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; |
