From c4e83faa576bdb05c0f4b420ad78640ae1945458 Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Wed, 26 Feb 2020 15:15:38 +1100 Subject: [PATCH] compiler: allow a type to be used as a variant of multiple sum types --- vlib/compiler/aparser.v | 17 +++++++++-------- vlib/compiler/expression.v | 13 +++++-------- vlib/compiler/if_match.v | 2 +- vlib/compiler/table.v | 9 +++++---- vlib/compiler/tests/type_test.v | 21 +++++++++++++++++++-- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/vlib/compiler/aparser.v b/vlib/compiler/aparser.v index 01b673fe0d..c139e019d3 100644 --- a/vlib/compiler/aparser.v +++ b/vlib/compiler/aparser.v @@ -850,6 +850,7 @@ fn (p mut Parser) type_decl() { mut idx := 0 mut done := false mut ctype_names := []string + mut sum_variants := []string for { // p.tok == .pipe { idx++ @@ -862,14 +863,17 @@ fn (p mut Parser) type_decl() { if p.pass == .main { // Update the type's parent // println('child=$child_type_name parent=$name') - mut t := p.find_type(child_type_name) + t := p.find_type(child_type_name) if t.name == '' { p.error('unknown type `$child_type_name`') } - t.parent = name - p.table.rewrite_type(t) - p.cgen.consts << '#define SumType_$child_type_name $idx // DEF2' + p.cgen.consts << '#define SumType_${name}_$child_type_name $idx // DEF2' ctype_names << child_type_name + sum_variants << if p.mod in ['builtin', 'main'] || child_type_name in builtin_types { + child_type_name + } else { + p.prepend_mod(child_type_name) + } } if done { break @@ -882,10 +886,7 @@ fn (p mut Parser) type_decl() { // p.fgen_nl() } } - if p.pass == .decl { - p.table.sum_types << name - // println(p.table.sum_types) - } + p.table.sum_types[name] = sum_variants // Register the actual sum type // println('registering sum $name') p.table.register_type(Type{ diff --git a/vlib/compiler/expression.v b/vlib/compiler/expression.v index ade220f44b..cf1cb2a642 100644 --- a/vlib/compiler/expression.v +++ b/vlib/compiler/expression.v @@ -66,11 +66,10 @@ fn (p mut Parser) bool_expression() string { // e.g. `return InfixExpr{}` in a function expecting `Expr` if expected != typ && expected in p.table.sum_types { // TODO perf //p.warn('SUM CAST exp=$expected typ=$typ p.exp=$p.expected_type') - T := p.table.find_type(typ) - if T.parent == expected { + if typ in p.table.sum_types[expected] { p.cgen.set_placeholder(start_ph, '/*SUM TYPE CAST2*/ ($expected) { .obj = memdup( &($typ[]) { ') tt := typ.all_after('_') // TODO - p.gen('}, sizeof($typ) ), .typ = SumType_${tt} }')//${val}_type }') + p.gen('}, sizeof($typ) ), .typ = SumType_${expected}_${tt} }')//${val}_type }') } } // `as` cast @@ -90,10 +89,8 @@ fn (p mut Parser) key_as(typ string, start_ph int) string { p.error('casting `$typ` to `$cast_typ` is not needed') } if typ in p.table.sum_types { - T := p.table.find_type(cast_typ) - if T.parent != typ { - p.error('cannot cast `$typ` to `$cast_typ`. `$cast_typ` is not a variant of `$typ`' + - 'parent=$T.parent') + if !(cast_typ in p.table.sum_types[typ]) { + p.error('cannot cast `$typ` to `$cast_typ`. `$cast_typ` is not a variant of `$typ`') } p.cgen.set_placeholder(start_ph, '*($cast_typ*)') p.gen('.obj') @@ -102,7 +99,7 @@ fn (p mut Parser) key_as(typ string, start_ph int) string { sum_type:= p.cgen.cur_line.all_after('*) (').replace('.obj', '.typ') n := cast_typ.all_after('__') - p.cgen.insert_before('if (($sum_type != SumType_$n) { + p.cgen.insert_before('if (($sum_type != SumType_${typ}_$n) { puts("runtime error: $p.file_name:$p.scanner.line_nr cannot cast sum type `$typ` to `$n`"); exit(1); } diff --git a/vlib/compiler/if_match.v b/vlib/compiler/if_match.v index 04c3200f0e..3f0a6004c0 100644 --- a/vlib/compiler/if_match.v +++ b/vlib/compiler/if_match.v @@ -140,7 +140,7 @@ fn (p mut Parser) match_statement(is_expr bool) string { if is_sum_type { sum_child_type = p.get_type2().name tt := sum_child_type.all_after('_') - p.gen('SumType_$tt') + p.gen('SumType_${typ}_$tt') // println('got child $sum_child_type') p.register_var(Var{ name: 'it' diff --git a/vlib/compiler/table.v b/vlib/compiler/table.v index 87fa93cecd..58cb29095c 100644 --- a/vlib/compiler/table.v +++ b/vlib/compiler/table.v @@ -21,8 +21,8 @@ pub mut: // names []Name max_field_len map[string]int // for vfmt: max_field_len['Parser'] == 12 generic_struct_params map[string][]string - tuple_variants map[string][]string // enum( Bool(BoolExpr) ) - sum_types []string + tuple_variants map[string][]string // enum( Bool(BoolExpr) ) + sum_types map[string][]string // SumType -> [Variants] } struct VargAccess { @@ -191,6 +191,8 @@ const ( float_types = ['f32', 'f64'] reserved_type_param_names = ['R', 'S', 'T', 'U', 'W'] pointer_types = ['byte*', 'byteptr', 'char*', 'charptr', 'void*', 'voidptr', 'voidptr*', 'intptr'] + builtin_types = ['int', 'i8', 'char', 'byte', 'i16', 'u16', 'u32', 'i64', 'u64', + 'f64', 'f32', 'byteptr', 'charptr', 'voidptr', 'intptr', 'string', 'ustring'] ) fn is_number_type(typ string) bool { @@ -745,8 +747,7 @@ fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool { // Sum type if expected in p.table.sum_types { //println('checking sum') - child := p.table.find_type(got) - if child.parent == expected { + if got in p.table.sum_types[expected] { //println('yep $expected') return true } diff --git a/vlib/compiler/tests/type_test.v b/vlib/compiler/tests/type_test.v index fc14fe6ef7..48a9761190 100644 --- a/vlib/compiler/tests/type_test.v +++ b/vlib/compiler/tests/type_test.v @@ -20,7 +20,9 @@ fn test_person_str() { struct Foo {} -type Expr = Foo | BoolExpr | BinExpr | UnaryExpr +type Expr = Foo | BoolExpr | BinExpr | UnaryExpr | DeclExprA | DeclExprB + +type DeclExpr = DeclExprA | DeclExprB struct BoolExpr { foo int @@ -31,6 +33,14 @@ struct BinExpr { name string } +struct DeclExprA { + name string +} + +struct DeclExprB { + name string +} + fn expr1() Expr { mut e := Expr{} e = BinExpr{'binexpr'} @@ -46,11 +56,14 @@ struct UnaryExpr { } - fn handle_expr(e Expr) { } +fn handle_decl_expr(de DeclExpr) { + +} + fn parse_bool() BoolExpr { return BoolExpr{} } @@ -64,6 +77,10 @@ fn test_sum_type_cast() { fn test_sum_types() { b := parse_bool() handle_expr(b) + + de := DeclExprA{} + handle_expr(de) + handle_decl_expr(de) } /*