mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
parser, checker, cgen: minor cleanup of go_expr() (#13875)
This commit is contained in:
parent
db3bbb58cf
commit
bc98c11d9d
@ -2111,32 +2111,6 @@ fn (mut c Checker) global_decl(mut node ast.GlobalDecl) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) go_expr(mut node ast.GoExpr) ast.Type {
|
||||
ret_type := c.call_expr(mut node.call_expr)
|
||||
if node.call_expr.or_block.kind != .absent {
|
||||
c.error('optional handling cannot be done in `go` call. Do it when calling `.wait()`',
|
||||
node.call_expr.or_block.pos)
|
||||
}
|
||||
// Make sure there are no mutable arguments
|
||||
for arg in node.call_expr.args {
|
||||
if arg.is_mut && !arg.typ.is_ptr() {
|
||||
c.error('function in `go` statement cannot contain mutable non-reference arguments',
|
||||
arg.expr.pos())
|
||||
}
|
||||
}
|
||||
if node.call_expr.is_method && node.call_expr.receiver_type.is_ptr()
|
||||
&& !node.call_expr.left_type.is_ptr() {
|
||||
c.error('method in `go` statement cannot have non-reference mutable receiver',
|
||||
node.call_expr.left.pos())
|
||||
}
|
||||
|
||||
if c.pref.backend.is_js() {
|
||||
return c.table.find_or_register_promise(ret_type)
|
||||
} else {
|
||||
return c.table.find_or_register_thread(ret_type)
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {
|
||||
if stmt.is_goto {
|
||||
c.warn('inline assembly goto is not supported, it will most likely not work',
|
||||
|
@ -1484,6 +1484,32 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||
return ast.void_type
|
||||
}
|
||||
|
||||
fn (mut c Checker) go_expr(mut node ast.GoExpr) ast.Type {
|
||||
ret_type := c.call_expr(mut node.call_expr)
|
||||
if node.call_expr.or_block.kind != .absent {
|
||||
c.error('optional handling cannot be done in `go` call. Do it when calling `.wait()`',
|
||||
node.call_expr.or_block.pos)
|
||||
}
|
||||
// Make sure there are no mutable arguments
|
||||
for arg in node.call_expr.args {
|
||||
if arg.is_mut && !arg.typ.is_ptr() {
|
||||
c.error('function in `go` statement cannot contain mutable non-reference arguments',
|
||||
arg.expr.pos())
|
||||
}
|
||||
}
|
||||
if node.call_expr.is_method && node.call_expr.receiver_type.is_ptr()
|
||||
&& !node.call_expr.left_type.is_ptr() {
|
||||
c.error('method in `go` statement cannot have non-reference mutable receiver',
|
||||
node.call_expr.left.pos())
|
||||
}
|
||||
|
||||
if c.pref.backend.is_js() {
|
||||
return c.table.find_or_register_promise(ret_type)
|
||||
} else {
|
||||
return c.table.find_or_register_thread(ret_type)
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) deprecate_fnmethod(kind string, name string, the_fn ast.Fn, node ast.CallExpr) {
|
||||
mut deprecation_message := ''
|
||||
now := time.now()
|
||||
|
@ -5146,258 +5146,6 @@ fn (mut g Gen) enum_val(node ast.EnumVal) {
|
||||
g.write('${styp}__$node.val')
|
||||
}
|
||||
|
||||
fn (mut g Gen) go_expr(node ast.GoExpr) {
|
||||
line := g.go_before_stmt(0)
|
||||
mut handle := ''
|
||||
tmp := g.new_tmp_var()
|
||||
mut expr := node.call_expr
|
||||
mut name := expr.name // util.no_dots(expr.name)
|
||||
// TODO: fn call is duplicated. merge with fn_call().
|
||||
for i, concrete_type in expr.concrete_types {
|
||||
if concrete_type != ast.void_type && concrete_type != 0 {
|
||||
// Using _T_ to differentiate between get<string> and get_string
|
||||
// `foo<int>()` => `foo_T_int()`
|
||||
if i == 0 {
|
||||
name += '_T'
|
||||
}
|
||||
name += '_' + g.typ(concrete_type)
|
||||
}
|
||||
}
|
||||
if expr.is_method {
|
||||
receiver_sym := g.table.sym(expr.receiver_type)
|
||||
name = receiver_sym.name + '_' + name
|
||||
} else if mut expr.left is ast.AnonFn {
|
||||
g.gen_anon_fn_decl(mut expr.left)
|
||||
name = expr.left.decl.name
|
||||
} else if expr.is_fn_var {
|
||||
name = g.table.sym(expr.fn_var_type).name
|
||||
}
|
||||
name = util.no_dots(name)
|
||||
if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') {
|
||||
mut key := expr.name
|
||||
if expr.is_method {
|
||||
sym := g.table.sym(expr.receiver_type)
|
||||
key = sym.name + '.' + expr.name
|
||||
}
|
||||
g.write('/* obf go: $key */')
|
||||
name = g.obf_table[key] or {
|
||||
panic('cgen: obf name "$key" not found, this should never happen')
|
||||
}
|
||||
}
|
||||
g.empty_line = true
|
||||
g.writeln('// start go')
|
||||
wrapper_struct_name := 'thread_arg_' + name
|
||||
wrapper_fn_name := name + '_thread_wrapper'
|
||||
arg_tmp_var := 'arg_' + tmp
|
||||
g.writeln('$wrapper_struct_name *$arg_tmp_var = malloc(sizeof(thread_arg_$name));')
|
||||
if expr.is_method {
|
||||
g.write('$arg_tmp_var->arg0 = ')
|
||||
// TODO is this needed?
|
||||
/*
|
||||
if false && !expr.return_type.is_ptr() {
|
||||
g.write('&')
|
||||
}
|
||||
*/
|
||||
g.expr(expr.left)
|
||||
g.writeln(';')
|
||||
}
|
||||
for i, arg in expr.args {
|
||||
g.write('$arg_tmp_var->arg${i + 1} = ')
|
||||
g.expr(arg.expr)
|
||||
g.writeln(';')
|
||||
}
|
||||
s_ret_typ := g.typ(node.call_expr.return_type)
|
||||
if g.pref.os == .windows && node.call_expr.return_type != ast.void_type {
|
||||
g.writeln('$arg_tmp_var->ret_ptr = malloc(sizeof($s_ret_typ));')
|
||||
}
|
||||
is_opt := node.call_expr.return_type.has_flag(.optional)
|
||||
mut gohandle_name := ''
|
||||
if node.call_expr.return_type == ast.void_type {
|
||||
gohandle_name = if is_opt { '__v_thread_Option_void' } else { '__v_thread' }
|
||||
} else {
|
||||
opt := if is_opt { 'Option_' } else { '' }
|
||||
gohandle_name = '__v_thread_$opt${g.table.sym(g.unwrap_generic(node.call_expr.return_type)).cname}'
|
||||
}
|
||||
if g.pref.os == .windows {
|
||||
simple_handle := if node.is_expr && node.call_expr.return_type != ast.void_type {
|
||||
'thread_handle_$tmp'
|
||||
} else {
|
||||
'thread_$tmp'
|
||||
}
|
||||
g.writeln('HANDLE $simple_handle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)$wrapper_fn_name, $arg_tmp_var, 0, 0);')
|
||||
g.writeln('if (!$simple_handle) panic_lasterr(tos3("`go ${name}()`: "));')
|
||||
if node.is_expr && node.call_expr.return_type != ast.void_type {
|
||||
g.writeln('$gohandle_name thread_$tmp = {')
|
||||
g.writeln('\t.ret_ptr = $arg_tmp_var->ret_ptr,')
|
||||
g.writeln('\t.handle = thread_handle_$tmp')
|
||||
g.writeln('};')
|
||||
}
|
||||
if !node.is_expr {
|
||||
g.writeln('CloseHandle(thread_$tmp);')
|
||||
}
|
||||
} else {
|
||||
g.writeln('pthread_t thread_$tmp;')
|
||||
g.writeln('int ${tmp}_thr_res = pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);')
|
||||
g.writeln('if (${tmp}_thr_res) panic_error_number(tos3("`go ${name}()`: "), ${tmp}_thr_res);')
|
||||
if !node.is_expr {
|
||||
g.writeln('pthread_detach(thread_$tmp);')
|
||||
}
|
||||
}
|
||||
g.writeln('// end go')
|
||||
if node.is_expr {
|
||||
handle = 'thread_$tmp'
|
||||
// create wait handler for this return type if none exists
|
||||
waiter_fn_name := gohandle_name + '_wait'
|
||||
mut should_register := false
|
||||
lock g.waiter_fns {
|
||||
if waiter_fn_name !in g.waiter_fns {
|
||||
g.waiter_fns << waiter_fn_name
|
||||
should_register = true
|
||||
}
|
||||
}
|
||||
if should_register {
|
||||
g.gowrappers.writeln('\n$s_ret_typ ${waiter_fn_name}($gohandle_name thread) {')
|
||||
mut c_ret_ptr_ptr := 'NULL'
|
||||
if node.call_expr.return_type != ast.void_type {
|
||||
g.gowrappers.writeln('\t$s_ret_typ* ret_ptr;')
|
||||
c_ret_ptr_ptr = '&ret_ptr'
|
||||
}
|
||||
if g.pref.os == .windows {
|
||||
if node.call_expr.return_type == ast.void_type {
|
||||
g.gowrappers.writeln('\tu32 stat = WaitForSingleObject(thread, INFINITE);')
|
||||
} else {
|
||||
g.gowrappers.writeln('\tu32 stat = WaitForSingleObject(thread.handle, INFINITE);')
|
||||
g.gowrappers.writeln('\tret_ptr = thread.ret_ptr;')
|
||||
}
|
||||
} else {
|
||||
g.gowrappers.writeln('\tint stat = pthread_join(thread, (void **)$c_ret_ptr_ptr);')
|
||||
}
|
||||
g.gowrappers.writeln('\tif (stat != 0) { _v_panic(_SLIT("unable to join thread")); }')
|
||||
if g.pref.os == .windows {
|
||||
if node.call_expr.return_type == ast.void_type {
|
||||
g.gowrappers.writeln('\tCloseHandle(thread);')
|
||||
} else {
|
||||
g.gowrappers.writeln('\tCloseHandle(thread.handle);')
|
||||
}
|
||||
}
|
||||
if node.call_expr.return_type != ast.void_type {
|
||||
g.gowrappers.writeln('\t$s_ret_typ ret = *ret_ptr;')
|
||||
g.gowrappers.writeln('\tfree(ret_ptr);')
|
||||
g.gowrappers.writeln('\treturn ret;')
|
||||
}
|
||||
g.gowrappers.writeln('}')
|
||||
}
|
||||
}
|
||||
// Register the wrapper type and function
|
||||
mut should_register := false
|
||||
lock g.threaded_fns {
|
||||
if name !in g.threaded_fns {
|
||||
g.threaded_fns << name
|
||||
should_register = true
|
||||
}
|
||||
}
|
||||
if should_register {
|
||||
g.type_definitions.writeln('\ntypedef struct $wrapper_struct_name {')
|
||||
if expr.is_method {
|
||||
styp := g.typ(expr.receiver_type)
|
||||
g.type_definitions.writeln('\t$styp arg0;')
|
||||
}
|
||||
need_return_ptr := g.pref.os == .windows && node.call_expr.return_type != ast.void_type
|
||||
if expr.args.len == 0 && !need_return_ptr {
|
||||
g.type_definitions.writeln('EMPTY_STRUCT_DECLARATION;')
|
||||
} else {
|
||||
for i, arg in expr.args {
|
||||
styp := g.typ(arg.typ)
|
||||
g.type_definitions.writeln('\t$styp arg${i + 1};')
|
||||
}
|
||||
}
|
||||
if need_return_ptr {
|
||||
g.type_definitions.writeln('\tvoid* ret_ptr;')
|
||||
}
|
||||
g.type_definitions.writeln('} $wrapper_struct_name;')
|
||||
thread_ret_type := if g.pref.os == .windows { 'u32' } else { 'void*' }
|
||||
g.type_definitions.writeln('$thread_ret_type ${wrapper_fn_name}($wrapper_struct_name *arg);')
|
||||
g.gowrappers.writeln('$thread_ret_type ${wrapper_fn_name}($wrapper_struct_name *arg) {')
|
||||
if node.call_expr.return_type != ast.void_type {
|
||||
if g.pref.os == .windows {
|
||||
g.gowrappers.write_string('\t*(($s_ret_typ*)(arg->ret_ptr)) = ')
|
||||
} else {
|
||||
g.gowrappers.writeln('\t$s_ret_typ* ret_ptr = malloc(sizeof($s_ret_typ));')
|
||||
g.gowrappers.write_string('\t*ret_ptr = ')
|
||||
}
|
||||
} else {
|
||||
g.gowrappers.write_string('\t')
|
||||
}
|
||||
if expr.is_method {
|
||||
unwrapped_rec_type := g.unwrap_generic(expr.receiver_type)
|
||||
typ_sym := g.table.sym(unwrapped_rec_type)
|
||||
if typ_sym.kind == .interface_
|
||||
&& (typ_sym.info as ast.Interface).defines_method(expr.name) {
|
||||
rec_cc_type := g.cc_type(unwrapped_rec_type, false)
|
||||
receiver_type_name := util.no_dots(rec_cc_type)
|
||||
g.gowrappers.write_string('${c_name(receiver_type_name)}_name_table[')
|
||||
g.gowrappers.write_string('arg->arg0')
|
||||
dot := if expr.left_type.is_ptr() { '->' } else { '.' }
|
||||
mname := c_name(expr.name)
|
||||
g.gowrappers.write_string('${dot}_typ]._method_${mname}(')
|
||||
g.gowrappers.write_string('arg->arg0')
|
||||
g.gowrappers.write_string('${dot}_object')
|
||||
} else {
|
||||
g.gowrappers.write_string('${name}(')
|
||||
g.gowrappers.write_string('arg->arg0')
|
||||
}
|
||||
if expr.args.len > 0 {
|
||||
g.gowrappers.write_string(', ')
|
||||
}
|
||||
} else {
|
||||
g.gowrappers.write_string('${name}(')
|
||||
}
|
||||
if expr.args.len > 0 {
|
||||
mut has_cast := false
|
||||
for i in 0 .. expr.args.len {
|
||||
if g.table.sym(expr.expected_arg_types[i]).kind == .interface_
|
||||
&& g.table.sym(expr.args[i].typ).kind != .interface_ {
|
||||
has_cast = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if has_cast {
|
||||
pos := g.out.len
|
||||
g.call_args(expr)
|
||||
mut call_args_str := g.out.after(pos)
|
||||
g.out.go_back(call_args_str.len)
|
||||
mut rep_group := []string{cap: 2 * expr.args.len}
|
||||
for i in 0 .. expr.args.len {
|
||||
rep_group << g.expr_string(expr.args[i].expr)
|
||||
rep_group << 'arg->arg${i + 1}'
|
||||
}
|
||||
call_args_str = call_args_str.replace_each(rep_group)
|
||||
g.gowrappers.write_string(call_args_str)
|
||||
} else {
|
||||
for i in 0 .. expr.args.len {
|
||||
g.gowrappers.write_string('arg->arg${i + 1}')
|
||||
if i != expr.args.len - 1 {
|
||||
g.gowrappers.write_string(', ')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.gowrappers.writeln(');')
|
||||
g.gowrappers.writeln('\tfree(arg);')
|
||||
if g.pref.os != .windows && node.call_expr.return_type != ast.void_type {
|
||||
g.gowrappers.writeln('\treturn ret_ptr;')
|
||||
} else {
|
||||
g.gowrappers.writeln('\treturn 0;')
|
||||
}
|
||||
g.gowrappers.writeln('}')
|
||||
}
|
||||
if node.is_expr {
|
||||
g.empty_line = false
|
||||
g.write(line)
|
||||
g.write(handle)
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) as_cast(node ast.AsCast) {
|
||||
// Make sure the sum type can be cast to this type (the types
|
||||
// are the same), otherwise panic.
|
||||
|
@ -1667,6 +1667,258 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) go_expr(node ast.GoExpr) {
|
||||
line := g.go_before_stmt(0)
|
||||
mut handle := ''
|
||||
tmp := g.new_tmp_var()
|
||||
mut expr := node.call_expr
|
||||
mut name := expr.name // util.no_dots(expr.name)
|
||||
// TODO: fn call is duplicated. merge with fn_call().
|
||||
for i, concrete_type in expr.concrete_types {
|
||||
if concrete_type != ast.void_type && concrete_type != 0 {
|
||||
// Using _T_ to differentiate between get<string> and get_string
|
||||
// `foo<int>()` => `foo_T_int()`
|
||||
if i == 0 {
|
||||
name += '_T'
|
||||
}
|
||||
name += '_' + g.typ(concrete_type)
|
||||
}
|
||||
}
|
||||
if expr.is_method {
|
||||
receiver_sym := g.table.sym(expr.receiver_type)
|
||||
name = receiver_sym.name + '_' + name
|
||||
} else if mut expr.left is ast.AnonFn {
|
||||
g.gen_anon_fn_decl(mut expr.left)
|
||||
name = expr.left.decl.name
|
||||
} else if expr.is_fn_var {
|
||||
name = g.table.sym(expr.fn_var_type).name
|
||||
}
|
||||
name = util.no_dots(name)
|
||||
if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') {
|
||||
mut key := expr.name
|
||||
if expr.is_method {
|
||||
sym := g.table.sym(expr.receiver_type)
|
||||
key = sym.name + '.' + expr.name
|
||||
}
|
||||
g.write('/* obf go: $key */')
|
||||
name = g.obf_table[key] or {
|
||||
panic('cgen: obf name "$key" not found, this should never happen')
|
||||
}
|
||||
}
|
||||
g.empty_line = true
|
||||
g.writeln('// start go')
|
||||
wrapper_struct_name := 'thread_arg_' + name
|
||||
wrapper_fn_name := name + '_thread_wrapper'
|
||||
arg_tmp_var := 'arg_' + tmp
|
||||
g.writeln('$wrapper_struct_name *$arg_tmp_var = malloc(sizeof(thread_arg_$name));')
|
||||
if expr.is_method {
|
||||
g.write('$arg_tmp_var->arg0 = ')
|
||||
// TODO is this needed?
|
||||
/*
|
||||
if false && !expr.return_type.is_ptr() {
|
||||
g.write('&')
|
||||
}
|
||||
*/
|
||||
g.expr(expr.left)
|
||||
g.writeln(';')
|
||||
}
|
||||
for i, arg in expr.args {
|
||||
g.write('$arg_tmp_var->arg${i + 1} = ')
|
||||
g.expr(arg.expr)
|
||||
g.writeln(';')
|
||||
}
|
||||
s_ret_typ := g.typ(node.call_expr.return_type)
|
||||
if g.pref.os == .windows && node.call_expr.return_type != ast.void_type {
|
||||
g.writeln('$arg_tmp_var->ret_ptr = malloc(sizeof($s_ret_typ));')
|
||||
}
|
||||
is_opt := node.call_expr.return_type.has_flag(.optional)
|
||||
mut gohandle_name := ''
|
||||
if node.call_expr.return_type == ast.void_type {
|
||||
gohandle_name = if is_opt { '__v_thread_Option_void' } else { '__v_thread' }
|
||||
} else {
|
||||
opt := if is_opt { 'Option_' } else { '' }
|
||||
gohandle_name = '__v_thread_$opt${g.table.sym(g.unwrap_generic(node.call_expr.return_type)).cname}'
|
||||
}
|
||||
if g.pref.os == .windows {
|
||||
simple_handle := if node.is_expr && node.call_expr.return_type != ast.void_type {
|
||||
'thread_handle_$tmp'
|
||||
} else {
|
||||
'thread_$tmp'
|
||||
}
|
||||
g.writeln('HANDLE $simple_handle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)$wrapper_fn_name, $arg_tmp_var, 0, 0);')
|
||||
g.writeln('if (!$simple_handle) panic_lasterr(tos3("`go ${name}()`: "));')
|
||||
if node.is_expr && node.call_expr.return_type != ast.void_type {
|
||||
g.writeln('$gohandle_name thread_$tmp = {')
|
||||
g.writeln('\t.ret_ptr = $arg_tmp_var->ret_ptr,')
|
||||
g.writeln('\t.handle = thread_handle_$tmp')
|
||||
g.writeln('};')
|
||||
}
|
||||
if !node.is_expr {
|
||||
g.writeln('CloseHandle(thread_$tmp);')
|
||||
}
|
||||
} else {
|
||||
g.writeln('pthread_t thread_$tmp;')
|
||||
g.writeln('int ${tmp}_thr_res = pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);')
|
||||
g.writeln('if (${tmp}_thr_res) panic_error_number(tos3("`go ${name}()`: "), ${tmp}_thr_res);')
|
||||
if !node.is_expr {
|
||||
g.writeln('pthread_detach(thread_$tmp);')
|
||||
}
|
||||
}
|
||||
g.writeln('// end go')
|
||||
if node.is_expr {
|
||||
handle = 'thread_$tmp'
|
||||
// create wait handler for this return type if none exists
|
||||
waiter_fn_name := gohandle_name + '_wait'
|
||||
mut should_register := false
|
||||
lock g.waiter_fns {
|
||||
if waiter_fn_name !in g.waiter_fns {
|
||||
g.waiter_fns << waiter_fn_name
|
||||
should_register = true
|
||||
}
|
||||
}
|
||||
if should_register {
|
||||
g.gowrappers.writeln('\n$s_ret_typ ${waiter_fn_name}($gohandle_name thread) {')
|
||||
mut c_ret_ptr_ptr := 'NULL'
|
||||
if node.call_expr.return_type != ast.void_type {
|
||||
g.gowrappers.writeln('\t$s_ret_typ* ret_ptr;')
|
||||
c_ret_ptr_ptr = '&ret_ptr'
|
||||
}
|
||||
if g.pref.os == .windows {
|
||||
if node.call_expr.return_type == ast.void_type {
|
||||
g.gowrappers.writeln('\tu32 stat = WaitForSingleObject(thread, INFINITE);')
|
||||
} else {
|
||||
g.gowrappers.writeln('\tu32 stat = WaitForSingleObject(thread.handle, INFINITE);')
|
||||
g.gowrappers.writeln('\tret_ptr = thread.ret_ptr;')
|
||||
}
|
||||
} else {
|
||||
g.gowrappers.writeln('\tint stat = pthread_join(thread, (void **)$c_ret_ptr_ptr);')
|
||||
}
|
||||
g.gowrappers.writeln('\tif (stat != 0) { _v_panic(_SLIT("unable to join thread")); }')
|
||||
if g.pref.os == .windows {
|
||||
if node.call_expr.return_type == ast.void_type {
|
||||
g.gowrappers.writeln('\tCloseHandle(thread);')
|
||||
} else {
|
||||
g.gowrappers.writeln('\tCloseHandle(thread.handle);')
|
||||
}
|
||||
}
|
||||
if node.call_expr.return_type != ast.void_type {
|
||||
g.gowrappers.writeln('\t$s_ret_typ ret = *ret_ptr;')
|
||||
g.gowrappers.writeln('\tfree(ret_ptr);')
|
||||
g.gowrappers.writeln('\treturn ret;')
|
||||
}
|
||||
g.gowrappers.writeln('}')
|
||||
}
|
||||
}
|
||||
// Register the wrapper type and function
|
||||
mut should_register := false
|
||||
lock g.threaded_fns {
|
||||
if name !in g.threaded_fns {
|
||||
g.threaded_fns << name
|
||||
should_register = true
|
||||
}
|
||||
}
|
||||
if should_register {
|
||||
g.type_definitions.writeln('\ntypedef struct $wrapper_struct_name {')
|
||||
if expr.is_method {
|
||||
styp := g.typ(expr.receiver_type)
|
||||
g.type_definitions.writeln('\t$styp arg0;')
|
||||
}
|
||||
need_return_ptr := g.pref.os == .windows && node.call_expr.return_type != ast.void_type
|
||||
if expr.args.len == 0 && !need_return_ptr {
|
||||
g.type_definitions.writeln('EMPTY_STRUCT_DECLARATION;')
|
||||
} else {
|
||||
for i, arg in expr.args {
|
||||
styp := g.typ(arg.typ)
|
||||
g.type_definitions.writeln('\t$styp arg${i + 1};')
|
||||
}
|
||||
}
|
||||
if need_return_ptr {
|
||||
g.type_definitions.writeln('\tvoid* ret_ptr;')
|
||||
}
|
||||
g.type_definitions.writeln('} $wrapper_struct_name;')
|
||||
thread_ret_type := if g.pref.os == .windows { 'u32' } else { 'void*' }
|
||||
g.type_definitions.writeln('$thread_ret_type ${wrapper_fn_name}($wrapper_struct_name *arg);')
|
||||
g.gowrappers.writeln('$thread_ret_type ${wrapper_fn_name}($wrapper_struct_name *arg) {')
|
||||
if node.call_expr.return_type != ast.void_type {
|
||||
if g.pref.os == .windows {
|
||||
g.gowrappers.write_string('\t*(($s_ret_typ*)(arg->ret_ptr)) = ')
|
||||
} else {
|
||||
g.gowrappers.writeln('\t$s_ret_typ* ret_ptr = malloc(sizeof($s_ret_typ));')
|
||||
g.gowrappers.write_string('\t*ret_ptr = ')
|
||||
}
|
||||
} else {
|
||||
g.gowrappers.write_string('\t')
|
||||
}
|
||||
if expr.is_method {
|
||||
unwrapped_rec_type := g.unwrap_generic(expr.receiver_type)
|
||||
typ_sym := g.table.sym(unwrapped_rec_type)
|
||||
if typ_sym.kind == .interface_
|
||||
&& (typ_sym.info as ast.Interface).defines_method(expr.name) {
|
||||
rec_cc_type := g.cc_type(unwrapped_rec_type, false)
|
||||
receiver_type_name := util.no_dots(rec_cc_type)
|
||||
g.gowrappers.write_string('${c_name(receiver_type_name)}_name_table[')
|
||||
g.gowrappers.write_string('arg->arg0')
|
||||
dot := if expr.left_type.is_ptr() { '->' } else { '.' }
|
||||
mname := c_name(expr.name)
|
||||
g.gowrappers.write_string('${dot}_typ]._method_${mname}(')
|
||||
g.gowrappers.write_string('arg->arg0')
|
||||
g.gowrappers.write_string('${dot}_object')
|
||||
} else {
|
||||
g.gowrappers.write_string('${name}(')
|
||||
g.gowrappers.write_string('arg->arg0')
|
||||
}
|
||||
if expr.args.len > 0 {
|
||||
g.gowrappers.write_string(', ')
|
||||
}
|
||||
} else {
|
||||
g.gowrappers.write_string('${name}(')
|
||||
}
|
||||
if expr.args.len > 0 {
|
||||
mut has_cast := false
|
||||
for i in 0 .. expr.args.len {
|
||||
if g.table.sym(expr.expected_arg_types[i]).kind == .interface_
|
||||
&& g.table.sym(expr.args[i].typ).kind != .interface_ {
|
||||
has_cast = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if has_cast {
|
||||
pos := g.out.len
|
||||
g.call_args(expr)
|
||||
mut call_args_str := g.out.after(pos)
|
||||
g.out.go_back(call_args_str.len)
|
||||
mut rep_group := []string{cap: 2 * expr.args.len}
|
||||
for i in 0 .. expr.args.len {
|
||||
rep_group << g.expr_string(expr.args[i].expr)
|
||||
rep_group << 'arg->arg${i + 1}'
|
||||
}
|
||||
call_args_str = call_args_str.replace_each(rep_group)
|
||||
g.gowrappers.write_string(call_args_str)
|
||||
} else {
|
||||
for i in 0 .. expr.args.len {
|
||||
g.gowrappers.write_string('arg->arg${i + 1}')
|
||||
if i != expr.args.len - 1 {
|
||||
g.gowrappers.write_string(', ')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.gowrappers.writeln(');')
|
||||
g.gowrappers.writeln('\tfree(arg);')
|
||||
if g.pref.os != .windows && node.call_expr.return_type != ast.void_type {
|
||||
g.gowrappers.writeln('\treturn ret_ptr;')
|
||||
} else {
|
||||
g.gowrappers.writeln('\treturn 0;')
|
||||
}
|
||||
g.gowrappers.writeln('}')
|
||||
}
|
||||
if node.is_expr {
|
||||
g.empty_line = false
|
||||
g.write(line)
|
||||
g.write(handle)
|
||||
}
|
||||
}
|
||||
|
||||
// similar to `autofree_call_pregen()` but only to to handle [keep_args_alive] for C functions
|
||||
fn (mut g Gen) keep_alive_call_pregen(node ast.CallExpr) int {
|
||||
g.empty_line = true
|
||||
|
@ -545,27 +545,6 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) go_expr() ast.GoExpr {
|
||||
p.next()
|
||||
spos := p.tok.pos()
|
||||
expr := p.expr(0)
|
||||
call_expr := if expr is ast.CallExpr {
|
||||
expr
|
||||
} else {
|
||||
p.error_with_pos('expression in `go` must be a function call', expr.pos())
|
||||
ast.CallExpr{
|
||||
scope: p.scope
|
||||
}
|
||||
}
|
||||
pos := spos.extend(p.prev_tok.pos())
|
||||
p.register_auto_import('sync.threads')
|
||||
p.table.gostmts++
|
||||
return ast.GoExpr{
|
||||
call_expr: call_expr
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
|
||||
fn (p &Parser) fileis(s string) bool {
|
||||
return p.file_name.contains(s)
|
||||
}
|
||||
|
@ -928,6 +928,27 @@ fn (mut p Parser) fn_args() ([]ast.Param, bool, bool) {
|
||||
return args, types_only, is_variadic
|
||||
}
|
||||
|
||||
fn (mut p Parser) go_expr() ast.GoExpr {
|
||||
p.next()
|
||||
spos := p.tok.pos()
|
||||
expr := p.expr(0)
|
||||
call_expr := if expr is ast.CallExpr {
|
||||
expr
|
||||
} else {
|
||||
p.error_with_pos('expression in `go` must be a function call', expr.pos())
|
||||
ast.CallExpr{
|
||||
scope: p.scope
|
||||
}
|
||||
}
|
||||
pos := spos.extend(p.prev_tok.pos())
|
||||
p.register_auto_import('sync.threads')
|
||||
p.table.gostmts++
|
||||
return ast.GoExpr{
|
||||
call_expr: call_expr
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) closure_vars() []ast.Param {
|
||||
p.check(.lsbr)
|
||||
mut vars := []ast.Param{cap: 5}
|
||||
|
Loading…
Reference in New Issue
Block a user