all: experimental locked concurrency support, part 1 (#5637)
parent
27149ba8bc
commit
3b067f5f85
|
@ -28,7 +28,7 @@ pub mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut mh TestMessageHandler) append_message(msg string) {
|
pub fn (mut mh TestMessageHandler) append_message(msg string) {
|
||||||
mh.mtx.lock()
|
mh.mtx.m_lock()
|
||||||
mh.messages << msg
|
mh.messages << msg
|
||||||
mh.mtx.unlock()
|
mh.mtx.unlock()
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ pub fn (mut ts TestSession) test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut m TestMessageHandler) display_message() {
|
pub fn (mut m TestMessageHandler) display_message() {
|
||||||
m.mtx.lock()
|
m.mtx.m_lock()
|
||||||
defer {
|
defer {
|
||||||
m.messages.clear()
|
m.messages.clear()
|
||||||
m.mtx.unlock()
|
m.mtx.unlock()
|
||||||
|
|
|
@ -2,8 +2,8 @@ module main
|
||||||
|
|
||||||
// This prelude is loaded in every v program compiled with -live,
|
// This prelude is loaded in every v program compiled with -live,
|
||||||
// but only for the shared library.
|
// but only for the shared library.
|
||||||
import live.shared
|
import live.sharedlib
|
||||||
|
|
||||||
const (
|
const (
|
||||||
no_warning_live_shared_is_used = shared.is_used
|
no_warning_live_shared_is_used = sharedlib.is_used
|
||||||
)
|
)
|
||||||
|
|
|
@ -1390,7 +1390,7 @@ mut:
|
||||||
|
|
||||||
fn (mut b St) g() {
|
fn (mut b St) g() {
|
||||||
...
|
...
|
||||||
b.mtx.lock()
|
b.mtx.m_lock()
|
||||||
// read/modify/write b.x
|
// read/modify/write b.x
|
||||||
...
|
...
|
||||||
b.mtx.unlock()
|
b.mtx.unlock()
|
||||||
|
@ -1404,7 +1404,7 @@ fn caller() {
|
||||||
}
|
}
|
||||||
go a.g()
|
go a.g()
|
||||||
...
|
...
|
||||||
a.mtx.lock()
|
a.mtx.m_lock()
|
||||||
// read/modify/write a.x
|
// read/modify/write a.x
|
||||||
...
|
...
|
||||||
a.mtx.unlock()
|
a.mtx.unlock()
|
||||||
|
|
|
@ -181,7 +181,7 @@ fn (mut cb Clipboard) free() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut cb Clipboard) clear(){
|
fn (mut cb Clipboard) clear(){
|
||||||
cb.mutex.lock()
|
cb.mutex.m_lock()
|
||||||
C.XSetSelectionOwner(cb.display, cb.selection, C.Window(C.None), C.CurrentTime)
|
C.XSetSelectionOwner(cb.display, cb.selection, C.Window(C.None), C.CurrentTime)
|
||||||
C.XFlush(cb.display)
|
C.XFlush(cb.display)
|
||||||
cb.is_owner = false
|
cb.is_owner = false
|
||||||
|
@ -200,7 +200,7 @@ fn (cb &Clipboard) take_ownership(){
|
||||||
|
|
||||||
fn (mut cb Clipboard) set_text(text string) bool {
|
fn (mut cb Clipboard) set_text(text string) bool {
|
||||||
if cb.window == C.Window(C.None) {return false}
|
if cb.window == C.Window(C.None) {return false}
|
||||||
cb.mutex.lock()
|
cb.mutex.m_lock()
|
||||||
cb.text = text
|
cb.text = text
|
||||||
cb.is_owner = true
|
cb.is_owner = true
|
||||||
cb.take_ownership()
|
cb.take_ownership()
|
||||||
|
@ -238,7 +238,7 @@ fn (mut cb Clipboard) transmit_selection(xse &C.XSelectionEvent) bool {
|
||||||
targets := cb.get_supported_targets()
|
targets := cb.get_supported_targets()
|
||||||
C.XChangeProperty(xse.display, xse.requestor, xse.property, cb.get_atom(.xa_atom), 32, C.PropModeReplace, targets.data, targets.len)
|
C.XChangeProperty(xse.display, xse.requestor, xse.property, cb.get_atom(.xa_atom), 32, C.PropModeReplace, targets.data, targets.len)
|
||||||
} else if cb.is_supported_target(xse.target) && cb.is_owner && cb.text != "" {
|
} else if cb.is_supported_target(xse.target) && cb.is_owner && cb.text != "" {
|
||||||
cb.mutex.lock()
|
cb.mutex.m_lock()
|
||||||
C.XChangeProperty(xse.display, xse.requestor, xse.property, xse.target, 8, C.PropModeReplace, cb.text.str, cb.text.len)
|
C.XChangeProperty(xse.display, xse.requestor, xse.property, xse.target, 8, C.PropModeReplace, cb.text.str, cb.text.len)
|
||||||
cb.mutex.unlock()
|
cb.mutex.unlock()
|
||||||
} else {
|
} else {
|
||||||
|
@ -265,7 +265,7 @@ fn (mut cb Clipboard) start_listener(){
|
||||||
}
|
}
|
||||||
C.SelectionClear {
|
C.SelectionClear {
|
||||||
if event.xselectionclear.window == cb.window && event.xselectionclear.selection == cb.selection {
|
if event.xselectionclear.window == cb.window && event.xselectionclear.selection == cb.selection {
|
||||||
cb.mutex.lock()
|
cb.mutex.m_lock()
|
||||||
cb.is_owner = false
|
cb.is_owner = false
|
||||||
cb.text = ""
|
cb.text = ""
|
||||||
cb.mutex.unlock()
|
cb.mutex.unlock()
|
||||||
|
@ -304,7 +304,7 @@ fn (mut cb Clipboard) start_listener(){
|
||||||
} else if event.xselection.target == to_be_requested {
|
} else if event.xselection.target == to_be_requested {
|
||||||
sent_request = false
|
sent_request = false
|
||||||
to_be_requested = C.Atom(0)
|
to_be_requested = C.Atom(0)
|
||||||
cb.mutex.lock()
|
cb.mutex.m_lock()
|
||||||
prop := read_property(event.xselection.display, event.xselection.requestor, event.xselection.property)
|
prop := read_property(event.xselection.display, event.xselection.requestor, event.xselection.property)
|
||||||
C.XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property)
|
C.XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property)
|
||||||
if cb.is_supported_target(prop.actual_type) {
|
if cb.is_supported_target(prop.actual_type) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module shared
|
module sharedlib
|
||||||
|
|
||||||
import live
|
import live
|
||||||
|
|
|
@ -2,7 +2,7 @@ module websocket
|
||||||
|
|
||||||
fn (mut ws Client) write_to_server(buf voidptr, len int) int {
|
fn (mut ws Client) write_to_server(buf voidptr, len int) int {
|
||||||
mut bytes_written := 0
|
mut bytes_written := 0
|
||||||
ws.write_lock.lock()
|
ws.write_lock.m_lock()
|
||||||
bytes_written = if ws.is_ssl {
|
bytes_written = if ws.is_ssl {
|
||||||
C.SSL_write(ws.ssl, buf, len)
|
C.SSL_write(ws.ssl, buf, len)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub struct Client {
|
||||||
// cwebsocket_subprotocol *subprotocol;
|
// cwebsocket_subprotocol *subprotocol;
|
||||||
// cwebsocket_subprotocol *subprotocols[];
|
// cwebsocket_subprotocol *subprotocols[];
|
||||||
mut:
|
mut:
|
||||||
lock &sync.Mutex = sync.new_mutex()
|
mtx &sync.Mutex = sync.new_mutex()
|
||||||
write_lock &sync.Mutex = sync.new_mutex()
|
write_lock &sync.Mutex = sync.new_mutex()
|
||||||
state State
|
state State
|
||||||
socket net.Socket
|
socket net.Socket
|
||||||
|
@ -132,9 +132,9 @@ pub fn (mut ws Client) connect() int {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ws.lock.lock()
|
ws.mtx.m_lock()
|
||||||
ws.state = .connecting
|
ws.state = .connecting
|
||||||
ws.lock.unlock()
|
ws.mtx.unlock()
|
||||||
uri := ws.parse_uri()
|
uri := ws.parse_uri()
|
||||||
nonce := get_nonce(ws.nonce_size)
|
nonce := get_nonce(ws.nonce_size)
|
||||||
seckey := base64.encode(nonce)
|
seckey := base64.encode(nonce)
|
||||||
|
@ -160,17 +160,17 @@ pub fn (mut ws Client) connect() int {
|
||||||
if ws.is_ssl {
|
if ws.is_ssl {
|
||||||
ws.connect_ssl()
|
ws.connect_ssl()
|
||||||
}
|
}
|
||||||
ws.lock.lock()
|
ws.mtx.m_lock()
|
||||||
ws.state = .connected
|
ws.state = .connected
|
||||||
ws.lock.unlock()
|
ws.mtx.unlock()
|
||||||
res := ws.write_to_server(handshake.str, handshake.len)
|
res := ws.write_to_server(handshake.str, handshake.len)
|
||||||
if res <= 0 {
|
if res <= 0 {
|
||||||
l.f('Handshake failed.')
|
l.f('Handshake failed.')
|
||||||
}
|
}
|
||||||
ws.read_handshake(seckey)
|
ws.read_handshake(seckey)
|
||||||
ws.lock.lock()
|
ws.mtx.m_lock()
|
||||||
ws.state = .open
|
ws.state = .open
|
||||||
ws.lock.unlock()
|
ws.mtx.unlock()
|
||||||
ws.send_open_event()
|
ws.send_open_event()
|
||||||
unsafe {
|
unsafe {
|
||||||
handshake.free()
|
handshake.free()
|
||||||
|
@ -182,9 +182,9 @@ pub fn (mut ws Client) connect() int {
|
||||||
|
|
||||||
pub fn (mut ws Client) close(code int, message string) {
|
pub fn (mut ws Client) close(code int, message string) {
|
||||||
if ws.state != .closed && ws.socket.sockfd > 1 {
|
if ws.state != .closed && ws.socket.sockfd > 1 {
|
||||||
ws.lock.lock()
|
ws.mtx.m_lock()
|
||||||
ws.state = .closing
|
ws.state = .closing
|
||||||
ws.lock.unlock()
|
ws.mtx.unlock()
|
||||||
mut code32 := 0
|
mut code32 := 0
|
||||||
if code > 0 {
|
if code > 0 {
|
||||||
code_ := C.htons(code)
|
code_ := C.htons(code)
|
||||||
|
@ -223,9 +223,9 @@ pub fn (mut ws Client) close(code int, message string) {
|
||||||
}
|
}
|
||||||
ws.fragments = []
|
ws.fragments = []
|
||||||
ws.send_close_event()
|
ws.send_close_event()
|
||||||
ws.lock.lock()
|
ws.mtx.m_lock()
|
||||||
ws.state = .closed
|
ws.state = .closed
|
||||||
ws.lock.unlock()
|
ws.mtx.unlock()
|
||||||
unsafe {
|
unsafe {
|
||||||
}
|
}
|
||||||
// TODO impl autoreconnect
|
// TODO impl autoreconnect
|
||||||
|
|
|
@ -139,7 +139,7 @@ fn process_in_thread(mut pool PoolProcessor, task_id int) {
|
||||||
if pool.ntask >= ilen {
|
if pool.ntask >= ilen {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
pool.ntask_mtx.lock()
|
pool.ntask_mtx.m_lock()
|
||||||
idx = pool.ntask
|
idx = pool.ntask
|
||||||
pool.ntask++
|
pool.ntask++
|
||||||
pool.ntask_mtx.unlock()
|
pool.ntask_mtx.unlock()
|
||||||
|
|
|
@ -17,7 +17,8 @@ pub fn new_mutex() &Mutex {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut m Mutex) lock() {
|
// m_lock(), for *manual* mutex handling, since `lock` is a keyword
|
||||||
|
pub fn (mut m Mutex) m_lock() {
|
||||||
C.pthread_mutex_lock(&m.mutex)
|
C.pthread_mutex_lock(&m.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub fn new_mutex() &Mutex {
|
||||||
return sm
|
return sm
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut m Mutex) lock() {
|
pub fn (mut m Mutex) m_lock() {
|
||||||
// if mutex handle not initalized
|
// if mutex handle not initalized
|
||||||
if isnil(m.mx) {
|
if isnil(m.mx) {
|
||||||
m.mx = MHANDLE(C.CreateMutex(0, false, 0))
|
m.mx = MHANDLE(C.CreateMutex(0, false, 0))
|
||||||
|
|
|
@ -10,7 +10,7 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut w Waiter) wait() {
|
pub fn (mut w Waiter) wait() {
|
||||||
w.mx.lock()
|
w.mx.m_lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut w Waiter) stop() {
|
pub fn (mut w Waiter) stop() {
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub fn new_waitgroup() &WaitGroup {
|
||||||
// add panics if task count drops below zero.
|
// add panics if task count drops below zero.
|
||||||
pub fn (mut wg WaitGroup) add(delta int) {
|
pub fn (mut wg WaitGroup) add(delta int) {
|
||||||
// protect task_count
|
// protect task_count
|
||||||
wg.task_count_mutex.lock()
|
wg.task_count_mutex.m_lock()
|
||||||
defer {
|
defer {
|
||||||
wg.task_count_mutex.unlock()
|
wg.task_count_mutex.unlock()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
|
||||||
|
|
||||||
pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | CastExpr |
|
pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | CastExpr |
|
||||||
CharLiteral | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr |
|
CharLiteral | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr |
|
||||||
IndexExpr | InfixExpr | IntegerLiteral | Likely | MapInit | MatchExpr | None | OrExpr |
|
IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | MapInit | MatchExpr | None | OrExpr |
|
||||||
ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral |
|
ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral |
|
||||||
StringLiteral | StructInit | Type | TypeOf
|
StringLiteral | StructInit | Type | TypeOf
|
||||||
|
|
||||||
|
@ -232,6 +232,7 @@ pub:
|
||||||
receiver_pos token.Position
|
receiver_pos token.Position
|
||||||
is_method bool
|
is_method bool
|
||||||
rec_mut bool // is receiver mutable
|
rec_mut bool // is receiver mutable
|
||||||
|
rec_share table.ShareType
|
||||||
language table.Language
|
language table.Language
|
||||||
no_body bool // just a definition `fn C.malloc()`
|
no_body bool // just a definition `fn C.malloc()`
|
||||||
is_builtin bool // this function is defined in builtin/strconv
|
is_builtin bool // this function is defined in builtin/strconv
|
||||||
|
@ -271,6 +272,7 @@ pub mut:
|
||||||
pub struct CallArg {
|
pub struct CallArg {
|
||||||
pub:
|
pub:
|
||||||
is_mut bool
|
is_mut bool
|
||||||
|
share table.ShareType
|
||||||
expr Expr
|
expr Expr
|
||||||
pub mut:
|
pub mut:
|
||||||
typ table.Type
|
typ table.Type
|
||||||
|
@ -301,6 +303,7 @@ pub struct Var {
|
||||||
pub:
|
pub:
|
||||||
name string
|
name string
|
||||||
expr Expr
|
expr Expr
|
||||||
|
share table.ShareType
|
||||||
is_mut bool
|
is_mut bool
|
||||||
is_arg bool // fn args should not be autofreed
|
is_arg bool // fn args should not be autofreed
|
||||||
pub mut:
|
pub mut:
|
||||||
|
@ -344,6 +347,7 @@ pub mut:
|
||||||
is_mut bool
|
is_mut bool
|
||||||
is_static bool
|
is_static bool
|
||||||
is_optional bool
|
is_optional bool
|
||||||
|
share table.ShareType
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type IdentInfo = IdentFn | IdentVar
|
pub type IdentInfo = IdentFn | IdentVar
|
||||||
|
@ -438,6 +442,18 @@ pub:
|
||||||
comment Comment
|
comment Comment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct LockExpr {
|
||||||
|
pub:
|
||||||
|
stmts []Stmt
|
||||||
|
is_rlock bool
|
||||||
|
pos token.Position
|
||||||
|
pub mut:
|
||||||
|
lockeds []Ident // `x`, `y` in `lock x, y {`
|
||||||
|
is_expr bool
|
||||||
|
is_rw bool // `rwshared` needs special special handling even in `lock` case
|
||||||
|
typ table.Type
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MatchExpr {
|
pub struct MatchExpr {
|
||||||
pub:
|
pub:
|
||||||
tok_kind token.Kind
|
tok_kind token.Kind
|
||||||
|
|
|
@ -1128,12 +1128,39 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
}
|
}
|
||||||
if call_arg.is_mut {
|
if call_arg.is_mut {
|
||||||
c.fail_if_immutable(call_arg.expr)
|
c.fail_if_immutable(call_arg.expr)
|
||||||
|
|
||||||
if !arg.is_mut {
|
if !arg.is_mut {
|
||||||
c.error('`$arg.name` argument is not mutable, `mut` is not needed`', call_arg.expr.position())
|
mut words := 'mutable'
|
||||||
|
mut tok := 'mut'
|
||||||
|
if call_arg.share == .shared_t {
|
||||||
|
words = 'shared'
|
||||||
|
tok = 'shared'
|
||||||
|
} else if call_arg.share == .rwshared_t {
|
||||||
|
words = 'read/write shared'
|
||||||
|
tok = 'rwshared'
|
||||||
|
} else if call_arg.share == .atomic_t {
|
||||||
|
words = 'atomic'
|
||||||
|
tok = 'atomic'
|
||||||
|
}
|
||||||
|
c.error('`$arg.name` argument is not $words, `$tok` is not needed`', call_arg.expr.position())
|
||||||
|
} else if arg.typ.share() != call_arg.share {
|
||||||
|
c.error('wrong shared type', call_arg.expr.position())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if arg.is_mut {
|
if arg.is_mut && (!call_arg.is_mut || arg.typ.share() != call_arg.share) {
|
||||||
c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`',
|
mut words := ' mutable'
|
||||||
|
mut tok := 'mut'
|
||||||
|
if arg.typ.share() == .shared_t {
|
||||||
|
words = ' shared'
|
||||||
|
tok = 'shared'
|
||||||
|
} else if arg.typ.share() == .rwshared_t {
|
||||||
|
words = ' read/write shared'
|
||||||
|
tok = 'rwshared'
|
||||||
|
} else if arg.typ.share() == .atomic_t {
|
||||||
|
words = 'n atomic'
|
||||||
|
tok = 'atomic'
|
||||||
|
}
|
||||||
|
c.error('`$arg.name` is a$words argument, you need to provide `$tok`: `${call_expr.name}($tok ...)`',
|
||||||
call_arg.expr.position())
|
call_arg.expr.position())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1497,6 +1524,13 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
|
mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
|
||||||
mut ident_var_info := left.var_info()
|
mut ident_var_info := left.var_info()
|
||||||
|
if ident_var_info.share in [.shared_t, .rwshared_t] {
|
||||||
|
left_type = left_type.set_flag(.shared_f)
|
||||||
|
}
|
||||||
|
if ident_var_info.share in [.atomic_t, .rwshared_t] {
|
||||||
|
left_type = left_type.set_flag(.atomic_or_rw)
|
||||||
|
}
|
||||||
|
assign_stmt.left_types[i] = left_type
|
||||||
ident_var_info.typ = left_type
|
ident_var_info.typ = left_type
|
||||||
left.info = ident_var_info
|
left.info = ident_var_info
|
||||||
scope.update_var_type(left.name, left_type)
|
scope.update_var_type(left.name, left_type)
|
||||||
|
@ -2116,6 +2150,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
return table.any_int_type
|
return table.any_int_type
|
||||||
}
|
}
|
||||||
|
ast.LockExpr {
|
||||||
|
return c.lock_expr(mut node)
|
||||||
|
}
|
||||||
ast.MapInit {
|
ast.MapInit {
|
||||||
return c.map_init(mut node)
|
return c.map_init(mut node)
|
||||||
}
|
}
|
||||||
|
@ -2494,6 +2531,15 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
|
||||||
c.error(err_details, node.pos)
|
c.error(err_details, node.pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Checker) lock_expr(mut node ast.LockExpr) table.Type {
|
||||||
|
for id in node.lockeds {
|
||||||
|
c.ident(mut id)
|
||||||
|
}
|
||||||
|
c.stmts(node.stmts)
|
||||||
|
// void for now... maybe sometime `x := lock a { a.getval() }`
|
||||||
|
return table.void_type
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||||
mut expr_required := false
|
mut expr_required := false
|
||||||
if c.expected_type != table.void_type {
|
if c.expected_type != table.void_type {
|
||||||
|
|
|
@ -835,6 +835,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
f.write(node.val)
|
f.write(node.val)
|
||||||
}
|
}
|
||||||
|
ast.LockExpr {
|
||||||
|
f.lock_expr(node)
|
||||||
|
}
|
||||||
ast.MapInit {
|
ast.MapInit {
|
||||||
if node.keys.len == 0 {
|
if node.keys.len == 0 {
|
||||||
mut ktyp := node.key_type
|
mut ktyp := node.key_type
|
||||||
|
@ -1164,6 +1167,20 @@ pub fn (mut f Fmt) short_module(name string) string {
|
||||||
return '${aname}.$symname'
|
return '${aname}.$symname'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut f Fmt) lock_expr(lex ast.LockExpr) {
|
||||||
|
f.write('lock ')
|
||||||
|
for i, v in lex.lockeds {
|
||||||
|
if i > 0 {
|
||||||
|
f.write(', ')
|
||||||
|
}
|
||||||
|
f.expr(v)
|
||||||
|
}
|
||||||
|
f.write(' {')
|
||||||
|
f.writeln('')
|
||||||
|
f.stmts(lex.stmts)
|
||||||
|
f.write('}')
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
|
pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
|
||||||
single_line := it.branches.len == 2 && it.has_else &&
|
single_line := it.branches.len == 2 && it.has_else &&
|
||||||
it.branches[0].stmts.len == 1 && it.branches[1].stmts.len == 1 &&
|
it.branches[0].stmts.len == 1 && it.branches[1].stmts.len == 1 &&
|
||||||
|
|
|
@ -58,7 +58,11 @@ mut:
|
||||||
is_array_set bool
|
is_array_set bool
|
||||||
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
||||||
is_sql bool // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc)
|
is_sql bool // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc)
|
||||||
|
is_shared bool // for initialization of hidden mutex in `[rw]shared` literals
|
||||||
|
is_rwshared bool
|
||||||
optionals []string // to avoid duplicates TODO perf, use map
|
optionals []string // to avoid duplicates TODO perf, use map
|
||||||
|
shareds []int // types with hidden mutex for which decl has been emitted
|
||||||
|
rwshareds []int // same with hidden rwmutex
|
||||||
inside_ternary int // ?: comma separated statements on a single line
|
inside_ternary int // ?: comma separated statements on a single line
|
||||||
inside_map_postfix bool // inside map++/-- postfix expr
|
inside_map_postfix bool // inside map++/-- postfix expr
|
||||||
inside_map_infix bool // inside map<</+=/-= infix expr
|
inside_map_infix bool // inside map<</+=/-= infix expr
|
||||||
|
@ -329,7 +333,11 @@ fn (g &Gen) typ(t table.Type) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g &Gen) base_type(t table.Type) string {
|
fn (g &Gen) base_type(t table.Type) string {
|
||||||
mut styp := g.cc_type(t)
|
share := t.share()
|
||||||
|
mut styp := if share == .atomic_t { t.atomic_typename() } else { g.cc_type(t) }
|
||||||
|
if t.has_flag(.shared_f) {
|
||||||
|
styp = g.find_or_register_shared(t, styp)
|
||||||
|
}
|
||||||
nr_muls := t.nr_muls()
|
nr_muls := t.nr_muls()
|
||||||
if nr_muls > 0 {
|
if nr_muls > 0 {
|
||||||
styp += strings.repeat(`*`, nr_muls)
|
styp += strings.repeat(`*`, nr_muls)
|
||||||
|
@ -386,6 +394,27 @@ fn (mut g Gen) register_optional(t table.Type) string {
|
||||||
return styp
|
return styp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) find_or_register_shared(t table.Type, base string) string {
|
||||||
|
is_rw := t.has_flag(.atomic_or_rw)
|
||||||
|
prefix := if is_rw { 'rw' } else { '' }
|
||||||
|
sh_typ := '__${prefix}shared__$base'
|
||||||
|
t_idx := t.idx()
|
||||||
|
if (is_rw && t_idx in g.rwshareds) || (!is_rw && t_idx in g.shareds) {
|
||||||
|
return sh_typ
|
||||||
|
}
|
||||||
|
// TODO: These two should become different...
|
||||||
|
mtx_typ := if is_rw { 'sync__Mutex' } else { 'sync__Mutex' }
|
||||||
|
g.hotcode_definitions.writeln('struct $sh_typ { $base val; $mtx_typ* mtx; };')
|
||||||
|
g.typedefs2.writeln('typedef struct $sh_typ $sh_typ;')
|
||||||
|
// println('registered shared type $sh_typ')
|
||||||
|
if is_rw {
|
||||||
|
g.rwshareds << t_idx
|
||||||
|
} else {
|
||||||
|
g.shareds << t_idx
|
||||||
|
}
|
||||||
|
return sh_typ
|
||||||
|
}
|
||||||
|
|
||||||
// cc_type returns the Cleaned Concrete Type name, *without ptr*,
|
// cc_type returns the Cleaned Concrete Type name, *without ptr*,
|
||||||
// i.e. it's always just Cat, not Cat_ptr:
|
// i.e. it's always just Cat, not Cat_ptr:
|
||||||
fn (g &Gen) cc_type(t table.Type) string {
|
fn (g &Gen) cc_type(t table.Type) string {
|
||||||
|
@ -1141,7 +1170,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
// `a := 1` | `a,b := 1,2`
|
// `a := 1` | `a,b := 1,2`
|
||||||
for i, left in assign_stmt.left {
|
for i, left in assign_stmt.left {
|
||||||
mut var_type := assign_stmt.left_types[i]
|
mut var_type := assign_stmt.left_types[i]
|
||||||
val_type := assign_stmt.right_types[i]
|
mut val_type := assign_stmt.right_types[i]
|
||||||
val := assign_stmt.right[i]
|
val := assign_stmt.right[i]
|
||||||
mut is_call := false
|
mut is_call := false
|
||||||
mut blank_assign := false
|
mut blank_assign := false
|
||||||
|
@ -1151,6 +1180,15 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
// id_info := ident.var_info()
|
// id_info := ident.var_info()
|
||||||
// var_type = id_info.typ
|
// var_type = id_info.typ
|
||||||
blank_assign = ident.kind == .blank_ident
|
blank_assign = ident.kind == .blank_ident
|
||||||
|
if ident.info is ast.IdentVar {
|
||||||
|
share := (ident.info as ast.IdentVar).share
|
||||||
|
if share in [.shared_t, .rwshared_t] {
|
||||||
|
var_type = var_type.set_flag(.shared_f)
|
||||||
|
}
|
||||||
|
if share in [.atomic_t, .rwshared_t] {
|
||||||
|
var_type = var_type.set_flag(.atomic_or_rw)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
styp := g.typ(var_type)
|
styp := g.typ(var_type)
|
||||||
mut is_fixed_array_init := false
|
mut is_fixed_array_init := false
|
||||||
|
@ -1278,6 +1316,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
if unwrap_optional {
|
if unwrap_optional {
|
||||||
g.write('*($styp*)')
|
g.write('*($styp*)')
|
||||||
}
|
}
|
||||||
|
g.is_shared = var_type.has_flag(.shared_f)
|
||||||
|
g.is_rwshared = var_type.has_flag(.atomic_or_rw)
|
||||||
if !cloned {
|
if !cloned {
|
||||||
if is_decl {
|
if is_decl {
|
||||||
if is_fixed_array_init && !has_val {
|
if is_fixed_array_init && !has_val {
|
||||||
|
@ -1303,6 +1343,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.write(' })')
|
g.write(' })')
|
||||||
g.is_array_set = false
|
g.is_array_set = false
|
||||||
}
|
}
|
||||||
|
g.is_rwshared = false
|
||||||
|
g.is_shared = false
|
||||||
}
|
}
|
||||||
g.right_is_opt = false
|
g.right_is_opt = false
|
||||||
g.is_assign_rhs = false
|
g.is_assign_rhs = false
|
||||||
|
@ -1622,6 +1664,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
g.write(node.val) // .int().str())
|
g.write(node.val) // .int().str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast.LockExpr {
|
||||||
|
g.lock_expr(node)
|
||||||
|
}
|
||||||
ast.MatchExpr {
|
ast.MatchExpr {
|
||||||
g.match_expr(node)
|
g.match_expr(node)
|
||||||
}
|
}
|
||||||
|
@ -1721,6 +1766,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
// g.write('. /*typ= $it.expr_type */') // ${g.typ(it.expr_type)} /')
|
// g.write('. /*typ= $it.expr_type */') // ${g.typ(it.expr_type)} /')
|
||||||
g.write('.')
|
g.write('.')
|
||||||
}
|
}
|
||||||
|
if node.expr_type.has_flag(.shared_f) {
|
||||||
|
g.write('val.')
|
||||||
|
}
|
||||||
if node.expr_type == 0 {
|
if node.expr_type == 0 {
|
||||||
verror('cgen: SelectorExpr | expr_type: 0 | it.expr: `$node.expr` | field: `$node.field_name` | file: $g.file.path | line: $node.pos.line_nr')
|
verror('cgen: SelectorExpr | expr_type: 0 | it.expr: `$node.expr` | field: `$node.field_name` | file: $g.file.path | line: $node.pos.line_nr')
|
||||||
}
|
}
|
||||||
|
@ -2011,6 +2059,36 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) lock_expr(node ast.LockExpr) {
|
||||||
|
for id in node.lockeds {
|
||||||
|
name := id.name
|
||||||
|
deref := if id.is_mut { '->' } else { '.' }
|
||||||
|
// TODO: use 3 different locking functions
|
||||||
|
if node.is_rlock {
|
||||||
|
g.writeln('sync__Mutex_m_lock(${name}${deref}mtx);')
|
||||||
|
} else if id.var_info().typ.has_flag(.atomic_or_rw) {
|
||||||
|
g.writeln('sync__Mutex_m_lock(${name}${deref}mtx);')
|
||||||
|
} else {
|
||||||
|
g.writeln('sync__Mutex_m_lock(${name}${deref}mtx);')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.stmts(node.stmts)
|
||||||
|
// unlock in reverse order
|
||||||
|
for i := node.lockeds.len-1; i >= 0; i-- {
|
||||||
|
id := node.lockeds[i]
|
||||||
|
name := id.name
|
||||||
|
deref := if id.is_mut { '->' } else { '.' }
|
||||||
|
// TODO: use 3 different unlocking functions
|
||||||
|
if node.is_rlock {
|
||||||
|
g.writeln('sync__Mutex_unlock(${name}${deref}mtx);')
|
||||||
|
} else if id.var_info().typ.has_flag(.atomic_or_rw) {
|
||||||
|
g.writeln('sync__Mutex_unlock(${name}${deref}mtx);')
|
||||||
|
} else {
|
||||||
|
g.writeln('sync__Mutex_unlock(${name}${deref}mtx);')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) match_expr(node ast.MatchExpr) {
|
fn (mut g Gen) match_expr(node ast.MatchExpr) {
|
||||||
// println('match expr typ=$it.expr_type')
|
// println('match expr typ=$it.expr_type')
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -2150,6 +2228,10 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||||
g.write('(*($styp*)${name}.data)')
|
g.write('(*($styp*)${name}.data)')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !g.is_assign_lhs && (ident_var.share == .shared_t || ident_var.share == .rwshared_t) {
|
||||||
|
g.write('${name}.val')
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g.write(g.get_ternary_name(name))
|
g.write(g.get_ternary_name(name))
|
||||||
}
|
}
|
||||||
|
@ -2671,6 +2753,7 @@ const (
|
||||||
|
|
||||||
fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
||||||
styp := g.typ(struct_init.typ)
|
styp := g.typ(struct_init.typ)
|
||||||
|
mut shared_styp := '' // only needed for shared &St{...
|
||||||
if styp in skip_struct_init {
|
if styp in skip_struct_init {
|
||||||
g.go_back_out(3)
|
g.go_back_out(3)
|
||||||
return
|
return
|
||||||
|
@ -2680,9 +2763,22 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
||||||
g.is_amp = false // reset the flag immediately so that other struct inits in this expr are handled correctly
|
g.is_amp = false // reset the flag immediately so that other struct inits in this expr are handled correctly
|
||||||
if is_amp {
|
if is_amp {
|
||||||
g.out.go_back(1) // delete the `&` already generated in `prefix_expr()
|
g.out.go_back(1) // delete the `&` already generated in `prefix_expr()
|
||||||
g.write('($styp*)memdup(&($styp){')
|
if g.is_shared {
|
||||||
|
mut shared_typ := struct_init.typ.set_flag(.shared_f)
|
||||||
|
if g.is_rwshared {
|
||||||
|
shared_typ = shared_typ.set_flag(.atomic_or_rw)
|
||||||
|
}
|
||||||
|
shared_styp = g.typ(shared_typ)
|
||||||
|
g.writeln('($shared_styp*)memdup(&($shared_styp){.val = ($styp){')
|
||||||
|
} else {
|
||||||
|
g.write('($styp*)memdup(&($styp){')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g.writeln('($styp){')
|
if g.is_shared {
|
||||||
|
g.writeln('{.val = {')
|
||||||
|
} else {
|
||||||
|
g.writeln('($styp){')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// mut fields := []string{}
|
// mut fields := []string{}
|
||||||
mut inited_fields := map[string]int{} // TODO this is done in checker, move to ast node
|
mut inited_fields := map[string]int{} // TODO this is done in checker, move to ast node
|
||||||
|
@ -2771,7 +2867,12 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
||||||
g.write('\n#ifndef __cplusplus\n0\n#endif\n')
|
g.write('\n#ifndef __cplusplus\n0\n#endif\n')
|
||||||
}
|
}
|
||||||
g.write('}')
|
g.write('}')
|
||||||
if is_amp {
|
if g.is_shared {
|
||||||
|
g.write(', .mtx = sync__new_mutex()}')
|
||||||
|
if is_amp {
|
||||||
|
g.write(', sizeof($shared_styp))')
|
||||||
|
}
|
||||||
|
} else if is_amp {
|
||||||
g.write(', sizeof($styp))')
|
g.write(', sizeof($styp))')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,6 +563,9 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
g.write(it.val)
|
g.write(it.val)
|
||||||
}
|
}
|
||||||
|
ast.LockExpr {
|
||||||
|
g.gen_lock_expr(it)
|
||||||
|
}
|
||||||
ast.MapInit {
|
ast.MapInit {
|
||||||
g.gen_map_init_expr(it)
|
g.gen_map_init_expr(it)
|
||||||
}
|
}
|
||||||
|
@ -1192,6 +1195,10 @@ fn (mut g JsGen) gen_ident(node ast.Ident) {
|
||||||
g.write(name)
|
g.write(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) gen_lock_expr(node ast.LockExpr) {
|
||||||
|
// TODO: implement this
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||||
type_sym := g.table.get_type_symbol(node.typ)
|
type_sym := g.table.get_type_symbol(node.typ)
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
module parser
|
module parser
|
||||||
|
|
||||||
import v.ast
|
import v.ast
|
||||||
|
import v.table
|
||||||
|
|
||||||
fn (mut p Parser) assign_stmt() ast.Stmt {
|
fn (mut p Parser) assign_stmt() ast.Stmt {
|
||||||
return p.partial_assign_stmt(p.expr_list())
|
return p.partial_assign_stmt(p.expr_list())
|
||||||
|
@ -106,16 +107,22 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt {
|
||||||
if p.scope.known_var(lx.name) {
|
if p.scope.known_var(lx.name) {
|
||||||
p.error_with_pos('redefinition of `$lx.name`', lx.pos)
|
p.error_with_pos('redefinition of `$lx.name`', lx.pos)
|
||||||
}
|
}
|
||||||
|
mut share := table.ShareType(0)
|
||||||
|
if lx.info is ast.IdentVar {
|
||||||
|
share = (lx.info as ast.IdentVar).share
|
||||||
|
}
|
||||||
if left.len == right.len {
|
if left.len == right.len {
|
||||||
p.scope.register(lx.name, ast.Var{
|
p.scope.register(lx.name, ast.Var{
|
||||||
name: lx.name
|
name: lx.name
|
||||||
expr: right[i]
|
expr: right[i]
|
||||||
|
share: share
|
||||||
is_mut: lx.is_mut || p.inside_for
|
is_mut: lx.is_mut || p.inside_for
|
||||||
pos: lx.pos
|
pos: lx.pos
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
p.scope.register(lx.name, ast.Var{
|
p.scope.register(lx.name, ast.Var{
|
||||||
name: lx.name
|
name: lx.name
|
||||||
|
share: share
|
||||||
is_mut: lx.is_mut || p.inside_for
|
is_mut: lx.is_mut || p.inside_for
|
||||||
pos: lx.pos
|
pos: lx.pos
|
||||||
})
|
})
|
||||||
|
|
|
@ -100,14 +100,16 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
|
||||||
pub fn (mut p Parser) call_args() []ast.CallArg {
|
pub fn (mut p Parser) call_args() []ast.CallArg {
|
||||||
mut args := []ast.CallArg{}
|
mut args := []ast.CallArg{}
|
||||||
for p.tok.kind != .rpar {
|
for p.tok.kind != .rpar {
|
||||||
mut is_mut := false
|
is_shared := p.tok.kind in [.key_shared, .key_rwshared]
|
||||||
if p.tok.kind == .key_mut {
|
is_atomic_or_rw := p.tok.kind in [.key_rwshared, .key_atomic]
|
||||||
|
is_mut := p.tok.kind == .key_mut || is_shared || is_atomic_or_rw
|
||||||
|
if is_mut {
|
||||||
p.next()
|
p.next()
|
||||||
is_mut = true
|
|
||||||
}
|
}
|
||||||
e := p.expr(0)
|
e := p.expr(0)
|
||||||
args << ast.CallArg{
|
args << ast.CallArg{
|
||||||
is_mut: is_mut
|
is_mut: is_mut
|
||||||
|
share: table.sharetype_from_flags(is_shared, is_atomic_or_rw)
|
||||||
expr: e
|
expr: e
|
||||||
}
|
}
|
||||||
if p.tok.kind != .rpar {
|
if p.tok.kind != .rpar {
|
||||||
|
@ -149,7 +151,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
if p.tok.kind == .lpar {
|
if p.tok.kind == .lpar {
|
||||||
p.next() // (
|
p.next() // (
|
||||||
is_method = true
|
is_method = true
|
||||||
rec_mut = p.tok.kind == .key_mut
|
is_shared := p.tok.kind in [.key_shared, .key_rwshared]
|
||||||
|
is_atomic_or_rw := p.tok.kind in [.key_rwshared, .key_atomic]
|
||||||
|
rec_mut = p.tok.kind == .key_mut || is_shared || is_atomic_or_rw
|
||||||
if rec_mut {
|
if rec_mut {
|
||||||
p.next() // `mut`
|
p.next() // `mut`
|
||||||
}
|
}
|
||||||
|
@ -172,6 +176,12 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
if is_amp && rec_mut {
|
if is_amp && rec_mut {
|
||||||
p.error('use `(mut f Foo)` or `(f &Foo)` instead of `(mut f &Foo)`')
|
p.error('use `(mut f Foo)` or `(f &Foo)` instead of `(mut f &Foo)`')
|
||||||
}
|
}
|
||||||
|
if is_shared {
|
||||||
|
rec_type = rec_type.set_flag(.shared_f)
|
||||||
|
}
|
||||||
|
if is_atomic_or_rw {
|
||||||
|
rec_type = rec_type.set_flag(.atomic_or_rw)
|
||||||
|
}
|
||||||
args << table.Arg{
|
args << table.Arg{
|
||||||
name: rec_name
|
name: rec_name
|
||||||
is_mut: rec_mut
|
is_mut: rec_mut
|
||||||
|
@ -390,7 +400,9 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool, bool) {
|
||||||
mut arg_no := 1
|
mut arg_no := 1
|
||||||
for p.tok.kind != .rpar {
|
for p.tok.kind != .rpar {
|
||||||
arg_name := 'arg_$arg_no'
|
arg_name := 'arg_$arg_no'
|
||||||
is_mut := p.tok.kind == .key_mut
|
is_shared := p.tok.kind in [.key_shared, .key_rwshared]
|
||||||
|
is_atomic_or_rw := p.tok.kind in [.key_rwshared, .key_atomic]
|
||||||
|
is_mut := p.tok.kind == .key_mut || is_shared || is_atomic_or_rw
|
||||||
if is_mut {
|
if is_mut {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
|
@ -402,13 +414,27 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool, bool) {
|
||||||
mut arg_type := p.parse_type()
|
mut arg_type := p.parse_type()
|
||||||
if is_mut {
|
if is_mut {
|
||||||
if !arg_type.has_flag(.generic) {
|
if !arg_type.has_flag(.generic) {
|
||||||
p.check_fn_mutable_arguments(arg_type, pos)
|
if is_shared {
|
||||||
|
p.check_fn_shared_arguments(arg_type, pos)
|
||||||
|
} else if is_atomic_or_rw {
|
||||||
|
p.check_fn_atomic_arguments(arg_type, pos)
|
||||||
|
} else {
|
||||||
|
p.check_fn_mutable_arguments(arg_type, pos)
|
||||||
|
}
|
||||||
|
} else if is_shared || is_atomic_or_rw {
|
||||||
|
p.error_with_pos('generic object cannot be `atomic`, `shared` or `rwshared`', pos)
|
||||||
}
|
}
|
||||||
// if arg_type.is_ptr() {
|
// if arg_type.is_ptr() {
|
||||||
// p.error('cannot mut')
|
// p.error('cannot mut')
|
||||||
// }
|
// }
|
||||||
// arg_type = arg_type.to_ptr()
|
// arg_type = arg_type.to_ptr()
|
||||||
arg_type = arg_type.set_nr_muls(1)
|
arg_type = arg_type.set_nr_muls(1)
|
||||||
|
if is_shared {
|
||||||
|
arg_type = arg_type.set_flag(.shared_f)
|
||||||
|
}
|
||||||
|
if is_atomic_or_rw {
|
||||||
|
arg_type = arg_type.set_flag(.atomic_or_rw)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if is_variadic {
|
if is_variadic {
|
||||||
arg_type = arg_type.set_flag(.variadic)
|
arg_type = arg_type.set_flag(.variadic)
|
||||||
|
@ -430,7 +456,9 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool, bool) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for p.tok.kind != .rpar {
|
for p.tok.kind != .rpar {
|
||||||
mut is_mut := p.tok.kind == .key_mut
|
is_shared := p.tok.kind in [.key_shared, .key_rwshared]
|
||||||
|
is_atomic_or_rw := p.tok.kind in [.key_rwshared, .key_atomic]
|
||||||
|
mut is_mut := p.tok.kind == .key_mut || is_shared || is_atomic_or_rw
|
||||||
if is_mut {
|
if is_mut {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
|
@ -455,9 +483,23 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool, bool) {
|
||||||
mut typ := p.parse_type()
|
mut typ := p.parse_type()
|
||||||
if is_mut {
|
if is_mut {
|
||||||
if !typ.has_flag(.generic) {
|
if !typ.has_flag(.generic) {
|
||||||
p.check_fn_mutable_arguments(typ, pos)
|
if is_shared {
|
||||||
|
p.check_fn_shared_arguments(typ, pos)
|
||||||
|
} else if is_atomic_or_rw {
|
||||||
|
p.check_fn_atomic_arguments(typ, pos)
|
||||||
|
} else {
|
||||||
|
p.check_fn_mutable_arguments(typ, pos)
|
||||||
|
}
|
||||||
|
} else if is_shared || is_atomic_or_rw {
|
||||||
|
p.error_with_pos('generic object cannot be `atomic`, `shared` or `rwshared`', pos)
|
||||||
}
|
}
|
||||||
typ = typ.set_nr_muls(1)
|
typ = typ.set_nr_muls(1)
|
||||||
|
if is_shared {
|
||||||
|
typ = typ.set_flag(.shared_f)
|
||||||
|
}
|
||||||
|
if is_atomic_or_rw {
|
||||||
|
typ = typ.set_flag(.atomic_or_rw)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if is_variadic {
|
if is_variadic {
|
||||||
typ = typ.set_flag(.variadic)
|
typ = typ.set_flag(.variadic)
|
||||||
|
@ -497,6 +539,22 @@ fn (mut p Parser) check_fn_mutable_arguments(typ table.Type, pos token.Position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut p Parser) check_fn_shared_arguments(typ table.Type, pos token.Position) {
|
||||||
|
sym := p.table.get_type_symbol(typ)
|
||||||
|
if sym.kind !in [.array, .struct_, .map, .placeholder] && !typ.is_ptr() {
|
||||||
|
p.error_with_pos('shared arguments are only allowed for arrays, maps, and structs\n', pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Parser) check_fn_atomic_arguments(typ table.Type, pos token.Position) {
|
||||||
|
sym := p.table.get_type_symbol(typ)
|
||||||
|
if sym.kind !in [.u32, .int, .u64] {
|
||||||
|
p.error_with_pos('atomic arguments are only allowed for 32/64 bit integers\n' +
|
||||||
|
'use shared arguments instead: `fn foo(atomic n $sym.name) {` => `fn foo(shared n $sym.name) {`',
|
||||||
|
pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut p Parser) fn_redefinition_error(name string) {
|
fn (mut p Parser) fn_redefinition_error(name string) {
|
||||||
// Find where this function was already declared
|
// Find where this function was already declared
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
module parser
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
import v.table
|
||||||
|
|
||||||
|
fn (mut p Parser) lock_expr() ast.LockExpr {
|
||||||
|
pos := p.tok.position()
|
||||||
|
is_rlock := p.tok.kind == .key_rlock
|
||||||
|
p.next()
|
||||||
|
mut lockeds := []ast.Ident{}
|
||||||
|
for p.tok.kind == .name {
|
||||||
|
lockeds << ast.Ident{
|
||||||
|
language: table.Language.v
|
||||||
|
kind: .variable
|
||||||
|
pos: p.tok.position()
|
||||||
|
name: p.tok.lit
|
||||||
|
is_mut: true
|
||||||
|
info: ast.IdentVar{}
|
||||||
|
}
|
||||||
|
p.next()
|
||||||
|
if p.tok.kind == .lcbr {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p.check(.comma)
|
||||||
|
}
|
||||||
|
stmts := p.parse_block()
|
||||||
|
return ast.LockExpr {
|
||||||
|
lockeds: lockeds
|
||||||
|
stmts: stmts
|
||||||
|
is_rlock: is_rlock
|
||||||
|
pos: pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,8 +105,10 @@ pub fn (mut p Parser) parse_type() table.Type {
|
||||||
p.next()
|
p.next()
|
||||||
is_optional = true
|
is_optional = true
|
||||||
}
|
}
|
||||||
|
is_shared := p.tok.kind in [.key_shared, .key_rwshared]
|
||||||
|
is_atomic_or_rw := p.tok.kind in [.key_rwshared, .key_atomic]
|
||||||
mut nr_muls := 0
|
mut nr_muls := 0
|
||||||
if p.tok.kind == .key_mut {
|
if p.tok.kind == .key_mut || is_shared || is_atomic_or_rw {
|
||||||
nr_muls++
|
nr_muls++
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
|
@ -139,6 +141,12 @@ pub fn (mut p Parser) parse_type() table.Type {
|
||||||
if is_optional {
|
if is_optional {
|
||||||
typ = typ.set_flag(.optional)
|
typ = typ.set_flag(.optional)
|
||||||
}
|
}
|
||||||
|
if is_shared {
|
||||||
|
typ = typ.set_flag(.shared_f)
|
||||||
|
}
|
||||||
|
if is_atomic_or_rw {
|
||||||
|
typ = typ.set_flag(.atomic_or_rw)
|
||||||
|
}
|
||||||
if nr_muls > 0 {
|
if nr_muls > 0 {
|
||||||
typ = typ.set_nr_muls(nr_muls)
|
typ = typ.set_nr_muls(nr_muls)
|
||||||
}
|
}
|
||||||
|
|
|
@ -506,7 +506,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
||||||
.key_for {
|
.key_for {
|
||||||
return p.for_stmt()
|
return p.for_stmt()
|
||||||
}
|
}
|
||||||
.name, .key_mut, .key_static, .mul {
|
.name, .key_mut, .key_shared, .key_atomic, .key_rwshared, .key_static, .mul {
|
||||||
if p.tok.kind == .name {
|
if p.tok.kind == .name {
|
||||||
if p.tok.lit == 'sql' {
|
if p.tok.lit == 'sql' {
|
||||||
return p.sql_stmt()
|
return p.sql_stmt()
|
||||||
|
@ -750,7 +750,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
|
||||||
left0 := left[0]
|
left0 := left[0]
|
||||||
if p.tok.kind in [.assign, .decl_assign] || p.tok.kind.is_assign() {
|
if p.tok.kind in [.assign, .decl_assign] || p.tok.kind.is_assign() {
|
||||||
return p.partial_assign_stmt(left)
|
return p.partial_assign_stmt(left)
|
||||||
} else if is_top_level && tok.kind !in [.key_if, .key_match] &&
|
} else if is_top_level && tok.kind !in [.key_if, .key_match, .key_lock, .key_rlock] &&
|
||||||
left0 !is ast.CallExpr && left0 !is ast.PostfixExpr && !(left0 is ast.InfixExpr &&
|
left0 !is ast.CallExpr && left0 !is ast.PostfixExpr && !(left0 is ast.InfixExpr &&
|
||||||
(left0 as ast.InfixExpr).op == .left_shift) &&
|
(left0 as ast.InfixExpr).op == .left_shift) &&
|
||||||
left0 !is ast.ComptimeCall {
|
left0 !is ast.ComptimeCall {
|
||||||
|
@ -773,7 +773,9 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
|
||||||
|
|
||||||
pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
|
pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
|
||||||
// p.warn('name ')
|
// p.warn('name ')
|
||||||
is_mut := p.tok.kind == .key_mut
|
is_shared := p.tok.kind in [.key_shared, .key_rwshared]
|
||||||
|
is_atomic_or_rw := p.tok.kind in [.key_rwshared, .key_atomic]
|
||||||
|
is_mut := p.tok.kind == .key_mut || is_shared || is_atomic_or_rw
|
||||||
if is_mut {
|
if is_mut {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
|
@ -811,6 +813,7 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
|
||||||
info: ast.IdentVar{
|
info: ast.IdentVar{
|
||||||
is_mut: is_mut
|
is_mut: is_mut
|
||||||
is_static: is_static
|
is_static: is_static
|
||||||
|
share: table.sharetype_from_flags(is_shared, is_atomic_or_rw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||||
p.eat_comments()
|
p.eat_comments()
|
||||||
// Prefix
|
// Prefix
|
||||||
match p.tok.kind {
|
match p.tok.kind {
|
||||||
.key_mut, .key_static {
|
.key_mut, .key_shared, .key_rwshared, .key_atomic, .key_static {
|
||||||
node = p.name_expr()
|
node = p.name_expr()
|
||||||
p.is_stmt_ident = is_stmt_ident
|
p.is_stmt_ident = is_stmt_ident
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,9 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||||
.key_if {
|
.key_if {
|
||||||
node = p.if_expr()
|
node = p.if_expr()
|
||||||
}
|
}
|
||||||
|
.key_lock, .key_rlock {
|
||||||
|
node = p.lock_expr()
|
||||||
|
}
|
||||||
.lsbr {
|
.lsbr {
|
||||||
if p.expecting_type {
|
if p.expecting_type {
|
||||||
// parse json.decode type (`json.decode([]User, s)`)
|
// parse json.decode type (`json.decode([]User, s)`)
|
||||||
|
|
|
@ -41,6 +41,49 @@ pub enum TypeFlag {
|
||||||
optional
|
optional
|
||||||
variadic
|
variadic
|
||||||
generic
|
generic
|
||||||
|
shared_f
|
||||||
|
atomic_or_rw
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
To save precious TypeFlag bits the 4 possible ShareTypes are coded in the two
|
||||||
|
bits `shared` and `atomic_or_rw` (see sharetype_from_flags() below).
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub enum ShareType {
|
||||||
|
mut_t
|
||||||
|
shared_t
|
||||||
|
atomic_t
|
||||||
|
rwshared_t
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (t ShareType) str() string {
|
||||||
|
match t {
|
||||||
|
.mut_t { return 'mut' }
|
||||||
|
.shared_t { return 'shared' }
|
||||||
|
.atomic_t { return 'atomic' }
|
||||||
|
.rwshared_t { return 'rwshared' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// <atomic.h> defines special typenames
|
||||||
|
pub fn (t Type) atomic_typename() string {
|
||||||
|
idx := t.idx()
|
||||||
|
match idx {
|
||||||
|
u32_type_idx { return 'atomic_uint' }
|
||||||
|
int_type_idx { return 'atomic_int' }
|
||||||
|
u64_type_idx { return 'atomic_ullong' }
|
||||||
|
i64_type_idx { return 'atomic_llong' }
|
||||||
|
else { return 'unknown_atomic' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sharetype_from_flags(is_shared, is_atomic_or_rw bool) ShareType {
|
||||||
|
return ShareType((int(is_atomic_or_rw) << 1) | int(is_shared))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (t Type) share() ShareType {
|
||||||
|
return sharetype_from_flags(t.has_flag(.shared_f), t.has_flag(.atomic_or_rw))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (types []Type) contains(typ Type) bool {
|
pub fn (types []Type) contains(typ Type) bool {
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import sync
|
||||||
|
import time
|
||||||
|
|
||||||
|
struct St {
|
||||||
|
mut:
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (shared x St) f(shared y St, shared z St) {
|
||||||
|
for _ in 0..101 {
|
||||||
|
lock x, y {
|
||||||
|
tmp := y.a
|
||||||
|
y.a = x.a
|
||||||
|
x.a = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lock z {
|
||||||
|
z.a--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_shared_receiver_lock() {
|
||||||
|
shared x := &St{
|
||||||
|
a: 5
|
||||||
|
}
|
||||||
|
shared y := &St{
|
||||||
|
a: 7
|
||||||
|
}
|
||||||
|
shared z := &St{
|
||||||
|
a: 1
|
||||||
|
}
|
||||||
|
go x.f(shared y, shared z)
|
||||||
|
for _ in 0..100 {
|
||||||
|
lock x, y {
|
||||||
|
tmp := x.a
|
||||||
|
x.a = y.a
|
||||||
|
y.a = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the following would be a good application for a channel
|
||||||
|
for finished := false; ; {
|
||||||
|
lock z {
|
||||||
|
finished = z.a == 0
|
||||||
|
}
|
||||||
|
if finished {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.sleep_ms(100)
|
||||||
|
}
|
||||||
|
lock x, y {
|
||||||
|
assert x.a == 7 && y.a == 5
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
import sync
|
||||||
|
import time
|
||||||
|
|
||||||
|
struct St {
|
||||||
|
mut:
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(shared x St, shared y St, shared z St) {
|
||||||
|
for _ in 0..101 {
|
||||||
|
lock x, y {
|
||||||
|
tmp := y.a
|
||||||
|
y.a = x.a
|
||||||
|
x.a = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lock z {
|
||||||
|
z.a--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_shared_lock() {
|
||||||
|
shared x := &St{
|
||||||
|
a: 5
|
||||||
|
}
|
||||||
|
shared y := &St{
|
||||||
|
a: 7
|
||||||
|
}
|
||||||
|
shared z := &St{
|
||||||
|
a: 1
|
||||||
|
}
|
||||||
|
go f(shared x, shared y, shared z)
|
||||||
|
for _ in 0..100 {
|
||||||
|
lock x, y {
|
||||||
|
tmp := x.a
|
||||||
|
x.a = y.a
|
||||||
|
y.a = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the following would be a good application for a channel
|
||||||
|
for finished := false; ; {
|
||||||
|
lock z {
|
||||||
|
finished = z.a == 0
|
||||||
|
}
|
||||||
|
if finished {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.sleep_ms(100)
|
||||||
|
}
|
||||||
|
lock x, y {
|
||||||
|
assert x.a == 7 && y.a == 5
|
||||||
|
}
|
||||||
|
}
|
|
@ -108,6 +108,10 @@ pub enum Kind {
|
||||||
key_match
|
key_match
|
||||||
key_module
|
key_module
|
||||||
key_mut
|
key_mut
|
||||||
|
key_shared
|
||||||
|
key_rwshared
|
||||||
|
key_lock
|
||||||
|
key_rlock
|
||||||
key_none
|
key_none
|
||||||
key_return
|
key_return
|
||||||
key_select
|
key_select
|
||||||
|
@ -226,6 +230,10 @@ fn build_token_str() []string {
|
||||||
s[Kind.key_goto] = 'goto'
|
s[Kind.key_goto] = 'goto'
|
||||||
s[Kind.key_const] = 'const'
|
s[Kind.key_const] = 'const'
|
||||||
s[Kind.key_mut] = 'mut'
|
s[Kind.key_mut] = 'mut'
|
||||||
|
s[Kind.key_shared] = 'shared'
|
||||||
|
s[Kind.key_rwshared] = 'rwshared'
|
||||||
|
s[Kind.key_lock] = 'lock'
|
||||||
|
s[Kind.key_rlock] = 'rlock'
|
||||||
s[Kind.key_type] = 'type'
|
s[Kind.key_type] = 'type'
|
||||||
s[Kind.key_for] = 'for'
|
s[Kind.key_for] = 'for'
|
||||||
s[Kind.key_switch] = 'switch'
|
s[Kind.key_switch] = 'switch'
|
||||||
|
|
Loading…
Reference in New Issue