diff --git a/.editorconfig b/.editorconfig index 26d7ca8bba..ed42a3deb0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,7 +17,7 @@ indent_size = 2 [*.md] trim_trailing_whitespace = false -[*.txt] +[*.{txt,out}] insert_final_newline = false [Makefile] diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index a84b1bc00e..990bf06a4d 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -367,7 +367,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.expr(it.default_exprs[j]) expr := g.out.after(pos) g.out.go_back(expr.len) - g.typedefs.writeln('$expr ,') + g.typedefs.writeln('$expr,') } else { g.typedefs.writeln('\t${name}_$val, // $j') } @@ -1210,10 +1210,10 @@ fn (g mut Gen) typeof_expr(node ast.TypeOf) { fn (g mut Gen) enum_expr(node ast.Expr) { match node { ast.EnumVal { - g.write('$it.val.capitalize()') + g.write(it.val) } else { - println(term.red('cgen.enum_expr(): bad node ' + typeof(node))) + g.expr(node) } } } @@ -2260,6 +2260,7 @@ fn (g mut Gen) string_inter_literal(node ast.StringInterLiteral) { // } // else {} // } + sym := g.table.get_type_symbol(node.expr_types[i]) sfmt := node.expr_fmts[i] if sfmt.len > 0 { fspec := sfmt[sfmt.len - 1] @@ -2267,10 +2268,13 @@ fn (g mut Gen) string_inter_literal(node ast.StringInterLiteral) { verror('only V strings can be formatted with a ${sfmt} format') } g.write('%' + sfmt[1..]) - } else if node.expr_types[i] == table.string_type || node.expr_types[i] == table.bool_type { + } else if node.expr_types[i] in [table.string_type, table.bool_type] || sym.kind == .enum_ { g.write('%.*s') } else { - g.write('%d') + match node.exprs[i] { + ast.EnumVal { g.write('%.*s') } + else { g.write('%d') } + } } } g.write('", ') @@ -2297,7 +2301,39 @@ fn (g mut Gen) string_inter_literal(node ast.StringInterLiteral) { g.expr(expr) g.write(' ? "true" : "false"') } else { - g.expr(expr) + sym := g.table.get_type_symbol(node.expr_types[i]) + if sym.kind == .enum_ { + is_var := match node.exprs[i] { + ast.SelectorExpr { true } + ast.Ident { true } + else { false } + } + if is_var { + styp := g.typ(node.expr_types[i]) + if !sym.has_method('str') && !(styp in g.str_types) { + // Generate an automatic str() method if this type doesn't have it already + g.str_types << styp + g.gen_str_for_type(sym, styp) + } + g.write('${styp}_str(') + g.enum_expr(expr) + g.write(')') + g.write('.len, ') + g.write('${styp}_str(') + g.enum_expr(expr) + g.write(').str') + } else { + g.write('tos3("') + g.enum_expr(expr) + g.write('")') + g.write('.len, ') + g.write('"') + g.enum_expr(expr) + g.write('"') + } + } else { + g.expr(expr) + } } if i < node.exprs.len - 1 { g.write(', ') @@ -2466,9 +2502,15 @@ fn (g mut Gen) fn_call(node ast.CallExpr) { g.expr(node.args[0].expr) g.writeln('); ${print_method}($tmp); string_free($tmp); //MEM2 $styp') } else if sym.kind == .enum_ { - g.write('${print_method}(tos3("') - g.enum_expr(node.args[0].expr) - g.write('"))') + expr := node.args[0].expr + is_var := match expr { + ast.SelectorExpr { true } + ast.Ident { true } + else { false } + } + g.write(if is_var { '${print_method}(${styp}_str(' } else { '${print_method}(tos3("' }) + g.enum_expr(expr) + g.write(if is_var { '))' } else { '"))' }) } else { // `println(int_str(10))` // sym := g.table.get_type_symbol(node.args[0].typ) @@ -2962,15 +3004,32 @@ fn (g mut Gen) go_stmt(node ast.GoStmt) { // already generated styp, reuse it fn (g mut Gen) gen_str_for_type(sym table.TypeSymbol, styp string) { - s := styp.replace('.', '__') match sym.info { - table.Struct {} + table.Struct { + g.gen_str_for_struct(it, styp) + } + table.Enum { + g.gen_str_for_enum(it, styp) + } else { - println('str() not a struct $sym.name') - return + println('cannot generate str() for $sym.name') } } - info := sym.info as table.Struct +} + +fn (g mut Gen) gen_str_for_enum(info table.Enum, styp string) { + s := styp.replace('.', '__') + g.definitions.write('string ${s}_str($styp a) {\n\tswitch(a) {\n') + for i, expr in info.default_exprs { + val := info.vals[i] + int_expr := expr as ast.IntegerLiteral + g.definitions.write('\t\tcase $int_expr.val: return tos3("$val");\n') + } + g.definitions.write('\t\tdefault: return tos3("unknown enum value"); } }\n') +} + +fn (g mut Gen) gen_str_for_struct(info table.Struct, styp string) { + s := styp.replace('.', '__') g.definitions.write('string ${s}_str($styp a) { return _STR("$styp {\\n') for field in info.fields { fmt := type_to_fmt(field.typ) diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index b7bd1fe018..60e903d1c1 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1873,6 +1873,7 @@ fn (p mut Parser) enum_decl() ast.EnumDecl { name: name info: table.Enum{ vals: vals + default_exprs: default_exprs } }) return ast.EnumDecl{ diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 93e90b5809..13ee5a7a60 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -14,6 +14,7 @@ module table import ( strings + v.ast ) pub type Type int @@ -546,6 +547,7 @@ pub mut: pub struct Enum { pub mut: vals []string + default_exprs []ast.Expr } pub struct Alias { diff --git a/vlib/v/tests/inout/enum_print.out b/vlib/v/tests/inout/enum_print.out new file mode 100644 index 0000000000..16b698f351 --- /dev/null +++ b/vlib/v/tests/inout/enum_print.out @@ -0,0 +1,5 @@ +yellow +green +green +interp: green +interp: green \ No newline at end of file diff --git a/vlib/v/tests/inout/enum_print.v b/vlib/v/tests/inout/enum_print.v new file mode 100644 index 0000000000..4f38d6bc48 --- /dev/null +++ b/vlib/v/tests/inout/enum_print.v @@ -0,0 +1,21 @@ +module main + +enum Color { + green = 5 + red = 2 + yellow = 1 +} + +struct A{ + color Color +} + +fn main() { + col := Color.green + a := A{color: col} + println(Color.yellow) + println(col) + println(a.color) + println('interp: ${col}') + println('interp: ${a.color}') +} diff --git a/vlib/v/tests/inout/enum_print.vv b/vlib/v/tests/inout/enum_print.vv new file mode 100644 index 0000000000..4f38d6bc48 --- /dev/null +++ b/vlib/v/tests/inout/enum_print.vv @@ -0,0 +1,21 @@ +module main + +enum Color { + green = 5 + red = 2 + yellow = 1 +} + +struct A{ + color Color +} + +fn main() { + col := Color.green + a := A{color: col} + println(Color.yellow) + println(col) + println(a.color) + println('interp: ${col}') + println('interp: ${a.color}') +} diff --git a/vlib/v/tests/inout/hello.out b/vlib/v/tests/inout/hello.out index 3b18e512db..95d09f2b10 100644 --- a/vlib/v/tests/inout/hello.out +++ b/vlib/v/tests/inout/hello.out @@ -1 +1 @@ -hello world +hello world \ No newline at end of file diff --git a/vlib/v/tests/inout/hello_devs.out b/vlib/v/tests/inout/hello_devs.out index adf8207172..58986d9472 100644 --- a/vlib/v/tests/inout/hello_devs.out +++ b/vlib/v/tests/inout/hello_devs.out @@ -3,4 +3,4 @@ Hello, web developers! Hello, tools developers! Hello, science developers! Hello, systems developers! -Hello, embedded developers! +Hello, embedded developers! \ No newline at end of file diff --git a/vlib/v/tests/inout/os.out b/vlib/v/tests/inout/os.out index bd656fcf15..d9ba4c4a5f 100644 --- a/vlib/v/tests/inout/os.out +++ b/vlib/v/tests/inout/os.out @@ -1,4 +1,4 @@ CHANGELOG.md CODE_OF_CONDUCT.md CONTRIBUTING.md -README.md +README.md \ No newline at end of file