Skip to content

Commit bc24d38

Browse files
authored
Merge pull request #5 from sravanioleti/fix/assignments-and-loops-1
feat: Implement 'bolte thak' loops and fix issue #1 (Value Assignments)Fix/assignments and loops 1
2 parents 9ca01ed + 8c1569d commit bc24d38

File tree

5 files changed

+188
-2
lines changed

5 files changed

+188
-2
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
*.exe
2+
*.exe~
3+
*.bak
4+
gola.exe
5+
tests.exe
6+
run_output.txt
7+
*.log

DOCUMENTATION.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,20 @@ Jay Shree Ram Bhai!
161161

162162
---
163163

164+
## New in Gola
165+
166+
### Variable Assignment Fix
167+
Assignments now support expressions on the right-hand side, correctly updating the variable:
168+
- `x = x + 5`
169+
170+
### Loop Statement (`bolte thak`)
171+
A basic file-mode loop is introduced. The loop header is followed by a single-line body on the next line:
172+
- **Syntax:** `bolte thak <iterator> [<start>] -> [<end>] [<increment>] :`
173+
- **Example:**
174+
```gola
175+
bolte thak i [0] -> [5] [i++] :
176+
kemon achis i
177+
164178
## Contributing
165179
Feel free to contribute to this project by submitting issues or pull requests to the GitHub repository.
166180

loop_test.gola

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// loop_test.gola - Example demonstrating new features
2+
3+
kemon achis "Testing Assignments and Loops"
4+
5+
x = 10
6+
x = x + 5 // Should now set x to 15
7+
kemon achis "x value is:"
8+
kemon achis x
9+
10+
// Loop from 0 to 5, printing the iterator
11+
bolte thak i [0] -> [5] [i++] :
12+
kemon achis i

main.go

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,52 @@ func NewInterpreter() *Interpreter {
2020

2121
// Execute parses and executes a single line of code
2222
func (i *Interpreter) Execute(line string) {
23+
// Remove inline comments starting with //
24+
if idx := strings.Index(line, "//"); idx != -1 {
25+
line = strings.TrimSpace(line[:idx])
26+
}
27+
// Normalize spacing around '=' so "x=x+5" also works
28+
line = strings.ReplaceAll(line, "=", " = ")
29+
2330
tokens := strings.Fields(line)
2431
if len(tokens) == 0 {
2532
return
2633
}
2734

35+
// Handle assignments like: x = 5 or x = y + 5 or x = "hello"
36+
if len(tokens) >= 3 && tokens[1] == "=" {
37+
varName := tokens[0]
38+
rhs := strings.Join(tokens[2:], " ")
39+
rhs = strings.TrimSpace(rhs)
40+
if rhs == "" {
41+
fmt.Println("bhul hoye gelo vai check kor ekbar: invalid assignment")
42+
return
43+
}
44+
// quoted string
45+
if strings.HasPrefix(rhs, "\"") && strings.HasSuffix(rhs, "\"") {
46+
i.variables[varName] = rhs[1 : len(rhs)-1]
47+
return
48+
}
49+
// try numeric expression
50+
rhsTokens := strings.Fields(rhs)
51+
if val, err := i.evaluateExpression(rhsTokens); err == nil {
52+
i.variables[varName] = val
53+
return
54+
}
55+
// try integer parse
56+
if v, err := strconv.Atoi(rhs); err == nil {
57+
i.variables[varName] = v
58+
return
59+
}
60+
// try variable lookup
61+
if value, ok := i.variables[rhs]; ok {
62+
i.variables[varName] = value
63+
return
64+
}
65+
fmt.Println("bhul hoye gelo vai check kor ekbar: invalid assignment")
66+
return
67+
}
68+
2869
switch tokens[0] {
2970
case "kemon":
3071
if len(tokens) < 3 || tokens[1] != "achis" {
@@ -118,6 +159,10 @@ func (i *Interpreter) Execute(line string) {
118159
}
119160

120161
func (i *Interpreter) evaluateExpression(tokens []string) (int, error) {
162+
if len(tokens) == 0 {
163+
return 0, fmt.Errorf("invalid expression")
164+
}
165+
121166
if len(tokens) == 1 {
122167
if value, ok := i.variables[tokens[0]]; ok {
123168
switch v := value.(type) {
@@ -211,6 +256,89 @@ func (i *Interpreter) getValue(token string) (int, error) {
211256
return 0, fmt.Errorf("unknown variable '%s'", token)
212257
}
213258

259+
// ExecuteLoop processes a loop header and executes the single-line body.
260+
// header: full header string (e.g., "bolte thak i [0] -> [10] [i++] :")
261+
// body: single-line loop body (e.g., "kemon achis i")
262+
func (i *Interpreter) ExecuteLoop(header, body string) {
263+
header = strings.TrimSpace(header)
264+
if strings.HasSuffix(header, ":") {
265+
header = strings.TrimSuffix(header, ":")
266+
}
267+
268+
// expected format: bolte thak <iter> [<start>] -> [<end>] [<incr>]
269+
parts := strings.Fields(header)
270+
if len(parts) < 4 {
271+
fmt.Println("bhul hoye gelo vai check kor ekbar: invalid loop syntax")
272+
return
273+
}
274+
// parts[0] = bolte, parts[1] = thak, parts[2] = iter
275+
iter := parts[2]
276+
277+
// find start and end between brackets
278+
startIdx := strings.Index(header, "[")
279+
endIdx := strings.Index(header, "]")
280+
if startIdx == -1 || endIdx == -1 || endIdx <= startIdx {
281+
fmt.Println("bhul hoye gelo vai check kor ekbar: invalid loop range")
282+
return
283+
}
284+
startStr := header[startIdx+1 : endIdx]
285+
286+
arrowIdx := strings.Index(header[endIdx:], "->")
287+
if arrowIdx == -1 {
288+
fmt.Println("bhul hoye gelo vai check kor ekbar: invalid loop arrow")
289+
return
290+
}
291+
292+
// find the next bracket after arrow
293+
rest := header[endIdx+arrowIdx:]
294+
nextOpen := strings.Index(rest, "[")
295+
nextClose := strings.Index(rest, "]")
296+
if nextOpen == -1 || nextClose == -1 {
297+
fmt.Println("bhul hoye gelo vai check kor ekbar: invalid loop end")
298+
return
299+
}
300+
endStr := rest[nextOpen+1 : nextClose]
301+
302+
// default increment = 1; check for optional increment bracket at end
303+
incr := 1
304+
// find last bracket content
305+
lastOpen := strings.LastIndex(header, "[")
306+
lastClose := strings.LastIndex(header, "]")
307+
if lastOpen != -1 && lastClose != -1 && lastClose > lastOpen {
308+
possible := header[lastOpen+1 : lastClose]
309+
// if possible contains ++ or += treat as increment
310+
if possible == iter+"++" || strings.Contains(possible, "++") {
311+
incr = 1
312+
} else if strings.Contains(possible, "+=") {
313+
parts := strings.Split(possible, "+=")
314+
if len(parts) == 2 {
315+
if v, err := strconv.Atoi(parts[1]); err == nil {
316+
incr = v
317+
}
318+
}
319+
}
320+
}
321+
322+
// parse start and end
323+
s, err1 := strconv.Atoi(strings.TrimSpace(startStr))
324+
e, err2 := strconv.Atoi(strings.TrimSpace(endStr))
325+
if err1 != nil || err2 != nil {
326+
fmt.Println("bhul hoye gelo vai check kor ekbar: invalid loop numeric values")
327+
return
328+
}
329+
330+
// run loop (support ascending only)
331+
if s <= e {
332+
for v := s; v <= e; v += incr {
333+
i.variables[iter] = v
334+
i.Execute(strings.TrimSpace(body))
335+
}
336+
return
337+
}
338+
339+
fmt.Println("bhul hoye gelo vai check kor ekbar: start greater than end not supported")
340+
}
341+
214342
func main() {
215343
version := flag.Bool("v", false, "Print the version")
216344
help := flag.Bool("h", false, "Display help")
@@ -244,8 +372,23 @@ func main() {
244372
interpreter := NewInterpreter()
245373
scanner := bufio.NewScanner(file)
246374
for scanner.Scan() {
247-
line := scanner.Text()
248-
interpreter.Execute(strings.TrimSpace(line))
375+
line := strings.TrimSpace(scanner.Text())
376+
// Skip blank lines and comment-only lines
377+
trimmed := strings.TrimSpace(line)
378+
if trimmed == "" || strings.HasPrefix(trimmed, "//") {
379+
continue
380+
}
381+
// If it's a loop header (file mode), read next line as body
382+
if strings.HasPrefix(trimmed, "bolte thak") {
383+
if scanner.Scan() {
384+
body := scanner.Text()
385+
interpreter.ExecuteLoop(trimmed, body)
386+
} else {
387+
fmt.Println("bhul hoye gelo vai check kor ekbar: loop header but no body")
388+
}
389+
continue
390+
}
391+
interpreter.Execute(line)
249392
}
250393
if err := scanner.Err(); err != nil {
251394
fmt.Printf("Error reading file '%s': %v\n", fileName, err)

test_loop_feature_1.gola

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
kemon achis "Testing Assignments and Loops"
2+
3+
x = 10
4+
x = x + 5 // Should now set x to 15
5+
kemon achis "x value is:"
6+
kemon achis x
7+
8+
// Loop from 0 to 5, printing the iterator
9+
bolte thak i [0] -> [5] [i++] :
10+
kemon achis i

0 commit comments

Comments
 (0)