all: merge GoExpr and GoStmt (#9685)

pull/9700/head
Enzo 2021-04-11 23:56:25 +02:00 committed by GitHub
parent 6cfd53bf57
commit 5a1a1b7c12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 112 additions and 137 deletions

View File

@ -19,8 +19,8 @@ pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr |
pub type Stmt = AsmStmt | AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl |
DeferStmt | EmptyStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt |
GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module |
NodeError | Return | SqlStmt | StructDecl | TypeDecl
GlobalDecl | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | NodeError |
Return | SqlStmt | StructDecl | TypeDecl
// NB: when you add a new Expr or Stmt type with a .pos field, remember to update
// the .position() token.Position methods too.
@ -963,20 +963,12 @@ pub:
pos token.Position
}
pub struct GoStmt {
pub:
pos token.Position
pub mut:
call_expr CallExpr
}
pub struct GoExpr {
pub:
pos token.Position
pub mut:
go_stmt GoStmt
mut:
return_type Type
call_expr CallExpr
is_expr bool
}
pub struct GotoLabel {

View File

@ -3539,13 +3539,6 @@ fn (mut c Checker) stmt(node ast.Stmt) {
ast.GlobalDecl {
c.global_decl(node)
}
ast.GoStmt {
c.go_stmt(mut node)
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)
}
}
ast.GotoLabel {}
ast.GotoStmt {
if !c.inside_unsafe {
@ -3779,8 +3772,12 @@ fn (mut c Checker) global_decl(node ast.GlobalDecl) {
}
}
fn (mut c Checker) go_stmt(mut node ast.GoStmt) {
c.call_expr(mut node.call_expr)
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() {
@ -3793,6 +3790,7 @@ fn (mut c Checker) go_stmt(mut node ast.GoStmt) {
c.error('method in `go` statement cannot have non-reference mutable receiver',
node.call_expr.left.position())
}
return c.table.find_or_register_thread(ret_type)
}
fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {
@ -4156,14 +4154,6 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
}
return ret_type
}
ast.GoExpr {
mut ret_type := c.call_expr(mut node.go_stmt.call_expr)
if node.go_stmt.call_expr.or_block.kind != .absent {
c.error('optional handling cannot be done in `go` call. Do it when calling `.wait()`',
node.go_stmt.call_expr.or_block.pos)
}
return c.table.find_or_register_thread(ret_type)
}
ast.ChanInit {
return c.chan_init(mut node)
}
@ -4226,6 +4216,9 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
ast.FloatLiteral {
return ast.float_literal_type
}
ast.GoExpr {
return c.go_expr(mut node)
}
ast.Ident {
// c.checked_ident = node.name
res := c.ident(mut node)

View File

@ -428,9 +428,6 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
ast.GlobalDecl {
f.global_decl(node)
}
ast.GoStmt {
f.go_stmt(node, false)
}
ast.GotoLabel {
f.goto_label(node)
}
@ -541,7 +538,7 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
f.write(node.val)
}
ast.GoExpr {
f.go_stmt(node.go_stmt, true)
f.go_expr(node)
}
ast.Ident {
f.ident(node)
@ -1130,12 +1127,9 @@ pub fn (mut f Fmt) global_decl(node ast.GlobalDecl) {
f.writeln(')\n')
}
pub fn (mut f Fmt) go_stmt(node ast.GoStmt, is_expr bool) {
pub fn (mut f Fmt) go_expr(node ast.GoExpr) {
f.write('go ')
f.expr(node.call_expr)
if !is_expr {
f.writeln('')
}
}
pub fn (mut f Fmt) goto_label(node ast.GotoLabel) {

View File

@ -1183,9 +1183,6 @@ fn (mut g Gen) stmt(node ast.Stmt) {
ast.GlobalDecl {
g.global_decl(node)
}
ast.GoStmt {
g.go_stmt(node, false)
}
ast.GotoLabel {
g.writeln('$node.name: {}')
}
@ -5890,13 +5887,6 @@ fn (g &Gen) is_importing_os() bool {
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()
mut expr := node.call_expr
@ -5966,30 +5956,30 @@ fn (mut g Gen) go_stmt(node ast.GoStmt, joinable bool) string {
gohandle_name = '__v_thread_$opt${g.table.get_type_symbol(g.unwrap_generic(node.call_expr.return_type)).cname}'
}
if g.pref.os == .windows {
simple_handle := if joinable && node.call_expr.return_type != ast.void_type {
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);')
if joinable && node.call_expr.return_type != ast.void_type {
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 !joinable {
if !node.is_expr {
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 {
if !node.is_expr {
g.writeln('pthread_detach(thread_$tmp);')
}
}
g.writeln('// endgo\n')
if joinable {
if node.is_expr {
handle = 'thread_$tmp'
// create wait handler for this return type if none exists
waiter_fn_name := gohandle_name + '_wait'
@ -6030,63 +6020,66 @@ fn (mut g Gen) go_stmt(node ast.GoStmt, joinable bool) string {
}
}
// Register the wrapper type and function
if name in g.threaded_fns {
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;')
}
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 name !in g.threaded_fns {
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 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)) = ')
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 {
g.gowrappers.writeln('\t$s_ret_typ* ret_ptr = malloc(sizeof($s_ret_typ));')
g.gowrappers.write_string('\t*ret_ptr = ')
for i, arg in expr.args {
styp := g.typ(arg.typ)
g.type_definitions.writeln('\t$styp arg${i + 1};')
}
}
} else {
g.gowrappers.write_string('\t')
}
g.gowrappers.write_string('${name}(')
if expr.is_method {
g.gowrappers.write_string('arg->arg0')
if expr.args.len > 0 {
g.gowrappers.write_string(', ')
if need_return_ptr {
g.type_definitions.writeln('\tvoid* ret_ptr;')
}
}
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.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')
}
g.gowrappers.write_string('${name}(')
if expr.is_method {
g.gowrappers.write_string('arg->arg0')
if expr.args.len > 0 {
g.gowrappers.write_string(', ')
}
}
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('}')
g.threaded_fns << name
}
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;')
if node.is_expr {
g.empty_line = false
g.write(line)
g.write(handle)
}
g.gowrappers.writeln('}')
g.threaded_fns << name
return handle
}
fn (mut g Gen) as_cast(node ast.AsCast) {

View File

@ -405,10 +405,6 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
ast.GlobalDecl {
// TODO
}
ast.GoStmt {
g.gen_go_stmt(node)
g.writeln('')
}
ast.GotoLabel {
g.writeln('${g.js_name(node.name)}:')
}
@ -499,7 +495,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
g.gen_float_literal_expr(node)
}
ast.GoExpr {
// TODO
g.gen_go_expr(node)
}
ast.Ident {
g.gen_ident(node)
@ -800,11 +796,14 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) {
g.gen_method_decl(it)
}
fn fn_has_go(it ast.FnDecl) bool {
fn fn_has_go(node ast.FnDecl) bool {
mut has_go := false
for stmt in it.stmts {
if stmt is ast.GoStmt {
has_go = true
for stmt in node.stmts {
if stmt is ast.ExprStmt {
if stmt.expr is ast.GoExpr {
has_go = true
break
}
}
}
return has_go
@ -989,8 +988,9 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
g.writeln('}')
}
fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
// x := node.call_expr as ast.CallEpxr // TODO
fn (mut g JsGen) gen_go_expr(node ast.GoExpr) {
// TODO Handle joinable expressions
// node.is_expr
mut name := node.call_expr.name
if node.call_expr.is_method {
receiver_sym := g.table.get_type_symbol(node.call_expr.receiver_type)

View File

@ -90,9 +90,6 @@ pub fn (mut w Walker) stmt(node ast.Stmt) {
w.expr(node.cond)
w.stmts(node.stmts)
}
ast.GoStmt {
w.expr(node.call_expr)
}
ast.Return {
w.exprs(node.exprs)
}
@ -201,7 +198,7 @@ fn (mut w Walker) expr(node ast.Expr) {
w.fn_by_name('eprintln')
}
ast.GoExpr {
w.expr(node.go_stmt.call_expr)
w.expr(node.call_expr)
}
ast.IndexExpr {
w.expr(node.left)

View File

@ -801,20 +801,10 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
}
}
.key_go {
p.next()
spos := p.tok.position()
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.position())
ast.CallExpr{
scope: p.scope
}
}
return ast.GoStmt{
call_expr: call_expr
pos: spos.extend(p.prev_tok.position())
go_expr := p.go_expr()
return ast.ExprStmt{
expr: go_expr
pos: go_expr.pos
}
}
.key_goto {

View File

@ -92,12 +92,9 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
}
}
.key_go {
stmt := p.stmt(false)
go_stmt := stmt as ast.GoStmt
node = ast.GoExpr{
go_stmt: go_stmt
pos: go_stmt.pos
}
mut go_expr := p.go_expr()
go_expr.is_expr = true
node = go_expr
}
.key_true, .key_false {
node = ast.BoolLiteral{
@ -490,6 +487,25 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
}
}
fn (mut p Parser) go_expr() ast.GoExpr {
p.next()
spos := p.tok.position()
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.position())
ast.CallExpr{
scope: p.scope
}
}
pos := spos.extend(p.prev_tok.position())
return ast.GoExpr{
call_expr: call_expr
pos: pos
}
}
fn (p &Parser) fileis(s string) bool {
return p.file_name.contains(s)
}