Skip to content

Commit e269df2

Browse files
committed
feat: Add switch/select statement support and move helper to Guix
Implement comprehensive switch and select statement support in the Guix language, enabling native Go control flow for pattern matching and channel operations. Changes: - Add switch/select AST nodes (SwitchStmt, SelectStmt, CaseClause, CommClause, etc.) - Update parser to recognize switch, select, case, default keywords - Implement code generation for switch and select statements - Add visitor pattern support for all new AST nodes - Fix for-range loop generation for channels (use Key field for single variable) - Move StartCommandProcessor logic from Go helper to Guix goroutine - Remove app_helpers.go (functionality now in app.gx) The switch and select statements work exactly like Go: - switch cmd.Type { case "x": ... default: ... } - select { case ch <- val: ... case x := <-ch: ... default: ... } This change enables the webgpu-cube example to use a pure Guix implementation for command processing, demonstrating the full power of goroutines, channels, and control flow in the Guix DSL.
1 parent 36ae013 commit e269df2

9 files changed

Lines changed: 364 additions & 40 deletions

File tree

examples/webgpu-cube/app.gx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ func App() (Component) {
1212
controlState <- ControlState{AutoRotate: autoRotate, Speed: float32(speed)}
1313
}()
1414

15+
go func() {
16+
for cmd := range commands {
17+
switch cmd.Type {
18+
case "rotX":
19+
rotationX += float64(cmd.Value)
20+
case "rotY":
21+
rotationY += float64(cmd.Value)
22+
case "autoRotate":
23+
autoRotate = !autoRotate
24+
case "speed":
25+
speed = float64(cmd.Value)
26+
}
27+
28+
select {
29+
case controlState <- ControlState{AutoRotate: autoRotate, Speed: float32(speed)}:
30+
default:
31+
}
32+
}
33+
}()
34+
1535
Div(
1636
Class("webgpu-container"),
1737
TabIndex(0)
@@ -21,7 +41,7 @@ func App() (Component) {
2141
Width(600),
2242
Height(400)
2343
) {
24-
GPUScene(NewCubeScene(rotationX, rotationY))
44+
GPUScene(NewCubeScene(float32(rotationX), float32(rotationY)))
2545
}
2646
Controls(WithCommands(commands), WithState(controlState))
2747
}

examples/webgpu-cube/app_gen.go

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/webgpu-cube/app_helpers.go

Lines changed: 0 additions & 30 deletions
This file was deleted.

examples/webgpu-cube/main.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,6 @@ func main() {
2727
appComponent := NewApp()
2828
log("[Go] App created")
2929

30-
// Start command processor (uses hoisted variables from component)
31-
log("[Go] Starting command processor...")
32-
appComponent.StartCommandProcessor()
33-
log("[Go] Command processor started")
34-
3530
// Create runtime app
3631
log("[Go] Creating runtime app...")
3732
runtimeApp := runtime.NewApp(appComponent)

pkg/ast/ast.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ type BodyStatement struct {
9393
Return *Return `| @@`
9494
If *IfStmt `| @@`
9595
For *ForLoop `| @@`
96+
Switch *SwitchStmt `| @@` // Switch statement
97+
Select *SelectStmt `| @@` // Select statement
9698
GoStmt *GoStmt `| @@` // Goroutine statement
9799
Assignment *Assignment `| @@` // Deprecated
98100
CallStmt *CallStmt `| @@` // Last to minimize conflicts with Elements
@@ -272,6 +274,8 @@ type Statement struct {
272274
Return *Return `| @@`
273275
If *IfStmt `| @@`
274276
For *ForLoop `| @@`
277+
Switch *SwitchStmt `| @@` // Switch statement
278+
Select *SelectStmt `| @@` // Select statement
275279
GoStmt *GoStmt `| @@` // Goroutine statement
276280
Assignment *Assignment `| @@` // Deprecated: kept for backward compatibility
277281
Expr *Expr `| @@` // Deprecated: kept for backward compatibility
@@ -378,6 +382,62 @@ type GoStmt struct {
378382
Call bool `"(" ")"` // Function call
379383
}
380384

385+
// SwitchStmt represents a switch statement
386+
// Example: switch expr { case val1: stmts... case val2: stmts... default: stmts... }
387+
type SwitchStmt struct {
388+
Pos lexer.Position
389+
Expr *Expr `"switch" @@?` // Optional expression
390+
Cases []*CaseClause `"{" @@* "}"`
391+
}
392+
393+
// CaseClause represents a case or default clause in a switch statement
394+
type CaseClause struct {
395+
Pos lexer.Position
396+
Values []*Expr `("case" @@ ("," @@)*`
397+
Statements []*Statement `":" @@*)`
398+
Default bool `| ("default"`
399+
DefStmts []*Statement `":" @@*)`
400+
}
401+
402+
// SelectStmt represents a select statement for channel operations
403+
// Example: select { case x := <-ch: stmts... case ch <- val: stmts... default: stmts... }
404+
type SelectStmt struct {
405+
Pos lexer.Position
406+
Cases []*CommClause `"select" "{" @@* "}"`
407+
}
408+
409+
// CommClause represents a case or default clause in a select statement
410+
type CommClause struct {
411+
Pos lexer.Position
412+
Comm *CommCase `("case" @@`
413+
Statements []*Statement `":" @@*)`
414+
Default bool `| ("default"`
415+
DefStmts []*Statement `":" @@*)`
416+
}
417+
418+
// CommCase represents a channel send or receive operation in a select case
419+
type CommCase struct {
420+
Pos lexer.Position
421+
Send *SendStmt `@@`
422+
Recv *RecvStmt `| @@`
423+
}
424+
425+
// SendStmt represents a channel send operation
426+
// Example: ch <- value
427+
type SendStmt struct {
428+
Pos lexer.Position
429+
Channel string `@Ident "<-"`
430+
Value *Expr `@@`
431+
}
432+
433+
// RecvStmt represents a channel receive operation with optional assignment
434+
// Example: x := <-ch or <-ch
435+
type RecvStmt struct {
436+
Pos lexer.Position
437+
Names []string `(@Ident ("," @Ident)* ":=")?`
438+
Channel string `"<-" @Ident`
439+
}
440+
381441
// Return represents a return statement
382442
type Return struct {
383443
Pos lexer.Position
@@ -491,6 +551,13 @@ func (n *AssignmentStmt) Accept(v Visitor) interface{} { return v.VisitAssignmen
491551
func (n *VarDecl) Accept(v Visitor) interface{} { return v.VisitVarDecl(n) }
492552
func (n *Assignment) Accept(v Visitor) interface{} { return v.VisitAssignment(n) }
493553
func (n *GoStmt) Accept(v Visitor) interface{} { return v.VisitGoStmt(n) }
554+
func (n *SwitchStmt) Accept(v Visitor) interface{} { return v.VisitSwitchStmt(n) }
555+
func (n *CaseClause) Accept(v Visitor) interface{} { return v.VisitCaseClause(n) }
556+
func (n *SelectStmt) Accept(v Visitor) interface{} { return v.VisitSelectStmt(n) }
557+
func (n *CommClause) Accept(v Visitor) interface{} { return v.VisitCommClause(n) }
558+
func (n *CommCase) Accept(v Visitor) interface{} { return v.VisitCommCase(n) }
559+
func (n *SendStmt) Accept(v Visitor) interface{} { return v.VisitSendStmt(n) }
560+
func (n *RecvStmt) Accept(v Visitor) interface{} { return v.VisitRecvStmt(n) }
494561
func (n *Return) Accept(v Visitor) interface{} { return v.VisitReturn(n) }
495562
func (n *IfStmt) Accept(v Visitor) interface{} { return v.VisitIfStmt(n) }
496563
func (n *Else) Accept(v Visitor) interface{} { return v.VisitElse(n) }

pkg/ast/base_visitor.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ func (v *BaseVisitor) VisitBodyStatement(node *BodyStatement) interface{} {
113113
if node.For != nil {
114114
node.For.Accept(v)
115115
}
116+
if node.Switch != nil {
117+
node.Switch.Accept(v)
118+
}
119+
if node.Select != nil {
120+
node.Select.Accept(v)
121+
}
116122
if node.GoStmt != nil {
117123
node.GoStmt.Accept(v)
118124
}
@@ -145,6 +151,12 @@ func (v *BaseVisitor) VisitStatement(node *Statement) interface{} {
145151
if node.For != nil {
146152
node.For.Accept(v)
147153
}
154+
if node.Switch != nil {
155+
node.Switch.Accept(v)
156+
}
157+
if node.Select != nil {
158+
node.Select.Accept(v)
159+
}
148160
if node.GoStmt != nil {
149161
node.GoStmt.Accept(v)
150162
}
@@ -203,6 +215,70 @@ func (v *BaseVisitor) VisitGoStmt(node *GoStmt) interface{} {
203215
return nil
204216
}
205217

218+
func (v *BaseVisitor) VisitSwitchStmt(node *SwitchStmt) interface{} {
219+
if node.Expr != nil {
220+
node.Expr.Accept(v)
221+
}
222+
for _, caseClause := range node.Cases {
223+
caseClause.Accept(v)
224+
}
225+
return nil
226+
}
227+
228+
func (v *BaseVisitor) VisitCaseClause(node *CaseClause) interface{} {
229+
for _, val := range node.Values {
230+
val.Accept(v)
231+
}
232+
for _, stmt := range node.Statements {
233+
stmt.Accept(v)
234+
}
235+
for _, stmt := range node.DefStmts {
236+
stmt.Accept(v)
237+
}
238+
return nil
239+
}
240+
241+
func (v *BaseVisitor) VisitSelectStmt(node *SelectStmt) interface{} {
242+
for _, commClause := range node.Cases {
243+
commClause.Accept(v)
244+
}
245+
return nil
246+
}
247+
248+
func (v *BaseVisitor) VisitCommClause(node *CommClause) interface{} {
249+
if node.Comm != nil {
250+
node.Comm.Accept(v)
251+
}
252+
for _, stmt := range node.Statements {
253+
stmt.Accept(v)
254+
}
255+
for _, stmt := range node.DefStmts {
256+
stmt.Accept(v)
257+
}
258+
return nil
259+
}
260+
261+
func (v *BaseVisitor) VisitCommCase(node *CommCase) interface{} {
262+
if node.Send != nil {
263+
node.Send.Accept(v)
264+
}
265+
if node.Recv != nil {
266+
node.Recv.Accept(v)
267+
}
268+
return nil
269+
}
270+
271+
func (v *BaseVisitor) VisitSendStmt(node *SendStmt) interface{} {
272+
if node.Value != nil {
273+
node.Value.Accept(v)
274+
}
275+
return nil
276+
}
277+
278+
func (v *BaseVisitor) VisitRecvStmt(node *RecvStmt) interface{} {
279+
return nil
280+
}
281+
206282
func (v *BaseVisitor) VisitIfStmt(node *IfStmt) interface{} {
207283
if node.Cond != nil {
208284
node.Cond.Accept(v)

pkg/ast/visitor.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ type Visitor interface {
2525
VisitVarDecl(*VarDecl) interface{}
2626
VisitAssignment(*Assignment) interface{}
2727
VisitGoStmt(*GoStmt) interface{}
28+
VisitSwitchStmt(*SwitchStmt) interface{}
29+
VisitCaseClause(*CaseClause) interface{}
30+
VisitSelectStmt(*SelectStmt) interface{}
31+
VisitCommClause(*CommClause) interface{}
32+
VisitCommCase(*CommCase) interface{}
33+
VisitSendStmt(*SendStmt) interface{}
34+
VisitRecvStmt(*RecvStmt) interface{}
2835
VisitReturn(*Return) interface{}
2936
VisitIfStmt(*IfStmt) interface{}
3037
VisitElse(*Else) interface{}

0 commit comments

Comments
 (0)