diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index d1494eaa76..1bbaf2692e 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -584,7 +584,16 @@ fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) { size_str = 'BYTE' } else { - g.n_error('unsupported type for mov_reg_to_var') + ts := g.table.sym(typ.idx()) + if ts.info is ast.Enum { + if is_extended_register { + g.write8(0x44) + } + g.write8(0x89) + size_str = 'DWORD' + } else { + g.n_error('unsupported type for mov_reg_to_var') + } } } far_var_offset := if is_far_var { 0x40 } else { 0 } @@ -2265,7 +2274,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { }) } } - if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx { + if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx + && g.table.sym(node.left_type).info !is ast.Enum { g.n_error('unsupported type for `$node.op`: $node.left_type') } // left: rax, right: rdx @@ -2467,17 +2477,9 @@ fn (mut g Gen) gen_asm_stmt_amd64(asm_node ast.AsmStmt) { fn (mut g Gen) gen_assert(assert_node ast.AssertStmt) { mut cjmp_addr := 0 - mut ine := ast.InfixExpr{} ane := assert_node.expr - if ane is ast.ParExpr { // assert(1==1) - ine = ane.expr as ast.InfixExpr - } else if ane is ast.InfixExpr { // assert 1==1 - ine = ane - } else { - g.n_error('Unsupported expression in assert') - } label := g.labels.new_label() - cjmp_addr = g.condition(ine, true) + cjmp_addr = g.condition(ane, true) g.labels.patches << LabelPatch{ id: label pos: cjmp_addr diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 123d073012..107e881d04 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -11,6 +11,7 @@ import v.mathutil as mu import v.token import v.errors import v.pref +import v.eval import term import strconv @@ -53,6 +54,8 @@ mut: defer_stmts []ast.DeferStmt builtins map[string]BuiltinFn structs []Struct + eval eval.Eval + enum_vals map[string]Enum // macho specific macho_ncmds int macho_cmdsize int @@ -107,6 +110,11 @@ mut: offsets []int } +struct Enum { +mut: + fields map[string]int +} + enum Size { _8 _16 @@ -217,11 +225,13 @@ pub fn gen(files []&ast.File, table &ast.Table, out_name string, pref &pref.Pref } labels: 0 structs: []Struct{len: table.type_symbols.len} + eval: eval.new_eval(table, pref) } g.code_gen.g = g g.generate_header() g.init_builtins() g.calculate_all_size_align() + g.calculate_enum_fields() for file in files { /* if file.warnings.len > 0 { @@ -330,6 +340,25 @@ pub fn (mut g Gen) calculate_all_size_align() { } } +pub fn (mut g Gen) calculate_enum_fields() { + for name, decl in g.table.enum_decls { + mut enum_vals := Enum{} + mut value := if decl.is_flag { 1 } else { 0 } + for field in decl.fields { + if field.has_expr { + value = int(g.eval.expr(field.expr, ast.int_type_idx).int_val()) + } + enum_vals.fields[field.name] = value + if decl.is_flag { + value <<= 1 + } else { + value++ + } + } + g.enum_vals[name] = enum_vals + } +} + pub fn (mut g Gen) stmts(stmts []ast.Stmt) { for stmt in stmts { g.stmt(stmt) @@ -496,13 +525,17 @@ fn (mut g Gen) get_type_size(typ ast.Type) int { } } size = (size + align - 1) / align * align + g.structs[typ.idx()] = strc + } + ast.Enum { + size = 4 + align = 4 } else {} } mut ts_ := g.table.sym(typ) ts_.size = size ts_.align = align - g.structs[typ.idx()] = strc // g.n_error('unknown type size') return size } @@ -1138,6 +1171,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { } ast.Import {} // do nothing here ast.StructDecl {} + ast.EnumDecl {} else { eprintln('native.stmt(): bad node: ' + node.type_name()) } @@ -1235,6 +1269,9 @@ fn (mut g Gen) expr(node ast.Expr) { ast.Struct { g.lea_var_to_reg(.rax, g.get_var_offset(node.name)) } + ast.Enum { + g.mov_var_to_reg(.rax, node as ast.Ident, typ: ast.int_type_idx) + } else { g.n_error('Unsupported variable type') } @@ -1289,6 +1326,10 @@ fn (mut g Gen) expr(node ast.Expr) { g.add(.rax, offset) g.mov_deref(.rax, .rax, node.typ) } + ast.EnumVal { + type_name := g.table.get_type_name(node.typ) + g.mov(.rax, g.enum_vals[type_name].fields[node.val]) + } else { g.n_error('expr: unhandled node type: $node.type_name()') } diff --git a/vlib/v/gen/native/tests/enum.vv b/vlib/v/gen/native/tests/enum.vv new file mode 100644 index 0000000000..45de3f7835 --- /dev/null +++ b/vlib/v/gen/native/tests/enum.vv @@ -0,0 +1,51 @@ +enum Color { + red + blue + green +} + +fn enum_test() { + assert Color.red == .red + assert Color.blue == .blue + assert Color.green == .green + assert Color.red != .blue + assert Color.red != .green + assert Color.blue != .green + mut color := Color.red + assert color == .red + color = .green + assert color == .green +} + +fn match_test() { + color := Color.green + num := 3 + match color { + .red { + assert false + } + .green { + assert true + } + else { + assert false + } + } +// println(color) + assert num == 3 +} + +enum Bar { + baz +} + +fn (_ Bar) baz() {} + +fn test_enum_variant_and_method_name_clash() { + x := Bar.baz +// println(x) + x.baz() +} + +fn main() { +} diff --git a/vlib/v/gen/native/tests/enum.vv.out b/vlib/v/gen/native/tests/enum.vv.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vlib/v/gen/native/tests/match.vv b/vlib/v/gen/native/tests/match.vv index 8e2b087f93..92f0506692 100644 --- a/vlib/v/gen/native/tests/match.vv +++ b/vlib/v/gen/native/tests/match.vv @@ -117,9 +117,42 @@ fn multiple_test() { // from match_test.v } } +enum Foo { + a + b + c = 4 + 8 +} + +fn get() Foo { + return .a +} + +fn foo(f Foo) { + match f { + .a { + println('a') + } + .b { + println('b') + } + .c { + println('c') + } + } +} + +fn enum_test() { + foo(match get() { + .a { .b } + .b { .c } + .c { .a } + }) +} + fn main() { match_for_test() ifexpr_match_test() integer_match_test() multiple_test() + enum_test() } diff --git a/vlib/v/gen/native/tests/match.vv.out b/vlib/v/gen/native/tests/match.vv.out index f7415a4b4e..c398896386 100644 --- a/vlib/v/gen/native/tests/match.vv.out +++ b/vlib/v/gen/native/tests/match.vv.out @@ -5,3 +5,4 @@ a == 0 0 three 6-9 +b