Skip to content

Commit

Permalink
all: coroutines (part 1)
Browse files Browse the repository at this point in the history
  • Loading branch information
medvednikov committed May 27, 2023
1 parent 5812579 commit 45f16a2
Show file tree
Hide file tree
Showing 18 changed files with 216 additions and 24 deletions.
12 changes: 12 additions & 0 deletions cmd/tools/vast/vast.v
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,9 @@ fn (t Tree) expr(expr ast.Expr) &Node {
ast.GoExpr {
return t.go_expr(expr)
}
ast.SpawnExpr {
return t.spawn_expr(expr)
}
ast.OffsetOf {
return t.offset_of(expr)
}
Expand Down Expand Up @@ -1862,6 +1865,15 @@ fn (t Tree) go_expr(expr ast.GoExpr) &Node {
return obj
}

fn (t Tree) spawn_expr(expr ast.SpawnExpr) &Node {
mut obj := new_object()
obj.add_terse('ast_type', t.string_node('SpawnExpr'))
obj.add_terse('call_expr', t.call_expr(expr.call_expr))
obj.add_terse('is_expr', t.bool_node(expr.is_expr))
obj.add('pos', t.pos(expr.pos))
return obj
}

fn (t Tree) offset_of(expr ast.OffsetOf) &Node {
mut obj := new_object()
obj.add_terse('ast_type', t.string_node('OffsetOf'))
Expand Down
44 changes: 44 additions & 0 deletions thirdparty/photon/photonwrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@



#ifndef C_PHOTONWRAPPER_H_
#define C_PHOTONWRAPPER_H_


#ifdef __cplusplus

#include <fcntl.h>
//#include <vector>

#include <photon/thread/std-compat.h>
#include <photon/common/alog.h>
#include <photon/common/iovector.h>
#include <photon/fs/localfs.h>
#include <photon/net/socket.h>

#include <iostream>

extern "C" {
#else
typedef struct CppClass CppClass;
#endif

//CppClass *cpp_class_create();
//void cpp_class_destroy(CppClass *c);
//void cpp_class_do_work(CppClass *c);

int photon_init_default();
void photon_thread_create11(void* (* f)(void*));

void photon_sleep_s(int n);

void photon_sleep_ms(int n);



#ifdef __cplusplus
}
#endif


#endif
21 changes: 21 additions & 0 deletions vlib/coroutines/coroutines.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module coroutines

import time

#flag -I @VEXEROOT/thirdparty/photon
#flag @VEXEROOT/thirdparty/photon/photonwrapper.so

#include "photonwrapper.h"

fn C.photon_init_default() int
fn C.photon_thread_create11(f voidptr)
fn C.photon_sleep_s(n int)
fn C.photon_sleep_ms(n int)

// sleep is coroutine-safe version of time.sleep()
pub fn sleep(duration time.Duration) {
C.photon_sleep_ms(duration.milliseconds())
}
19 changes: 15 additions & 4 deletions vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub type Expr = AnonFn
| SelectExpr
| SelectorExpr
| SizeOf
| SpawnExpr
| SqlExpr
| StringInterLiteral
| StringLiteral
Expand Down Expand Up @@ -1386,6 +1387,15 @@ pub mut:
is_expr bool
}

[minify]
pub struct SpawnExpr {
pub:
pos token.Pos
pub mut:
call_expr CallExpr
is_expr bool
}

pub struct GotoLabel {
pub:
name string
Expand Down Expand Up @@ -1948,10 +1958,11 @@ pub fn (expr Expr) pos() token.Pos {
}
NodeError, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr,
CastExpr, ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector,
EnumVal, DumpExpr, FloatLiteral, GoExpr, Ident, IfExpr, IntegerLiteral, IsRefType, Likely,
LockExpr, MapInit, MatchExpr, None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr,
RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral,
StructInit, TypeNode, TypeOf, UnsafeExpr, ComptimeType, Nil {
EnumVal, DumpExpr, FloatLiteral, GoExpr, SpawnExpr, Ident, IfExpr, IntegerLiteral,
IsRefType, Likely, LockExpr, MapInit, MatchExpr, None, OffsetOf, OrExpr, ParExpr,
PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr,
StringInterLiteral, StringLiteral, StructInit, TypeNode, TypeOf, UnsafeExpr, ComptimeType,
Nil {
return expr.pos
}
IndexExpr {
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/ast/str.v
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,9 @@ pub fn (x Expr) str() string {
GoExpr {
return 'go ${x.call_expr}'
}
SpawnExpr {
return 'spawn ${x.call_expr}'
}
Ident {
return x.name.clone()
}
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -2548,6 +2548,9 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
ast.GoExpr {
return c.go_expr(mut node)
}
ast.SpawnExpr {
return c.spawn_expr(mut node)
}
ast.Ident {
return c.ident(mut node)
}
Expand Down
29 changes: 28 additions & 1 deletion vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -2100,7 +2100,7 @@ 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 {
fn (mut c Checker) spawn_expr(mut node ast.SpawnExpr) ast.Type {
ret_type := c.call_expr(mut node.call_expr)
if node.call_expr.or_block.kind != .absent {
c.error('option handling cannot be done in `spawn` call. Do it when calling `.wait()`',
Expand All @@ -2126,6 +2126,33 @@ fn (mut c Checker) go_expr(mut node ast.GoExpr) ast.Type {
}
}

fn (mut c Checker) go_expr(mut node ast.GoExpr) ast.Type {
// TODO copypasta from spawn_expr
ret_type := c.call_expr(mut node.call_expr)
if node.call_expr.or_block.kind != .absent {
c.error('option 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(c.unwrap_generic(ret_type))
} else {
return c.table.find_or_register_thread(c.unwrap_generic(ret_type))
}
}

fn (mut c Checker) set_node_expected_arg_types(mut node ast.CallExpr, func &ast.Fn) {
if node.expected_arg_types.len == 0 {
start_idx := if func.is_method { 1 } else { 0 }
Expand Down
8 changes: 4 additions & 4 deletions vlib/v/eval/expr.v
Original file line number Diff line number Diff line change
Expand Up @@ -534,10 +534,10 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
}
ast.AnonFn, ast.ArrayDecompose, ast.AsCast, ast.Assoc, ast.AtExpr, ast.CTempVar,
ast.ChanInit, ast.Comment, ast.ComptimeCall, ast.ComptimeSelector, ast.ComptimeType,
ast.ConcatExpr, ast.DumpExpr, ast.EmptyExpr, ast.EnumVal, ast.GoExpr, ast.IfGuardExpr,
ast.IndexExpr, ast.IsRefType, ast.Likely, ast.LockExpr, ast.MapInit, ast.MatchExpr,
ast.Nil, ast.NodeError, ast.None, ast.OffsetOf, ast.OrExpr, ast.RangeExpr, ast.SelectExpr,
ast.SqlExpr, ast.TypeNode, ast.TypeOf {
ast.ConcatExpr, ast.DumpExpr, ast.EmptyExpr, ast.EnumVal, ast.GoExpr, ast.SpawnExpr,
ast.IfGuardExpr, ast.IndexExpr, ast.IsRefType, ast.Likely, ast.LockExpr, ast.MapInit,
ast.MatchExpr, ast.Nil, ast.NodeError, ast.None, ast.OffsetOf, ast.OrExpr, ast.RangeExpr,
ast.SelectExpr, ast.SqlExpr, ast.TypeNode, ast.TypeOf {
e.error('unhandled expression ${typeof(expr).name}')
}
}
Expand Down
10 changes: 9 additions & 1 deletion vlib/v/fmt/fmt.v
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,9 @@ pub fn (mut f Fmt) expr(node_ ast.Expr) {
ast.GoExpr {
f.go_expr(node)
}
ast.SpawnExpr {
f.spawn_expr(node)
}
ast.Ident {
f.ident(node)
}
Expand Down Expand Up @@ -1206,11 +1209,16 @@ pub fn (mut f Fmt) global_decl(node ast.GlobalDecl) {
}
}

pub fn (mut f Fmt) go_expr(node ast.GoExpr) {
pub fn (mut f Fmt) spawn_expr(node ast.SpawnExpr) {
f.write('spawn ')
f.call_expr(node.call_expr)
}

pub fn (mut f Fmt) go_expr(node ast.GoExpr) {
f.write('go ')
f.call_expr(node.call_expr)
}

pub fn (mut f Fmt) goto_label(node ast.GotoLabel) {
f.writeln('${node.name}:')
}
Expand Down
5 changes: 4 additions & 1 deletion vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -3160,6 +3160,9 @@ fn (mut g Gen) expr(node_ ast.Expr) {
g.write(node.val)
}
}
ast.SpawnExpr {
g.spawn_expr(node)
}
ast.GoExpr {
g.go_expr(node)
}
Expand Down Expand Up @@ -3260,7 +3263,7 @@ fn (mut g Gen) expr(node_ ast.Expr) {
mut expr_str := ''
if mut node.expr is ast.ComptimeSelector
&& (node.expr as ast.ComptimeSelector).left is ast.Ident {
// val.$(field.name)?
// val.$(field.name)?
expr_str = '${node.expr.left.str()}.${g.comptime_for_field_value.name}'
} else if mut node.expr is ast.Ident && g.is_comptime_var(node.expr) {
// val?
Expand Down
5 changes: 5 additions & 0 deletions vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -2090,6 +2090,11 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
}

fn (mut g Gen) go_expr(node ast.GoExpr) {
g.writeln('/*go (coroutine) */')
}

fn (mut g Gen) spawn_expr(node ast.SpawnExpr) {
g.writeln('/*spawn (thread) */')
line := g.go_before_stmt(0)
mut handle := ''
tmp := g.new_tmp_var()
Expand Down
17 changes: 17 additions & 0 deletions vlib/v/gen/js/js.v
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,9 @@ fn (mut g JsGen) expr(node_ ast.Expr) {
ast.GoExpr {
g.gen_go_expr(node)
}
ast.SpawnExpr {
g.gen_spawn_expr(node)
}
ast.Ident {
g.gen_ident(node)
}
Expand Down Expand Up @@ -1826,6 +1829,20 @@ fn (mut g JsGen) gen_go_expr(node ast.GoExpr) {
g.writeln('})});')
}

fn (mut g JsGen) gen_spawn_expr(node ast.SpawnExpr) {
if g.pref.output_es5 {
verror('No support for goroutines on ES5 output')
return
}
g.writeln('new _v_Promise({promise: new Promise(function(resolve){')
g.inc_indent()
g.write('resolve(')
g.expr(node.call_expr)
g.write(');')
g.dec_indent()
g.writeln('})});')
}

fn (mut g JsGen) gen_import_stmt(it ast.Import) {
g.ns.imports[it.mod] = it.alias
}
Expand Down
5 changes: 4 additions & 1 deletion vlib/v/markused/walker.v
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.fn_by_name('eprint')
w.fn_by_name('eprintln')
}
ast.GoExpr {
ast.SpawnExpr {
w.expr(node.call_expr)
if w.pref.os == .windows {
w.fn_by_name('panic_lasterr')
Expand All @@ -283,6 +283,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.fn_by_name('panic_error_number')
}
}
ast.GoExpr {
w.expr(node.call_expr)
}
ast.IndexExpr {
w.expr(node.left)
w.expr(node.index)
Expand Down
12 changes: 9 additions & 3 deletions vlib/v/parser/expr.v
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,15 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr {
}
}
.key_go, .key_spawn {
mut go_expr := p.go_expr()
go_expr.is_expr = true
node = go_expr
if p.pref.use_coroutines && p.tok.kind == .key_go {
mut go_expr := p.go_expr()
go_expr.is_expr = true
node = go_expr
} else {
mut spawn_expr := p.spawn_expr()
spawn_expr.is_expr = true
node = spawn_expr
}
}
.key_true, .key_false {
node = ast.BoolLiteral{
Expand Down
23 changes: 22 additions & 1 deletion vlib/v/parser/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,7 @@ fn (mut p Parser) fn_args() ([]ast.Param, bool, bool) {
return args, types_only, is_variadic
}

fn (mut p Parser) go_expr() ast.GoExpr {
fn (mut p Parser) spawn_expr() ast.SpawnExpr {
p.next()
spos := p.tok.pos()
expr := p.expr(0)
Expand All @@ -1053,6 +1053,27 @@ fn (mut p Parser) go_expr() ast.GoExpr {
pos := spos.extend(p.prev_tok.pos())
p.register_auto_import('sync.threads')
p.table.gostmts++
return ast.SpawnExpr{
call_expr: call_expr
pos: pos
}
}

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('coroutines')
p.table.gostmts++
return ast.GoExpr{
call_expr: call_expr
pos: pos
Expand Down
16 changes: 12 additions & 4 deletions vlib/v/parser/parser.v
Original file line number Diff line number Diff line change
Expand Up @@ -1078,10 +1078,18 @@ fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
}
}
.key_go, .key_spawn {
go_expr := p.go_expr()
return ast.ExprStmt{
expr: go_expr
pos: go_expr.pos
if p.pref.use_coroutines && p.tok.kind == .key_go {
go_expr := p.go_expr()
return ast.ExprStmt{
expr: go_expr
pos: go_expr.pos
}
} else {
spawn_expr := p.spawn_expr()
return ast.ExprStmt{
expr: spawn_expr
pos: spawn_expr.pos
}
}
}
.key_goto {
Expand Down

1 comment on commit 45f16a2

@ttytm
Copy link
Member

@ttytm ttytm commented on 45f16a2 May 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

Please sign in to comment.