From 52f096f5d93369c079281e598a20d0d39bf85271 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 3 Apr 2020 15:18:17 +0200 Subject: [PATCH] cgen: `go xxx()` --- vlib/v/ast/ast.v | 4 +-- vlib/v/checker/checker.v | 11 +++--- vlib/v/gen/cgen.v | 75 +++++++++++++++++++++++++++++++++++++--- vlib/v/parser/parser.v | 12 ++++++- 4 files changed, 90 insertions(+), 12 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 0b89c3f97f..06bb4d26af 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -187,7 +187,7 @@ pub: mut: name string args []CallArg - exp_arg_types []table.Type + expected_arg_types []table.Type is_c bool or_block OrExpr // has_or_block bool @@ -546,7 +546,7 @@ mut: pub struct GoStmt { pub: - expr Expr + call_expr Expr } pub struct GotoLabel { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b2d21674fb..c0dde923ae 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -238,9 +238,9 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { call_expr.args[i].typ = c.expr(arg.expr) } // TODO: typ optimize.. this node can get processed more than once - if call_expr.exp_arg_types.len == 0 { + if call_expr.expected_arg_types.len == 0 { for i in 1 .. method.args.len { - call_expr.exp_arg_types << method.args[i].typ + call_expr.expected_arg_types << method.args[i].typ } } call_expr.receiver_type = method.args[0].typ @@ -337,9 +337,9 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { return f.return_type } // TODO: typ optimize.. this node can get processed more than once - if call_expr.exp_arg_types.len == 0 { + if call_expr.expected_arg_types.len == 0 { for arg in f.args { - call_expr.exp_arg_types << arg.typ + call_expr.expected_arg_types << arg.typ } } for i, call_arg in call_expr.args { @@ -694,6 +694,9 @@ fn (c mut Checker) stmt(node ast.Stmt) { } c.stmts(it.stmts) } + ast.GoStmt{ + c.expr(it.call_expr) + } // ast.GlobalDecl {} // ast.HashStmt {} ast.Import {} diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index f680c4e7f1..eddef7814e 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -49,6 +49,7 @@ mut: defer_stmts []ast.DeferStmt defer_ifdef string str_types []int // types that need automatic str() generation + threaded_fns []string // for generating unique wrapper types and fns for `go xxx()` } const ( @@ -392,8 +393,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.definitions.writeln('$styp $it.name; // global') } ast.GoStmt { - g.writeln('// go') - g.expr(it.expr) + g.go_stmt(it) } ast.GotoLabel { g.writeln('$it.name:') @@ -2369,7 +2369,8 @@ fn (g mut Gen) method_call(node ast.CallExpr) { g.write('/*rec*/*') } g.expr(node.left) - is_variadic := node.exp_arg_types.len > 0 && table.type_is_variadic(node.exp_arg_types[node.exp_arg_types.len - 1]) + is_variadic := node.expected_arg_types.len > 0 && + table.type_is_variadic(node.expected_arg_types[node.expected_arg_types.len - 1]) if node.args.len > 0 || is_variadic { g.write(', ') } @@ -2385,7 +2386,7 @@ fn (g mut Gen) method_call(node ast.CallExpr) { } */ // /////// - g.call_args(node.args, node.exp_arg_types) + g.call_args(node.args, node.expected_arg_types) g.write(')') // if node.or_block.stmts.len > 0 { // g.or_block(node.or_block.stmts, node.return_type) @@ -2461,7 +2462,7 @@ fn (g mut Gen) fn_call(node ast.CallExpr) { } else { g.write('${name}(') - g.call_args(node.args, node.exp_arg_types) + g.call_args(node.args, node.expected_arg_types) g.write(')') } // if node.or_block.stmts.len > 0 { @@ -2802,3 +2803,67 @@ fn (g mut Gen) comp_if(it ast.CompIf) { } g.writeln('#endif') } + +fn (g mut Gen) go_stmt(node ast.GoStmt) { + tmp := g.new_tmp_var() + // x := node.call_expr as ast.CallEpxr // TODO + match node.call_expr { + ast.CallExpr{ + mut name := it.name + if it.is_method { + receiver_sym := g.table.get_type_symbol(it.receiver_type) + name = receiver_sym.name + '_' + name + } + g.writeln('// go') + wrapper_struct_name := 'thread_arg_' + name + g.writeln('$wrapper_struct_name *arg_$tmp = malloc(sizeof(thread_arg_$name));') + if it.is_method { + g.write('arg_${tmp}->arg0 = ') + g.expr(it.left) + g.writeln(';') + } + for i, arg in it.args { + g.write('arg_${tmp}->arg${i+1} = ') + g.expr(arg.expr) + g.writeln(';') + } + g.writeln('pthread_t thread_$tmp;') + wrapper_fn_name := name + '_thread_wrapper' + g.writeln('pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, arg_$tmp);') + g.writeln('// endgo\n') + // Register the wrapper type and function + if name in g.threaded_fns { + return + } + g.definitions.writeln('\ntypedef struct $wrapper_struct_name {') + if it.is_method { + sym := g.table.get_type_symbol(it.receiver_type) + g.definitions.writeln('\t$sym.name arg0;') + } + for i, arg in it.args { + sym := g.table.get_type_symbol(arg.typ) + g.definitions.writeln('\t$sym.name arg${i+1};') + } + g.definitions.writeln('} $wrapper_struct_name;') + g.definitions.writeln('void* ${wrapper_fn_name}($wrapper_struct_name *arg) {') + g.definitions.write(name + '(') + if it.is_method { + g.definitions.write('arg->arg0') + if it.args.len > 0 { + g.definitions.write(', ') + } + } + for i in 0..it.args.len { + g.definitions.write('arg->arg${i+1}') + if i < it.args.len - 1 { + g.definitions.write(', ') + } + } + + g.definitions.writeln(');\n return 0; }') + g.threaded_fns << name + } + else{} + } +} + diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index b533d8f327..baf11d29f5 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -399,8 +399,18 @@ pub fn (p mut Parser) stmt() ast.Stmt { } .key_go { p.next() + expr := p.expr(0) + //mut call_expr := &ast.CallExpr(0) // TODO + match expr { + ast.CallExpr { + //call_expr = it + } + else { + p.error('expression in `go` must be a function call') + } + } return ast.GoStmt{ - expr: p.expr(0) + call_expr: expr } } .key_goto {