more vfmt fixes

pull/2717/head
Alexander Medvednikov 2019-11-09 22:05:44 +03:00
parent 30481a36dc
commit 3d4f85069f
11 changed files with 91 additions and 50 deletions

View File

@ -89,8 +89,10 @@ fn (p mut Parser) comp_time() {
p.returns = false
//p.gen('/* returns $p.returns */')
if p.tok == .dollar && p.peek() == .key_else {
p.fspace()
p.next()
p.next()
p.fspace() // spaces before and after $else
p.check(.lcbr)
p.genln('#else')
p.statements_no_rcbr()

View File

@ -58,10 +58,11 @@ fn (p mut Parser) bterm() string {
if tok in [.eq, .gt, .lt, .le, .ge, .ne] {
//TODO: remove when array comparing is supported
if is_array {
p.error('Array comparing is not supported yet')
p.error('array comparing is not supported yet')
}
p.fgen(' ${p.tok.str()} ')
p.fspace()
//p.fgen(' ${p.tok.str()} ')
if (is_float || is_str || is_ustr) && !p.is_js {
p.gen(',')
}
@ -72,6 +73,7 @@ fn (p mut Parser) bterm() string {
p.gen(tok.str())
}
p.next()
p.fspace()
// `id == user.id` => `id == $1`, `user.id`
if p.is_sql {
p.sql_i++
@ -140,7 +142,6 @@ fn (p mut Parser) name_expr() string {
p.string_expr()
return 'string'
}
p.fgen(name)
// known_type := p.table.known_type(name)
orig_name := name
is_c := name == 'C' && p.peek() == .dot
@ -190,7 +191,6 @@ fn (p mut Parser) name_expr() string {
p.next()
p.check(.dot)
name = p.lit
p.fgen(name)
name = prepend_mod(mod_gen_name(mod), name)
}
// Unknown name, try prepending the module name to it
@ -484,10 +484,11 @@ fn (p mut Parser) term() string {
is_mul := tok == .mul
is_div := tok == .div
is_mod := tok == .mod
p.fspace()
p.next()
p.gen(tok.str())// + ' /*op2*/ ')
oph := p.cgen.add_placeholder()
p.fgen(' ' + tok.str() + ' ')
p.fspace()
if (is_div || is_mod) && p.tok == .number && p.lit == '0' {
p.error('division or modulo by zero')
}
@ -575,11 +576,9 @@ fn (p mut Parser) factor() string {
p.error('constant `$p.lit` overflows `$p.expected_type`')
}
p.gen(p.lit)
p.fgen(p.lit)
}
.minus {
p.gen('-')
p.fgen('-')
p.next()
return p.factor()
// Variable

View File

@ -179,8 +179,7 @@ fn (p mut Parser) clear_vars() {
// Function signatures are added to the top of the .c file in the first run.
fn (p mut Parser) fn_decl() {
p.clear_vars() // clear local vars every time a new fn is started
//defer { p.fgenln('\n') }
defer { p.fgenln2('\n') }
// If we are in the first pass, create a new function.
// In the second pass fetch the one we created.
/*
@ -206,6 +205,7 @@ fn (p mut Parser) fn_decl() {
}
if is_pub {
p.next()
p.fspace()
}
p.returns = false
//p.gen('/* returns $p.returns */')
@ -218,10 +218,12 @@ fn (p mut Parser) fn_decl() {
f.is_method = true
p.check(.lpar)
receiver_name := p.check_name()
p.fspace()
is_mut := p.tok == .key_mut
is_amp := p.tok == .amp
if is_mut || is_amp {
p.check_space(p.tok)
p.check(p.tok)
p.fspace()
}
receiver_typ = p.get_type()
t := p.table.find_type(receiver_typ)
@ -350,7 +352,7 @@ fn (p mut Parser) fn_decl() {
// Returns a type?
mut typ := 'void'
if p.tok in [.name, .mul, .amp, .lsbr, .question, .lpar] {
p.fgen(' ')
p.fspace()
typ = p.get_type()
}
// V allows empty functions (just definitions)
@ -1568,9 +1570,9 @@ pub fn (f &Fn) v_fn_name() string {
pub fn (f &Fn) str_for_error() string {
// Build the args for the error
mut s := ''
for i, a in f.args {
if i == 0 {
mut s := ''
for i, a in f.args {
if i == 0 {
if f.is_method {
s += a.typ + '.' + f.name + '('
continue
@ -1581,7 +1583,7 @@ pub fn (f &Fn) str_for_error() string {
if i < f.args.len - 1 {
s += ', '
}
}
}
return s + ')'
}

View File

@ -6,7 +6,7 @@ module compiler
fn (p mut Parser) for_st() {
p.check(.key_for)
p.fgen(' ')
p.fspace()
p.for_expr_cnt++
next_tok := p.peek()
//debug := p.scanner.file_path.contains('r_draw')
@ -32,13 +32,13 @@ fn (p mut Parser) for_st() {
}
p.check(.semicolon)
p.gen(' ; ')
p.fgen(' ')
p.fspace()
if p.tok != .semicolon {
p.bool_expression()
}
p.check(.semicolon)
p.gen(' ; ')
p.fgen(' ')
p.fspace()
if p.tok != .lcbr {
p.statement(false)
}
@ -61,9 +61,9 @@ fn (p mut Parser) for_st() {
if i == '_' && val == '_' {
p.error('no new variables on the left side of `in`')
}
p.fgen(' ')
p.fspace()
p.check(.key_in)
p.fgen(' ')
p.fspace()
tmp := p.get_tmp()
p.cgen.start_tmp()
mut typ := p.bool_expression()
@ -121,7 +121,7 @@ fn (p mut Parser) for_st() {
// `for val in vals`
else if p.peek() == .key_in {
val := p.check_name()
p.fgen(' ')
p.fspace()
p.check(.key_in)
p.fspace()
tmp := p.get_tmp()

View File

@ -117,6 +117,7 @@ pub mut:
comptime_define string // -D vfmt for `if $vfmt {`
fast bool // use tcc/x64 codegen
enable_globals bool // allow __global for low level code
is_fmt bool
}
// Should be called by main at the end of the compilation process, to cleanup
@ -946,6 +947,7 @@ pub fn new_v(args[]string) &V {
ccompiler: find_c_compiler()
building_v: !is_repl && (rdir_name == 'compiler' || rdir_name == 'v.v' || dir.contains('vlib'))
comptime_define: comptime_define
is_fmt: comptime_define == 'vfmt'
}
if pref.is_verbose || pref.is_debug {
println('C compiler=$pref.ccompiler')

View File

@ -279,6 +279,7 @@ fn (p mut Parser) parse(pass Pass) {
p.mod = p.check_name()
}
//
p.fgenln2('\n')
p.cgen.nogen = false
if p.pref.build_mode == .build_module && p.mod != p.v.mod {
@ -392,6 +393,7 @@ fn (p mut Parser) parse(pass Pass) {
//p.error('__global is only allowed in translated code')
}
p.next()
p.fspace()
name := p.check_name()
typ := p.get_type()
p.register_global(name, typ)
@ -408,6 +410,11 @@ fn (p mut Parser) parse(pass Pass) {
if !p.cgen.nogen {
p.cgen.consts << g
}
p.fgenln2('')
if p.tok != .key_global {
// An extra empty line to separate a block of globals
p.fgenln2('')
}
}
.eof {
//p.log('end of parse()')
@ -420,19 +427,7 @@ fn (p mut Parser) parse(pass Pass) {
if !p.first_pass() && !p.pref.is_repl {
p.check_unused_imports()
}
if !p.first_pass() && p.fileis('main.v') {
s := p.scanner.fmt_out.str().trim_space()
if s.len > 0 {
println('GENERATING MAIN.V')
out := os.create('/var/tmp/fmt.v') or {
verror('failed to create fmt.v')
return
}
//println(p.scanner.fmt_out.str())
out.writeln(p.scanner.fmt_out.str().trim_space())
out.close()
}
}
p.gen_fmt() // not generated unless `-d vfmt` is provided
return
}
else {
@ -720,8 +715,15 @@ fn (p &Parser) strtok() string {
if p.tok == .name {
return p.lit
}
if p.tok == .number {
return p.lit
}
if p.tok == .str {
return '"$p.lit"'
if p.lit.contains("'") {
return '"$p.lit"'
} else {
return "'$p.lit'"
}
}
res := p.tok.str()
if res == '' {
@ -782,6 +784,8 @@ fn (p mut Parser) get_type() string {
mut typ := ''
// multiple returns
if p.tok == .lpar {
//p.warn('`()` are no longer necessary in multiple returns' +
//'\nuse `fn foo() int, int {` instead of `fn foo() (int, int) {`')
// if p.inside_tuple {p.error('unexpected (')}
// p.inside_tuple = true
p.check(.lpar)
@ -1270,9 +1274,8 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) {
}
}
p.fspace()
p.fgen(tok.str())
p.fspace()
p.next()
p.fspace()
pos := p.cgen.cur_line.len
expr_type := p.bool_expression()
//if p.expected_type.starts_with('array_') {
@ -1633,7 +1636,6 @@ fn (p mut Parser) var_expr(v Var) string {
}
}
p.gen(p.tok.str())
p.fgen(p.tok.str())
p.next()// ++/--
// allow `a := c++` in translated code TODO remove once c2v handles this
if p.pref.translated {
@ -2541,9 +2543,10 @@ fn (p mut Parser) if_st(is_expr bool, elif_depth int) string {
}
if_returns := p.returns
p.returns = false
// println('IF TYp=$typ')
if p.tok == .key_else {
p.fgenln2('')
if !p.inside_if_expr {
p.fgenln2('')
}
p.check(.key_else)
p.fspace()
if p.tok == .key_if {
@ -2730,6 +2733,7 @@ fn (p mut Parser) return_st() {
p.gen('return')
}
}
p.fgenln('//ret')
p.returns = true
}
@ -2876,6 +2880,7 @@ fn (p mut Parser) attribute() {
p.attr = p.attr + ':' + p.check_name()
}
p.check(.rsbr)
p.fgenln2('')
if p.tok == .key_fn || (p.tok == .key_pub && p.peek() == .key_fn) {
p.fn_decl()
p.attr = ''

View File

@ -76,7 +76,7 @@ fn new_scanner_file(file_path string) &Scanner {
fn new_scanner(text string) &Scanner {
return &Scanner {
text: text
fmt_out: strings.new_builder(1000)
fmt_out: strings.new_builder(10000)
should_print_line_on_error: true
should_print_errors_in_color: true
should_print_relative_paths_on_error: true
@ -481,7 +481,7 @@ fn (s mut Scanner) scan() ScanRes {
if nextc == `!` {
// treat shebang line (#!) as a comment
s.line_comment = s.text[start + 1..s.pos].trim_space()
s.fgenln('// shebang line "$s.line_comment"')
//s.fgenln('// shebang line "$s.line_comment"')
return s.scan()
}
hash := s.text[start..s.pos]
@ -585,7 +585,7 @@ fn (s mut Scanner) scan() ScanRes {
s.ignore_line()
s.line_comment = s.text[start + 1..s.pos]
s.line_comment = s.line_comment.trim_space()
s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"')
//s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"')
// Skip the comment (return the next token)
return s.scan()
}

View File

@ -9,6 +9,7 @@ fn (p mut Parser) struct_decl() {
is_pub := p.tok == .key_pub
if is_pub {
p.next()
p.fspace()
}
// V can generate Objective C for integration with Cocoa
// `[objc_interface:ParentInterface]`
@ -220,7 +221,7 @@ fn (p mut Parser) struct_decl() {
if p.first_pass() {
p.table.add_field(typ.name, field_name, field_type, is_mut, attr, access_mod)
}
p.fgenln2('')
p.fgenln2('') // newline between struct fields
}
p.check(.rcbr)
if !is_c && !did_gen_something && p.first_pass() {
@ -272,6 +273,7 @@ fn (p mut Parser) struct_init(typ string) string {
}
p.fspace()
did_gen_something = true
p.fgenln2('') // newline between struct fields
}
// If we already set some fields, need to prepend a comma
if t.fields.len != inited_fields.len && inited_fields.len > 0 {
@ -308,6 +310,7 @@ fn (p mut Parser) struct_init(typ string) string {
p.gen(',')
}
did_gen_something = true
p.fgenln2('') // newline between struct fields
}
}
}

View File

@ -286,6 +286,10 @@ fn (t []TokenKind) contains(val TokenKind) bool {
}
fn (t Token) str() string {
if t.tok == .number {
return t.lit
}
if t.tok == .str {
return "'$t.lit'"
}

View File

@ -5,6 +5,7 @@
module compiler
import strings
import os
[if vfmt]
fn (scanner mut Scanner) fgen(s_ string) {
@ -93,14 +94,37 @@ fn (p mut Parser) fnext() {
if p.tok == .eof {
return
}
if p.tok == .rcbr {
if p.tok == .rcbr && !p.inside_if_expr {
p.fmt_dec()
}
p.fgen2(p.strtok())
// vfmt: increase indentation on `{` unless it's `{}`
if p.tok == .lcbr { //&& p.scanner.pos + 1 < p.scanner.text.len && p.scanner.text[p.scanner.pos + 1] != `}` {
if p.tok == .lcbr && !p.inside_if_expr { //&& p.scanner.pos + 1 < p.scanner.text.len && p.scanner.text[p.scanner.pos + 1] != `}` {
p.fgenln2('')
p.fmt_inc()
}
}
[if vfmt]
fn (p mut Parser) gen_fmt() {
if p.pass != .main {
return
}
if p.file_name == '' {
return
}
s := p.scanner.fmt_out.str().trim_space()
if s == '' {
return
}
println('GENERATING ${p.file_name}.V')
out := os.create('/var/tmp/fmt/' + p.file_name) or {
verror('failed to create fmt.v')
return
}
//println(p.scanner.fmt_out.str())
out.writeln(p.scanner.fmt_out.str().trim_space())
out.close()
}