run vfmt on fn.v

pull/3132/head
Alexander Medvednikov 2019-12-18 09:04:35 +03:00
parent 81045023c4
commit 569b32bd1e
6 changed files with 347 additions and 323 deletions

1
v.v
View File

@ -21,7 +21,6 @@ const (
fn main() { fn main() {
//t := time.ticks() //t := time.ticks()
//defer { println(time.ticks() - t) } //defer { println(time.ticks() - t) }
// There's no `flags` module yet, so args have to be parsed manually
args := compiler.env_vflags_and_os_args() args := compiler.env_vflags_and_os_args()
options, command := compiler.get_v_options_and_main_command( args ) options, command := compiler.get_v_options_and_main_command( args )
// external tool // external tool

View File

@ -1,7 +1,6 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module compiler module compiler
import ( import (
@ -56,8 +55,11 @@ mut:
} }
const ( const (
EmptyFn = Fn{} EmptyFn = Fn{
MainFn = Fn{ name: 'main' } }
MainFn = Fn{
name: 'main'
}
) )
pub fn (a []TypeInst) str() string { pub fn (a []TypeInst) str() string {
@ -165,7 +167,11 @@ fn (p &Parser) known_var_check_new_var(name string) bool {
} }
fn (p mut Parser) register_var(v Var) { fn (p mut Parser) register_var(v Var) {
mut new_var := {v | idx: p.var_idx, scope_level: p.cur_fn.scope_level} mut new_var := {
v |
idx:p.var_idx,
scope_level:p.cur_fn.scope_level
}
if v.line_nr == 0 { if v.line_nr == 0 {
new_var.token_idx = p.cur_tok_index() new_var.token_idx = p.cur_tok_index()
new_var.line_nr = p.cur_tok().line_nr new_var.line_nr = p.cur_tok().line_nr
@ -189,13 +195,15 @@ fn (p mut Parser) clear_vars() {
} }
p.local_vars = [] p.local_vars = []
} }
} }
// Function signatures are added to the top of the .c file in the first run. // Function signatures are added to the top of the .c file in the first run.
fn (p mut Parser) fn_decl() { fn (p mut Parser) fn_decl() {
p.clear_vars() // clear local vars every time a new fn is started p.clear_vars() // clear local vars every time a new fn is started
defer { p.fgen_nl() p.fgen_nl() } defer {
p.fgen_nl()
p.fgen_nl()
}
fn_start_idx := p.cur_tok_index() fn_start_idx := p.cur_tok_index()
// If we are in the first pass, create a new function. // If we are in the first pass, create a new function.
// In the second pass fetch the one we created. // In the second pass fetch the one we created.
@ -208,10 +216,12 @@ fn (p mut Parser) fn_decl() {
else { else {
} }
*/ */
is_pub := p.tok == .key_pub is_pub := p.tok == .key_pub
mut f := Fn{ mut f := Fn{
mod: p.mod mod: p.mod
is_public: is_pub || p.is_vh // functions defined in .vh are always public is_public: is_pub || p.is_vh // functions defined in .vh are always public
is_unsafe: p.attr == 'unsafe_fn' is_unsafe: p.attr == 'unsafe_fn'
is_deprecated: p.attr == 'deprecated' is_deprecated: p.attr == 'deprecated'
comptime_define: if p.attr.starts_with('if ') {p.attr[3..]}else {''} comptime_define: if p.attr.starts_with('if ') {p.attr[3..]}else {''}
@ -228,7 +238,6 @@ fn (p mut Parser) fn_decl() {
// p.gen('/* returns $p.returns */') // p.gen('/* returns $p.returns */')
p.next() p.next()
p.fspace() p.fspace()
// Method receiver // Method receiver
mut receiver_typ := '' mut receiver_typ := ''
if p.tok == .lpar { if p.tok == .lpar {
@ -253,8 +262,7 @@ fn (p mut Parser) fn_decl() {
p.error('invalid receiver type `$receiver_typ` (`$receiver_typ` is an interface)') p.error('invalid receiver type `$receiver_typ` (`$receiver_typ` is an interface)')
} }
// Don't allow modifying types from a different module // Don't allow modifying types from a different module
if !p.first_pass() && !p.builtin_mod && t.mod != p.mod && if !p.first_pass() && !p.builtin_mod && t.mod != p.mod && !p.is_vgen // let vgen define methods like .str() on types defined in other modules
!p.is_vgen // let vgen define methods like .str() on types defined in other modules
{ {
// println('T.mod=$T.mod') // println('T.mod=$T.mod')
// println('p.mod=$p.mod') // println('p.mod=$p.mod')
@ -325,9 +333,7 @@ fn (p mut Parser) fn_decl() {
// full mod function name // full mod function name
// `os.exit()` ==> `os__exit()` // `os.exit()` ==> `os__exit()`
// if !is_c && !p.builtin_mod && receiver_typ.len == 0 { // if !is_c && !p.builtin_mod && receiver_typ.len == 0 {
if !is_c && !has_receiver && if !is_c && !has_receiver && (!p.builtin_mod || (p.builtin_mod && f.name == 'init')) {
(!p.builtin_mod || (p.builtin_mod && f.name == 'init'))
{
f.name = p.prepend_mod(f.name) f.name = p.prepend_mod(f.name)
} }
if p.first_pass() && receiver_typ.len == 0 { if p.first_pass() && receiver_typ.len == 0 {
@ -345,7 +351,8 @@ fn (p mut Parser) fn_decl() {
if p.generic_dispatch.inst.size > 0 { if p.generic_dispatch.inst.size > 0 {
f.dispatch_of = p.generic_dispatch f.dispatch_of = p.generic_dispatch
rename_generic_fn_instance(mut f, f.dispatch_of) rename_generic_fn_instance(mut f, f.dispatch_of)
} else { }
else {
f.is_generic = true f.is_generic = true
} }
p.next() p.next()
@ -358,7 +365,9 @@ fn (p mut Parser) fn_decl() {
p.error('redeclaration of type parameter `$type_par`') p.error('redeclaration of type parameter `$type_par`')
} }
f.type_pars << type_par f.type_pars << type_par
if p.tok == .gt { break } if p.tok == .gt {
break
}
p.check(.comma) p.check(.comma)
} }
p.check(.gt) p.check(.gt)
@ -367,7 +376,8 @@ fn (p mut Parser) fn_decl() {
// Args (...) // Args (...)
p.fn_args(mut f) p.fn_args(mut f)
if is_op { if is_op {
if f.args.len != 1 + 1 { // +1 is for the receiver if f.args.len != 1 + 1 {
// +1 is for the receiver
p.error('operator overloading methods must have only 1 argument') p.error('operator overloading methods must have only 1 argument')
} }
if f.args[0].typ != f.args[1].typ { if f.args[0].typ != f.args[1].typ {
@ -460,18 +470,19 @@ fn (p mut Parser) fn_decl() {
} }
// println('added generic method r:$rcv.name f:$f.name') // println('added generic method r:$rcv.name f:$f.name')
p.add_method(rcv.name, f) p.add_method(rcv.name, f)
} else { }
else {
p.table.register_fn(f) p.table.register_fn(f)
} }
} }
p.set_current_fn(EmptyFn) p.set_current_fn(EmptyFn)
p.skip_fn_body() p.skip_fn_body()
return return
} else { }
else {
p.gen_fn_decl(f, typ, str_args) p.gen_fn_decl(f, typ, str_args)
} }
} }
if is_fn_header { if is_fn_header {
p.genln('$typ $fn_name_cgen ($str_args);') p.genln('$typ $fn_name_cgen ($str_args);')
p.fgen_nl() p.fgen_nl()
@ -527,7 +538,6 @@ fn (p mut Parser) fn_decl() {
// p.genln('// live_function body start') // p.genln('// live_function body start')
p.genln('pthread_mutex_lock(&live_fn_mutex);') p.genln('pthread_mutex_lock(&live_fn_mutex);')
} }
if f.name in ['main__main', 'main', 'WinMain'] { if f.name in ['main__main', 'main', 'WinMain'] {
if p.pref.is_test { if p.pref.is_test {
p.error_with_token_index('tests cannot have function `main`', f.fn_name_token_idx) p.error_with_token_index('tests cannot have function `main`', f.fn_name_token_idx)
@ -585,6 +595,7 @@ fn (p mut Parser) fn_decl() {
return return
} }
*/ */
p.genln('}') p.genln('}')
if !p.builtin_mod && p.mod != 'os' { if !p.builtin_mod && p.mod != 'os' {
p.check_unused_and_mut_vars() p.check_unused_and_mut_vars()
@ -623,13 +634,7 @@ fn (p mut Parser) skip_fn_body() {
} }
fn (p &Parser) get_linkage_prefix() string { fn (p &Parser) get_linkage_prefix() string {
return if p.pref.ccompiler == 'msvc' && p.attr == 'live' && p.pref.is_so { return if p.pref.ccompiler == 'msvc' && p.attr == 'live' && p.pref.is_so {'__declspec(dllexport) '}else if p.attr == 'inline' {'static inline '}else {''}
'__declspec(dllexport) '
} else if p.attr == 'inline' {
'static inline '
} else {
''
}
} }
fn (p mut Parser) check_unused_and_mut_vars() { fn (p mut Parser) check_unused_and_mut_vars() {
@ -637,15 +642,10 @@ fn (p mut Parser) check_unused_and_mut_vars() {
if var.name == '' { if var.name == '' {
break break
} }
if !var.is_used && !p.pref.is_repl && !var.is_arg && if !var.is_used && !p.pref.is_repl && !var.is_arg && !p.pref.translated && var.name != 'tmpl_res' && p.mod != 'vweb' {
!p.pref.translated && var.name != 'tmpl_res' && p.mod != 'vweb'
{
p.production_error_with_token_index('`$var.name` declared and not used', var.token_idx) p.production_error_with_token_index('`$var.name` declared and not used', var.token_idx)
} }
if !var.is_changed && var.is_mut && !p.pref.is_repl && if !var.is_changed && var.is_mut && !p.pref.is_repl && !p.pref.translated && var.typ != 'T*' && p.mod != 'ui' && var.typ != 'App*' {
!p.pref.translated && var.typ != 'T*' &&
p.mod != 'ui' && var.typ != 'App*'
{
p.error_with_token_index('`$var.name` is declared as mutable, but it was never changed', var.token_idx) p.error_with_token_index('`$var.name` is declared as mutable, but it was never changed', var.token_idx)
} }
} }
@ -698,12 +698,10 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
} }
did_gen_something = true did_gen_something = true
} }
if !did_gen_something { if !did_gen_something {
// Msvc doesnt like empty struct // Msvc doesnt like empty struct
arg_struct += 'EMPTY_STRUCT_DECLARATION;' arg_struct += 'EMPTY_STRUCT_DECLARATION;'
} }
arg_struct += '} $arg_struct_name ;' arg_struct += '} $arg_struct_name ;'
// Also register the wrapper, so we can use the original function without modifying it // Also register the wrapper, so we can use the original function without modifying it
fn_name = p.table.fn_gen_name(f) fn_name = p.table.fn_gen_name(f)
@ -733,7 +731,6 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
p.genln('int $tmp2 = pthread_create(& $thread_name, NULL, (void *)$wrapper_name, $parg);') p.genln('int $tmp2 = pthread_create(& $thread_name, NULL, (void *)$wrapper_name, $parg);')
} }
p.check(.rpar) p.check(.rpar)
} }
fn (p mut Parser) verify_fn_before_call(f &Fn) { fn (p mut Parser) verify_fn_before_call(f &Fn) {
@ -765,7 +762,8 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
if f.is_c && !p.builtin_mod { if f.is_c && !p.builtin_mod {
if f.name == 'free' { if f.name == 'free' {
p.error('use `free()` instead of `C.free()`') p.error('use `free()` instead of `C.free()`')
} else if f.name == 'malloc' { }
else if f.name == 'malloc' {
p.error('use `malloc()` instead of `C.malloc()`') p.error('use `malloc()` instead of `C.malloc()`')
} }
} }
@ -777,7 +775,8 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
for { for {
if p.tokens[i].tok == .gt { if p.tokens[i].tok == .gt {
p.error('explicit type arguments are not allowed; remove `<...>`') p.error('explicit type arguments are not allowed; remove `<...>`')
} else if p.tokens[i].tok == .lpar { }
else if p.tokens[i].tok == .lpar {
// probably a typo, do not concern the user with the above error message // probably a typo, do not concern the user with the above error message
break break
} }
@ -787,12 +786,10 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
// if p.pref.is_prof { // if p.pref.is_prof {
// p.cur_fn.called_fns << cgen_name // p.cur_fn.called_fns << cgen_name
// } // }
// If we have a method placeholder, // If we have a method placeholder,
// we need to preappend "method(receiver, ...)" // we need to preappend "method(receiver, ...)"
if f.is_method { if f.is_method {
receiver := f.args.first() receiver := f.args.first()
mut receiver_is_interface := false mut receiver_is_interface := false
if receiver.typ.ends_with('er') { if receiver.typ.ends_with('er') {
// I absolutely love this syntax // I absolutely love this syntax
@ -820,39 +817,33 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
if receiver.is_mut && !p.expr_var.is_mut { if receiver.is_mut && !p.expr_var.is_mut {
// println('$method_call recv=$receiver.name recv_mut=$receiver.is_mut') // println('$method_call recv=$receiver.name recv_mut=$receiver.is_mut')
if p.expr_var.is_for_var { if p.expr_var.is_for_var {
p.error('`$p.expr_var.name` is immutable, `for` variables' + p.error('`$p.expr_var.name` is immutable, `for` variables' + ' always are')
' always are') }
} else { else {
p.error('`$p.expr_var.name` is immutable, declare it with `mut`') p.error('`$p.expr_var.name` is immutable, declare it with `mut`')
} }
} }
if !p.expr_var.is_changed && receiver.is_mut { if !p.expr_var.is_changed && receiver.is_mut {
p.mark_var_changed(p.expr_var) p.mark_var_changed(p.expr_var)
} }
if !receiver_is_interface { if !receiver_is_interface {
p.gen_method_call(receiver, receiver_type, cgen_name, f.typ, method_ph) p.gen_method_call(receiver, receiver_type, cgen_name, f.typ, method_ph)
} }
} else { }
else {
// Normal function call // Normal function call
p.gen('$cgen_name (') p.gen('$cgen_name (')
} }
// `foo<Bar>()` // `foo<Bar>()`
// if f is generic, the name is changed to a suitable instance in dispatch_generic_fn_instance() // if f is generic, the name is changed to a suitable instance in dispatch_generic_fn_instance()
// we then replace `cgen_name` with the instance's name // we then replace `cgen_name` with the instance's name
generic := f.is_generic generic := f.is_generic
p.fn_call_args(mut f) p.fn_call_args(mut f)
if generic { if generic {
line := if p.cgen.is_tmp { line := if p.cgen.is_tmp {p.cgen.tmp_line}else {p.cgen.cur_line}
p.cgen.tmp_line
} else {
p.cgen.cur_line
}
p.cgen.resetln(line.replace('$cgen_name (', '$f.name (')) p.cgen.resetln(line.replace('$cgen_name (', '$f.name ('))
// println('calling inst $f.name: $p.cgen.cur_line') // println('calling inst $f.name: $p.cgen.cur_line')
} }
// if !is_interface { // if !is_interface {
p.gen(')') p.gen(')')
// } // }
@ -863,12 +854,13 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
} }
// println('end of fn call typ=$f.typ') // println('end of fn call typ=$f.typ')
} }
// for declaration // for declaration
// update the Fn object's args[] // update the Fn object's args[]
fn (p mut Parser) fn_args(f mut Fn) { fn (p mut Parser) fn_args(f mut Fn) {
p.check(.lpar) p.check(.lpar)
defer { p.check(.rpar) } defer {
p.check(.rpar)
}
if f.is_interface { if f.is_interface {
interface_arg := Var{ interface_arg := Var{
typ: f.receiver_typ typ: f.receiver_typ
@ -882,7 +874,8 @@ fn (p mut Parser) fn_args(f mut Fn) {
if types_only { if types_only {
for p.tok != .rpar { for p.tok != .rpar {
typ := p.get_type() typ := p.get_type()
if typ == '' { //&& !f.is_c { if typ == '' {
// && !f.is_c {
if p.prev_tok != .ellipsis { if p.prev_tok != .ellipsis {
p.error('bad fn arg type') p.error('bad fn arg type')
} }
@ -892,6 +885,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
typ: typ typ: typ
is_arg: true is_arg: true
// is_mut: is_mut // is_mut: is_mut
line_nr: p.scanner.line_nr line_nr: p.scanner.line_nr
token_idx: p.cur_tok_index() token_idx: p.cur_tok_index()
} }
@ -899,6 +893,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
f.args << v f.args << v
if p.tok == .comma { if p.tok == .comma {
p.next() p.next()
p.fspace()
} }
} }
} }
@ -915,6 +910,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
is_mut := p.tok == .key_mut is_mut := p.tok == .key_mut
if is_mut { if is_mut {
p.check(.key_mut) p.check(.key_mut)
p.fspace()
} }
// variadic arg // variadic arg
if p.tok == .ellipsis { if p.tok == .ellipsis {
@ -935,14 +931,14 @@ fn (p mut Parser) fn_args(f mut Fn) {
p.register_vargs_stuct(typ, 0) p.register_vargs_stuct(typ, 0)
} }
typ = 'varg_$typ' typ = 'varg_$typ'
} else { }
else {
typ = '...$typ' // TODO: fix, this is invalid in C typ = '...$typ' // TODO: fix, this is invalid in C
} }
} }
p.check_and_register_used_imported_type(typ) p.check_and_register_used_imported_type(typ)
if is_mut && is_primitive_type(typ) { if is_mut && is_primitive_type(typ) {
p.error('mutable arguments are only allowed for arrays, maps, and structs.' + p.error('mutable arguments are only allowed for arrays, maps, and structs.' + '\nreturn values instead: `fn foo(n mut int) {` => `fn foo(n int) int {`')
'\nreturn values instead: `fn foo(n mut int) {` => `fn foo(n int) int {`')
} }
for name in names { for name in names {
if is_mut { if is_mut {
@ -962,6 +958,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
} }
if p.tok == .comma { if p.tok == .comma {
p.check(.comma) p.check(.comma)
p.fspace()
} }
// unnamed (C definition) // unnamed (C definition)
if p.tok == .ellipsis { if p.tok == .ellipsis {
@ -1008,17 +1005,15 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
mod_name := p.mod.replace('_dot_', '.') mod_name := p.mod.replace('_dot_', '.')
fn_name := p.cur_fn.name.replace('${p.mod}__', '') fn_name := p.cur_fn.name.replace('${p.mod}__', '')
file_path := cescaped_path(p.file_path) file_path := cescaped_path(p.file_path)
p.cgen.resetln(p.cgen.cur_line.replace( p.cgen.resetln(p.cgen.cur_line.replace('v_panic (', 'panic_debug ($p.scanner.line_nr, tos3("$file_path"), tos3("$mod_name"), tos2((byte *)"$fn_name"), '))
'v_panic (',
'panic_debug ($p.scanner.line_nr, tos3("$file_path"), tos3("$mod_name"), tos2((byte *)"$fn_name"), '
))
} }
mut saved_args := []string mut saved_args := []string
for i,arg in f.args { for i,arg in f.args {
// Receiver is the first arg // Receiver is the first arg
// Skip the receiver, because it was already generated in the expression // Skip the receiver, because it was already generated in the expression
if i == 0 && f.is_method { if i == 0 && f.is_method {
if f.args.len > 1 { // && !p.is_js { if f.args.len > 1 {
// && !p.is_js {
p.gen(', ') p.gen(', ')
} }
// if f.args[0].typ.ends_with('*') { // if f.args[0].typ.ends_with('*') {
@ -1036,6 +1031,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
} }
} }
*/ */
continue continue
} }
// Reached the final vararg? Quit // Reached the final vararg? Quit
@ -1054,15 +1050,13 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
p.mutable_arg_error(i, arg, f) p.mutable_arg_error(i, arg, f)
} }
if p.peek() != .name { if p.peek() != .name {
p.error('`$arg.name` is a mutable argument, you need to ' + p.error('`$arg.name` is a mutable argument, you need to ' + 'provide a variable to modify: `${f.name}(... mut a...)`')
'provide a variable to modify: `${f.name}(... mut a...)`')
} }
p.check(.key_mut) p.check(.key_mut)
p.fspace() p.fspace()
var_name := p.lit var_name := p.lit
v := p.find_var(var_name) or { v := p.find_var(var_name) or {
p.error('`$arg.name` is a mutable argument, you need to ' + p.error('`$arg.name` is a mutable argument, you need to ' + 'provide a variable to modify: `${f.name}(... mut a...)`')
'provide a variable to modify: `${f.name}(... mut a...)`')
exit(1) exit(1)
} }
if !v.is_changed { if !v.is_changed {
@ -1070,17 +1064,14 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
} }
} }
p.expected_type = arg.typ p.expected_type = arg.typ
clone := p.pref.autofree && p.mod != 'string' && arg.typ == 'string' && clone := p.pref.autofree && p.mod != 'string' && arg.typ == 'string' && !p.builtin_mod // && arg.is_moved
!p.builtin_mod //&& arg.is_moved
if clone { if clone {
p.gen('/*YY f=$f.name arg=$arg.name is_moved=$arg.is_moved*/string_clone(') p.gen('/*YY f=$f.name arg=$arg.name is_moved=$arg.is_moved*/string_clone(')
} }
// x64 println gen // x64 println gen
if p.pref.x64 && i == 0 && f.name == 'println' && p.tok == .str && p.peek() == .rpar { if p.pref.x64 && i == 0 && f.name == 'println' && p.tok == .str && p.peek() == .rpar {
p.x64.gen_print(p.lit) p.x64.gen_print(p.lit)
} }
mut typ := p.bool_expression() mut typ := p.bool_expression()
// Register an interface type usage: // Register an interface type usage:
// fn run(r Animal) { ... } // fn run(r Animal) { ... }
@ -1096,12 +1087,9 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
p.table.add_gen_type(arg.typ, typ) p.table.add_gen_type(arg.typ, typ)
} }
} }
if clone { if clone {
p.gen(')') p.gen(')')
} }
// Optimize `println`: replace it with `printf` to avoid extra allocations and // Optimize `println`: replace it with `printf` to avoid extra allocations and
// function calls. // function calls.
// `println(777)` => `printf("%d\n", 777)` // `println(777)` => `printf("%d\n", 777)`
@ -1112,9 +1100,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
} }
typ = 'string' typ = 'string'
} }
if i == 0 && (f.name == 'println' || f.name == 'print') && if i == 0 && (f.name == 'println' || f.name == 'print') && !(typ in ['string', 'ustring', 'void']) {
!(typ in ['string', 'ustring', 'void' ])
{
// //
T := p.table.find_type(typ) T := p.table.find_type(typ)
$if !windows { $if !windows {
@ -1122,8 +1108,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
fmt := p.typ_to_fmt(typ, 0) fmt := p.typ_to_fmt(typ, 0)
if fmt != '' && typ != 'bool' { if fmt != '' && typ != 'bool' {
nl := if f.name == 'println' {'\\n'}else {''} nl := if f.name == 'println' {'\\n'}else {''}
p.cgen.resetln(p.cgen.cur_line.replace(f.name + p.cgen.resetln(p.cgen.cur_line.replace(f.name + ' (', '/*opt*/printf ("' + fmt + '$nl", '))
' (', '/*opt*/printf ("' + fmt + '$nl", '))
continue continue
} }
} }
@ -1156,7 +1141,8 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
p.cgen.set_placeholder(ph, '${typ}_str(') p.cgen.set_placeholder(ph, '${typ}_str(')
p.gen(')') p.gen(')')
continue continue
} else { }
else {
base := p.base_type(T.name) base := p.base_type(T.name)
if base != T.name { if base != T.name {
base_type := p.find_type(base) base_type := p.find_type(base)
@ -1184,7 +1170,8 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
if type_mismatch && f.is_generic { if type_mismatch && f.is_generic {
// println("argument `$arg.name` is generic") // println("argument `$arg.name` is generic")
saved_args << got saved_args << got
} else if type_mismatch { }
else if type_mismatch {
mut j := i mut j := i
if f.is_method { if f.is_method {
j-- j--
@ -1192,14 +1179,16 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
mut nr := '${j+1}th' mut nr := '${j+1}th'
if j == 0 { if j == 0 {
nr = 'first' nr = 'first'
} else if j == 1 { }
else if j == 1 {
nr = 'second' nr = 'second'
} else if j == 2 { }
else if j == 2 {
nr = 'third' nr = 'third'
} }
p.error('cannot use type `$typ` as type `$arg.typ` in $nr ' + p.error('cannot use type `$typ` as type `$arg.typ` in $nr ' + 'argument to `${f.name}()`')
'argument to `${f.name}()`') }
} else { else {
saved_args << '' saved_args << ''
} }
is_interface := p.table.is_interface(arg.typ) is_interface := p.table.is_interface(arg.typ)
@ -1220,7 +1209,8 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
// Special case for mutable arrays. We can't `&` function // Special case for mutable arrays. We can't `&` function
// results, // results,
// have to use `(array[]){ expr }` hack. // have to use `(array[]){ expr }` hack.
if expected.starts_with('array_') && exp_ptr { //&& !arg.is_mut{ if expected.starts_with('array_') && exp_ptr {
// && !arg.is_mut{
p.cgen.set_placeholder(ph, '& /*111*/ (array[]){') p.cgen.set_placeholder(ph, '& /*111*/ (array[]){')
p.gen('}[0] ') p.gen('}[0] ')
} }
@ -1233,19 +1223,16 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
// println('fn hack expr=$expr') // println('fn hack expr=$expr')
p.cgen.set_placeholder(ph, '& /*113 e="$expected" g="$got"*/ ($got[]){') p.cgen.set_placeholder(ph, '& /*113 e="$expected" g="$got"*/ ($got[]){')
p.gen('}[0] ') p.gen('}[0] ')
} else { }
else {
p.cgen.set_placeholder(ph, '& /*114*/') p.cgen.set_placeholder(ph, '& /*114*/')
} }
} $else { } $else {
p.cgen.set_placeholder(ph, '& /*114*/') p.cgen.set_placeholder(ph, '& /*114*/')
} }
} }
// println('\ne:"$expected" got:"$got"') // println('\ne:"$expected" got:"$got"')
else if ! (expected == 'void*' && got == 'int') && else if !(expected == 'void*' && got == 'int') && !(expected == 'void*' && got == 'byteptr') && !(expected == 'byte*' && got.contains(']byte')) && !(expected == 'byte*' && got == 'string') &&
! (expected == 'void*' && got == 'byteptr') &&
! (expected == 'byte*' && got.contains(']byte')) &&
! (expected == 'byte*' && got == 'string') &&
// ! (expected == 'void*' && got == 'array_int') { // ! (expected == 'void*' && got == 'array_int') {
!(expected == 'byte*' && got == 'byteptr') && !p.pref.is_bare { !(expected == 'byte*' && got == 'byteptr') && !p.pref.is_bare {
p.cgen.set_placeholder(ph, '& /*112 e="$expected" g="$got" */') p.cgen.set_placeholder(ph, '& /*112 e="$expected" g="$got" */')
@ -1296,12 +1283,17 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
// From a given generic function and an argument list matching its signature, // From a given generic function and an argument list matching its signature,
// create a type instantiation // create a type instantiation
fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst { fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst {
mut r := TypeInst{} mut r := TypeInst{
}
mut i := 0 mut i := 0
mut args := args_ mut args := args_
if f.typ != 'void' { args << f.typ } if f.typ != 'void' {
args << f.typ
}
for e in args { for e in args {
if e == '' { continue } if e == '' {
continue
}
tp := f.type_pars[i] tp := f.type_pars[i]
mut ti := e mut ti := e
if ti.starts_with('fn (') { if ti.starts_with('fn (') {
@ -1309,7 +1301,9 @@ fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst {
mut found := false mut found := false
for fa_ in fn_args { for fa_ in fn_args {
mut fa := fa_ mut fa := fa_
for fa.starts_with('array_') { fa = fa[6..] } for fa.starts_with('array_') {
fa = fa[6..]
}
if fa == tp { if fa == tp {
r.inst[tp] = fa r.inst[tp] = fa
found = true found = true
@ -1317,10 +1311,14 @@ fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst {
break break
} }
} }
if found { continue } if found {
continue
}
ti = ti.all_after(') ') ti = ti.all_after(') ')
} }
for ti.starts_with('array_') { ti = ti[6..] } for ti.starts_with('array_') {
ti = ti[6..]
}
if r.inst[tp] != '' { if r.inst[tp] != '' {
if r.inst[tp] != ti { if r.inst[tp] != ti {
p.error('type parameter `$tp` has type ${r.inst[tp]}, not `$ti`') p.error('type parameter `$tp` has type ${r.inst[tp]}, not `$ti`')
@ -1330,7 +1328,9 @@ fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst {
// println("extracted $tp => $ti") // println("extracted $tp => $ti")
r.inst[tp] = ti r.inst[tp] = ti
i++ i++
if i >= f.type_pars.len { break } if i >= f.type_pars.len {
break
}
} }
if r.inst[f.typ] == '' && f.typ in f.type_pars { if r.inst[f.typ] == '' && f.typ in f.type_pars {
r.inst[f.typ] = '_ANYTYPE_' r.inst[f.typ] = '_ANYTYPE_'
@ -1346,9 +1346,10 @@ fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst {
// replace a generic type using TypeInst // replace a generic type using TypeInst
fn replace_generic_type(gen_type string, ti &TypeInst) string { fn replace_generic_type(gen_type string, ti &TypeInst) string {
mut typ := gen_type.replace('map_', '') mut typ := gen_type.replace('map_', '').replace('varg_', '').trim_right('*')
.replace('varg_', '').trim_right('*') for typ.starts_with('array_') {
for typ.starts_with('array_') { typ = typ[6..] } typ = typ[6..]
}
if typ in ti.inst { if typ in ti.inst {
typ = gen_type.replace(typ, ti.inst[typ]) typ = gen_type.replace(typ, ti.inst[typ])
return typ return typ
@ -1393,15 +1394,17 @@ fn (p mut Parser) register_vargs_stuct(typ string, len int) string {
if !p.table.known_type(vargs_struct) { if !p.table.known_type(vargs_struct) {
p.table.register_type(varg_type) p.table.register_type(varg_type)
p.cgen.typedefs << 'typedef struct $vargs_struct $vargs_struct;\n' p.cgen.typedefs << 'typedef struct $vargs_struct $vargs_struct;\n'
} else { }
else {
ex_typ := p.table.find_type(vargs_struct) ex_typ := p.table.find_type(vargs_struct)
ex_len := ex_typ.fields[1].name[5..ex_typ.fields[1].name.len - 1].int() ex_len := ex_typ.fields[1].name[5..ex_typ.fields[1].name.len - 1].int()
if ex_len > varg_len { varg_len = ex_len } if ex_len > varg_len {
varg_len = ex_len
}
p.table.rewrite_type(varg_type) p.table.rewrite_type(varg_type)
} }
p.table.add_field(vargs_struct, 'len', 'int', false, '', .public) p.table.add_field(vargs_struct, 'len', 'int', false, '', .public)
p.table.add_field(vargs_struct, 'args[$varg_len]', typ, false, '', .public) p.table.add_field(vargs_struct, 'args[$varg_len]', typ, false, '', .public)
return vargs_struct return vargs_struct
} }
@ -1418,28 +1421,27 @@ fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) {
p.check(.comma) p.check(.comma)
} }
varg_type,varg_value := p.tmp_expr() varg_type,varg_value := p.tmp_expr()
if varg_type.starts_with('varg_') && if varg_type.starts_with('varg_') && (values.len > 0 || p.tok == .comma) {
(values.len > 0 || p.tok == .comma)
{
p.error('You cannot pass additional vargs when forwarding vargs to another function/method') p.error('You cannot pass additional vargs when forwarding vargs to another function/method')
} }
if !f.is_generic { if !f.is_generic {
p.check_types(last_arg.typ, varg_type) p.check_types(last_arg.typ, varg_type)
} else { }
else {
if types.len > 0 { if types.len > 0 {
for t in types { for t in types {
p.check_types(varg_type, t) p.check_types(varg_type, t)
} }
} }
} }
ref_deref := if last_arg.typ.ends_with('*') && !varg_type.ends_with('*') { '&' } ref_deref := if last_arg.typ.ends_with('*') && !varg_type.ends_with('*') {'&'}else if !last_arg.typ.ends_with('*') && varg_type.ends_with('*') {'*'}else {''}
else if !last_arg.typ.ends_with('*') && varg_type.ends_with('*') { '*' }
else { '' }
types << varg_type types << varg_type
values << '$ref_deref$varg_value' values << '$ref_deref$varg_value'
} }
for va in p.table.varg_access { for va in p.table.varg_access {
if va.fn_name != f.name { continue } if va.fn_name != f.name {
continue
}
if va.index >= values.len { if va.index >= values.len {
p.error_with_token_index('variadic arg index out of range: $va.index/${values.len-1}, vargs are 0 indexed', va.tok_idx) p.error_with_token_index('variadic arg index out of range: $va.index/${values.len-1}, vargs are 0 indexed', va.tok_idx)
} }
@ -1452,9 +1454,11 @@ fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) {
fn (p mut Parser) fn_gen_caller_vargs(f &Fn, varg_type string, values []string) { fn (p mut Parser) fn_gen_caller_vargs(f &Fn, varg_type string, values []string) {
is_varg := varg_type.starts_with('varg_') is_varg := varg_type.starts_with('varg_')
if is_varg { // forwarding varg if is_varg {
// forwarding varg
p.cgen.gen('${values[0]}') p.cgen.gen('${values[0]}')
} else { }
else {
vargs_struct := p.register_vargs_stuct(varg_type, values.len) vargs_struct := p.register_vargs_stuct(varg_type, values.len)
p.cgen.gen('&($vargs_struct){.len=$values.len,.args={' + values.join(',') + '}}') p.cgen.gen('&($vargs_struct){.len=$values.len,.args={' + values.join(',') + '}}')
} }
@ -1462,10 +1466,12 @@ fn (p mut Parser) fn_gen_caller_vargs(f &Fn, varg_type string, values []string)
fn (p mut Parser) register_multi_return_stuct(types []string) string { fn (p mut Parser) register_multi_return_stuct(types []string) string {
typ := '_V_MulRet_' + types.join('_V_').replace('*', '_PTR_') typ := '_V_MulRet_' + types.join('_V_').replace('*', '_PTR_')
if p.table.known_type(typ) { return typ } if p.table.known_type(typ) {
return typ
}
p.table.register_type(Type{ p.table.register_type(Type{
cat: .struct_, cat: .struct_
name: typ, name: typ
mod: p.mod mod: p.mod
}) })
for i,t in typ.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_') { for i,t in typ.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_') {
@ -1516,7 +1522,8 @@ fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti &TypeInst) {
if f.is_method { if f.is_method {
// TODO: add_method won't add anything on second pass // TODO: add_method won't add anything on second pass
// p.add_method(f.args[0].typ.trim_right('*'), f) // p.add_method(f.args[0].typ.trim_right('*'), f)
} else { }
else {
p.table.register_fn(f) p.table.register_fn(f)
} }
mut gp := p.v.parsers[f.parser_idx] mut gp := p.v.parsers[f.parser_idx]
@ -1529,7 +1536,6 @@ fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti &TypeInst) {
gp.fn_decl() gp.fn_decl()
p.cgen.lines_extra << p.cgen.lines p.cgen.lines_extra << p.cgen.lines
p.restore_state(saved_state, false, true) p.restore_state(saved_state, false, true)
p.cgen.fns << '${p.fn_signature(f)};' p.cgen.fns << '${p.fn_signature(f)};'
} }
@ -1598,7 +1604,9 @@ fn (p &Parser) find_misspelled_local_var(name string, min_match f32) string {
continue continue
} }
n := name.all_after('.') n := name.all_after('.')
if var.name == '' || (n.len - var.name.len > 2 || var.name.len - n.len > 2) { continue } if var.name == '' || (n.len - var.name.len > 2 || var.name.len - n.len > 2) {
continue
}
c := strings.dice_coefficient(var.name, n) c := strings.dice_coefficient(var.name, n)
if c > closest { if c > closest {
closest = c closest = c
@ -1616,6 +1624,7 @@ fn (fns []Fn) contains(f Fn) bool {
} }
return false return false
} }
fn (p &Parser) fn_signature(f &Fn) string { fn (p &Parser) fn_signature(f &Fn) string {
return '$f.typ ${f.name}(${f.str_args(p.table)})' return '$f.typ ${f.name}(${f.str_args(p.table)})'
} }

View File

@ -1159,6 +1159,20 @@ pub fn vfmt(args[]string) {
println('v fmt can only be used on .v files') println('v fmt can only be used on .v files')
exit(1) exit(1)
} }
println('WIP')
/*
vexe := vexe_path()
//launch_tool('vfmt', '-d vfmt')
vroot := os.dir(vexe)
os.chdir(vroot)
ret := os.system('$vexe -o $vroot/tools/vfmt -d vfmt v.v')
if ret != 0 {
println('err')
return
}
os.exec('$vroot/tools/vfmt $file') or { panic(err) }
//if !os.exists('
*/
} }
pub fn create_symlink() { pub fn create_symlink() {

View File

@ -853,6 +853,9 @@ fn (p &Parser) strtok() string {
return p.lit return p.lit
} }
if p.tok == .chartoken { if p.tok == .chartoken {
if p.lit == '`' {
return '`\\$p.lit`'
}
return '`$p.lit`' return '`$p.lit`'
} }
if p.tok == .str { if p.tok == .str {
@ -2902,6 +2905,7 @@ fn (p mut Parser) attribute() {
fn (p mut Parser) defer_st() { fn (p mut Parser) defer_st() {
p.check(.key_defer) p.check(.key_defer)
p.fspace()
p.check(.lcbr) p.check(.lcbr)
pos := p.cgen.lines.len pos := p.cgen.lines.len
// Save everything inside the defer block to `defer_text`. // Save everything inside the defer block to `defer_text`.

View File

@ -75,8 +75,6 @@ fn new_scanner_file(file_path string) &Scanner {
fn new_scanner(text string) &Scanner { fn new_scanner(text string) &Scanner {
return &Scanner{ return &Scanner{
text: text text: text
// fmt_out: strings.new_builder(1000)
print_line_on_error: true print_line_on_error: true
print_colored_error: true print_colored_error: true
print_rel_paths_on_error: true print_rel_paths_on_error: true

View File

@ -243,16 +243,16 @@ fn (p &Parser) gen_fmt() {
if s == '' { if s == '' {
return return
} }
if !p.file_name.contains('scanner.v') {return} if !p.file_name.contains('fn.v') {return}
path := os.tmpdir() + '/' + p.file_name path := os.tmpdir() + '/' + p.file_name
println('generating ${path}') println('generating ${path}')
mut out := os.create(path) or { mut out := os.create(path) or {
verror('failed to create fmt.v') verror('failed to create fmt.v')
return return
} }
println('replacing ${p.file_path}...') println('replacing ${p.file_path}...\n')
os.mv(path, p.file_path)
out.writeln(s)//p.scanner.fmt_out.str().trim_space()) out.writeln(s)//p.scanner.fmt_out.str().trim_space())
out.close() out.close()
os.mv(path, p.file_path)
} }