mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: add varg str method & varg / parser optimizations
This commit is contained in:
parent
7b1993b1e4
commit
4120982da1
|
@ -331,7 +331,32 @@ fn (p mut Parser) gen_struct_str(typ Type) {
|
||||||
p.v.vgen_buf.writeln(sb.str())
|
p.v.vgen_buf.writeln(sb.str())
|
||||||
// Need to manually add the definition to `fns` so that it stays
|
// Need to manually add the definition to `fns` so that it stays
|
||||||
// at the top of the file.
|
// at the top of the file.
|
||||||
// This function will get parsee by V after the main pass.
|
// This function will get parsed by V after the main pass.
|
||||||
|
p.cgen.fns << 'string ${typ.name}_str();'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (p mut Parser) gen_varg_str(typ Type) {
|
||||||
|
elm_type := typ.name[5..]
|
||||||
|
elm_type2 := p.table.find_type(elm_type)
|
||||||
|
is_array := elm_type.starts_with('array_')
|
||||||
|
if is_array {
|
||||||
|
p.gen_array_str(elm_type2)
|
||||||
|
} else if elm_type2.cat == .struct_ {
|
||||||
|
p.gen_struct_str(elm_type2)
|
||||||
|
}
|
||||||
|
p.v.vgen_buf.writeln('
|
||||||
|
fn (a $typ.name) str() string {
|
||||||
|
mut sb := strings.new_builder(a.len * 3)
|
||||||
|
sb.write("[")
|
||||||
|
for i, elm in a {
|
||||||
|
sb.write(elm.str())
|
||||||
|
if i < a.len - 1 {
|
||||||
|
sb.write(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.write("]")
|
||||||
|
return sb.str()
|
||||||
|
}')
|
||||||
p.cgen.fns << 'string ${typ.name}_str();'
|
p.cgen.fns << 'string ${typ.name}_str();'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -713,7 +713,6 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
|
||||||
// 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 {
|
||||||
|
@ -803,7 +802,6 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
||||||
if is_mut {
|
if is_mut {
|
||||||
p.check(.key_mut)
|
p.check(.key_mut)
|
||||||
}
|
}
|
||||||
mut typ := ''
|
|
||||||
// variadic arg
|
// variadic arg
|
||||||
if p.tok == .ellipsis {
|
if p.tok == .ellipsis {
|
||||||
p.check(.ellipsis)
|
p.check(.ellipsis)
|
||||||
|
@ -811,25 +809,28 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
||||||
p.error('you must provide a type for vargs: eg `...string`. multiple types `...` are not supported yet.')
|
p.error('you must provide a type for vargs: eg `...string`. multiple types `...` are not supported yet.')
|
||||||
}
|
}
|
||||||
f.is_variadic = true
|
f.is_variadic = true
|
||||||
t := p.get_type()
|
}
|
||||||
|
mut typ := p.get_type()
|
||||||
|
if !p.first_pass() && !p.table.known_type(typ) {
|
||||||
|
p.error('fn_args: unknown type $typ')
|
||||||
|
}
|
||||||
|
if f.is_variadic {
|
||||||
|
if !f.is_c {
|
||||||
// register varg struct, incase function is never called
|
// register varg struct, incase function is never called
|
||||||
if p.first_pass() && !f.is_generic && !f.is_c{
|
if p.first_pass() && !f.is_generic {
|
||||||
p.register_vargs_stuct(t, 0)
|
p.register_vargs_stuct(typ, 0)
|
||||||
}
|
}
|
||||||
typ = '...$t'
|
typ = 'varg_$typ'
|
||||||
} else {
|
} else {
|
||||||
typ = p.get_type()
|
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: `foo(n mut int)` => `foo(n int) int`')
|
'\nreturn values instead: `foo(n mut int)` => `foo(n int) int`')
|
||||||
}
|
}
|
||||||
for name in names {
|
for name in names {
|
||||||
if !p.first_pass() && !p.table.known_type(typ) {
|
|
||||||
p.error('fn_args: unknown type $typ')
|
|
||||||
}
|
|
||||||
if is_mut {
|
if is_mut {
|
||||||
typ += '*'
|
typ += '*'
|
||||||
}
|
}
|
||||||
|
@ -908,7 +909,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Reached the final vararg? Quit
|
// Reached the final vararg? Quit
|
||||||
if i == f.args.len - 1 && arg.typ.starts_with('...') {
|
if i == f.args.len - 1 && arg.typ.starts_with('varg_') {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
ph := p.cgen.add_placeholder()
|
ph := p.cgen.add_placeholder()
|
||||||
|
@ -982,13 +983,22 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||||
// Make sure this type has a `str()` method
|
// Make sure this type has a `str()` method
|
||||||
$if !js {
|
$if !js {
|
||||||
if !T.has_method('str') {
|
if !T.has_method('str') {
|
||||||
|
// varg
|
||||||
|
if T.name.starts_with('varg_') {
|
||||||
|
p.gen_varg_str(T)
|
||||||
|
p.cgen.set_placeholder(ph, '${typ}_str(')
|
||||||
|
p.gen(')')
|
||||||
|
continue
|
||||||
|
}
|
||||||
// Arrays have automatic `str()` methods
|
// Arrays have automatic `str()` methods
|
||||||
if T.name.starts_with('array_') {
|
else if T.name.starts_with('array_') {
|
||||||
p.gen_array_str(T)
|
p.gen_array_str(T)
|
||||||
p.cgen.set_placeholder(ph, '${typ}_str(')
|
p.cgen.set_placeholder(ph, '${typ}_str(')
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
continue
|
continue
|
||||||
} else if T.cat == .struct_ {
|
}
|
||||||
|
// struct
|
||||||
|
else if T.cat == .struct_ {
|
||||||
p.gen_struct_str(T)
|
p.gen_struct_str(T)
|
||||||
p.cgen.set_placeholder(ph, '${typ}_str(')
|
p.cgen.set_placeholder(ph, '${typ}_str(')
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
|
@ -1190,11 +1200,12 @@ fn (p mut Parser) replace_type_params(f &Fn, ti TypeInst) []string {
|
||||||
fi = fi[6..]
|
fi = fi[6..]
|
||||||
fr += 'array_'
|
fr += 'array_'
|
||||||
}
|
}
|
||||||
is_varg := fi.starts_with('...')
|
if fi.starts_with('varg_') {
|
||||||
if is_varg { fi = fi[3..] }
|
fi = fi[5..]
|
||||||
|
fr += 'varg_'
|
||||||
|
}
|
||||||
if fi in ti.inst.keys() {
|
if fi in ti.inst.keys() {
|
||||||
mut t := ti.inst[fi]
|
mut t := ti.inst[fi]
|
||||||
if is_varg { t = '...$t' }
|
|
||||||
fr += t
|
fr += t
|
||||||
// println("replaced $a => $fr")
|
// println("replaced $a => $fr")
|
||||||
} else {
|
} else {
|
||||||
|
@ -1206,7 +1217,7 @@ fn (p mut Parser) replace_type_params(f &Fn, ti TypeInst) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) register_vargs_stuct(typ string, len int) string {
|
fn (p mut Parser) register_vargs_stuct(typ string, len int) string {
|
||||||
vargs_struct := '_V_FnVargs_$typ'
|
vargs_struct := 'varg_$typ'
|
||||||
varg_type := Type{
|
varg_type := Type{
|
||||||
cat: TypeCategory.struct_,
|
cat: TypeCategory.struct_,
|
||||||
name: vargs_struct,
|
name: vargs_struct,
|
||||||
|
@ -1224,6 +1235,7 @@ fn (p mut Parser) register_vargs_stuct(typ string, len int) string {
|
||||||
}
|
}
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1242,7 +1254,7 @@ fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) {
|
||||||
p.cgen.start_tmp()
|
p.cgen.start_tmp()
|
||||||
mut varg_type := p.bool_expression()
|
mut varg_type := p.bool_expression()
|
||||||
varg_value := p.cgen.end_tmp()
|
varg_value := p.cgen.end_tmp()
|
||||||
if varg_type.starts_with('...') &&
|
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')
|
||||||
}
|
}
|
||||||
|
@ -1274,7 +1286,7 @@ 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('...')
|
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 {
|
||||||
|
@ -1304,7 +1316,7 @@ fn (p mut Parser) rename_generic_fn_instance(f mut Fn, ti TypeInst) {
|
||||||
}
|
}
|
||||||
f.name = f.name + '_T'
|
f.name = f.name + '_T'
|
||||||
for k in ti.inst.keys() {
|
for k in ti.inst.keys() {
|
||||||
f.name = f.name + '_' + type_to_safe_str(ti.inst[k].replace('...', ''))
|
f.name = f.name + '_' + type_to_safe_str(ti.inst[k])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1461,8 +1473,8 @@ fn (f &Fn) str_args(table &Table) string {
|
||||||
s += ')'
|
s += ')'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if arg.typ.starts_with('...') {
|
else if arg.typ.starts_with('varg_') {
|
||||||
s += '_V_FnVargs_${arg.typ[3..]} *$arg.name'
|
s += '$arg.typ *$arg.name'
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// s += '$arg.typ $arg.name'
|
// s += '$arg.typ $arg.name'
|
||||||
|
|
|
@ -770,7 +770,7 @@ pub fn new_v(args[]string) &V {
|
||||||
vroot := os.dir(vexe_path())
|
vroot := os.dir(vexe_path())
|
||||||
|
|
||||||
mut vgen_buf := strings.new_builder(1000)
|
mut vgen_buf := strings.new_builder(1000)
|
||||||
vgen_buf.writeln('module main\nimport strings')
|
vgen_buf.writeln('module vgen\nimport strings')
|
||||||
|
|
||||||
joined_args := args.join(' ')
|
joined_args := args.join(' ')
|
||||||
target_os := get_arg(joined_args, 'os', '')
|
target_os := get_arg(joined_args, 'os', '')
|
||||||
|
|
|
@ -900,7 +900,7 @@ fn (p mut Parser) get_type() string {
|
||||||
p.error('unknown type `$typ`')
|
p.error('unknown type `$typ`')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if !t.is_public && t.mod != p.mod && t.name != '' && !p.first_pass() {
|
else if !t.is_public && t.mod != p.mod && !p.is_vgen && t.name != '' && !p.first_pass() {
|
||||||
p.error('type `$t.name` is private')
|
p.error('type `$t.name` is private')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1949,8 +1949,7 @@ fn (p mut Parser) dot(str_typ_ string, method_ph int) string {
|
||||||
//}
|
//}
|
||||||
mut str_typ := str_typ_
|
mut str_typ := str_typ_
|
||||||
p.check(.dot)
|
p.check(.dot)
|
||||||
is_variadic_arg := str_typ.starts_with('...')
|
is_variadic_arg := str_typ.starts_with('varg_')
|
||||||
if is_variadic_arg { str_typ = str_typ[3..] }
|
|
||||||
mut typ := p.find_type(str_typ)
|
mut typ := p.find_type(str_typ)
|
||||||
if typ.name.len == 0 {
|
if typ.name.len == 0 {
|
||||||
p.error('dot(): cannot find type `$str_typ`')
|
p.error('dot(): cannot find type `$str_typ`')
|
||||||
|
@ -2102,7 +2101,7 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
|
||||||
//println('index expr typ=$typ')
|
//println('index expr typ=$typ')
|
||||||
//println(v.name)
|
//println(v.name)
|
||||||
//}
|
//}
|
||||||
is_variadic_arg := typ.starts_with('...')
|
is_variadic_arg := typ.starts_with('varg_')
|
||||||
is_map := typ.starts_with('map_')
|
is_map := typ.starts_with('map_')
|
||||||
is_str := typ == 'string'
|
is_str := typ == 'string'
|
||||||
is_arr0 := typ.starts_with('array_')
|
is_arr0 := typ.starts_with('array_')
|
||||||
|
@ -2132,6 +2131,7 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
|
||||||
p.gen(',')
|
p.gen(',')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if is_variadic_arg { typ = typ[5..] }
|
||||||
if is_fixed_arr {
|
if is_fixed_arr {
|
||||||
// `[10]int` => `int`, `[10][3]int` => `[3]int`
|
// `[10]int` => `int`, `[10][3]int` => `[3]int`
|
||||||
if typ.contains('][') {
|
if typ.contains('][') {
|
||||||
|
@ -3254,8 +3254,7 @@ fn (p mut Parser) for_st() {
|
||||||
is_arr := typ.starts_with('array_')
|
is_arr := typ.starts_with('array_')
|
||||||
is_map := typ.starts_with('map_')
|
is_map := typ.starts_with('map_')
|
||||||
is_str := typ == 'string'
|
is_str := typ == 'string'
|
||||||
is_variadic_arg := typ.starts_with('...')
|
is_variadic_arg := typ.starts_with('varg_')
|
||||||
if is_variadic_arg { typ = typ[3..] }
|
|
||||||
if !is_arr && !is_str && !is_map && !is_variadic_arg {
|
if !is_arr && !is_str && !is_map && !is_variadic_arg {
|
||||||
p.error('cannot range over type `$typ`')
|
p.error('cannot range over type `$typ`')
|
||||||
}
|
}
|
||||||
|
@ -3267,25 +3266,24 @@ fn (p mut Parser) for_st() {
|
||||||
p.genln('$typ $tmp = $expr;')
|
p.genln('$typ $tmp = $expr;')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pad := if is_arr { 6 } else { 4 }
|
|
||||||
var_typ := if is_str { 'byte' }
|
|
||||||
else if is_variadic_arg { typ }
|
|
||||||
else { typ[pad..] }
|
|
||||||
// typ = strings.Replace(typ, "_ptr", "*", -1)
|
// typ = strings.Replace(typ, "_ptr", "*", -1)
|
||||||
mut i_var_type := 'int'
|
mut i_var_type := 'int'
|
||||||
if is_variadic_arg {
|
if is_variadic_arg {
|
||||||
|
typ = typ[5..]
|
||||||
p.gen_for_varg_header(i, expr, typ, val)
|
p.gen_for_varg_header(i, expr, typ, val)
|
||||||
}
|
}
|
||||||
else if is_arr {
|
else if is_arr {
|
||||||
p.gen_for_header(i, tmp, var_typ, val)
|
typ = typ[6..]
|
||||||
|
p.gen_for_header(i, tmp, typ, val)
|
||||||
}
|
}
|
||||||
else if is_map {
|
else if is_map {
|
||||||
i_var_type = 'string'
|
i_var_type = 'string'
|
||||||
p.gen_for_map_header(i, tmp, var_typ, val, typ)
|
typ = typ[4..]
|
||||||
|
p.gen_for_map_header(i, tmp, typ, val, typ)
|
||||||
}
|
}
|
||||||
else if is_str {
|
else if is_str {
|
||||||
i_var_type = 'byte'
|
typ = 'byte'
|
||||||
p.gen_for_str_header(i, tmp, var_typ, val)
|
p.gen_for_str_header(i, tmp, typ, val)
|
||||||
}
|
}
|
||||||
// Register temp vars
|
// Register temp vars
|
||||||
if i != '_' {
|
if i != '_' {
|
||||||
|
@ -3299,7 +3297,7 @@ fn (p mut Parser) for_st() {
|
||||||
if val != '_' {
|
if val != '_' {
|
||||||
p.register_var(Var {
|
p.register_var(Var {
|
||||||
name: val
|
name: val
|
||||||
typ: var_typ
|
typ: typ
|
||||||
ptr: typ.contains('*')
|
ptr: typ.contains('*')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -3315,8 +3313,7 @@ fn (p mut Parser) for_st() {
|
||||||
mut typ := p.bool_expression()
|
mut typ := p.bool_expression()
|
||||||
expr := p.cgen.end_tmp()
|
expr := p.cgen.end_tmp()
|
||||||
is_range := p.tok == .dotdot
|
is_range := p.tok == .dotdot
|
||||||
is_variadic_arg := typ.starts_with('...')
|
is_variadic_arg := typ.starts_with('varg_')
|
||||||
if is_variadic_arg { typ = typ[3..] }
|
|
||||||
mut range_end := ''
|
mut range_end := ''
|
||||||
if is_range {
|
if is_range {
|
||||||
p.check_types(typ, 'int')
|
p.check_types(typ, 'int')
|
||||||
|
@ -3339,28 +3336,28 @@ fn (p mut Parser) for_st() {
|
||||||
}
|
}
|
||||||
// TODO var_type := if...
|
// TODO var_type := if...
|
||||||
i := p.get_tmp()
|
i := p.get_tmp()
|
||||||
mut var_type := typ
|
|
||||||
if is_variadic_arg {
|
if is_variadic_arg {
|
||||||
|
typ = typ[5..]
|
||||||
p.gen_for_varg_header(i, expr, typ, val)
|
p.gen_for_varg_header(i, expr, typ, val)
|
||||||
}
|
}
|
||||||
else if is_range {
|
else if is_range {
|
||||||
var_type = 'int'
|
typ = 'int'
|
||||||
p.gen_for_range_header(i, range_end, tmp, var_type, val)
|
p.gen_for_range_header(i, range_end, tmp, typ, val)
|
||||||
}
|
}
|
||||||
else if is_arr {
|
else if is_arr {
|
||||||
var_type = typ[6..]// all after `array_`
|
typ = typ[6..]// all after `array_`
|
||||||
p.gen_for_header(i, tmp, var_type, val)
|
p.gen_for_header(i, tmp, typ, val)
|
||||||
}
|
}
|
||||||
else if is_str {
|
else if is_str {
|
||||||
var_type = 'byte'
|
typ = 'byte'
|
||||||
p.gen_for_str_header(i, tmp, var_type, val)
|
p.gen_for_str_header(i, tmp, typ, val)
|
||||||
}
|
}
|
||||||
// println('for typ=$typ vartyp=$var_typ')
|
// println('for typ=$typ vartyp=$var_typ')
|
||||||
// Register temp var
|
// Register temp var
|
||||||
if val != '_' {
|
if val != '_' {
|
||||||
p.register_var(Var {
|
p.register_var(Var {
|
||||||
name: val
|
name: val
|
||||||
typ: var_type
|
typ: typ
|
||||||
ptr: typ.contains('*')
|
ptr: typ.contains('*')
|
||||||
is_changed: true
|
is_changed: true
|
||||||
is_mut: false
|
is_mut: false
|
||||||
|
|
|
@ -328,10 +328,6 @@ fn (t mut Table) register_fn(new_fn Fn) {
|
||||||
|
|
||||||
fn (table &Table) known_type(typ_ string) bool {
|
fn (table &Table) known_type(typ_ string) bool {
|
||||||
mut typ := typ_
|
mut typ := typ_
|
||||||
// vararg
|
|
||||||
if typ.starts_with('...') && typ.len > 3 {
|
|
||||||
typ = typ[3..]
|
|
||||||
}
|
|
||||||
// 'byte*' => look up 'byte', but don't mess up fns
|
// 'byte*' => look up 'byte', but don't mess up fns
|
||||||
if typ.ends_with('*') && !typ.contains(' ') {
|
if typ.ends_with('*') && !typ.contains(' ') {
|
||||||
typ = typ[..typ.len - 1]
|
typ = typ[..typ.len - 1]
|
||||||
|
@ -584,11 +580,11 @@ fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// variadic
|
// variadic
|
||||||
if expected.starts_with('...') {
|
if expected.starts_with('varg_') {
|
||||||
expected = expected[3..]
|
expected = expected[5..]
|
||||||
}
|
}
|
||||||
if got.starts_with('...') {
|
if got.starts_with('varg_') {
|
||||||
got = got[3..]
|
got = got[5..]
|
||||||
}
|
}
|
||||||
// Allow ints to be used as floats
|
// Allow ints to be used as floats
|
||||||
if got == 'int' && expected == 'f32' {
|
if got == 'int' && expected == 'f32' {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user