mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: coroutines (part 1)
This commit is contained in:
parent
5812579d53
commit
45f16a2640
@ -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)
|
||||
}
|
||||
@ -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'))
|
||||
|
44
thirdparty/photon/photonwrapper.h
vendored
Normal file
44
thirdparty/photon/photonwrapper.h
vendored
Normal file
@ -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
vlib/coroutines/coroutines.v
Normal file
21
vlib/coroutines/coroutines.v
Normal file
@ -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())
|
||||
}
|
@ -54,6 +54,7 @@ pub type Expr = AnonFn
|
||||
| SelectExpr
|
||||
| SelectorExpr
|
||||
| SizeOf
|
||||
| SpawnExpr
|
||||
| SqlExpr
|
||||
| StringInterLiteral
|
||||
| StringLiteral
|
||||
@ -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
|
||||
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()`',
|
||||
@ -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 }
|
||||
|
@ -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}')
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
@ -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}:')
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
@ -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?
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
@ -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')
|
||||
@ -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)
|
||||
|
@ -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{
|
||||
|
@ -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)
|
||||
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -218,10 +218,6 @@ pub fn default_tcc_compiler() string {
|
||||
}
|
||||
|
||||
pub fn (mut p Preferences) default_c_compiler() {
|
||||
// fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang'
|
||||
// if os.exists(fast_clang) {
|
||||
// return fast_clang
|
||||
// }
|
||||
// TODO fix $if after 'string'
|
||||
$if windows {
|
||||
p.ccompiler = 'gcc'
|
||||
|
@ -223,6 +223,7 @@ pub mut:
|
||||
assert_failure_mode AssertFailureMode // whether to call abort() or print_backtrace() after an assertion failure
|
||||
message_limit int = 150 // the maximum amount of warnings/errors/notices that will be accumulated
|
||||
nofloat bool // for low level code, like kernels: replaces f32 with u32 and f64 with u64
|
||||
use_coroutines bool // experimental coroutines
|
||||
// checker settings:
|
||||
checker_match_exhaustive_cutoff_limit int = 12
|
||||
thread_stack_size int = 8388608 // Change with `-thread-stack-size 4194304`. Note: on macos it was 524288, which is too small for more complex programs with many nested callexprs.
|
||||
@ -798,6 +799,9 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
|
||||
res.cmain = cmdline.option(current_args, '-cmain', '')
|
||||
i++
|
||||
}
|
||||
'-use-coroutines' {
|
||||
res.use_coroutines = true
|
||||
}
|
||||
else {
|
||||
if command == 'build' && is_source_file(arg) {
|
||||
eprintln('Use `v ${arg}` instead.')
|
||||
|
Loading…
Reference in New Issue
Block a user