sync: allow `go` routine join with return value (#8125)
parent
995f27a7c0
commit
8d014d4646
|
@ -11,10 +11,10 @@ pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
|
|||
|
||||
pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral |
|
||||
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ComptimeSelector |
|
||||
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
|
||||
ConcatExpr | EnumVal | FloatLiteral | GoExpr | 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
|
||||
|
||||
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt |
|
||||
EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
|
||||
|
@ -875,8 +875,18 @@ pub:
|
|||
|
||||
pub struct GoStmt {
|
||||
pub:
|
||||
call_expr Expr
|
||||
pos token.Position
|
||||
pub mut:
|
||||
call_expr CallExpr
|
||||
}
|
||||
|
||||
pub struct GoExpr {
|
||||
pub:
|
||||
pos token.Position
|
||||
pub mut:
|
||||
go_stmt GoStmt
|
||||
mut:
|
||||
return_type table.Type
|
||||
}
|
||||
|
||||
pub struct GotoLabel {
|
||||
|
@ -1172,7 +1182,7 @@ pub fn (expr Expr) position() token.Position {
|
|||
AnonFn {
|
||||
return expr.decl.pos
|
||||
}
|
||||
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, GoExpr, 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 {
|
||||
|
@ -1261,7 +1271,7 @@ pub fn (stmt Stmt) position() token.Position {
|
|||
return stmt.pos
|
||||
}
|
||||
GoStmt {
|
||||
return stmt.call_expr.position()
|
||||
return stmt.call_expr.pos
|
||||
}
|
||||
TypeDecl {
|
||||
match stmt {
|
||||
|
|
|
@ -1338,6 +1338,12 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
|||
if !c.check_types(arg_type, info.elem_type) && !c.check_types(left_type, arg_type) {
|
||||
c.error('cannot $method_name `$arg_sym.name` to `$left_type_sym.name`', arg_expr.position())
|
||||
}
|
||||
} else if left_type_sym.kind == .gohandle && method_name == 'wait' {
|
||||
info := left_type_sym.info as table.GoHandle
|
||||
if call_expr.args.len > 0 {
|
||||
c.error('wait() does not have any arguments', call_expr.args[0].pos)
|
||||
}
|
||||
return info.return_type
|
||||
}
|
||||
mut method := table.Fn{}
|
||||
mut has_method := false
|
||||
|
@ -2978,11 +2984,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
}
|
||||
}
|
||||
ast.GoStmt {
|
||||
if node.call_expr !is ast.CallExpr {
|
||||
c.error('expression in `go` must be a function call', node.call_expr.position())
|
||||
}
|
||||
c.expr(node.call_expr)
|
||||
if mut node.call_expr is ast.CallExpr {
|
||||
c.call_expr(mut node.call_expr)
|
||||
// Make sure there are no mutable arguments
|
||||
for arg in node.call_expr.args {
|
||||
if arg.is_mut && !arg.typ.is_ptr() {
|
||||
|
@ -2995,7 +2997,6 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
node.call_expr.left.position())
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.GotoLabel {}
|
||||
ast.GotoStmt {
|
||||
// TODO: check label doesn't bypass variable declarations
|
||||
|
@ -3241,6 +3242,10 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
ast.CallExpr {
|
||||
return c.call_expr(mut node)
|
||||
}
|
||||
ast.GoExpr {
|
||||
ret_type := c.call_expr(mut node.go_stmt.call_expr)
|
||||
return c.table.find_or_register_gohandle(ret_type)
|
||||
}
|
||||
ast.ChanInit {
|
||||
return c.chan_init(mut node)
|
||||
}
|
||||
|
|
|
@ -892,6 +892,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
|||
ast.FloatLiteral {
|
||||
f.write(node.val)
|
||||
}
|
||||
ast.GoExpr {
|
||||
f.stmt(node.go_stmt)
|
||||
}
|
||||
ast.IfExpr {
|
||||
f.if_expr(node)
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ mut:
|
|||
defer_profile_code string
|
||||
str_types []string // types that need automatic str() generation
|
||||
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
|
||||
waiter_fns []string // functions that wait for `go xxx()` to finish
|
||||
array_fn_definitions []string // array equality functions that have been defined
|
||||
map_fn_definitions []string // map equality functions that have been defined
|
||||
struct_fn_definitions []string // struct equality functions that have been defined
|
||||
|
@ -1107,7 +1108,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
g.global_decl(node)
|
||||
}
|
||||
ast.GoStmt {
|
||||
g.go_stmt(node)
|
||||
g.go_stmt(node, false)
|
||||
}
|
||||
ast.GotoLabel {
|
||||
g.writeln('$node.name: {}')
|
||||
|
@ -2577,6 +2578,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
ast.FloatLiteral {
|
||||
g.write(node.val)
|
||||
}
|
||||
ast.GoExpr {
|
||||
g.go_expr(node)
|
||||
}
|
||||
ast.Ident {
|
||||
g.ident(node)
|
||||
}
|
||||
|
@ -4883,6 +4887,22 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
|
|||
table.Alias {
|
||||
// table.Alias { TODO
|
||||
}
|
||||
table.GoHandle {
|
||||
if g.pref.os == .windows {
|
||||
if name == 'gohandle_void' {
|
||||
g.type_definitions.writeln('typedef HANDLE $name;')
|
||||
} else {
|
||||
// Windows can only return `u32` (no void*) from a thread, so the
|
||||
// V gohandle must maintain a pointer to the return value
|
||||
g.type_definitions.writeln('typedef struct {')
|
||||
g.type_definitions.writeln('\tvoid* ret_ptr;')
|
||||
g.type_definitions.writeln('\tHANDLE handle;')
|
||||
g.type_definitions.writeln('} $name;')
|
||||
}
|
||||
} else {
|
||||
g.type_definitions.writeln('typedef pthread_t $name;')
|
||||
}
|
||||
}
|
||||
table.SumType {
|
||||
g.typedefs.writeln('typedef struct $name $name;')
|
||||
g.type_definitions.writeln('')
|
||||
|
@ -5414,9 +5434,18 @@ fn (g &Gen) is_importing_os() bool {
|
|||
return 'os' in g.table.imports
|
||||
}
|
||||
|
||||
fn (mut g Gen) go_stmt(node ast.GoStmt) {
|
||||
fn (mut g Gen) go_expr(node ast.GoExpr) {
|
||||
line := g.go_before_stmt(0)
|
||||
handle := g.go_stmt(node.go_stmt, true)
|
||||
g.empty_line = false
|
||||
g.write(line)
|
||||
g.write(handle)
|
||||
}
|
||||
|
||||
fn (mut g Gen) go_stmt(node ast.GoStmt, joinable bool) string {
|
||||
mut handle := ''
|
||||
tmp := g.new_tmp_var()
|
||||
expr := node.call_expr as ast.CallExpr
|
||||
expr := node.call_expr
|
||||
mut name := expr.name // util.no_dots(expr.name)
|
||||
// TODO: fn call is duplicated. merge with fn_call().
|
||||
if expr.generic_type != table.void_type && expr.generic_type != 0 {
|
||||
|
@ -5454,23 +5483,87 @@ fn (mut g Gen) go_stmt(node ast.GoStmt) {
|
|||
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 != table.void_type {
|
||||
g.writeln('$arg_tmp_var->ret_ptr = malloc(sizeof($s_ret_typ));')
|
||||
}
|
||||
gohandle_name := 'gohandle_' +
|
||||
g.table.get_type_symbol(g.unwrap_generic(node.call_expr.return_type)).name
|
||||
if g.pref.os == .windows {
|
||||
g.writeln('CreateThread(0,0, (LPTHREAD_START_ROUTINE)$wrapper_fn_name, $arg_tmp_var, 0,0);')
|
||||
simple_handle := if joinable && node.call_expr.return_type != table.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);')
|
||||
if joinable && node.call_expr.return_type != table.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 !joinable {
|
||||
g.writeln('CloseHandle(thread_$tmp);')
|
||||
}
|
||||
} else {
|
||||
g.writeln('pthread_t thread_$tmp;')
|
||||
g.writeln('pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);')
|
||||
if !joinable {
|
||||
g.writeln('pthread_detach(thread_$tmp);')
|
||||
}
|
||||
}
|
||||
g.writeln('// endgo\n')
|
||||
if joinable {
|
||||
handle = 'thread_$tmp'
|
||||
// create wait handler for this return type if none exists
|
||||
waiter_fn_name := gohandle_name + '_wait'
|
||||
if waiter_fn_name !in g.waiter_fns {
|
||||
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 != table.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 == table.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, $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 == table.void_type {
|
||||
g.gowrappers.writeln('\tCloseHandle(thread);')
|
||||
} else {
|
||||
g.gowrappers.writeln('\tCloseHandle(thread.handle);')
|
||||
}
|
||||
}
|
||||
if node.call_expr.return_type != table.void_type {
|
||||
g.gowrappers.writeln('\t$s_ret_typ ret = *ret_ptr;')
|
||||
g.gowrappers.writeln('\tfree(ret_ptr);')
|
||||
g.gowrappers.writeln('\treturn ret;')
|
||||
} else {
|
||||
g.gowrappers.writeln('\treturn;')
|
||||
}
|
||||
g.gowrappers.writeln('}')
|
||||
g.waiter_fns << waiter_fn_name
|
||||
}
|
||||
}
|
||||
// Register the wrapper type and function
|
||||
if name in g.threaded_fns {
|
||||
return
|
||||
return handle
|
||||
}
|
||||
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;')
|
||||
}
|
||||
if expr.args.len == 0 {
|
||||
need_return_ptr := g.pref.os == .windows && node.call_expr.return_type != table.void_type
|
||||
if expr.args.len == 0 && !need_return_ptr {
|
||||
g.type_definitions.writeln('EMPTY_STRUCT_DECLARATION;')
|
||||
} else {
|
||||
for i, arg in expr.args {
|
||||
|
@ -5478,10 +5571,24 @@ fn (mut g Gen) go_stmt(node ast.GoStmt) {
|
|||
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;')
|
||||
g.type_definitions.writeln('void* ${wrapper_fn_name}($wrapper_struct_name *arg);')
|
||||
g.gowrappers.writeln('void* ${wrapper_fn_name}($wrapper_struct_name *arg) {')
|
||||
g.gowrappers.write('\t${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 != table.void_type {
|
||||
if g.pref.os == .windows {
|
||||
g.gowrappers.write('\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('\t*ret_ptr = ')
|
||||
}
|
||||
} else {
|
||||
g.gowrappers.write('\t')
|
||||
}
|
||||
g.gowrappers.write('${name}(')
|
||||
if expr.is_method {
|
||||
g.gowrappers.write('arg->arg0')
|
||||
if expr.args.len > 0 {
|
||||
|
@ -5495,9 +5602,15 @@ fn (mut g Gen) go_stmt(node ast.GoStmt) {
|
|||
}
|
||||
}
|
||||
g.gowrappers.writeln(');')
|
||||
g.gowrappers.writeln('\tfree(arg);')
|
||||
if g.pref.os != .windows && node.call_expr.return_type != table.void_type {
|
||||
g.gowrappers.writeln('\treturn ret_ptr;')
|
||||
} else {
|
||||
g.gowrappers.writeln('\treturn 0;')
|
||||
}
|
||||
g.gowrappers.writeln('}')
|
||||
g.threaded_fns << name
|
||||
return handle
|
||||
}
|
||||
|
||||
fn (mut g Gen) as_cast(node ast.AsCast) {
|
||||
|
|
|
@ -165,6 +165,9 @@ pub fn (mut g JsGen) typ(t table.Type) string {
|
|||
.aggregate {
|
||||
panic('TODO: unhandled aggregate in JS')
|
||||
}
|
||||
.gohandle {
|
||||
panic('TODO: unhandled gohandle in JS')
|
||||
}
|
||||
}
|
||||
/*
|
||||
else {
|
||||
|
|
|
@ -475,6 +475,9 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||
ast.FloatLiteral {
|
||||
g.write('${g.typ(table.Type(table.f32_type))}($node.val)')
|
||||
}
|
||||
ast.GoExpr {
|
||||
// TODO
|
||||
}
|
||||
ast.Ident {
|
||||
g.gen_ident(node)
|
||||
}
|
||||
|
@ -923,8 +926,6 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
|
|||
|
||||
fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
|
||||
// x := node.call_expr as ast.CallEpxr // TODO
|
||||
match node.call_expr {
|
||||
ast.CallExpr {
|
||||
mut name := node.call_expr.name
|
||||
if node.call_expr.is_method {
|
||||
receiver_sym := g.table.get_type_symbol(node.call_expr.receiver_type)
|
||||
|
@ -947,9 +948,6 @@ fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
|
|||
g.writeln('resolve();')
|
||||
g.dec_indent()
|
||||
g.writeln('});')
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g JsGen) gen_import_stmt(it ast.Import) {
|
||||
|
|
|
@ -90,7 +90,39 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
|
|||
op := p.tok.kind
|
||||
pos := p.tok.position()
|
||||
p.next()
|
||||
right, right_comments := p.expr_list()
|
||||
mut right_comments := []ast.Comment{}
|
||||
mut right := []ast.Expr{cap: left.len}
|
||||
if p.tok.kind == .key_go {
|
||||
spos := p.tok.position()
|
||||
p.next()
|
||||
right_comments = p.eat_comments()
|
||||
mut mod := ''
|
||||
mut language := table.Language.v
|
||||
if p.peek_tok.kind == .dot {
|
||||
if p.tok.lit == 'C' {
|
||||
language = table.Language.c
|
||||
p.check_for_impure_v(language, p.tok.position())
|
||||
} else if p.tok.lit == 'JS' {
|
||||
language = table.Language.js
|
||||
p.check_for_impure_v(language, p.tok.position())
|
||||
} else {
|
||||
mod = p.tok.lit
|
||||
}
|
||||
p.next()
|
||||
p.next()
|
||||
}
|
||||
call_expr := p.call_expr(language, mod)
|
||||
allpos := spos.extend(p.tok.position())
|
||||
right << ast.GoExpr{
|
||||
go_stmt: ast.GoStmt{
|
||||
call_expr: call_expr
|
||||
pos: allpos
|
||||
}
|
||||
pos: allpos
|
||||
}
|
||||
} else {
|
||||
right, right_comments = p.expr_list()
|
||||
}
|
||||
mut comments := []ast.Comment{cap: left_comments.len + right_comments.len}
|
||||
comments << left_comments
|
||||
comments << right_comments
|
||||
|
|
|
@ -738,10 +738,16 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
|||
p.next()
|
||||
spos := p.tok.position()
|
||||
expr := p.expr(0)
|
||||
// mut call_expr := &ast.CallExpr(0) // TODO
|
||||
// { call_expr = it }
|
||||
call_expr := if expr is ast.CallExpr {
|
||||
expr
|
||||
} else {
|
||||
p.error_with_pos('expression in `go` must be a function call', expr.position())
|
||||
ast.CallExpr{
|
||||
scope: p.scope
|
||||
}
|
||||
}
|
||||
return ast.GoStmt{
|
||||
call_expr: expr
|
||||
call_expr: call_expr
|
||||
pos: spos.extend(p.tok.position())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -454,6 +454,20 @@ pub fn (t &Table) chan_cname(elem_type Type, is_mut bool) string {
|
|||
return 'chan_$elem_type_sym.cname' + suffix
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &Table) gohandle_name(return_type Type) string {
|
||||
return_type_sym := t.get_type_symbol(return_type)
|
||||
ptr := if return_type.is_ptr() { '&' } else { '' }
|
||||
return 'gohandle[$ptr$return_type_sym.name]'
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &Table) gohandle_cname(return_type Type) string {
|
||||
return_type_sym := t.get_type_symbol(return_type)
|
||||
suffix := if return_type.is_ptr() { '_ptr' } else { '' }
|
||||
return 'gohandle_$return_type_sym.cname$suffix'
|
||||
}
|
||||
|
||||
// map_source_name generates the original name for the v source.
|
||||
// e. g. map[string]int
|
||||
[inline]
|
||||
|
@ -517,6 +531,27 @@ pub fn (mut t Table) find_or_register_map(key_type Type, value_type Type) int {
|
|||
return t.register_type_symbol(map_typ)
|
||||
}
|
||||
|
||||
pub fn (mut t Table) find_or_register_gohandle(return_type Type) int {
|
||||
name := t.gohandle_name(return_type)
|
||||
cname := t.gohandle_cname(return_type)
|
||||
// existing
|
||||
existing_idx := t.type_idxs[name]
|
||||
if existing_idx > 0 {
|
||||
return existing_idx
|
||||
}
|
||||
// register
|
||||
gohandle_typ := TypeSymbol{
|
||||
parent_idx: gohandle_type_idx
|
||||
kind: .gohandle
|
||||
name: name
|
||||
cname: cname
|
||||
info: GoHandle{
|
||||
return_type: return_type
|
||||
}
|
||||
}
|
||||
return t.register_type_symbol(gohandle_typ)
|
||||
}
|
||||
|
||||
pub fn (mut t Table) find_or_register_array(elem_type Type) int {
|
||||
name := t.array_name(elem_type)
|
||||
cname := t.array_cname(elem_type)
|
||||
|
|
|
@ -16,7 +16,7 @@ import strings
|
|||
pub type Type = int
|
||||
|
||||
pub type TypeInfo = Aggregate | Alias | Array | ArrayFixed | Chan | Enum | FnType | GenericStructInst |
|
||||
Interface | Map | MultiReturn | Struct | SumType
|
||||
GoHandle | Interface | Map | MultiReturn | Struct | SumType
|
||||
|
||||
pub enum Language {
|
||||
v
|
||||
|
@ -306,6 +306,7 @@ pub const (
|
|||
any_type_idx = 25
|
||||
float_literal_type_idx = 26
|
||||
int_literal_type_idx = 27
|
||||
gohandle_type_idx = 28
|
||||
)
|
||||
|
||||
pub const (
|
||||
|
@ -350,12 +351,15 @@ pub const (
|
|||
any_type = new_type(any_type_idx)
|
||||
float_literal_type = new_type(float_literal_type_idx)
|
||||
int_literal_type = new_type(int_literal_type_idx)
|
||||
gohandle_type = new_type(gohandle_type_idx)
|
||||
)
|
||||
|
||||
pub const (
|
||||
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16',
|
||||
'u32', 'u64', 'int_literal', 'f32', 'f64', 'float_literal', 'string', 'ustring', 'char', 'byte',
|
||||
'bool', 'none', 'array', 'array_fixed', 'map', 'chan', 'any', 'struct', 'mapnode', 'size_t', 'rune']
|
||||
'bool', 'none', 'array', 'array_fixed', 'map', 'chan', 'any', 'struct', 'mapnode', 'size_t', 'rune',
|
||||
'gohandle',
|
||||
]
|
||||
)
|
||||
|
||||
pub struct MultiReturn {
|
||||
|
@ -417,6 +421,7 @@ pub enum Kind {
|
|||
float_literal
|
||||
int_literal
|
||||
aggregate
|
||||
gohandle
|
||||
}
|
||||
|
||||
pub fn (t &TypeSymbol) str() string {
|
||||
|
@ -467,6 +472,14 @@ pub fn (t &TypeSymbol) chan_info() Chan {
|
|||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &TypeSymbol) gohandle_info() GoHandle {
|
||||
match mut t.info {
|
||||
GoHandle { return t.info }
|
||||
else { panic('TypeSymbol.gohandle_info(): no gohandle info for type: $t.name') }
|
||||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &TypeSymbol) map_info() Map {
|
||||
match mut t.info {
|
||||
|
@ -529,6 +542,7 @@ pub fn (mut t Table) register_builtin_type_symbols() {
|
|||
cname: 'int_literal'
|
||||
mod: 'builtin'
|
||||
)
|
||||
t.register_type_symbol(kind: .gohandle, name: 'gohandle', cname: 'gohandle', mod: 'builtin')
|
||||
}
|
||||
|
||||
[inline]
|
||||
|
@ -602,6 +616,7 @@ pub fn (k Kind) str() string {
|
|||
.generic_struct_inst { 'generic_struct_inst' }
|
||||
.rune { 'rune' }
|
||||
.aggregate { 'aggregate' }
|
||||
.gohandle { 'gohandle' }
|
||||
}
|
||||
return k_str
|
||||
}
|
||||
|
@ -709,6 +724,11 @@ pub mut:
|
|||
is_mut bool
|
||||
}
|
||||
|
||||
pub struct GoHandle {
|
||||
pub mut:
|
||||
return_type Type
|
||||
}
|
||||
|
||||
pub struct Map {
|
||||
pub mut:
|
||||
key_type Type
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
fn f(x int, y f64) f64 {
|
||||
return x * y
|
||||
}
|
||||
|
||||
fn test_go_return() {
|
||||
r := go f(3, 4.0)
|
||||
z := r.wait()
|
||||
assert typeof(z).name == 'f64'
|
||||
assert z == 12.0
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import time
|
||||
|
||||
struct St {
|
||||
mut:
|
||||
x f64
|
||||
}
|
||||
|
||||
fn f(x int, y f64, shared s St) {
|
||||
time.usleep(50000)
|
||||
lock s {
|
||||
s.x = x * y
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fn test_go_return() {
|
||||
shared t := &St{}
|
||||
r := go f(3, 4.0, shared t)
|
||||
r.wait()
|
||||
rlock t {
|
||||
assert t.x == 12.0
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue