all: re-implement variadics using arrays & implement array decomposition to varg (#7689)
parent
6cf3b96a37
commit
02965e753e
|
@ -9,9 +9,9 @@ import v.errors
|
||||||
|
|
||||||
pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
|
pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
|
||||||
|
|
||||||
pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral | CTempVar |
|
pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral |
|
||||||
CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal |
|
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr |
|
||||||
FloatLiteral | Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral |
|
EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral |
|
||||||
Likely | LockExpr | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr |
|
Likely | LockExpr | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr |
|
||||||
RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral |
|
RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral |
|
||||||
StructInit | Type | TypeOf | UnsafeExpr
|
StructInit | Type | TypeOf | UnsafeExpr
|
||||||
|
@ -890,6 +890,15 @@ pub mut:
|
||||||
typ table.Type // array type
|
typ table.Type // array type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ArrayDecompose {
|
||||||
|
pub:
|
||||||
|
expr Expr
|
||||||
|
pos token.Position
|
||||||
|
pub mut:
|
||||||
|
expr_type table.Type
|
||||||
|
arg_type table.Type
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ChanInit {
|
pub struct ChanInit {
|
||||||
pub:
|
pub:
|
||||||
pos token.Position
|
pos token.Position
|
||||||
|
@ -1129,6 +1138,9 @@ pub fn (expr Expr) position() token.Position {
|
||||||
ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, ChanInit, CharLiteral, ConcatExpr, Comment, EnumVal, FloatLiteral, Ident, IfExpr, IndexExpr, IntegerLiteral, Likely, LockExpr, MapInit, MatchExpr, None, OrExpr, ParExpr, PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral, StructInit, Type, TypeOf, UnsafeExpr {
|
ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, ChanInit, CharLiteral, ConcatExpr, Comment, EnumVal, FloatLiteral, Ident, IfExpr, IndexExpr, IntegerLiteral, Likely, LockExpr, MapInit, MatchExpr, None, OrExpr, ParExpr, PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral, StructInit, Type, TypeOf, UnsafeExpr {
|
||||||
return expr.pos
|
return expr.pos
|
||||||
}
|
}
|
||||||
|
ArrayDecompose {
|
||||||
|
return expr.pos
|
||||||
|
}
|
||||||
IfGuardExpr {
|
IfGuardExpr {
|
||||||
return expr.expr.position()
|
return expr.expr.position()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,20 @@ import v.table
|
||||||
import v.token
|
import v.token
|
||||||
import v.ast
|
import v.ast
|
||||||
|
|
||||||
|
pub fn (mut c Checker) check_expected_call_arg(got table.Type, expected_ table.Type) ? {
|
||||||
|
mut expected := expected_
|
||||||
|
// variadic
|
||||||
|
if expected.has_flag(.variadic) {
|
||||||
|
exp_type_sym := c.table.get_type_symbol(expected_)
|
||||||
|
exp_info := exp_type_sym.info as table.Array
|
||||||
|
expected = exp_info.elem_type
|
||||||
|
}
|
||||||
|
if c.check_types(got, expected) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return error('cannot use `${c.table.type_to_str(got.clear_flag(.variadic))}` as `${c.table.type_to_str(expected.clear_flag(.variadic))}`')
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) check_basic(got table.Type, expected table.Type) bool {
|
pub fn (mut c Checker) check_basic(got table.Type, expected table.Type) bool {
|
||||||
if got == expected {
|
if got == expected {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -1333,21 +1333,16 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
||||||
c.type_implements(got_arg_typ, exp_arg_typ, arg.expr.position())
|
c.type_implements(got_arg_typ, exp_arg_typ, arg.expr.position())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !c.check_types(got_arg_typ, exp_arg_typ) {
|
c.check_expected_call_arg(got_arg_typ, exp_arg_typ) or {
|
||||||
got_arg_sym := c.table.get_type_symbol(got_arg_typ)
|
|
||||||
// str method, allow type with str method if fn arg is string
|
// str method, allow type with str method if fn arg is string
|
||||||
// if exp_arg_sym.kind == .string && got_arg_sym.has_method('str') {
|
// Passing an int or a string array produces a c error here
|
||||||
|
// Deleting this condition results in propper V error messages
|
||||||
|
// if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
||||||
// continue
|
// continue
|
||||||
// }
|
// }
|
||||||
// same ancestor? let it be
|
|
||||||
if exp_arg_sym.parent_idx == got_arg_sym.parent_idx {
|
|
||||||
if got_arg_sym.parent_idx != 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if got_arg_typ != table.void_type {
|
if got_arg_typ != table.void_type {
|
||||||
c.error('cannot use type `$got_arg_sym.name` as type `$exp_arg_sym.name` in argument ${i +
|
c.error('$err in argument ${i + 1} to `${left_type_sym.name}.$method_name`',
|
||||||
1} to `${left_type_sym.name}.$method_name`', call_expr.pos)
|
call_expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
param := if method.is_variadic && i >= method.params.len - 1 { method.params[method.params.len -
|
param := if method.is_variadic && i >= method.params.len - 1 { method.params[method.params.len -
|
||||||
|
@ -1660,7 +1655,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
c.type_implements(typ, arg.typ, call_arg.expr.position())
|
c.type_implements(typ, arg.typ, call_arg.expr.position())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.check_expected(typ, arg.typ) or {
|
c.check_expected_call_arg(typ, arg.typ) or {
|
||||||
// str method, allow type with str method if fn arg is string
|
// str method, allow type with str method if fn arg is string
|
||||||
// Passing an int or a string array produces a c error here
|
// Passing an int or a string array produces a c error here
|
||||||
// Deleting this condition results in propper V error messages
|
// Deleting this condition results in propper V error messages
|
||||||
|
@ -1673,7 +1668,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
if f.is_generic {
|
if f.is_generic {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.error('invalid argument ${i + 1} to `$fn_name`: $err', call_arg.pos)
|
c.error('$err in argument ${i + 1} to `$fn_name`', call_arg.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if f.is_generic && call_expr.generic_type == table.void_type {
|
if f.is_generic && call_expr.generic_type == table.void_type {
|
||||||
|
@ -2981,6 +2976,18 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
c.cur_fn = keep_fn
|
c.cur_fn = keep_fn
|
||||||
return node.typ
|
return node.typ
|
||||||
}
|
}
|
||||||
|
ast.ArrayDecompose {
|
||||||
|
typ := c.expr(node.expr)
|
||||||
|
type_sym := c.table.get_type_symbol(typ)
|
||||||
|
if type_sym.kind != .array {
|
||||||
|
c.error('expected array', node.pos)
|
||||||
|
}
|
||||||
|
array_info := type_sym.info as table.Array
|
||||||
|
elem_type := array_info.elem_type.set_flag(.variadic)
|
||||||
|
node.expr_type = typ
|
||||||
|
node.arg_type = elem_type
|
||||||
|
return elem_type
|
||||||
|
}
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
return c.array_init(mut node)
|
return c.array_init(mut node)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
vlib/v/checker/tests/fn_args.vv:6:5: error: invalid argument 1 to `ptr`: expected `byte`, not `&int`
|
vlib/v/checker/tests/fn_args.vv:6:5: error: cannot use `&int` as `byte` in argument 1 to `ptr`
|
||||||
4 |
|
4 |
|
||||||
5 | v := 4
|
5 | v := 4
|
||||||
6 | ptr(&v)
|
6 | ptr(&v)
|
||||||
| ~~
|
| ~~
|
||||||
7 | arr([5]!!)
|
7 | arr([5]!!)
|
||||||
8 | fun(fn(i &int){})
|
8 | fun(fn(i &int){})
|
||||||
vlib/v/checker/tests/fn_args.vv:7:5: error: invalid argument 1 to `arr`: expected `[]int`, not `[1]int`
|
vlib/v/checker/tests/fn_args.vv:7:5: error: cannot use `[1]int` as `[]int` in argument 1 to `arr`
|
||||||
5 | v := 4
|
5 | v := 4
|
||||||
6 | ptr(&v)
|
6 | ptr(&v)
|
||||||
7 | arr([5]!!)
|
7 | arr([5]!!)
|
||||||
| ~~~~~
|
| ~~~~~
|
||||||
8 | fun(fn(i &int){})
|
8 | fun(fn(i &int){})
|
||||||
vlib/v/checker/tests/fn_args.vv:8:5: error: invalid argument 1 to `fun`: expected `fn (int)`, not `fn (&int)`
|
vlib/v/checker/tests/fn_args.vv:8:5: error: cannot use `fn (&int)` as `fn (int)` in argument 1 to `fun`
|
||||||
6 | ptr(&v)
|
6 | ptr(&v)
|
||||||
7 | arr([5]!!)
|
7 | arr([5]!!)
|
||||||
8 | fun(fn(i &int){})
|
8 | fun(fn(i &int){})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/function_wrong_arg_type.vv:7:9: error: invalid argument 1 to `f`: expected `int`, not `f64`
|
vlib/v/checker/tests/function_wrong_arg_type.vv:7:9: error: cannot use `f64` as `int` in argument 1 to `f`
|
||||||
5 | fn main() {
|
5 | fn main() {
|
||||||
6 | a := 12.3
|
6 | a := 12.3
|
||||||
7 | q := f(a)
|
7 | q := f(a)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/is_type_not_exist.vv:4:25: error: invalid argument 1 to `fn_with_sum_type_param`: expected `Integer`, not `any_int`
|
vlib/v/checker/tests/is_type_not_exist.vv:4:25: error: cannot use `any_int` as `Integer` in argument 1 to `fn_with_sum_type_param`
|
||||||
2 |
|
2 |
|
||||||
3 | fn main() {
|
3 | fn main() {
|
||||||
4 | fn_with_sum_type_param(1)
|
4 | fn_with_sum_type_param(1)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/method_wrong_arg_type.vv:8:4: error: cannot use type `MyEnum` as type `string` in argument 1 to `Sss.info`
|
vlib/v/checker/tests/method_wrong_arg_type.vv:8:4: error: cannot use `MyEnum` as `string` in argument 1 to `Sss.info`
|
||||||
6 | e := MyEnum.x
|
6 | e := MyEnum.x
|
||||||
7 | s := Sss{}
|
7 | s := Sss{}
|
||||||
8 | s.info(e)
|
8 | s.info(e)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/non_matching_functional_args.vv:27:6: error: invalid argument 1 to `sum`: expected `fn (Table)`, not `fn (mut Table)`
|
vlib/v/checker/tests/non_matching_functional_args.vv:27:6: error: cannot use `fn (mut Table)` as `fn (Table)` in argument 1 to `sum`
|
||||||
25 |
|
25 |
|
||||||
26 | fn main() {
|
26 | fn main() {
|
||||||
27 | sum(fn (mut t Table) {
|
27 | sum(fn (mut t Table) {
|
||||||
|
@ -6,7 +6,7 @@ vlib/v/checker/tests/non_matching_functional_args.vv:27:6: error: invalid argume
|
||||||
28 | t.rename()
|
28 | t.rename()
|
||||||
29 | println(t.name)
|
29 | println(t.name)
|
||||||
details: `main.MyFn`'s expected fn argument: `zzzz` is NOT a pointer, but the passed fn argument: `t` is a pointer
|
details: `main.MyFn`'s expected fn argument: `zzzz` is NOT a pointer, but the passed fn argument: `t` is a pointer
|
||||||
vlib/v/checker/tests/non_matching_functional_args.vv:31:6: error: invalid argument 1 to `sum`: expected `fn (Table)`, not `fn (mut Table)`
|
vlib/v/checker/tests/non_matching_functional_args.vv:31:6: error: cannot use `fn (mut Table)` as `fn (Table)` in argument 1 to `sum`
|
||||||
29 | println(t.name)
|
29 | println(t.name)
|
||||||
30 | })
|
30 | })
|
||||||
31 | sum(xxx)
|
31 | sum(xxx)
|
||||||
|
|
|
@ -1138,6 +1138,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
f.write('}')
|
f.write('}')
|
||||||
}
|
}
|
||||||
|
ast.ArrayDecompose {
|
||||||
|
f.expr(node.expr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,15 +63,6 @@ fn (mut g Gen) gen_str_for_type(typ table.Type) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if varg, generate str for varg
|
|
||||||
if typ.has_flag(.variadic) {
|
|
||||||
varg_already_generated_key := 'varg_$already_generated_key'
|
|
||||||
if varg_already_generated_key !in g.str_types {
|
|
||||||
g.gen_str_for_varg(styp, str_fn_name, sym_has_str_method)
|
|
||||||
g.str_types << varg_already_generated_key
|
|
||||||
}
|
|
||||||
return 'varg_$str_fn_name'
|
|
||||||
}
|
|
||||||
if typ.has_flag(.optional) {
|
if typ.has_flag(.optional) {
|
||||||
option_already_generated_key := 'option_$already_generated_key'
|
option_already_generated_key := 'option_$already_generated_key'
|
||||||
if option_already_generated_key !in g.str_types {
|
if option_already_generated_key !in g.str_types {
|
||||||
|
@ -305,22 +296,6 @@ fn (mut g Gen) gen_str_for_map(info table.Map, styp string, str_fn_name string)
|
||||||
g.auto_str_funcs.writeln('}')
|
g.auto_str_funcs.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_varg(styp string, str_fn_name string, has_str_method bool) {
|
|
||||||
g.definitions.writeln('static string varg_${str_fn_name}(varg_$styp it); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string varg_${str_fn_name}(varg_$styp it) {')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(it.len);')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, _SLIT("["));')
|
|
||||||
g.auto_str_funcs.writeln('\tfor(int i=0; i<it.len; ++i) {')
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${str_fn_name}(it.args[i]));')
|
|
||||||
g.auto_str_funcs.writeln('\t\tif (i < it.len-1) {')
|
|
||||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write(&sb, _SLIT(", "));')
|
|
||||||
g.auto_str_funcs.writeln('\t\t}')
|
|
||||||
g.auto_str_funcs.writeln('\t}')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, _SLIT("]"));')
|
|
||||||
g.auto_str_funcs.writeln('\treturn strings__Builder_str(&sb);')
|
|
||||||
g.auto_str_funcs.writeln('}')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_multi_return(info table.MultiReturn, styp string, str_fn_name string) {
|
fn (mut g Gen) gen_str_for_multi_return(info table.MultiReturn, styp string, str_fn_name string) {
|
||||||
for typ in info.types {
|
for typ in info.types {
|
||||||
sym := g.table.get_type_symbol(typ)
|
sym := g.table.get_type_symbol(typ)
|
||||||
|
|
|
@ -56,7 +56,6 @@ mut:
|
||||||
last_fn_c_name string
|
last_fn_c_name string
|
||||||
tmp_count int // counter for unique tmp vars (_tmp1, tmp2 etc)
|
tmp_count int // counter for unique tmp vars (_tmp1, tmp2 etc)
|
||||||
tmp_count2 int // a separate tmp var counter for autofree fn calls
|
tmp_count2 int // a separate tmp var counter for autofree fn calls
|
||||||
variadic_args map[string]int
|
|
||||||
is_c_call bool // e.g. `C.printf("v")`
|
is_c_call bool // e.g. `C.printf("v")`
|
||||||
is_assign_lhs bool // inside left part of assign expr (for array_set(), etc)
|
is_assign_lhs bool // inside left part of assign expr (for array_set(), etc)
|
||||||
is_assign_rhs bool // inside right part of assign after `=` (val expr)
|
is_assign_rhs bool // inside right part of assign after `=` (val expr)
|
||||||
|
@ -246,7 +245,6 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
g.definitions.writeln('int _v_type_idx_${typ.cname}() { return $idx; };')
|
g.definitions.writeln('int _v_type_idx_${typ.cname}() { return $idx; };')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.write_variadic_types()
|
|
||||||
// g.write_str_definitions()
|
// g.write_str_definitions()
|
||||||
// v files are finished, what remains is pure C code
|
// v files are finished, what remains is pure C code
|
||||||
g.gen_vlines_reset()
|
g.gen_vlines_reset()
|
||||||
|
@ -704,21 +702,6 @@ pub fn (mut g Gen) write_multi_return_types() {
|
||||||
g.type_definitions.writeln('// END_multi_return_structs\n')
|
g.type_definitions.writeln('// END_multi_return_structs\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) write_variadic_types() {
|
|
||||||
g.type_definitions.writeln('\n//BEGIN_variadic_structs')
|
|
||||||
for type_str, arg_len in g.variadic_args {
|
|
||||||
typ := table.Type(type_str.int())
|
|
||||||
type_name := g.typ(typ)
|
|
||||||
struct_name := 'varg_' + type_name.replace('*', '_ptr')
|
|
||||||
g.type_definitions.writeln('struct $struct_name {')
|
|
||||||
g.type_definitions.writeln('\tint len;')
|
|
||||||
g.type_definitions.writeln('\t$type_name args[$arg_len];')
|
|
||||||
g.type_definitions.writeln('};\n')
|
|
||||||
g.typedefs.writeln('typedef struct $struct_name $struct_name;')
|
|
||||||
}
|
|
||||||
g.type_definitions.writeln('// END_variadic_structs\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (mut g Gen) write(s string) {
|
pub fn (mut g Gen) write(s string) {
|
||||||
$if trace_gen ? {
|
$if trace_gen ? {
|
||||||
eprintln('gen file: ${g.file.path:-30} | last_fn_c_name: ${g.last_fn_c_name:-45} | write: $s')
|
eprintln('gen file: ${g.file.path:-30} | last_fn_c_name: ${g.last_fn_c_name:-45} | write: $s')
|
||||||
|
@ -1324,16 +1307,6 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
|
||||||
g.writeln('\t${it.label}__break: {}')
|
g.writeln('\t${it.label}__break: {}')
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} else if it.cond_type.has_flag(.variadic) {
|
|
||||||
g.writeln('// FOR IN cond_type/variadic')
|
|
||||||
i := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var }
|
|
||||||
styp := g.typ(it.cond_type)
|
|
||||||
g.write('for (int $i = 0; $i < ')
|
|
||||||
g.expr(it.cond)
|
|
||||||
g.writeln('.len; ++$i) {')
|
|
||||||
g.write('\t$styp ${c_name(it.val_var)} = ')
|
|
||||||
g.expr(it.cond)
|
|
||||||
g.writeln('.args[$i];')
|
|
||||||
} else if it.kind == .string {
|
} else if it.kind == .string {
|
||||||
i := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var }
|
i := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var }
|
||||||
g.write('for (int $i = 0; $i < ')
|
g.write('for (int $i = 0; $i < ')
|
||||||
|
@ -2374,6 +2347,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
fsym := g.table.get_type_symbol(node.typ)
|
fsym := g.table.get_type_symbol(node.typ)
|
||||||
g.write(fsym.name)
|
g.write(fsym.name)
|
||||||
}
|
}
|
||||||
|
ast.ArrayDecompose {
|
||||||
|
g.expr(node.expr)
|
||||||
|
}
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
g.array_init(node)
|
g.array_init(node)
|
||||||
}
|
}
|
||||||
|
@ -2775,7 +2751,8 @@ fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
||||||
info := sym.info as table.FnType
|
info := sym.info as table.FnType
|
||||||
g.write('_SLIT("${g.fn_decl_str(info)}")')
|
g.write('_SLIT("${g.fn_decl_str(info)}")')
|
||||||
} else if node.expr_type.has_flag(.variadic) {
|
} else if node.expr_type.has_flag(.variadic) {
|
||||||
g.write('_SLIT("...${util.strip_main_name(sym.name)}")')
|
varg_elem_type_sym := g.table.get_type_symbol(g.table.value_type(node.expr_type))
|
||||||
|
g.write('_SLIT("...${util.strip_main_name(varg_elem_type_sym.name)}")')
|
||||||
} else {
|
} else {
|
||||||
g.write('_SLIT("${util.strip_main_name(sym.name)}")')
|
g.write('_SLIT("${util.strip_main_name(sym.name)}")')
|
||||||
}
|
}
|
||||||
|
@ -3835,13 +3812,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||||
else {
|
else {
|
||||||
sym := g.table.get_type_symbol(node.left_type)
|
sym := g.table.get_type_symbol(node.left_type)
|
||||||
left_is_ptr := node.left_type.is_ptr()
|
left_is_ptr := node.left_type.is_ptr()
|
||||||
if node.left_type.has_flag(.variadic) {
|
if sym.kind == .array {
|
||||||
g.expr(node.left)
|
|
||||||
g.write('.args')
|
|
||||||
g.write('[')
|
|
||||||
g.expr(node.index)
|
|
||||||
g.write(']')
|
|
||||||
} else if sym.kind == .array {
|
|
||||||
info := sym.info as table.Array
|
info := sym.info as table.Array
|
||||||
elem_type_str := g.typ(info.elem_type)
|
elem_type_str := g.typ(info.elem_type)
|
||||||
elem_typ := g.table.get_type_symbol(info.elem_type)
|
elem_typ := g.table.get_type_symbol(info.elem_type)
|
||||||
|
|
|
@ -52,10 +52,8 @@ const (
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __TINYC__
|
#ifdef __TINYC__
|
||||||
#undef EMPTY_VARG_INITIALIZATION
|
|
||||||
#undef EMPTY_STRUCT_DECLARATION
|
#undef EMPTY_STRUCT_DECLARATION
|
||||||
#undef EMPTY_STRUCT_INITIALIZATION
|
#undef EMPTY_STRUCT_INITIALIZATION
|
||||||
#define EMPTY_VARG_INITIALIZATION
|
|
||||||
#define EMPTY_STRUCT_DECLARATION char _dummy
|
#define EMPTY_STRUCT_DECLARATION char _dummy
|
||||||
#define EMPTY_STRUCT_INITIALIZATION 0
|
#define EMPTY_STRUCT_INITIALIZATION 0
|
||||||
#undef EMPTY_ARRAY_OF_ELEMS
|
#undef EMPTY_ARRAY_OF_ELEMS
|
||||||
|
|
|
@ -215,14 +215,6 @@ fn (mut g Gen) fn_args(args []table.Param, is_variadic bool) ([]string, []string
|
||||||
typ := g.unwrap_generic(arg.typ)
|
typ := g.unwrap_generic(arg.typ)
|
||||||
arg_type_sym := g.table.get_type_symbol(typ)
|
arg_type_sym := g.table.get_type_symbol(typ)
|
||||||
mut arg_type_name := g.typ(typ) // util.no_dots(arg_type_sym.name)
|
mut arg_type_name := g.typ(typ) // util.no_dots(arg_type_sym.name)
|
||||||
is_varg := i == args.len - 1 && is_variadic
|
|
||||||
if is_varg {
|
|
||||||
varg_type_str := int(arg.typ).str()
|
|
||||||
if varg_type_str !in g.variadic_args {
|
|
||||||
g.variadic_args[varg_type_str] = 0
|
|
||||||
}
|
|
||||||
arg_type_name = 'varg_' + g.typ(arg.typ).replace('*', '_ptr')
|
|
||||||
}
|
|
||||||
if arg_type_sym.kind == .function {
|
if arg_type_sym.kind == .function {
|
||||||
info := arg_type_sym.info as table.FnType
|
info := arg_type_sym.info as table.FnType
|
||||||
func := info.func
|
func := info.func
|
||||||
|
@ -764,10 +756,8 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||||
args := if g.is_js_call { node.args[1..] } else { node.args }
|
args := if g.is_js_call { node.args[1..] } else { node.args }
|
||||||
expected_types := node.expected_arg_types
|
expected_types := node.expected_arg_types
|
||||||
is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].has_flag(.variadic)
|
is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].has_flag(.variadic)
|
||||||
is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.has_flag(.variadic)
|
|
||||||
gen_vargs := is_variadic && !is_forwarding_varg
|
|
||||||
for i, arg in args {
|
for i, arg in args {
|
||||||
if gen_vargs && i == expected_types.len - 1 {
|
if is_variadic && i == expected_types.len - 1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
use_tmp_var_autofree := g.autofree && arg.typ == table.string_type && arg.is_tmp_autofree &&
|
use_tmp_var_autofree := g.autofree && arg.typ == table.string_type && arg.is_tmp_autofree &&
|
||||||
|
@ -818,32 +808,33 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||||
if is_interface {
|
if is_interface {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
if i < args.len - 1 || gen_vargs {
|
if i < args.len - 1 || is_variadic {
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arg_nr := expected_types.len - 1
|
arg_nr := expected_types.len - 1
|
||||||
if gen_vargs {
|
if is_variadic {
|
||||||
varg_type := expected_types[expected_types.len - 1]
|
varg_type := expected_types[expected_types.len - 1]
|
||||||
struct_name := 'varg_' + g.typ(varg_type).replace('*', '_ptr')
|
|
||||||
variadic_count := args.len - arg_nr
|
variadic_count := args.len - arg_nr
|
||||||
varg_type_str := int(varg_type).str()
|
arr_sym := g.table.get_type_symbol(varg_type)
|
||||||
if variadic_count > g.variadic_args[varg_type_str] {
|
arr_info := arr_sym.info as table.Array
|
||||||
g.variadic_args[varg_type_str] = variadic_count
|
elem_type := g.typ(arr_info.elem_type)
|
||||||
}
|
if args.len > 0 && args[args.len - 1].expr is ast.ArrayDecompose {
|
||||||
g.write('($struct_name){.len=$variadic_count,.args={')
|
g.expr(args[args.len - 1].expr)
|
||||||
if variadic_count > 0 {
|
|
||||||
for j in arg_nr .. args.len {
|
|
||||||
g.ref_or_deref_arg(args[j], varg_type)
|
|
||||||
if j < args.len - 1 {
|
|
||||||
g.write(', ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// NB: tcc can not handle 0 here, while msvc needs it
|
if variadic_count > 0 {
|
||||||
g.write('EMPTY_VARG_INITIALIZATION')
|
g.write('new_array_from_c_array($variadic_count, $variadic_count, sizeof($elem_type), _MOV(($elem_type[$variadic_count]){')
|
||||||
|
for j in arg_nr .. args.len {
|
||||||
|
g.ref_or_deref_arg(args[j], arr_info.elem_type)
|
||||||
|
if j < args.len - 1 {
|
||||||
|
g.write(', ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.write('}))')
|
||||||
|
} else {
|
||||||
|
g.write('__new_array_with_default(0, 0, sizeof($elem_type), 0)')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g.write('}}')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ const (
|
||||||
'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void',
|
'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void',
|
||||||
'while', 'with', 'yield', 'Number', 'String', 'Boolean', 'Array', 'Map']
|
'while', 'with', 'yield', 'Number', 'String', 'Boolean', 'Array', 'Map']
|
||||||
// used to generate type structs
|
// used to generate type structs
|
||||||
v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64', 'any_int', 'any_float', 'size_t', 'bool', 'string', 'map', 'array']
|
v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64', 'any_int',
|
||||||
|
'any_float', 'size_t', 'bool', 'string', 'map', 'array']
|
||||||
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t',
|
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t',
|
||||||
'\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t']
|
'\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t\t']
|
||||||
)
|
)
|
||||||
|
@ -32,30 +33,30 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JsGen {
|
struct JsGen {
|
||||||
table &table.Table
|
table &table.Table
|
||||||
pref &pref.Preferences
|
pref &pref.Preferences
|
||||||
mut:
|
mut:
|
||||||
definitions strings.Builder
|
definitions strings.Builder
|
||||||
ns &Namespace
|
ns &Namespace
|
||||||
namespaces map[string]&Namespace
|
namespaces map[string]&Namespace
|
||||||
doc &JsDoc
|
doc &JsDoc
|
||||||
enable_doc bool
|
enable_doc bool
|
||||||
file ast.File
|
file ast.File
|
||||||
tmp_count int
|
tmp_count int
|
||||||
inside_ternary bool
|
inside_ternary bool
|
||||||
inside_loop bool
|
inside_loop bool
|
||||||
inside_map_set bool // map.set(key, value)
|
inside_map_set bool // map.set(key, value)
|
||||||
inside_builtin bool
|
inside_builtin bool
|
||||||
generated_builtin bool
|
generated_builtin bool
|
||||||
inside_def_typ_decl bool
|
inside_def_typ_decl bool
|
||||||
is_test bool
|
is_test bool
|
||||||
stmt_start_pos int
|
stmt_start_pos int
|
||||||
defer_stmts []ast.DeferStmt
|
defer_stmts []ast.DeferStmt
|
||||||
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
||||||
str_types []string // types that need automatic str() generation
|
str_types []string // types that need automatic str() generation
|
||||||
method_fn_decls map[string][]ast.FnDecl
|
method_fn_decls map[string][]ast.FnDecl
|
||||||
builtin_fns []string // Functions defined in `builtin`
|
builtin_fns []string // Functions defined in `builtin`
|
||||||
empty_line bool
|
empty_line bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string {
|
pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string {
|
||||||
|
@ -158,12 +159,16 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
out += '// builtin type casts\n'
|
out += '// builtin type casts\n'
|
||||||
out += 'const ['
|
out += 'const ['
|
||||||
for i, typ in v_types {
|
for i, typ in v_types {
|
||||||
if i > 0 { out += ', ' }
|
if i > 0 {
|
||||||
|
out += ', '
|
||||||
|
}
|
||||||
out += '$typ'
|
out += '$typ'
|
||||||
}
|
}
|
||||||
out += '] = ['
|
out += '] = ['
|
||||||
for i, typ in v_types {
|
for i, typ in v_types {
|
||||||
if i > 0 { out += ',' }
|
if i > 0 {
|
||||||
|
out += ','
|
||||||
|
}
|
||||||
out += '\n\tfunction(val) { return new builtin.${typ}(val) }'
|
out += '\n\tfunction(val) { return new builtin.${typ}(val) }'
|
||||||
}
|
}
|
||||||
out += '\n]\n'
|
out += '\n]\n'
|
||||||
|
@ -257,14 +262,18 @@ pub fn (mut g JsGen) dec_indent() {
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut g JsGen) write(s string) {
|
pub fn (mut g JsGen) write(s string) {
|
||||||
if g.ns == 0 { verror('g.write: not in a namespace') }
|
if g.ns == 0 {
|
||||||
|
verror('g.write: not in a namespace')
|
||||||
|
}
|
||||||
g.gen_indent()
|
g.gen_indent()
|
||||||
g.ns.out.write(s)
|
g.ns.out.write(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut g JsGen) writeln(s string) {
|
pub fn (mut g JsGen) writeln(s string) {
|
||||||
if g.ns == 0 { verror('g.writeln: not in a namespace') }
|
if g.ns == 0 {
|
||||||
|
verror('g.writeln: not in a namespace')
|
||||||
|
}
|
||||||
g.gen_indent()
|
g.gen_indent()
|
||||||
g.ns.out.writeln(s)
|
g.ns.out.writeln(s)
|
||||||
g.empty_line = true
|
g.empty_line = true
|
||||||
|
@ -304,7 +313,13 @@ fn (mut g JsGen) js_name(name_ string) string {
|
||||||
is_js = true
|
is_js = true
|
||||||
}
|
}
|
||||||
ns := get_ns(name)
|
ns := get_ns(name)
|
||||||
name = if g.ns == 0 { name } else if ns == g.ns.name { name.split('.').last() } else { g.get_alias(name) }
|
name = if g.ns == 0 {
|
||||||
|
name
|
||||||
|
} else if ns == g.ns.name {
|
||||||
|
name.split('.').last()
|
||||||
|
} else {
|
||||||
|
g.get_alias(name)
|
||||||
|
}
|
||||||
mut parts := name.split('.')
|
mut parts := name.split('.')
|
||||||
if !is_js {
|
if !is_js {
|
||||||
for i, p in parts {
|
for i, p in parts {
|
||||||
|
@ -529,8 +544,10 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
g.gen_string_inter_literal(node)
|
g.gen_string_inter_literal(node)
|
||||||
}
|
}
|
||||||
ast.StringLiteral {
|
ast.StringLiteral {
|
||||||
text := node.val.replace('\'', "\\'")
|
text := node.val.replace("\'", "\\'")
|
||||||
if g.file.mod.name == 'builtin' { g.write('new ') }
|
if g.file.mod.name == 'builtin' {
|
||||||
|
g.write('new ')
|
||||||
|
}
|
||||||
g.write("string('$text')")
|
g.write("string('$text')")
|
||||||
}
|
}
|
||||||
ast.StructInit {
|
ast.StructInit {
|
||||||
|
@ -559,6 +576,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
ast.UnsafeExpr {
|
ast.UnsafeExpr {
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
}
|
}
|
||||||
|
ast.ArrayDecompose {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1012,19 +1030,22 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
||||||
if !('toString' in fn_names) {
|
if !('toString' in fn_names) {
|
||||||
g.writeln('toString() {')
|
g.writeln('toString() {')
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
g.write('return `${js_name} {')
|
g.write('return `$js_name {')
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
g.write(if i == 0 { ' ' } else { ', ' })
|
g.write(if i == 0 {
|
||||||
|
' '
|
||||||
|
} else {
|
||||||
|
', '
|
||||||
|
})
|
||||||
match g.typ(field.typ).split('.').last() {
|
match g.typ(field.typ).split('.').last() {
|
||||||
"string" { g.write('$field.name: "\${this["${field.name}"].toString()}"') }
|
'string' { g.write('$field.name: "\${this["$field.name"].toString()}"') }
|
||||||
else { g.write('$field.name: \${this["${field.name}"].toString()} ') }
|
else { g.write('$field.name: \${this["$field.name"].toString()} ') }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.writeln('}`')
|
g.writeln('}`')
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('};\n')
|
g.writeln('};\n')
|
||||||
if node.is_pub {
|
if node.is_pub {
|
||||||
|
@ -1378,31 +1399,49 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
||||||
fn (mut g JsGen) greater_typ(left table.Type, right table.Type) table.Type {
|
fn (mut g JsGen) greater_typ(left table.Type, right table.Type) table.Type {
|
||||||
l := int(left)
|
l := int(left)
|
||||||
r := int(right)
|
r := int(right)
|
||||||
lr := [l,r]
|
lr := [l, r]
|
||||||
|
if table.string_type_idx in lr {
|
||||||
if table.string_type_idx in lr { return table.Type(table.string_type_idx) }
|
return table.Type(table.string_type_idx)
|
||||||
|
}
|
||||||
should_float := (l in table.integer_type_idxs && r in table.float_type_idxs) || (r in table.integer_type_idxs && l in table.float_type_idxs)
|
should_float := (l in table.integer_type_idxs &&
|
||||||
|
r in table.float_type_idxs) ||
|
||||||
|
(r in table.integer_type_idxs && l in table.float_type_idxs)
|
||||||
if should_float {
|
if should_float {
|
||||||
if table.f64_type_idx in lr { return table.Type(table.f64_type_idx) }
|
if table.f64_type_idx in lr {
|
||||||
if table.f32_type_idx in lr { return table.Type(table.f32_type_idx) }
|
return table.Type(table.f64_type_idx)
|
||||||
|
}
|
||||||
|
if table.f32_type_idx in lr {
|
||||||
|
return table.Type(table.f32_type_idx)
|
||||||
|
}
|
||||||
return table.Type(table.any_flt_type)
|
return table.Type(table.any_flt_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
should_int := (l in table.integer_type_idxs && r in table.integer_type_idxs)
|
should_int := (l in table.integer_type_idxs && r in table.integer_type_idxs)
|
||||||
if should_int {
|
if should_int {
|
||||||
// cant add to u64 - if (table.u64_type_idx in lr) { return table.Type(table.u64_type_idx) }
|
// cant add to u64 - if (table.u64_type_idx in lr) { return table.Type(table.u64_type_idx) }
|
||||||
// just guessing this order
|
// just guessing this order
|
||||||
if table.i64_type_idx in lr { return table.Type(table.i64_type_idx) }
|
if table.i64_type_idx in lr {
|
||||||
if table.u32_type_idx in lr { return table.Type(table.u32_type_idx) }
|
return table.Type(table.i64_type_idx)
|
||||||
if table.int_type_idx in lr { return table.Type(table.int_type_idx) }
|
}
|
||||||
if table.u16_type_idx in lr { return table.Type(table.u16_type_idx) }
|
if table.u32_type_idx in lr {
|
||||||
if table.i16_type_idx in lr { return table.Type(table.i16_type_idx) }
|
return table.Type(table.u32_type_idx)
|
||||||
if table.byte_type_idx in lr { return table.Type(table.byte_type_idx) }
|
}
|
||||||
if table.i8_type_idx in lr { return table.Type(table.i8_type_idx) }
|
if table.int_type_idx in lr {
|
||||||
|
return table.Type(table.int_type_idx)
|
||||||
|
}
|
||||||
|
if table.u16_type_idx in lr {
|
||||||
|
return table.Type(table.u16_type_idx)
|
||||||
|
}
|
||||||
|
if table.i16_type_idx in lr {
|
||||||
|
return table.Type(table.i16_type_idx)
|
||||||
|
}
|
||||||
|
if table.byte_type_idx in lr {
|
||||||
|
return table.Type(table.byte_type_idx)
|
||||||
|
}
|
||||||
|
if table.i8_type_idx in lr {
|
||||||
|
return table.Type(table.i8_type_idx)
|
||||||
|
}
|
||||||
return table.Type(table.any_int_type_idx)
|
return table.Type(table.any_int_type_idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return table.Type(l)
|
return table.Type(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1439,7 +1478,9 @@ fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
|
fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
|
||||||
if g.file.mod.name == 'builtin' { g.write('new ') }
|
if g.file.mod.name == 'builtin' {
|
||||||
|
g.write('new ')
|
||||||
|
}
|
||||||
g.write('string(`')
|
g.write('string(`')
|
||||||
for i, val in it.vals {
|
for i, val in it.vals {
|
||||||
escaped_val := val.replace('`', '\\`')
|
escaped_val := val.replace('`', '\\`')
|
||||||
|
@ -1517,10 +1558,9 @@ fn (mut g JsGen) gen_typeof_expr(it ast.TypeOf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) {
|
fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) {
|
||||||
is_literal := (
|
is_literal := ((it.expr is ast.IntegerLiteral &&
|
||||||
(it.expr is ast.IntegerLiteral && it.typ in table.integer_type_idxs) ||
|
it.typ in table.integer_type_idxs) ||
|
||||||
(it.expr is ast.FloatLiteral && it.typ in table.float_type_idxs)
|
(it.expr is ast.FloatLiteral && it.typ in table.float_type_idxs))
|
||||||
)
|
|
||||||
typ := g.typ(it.typ)
|
typ := g.typ(it.typ)
|
||||||
if !is_literal {
|
if !is_literal {
|
||||||
if !(typ in v_types) || g.ns.name == 'builtin' {
|
if !(typ in v_types) || g.ns.name == 'builtin' {
|
||||||
|
|
|
@ -224,8 +224,6 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||||
} else {
|
} else {
|
||||||
g.write('*.*s')
|
g.write('*.*s')
|
||||||
}
|
}
|
||||||
} else if typ.has_flag(.variadic) {
|
|
||||||
g.write('.*s')
|
|
||||||
} else if typ.is_float() {
|
} else if typ.is_float() {
|
||||||
g.write('$fmt${fspec:c}')
|
g.write('$fmt${fspec:c}')
|
||||||
} else if typ.is_pointer() {
|
} else if typ.is_pointer() {
|
||||||
|
|
|
@ -126,6 +126,13 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
|
||||||
mut comments := p.eat_comments()
|
mut comments := p.eat_comments()
|
||||||
arg_start_pos := p.tok.position()
|
arg_start_pos := p.tok.position()
|
||||||
mut e := p.expr(0)
|
mut e := p.expr(0)
|
||||||
|
if p.tok.kind == .ellipsis {
|
||||||
|
p.next()
|
||||||
|
e = ast.ArrayDecompose{
|
||||||
|
expr: e
|
||||||
|
pos: p.tok.position()
|
||||||
|
}
|
||||||
|
}
|
||||||
if mut e is ast.StructInit {
|
if mut e is ast.StructInit {
|
||||||
e.pre_comments << comments
|
e.pre_comments << comments
|
||||||
comments = []ast.Comment{}
|
comments = []ast.Comment{}
|
||||||
|
@ -533,7 +540,7 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_variadic {
|
if is_variadic {
|
||||||
arg_type = arg_type.set_flag(.variadic)
|
arg_type = table.new_type(p.table.find_or_register_array(arg_type, 1)).set_flag(.variadic)
|
||||||
}
|
}
|
||||||
if p.tok.kind == .eof {
|
if p.tok.kind == .eof {
|
||||||
p.error_with_pos('expecting `)`', p.prev_tok.position())
|
p.error_with_pos('expecting `)`', p.prev_tok.position())
|
||||||
|
@ -621,7 +628,7 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_variadic {
|
if is_variadic {
|
||||||
typ = typ.set_flag(.variadic)
|
typ = table.new_type(p.table.find_or_register_array(typ, 1)).set_flag(.variadic)
|
||||||
}
|
}
|
||||||
for i, arg_name in arg_names {
|
for i, arg_name in arg_names {
|
||||||
args << table.Param{
|
args << table.Param{
|
||||||
|
|
|
@ -641,7 +641,9 @@ pub fn (t &Table) value_type(typ Type) Type {
|
||||||
typ_sym := t.get_type_symbol(typ)
|
typ_sym := t.get_type_symbol(typ)
|
||||||
if typ.has_flag(.variadic) {
|
if typ.has_flag(.variadic) {
|
||||||
// ...string => string
|
// ...string => string
|
||||||
return typ.clear_flag(.variadic)
|
// return typ.clear_flag(.variadic)
|
||||||
|
array_info := typ_sym.info as Array
|
||||||
|
return array_info.elem_type
|
||||||
}
|
}
|
||||||
if typ_sym.kind == .array {
|
if typ_sym.kind == .array {
|
||||||
// Check index type
|
// Check index type
|
||||||
|
|
|
@ -718,9 +718,13 @@ pub fn (table &Table) type_to_str_using_aliases(t Type, import_aliases map[strin
|
||||||
if t == array_type {
|
if t == array_type {
|
||||||
return 'array'
|
return 'array'
|
||||||
}
|
}
|
||||||
info := sym.info as Array
|
if t.has_flag(.variadic) {
|
||||||
elem_str := table.type_to_str_using_aliases(info.elem_type, import_aliases)
|
res = table.type_to_str_using_aliases(table.value_type(t), import_aliases)
|
||||||
res = '[]$elem_str'
|
} else {
|
||||||
|
info := sym.info as Array
|
||||||
|
elem_str := table.type_to_str_using_aliases(info.elem_type, import_aliases)
|
||||||
|
res = '[]$elem_str'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.array_fixed {
|
.array_fixed {
|
||||||
info := sym.info as ArrayFixed
|
info := sym.info as ArrayFixed
|
||||||
|
|
|
@ -34,10 +34,10 @@ fn test_fn_variadic_generic() {
|
||||||
*/
|
*/
|
||||||
// forwarding
|
// forwarding
|
||||||
fn variadic_forward_a(a ...string) string {
|
fn variadic_forward_a(a ...string) string {
|
||||||
return variadic_forward_b(a)
|
return variadic_fn_a(a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variadic_forward_b(a ...string) string {
|
fn variadic_fn_a(a ...string) string {
|
||||||
a0 := a[0]
|
a0 := a[0]
|
||||||
a1 := a[1]
|
a1 := a[1]
|
||||||
a2 := a[2]
|
a2 := a[2]
|
||||||
|
@ -64,6 +64,11 @@ fn test_variadic_only_with_no_vargs() {
|
||||||
fn_variadic_only_with_no_vargs()
|
fn_variadic_only_with_no_vargs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_array_decomposition_to_vargs() {
|
||||||
|
a := ['a', 'b', 'c']
|
||||||
|
assert variadic_fn_a(a...) == 'abc'
|
||||||
|
}
|
||||||
|
|
||||||
struct VaTestStruct {
|
struct VaTestStruct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,13 +180,13 @@ pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr byteptr, len int) ?int {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s SSLConn) read_into(mut buffer []Byte) ?int {
|
pub fn (mut s SSLConn) read_into(mut buffer []byte) ?int {
|
||||||
res := s.socket_read_into_ptr(byteptr(buffer.data), buffer.len)?
|
res := s.socket_read_into_ptr(byteptr(buffer.data), buffer.len)?
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// write number of bytes to SSL connection
|
// write number of bytes to SSL connection
|
||||||
pub fn (mut s SSLConn) write(bytes []Byte) ? {
|
pub fn (mut s SSLConn) write(bytes []byte) ? {
|
||||||
unsafe {
|
unsafe {
|
||||||
mut ptr_base := byteptr(bytes.data)
|
mut ptr_base := byteptr(bytes.data)
|
||||||
mut total_sent := 0
|
mut total_sent := 0
|
||||||
|
|
Loading…
Reference in New Issue