diff options
| -rw-r--r-- | src/compile/binops.c | 11 | ||||
| -rw-r--r-- | src/compile/tables.c | 20 | ||||
| -rw-r--r-- | src/stdlib/tables.c | 16 | ||||
| -rw-r--r-- | src/stdlib/tables.h | 8 | ||||
| -rw-r--r-- | src/typecheck.c | 18 | ||||
| -rw-r--r-- | test/tables.tm | 10 |
6 files changed, 49 insertions, 34 deletions
diff --git a/src/compile/binops.c b/src/compile/binops.c index 0bff98c0..acf1e031 100644 --- a/src/compile/binops.c +++ b/src/compile/binops.c @@ -160,8 +160,6 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { return Texts("(", lhs, " + ", rhs, ")"); } case Minus: { - if (overall_t->tag == TableType) - return Texts("Table$minus(", 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 " @@ -204,8 +202,6 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { 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, ")"); - else if (overall_t->tag == TableType) - return Texts("Table$and(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); else code_err(ast, "The 'and' operator isn't supported between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t), " values"); @@ -218,8 +214,6 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { return Texts("(", lhs, " || ", rhs, ")"); } else if (overall_t->tag == IntType || overall_t->tag == ByteType) { return Texts("(", lhs, " | ", rhs, ")"); - } else if (overall_t->tag == TableType) { - return Texts("Table$or(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); } else { code_err(ast, "The 'or' operator isn't supported between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t), " values"); @@ -229,8 +223,6 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { // TODO: support optional values in `xor` expressions if (overall_t->tag == BoolType || overall_t->tag == IntType || overall_t->tag == ByteType) return Texts("(", lhs, " ^ ", rhs, ")"); - else if (overall_t->tag == TableType) - return Texts("Table$xor(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); else code_err(ast, "The 'xor' operator isn't supported between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t), " values"); @@ -245,6 +237,9 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { return Texts("List$concat(", lhs, ", ", rhs, ", sizeof(", compile_type(Match(overall_t, ListType)->item_type), "))"); } + case TableType: { + return Texts("Table$with(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); + } default: code_err(ast, "Concatenation isn't supported between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t), " values"); diff --git a/src/compile/tables.c b/src/compile/tables.c index b6efdecd..814d81f5 100644 --- a/src/compile/tables.c +++ b/src/compile/tables.c @@ -139,5 +139,25 @@ Text_t compile_table_method_call(env_t *env, ast_t *ast) { 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), ")"); + } else if (streq(call->name, "intersection")) { + 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$intersection(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + compile_type_info(self_value_t), ")"); + } 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), ")"); + } 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), ")"); + } else if (streq(call->name, "difference")) { + 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$difference(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + compile_type_info(self_value_t), ")"); } else code_err(ast, "There is no '", call->name, "' method for tables"); } diff --git a/src/stdlib/tables.c b/src/stdlib/tables.c index bda55375..6698dea3 100644 --- a/src/stdlib/tables.c +++ b/src/stdlib/tables.c @@ -577,9 +577,9 @@ Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) { return t; } -// And is "set intersection" in formal terms +// "set intersection" in formal terms public -Table_t Table$and(Table_t a, Table_t b, const TypeInfo_t *type) { +Table_t Table$intersection(Table_t a, Table_t b, const TypeInfo_t *type) { // Return a table such that t[k]==a[k] for all k such that a.has(k), b.has(k), and a[k]==b[k] Table_t result = {}; const size_t offset = value_offset(type); @@ -595,9 +595,9 @@ Table_t Table$and(Table_t a, Table_t b, const TypeInfo_t *type) { return result; } -// Or is "set union" in formal terms +// "set union" in formal terms public -Table_t Table$or(Table_t a, Table_t b, const TypeInfo_t *type) { +Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type) { // return a table such that t[k]==b[k] for all k such that b.has(k), and t[k]==a[k] for all k such that a.has(k) and // not b.has(k) Table_t result = {}; @@ -617,9 +617,9 @@ Table_t Table$or(Table_t a, Table_t b, const TypeInfo_t *type) { return result; } -// Xor is "disjunctive union" or "symmetric difference" in formal terms +// "disjunctive union" or "symmetric difference" in formal terms public -Table_t Table$xor(Table_t a, Table_t b, const TypeInfo_t *type) { +Table_t Table$difference(Table_t a, Table_t b, const TypeInfo_t *type) { // return a table with elements in `a` or `b`, but not both Table_t result = {}; const size_t offset = value_offset(type); @@ -638,9 +638,9 @@ Table_t Table$xor(Table_t a, Table_t b, const TypeInfo_t *type) { return result; } -// Minus is "set difference" in formal terms +// "without" is "set difference" in formal terms public -Table_t Table$minus(Table_t a, Table_t b, const TypeInfo_t *type) { +Table_t Table$without(Table_t a, Table_t b, const TypeInfo_t *type) { // Return a table such that t[k]==a[k] for all k such that not b.has(k) or b[k] != a[k] Table_t result = {}; const size_t offset = value_offset(type); diff --git a/src/stdlib/tables.h b/src/stdlib/tables.h index 4364530a..f4870f80 100644 --- a/src/stdlib/tables.h +++ b/src/stdlib/tables.h @@ -91,10 +91,10 @@ void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type); Table$remove(t, &k, type); \ }) -Table_t Table$and(Table_t a, Table_t b, const TypeInfo_t *type); -Table_t Table$or(Table_t a, Table_t b, const TypeInfo_t *type); -Table_t Table$minus(Table_t a, Table_t b, const TypeInfo_t *type); -Table_t Table$xor(Table_t a, Table_t b, const TypeInfo_t *type); +Table_t Table$intersection(Table_t a, Table_t b, const TypeInfo_t *type); +Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type); +Table_t Table$without(Table_t a, Table_t b, const TypeInfo_t *type); +Table_t Table$difference(Table_t a, Table_t b, const TypeInfo_t *type); Table_t Table$with_fallback(Table_t t, OptionalTable_t fallback); void Table$clear(Table_t *t); diff --git a/src/typecheck.c b/src/typecheck.c index 6cd87289..0f720faa 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -1033,6 +1033,10 @@ type_t *get_type(env_t *env, ast_t *ast) { else if (streq(call->name, "set")) return Type(VoidType); else if (streq(call->name, "sorted")) return self_value_t; else if (streq(call->name, "with_fallback")) return self_value_t; + else if (streq(call->name, "without")) return self_value_t; + else if (streq(call->name, "intersection")) return self_value_t; + else if (streq(call->name, "difference")) return self_value_t; + else if (streq(call->name, "with")) return self_value_t; code_err(ast, "There is no '", call->name, "' method for ", type_to_text(self_value_t), " tables"); } default: { @@ -1152,9 +1156,6 @@ type_t *get_type(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 *lhs_val = value_type(lhs_t), *rhs_val = value_type(rhs_t); - if (type_eq(lhs_val, rhs_val) && lhs_val->tag == TableType) return lhs_val; - if (binop.lhs->tag == Int && is_int_type(rhs_t)) return rhs_t; else if (binop.rhs->tag == Int && is_int_type(lhs_t)) return lhs_t; @@ -1198,9 +1199,6 @@ type_t *get_type(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 *lhs_val = value_type(lhs_t), *rhs_val = value_type(rhs_t); - if (type_eq(lhs_val, rhs_val) && lhs_val->tag == TableType) return lhs_val; - if (binop.lhs->tag == Int && is_int_type(rhs_t)) return rhs_t; else if (binop.rhs->tag == Int && is_int_type(lhs_t)) return lhs_t; @@ -1231,9 +1229,6 @@ type_t *get_type(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 *lhs_val = value_type(lhs_t), *rhs_val = value_type(rhs_t); - if (type_eq(lhs_val, rhs_val) && lhs_val->tag == TableType) return lhs_val; - if (binop.lhs->tag == Int && is_int_type(rhs_t)) return rhs_t; else if (binop.rhs->tag == Int && is_int_type(lhs_t)) return lhs_t; @@ -1291,11 +1286,6 @@ type_t *get_type(env_t *env, ast_t *ast) { type_t *lhs_t = get_type(env, binop.lhs); type_t *rhs_t = get_type(env, binop.rhs); - if (ast->tag == Minus) { - type_t *lhs_val = value_type(lhs_t), *rhs_val = value_type(rhs_t); - if (type_eq(lhs_val, rhs_val) && lhs_val->tag == TableType) return lhs_val; - } - if (ast->tag == LeftShift || ast->tag == UnsignedLeftShift || ast->tag == RightShift || ast->tag == UnsignedRightShift) { if (!is_int_type(rhs_t)) diff --git a/test/tables.tm b/test/tables.tm index 7b1ac22c..2eb1409e 100644 --- a/test/tables.tm +++ b/test/tables.tm @@ -77,3 +77,13 @@ func main() assert counter.has("y") == no >> counter["y"] += 1 + + do + # Set operations + a := {"A":1, "B":2, "C":3} + b := {"B":2, "C":30, "D":40} + assert a.with(b) == {"A":1, "B":2, "C":30, "D":40} + assert a.with(b) == a ++ b + assert a.intersection(b) == {"B":2} + assert a.difference(b) == {"A":1, "D":40} + assert a.without(b) == {"A":1, "C":3} |
