diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index b447463116..563eec7330 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -641,6 +641,8 @@ pub: pub struct TypeOf { pub: expr Expr +mut: + expr_type table.Type } pub struct LineComment { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index e7f79c2675..177a8ad44b 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -779,6 +779,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type { return it.typ } ast.TypeOf { + it.expr_type = c.expr(it.expr) return table.string_type } /* diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 2f5c539377..bc01fc35a1 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -107,12 +107,34 @@ pub fn (g mut Gen) init() { g.definitions.writeln('\nstring _STR_TMP(const char*, ...);\n') g.write_builtin_types() g.write_typedef_types() + g.write_typeof_functions() g.write_str_definitions() g.write_sorted_types() g.write_multi_return_types() g.definitions.writeln('// end of definitions #endif') } +pub fn (g mut Gen) write_typeof_functions() { + g.writeln('// >> typeof() support for sum types') + for typ in g.table.types { + if typ.kind == .sum_type { + sum_info := typ.info as table.SumType + tidx := g.table.find_type_idx( typ.name ) + g.writeln('char * v_typeof_sumtype_${tidx}(int sidx) { /* ${typ.name} */ ') + g.writeln(' switch(sidx) {') + g.writeln(' case $tidx: return "$typ.name";') + for v in sum_info.variants { + subtype := g.table.get_type_symbol(v) + g.writeln(' case $v: return "$subtype.name";') + } + g.writeln(' default: return "unknown ${typ.name}";') + g.writeln(' }') + g.writeln('}') + } + } + g.writeln('// << typeof() support for sum types') +} + // V type to C type pub fn (g mut Gen) typ(t table.Type) string { nr_muls := table.type_nr_muls(t) @@ -188,7 +210,7 @@ pub fn (g mut Gen) write_typedef_types() { else { continue } - } + } } } @@ -772,7 +794,7 @@ fn (g mut Gen) free_scope_vars(pos int) { else { g.writeln('// other ' + t) } - } + } g.writeln('string_free($var.name); // autofreed') } } @@ -1165,7 +1187,7 @@ fn (g mut Gen) expr(node ast.Expr) { g.write('$type_idx /* $sym.name */') } ast.TypeOf { - g.write('tos3("TYPEOF_TODO")') + g.typeof_expr(it) } else { // #printf("node=%d\n", node.typ); @@ -1174,6 +1196,20 @@ fn (g mut Gen) expr(node ast.Expr) { } } +fn (g mut Gen) typeof_expr(node ast.TypeOf) { + sym := g.table.get_type_symbol(node.expr_type) + if sym.kind == .sum_type { + // When encountering a .sum_type, typeof() should be done at runtime, + // because the subtype of the expression may change: + sum_type_idx := table.type_idx( node.expr_type ) + g.write('tos3( /* ${sym.name} */ v_typeof_sumtype_${sum_type_idx}( (') + g.expr(node.expr) + g.write(').typ ))') + }else{ + g.write('tos3("${sym.name}")') + } +} + fn (g mut Gen) infix_expr(node ast.InfixExpr) { // println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr') // g.write('/*infix*/') diff --git a/vlib/v/tests/typeof_simple_types_test.v b/vlib/v/tests/typeof_simple_types_test.v new file mode 100644 index 0000000000..e1f2a8701d --- /dev/null +++ b/vlib/v/tests/typeof_simple_types_test.v @@ -0,0 +1,66 @@ +struct Abc { + x int +} + +struct Xyz { + y int +} + +struct XxYyZz { + y int +} + +type MySumType = Abc | Xyz + +type AnotherSumType = XxYyZz | int + +type SuperSumType = MySumType | AnotherSumType | string + +fn test_typeof_for_builtin_int_types() { + assert typeof(1) == 'int' + assert typeof(i64(1)) == 'i64' + assert typeof(u32(1)) == 'u32' + assert typeof(u64(1)) == 'u64' +} + +fn test_typeof_for_builtin_float_types() { + assert typeof(f32(1.0)) == 'f32' + assert typeof(1.0) == 'f64' +} + +fn test_typeof_for_builtin_string_type() { + assert typeof('abc') == 'string' + assert typeof('/v/nv/vlib/v/tests/typeof_simple_types_test.v') == 'string' + assert typeof('22') == 'string' +} + +fn test_typeof_for_structs() { + assert typeof(Abc{}) == 'Abc' + assert typeof(Xyz{}) == 'Xyz' +} + +// +fn mysumtype_typeof(x MySumType) string { + return typeof(x) +} + +fn test_typeof_for_sumtypes() { + z_abc := Abc{} + z_xyz := Xyz{} + assert mysumtype_typeof(z_abc) == 'Abc' + assert mysumtype_typeof(z_xyz) == 'Xyz' +} + +// +fn supersumtype_typeof(x SuperSumType) string { + return typeof(x) +} + +fn mst(x MySumType) MySumType { + return x +} + +fn test_typeof_for_sumtypes_of_sumtypes() { + assert supersumtype_typeof('abc') == 'string' + assert supersumtype_typeof(mst(Abc{})) == 'MySumType' +}