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 |
|
pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral |
|
||||||
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ComptimeSelector |
|
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ComptimeSelector |
|
||||||
ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr |
|
ConcatExpr | EnumVal | FloatLiteral | GoExpr | Ident | IfExpr | IfGuardExpr | IndexExpr |
|
||||||
IntegerLiteral | Likely | LockExpr | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr |
|
InfixExpr | IntegerLiteral | Likely | LockExpr | MapInit | MatchExpr | None | OrExpr |
|
||||||
PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral |
|
ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf |
|
||||||
StringLiteral | StructInit | Type | TypeOf | UnsafeExpr
|
SqlExpr | StringInterLiteral | StringLiteral | StructInit | Type | TypeOf | UnsafeExpr
|
||||||
|
|
||||||
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt |
|
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt |
|
||||||
EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
|
EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
|
||||||
|
@ -875,8 +875,18 @@ pub:
|
||||||
|
|
||||||
pub struct GoStmt {
|
pub struct GoStmt {
|
||||||
pub:
|
pub:
|
||||||
call_expr Expr
|
|
||||||
pos token.Position
|
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 {
|
pub struct GotoLabel {
|
||||||
|
@ -1172,7 +1182,7 @@ pub fn (expr Expr) position() token.Position {
|
||||||
AnonFn {
|
AnonFn {
|
||||||
return expr.decl.pos
|
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
|
return expr.pos
|
||||||
}
|
}
|
||||||
ArrayDecompose {
|
ArrayDecompose {
|
||||||
|
@ -1261,7 +1271,7 @@ pub fn (stmt Stmt) position() token.Position {
|
||||||
return stmt.pos
|
return stmt.pos
|
||||||
}
|
}
|
||||||
GoStmt {
|
GoStmt {
|
||||||
return stmt.call_expr.position()
|
return stmt.call_expr.pos
|
||||||
}
|
}
|
||||||
TypeDecl {
|
TypeDecl {
|
||||||
match stmt {
|
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) {
|
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())
|
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 method := table.Fn{}
|
||||||
mut has_method := false
|
mut has_method := false
|
||||||
|
@ -2978,11 +2984,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.GoStmt {
|
ast.GoStmt {
|
||||||
if node.call_expr !is ast.CallExpr {
|
c.call_expr(mut node.call_expr)
|
||||||
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 {
|
|
||||||
// Make sure there are no mutable arguments
|
// Make sure there are no mutable arguments
|
||||||
for arg in node.call_expr.args {
|
for arg in node.call_expr.args {
|
||||||
if arg.is_mut && !arg.typ.is_ptr() {
|
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())
|
node.call_expr.left.position())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ast.GotoLabel {}
|
ast.GotoLabel {}
|
||||||
ast.GotoStmt {
|
ast.GotoStmt {
|
||||||
// TODO: check label doesn't bypass variable declarations
|
// 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 {
|
ast.CallExpr {
|
||||||
return c.call_expr(mut node)
|
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 {
|
ast.ChanInit {
|
||||||
return c.chan_init(mut node)
|
return c.chan_init(mut node)
|
||||||
}
|
}
|
||||||
|
|
|
@ -892,6 +892,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
||||||
ast.FloatLiteral {
|
ast.FloatLiteral {
|
||||||
f.write(node.val)
|
f.write(node.val)
|
||||||
}
|
}
|
||||||
|
ast.GoExpr {
|
||||||
|
f.stmt(node.go_stmt)
|
||||||
|
}
|
||||||
ast.IfExpr {
|
ast.IfExpr {
|
||||||
f.if_expr(node)
|
f.if_expr(node)
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ mut:
|
||||||
defer_profile_code string
|
defer_profile_code string
|
||||||
str_types []string // types that need automatic str() generation
|
str_types []string // types that need automatic str() generation
|
||||||
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
|
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
|
array_fn_definitions []string // array equality functions that have been defined
|
||||||
map_fn_definitions []string // map 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
|
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)
|
g.global_decl(node)
|
||||||
}
|
}
|
||||||
ast.GoStmt {
|
ast.GoStmt {
|
||||||
g.go_stmt(node)
|
g.go_stmt(node, false)
|
||||||
}
|
}
|
||||||
ast.GotoLabel {
|
ast.GotoLabel {
|
||||||
g.writeln('$node.name: {}')
|
g.writeln('$node.name: {}')
|
||||||
|
@ -2577,6 +2578,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
ast.FloatLiteral {
|
ast.FloatLiteral {
|
||||||
g.write(node.val)
|
g.write(node.val)
|
||||||
}
|
}
|
||||||
|
ast.GoExpr {
|
||||||
|
g.go_expr(node)
|
||||||
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
g.ident(node)
|
g.ident(node)
|
||||||
}
|
}
|
||||||
|
@ -4883,6 +4887,22 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
|
||||||
table.Alias {
|
table.Alias {
|
||||||
// table.Alias { TODO
|
// 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 {
|
table.SumType {
|
||||||
g.typedefs.writeln('typedef struct $name $name;')
|
g.typedefs.writeln('typedef struct $name $name;')
|
||||||
g.type_definitions.writeln('')
|
g.type_definitions.writeln('')
|
||||||
|
@ -5414,9 +5434,18 @@ fn (g &Gen) is_importing_os() bool {
|
||||||
return 'os' in g.table.imports
|
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()
|
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)
|
mut name := expr.name // util.no_dots(expr.name)
|
||||||
// TODO: fn call is duplicated. merge with fn_call().
|
// TODO: fn call is duplicated. merge with fn_call().
|
||||||
if expr.generic_type != table.void_type && expr.generic_type != 0 {
|
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.expr(arg.expr)
|
||||||
g.writeln(';')
|
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 {
|
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 {
|
} else {
|
||||||
g.writeln('pthread_t thread_$tmp;')
|
g.writeln('pthread_t thread_$tmp;')
|
||||||
g.writeln('pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);')
|
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')
|
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
|
// Register the wrapper type and function
|
||||||
if name in g.threaded_fns {
|
if name in g.threaded_fns {
|
||||||
return
|
return handle
|
||||||
}
|
}
|
||||||
g.type_definitions.writeln('\ntypedef struct $wrapper_struct_name {')
|
g.type_definitions.writeln('\ntypedef struct $wrapper_struct_name {')
|
||||||
if expr.is_method {
|
if expr.is_method {
|
||||||
styp := g.typ(expr.receiver_type)
|
styp := g.typ(expr.receiver_type)
|
||||||
g.type_definitions.writeln('\t$styp arg0;')
|
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;')
|
g.type_definitions.writeln('EMPTY_STRUCT_DECLARATION;')
|
||||||
} else {
|
} else {
|
||||||
for i, arg in expr.args {
|
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};')
|
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('} $wrapper_struct_name;')
|
||||||
g.type_definitions.writeln('void* ${wrapper_fn_name}($wrapper_struct_name *arg);')
|
thread_ret_type := if g.pref.os == .windows { 'u32' } else { 'void*' }
|
||||||
g.gowrappers.writeln('void* ${wrapper_fn_name}($wrapper_struct_name *arg) {')
|
g.type_definitions.writeln('$thread_ret_type ${wrapper_fn_name}($wrapper_struct_name *arg);')
|
||||||
g.gowrappers.write('\t${name}(')
|
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 {
|
if expr.is_method {
|
||||||
g.gowrappers.write('arg->arg0')
|
g.gowrappers.write('arg->arg0')
|
||||||
if expr.args.len > 0 {
|
if expr.args.len > 0 {
|
||||||
|
@ -5495,9 +5602,15 @@ fn (mut g Gen) go_stmt(node ast.GoStmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.gowrappers.writeln(');')
|
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('\treturn 0;')
|
||||||
|
}
|
||||||
g.gowrappers.writeln('}')
|
g.gowrappers.writeln('}')
|
||||||
g.threaded_fns << name
|
g.threaded_fns << name
|
||||||
|
return handle
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) as_cast(node ast.AsCast) {
|
fn (mut g Gen) as_cast(node ast.AsCast) {
|
||||||
|
|
|
@ -165,6 +165,9 @@ pub fn (mut g JsGen) typ(t table.Type) string {
|
||||||
.aggregate {
|
.aggregate {
|
||||||
panic('TODO: unhandled aggregate in JS')
|
panic('TODO: unhandled aggregate in JS')
|
||||||
}
|
}
|
||||||
|
.gohandle {
|
||||||
|
panic('TODO: unhandled gohandle in JS')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -475,6 +475,9 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
ast.FloatLiteral {
|
ast.FloatLiteral {
|
||||||
g.write('${g.typ(table.Type(table.f32_type))}($node.val)')
|
g.write('${g.typ(table.Type(table.f32_type))}($node.val)')
|
||||||
}
|
}
|
||||||
|
ast.GoExpr {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
g.gen_ident(node)
|
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) {
|
fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
|
||||||
// x := node.call_expr as ast.CallEpxr // TODO
|
// x := node.call_expr as ast.CallEpxr // TODO
|
||||||
match node.call_expr {
|
|
||||||
ast.CallExpr {
|
|
||||||
mut name := node.call_expr.name
|
mut name := node.call_expr.name
|
||||||
if node.call_expr.is_method {
|
if node.call_expr.is_method {
|
||||||
receiver_sym := g.table.get_type_symbol(node.call_expr.receiver_type)
|
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.writeln('resolve();')
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('});')
|
g.writeln('});')
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_import_stmt(it ast.Import) {
|
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
|
op := p.tok.kind
|
||||||
pos := p.tok.position()
|
pos := p.tok.position()
|
||||||
p.next()
|
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}
|
mut comments := []ast.Comment{cap: left_comments.len + right_comments.len}
|
||||||
comments << left_comments
|
comments << left_comments
|
||||||
comments << right_comments
|
comments << right_comments
|
||||||
|
|
|
@ -738,10 +738,16 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
||||||
p.next()
|
p.next()
|
||||||
spos := p.tok.position()
|
spos := p.tok.position()
|
||||||
expr := p.expr(0)
|
expr := p.expr(0)
|
||||||
// mut call_expr := &ast.CallExpr(0) // TODO
|
call_expr := if expr is ast.CallExpr {
|
||||||
// { call_expr = it }
|
expr
|
||||||
|
} else {
|
||||||
|
p.error_with_pos('expression in `go` must be a function call', expr.position())
|
||||||
|
ast.CallExpr{
|
||||||
|
scope: p.scope
|
||||||
|
}
|
||||||
|
}
|
||||||
return ast.GoStmt{
|
return ast.GoStmt{
|
||||||
call_expr: expr
|
call_expr: call_expr
|
||||||
pos: spos.extend(p.tok.position())
|
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
|
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.
|
// map_source_name generates the original name for the v source.
|
||||||
// e. g. map[string]int
|
// e. g. map[string]int
|
||||||
[inline]
|
[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)
|
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 {
|
pub fn (mut t Table) find_or_register_array(elem_type Type) int {
|
||||||
name := t.array_name(elem_type)
|
name := t.array_name(elem_type)
|
||||||
cname := t.array_cname(elem_type)
|
cname := t.array_cname(elem_type)
|
||||||
|
|
|
@ -16,7 +16,7 @@ import strings
|
||||||
pub type Type = int
|
pub type Type = int
|
||||||
|
|
||||||
pub type TypeInfo = Aggregate | Alias | Array | ArrayFixed | Chan | Enum | FnType | GenericStructInst |
|
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 {
|
pub enum Language {
|
||||||
v
|
v
|
||||||
|
@ -306,6 +306,7 @@ pub const (
|
||||||
any_type_idx = 25
|
any_type_idx = 25
|
||||||
float_literal_type_idx = 26
|
float_literal_type_idx = 26
|
||||||
int_literal_type_idx = 27
|
int_literal_type_idx = 27
|
||||||
|
gohandle_type_idx = 28
|
||||||
)
|
)
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
|
@ -350,12 +351,15 @@ pub const (
|
||||||
any_type = new_type(any_type_idx)
|
any_type = new_type(any_type_idx)
|
||||||
float_literal_type = new_type(float_literal_type_idx)
|
float_literal_type = new_type(float_literal_type_idx)
|
||||||
int_literal_type = new_type(int_literal_type_idx)
|
int_literal_type = new_type(int_literal_type_idx)
|
||||||
|
gohandle_type = new_type(gohandle_type_idx)
|
||||||
)
|
)
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16',
|
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16',
|
||||||
'u32', 'u64', 'int_literal', 'f32', 'f64', 'float_literal', 'string', 'ustring', 'char', 'byte',
|
'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 {
|
pub struct MultiReturn {
|
||||||
|
@ -417,6 +421,7 @@ pub enum Kind {
|
||||||
float_literal
|
float_literal
|
||||||
int_literal
|
int_literal
|
||||||
aggregate
|
aggregate
|
||||||
|
gohandle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (t &TypeSymbol) str() string {
|
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]
|
[inline]
|
||||||
pub fn (t &TypeSymbol) map_info() Map {
|
pub fn (t &TypeSymbol) map_info() Map {
|
||||||
match mut t.info {
|
match mut t.info {
|
||||||
|
@ -529,6 +542,7 @@ pub fn (mut t Table) register_builtin_type_symbols() {
|
||||||
cname: 'int_literal'
|
cname: 'int_literal'
|
||||||
mod: 'builtin'
|
mod: 'builtin'
|
||||||
)
|
)
|
||||||
|
t.register_type_symbol(kind: .gohandle, name: 'gohandle', cname: 'gohandle', mod: 'builtin')
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
|
@ -602,6 +616,7 @@ pub fn (k Kind) str() string {
|
||||||
.generic_struct_inst { 'generic_struct_inst' }
|
.generic_struct_inst { 'generic_struct_inst' }
|
||||||
.rune { 'rune' }
|
.rune { 'rune' }
|
||||||
.aggregate { 'aggregate' }
|
.aggregate { 'aggregate' }
|
||||||
|
.gohandle { 'gohandle' }
|
||||||
}
|
}
|
||||||
return k_str
|
return k_str
|
||||||
}
|
}
|
||||||
|
@ -709,6 +724,11 @@ pub mut:
|
||||||
is_mut bool
|
is_mut bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct GoHandle {
|
||||||
|
pub mut:
|
||||||
|
return_type Type
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
pub mut:
|
pub mut:
|
||||||
key_type Type
|
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