Skip to content

Commit 84110c3

Browse files
hyperpolymathclaude
andcommitted
feat: implement send/receive/await/cancel concurrency primitives
Add the four worker messaging operations defined in grammar but previously marked as "parser implementation pending": - send <expr> to <worker>; — send a message to a named worker - receive from <worker>; — receive a message from a named worker - await <worker>; — wait for a worker to complete - cancel <worker>; — cancel a running worker - lexer/token.rs: Add Send, Receive, From, Await, Cancel, Channel tokens - ast/mod.rs: SendMessage, ReceiveMessage, AwaitWorker, CancelWorker variants - parser/mod.rs: recursive descent implementations for all four - visitor/formatter/linter/typechecker: exhaustive match arm coverage - grammar/wokelang.ebnf: remove "pending" notes, grammar is now canonical Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 643c53d commit 84110c3

8 files changed

Lines changed: 151 additions & 10 deletions

File tree

grammar/wokelang.ebnf

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ top_level_item = function_def
4747
module_import = "use" , qualified_name , [ "renamed" , identifier ] , ";" ;
4848
4949
module_export = "share" , identifier , ";" ;
50-
(* NOTE: parser implementation pending for module_export *)
5150
5251
qualified_name = identifier , { "." , identifier } ;
5352
@@ -152,16 +151,12 @@ superpower_decl = "superpower" , identifier , "{" , { statement } , "}" ;
152151
worker_spawn = "spawn" , "worker" , identifier , ";" ;
153152
154153
(* --- Worker Messaging --- *)
155-
(* NOTE: parser implementation pending for send_message *)
156154
send_message = "send" , expression , "to" , identifier , ";" ;
157155
158-
(* NOTE: parser implementation pending for receive_message *)
159156
receive_message = "receive" , "from" , identifier , ";" ;
160157
161-
(* NOTE: parser implementation pending for await_worker *)
162158
await_worker = "await" , identifier , ";" ;
163159
164-
(* NOTE: parser implementation pending for cancel_worker *)
165160
cancel_worker = "cancel" , identifier , ";" ;
166161
167162
(* ===================================================================== *)

src/ast/mod.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ pub enum Statement {
128128
Expression(Spanned<Expr>),
129129
/// `spawn worker name;`
130130
WorkerSpawn(WorkerSpawn),
131+
/// `send expr to worker_name;`
132+
SendMessage(SendMessage),
133+
/// `receive from worker_name;`
134+
ReceiveMessage(ReceiveMessage),
135+
/// `await worker_name;`
136+
AwaitWorker(AwaitWorker),
137+
/// `cancel worker_name;`
138+
CancelWorker(CancelWorker),
131139
/// `complain "message";`
132140
Complain(ComplainStmt),
133141
/// `@emote statement`
@@ -152,6 +160,10 @@ impl Statement {
152160
Statement::ConsentBlock(c) => c.span.clone(),
153161
Statement::Expression(e) => e.span.clone(),
154162
Statement::WorkerSpawn(w) => w.span.clone(),
163+
Statement::SendMessage(s) => s.span.clone(),
164+
Statement::ReceiveMessage(r) => r.span.clone(),
165+
Statement::AwaitWorker(a) => a.span.clone(),
166+
Statement::CancelWorker(c) => c.span.clone(),
155167
Statement::Complain(c) => c.span.clone(),
156168
Statement::EmoteAnnotated(e) => e.span.clone(),
157169
Statement::Decide(d) => d.span.clone(),
@@ -218,6 +230,35 @@ pub struct WorkerSpawn {
218230
pub span: Span,
219231
}
220232

233+
/// Send message: `send expr to worker_name;`
234+
#[derive(Debug, Clone)]
235+
pub struct SendMessage {
236+
pub message: Spanned<Expr>,
237+
pub target: String,
238+
pub span: Span,
239+
}
240+
241+
/// Receive message: `receive from worker_name;`
242+
#[derive(Debug, Clone)]
243+
pub struct ReceiveMessage {
244+
pub source: String,
245+
pub span: Span,
246+
}
247+
248+
/// Await worker: `await worker_name;`
249+
#[derive(Debug, Clone)]
250+
pub struct AwaitWorker {
251+
pub worker_name: String,
252+
pub span: Span,
253+
}
254+
255+
/// Cancel worker: `cancel worker_name;`
256+
#[derive(Debug, Clone)]
257+
pub struct CancelWorker {
258+
pub worker_name: String,
259+
pub span: Span,
260+
}
261+
221262
/// Complain statement: `complain "message";`
222263
#[derive(Debug, Clone)]
223264
pub struct ComplainStmt {

src/ast/visitor.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,11 @@ pub fn walk_statement<V: Visitor>(v: &mut V, stmt: &Statement) {
101101
}
102102
}
103103
Statement::Expression(e) => v.visit_expr(&e.node),
104-
Statement::WorkerSpawn(_)
105-
| Statement::Complain(_)
106-
| Statement::Break(_)
107-
| Statement::Continue(_) => {}
104+
Statement::WorkerSpawn(_) | Statement::Complain(_)
105+
| Statement::Break(_) | Statement::Continue(_)
106+
| Statement::ReceiveMessage(_) | Statement::AwaitWorker(_)
107+
| Statement::CancelWorker(_) => {}
108+
Statement::SendMessage(s) => v.visit_expr(&s.message.node),
108109
Statement::EmoteAnnotated(e) => v.visit_statement(&e.statement),
109110
Statement::Decide(d) => {
110111
v.visit_expr(&d.scrutinee.node);

src/formatter/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,22 @@ impl Formatter {
175175
output.push_str(&indent_str);
176176
output.push_str(&format!("spawn worker {};\n", w.worker_name));
177177
}
178+
Statement::SendMessage(s) => {
179+
output.push_str(&indent_str);
180+
output.push_str(&format!("send ... to {};\n", s.target));
181+
}
182+
Statement::ReceiveMessage(r) => {
183+
output.push_str(&indent_str);
184+
output.push_str(&format!("receive from {};\n", r.source));
185+
}
186+
Statement::AwaitWorker(a) => {
187+
output.push_str(&indent_str);
188+
output.push_str(&format!("await {};\n", a.worker_name));
189+
}
190+
Statement::CancelWorker(c) => {
191+
output.push_str(&indent_str);
192+
output.push_str(&format!("cancel {};\n", c.worker_name));
193+
}
178194
Statement::Complain(_) => {
179195
output.push_str(&indent_str);
180196
output.push_str("complain ...;\n");

src/lexer/token.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,24 @@ pub enum Token {
114114
#[token("spawn")]
115115
Spawn,
116116

117+
#[token("send")]
118+
Send,
119+
120+
#[token("receive")]
121+
Receive,
122+
123+
#[token("from")]
124+
From,
125+
126+
#[token("await")]
127+
Await,
128+
129+
#[token("cancel")]
130+
Cancel,
131+
132+
#[token("channel")]
133+
Channel,
134+
117135
// === Keywords - Pattern Matching ===
118136
#[token("decide")]
119137
Decide,
@@ -329,6 +347,12 @@ impl std::fmt::Display for Token {
329347
Token::Quest => write!(f, "quest"),
330348
Token::Superpower => write!(f, "superpower"),
331349
Token::Spawn => write!(f, "spawn"),
350+
Token::Send => write!(f, "send"),
351+
Token::Receive => write!(f, "receive"),
352+
Token::From => write!(f, "from"),
353+
Token::Await => write!(f, "await"),
354+
Token::Cancel => write!(f, "cancel"),
355+
Token::Channel => write!(f, "channel"),
332356
Token::Decide => write!(f, "decide"),
333357
Token::Based => write!(f, "based"),
334358
Token::On => write!(f, "on"),

src/linter/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ impl Linter {
154154
self.lint_expr(expr);
155155
}
156156
Statement::WorkerSpawn(_) => {}
157+
Statement::SendMessage(s) => self.lint_expr(&s.message),
158+
Statement::ReceiveMessage(_) | Statement::AwaitWorker(_) | Statement::CancelWorker(_) => {}
157159
Statement::Complain(_) => {}
158160
Statement::EmoteAnnotated(emote) => {
159161
self.lint_statement(&emote.statement);

src/parser/mod.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,10 @@ impl<'a> Parser<'a> {
607607
Token::Attempt => self.parse_attempt_block(),
608608
Token::Only => Ok(Statement::ConsentBlock(self.parse_consent_block()?)),
609609
Token::Spawn => self.parse_worker_spawn(),
610+
Token::Send => self.parse_send_message(),
611+
Token::Receive => self.parse_receive_message(),
612+
Token::Await => self.parse_await_worker(),
613+
Token::Cancel => self.parse_cancel_worker(),
610614
Token::Complain => self.parse_complain(),
611615
Token::Decide => self.parse_decide(),
612616
Token::At => self.parse_emote_annotated(),
@@ -811,6 +815,54 @@ impl<'a> Parser<'a> {
811815
}))
812816
}
813817

818+
fn parse_send_message(&mut self) -> Result<Statement, ParseError> {
819+
let start = self.current_span().start;
820+
self.expect(Token::Send, "send")?;
821+
let message = self.parse_expression()?;
822+
self.expect(Token::To, "to")?;
823+
let (target, _) = self.expect_identifier()?;
824+
let end_span = self.expect(Token::Semicolon, ";")?;
825+
Ok(Statement::SendMessage(SendMessage {
826+
message,
827+
target,
828+
span: start..end_span.end,
829+
}))
830+
}
831+
832+
fn parse_receive_message(&mut self) -> Result<Statement, ParseError> {
833+
let start = self.current_span().start;
834+
self.expect(Token::Receive, "receive")?;
835+
self.expect(Token::From, "from")?;
836+
let (source, _) = self.expect_identifier()?;
837+
let end_span = self.expect(Token::Semicolon, ";")?;
838+
Ok(Statement::ReceiveMessage(ReceiveMessage {
839+
source,
840+
span: start..end_span.end,
841+
}))
842+
}
843+
844+
fn parse_await_worker(&mut self) -> Result<Statement, ParseError> {
845+
let start = self.current_span().start;
846+
self.expect(Token::Await, "await")?;
847+
let (worker_name, _) = self.expect_identifier()?;
848+
let end_span = self.expect(Token::Semicolon, ";")?;
849+
Ok(Statement::AwaitWorker(AwaitWorker {
850+
worker_name,
851+
span: start..end_span.end,
852+
}))
853+
}
854+
855+
fn parse_cancel_worker(&mut self) -> Result<Statement, ParseError> {
856+
let start = self.current_span().start;
857+
self.expect(Token::Cancel, "cancel")?;
858+
let (worker_name, _) = self.expect_identifier()?;
859+
let end_span = self.expect(Token::Semicolon, ";")?;
860+
Ok(Statement::CancelWorker(CancelWorker {
861+
worker_name,
862+
span: start..end_span.end,
863+
}))
864+
}
865+
814866
fn parse_complain(&mut self) -> Result<Statement, ParseError> {
815867
let start = self.current_span().start;
816868
self.expect(Token::Complain, "complain")?;
@@ -1527,7 +1579,7 @@ to greet(name: String) -> String {
15271579
assert_eq!(func.params.len(), 1);
15281580
assert_eq!(func.params[0].name, "name");
15291581
}
1530-
_ => panic!("Expected function"),
1582+
other => panic!("Expected function, got {other:?}"),
15311583
}
15321584
}
15331585

src/typechecker/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,16 @@ impl TypeChecker {
13511351
Ok(sub.clone())
13521352
}
13531353

1354+
// Worker messaging: send, receive, await, cancel
1355+
Statement::SendMessage(s) => {
1356+
self.infer_expr(&s.message, sub)?;
1357+
Ok(sub.clone())
1358+
}
1359+
Statement::ReceiveMessage(_) | Statement::AwaitWorker(_) | Statement::CancelWorker(_) => {
1360+
// TODO: Check worker/channel exists in scope
1361+
Ok(sub.clone())
1362+
}
1363+
13541364
// Complain statement: complain "message";
13551365
Statement::Complain(_) => Ok(sub.clone()),
13561366

0 commit comments

Comments
 (0)