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 Expr = AnonFn | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral | CTempVar |
|
||||
CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal |
|
||||
FloatLiteral | Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral |
|
||||
pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral |
|
||||
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr |
|
||||
EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral |
|
||||
Likely | LockExpr | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr |
|
||||
RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral |
|
||||
StructInit | Type | TypeOf | UnsafeExpr
|
||||
|
@ -890,6 +890,15 @@ pub mut:
|
|||
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:
|
||||
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 {
|
||||
return expr.pos
|
||||
}
|
||||
ArrayDecompose {
|
||||
return expr.pos
|
||||
}
|
||||
IfGuardExpr {
|
||||
return expr.expr.position()
|
||||
}
|
||||
|
|
|
@ -7,6 +7,20 @@ import v.table
|
|||
import v.token
|
||||
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 {
|
||||
if got == expected {
|
||||
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())
|
||||
continue
|
||||
}
|
||||
if !c.check_types(got_arg_typ, exp_arg_typ) {
|
||||
got_arg_sym := c.table.get_type_symbol(got_arg_typ)
|
||||
c.check_expected_call_arg(got_arg_typ, exp_arg_typ) or {
|
||||
// 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
|
||||
// }
|
||||
// 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 {
|
||||
c.error('cannot use type `$got_arg_sym.name` as type `$exp_arg_sym.name` in argument ${i +
|
||||
1} to `${left_type_sym.name}.$method_name`', call_expr.pos)
|
||||
c.error('$err in argument ${i + 1} to `${left_type_sym.name}.$method_name`',
|
||||
call_expr.pos)
|
||||
}
|
||||
}
|
||||
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())
|
||||
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
|
||||
// Passing an int or a string array produces a c error here
|
||||
// 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 {
|
||||
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 {
|
||||
|
@ -2981,6 +2976,18 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
c.cur_fn = keep_fn
|
||||
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 {
|
||||
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 |
|
||||
5 | v := 4
|
||||
6 | ptr(&v)
|
||||
| ~~
|
||||
7 | arr([5]!!)
|
||||
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
|
||||
6 | ptr(&v)
|
||||
7 | arr([5]!!)
|
||||
| ~~~~~
|
||||
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)
|
||||
7 | arr([5]!!)
|
||||
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() {
|
||||
6 | a := 12.3
|
||||
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 |
|
||||
3 | fn main() {
|
||||
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
|
||||
7 | s := Sss{}
|
||||
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 |
|
||||
26 | fn main() {
|
||||
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()
|
||||
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
|
||||
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)
|
||||
30 | })
|
||||
31 | sum(xxx)
|
||||
|
|
|
@ -1138,6 +1138,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
|||
}
|
||||
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) {
|
||||
option_already_generated_key := 'option_$already_generated_key'
|
||||
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('}')
|
||||
}
|
||||
|
||||
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) {
|
||||
for typ in info.types {
|
||||
sym := g.table.get_type_symbol(typ)
|
||||
|
|
|
@ -56,7 +56,6 @@ mut:
|
|||
last_fn_c_name string
|
||||
tmp_count int // counter for unique tmp vars (_tmp1, tmp2 etc)
|
||||
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_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)
|
||||
|
@ -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.write_variadic_types()
|
||||
// g.write_str_definitions()
|
||||
// v files are finished, what remains is pure C code
|
||||
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')
|
||||
}
|
||||
|
||||
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) {
|
||||
$if trace_gen ? {
|
||||
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: {}')
|
||||
}
|
||||
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 {
|
||||
i := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var }
|
||||
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)
|
||||
g.write(fsym.name)
|
||||
}
|
||||
ast.ArrayDecompose {
|
||||
g.expr(node.expr)
|
||||
}
|
||||
ast.ArrayInit {
|
||||
g.array_init(node)
|
||||
}
|
||||
|
@ -2775,7 +2751,8 @@ fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
|||
info := sym.info as table.FnType
|
||||
g.write('_SLIT("${g.fn_decl_str(info)}")')
|
||||
} 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 {
|
||||
g.write('_SLIT("${util.strip_main_name(sym.name)}")')
|
||||
}
|
||||
|
@ -3835,13 +3812,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
|||
else {
|
||||
sym := g.table.get_type_symbol(node.left_type)
|
||||
left_is_ptr := node.left_type.is_ptr()
|
||||
if node.left_type.has_flag(.variadic) {
|
||||
g.expr(node.left)
|
||||
g.write('.args')
|
||||
g.write('[')
|
||||
g.expr(node.index)
|
||||
g.write(']')
|
||||
} else if sym.kind == .array {
|
||||
if sym.kind == .array {
|
||||
info := sym.info as table.Array
|
||||
elem_type_str := g.typ(info.elem_type)
|
||||
elem_typ := g.table.get_type_symbol(info.elem_type)
|
||||
|
|
|
@ -52,10 +52,8 @@ const (
|
|||
#endif
|
||||
|
||||
#ifdef __TINYC__
|
||||
#undef EMPTY_VARG_INITIALIZATION
|
||||
#undef EMPTY_STRUCT_DECLARATION
|
||||
#undef EMPTY_STRUCT_INITIALIZATION
|
||||
#define EMPTY_VARG_INITIALIZATION
|
||||
#define EMPTY_STRUCT_DECLARATION char _dummy
|
||||
#define EMPTY_STRUCT_INITIALIZATION 0
|
||||
#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)
|
||||
arg_type_sym := g.table.get_type_symbol(typ)
|
||||
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 {
|
||||
info := arg_type_sym.info as table.FnType
|
||||
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 }
|
||||
expected_types := node.expected_arg_types
|
||||
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 {
|
||||
if gen_vargs && i == expected_types.len - 1 {
|
||||
if is_variadic && i == expected_types.len - 1 {
|
||||
break
|
||||
}
|
||||
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 {
|
||||
g.write(')')
|
||||
}
|
||||
if i < args.len - 1 || gen_vargs {
|
||||
if i < args.len - 1 || is_variadic {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
arg_nr := expected_types.len - 1
|
||||
if gen_vargs {
|
||||
if is_variadic {
|
||||
varg_type := expected_types[expected_types.len - 1]
|
||||
struct_name := 'varg_' + g.typ(varg_type).replace('*', '_ptr')
|
||||
variadic_count := args.len - arg_nr
|
||||
varg_type_str := int(varg_type).str()
|
||||
if variadic_count > g.variadic_args[varg_type_str] {
|
||||
g.variadic_args[varg_type_str] = variadic_count
|
||||
}
|
||||
g.write('($struct_name){.len=$variadic_count,.args={')
|
||||
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(', ')
|
||||
}
|
||||
}
|
||||
arr_sym := g.table.get_type_symbol(varg_type)
|
||||
arr_info := arr_sym.info as table.Array
|
||||
elem_type := g.typ(arr_info.elem_type)
|
||||
if args.len > 0 && args[args.len - 1].expr is ast.ArrayDecompose {
|
||||
g.expr(args[args.len - 1].expr)
|
||||
} else {
|
||||
// NB: tcc can not handle 0 here, while msvc needs it
|
||||
g.write('EMPTY_VARG_INITIALIZATION')
|
||||
if variadic_count > 0 {
|
||||
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',
|
||||
'while', 'with', 'yield', 'Number', 'String', 'Boolean', 'Array', 'Map']
|
||||
// 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',
|
||||
'\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 {
|
||||
table &table.Table
|
||||
pref &pref.Preferences
|
||||
table &table.Table
|
||||
pref &pref.Preferences
|
||||
mut:
|
||||
definitions strings.Builder
|
||||
ns &Namespace
|
||||
namespaces map[string]&Namespace
|
||||
doc &JsDoc
|
||||
enable_doc bool
|
||||
file ast.File
|
||||
tmp_count int
|
||||
inside_ternary bool
|
||||
inside_loop bool
|
||||
inside_map_set bool // map.set(key, value)
|
||||
inside_builtin bool
|
||||
generated_builtin bool
|
||||
definitions strings.Builder
|
||||
ns &Namespace
|
||||
namespaces map[string]&Namespace
|
||||
doc &JsDoc
|
||||
enable_doc bool
|
||||
file ast.File
|
||||
tmp_count int
|
||||
inside_ternary bool
|
||||
inside_loop bool
|
||||
inside_map_set bool // map.set(key, value)
|
||||
inside_builtin bool
|
||||
generated_builtin bool
|
||||
inside_def_typ_decl bool
|
||||
is_test bool
|
||||
stmt_start_pos int
|
||||
defer_stmts []ast.DeferStmt
|
||||
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
||||
str_types []string // types that need automatic str() generation
|
||||
method_fn_decls map[string][]ast.FnDecl
|
||||
builtin_fns []string // Functions defined in `builtin`
|
||||
empty_line bool
|
||||
is_test bool
|
||||
stmt_start_pos int
|
||||
defer_stmts []ast.DeferStmt
|
||||
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
||||
str_types []string // types that need automatic str() generation
|
||||
method_fn_decls map[string][]ast.FnDecl
|
||||
builtin_fns []string // Functions defined in `builtin`
|
||||
empty_line bool
|
||||
}
|
||||
|
||||
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 += 'const ['
|
||||
for i, typ in v_types {
|
||||
if i > 0 { out += ', ' }
|
||||
if i > 0 {
|
||||
out += ', '
|
||||
}
|
||||
out += '$typ'
|
||||
}
|
||||
out += '] = ['
|
||||
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]\n'
|
||||
|
@ -257,14 +262,18 @@ pub fn (mut g JsGen) dec_indent() {
|
|||
|
||||
[inline]
|
||||
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.ns.out.write(s)
|
||||
}
|
||||
|
||||
[inline]
|
||||
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.ns.out.writeln(s)
|
||||
g.empty_line = true
|
||||
|
@ -304,7 +313,13 @@ fn (mut g JsGen) js_name(name_ string) string {
|
|||
is_js = true
|
||||
}
|
||||
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('.')
|
||||
if !is_js {
|
||||
for i, p in parts {
|
||||
|
@ -529,8 +544,10 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
g.gen_string_inter_literal(node)
|
||||
}
|
||||
ast.StringLiteral {
|
||||
text := node.val.replace('\'', "\\'")
|
||||
if g.file.mod.name == 'builtin' { g.write('new ') }
|
||||
text := node.val.replace("\'", "\\'")
|
||||
if g.file.mod.name == 'builtin' {
|
||||
g.write('new ')
|
||||
}
|
||||
g.write("string('$text')")
|
||||
}
|
||||
ast.StructInit {
|
||||
|
@ -559,6 +576,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
ast.UnsafeExpr {
|
||||
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) {
|
||||
g.writeln('toString() {')
|
||||
g.inc_indent()
|
||||
g.write('return `${js_name} {')
|
||||
g.write('return `$js_name {')
|
||||
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() {
|
||||
"string" { g.write('$field.name: "\${this["${field.name}"].toString()}"') }
|
||||
else { 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()} ') }
|
||||
}
|
||||
}
|
||||
g.writeln('}`')
|
||||
g.dec_indent()
|
||||
g.writeln('}')
|
||||
}
|
||||
|
||||
g.dec_indent()
|
||||
g.writeln('};\n')
|
||||
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 {
|
||||
l := int(left)
|
||||
r := int(right)
|
||||
lr := [l,r]
|
||||
|
||||
if table.string_type_idx in lr { 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)
|
||||
lr := [l, r]
|
||||
if table.string_type_idx in lr {
|
||||
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)
|
||||
if should_float {
|
||||
if table.f64_type_idx in lr { return table.Type(table.f64_type_idx) }
|
||||
if table.f32_type_idx in lr { return table.Type(table.f32_type_idx) }
|
||||
if table.f64_type_idx in lr {
|
||||
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)
|
||||
}
|
||||
|
||||
should_int := (l in table.integer_type_idxs && r in table.integer_type_idxs)
|
||||
if should_int {
|
||||
// cant add to u64 - if (table.u64_type_idx in lr) { return table.Type(table.u64_type_idx) }
|
||||
// just guessing this order
|
||||
if table.i64_type_idx in lr { return table.Type(table.i64_type_idx) }
|
||||
if table.u32_type_idx in lr { return table.Type(table.u32_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) }
|
||||
if table.i64_type_idx in lr {
|
||||
return table.Type(table.i64_type_idx)
|
||||
}
|
||||
if table.u32_type_idx in lr {
|
||||
return table.Type(table.u32_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(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) {
|
||||
if g.file.mod.name == 'builtin' { g.write('new ') }
|
||||
if g.file.mod.name == 'builtin' {
|
||||
g.write('new ')
|
||||
}
|
||||
g.write('string(`')
|
||||
for i, val in it.vals {
|
||||
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) {
|
||||
is_literal := (
|
||||
(it.expr is ast.IntegerLiteral && it.typ in table.integer_type_idxs) ||
|
||||
(it.expr is ast.FloatLiteral && it.typ in table.float_type_idxs)
|
||||
)
|
||||
is_literal := ((it.expr is ast.IntegerLiteral &&
|
||||
it.typ in table.integer_type_idxs) ||
|
||||
(it.expr is ast.FloatLiteral && it.typ in table.float_type_idxs))
|
||||
typ := g.typ(it.typ)
|
||||
if !is_literal {
|
||||
if !(typ in v_types) || g.ns.name == 'builtin' {
|
||||
|
|
|
@ -224,8 +224,6 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|||
} else {
|
||||
g.write('*.*s')
|
||||
}
|
||||
} else if typ.has_flag(.variadic) {
|
||||
g.write('.*s')
|
||||
} else if typ.is_float() {
|
||||
g.write('$fmt${fspec:c}')
|
||||
} else if typ.is_pointer() {
|
||||
|
|
|
@ -126,6 +126,13 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
|
|||
mut comments := p.eat_comments()
|
||||
arg_start_pos := p.tok.position()
|
||||
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 {
|
||||
e.pre_comments << comments
|
||||
comments = []ast.Comment{}
|
||||
|
@ -533,7 +540,7 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) {
|
|||
}
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
args << table.Param{
|
||||
|
|
|
@ -641,7 +641,9 @@ pub fn (t &Table) value_type(typ Type) Type {
|
|||
typ_sym := t.get_type_symbol(typ)
|
||||
if typ.has_flag(.variadic) {
|
||||
// ...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 {
|
||||
// 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 {
|
||||
return 'array'
|
||||
}
|
||||
info := sym.info as Array
|
||||
elem_str := table.type_to_str_using_aliases(info.elem_type, import_aliases)
|
||||
res = '[]$elem_str'
|
||||
if t.has_flag(.variadic) {
|
||||
res = table.type_to_str_using_aliases(table.value_type(t), import_aliases)
|
||||
} else {
|
||||
info := sym.info as Array
|
||||
elem_str := table.type_to_str_using_aliases(info.elem_type, import_aliases)
|
||||
res = '[]$elem_str'
|
||||
}
|
||||
}
|
||||
.array_fixed {
|
||||
info := sym.info as ArrayFixed
|
||||
|
|
|
@ -34,10 +34,10 @@ fn test_fn_variadic_generic() {
|
|||
*/
|
||||
// forwarding
|
||||
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]
|
||||
a1 := a[1]
|
||||
a2 := a[2]
|
||||
|
@ -64,6 +64,11 @@ fn test_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 {
|
||||
}
|
||||
|
||||
|
|
|
@ -180,13 +180,13 @@ pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr byteptr, len int) ?int {
|
|||
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)?
|
||||
return res
|
||||
}
|
||||
|
||||
// write number of bytes to SSL connection
|
||||
pub fn (mut s SSLConn) write(bytes []Byte) ? {
|
||||
pub fn (mut s SSLConn) write(bytes []byte) ? {
|
||||
unsafe {
|
||||
mut ptr_base := byteptr(bytes.data)
|
||||
mut total_sent := 0
|
||||
|
|
Loading…
Reference in New Issue