From 59beec8fae0246ee22cc6b5a5322224947183828 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Mon, 17 Feb 2020 22:50:04 +0100 Subject: [PATCH] new vfmt using the new parser --- vlib/v/ast/ast.v | 42 ++++--- vlib/v/fmt/fmt.v | 251 ++++++++++++++++++++++++++++++++++++++ vlib/v/fmt/fmt_test.v | 31 +++++ vlib/v/fmt/tests/1.vv | 37 ++++++ vlib/v/fmt/tests/1_out.vv | 0 vlib/v/gen/cgen.v | 36 +++--- 6 files changed, 359 insertions(+), 38 deletions(-) create mode 100644 vlib/v/fmt/fmt_test.v create mode 100644 vlib/v/fmt/tests/1.vv create mode 100644 vlib/v/fmt/tests/1_out.vv diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index c88b76ea15..f5d5d3fc77 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -8,14 +8,23 @@ import ( v.table ) -pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral | -FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | -AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr | +pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral | +FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | +AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr | CastExpr | EnumVal -pub type Stmt = VarDecl | GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | -ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | +pub type Stmt = VarDecl | GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | +ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt + +pub type Type = StructType | ArrayType + +pub struct StructType { + fields []Field +} + +pub struct ArrayType {} + // | IncDecStmt k // Stand-alone expression in a statement list. pub struct ExprStmt { @@ -72,6 +81,7 @@ pub: // type_idx int mut: typ table.Type + // typ2 Type } pub struct ConstDecl { @@ -194,11 +204,11 @@ pub: pub struct File { pub: - path string - mod Module - imports []Import - stmts []Stmt - scope Scope + path string + mod Module + imports []Import + stmts []Stmt + scope Scope } pub struct IdentFunc { @@ -387,15 +397,15 @@ pub: vals []string } -pub struct TypeDecl{ +pub struct TypeDecl { pub: name string is_pub bool } -pub struct DeferStmt{ +pub struct DeferStmt { pub: -stmts []Stmt + stmts []Stmt } pub struct AssignExpr { @@ -406,14 +416,14 @@ pub: val Expr } -pub struct GotoLabel{ +pub struct GotoLabel { pub: -name string + name string } pub struct GotoStmt { pub: -name string + name string } pub struct ArrayInit { diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 0cea66d5fc..156145041f 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -3,7 +3,24 @@ // that can be found in the LICENSE file. module fmt +import ( + v.ast + v.table + strings +) + +const ( + tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t'] + // tabs = ['', ' ', ' ', ' ', ' '] +) + struct Fmt { + out strings.Builder + table &table.Table +mut: + indent int + empty_line bool + /* // vfmt fields TODO move to a separate struct // fmt_out strings.Builder fmt_lines []string @@ -11,5 +28,239 @@ struct Fmt { fmt_indent int fmt_line_empty bool // fmt_needs_nl bool + */ } + +pub fn fmt(file ast.File, table &table.Table) { + mut f := Fmt{ + out: strings.new_builder(1000) + table: table + indent: -1 + } + f.stmts(file.stmts) + println('!!!!!!!!!') + println(f.out.str()) +} + +pub fn (f mut Fmt) write(s string) { + if f.indent > 0 && f.empty_line { + f.out.write(tabs[f.indent]) + f.empty_line = false + } + f.out.write(s) +} + +pub fn (f mut Fmt) writeln(s string) { + if f.indent > 0 { + println(f.indent.str() + s) + f.out.write(tabs[f.indent]) + } + f.out.writeln(s) + f.empty_line = true +} + +fn (f mut Fmt) stmts(stmts []ast.Stmt) { + f.indent++ + for stmt in stmts { + f.stmt(stmt) + } + f.indent-- +} + +fn (f mut Fmt) stmt(node ast.Stmt) { + match node { + ast.AssignStmt { + for i, left in it.left { + f.expr(left) + if i < it.left.len - 1 { + f.write(', ') + } + } + f.write(' = ') + for right in it.right { + f.expr(right) + } + } + ast.ConstDecl { + f.writeln('const (') + f.indent++ + for i, field in it.fields { + f.write('$field.name = ') + f.expr(it.exprs[i]) + } + f.indent-- + f.writeln('\n)\n') + } + ast.ExprStmt { + f.expr(it.expr) + f.writeln('') + } + ast.FnDecl { + f.writeln('fn ${it.name}() {') + f.stmts(it.stmts) + f.writeln('}\n') + } + ast.Return { + f.write('return') + // multiple returns + if it.exprs.len > 1 { + for i, expr in it.exprs { + f.expr(expr) + if i < it.exprs.len - 1 { + f.write(', ') + } + } + } + // normal return + else if it.exprs.len == 1 { + f.write(' ') + f.expr(it.exprs[0]) + } + f.writeln('') + } + ast.StructDecl { + f.struct_decl(it) + } + ast.VarDecl { + // type_sym := f.table.get_type_symbol(it.typ) + if it.is_mut { + f.write('mut ') + } + f.write('$it.name := ') + f.expr(it.expr) + f.writeln('') + } + else { + println('unknown node') + // exit(1) + } + } +} + +fn (f mut Fmt) struct_decl(node ast.StructDecl) { + f.writeln('struct $node.name {') + mut max := 0 + for field in node.fields { + if field.name.len > max { + max = field.name.len + } + } + for field in node.fields { + field_type_sym := f.table.get_type_symbol(field.typ) + f.write('\t$field.name ') + f.write(strings.repeat(` `, max - field.name.len)) + f.writeln('$field_type_sym.name') + } + f.writeln('}\n') +} + +fn (f mut Fmt) expr(node ast.Expr) { + match node { + ast.ArrayInit { + // type_sym := f.table.get_type_symbol(it.typ) + f.write('[') + for i, expr in it.exprs { + f.expr(expr) + if i < it.exprs.len - 1 { + f.write(', ') + } + } + f.write(']') + } + ast.AssignExpr { + f.expr(it.left) + f.write(' $it.op.str() ') + f.expr(it.val) + } + ast.BoolLiteral { + f.write(it.val.str()) + } + ast.CallExpr { + f.write('${it.name}(') + for i, expr in it.args { + f.expr(expr) + if i != it.args.len - 1 { + f.write(', ') + } + } + f.write(')') + } + ast.FloatLiteral { + f.write(it.val) + } + ast.IfExpr { + f.write('if ') + f.expr(it.cond) + f.writeln('{') + f.stmts(it.stmts) + f.writeln('}') + if it.else_stmts.len > 0 { + f.writeln('else { ') + f.stmts(it.else_stmts) + f.writeln('}') + } + } + ast.Ident { + f.write('$it.name') + } + ast.InfixExpr { + f.expr(it.left) + f.write(' $it.op.str() ') + f.expr(it.right) + } + ast.IndexExpr { + f.index_expr(it) + } + ast.IntegerLiteral { + f.write(it.val.str()) + } + ast.PostfixExpr { + f.expr(it.expr) + f.write(it.op.str()) + } + ast.PrefixExpr { + f.write(it.op.str()) + f.expr(it.right) + } + ast.SelectorExpr { + f.expr(it.expr) + f.write('.') + f.write(it.field) + } + ast.StringLiteral { + f.write('"$it.val"') + } + ast.StructInit { + type_sym := f.table.get_type_symbol(it.typ) + f.writeln('$type_sym.name{') + for i, field in it.fields { + f.write('\t$field: ') + f.expr(it.exprs[i]) + f.writeln('') + } + f.write('}') + } + else {} + } +} + +fn (f mut Fmt) index_expr(node ast.IndexExpr) { + mut is_range := false + match node.index { + ast.RangeExpr { + is_range = true + f.expr(node.left) + f.write('..') + f.expr(it.high) + f.write(')') + } + else {} + } + if !is_range { + f.expr(node.left) + f.write('[') + f.expr(node.index) + f.write(']') + } +} diff --git a/vlib/v/fmt/fmt_test.v b/vlib/v/fmt/fmt_test.v new file mode 100644 index 0000000000..79f62c26ee --- /dev/null +++ b/vlib/v/fmt/fmt_test.v @@ -0,0 +1,31 @@ +import ( + os + v.fmt + filepath + term + v.table + v.parser +) + +const ( + nr_tests = 1 +) + +fn test_fmt() { + println('Running vfmt tests') + vexe := os.getenv('VEXE') + vroot := filepath.dir(vexe) + term_ok := term.ok_message('OK') + term_fail := term.fail_message('FAIL') + for i in 1 .. nr_tests + 1 { + path := '$vroot/vlib/v/fmt/tests/${i}.vv' + println(path) + mut ctext := os.read_file('$vroot/vlib/v/fmt/tests/${i}_out.vv') or { + panic(err) + } + ctext = ctext // unused warn + table := table.new_table() + file := parser.parse_file(path, table) + fmt.fmt(file, table) + } +} diff --git a/vlib/v/fmt/tests/1.vv b/vlib/v/fmt/tests/1.vv new file mode 100644 index 0000000000..6bfb2cf084 --- /dev/null +++ b/vlib/v/fmt/tests/1.vv @@ -0,0 +1,37 @@ +fn hello() +{ + mut a:= 3 + 3 + a = 10 + a++ + -23 + b:= 42 + println( 'hello' ) + abc() + if true { + a = 10 + a++ + } else { + println('false') + } +} + +const ( +pi=3.14 +) + +struct User { + name string + age int + + very_long_field bool +} + + +fn abc() int { + mut u := User{name:'Bob'} + u.age = 20 + + nums := [1,2,3] + number := nums[0] + return 0 +} diff --git a/vlib/v/fmt/tests/1_out.vv b/vlib/v/fmt/tests/1_out.vv new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 8ddb329034..25807462f9 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -24,10 +24,7 @@ pub fn cgen(files []ast.File, table &table.Table) string { fn_decl: 0 } for file in files { - for stmt in file.stmts { - g.stmt(stmt) - g.writeln('') - } + g.stmts(file.stmts) } return g.definitions.str() + g.out.str() } @@ -76,7 +73,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { for i, arg in it.args { arg_type_sym := g.table.get_type_symbol(arg.typ) mut arg_type_name := arg_type_sym.name - if i == it.args.len-1 && it.is_variadic { + if i == it.args.len - 1 && it.is_variadic { arg_type_name = 'variadic_$arg_type_sym.name' } g.write(arg_type_name + ' ' + arg.name) @@ -194,11 +191,23 @@ fn (g mut Gen) stmt(node ast.Stmt) { fn (g mut Gen) expr(node ast.Expr) { // println('cgen expr()') match node { + ast.ArrayInit { + type_sym := g.table.get_type_symbol(it.typ) + g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($type_sym.name), {\t') + for expr in it.exprs { + g.expr(expr) + g.write(', ') + } + g.write('\n})') + } ast.AssignExpr { g.expr(it.left) g.write(' $it.op.str() ') g.expr(it.val) } + ast.BoolLiteral { + g.write(it.val.str()) + } ast.IntegerLiteral { g.write(it.val.str()) } @@ -263,26 +272,9 @@ fn (g mut Gen) expr(node ast.Expr) { g.write(')') } ast.MethodCallExpr {} - ast.ArrayInit { - type_sym := g.table.get_type_symbol(it.typ) - g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($type_sym.name), {\t') - for expr in it.exprs { - g.expr(expr) - g.write(', ') - } - g.write('\n})') - } ast.Ident { g.write('$it.name') } - ast.BoolLiteral { - if it.val == true { - g.write('true') - } - else { - g.write('false') - } - } ast.SelectorExpr { g.expr(it.expr) g.write('.')