diff --git a/transpiler/ast.v b/transpiler/ast.v index 66477cf..0e844f7 100644 --- a/transpiler/ast.v +++ b/transpiler/ast.v @@ -78,36 +78,6 @@ type Statement = ArrayStmt | UnsafeStmt | VariableStmt -struct NotYetImplStmt {} - -struct MultipleStmt { -mut: - stmts []Statement -} - -struct FunctionStmt { -mut: - comment string - public bool - generic bool - method []string - name string - args map[string]string - ret_vals []string - type_ctx bool - body []Statement -} - -struct VariableStmt { -mut: - comment string - names []string - middle string - values []Statement - mutable bool = true - @type string -} - struct ArrayStmt { mut: @type string @@ -115,27 +85,20 @@ mut: len string } -struct SliceStmt { -mut: - value string - low Statement - high Statement -} - struct BasicValueStmt { mut: value string } -struct OptionalStmt { +struct BlockStmt { mut: - stmt Statement + body []Statement } -struct IncDecStmt { +struct BranchStmt { mut: - var string - inc string + name string + label string } struct CallStmt { @@ -145,16 +108,17 @@ mut: args []Statement } -struct IfStmt { +struct DeferStmt { mut: - init_vars []VariableStmt - branchs []IfElse + body []Statement } -struct IfElse { +struct ForInStmt { mut: - condition Statement - body []Statement + idx string + element string + variable Statement + body []Statement } struct ForStmt { @@ -165,40 +129,59 @@ mut: body []Statement } -struct ForInStmt { +struct FunctionStmt { mut: - idx string - element string - variable Statement + comment string + public bool + generic bool + method []string + name string + args map[string]string + ret_vals []string + type_ctx bool body []Statement } -struct BranchStmt { +struct GoStmt { mut: - name string - label string + stmt Statement } -struct ReturnStmt { +struct IfElse { mut: - values []Statement + condition Statement + body []Statement } -struct DeferStmt { +struct IfStmt { mut: - body []Statement + init_vars []VariableStmt + branchs []IfElse } -struct UnsafeStmt { +struct IncDecStmt { mut: - body []Statement + var string + inc string } -struct MatchStmt { +struct KeyValStmt { mut: - init VariableStmt + key string value Statement - cases []MatchCase +} + +struct LabelStmt { +mut: + name string + stmt Statement +} + +struct MapStmt { +mut: + key_type string + value_type string + values []Statement } struct MatchCase { @@ -207,23 +190,23 @@ mut: body []Statement } -struct StructStmt { +struct MatchStmt { mut: - name string - fields []Statement + init VariableStmt + value Statement + cases []MatchCase } -struct KeyValStmt { +struct MultipleStmt { mut: - key string - value Statement + stmts []Statement } -struct MapStmt { +struct NotYetImplStmt {} + +struct OptionalStmt { mut: - key_type string - value_type string - values []Statement + stmt Statement } struct PushStmt { @@ -232,18 +215,35 @@ mut: value Statement } -struct LabelStmt { +struct ReturnStmt { mut: - name string - stmt Statement + values []Statement } -struct GoStmt { +struct SliceStmt { mut: - stmt Statement + value string + low Statement + high Statement } -struct BlockStmt { +struct StructStmt { +mut: + name string + fields []Statement +} + +struct UnsafeStmt { mut: body []Statement } + +struct VariableStmt { +mut: + comment string + names []string + middle string + values []Statement + mutable bool = true + @type string +} diff --git a/transpiler/ast_extractor.v b/transpiler/ast_extractor.v index ef795b9..65f2fdb 100644 --- a/transpiler/ast_extractor.v +++ b/transpiler/ast_extractor.v @@ -299,12 +299,10 @@ fn (mut v VAST) extract_stmt(tree Tree) Statement { mut ret := Statement(NotYetImplStmt{}) match tree.name { - // `var` syntax - '*ast.DeclStmt' { - mut var_stmt := v.extract_variable(tree.child['Decl'].tree.child['Specs'].tree.child['0'].tree, - false, true) - - ret = var_stmt + '*ast.ArrayType' { + ret = ArrayStmt{ + @type: v.get_name(tree.child['Elt'].tree, .ignore, .other) + } } // `:=`, `+=` etc. syntax '*ast.AssignStmt' { @@ -314,30 +312,6 @@ fn (mut v VAST) extract_stmt(tree Tree) Statement { '*ast.BasicLit', '*ast.StarExpr', '*ast.TypeAssertExpr' { ret = BasicValueStmt{v.get_name(tree, .ignore, .other)} } - // variable, function call, etc. - '*ast.Ident', '*ast.IndexExpr', '*ast.SelectorExpr' { - ret = BasicValueStmt{v.get_name(tree, .snake_case, .other)} - v.extract_embedded_declaration(tree) - } - '*ast.MapType' { - ret = MapStmt{ - key_type: v.get_name(tree.child['Key'].tree, .ignore, .other) - value_type: v.get_name(tree.child['Value'].tree, .ignore, .other) - } - } - '*ast.ArrayType' { - ret = ArrayStmt{ - @type: v.get_name(tree.child['Elt'].tree, .ignore, .other) - } - } - '*ast.UnaryExpr' { - op := if tree.child['Op'].val !in ['range', '+'] { tree.child['Op'].val } else { '' } - - ret = MultipleStmt{[ - bv_stmt('${op}'), - v.extract_stmt(tree.child['X'].tree), - ]} - } '*ast.BinaryExpr' { op := if tree.child['Op'].val != '&^' { tree.child['Op'].val } else { '&~' } @@ -347,6 +321,48 @@ fn (mut v VAST) extract_stmt(tree Tree) Statement { v.extract_stmt(tree.child['Y'].tree), ]} } + '*ast.BlockStmt' { + ret = BlockStmt{v.extract_body(tree)} + } + // break/continue + '*ast.BranchStmt' { + ret = BranchStmt{tree.child['Tok'].val, v.get_name(tree.child['Label'].tree, + .snake_case, .other)} + } + // (nested) function/method call + '*ast.CallExpr', '*ast.ExprStmt' { + base := if tree.name == '*ast.ExprStmt' { tree.child['X'].tree } else { tree } + + fn_stmt := v.extract_function(base.child['Fun'].tree, false) + if fn_stmt.body.len < 1 { + mut call_stmt := CallStmt{ + namespaces: fn_stmt.name + } + // function/method arguments + for _, arg in base.child['Args'].tree.child { + call_stmt.args << v.extract_stmt(arg.tree) + } + + // ellipsis (`...a` syntax) + if base.child['Ellipsis'].val != '0' { + idx := call_stmt.args.len - 1 + call_stmt.args[idx] = MultipleStmt{[bv_stmt('...'), call_stmt.args[idx]]} + } + + // `[]byte("Hello, 世界")` -> `"Hello, 世界".bytes()` + if fn_stmt.name[0] == `[` { + call_stmt = CallStmt{ + namespaces: '${v.stmt_to_string(call_stmt.args[0])}.bytes' + } + } + + v.extract_embedded_declaration(base.child['Fun'].tree) + + ret = call_stmt + } else { + ret = fn_stmt + } + } // arrays & `Struct{}` syntaxt '*ast.CompositeLit' { base := tree.child['Type'].tree @@ -466,68 +482,67 @@ fn (mut v VAST) extract_stmt(tree Tree) Statement { } } } - // `key: value` syntax - '*ast.KeyValueExpr' { - ret = KeyValStmt{ - key: v.get_name(tree.child['Key'].tree, .snake_case, .other) - value: v.extract_stmt(tree.child['Value'].tree) - } + // `var` syntax + '*ast.DeclStmt' { + mut var_stmt := v.extract_variable(tree.child['Decl'].tree.child['Specs'].tree.child['0'].tree, + false, true) + + ret = var_stmt } - // slices (slicing) - '*ast.SliceExpr' { - mut slice_stmt := SliceStmt{ - value: v.get_name(tree.child['X'].tree, .ignore, .other) - low: BasicValueStmt{} - high: BasicValueStmt{} - } - if 'Low' in tree.child { - slice_stmt.low = v.extract_stmt(tree.child['Low'].tree) - } - if 'High' in tree.child { - slice_stmt.high = v.extract_stmt(tree.child['High'].tree) + '*ast.DeferStmt' { + mut defer_stmt := DeferStmt{[v.extract_stmt(tree.child['Call'].tree)]} + + // as Go's defer stmt only support deferring one stmt, in Go if you want to defer multiple stmts you have to use an anonymous function, here we just extract the anonymous function's body + if defer_stmt.body.len == 1 && defer_stmt.body[0] is FunctionStmt { + defer_stmt.body = (defer_stmt.body[0] as FunctionStmt).body } - ret = slice_stmt + + ret = defer_stmt } - // (nested) function/method call - '*ast.ExprStmt', '*ast.CallExpr' { - base := if tree.name == '*ast.ExprStmt' { tree.child['X'].tree } else { tree } + '*ast.Ellipsis' { + ret = bv_stmt('...') + } + // condition for/bare for/C-style for + '*ast.ForStmt' { + mut for_stmt := ForStmt{} - fn_stmt := v.extract_function(base.child['Fun'].tree, false) - if fn_stmt.body.len < 1 { - mut call_stmt := CallStmt{ - namespaces: fn_stmt.name - } - // function/method arguments - for _, arg in base.child['Args'].tree.child { - call_stmt.args << v.extract_stmt(arg.tree) - } + // init + for_stmt.init = v.extract_variable(tree.child['Init'].tree, true, false) + for_stmt.init.mutable = false - // ellipsis (`...a` syntax) - if base.child['Ellipsis'].val != '0' { - idx := call_stmt.args.len - 1 - call_stmt.args[idx] = MultipleStmt{[bv_stmt('...'), call_stmt.args[idx]]} - } + // condition + for_stmt.condition = v.extract_stmt(tree.child['Cond'].tree) - // `[]byte("Hello, 世界")` -> `"Hello, 世界".bytes()` - if fn_stmt.name[0] == `[` { - call_stmt = CallStmt{ - namespaces: '${v.stmt_to_string(call_stmt.args[0])}.bytes' - } - } + // post + post_base := tree.child['Post'].tree + if post_base.child.len > 0 { + for_stmt.post = v.extract_stmt(post_base) + } - v.extract_embedded_declaration(base.child['Fun'].tree) + // body + for_stmt.body = v.extract_body(tree.child['Body'].tree) - ret = call_stmt + ret = for_stmt + } + '*ast.FuncLit' { + ret = v.extract_function(tree, true) + } + '*ast.GoStmt' { + to_call := v.extract_stmt(tree.child['Call'].tree) + if to_call is FunctionStmt { + mut multiple_stmts := MultipleStmt{} + for _, child_stmt in to_call.body { + multiple_stmts.stmts << GoStmt{child_stmt} + } + ret = multiple_stmts } else { - ret = fn_stmt + ret = GoStmt{to_call} } } - // `i++` & `i--` - '*ast.IncDecStmt' { - ret = IncDecStmt{ - var: v.get_name(tree, .ignore, .other) - inc: tree.child['Tok'].val - } + // variable, function call, etc. + '*ast.Ident', '*ast.IndexExpr', '*ast.SelectorExpr' { + ret = BasicValueStmt{v.get_name(tree, .snake_case, .other)} + v.extract_embedded_declaration(tree) } // if/else '*ast.IfStmt' { @@ -569,32 +584,31 @@ fn (mut v VAST) extract_stmt(tree Tree) Statement { ret = if_stmt } - // condition for/bare for/C-style for - '*ast.ForStmt' { - mut for_stmt := ForStmt{} - - // init - for_stmt.init = v.extract_variable(tree.child['Init'].tree, true, false) - for_stmt.init.mutable = false - - // condition - for_stmt.condition = v.extract_stmt(tree.child['Cond'].tree) - - // post - post_base := tree.child['Post'].tree - if post_base.child.len > 0 { - for_stmt.post = v.extract_stmt(post_base) + // `i++` & `i--` + '*ast.IncDecStmt' { + ret = IncDecStmt{ + var: v.get_name(tree, .ignore, .other) + inc: tree.child['Tok'].val } - - // body - for_stmt.body = v.extract_body(tree.child['Body'].tree) - - ret = for_stmt } - // break/continue - '*ast.BranchStmt' { - ret = BranchStmt{tree.child['Tok'].val, v.get_name(tree.child['Label'].tree, - .snake_case, .other)} + // `key: value` syntax + '*ast.KeyValueExpr' { + ret = KeyValStmt{ + key: v.get_name(tree.child['Key'].tree, .snake_case, .other) + value: v.extract_stmt(tree.child['Value'].tree) + } + } + '*ast.LabeledStmt' { + ret = LabelStmt{v.get_name(tree.child['Label'].tree, .snake_case, .other), v.extract_stmt(tree.child['Stmt'].tree)} + } + '*ast.MapType' { + ret = MapStmt{ + key_type: v.get_name(tree.child['Key'].tree, .ignore, .other) + value_type: v.get_name(tree.child['Value'].tree, .ignore, .other) + } + } + '*ast.ParenExpr' { + ret = bv_stmt('(' + v.stmt_to_string(v.extract_stmt(tree.child['X'].tree)) + ')') } // for in '*ast.RangeStmt' { @@ -629,15 +643,20 @@ fn (mut v VAST) extract_stmt(tree Tree) Statement { ret = return_stmt } - '*ast.DeferStmt' { - mut defer_stmt := DeferStmt{[v.extract_stmt(tree.child['Call'].tree)]} - - // as Go's defer stmt only support deferring one stmt, in Go if you want to defer multiple stmts you have to use an anonymous function, here we just extract the anonymous function's body - if defer_stmt.body.len == 1 && defer_stmt.body[0] is FunctionStmt { - defer_stmt.body = (defer_stmt.body[0] as FunctionStmt).body + // slices (slicing) + '*ast.SliceExpr' { + mut slice_stmt := SliceStmt{ + value: v.get_name(tree.child['X'].tree, .ignore, .other) + low: BasicValueStmt{} + high: BasicValueStmt{} } - - ret = defer_stmt + if 'Low' in tree.child { + slice_stmt.low = v.extract_stmt(tree.child['Low'].tree) + } + if 'High' in tree.child { + slice_stmt.high = v.extract_stmt(tree.child['High'].tree) + } + ret = slice_stmt } '*ast.SwitchStmt', '*ast.TypeSwitchStmt' { is_type_switch := tree.name == '*ast.TypeSwitchStmt' @@ -694,32 +713,13 @@ fn (mut v VAST) extract_stmt(tree Tree) Statement { ret = match_stmt } - '*ast.FuncLit' { - ret = v.extract_function(tree, true) - } - '*ast.Ellipsis' { - ret = bv_stmt('...') - } - '*ast.LabeledStmt' { - ret = LabelStmt{v.get_name(tree.child['Label'].tree, .snake_case, .other), v.extract_stmt(tree.child['Stmt'].tree)} - } - '*ast.ParenExpr' { - ret = bv_stmt('(' + v.stmt_to_string(v.extract_stmt(tree.child['X'].tree)) + ')') - } - '*ast.GoStmt' { - to_call := v.extract_stmt(tree.child['Call'].tree) - if to_call is FunctionStmt { - mut multiple_stmts := MultipleStmt{} - for _, child_stmt in to_call.body { - multiple_stmts.stmts << GoStmt{child_stmt} - } - ret = multiple_stmts - } else { - ret = GoStmt{to_call} - } - } - '*ast.BlockStmt' { - ret = BlockStmt{v.extract_body(tree)} + '*ast.UnaryExpr' { + op := if tree.child['Op'].val !in ['range', '+'] { tree.child['Op'].val } else { '' } + + ret = MultipleStmt{[ + bv_stmt('${op}'), + v.extract_stmt(tree.child['X'].tree), + ]} } '' { ret = bv_stmt('') diff --git a/transpiler/file_writer.v b/transpiler/file_writer.v index fe4f639..cdf5a64 100644 --- a/transpiler/file_writer.v +++ b/transpiler/file_writer.v @@ -114,159 +114,6 @@ fn (mut v VAST) write_body(body []Statement) { // write a statement fn (mut v VAST) write_stmt(stmt Statement, is_value bool) { match stmt { - FunctionStmt { - // comment - if stmt.comment.len > 0 { - v.out.writeln(stmt.comment) - } - // public/private - if stmt.public { - v.out.write_string('pub ') - } - // keyword - v.out.write_string('fn ') - // method - if stmt.method.len != 0 { - v.out.write_string('(mut ${stmt.method[0]} ${stmt.method[1]}) ') - } - // name - v.out.write_string('${stmt.name}') - // generic - if stmt.generic { - v.out.write_string('') - } - v.out.write_rune(`(`) - // arguments - // useless after https://github.com/vlang/v/issues/14551 gets fixed - mut i := 0 - for name, @type in stmt.args { - name_ := if stmt.type_ctx { '' } else { name } - if i != stmt.args.len - 1 { - v.out.write_string('${name_} ${@type}, ') - } else { - v.out.write_string('${name_} ${@type}') - } - i++ - } - v.out.write_string(')') - // return value(s) - - if stmt.ret_vals.len > 0 { - v.out.write_string(' (') - for val in stmt.ret_vals { - v.out.write_string('${val}, ') - } - v.out.write_string(')') - } - // body - if !stmt.type_ctx { - v.out.write_string(' {') - v.write_body(stmt.body) - v.out.writeln('}') - } - } - VariableStmt { - if stmt.names.len > 0 { - has_explicit_type := stmt.@type.len > 0 - - if stmt.mutable && stmt.middle == ':=' { - v.out.write_string('mut ') - } - - // name(s) - for i, name in stmt.names { - v.out.write_string(name) - v.out.write_string(if i != stmt.names.len - 1 { ',' } else { '' }) - } - - // eg: `:=`, `+=`, `=` - v.out.write_string(stmt.middle) - - // value(s) - if stmt.values.len > 0 { - for value in stmt.values { - // explicit type - if has_explicit_type { - v.out.write_string('${stmt.@type}(') - } - v.write_stmt(value, true) - if has_explicit_type { - v.out.write_rune(`)`) - } - v.out.write_rune(`,`) - } - v.out.cut_last(1) - } else { - for _ in stmt.names { - v.out.write_string(type_to_default_value(stmt.@type)) - v.out.write_rune(`,`) - } - v.out.cut_last(1) - } - } - } - IncDecStmt { - v.out.write_string('${stmt.var}${stmt.inc}') - } - CallStmt { - v.out.write_string('${stmt.namespaces}(') - for arg in stmt.args { - v.write_stmt(arg, true) - v.out.write_rune(`,`) - } - v.out.write_rune(`)`) - } - IfStmt { - for var_stmt in stmt.init_vars { - v.write_stmt(var_stmt, false) - } - for i, branch in stmt.branchs { - if i != 0 { - v.out.write_string('else ') - } - - if branch.condition != bv_stmt('') { - v.out.write_string('if ') - v.write_stmt(branch.condition, true) - } - v.out.write_string('{\n') - v.write_body(branch.body) - v.out.write_rune(`}`) - } - } - ForStmt { - v.out.write_string('for ') - // check if stmt.init or stmt.post aren't null - if stmt.init.names.len > 0 || stmt.post.type_name() != 'unknown transpiler.Statement' { - // c-style for - v.write_stmt(stmt.init, true) - v.out.write_rune(`;`) - v.write_stmt(stmt.condition, true) - v.out.write_rune(`;`) - v.write_stmt(stmt.post, true) - } else { - // while - v.write_stmt(stmt.condition, true) - } - // for bare loops no need to write anything - v.out.write_string('{\n') - v.write_body(stmt.body) - v.out.write_rune(`}`) - } - ForInStmt { - if stmt.idx.len > 0 || stmt.element.len > 0 { - v.out.write_string('for ${stmt.idx}, ${stmt.element} in ') - } else { - v.out.write_string('for _ in ') - } - v.write_stmt(stmt.variable, true) - v.out.write_string('{\n') - v.write_body(stmt.body) - v.out.write_rune(`}`) - } - BranchStmt { - v.out.write_string('${stmt.name} ${stmt.label}') - } ArrayStmt { is_empty := stmt.values.len < 1 is_fixed_size := stmt.len.trim_space().len > 0 @@ -343,32 +190,152 @@ fn (mut v VAST) write_stmt(stmt Statement, is_value bool) { BasicValueStmt { v.out.write_string(stmt.value) } - SliceStmt { - v.out.write_string('${stmt.value}[') - v.write_stmt(stmt.low, true) - v.out.write_string('..') - v.write_stmt(stmt.high, true) - v.out.write_rune(`]`) + BlockStmt { + v.out.write_rune(`{`) + v.write_body(stmt.body) + v.out.write_rune(`}`) } - ReturnStmt { - v.out.write_string('return ') - for i, el in stmt.values { - v.write_stmt(el, true) - if i != stmt.values.len - 1 { - v.out.write_rune(`,`) - } + BranchStmt { + v.out.write_string('${stmt.name} ${stmt.label}') + } + CallStmt { + v.out.write_string('${stmt.namespaces}(') + for arg in stmt.args { + v.write_stmt(arg, true) + v.out.write_rune(`,`) } + v.out.write_rune(`)`) } DeferStmt { v.out.write_string('defer {') v.write_body(stmt.body) v.out.write_rune(`}`) } - UnsafeStmt { - v.out.write_string('unsafe {') + ForInStmt { + if stmt.idx.len > 0 || stmt.element.len > 0 { + v.out.write_string('for ${stmt.idx}, ${stmt.element} in ') + } else { + v.out.write_string('for _ in ') + } + v.write_stmt(stmt.variable, true) + v.out.write_string('{\n') + v.write_body(stmt.body) + v.out.write_rune(`}`) + } + ForStmt { + v.out.write_string('for ') + // check if stmt.init or stmt.post aren't null + if stmt.init.names.len > 0 || stmt.post.type_name() != 'unknown transpiler.Statement' { + // c-style for + v.write_stmt(stmt.init, true) + v.out.write_rune(`;`) + v.write_stmt(stmt.condition, true) + v.out.write_rune(`;`) + v.write_stmt(stmt.post, true) + } else { + // while + v.write_stmt(stmt.condition, true) + } + // for bare loops no need to write anything + v.out.write_string('{\n') v.write_body(stmt.body) v.out.write_rune(`}`) } + FunctionStmt { + // comment + if stmt.comment.len > 0 { + v.out.writeln(stmt.comment) + } + // public/private + if stmt.public { + v.out.write_string('pub ') + } + // keyword + v.out.write_string('fn ') + // method + if stmt.method.len != 0 { + v.out.write_string('(mut ${stmt.method[0]} ${stmt.method[1]}) ') + } + // name + v.out.write_string('${stmt.name}') + // generic + if stmt.generic { + v.out.write_string('') + } + v.out.write_rune(`(`) + // arguments + // useless after https://github.com/vlang/v/issues/14551 gets fixed + mut i := 0 + for name, @type in stmt.args { + name_ := if stmt.type_ctx { '' } else { name } + if i != stmt.args.len - 1 { + v.out.write_string('${name_} ${@type}, ') + } else { + v.out.write_string('${name_} ${@type}') + } + i++ + } + v.out.write_string(')') + // return value(s) + + if stmt.ret_vals.len > 0 { + v.out.write_string(' (') + for val in stmt.ret_vals { + v.out.write_string('${val}, ') + } + v.out.write_string(')') + } + // body + if !stmt.type_ctx { + v.out.write_string(' {') + v.write_body(stmt.body) + v.out.writeln('}') + } + } + GoStmt { + v.out.write_string('go ') + v.write_stmt(stmt.stmt, true) + } + IncDecStmt { + v.out.write_string('${stmt.var}${stmt.inc}') + } + IfStmt { + for var_stmt in stmt.init_vars { + v.write_stmt(var_stmt, false) + } + for i, branch in stmt.branchs { + if i != 0 { + v.out.write_string('else ') + } + + if branch.condition != bv_stmt('') { + v.out.write_string('if ') + v.write_stmt(branch.condition, true) + } + v.out.write_string('{\n') + v.write_body(branch.body) + v.out.write_rune(`}`) + } + } + KeyValStmt { + v.out.write_string('\n${stmt.key}:') + v.write_stmt(stmt.value, true) + } + LabelStmt { + v.out.write_string('${stmt.name}: ') + v.write_stmt(stmt.stmt, true) + } + MapStmt { + if stmt.values.len > 0 { + v.out.write_rune(`{`) + for value in stmt.values { + v.write_stmt(value, true) + } + v.out.write_rune(`}`) + } else { + v.out.write_string('map[${stmt.key_type}]${stmt.value_type}{}') + } + } MatchStmt { v.write_stmt(stmt.init, true) @@ -398,60 +365,93 @@ fn (mut v VAST) write_stmt(stmt Statement, is_value bool) { } v.out.write_rune(`}`) } - StructStmt { - v.out.write_string('${stmt.name}{') - for i, field in stmt.fields { - if i > 0 { - v.out.write_rune(`,`) - } - v.write_stmt(field, true) + MultipleStmt { + for el in stmt.stmts { + v.write_stmt(el, true) } - v.out.write_rune(`}`) } - KeyValStmt { - v.out.write_string('\n${stmt.key}:') - v.write_stmt(stmt.value, true) + NotYetImplStmt { + v.out.write_string('NOT_YET_IMPLEMENTED') } - MapStmt { - if stmt.values.len > 0 { - v.out.write_rune(`{`) - for value in stmt.values { - v.write_stmt(value, true) - } - v.out.write_rune(`}`) - } else { - v.out.write_string('map[${stmt.key_type}]${stmt.value_type}{}') - } + OptionalStmt { + v.write_stmt(stmt.stmt, true) + v.out.write_rune(`?`) } PushStmt { v.write_stmt(stmt.stmt, true) v.out.write_string('<<') v.write_stmt(stmt.value, true) } - OptionalStmt { - v.write_stmt(stmt.stmt, true) - v.out.write_rune(`?`) - } - MultipleStmt { - for el in stmt.stmts { + ReturnStmt { + v.out.write_string('return ') + for i, el in stmt.values { v.write_stmt(el, true) + if i != stmt.values.len - 1 { + v.out.write_rune(`,`) + } } } - LabelStmt { - v.out.write_string('${stmt.name}: ') - v.write_stmt(stmt.stmt, true) + SliceStmt { + v.out.write_string('${stmt.value}[') + v.write_stmt(stmt.low, true) + v.out.write_string('..') + v.write_stmt(stmt.high, true) + v.out.write_rune(`]`) } - GoStmt { - v.out.write_string('go ') - v.write_stmt(stmt.stmt, true) + StructStmt { + v.out.write_string('${stmt.name}{') + for i, field in stmt.fields { + if i > 0 { + v.out.write_rune(`,`) + } + v.write_stmt(field, true) + } + v.out.write_rune(`}`) } - BlockStmt { - v.out.write_rune(`{`) + UnsafeStmt { + v.out.write_string('unsafe {') v.write_body(stmt.body) v.out.write_rune(`}`) } - NotYetImplStmt { - v.out.write_string('NOT_YET_IMPLEMENTED') + VariableStmt { + if stmt.names.len > 0 { + has_explicit_type := stmt.@type.len > 0 + + if stmt.mutable && stmt.middle == ':=' { + v.out.write_string('mut ') + } + + // name(s) + for i, name in stmt.names { + v.out.write_string(name) + v.out.write_string(if i != stmt.names.len - 1 { ',' } else { '' }) + } + + // eg: `:=`, `+=`, `=` + v.out.write_string(stmt.middle) + + // value(s) + if stmt.values.len > 0 { + for value in stmt.values { + // explicit type + if has_explicit_type { + v.out.write_string('${stmt.@type}(') + } + v.write_stmt(value, true) + if has_explicit_type { + v.out.write_rune(`)`) + } + v.out.write_rune(`,`) + } + v.out.cut_last(1) + } else { + for _ in stmt.names { + v.out.write_string(type_to_default_value(stmt.@type)) + v.out.write_rune(`,`) + } + v.out.cut_last(1) + } + } } } diff --git a/transpiler/go2v.v b/transpiler/go2v.v index bb8d76d..43533c7 100644 --- a/transpiler/go2v.v +++ b/transpiler/go2v.v @@ -113,12 +113,13 @@ pub fn convert_and_write(input_path string, output_path string) ! { // compile with -cg to enable this block // only works properly if converting single file. $if debug { - os.mkdir('temp') or {} - os.write_file('temp/go_ast', go_ast)! - os.write_file('temp/tokens', tokens.str())! - os.write_file('temp/tree', tree.str())! - os.write_file('temp/v_ast', v_ast.str())! - os.write_file('temp/raw_file.v', raw_v_file)! + temp_output_path := 'temp/${os.file_name(input_path)}/' + os.mkdir_all(temp_output_path) or {} + os.write_file('${temp_output_path}go_ast', go_ast)! + os.write_file('${temp_output_path}tokens', tokens.str())! + os.write_file('${temp_output_path}tree', tree.str())! + os.write_file('${temp_output_path}v_ast', v_ast.str())! + os.write_file('${temp_output_path}raw_file.v', raw_v_file)! } os.mkdir_all(os.dir(output_path))! @@ -142,7 +143,8 @@ pub fn convert_and_write(input_path string, output_path string) ! { // compile with -cg to enable this block // only works properly if converting single file. $if debug { - os.write_file('temp/formatted_file.v', formatted_content)! + formatted_output_path := 'temp/${os.file_name(input_path)}/' + os.write_file('${formatted_output_path}formatted_file.v', formatted_content)! } os.write_file(output_path, formatted_content)!