Skip to content

Commit bf6c272

Browse files
committed
Add comprehensive language features for calculator example
- Add type definition support (type, struct) to AST and parser - Add binary expression support (==, !=, +, -, *, /, &&, ||, etc.) - Add unary expression support (!, -, +) - Add composite literal support for struct initialization - Add assignment to struct fields (selector on LHS) - Add BodyStatement type to distinguish component from regular function bodies - Add if/else statement generation in function bodies - Move all calculator functionality to Guix files (calculator.gx) - Use explicit return statements for regular functions
1 parent ac916dd commit bf6c272

4 files changed

Lines changed: 478 additions & 82 deletions

File tree

examples/calculator/calculator.gx

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
package main
22

3+
import "fmt"
4+
import "strconv"
5+
6+
type CalculatorState struct {
7+
Display string
8+
PreviousValue float64
9+
Operator string
10+
WaitingForOperand bool
11+
}
12+
313
func Calculator(stateChannel: chan CalculatorState) (Component) {
414
currentState := <-stateChannel
515

@@ -99,3 +109,93 @@ func Calculator(stateChannel: chan CalculatorState) (Component) {
99109
}
100110
}
101111
}
112+
113+
func handleNumber(stateChannel: chan CalculatorState, state: CalculatorState, digit: string) {
114+
if state.WaitingForOperand {
115+
state.Display = digit
116+
state.WaitingForOperand = false
117+
} else {
118+
if state.Display == "0" {
119+
state.Display = digit
120+
} else {
121+
state.Display = state.Display + digit
122+
}
123+
}
124+
125+
stateChannel <- state
126+
}
127+
128+
func handleOperator(stateChannel: chan CalculatorState, state: CalculatorState, operator: string) {
129+
displayValue, _ := strconv.ParseFloat(state.Display, 64)
130+
131+
if state.Operator != "" && !state.WaitingForOperand {
132+
result := calculate(state.PreviousValue, displayValue, state.Operator)
133+
state.Display = formatNumber(result)
134+
state.PreviousValue = result
135+
} else {
136+
state.PreviousValue = displayValue
137+
}
138+
139+
state.WaitingForOperand = true
140+
state.Operator = operator
141+
142+
stateChannel <- state
143+
}
144+
145+
func handleEquals(stateChannel: chan CalculatorState, state: CalculatorState) {
146+
if state.Operator == "" {
147+
stateChannel <- state
148+
} else {
149+
displayValue, _ := strconv.ParseFloat(state.Display, 64)
150+
result := calculate(state.PreviousValue, displayValue, state.Operator)
151+
152+
state.Display = formatNumber(result)
153+
state.Operator = ""
154+
state.WaitingForOperand = true
155+
state.PreviousValue = 0
156+
157+
stateChannel <- state
158+
}
159+
}
160+
161+
func handleClear(stateChannel: chan CalculatorState) {
162+
stateChannel <- CalculatorState{
163+
Display: "0",
164+
PreviousValue: 0,
165+
Operator: "",
166+
WaitingForOperand: false,
167+
}
168+
}
169+
170+
func calculate(a: float64, b: float64, operator: string) (float64) {
171+
result := b
172+
if operator == "+" {
173+
result = a + b
174+
} else if operator == "-" {
175+
result = a - b
176+
} else if operator == "*" {
177+
result = a * b
178+
} else if operator == "/" {
179+
if b != 0 {
180+
result = a / b
181+
} else {
182+
result = 0
183+
}
184+
}
185+
return result
186+
}
187+
188+
func formatNumber(num: float64) (string) {
189+
return fmt.Sprintf("%g", num)
190+
}
191+
192+
func NewCalculatorStateChannel() (chan CalculatorState) {
193+
ch := make(chan CalculatorState, 10)
194+
ch <- CalculatorState{
195+
Display: "0",
196+
PreviousValue: 0,
197+
Operator: "",
198+
WaitingForOperand: false,
199+
}
200+
return ch
201+
}

pkg/ast/ast.go

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,30 @@ type File struct {
1010
Pos lexer.Position
1111
Package string `"package" @Ident`
1212
Imports []*Import `@@*`
13+
Types []*TypeDef `@@*`
1314
Components []*Component `@@*`
1415
}
1516

17+
// TypeDef represents a type definition
18+
type TypeDef struct {
19+
Pos lexer.Position
20+
Name string `"type" @Ident`
21+
Struct *StructType `@@`
22+
}
23+
24+
// StructType represents a struct type definition
25+
type StructType struct {
26+
Pos lexer.Position
27+
Fields []*StructField `"struct" "{" @@* "}"`
28+
}
29+
30+
// StructField represents a field in a struct
31+
type StructField struct {
32+
Pos lexer.Position
33+
Name string `@Ident`
34+
Type *Type `@@`
35+
}
36+
1637
// Import represents an import statement
1738
type Import struct {
1839
Pos lexer.Position
@@ -50,12 +71,22 @@ type Type struct {
5071
FuncResults []*Type
5172
}
5273

53-
// Body represents a component body with optional variable declarations, assignments, and UI tree
74+
// Body represents a component body with optional variable declarations, statements, and UI tree
5475
type Body struct {
55-
Pos lexer.Position
56-
VarDecls []*VarDecl `"{" @@*`
57-
Assignments []*Assignment `@@*`
58-
Children []*Node `@@* "}"`
76+
Pos lexer.Position
77+
VarDecls []*VarDecl `"{" @@*`
78+
Statements []*BodyStatement `@@*`
79+
Children []*Node `@@* "}"`
80+
}
81+
82+
// BodyStatement represents a statement in a component body
83+
type BodyStatement struct {
84+
Pos lexer.Position
85+
VarDecl *VarDecl `@@`
86+
Assignment *Assignment `| @@`
87+
Return *Return `| @@`
88+
If *IfStmt `| @@`
89+
For *ForLoop `| @@`
5990
}
6091

6192
// Node represents any node in the component tree
@@ -93,15 +124,54 @@ type Prop struct {
93124
Value *Expr `"(" @@ ")"`
94125
}
95126

96-
// Expr represents an expression (simplified to avoid recursion)
127+
// Expr represents an expression with optional binary operations
97128
type Expr struct {
98-
Pos lexer.Position
99-
Literal *Literal `@@`
100-
MakeCall *MakeCall `| @@`
101-
CallOrSel *CallOrSelect `| @@`
102-
FuncLit *FuncLit `| @@`
103-
ChannelOp *ChannelOp `| @@`
104-
Ident string `| @Ident`
129+
Pos lexer.Position
130+
Left *Primary `@@`
131+
BinOps []*BinaryOp `@@*`
132+
}
133+
134+
// BinaryOp represents a binary operation (operator and right operand)
135+
type BinaryOp struct {
136+
Pos lexer.Position
137+
Op string `@("==" | "!=" | "<=" | ">=" | "<" | ">" | "&&" | "||" | "+" | "-" | "*" | "/")`
138+
Right *Primary `@@`
139+
}
140+
141+
// Primary represents a primary expression (operand in binary expressions)
142+
type Primary struct {
143+
Pos lexer.Position
144+
Unary *UnaryExpr ` @@`
145+
Literal *Literal `| @@`
146+
CompositeLit *CompositeLit `| @@`
147+
MakeCall *MakeCall `| @@`
148+
CallOrSel *CallOrSelect `| @@`
149+
FuncLit *FuncLit `| @@`
150+
ChannelOp *ChannelOp `| @@`
151+
Paren *Expr `| "(" @@ ")"`
152+
Ident string `| @Ident`
153+
}
154+
155+
// CompositeLit represents a composite literal (struct initialization)
156+
// Example: CalculatorState{Display: "0", PreviousValue: 0}
157+
type CompositeLit struct {
158+
Pos lexer.Position
159+
Type string `@Ident`
160+
Elements []*KeyValue `"{" (@@ ("," @@)*)? ","? "}"`
161+
}
162+
163+
// KeyValue represents a key-value pair in a composite literal
164+
type KeyValue struct {
165+
Pos lexer.Position
166+
Key string `@Ident ":"`
167+
Value *Expr `@@`
168+
}
169+
170+
// UnaryExpr represents a unary expression (e.g., !x, -x)
171+
type UnaryExpr struct {
172+
Pos lexer.Position
173+
Op string `@("!" | "-" | "+")`
174+
Right *Primary `@@`
105175
}
106176

107177
// Literal represents a literal value
@@ -167,18 +237,19 @@ type Statement struct {
167237
Pos lexer.Position
168238
VarDecl *VarDecl `@@`
169239
Assignment *Assignment `| @@`
170-
Expr *Expr `| @@`
171240
Return *Return `| @@`
172241
If *IfStmt `| @@`
173242
For *ForLoop `| @@`
243+
Expr *Expr `| @@`
174244
}
175245

176246
// Assignment represents an assignment statement
177247
type Assignment struct {
178-
Pos lexer.Position
179-
Left string `@Ident`
180-
Op string `@("<-" | ":=" | "=" | "+=" | "-=" | "*=" | "/=")`
181-
Right *Expr `@@`
248+
Pos lexer.Position
249+
Left string `@Ident`
250+
LeftSelector []string `("." @Ident)*`
251+
Op string `@("<-" | ":=" | "=" | "+=" | "-=" | "*=" | "/=")`
252+
Right *Expr `@@`
182253
}
183254

184255
// Return represents a return statement

0 commit comments

Comments
 (0)