From 092c09d81fe066b9bd4ced1d431c351247ff1562 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 19 Feb 2020 16:12:39 +0100 Subject: [PATCH] vdoc using the new parser --- cmd/v/v.v | 18 +++++-- vlib/v/ast/scope.v | 21 ++++---- vlib/v/ast/str.v | 36 +++++++++++++ vlib/v/builder/modules.v | 2 +- vlib/v/doc/doc.v | 104 +++++++++++++++++++++++++++++++++++++ vlib/v/doc/doc_test.v | 9 ++++ vlib/v/fmt/fmt.v | 25 ++++----- vlib/v/parser/fn.v | 8 +-- vlib/v/parser/parse_type.v | 4 +- vlib/v/parser/parser.v | 50 +++++++++++------- vlib/v/table/table.v | 2 +- 11 files changed, 219 insertions(+), 60 deletions(-) create mode 100644 vlib/v/ast/str.v create mode 100644 vlib/v/doc/doc.v create mode 100644 vlib/v/doc/doc_test.v diff --git a/cmd/v/v.v b/cmd/v/v.v index 4ea4788f41..0ddfe6b7c4 100644 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -7,6 +7,8 @@ import ( compiler internal.help os + v.table + v.doc ) const ( @@ -43,6 +45,12 @@ fn main() { eprintln('v command: $command') eprintln('v options: $option') } + if command == 'doc' { + mod := arg[arg.len-1] + table := table.new_table() + println(doc.doc(mod, table)) + return + } if command in simple_cmd { // External tools launch_tool(is_verbose, 'v' + command, command) @@ -60,20 +68,20 @@ fn main() { launch_tool(is_verbose, 'vrepl', '') } 'translate' { - println('Translating C to V will be available in V 0.3 (January)') + println('Translating C to V will be available in V 0.3') } 'search', 'install', 'update', 'remove' { launch_tool(is_verbose, 'vpm', command) } 'get' { - println('Use `v install` to install modules from vpm.vlang.io.') + println('Use `v install` to install modules from vpm.vlang.io') } 'symlink' { create_symlink() } - 'doc' { - println('Currently unimplemented') - } + //'doc' { + //println('Currently unimplemented') + //} else { eprintln('v $command: unknown command\nRun "v help" for usage.') exit(1) diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index 14acbb7912..3735af72e8 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -9,7 +9,7 @@ mut: children []&Scope start_pos int end_pos int - //vars map[string]table.Var + // vars map[string]table.Var vars map[string]VarDecl } @@ -46,7 +46,7 @@ pub fn (s &Scope) find_var(name string) ?VarDecl { pub fn (s mut Scope) register_var(var VarDecl) { if x := s.find_var(var.name) { - println('existing var: $var.name') + // println('existing var: $var.name') return } s.vars[var.name] = var @@ -61,21 +61,21 @@ pub fn (s &Scope) innermost(pos int) ?&Scope { if s.contains(pos) { // binary search mut first := 0 - mut last := s.children.len-1 - mut middle := last/2 + mut last := s.children.len - 1 + mut middle := last / 2 for first <= last { - //println('FIRST: $first, LAST: $last, LEN: $s.children.len-1') + // println('FIRST: $first, LAST: $last, LEN: $s.children.len-1') s1 := s.children[middle] if s1.end_pos < pos { - first = middle+1 + first = middle + 1 } else if s1.contains(pos) { return s1.innermost(pos) } else { - last = middle-1 + last = middle - 1 } - middle = (first+last)/2 + middle = (first + last) / 2 if first > last { break } @@ -99,6 +99,7 @@ pub fn (s &Scope) innermost(pos int) ?&Scope { } */ + [inline] fn (s &Scope) contains(pos int) bool { return pos > s.start_pos && pos < s.end_pos @@ -106,7 +107,7 @@ fn (s &Scope) contains(pos int) bool { pub fn (sc &Scope) print_vars(level int) { mut indent := '' - for _ in 0..level*4 { + for _ in 0 .. level * 4 { indent += ' ' } println('$indent# $sc.start_pos - $sc.end_pos') @@ -114,6 +115,6 @@ pub fn (sc &Scope) print_vars(level int) { println('$indent * $var.name - $var.typ') } for child in sc.children { - child.print_vars(level+1) + child.print_vars(level + 1) } } diff --git a/vlib/v/ast/str.v b/vlib/v/ast/str.v new file mode 100644 index 0000000000..c2215a85e6 --- /dev/null +++ b/vlib/v/ast/str.v @@ -0,0 +1,36 @@ +module ast + +import ( + v.table + strings +) + +pub fn (node &FnDecl) str(t &table.Table) string { + mut f := strings.new_builder(30) + mut receiver := '' + if node.is_method { + sym := t.get_type_symbol(node.receiver.typ) + name := sym.name.after('.') + m := if node.rec_mut { 'mut ' } else { '' } + receiver = '($node.receiver.name ${m}$name) ' + } + f.write('fn ${receiver}${node.name}(') + for i, arg in node.args { + is_last_arg := i == node.args.len - 1 + should_add_type := is_last_arg || node.args[i + 1].typ != arg.typ + f.write(arg.name) + if should_add_type { + arg_typ_sym := t.get_type_symbol(arg.typ) + f.write(' ${arg_typ_sym.name}') + } + if !is_last_arg { + f.write(', ') + } + } + f.write(')') + if node.typ != table.void_type { + sym := t.get_type_symbol(node.typ) + f.write(' ' + sym.name) + } + return f.str() +} diff --git a/vlib/v/builder/modules.v b/vlib/v/builder/modules.v index 6d85323541..0a83839589 100644 --- a/vlib/v/builder/modules.v +++ b/vlib/v/builder/modules.v @@ -11,7 +11,7 @@ fn module_path(mod string) string { return mod.replace('.', filepath.separator) } -fn (b &Builder) find_module_path(mod string) ?string { +pub fn (b &Builder) find_module_path(mod string) ?string { mod_path := module_path(mod) for search_path in b.module_search_paths { try_path := filepath.join(search_path,mod_path) diff --git a/vlib/v/doc/doc.v b/vlib/v/doc/doc.v new file mode 100644 index 0000000000..5a6f71cb59 --- /dev/null +++ b/vlib/v/doc/doc.v @@ -0,0 +1,104 @@ +module doc + +import ( + strings + // v.builder + // v.pref + v.table + v.parser + v.ast + os + filepath +) + +struct Doc { + out strings.Builder + table &table.Table + mod string +mut: + stmts []ast.Stmt // all module statements from all files +} + +pub fn doc(mod string, table &table.Table) string { + mut d := Doc{ + out: strings.new_builder(1000) + table: table + mod: mod + } + mods_path := filepath.dir(vexe_path()) + '/vlib' + path := filepath.join(mods_path,mod) + if !os.exists(path) { + println('module "$mod" not found') + println(path) + return '' + } + // vfiles := os.walk_ext(path, '.v') + files := os.ls(path) or { + panic(err) + } + for file in files { + if !file.ends_with('.v') { + continue + } + if file.ends_with('_test.v') { + continue + } + file_ast := parser.parse_file(filepath.join(path,file), table) + d.stmts << file_ast.stmts + } + d.print_fns() + d.writeln('') + d.print_methods() + /* + for stmt in file_ast.stmts { + d.stmt(stmt) + } + println(path) + */ + + return d.out.str() +} + +fn (d mut Doc) writeln(s string) { + d.out.writeln(s) +} + +fn (d mut Doc) write_fn_node(f ast.FnDecl) { + d.writeln(f.str(d.table).replace(d.mod + '.', '')) +} + +fn (d mut Doc) print_fns() { + for stmt in d.stmts { + match stmt { + ast.FnDecl { + if it.is_pub && !it.is_method { + d.write_fn_node(it) + } + } + else {} + } + } +} + +fn (d mut Doc) print_methods() { + for stmt in d.stmts { + match stmt { + ast.FnDecl { + if it.is_pub && it.is_method { + d.write_fn_node(it) + } + } + else {} + } + } +} + +pub fn vexe_path() string { + vexe := os.getenv('VEXE') + if '' != vexe { + return vexe + } + real_vexe_path := os.realpath(os.executable()) + os.setenv('VEXE', real_vexe_path, true) + return real_vexe_path +} diff --git a/vlib/v/doc/doc_test.v b/vlib/v/doc/doc_test.v new file mode 100644 index 0000000000..fe97ec16d1 --- /dev/null +++ b/vlib/v/doc/doc_test.v @@ -0,0 +1,9 @@ +import ( + v.table + v.doc +) + +fn test_vdoc() { + table := table.new_table() + println(doc.doc('net', table)) +} diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 2141f7b943..68c8c53c0f 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -28,7 +28,12 @@ pub fn fmt(file ast.File, table &table.Table) string { table: table indent: 0 } - return f.process(file) + f.mod(file.mod) + f.imports(file.imports) + for stmt in file.stmts { + f.stmt(stmt) + } + return f.out.str().trim_space() + '\n' } pub fn (f mut Fmt) write(s string) { @@ -48,15 +53,6 @@ pub fn (f mut Fmt) writeln(s string) { f.empty_line = true } -fn (f mut Fmt) process(file ast.File) string { - f.mod(file.mod) - f.imports(file.imports) - for stmt in file.stmts { - f.stmt(stmt) - } - return f.out.str().trim_space() + '\n' -} - fn (f mut Fmt) mod(mod ast.Module) { if mod.name != 'main' { f.writeln('module ${mod.name}\n') @@ -67,7 +63,8 @@ fn (f mut Fmt) imports(imports []ast.Import) { if imports.len == 1 { imp_stmt_str := f.imp_stmt_str(imports[0]) f.writeln('import ${imp_stmt_str}\n') - } else if imports.len > 1 { + } + else if imports.len > 1 { f.writeln('import (') f.indent++ for imp in imports { @@ -79,11 +76,7 @@ fn (f mut Fmt) imports(imports []ast.Import) { } fn (f Fmt) imp_stmt_str(imp ast.Import) string { - imp_alias_suffix := if imp.alias != imp.mod { - ' as ${imp.alias}' - } else { - '' - } + imp_alias_suffix := if imp.alias != imp.mod { ' as ${imp.alias}' } else { '' } return '${imp.mod}${imp_alias_suffix}' } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 52bc607d69..3e98aae5a2 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -11,11 +11,7 @@ import ( pub fn (p mut Parser) call_expr(is_c bool, mod string) ast.CallExpr { tok := p.tok name := p.check_name() - fn_name := if mod.len > 0 { - '${mod}.$name' - } else { - name - } + fn_name := if mod.len > 0 { '${mod}.$name' } else { name } p.check(.lpar) args := p.call_args() node := ast.CallExpr{ @@ -193,7 +189,7 @@ fn (p mut Parser) fn_args() ([]ast.Arg,bool) { // `int, int, string` (no names, just types) types_only := p.tok.kind in [.amp] || (p.peek_tok.kind == .comma && p.table.known_type(p.tok.lit)) || p.peek_tok.kind == .rpar if types_only { - p.warn('types only') + // p.warn('types only') mut arg_no := 1 for p.tok.kind != .rpar { arg_name := 'arg_$arg_no' diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 4c906e6151..c30199154a 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -67,7 +67,7 @@ pub fn (p mut Parser) parse_multi_return_type() table.Type { } pub fn (p mut Parser) parse_fn_type() table.Type { - p.warn('parrse fn') + // p.warn('parrse fn') p.check(.key_fn) // p.fn_decl() p.fn_args() @@ -196,7 +196,7 @@ pub fn (p mut Parser) parse_type() table.Type { } // not found - add placeholder idx = p.table.add_placeholder_type(name) - println('NOT FOUND: $name - adding placeholder - $idx') + // println('NOT FOUND: $name - adding placeholder - $idx') return table.new_type_ptr(idx, nr_muls) } } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 3c8c5a8f9f..ac52f42152 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -64,7 +64,7 @@ pub fn parse_stmt(text string, table &table.Table, scope &ast.Scope) ast.Stmt { } pub fn parse_file(path string, table &table.Table) ast.File { - println('parse_file("$path")') + // println('parse_file("$path")') text := os.read_file(path) or { panic(err) } @@ -95,7 +95,7 @@ pub fn parse_file(path string, table &table.Table) ast.File { for { // res := s.scan() if p.tok.kind == .eof { - println('EOF, breaking') + // println('EOF, breaking') break } // println('stmt at ' + p.tok.str()) @@ -642,6 +642,13 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) { .key_sizeof { p.next() // sizeof p.check(.lpar) + if p.tok.lit == 'C' { + p.next() + p.check(.dot) + } + if p.tok.kind == .amp { + p.next() + } type_name := p.check_name() p.check(.rpar) node = ast.SizeOf{ @@ -912,17 +919,17 @@ fn (p mut Parser) for_statement() ast.Stmt { if p.peek_tok.kind == .decl_assign { init = p.var_decl() } - else if p.tok.kind != .semicolon { - // allow `for ;; i++ {` - // Allow `for i = 0; i < ...` - /* + else if p.tok.kind != .semicolon {} + // allow `for ;; i++ {` + // Allow `for i = 0; i < ...` + /* cond, typ = p.expr(0) if typ.kind != _bool { p.error('non-bool used as for condition') } */ - println(1) - } + // println(1) + // } p.check(.semicolon) if p.tok.kind != .semicolon { mut typ := table.void_type @@ -973,12 +980,12 @@ fn (p mut Parser) for_statement() ast.Stmt { table.Map { elem_type = it.value_type } - else { - println(1) - // elem_type_sym := p.table.get_type_symbol(elem_type) - // p.error('cannot loop over type: $elem_type_sym.name') - } - } + else {} + // println(1) + // elem_type_sym := p.table.get_type_symbol(elem_type) + // p.error('cannot loop over type: $elem_type_sym.name') + // } + } } // 0 .. 10 // start := p.tok.lit.int() @@ -1144,10 +1151,8 @@ fn (p mut Parser) array_init() ast.ArrayInit { array_type = table.new_type(idx) } // [] - else { - // TODO ? - println(0) - } + else {} + // TODO ? } else { // [1,2,3] @@ -1177,6 +1182,13 @@ fn (p mut Parser) array_init() ast.ArrayInit { */ } + // ! + if p.tok.kind == .not { + p.next() + } + if p.tok.kind == .not { + p.next() + } // idx := if is_fixed { p.table.find_or_register_array_fixed(val_type, fixed_size, 1) } else { p.table.find_or_register_array(val_type, 1) } // array_type := table.new_type(idx) return ast.ArrayInit{ @@ -1265,7 +1277,7 @@ fn (p mut Parser) const_decl() ast.ConstDecl { mut exprs := []ast.Expr for p.tok.kind != .rpar { name := p.check_name() - println('const: $name') + // println('const: $name') p.check(.assign) expr,typ := p.expr(0) fields << ast.Field{ diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 323bb3f426..85afd149ae 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -87,7 +87,7 @@ pub fn (t mut Table) register_fn(new_fn Fn) { pub fn (t &Table) register_method(typ &TypeSymbol, new_fn Fn) bool { // println('register method `$new_fn.name` type=$typ.name idx=$typ.idx') - println('register method `$new_fn.name` type=$typ.name') + // println('register method `$new_fn.name` type=$typ.name') mut t1 := typ mut methods := typ.methods methods << new_fn