endbasic-core 0.13.0

The EndBASIC programming language - core
Documentation
# Test: Produce and consume empty strings

## Source

```basic
s$ = ""
FOR i% = 1 TO 100000
    ' Produce a new string by _consuming_ an earlier one.
    s$ = s$ + ""
NEXT
OUT "success"
```

## Disassembly

```asm
0000:   LOADI       R64, 0              ; 1:6
0001:   LOADI       R65, 1              ; 2:10
0002:   MOVE        R66, R65            ; 2:5
0003:   LOADC       R67, 1              ; 2:15, 100000
0004:   CMPLEI      R66, R66, R67       ; 2:12
0005:   JMPF        R66, 15             ; 2:5
0006:   MOVE        R66, R64            ; 4:10
0007:   LOADI       R67, 0              ; 4:15
0008:   CONCAT      R66, R66, R67       ; 4:13
0009:   MOVE        R64, R66            ; 4:5
0010:   MOVE        R66, R65            ; 2:5
0011:   LOADI       R67, 1              ; 2:1
0012:   ADDI        R66, R66, R67       ; 2:12
0013:   MOVE        R65, R66            ; 2:5
0014:   JUMP        2                   ; 2:5
0015:   LOADI       R67, 2              ; 6:5
0016:   LOADI       R66, 259            ; 6:5
0017:   UPCALL      0, R66              ; 6:1, OUT
0018:   EOF                             ; 0:0
```

## Output

```plain
0=success$
```

# Test: Produce and consume non-empty strings

## Source

```basic
s$ = ""
FOR i% = 1 TO 100000
    ' Produce a new string by _consuming_ an earlier one.
    s$ = s$ + "x"
    ' But keep overall memory bounded.
    s$ = ""
NEXT
OUT "success"
```

## Disassembly

```asm
0000:   LOADI       R64, 0              ; 1:6
0001:   LOADI       R65, 1              ; 2:10
0002:   MOVE        R66, R65            ; 2:5
0003:   LOADC       R67, 1              ; 2:15, 100000
0004:   CMPLEI      R66, R66, R67       ; 2:12
0005:   JMPF        R66, 16             ; 2:5
0006:   MOVE        R66, R64            ; 4:10
0007:   LOADI       R67, 2              ; 4:15
0008:   CONCAT      R66, R66, R67       ; 4:13
0009:   MOVE        R64, R66            ; 4:5
0010:   LOADI       R64, 0              ; 6:10
0011:   MOVE        R66, R65            ; 2:5
0012:   LOADI       R67, 1              ; 2:1
0013:   ADDI        R66, R66, R67       ; 2:12
0014:   MOVE        R65, R66            ; 2:5
0015:   JUMP        2                   ; 2:5
0016:   LOADI       R67, 3              ; 8:5
0017:   LOADI       R66, 259            ; 8:5
0018:   UPCALL      0, R66              ; 8:1, OUT
0019:   EOF                             ; 0:0
```

## Runtime errors

```plain
4:13: Out of heap space
```

# Test: Recursive subroutine runs out of call stack

## Source

```basic
SUB recurse(n%)
    IF n < 5000 THEN
        recurse n + 1
    END IF
END SUB

recurse 0
OUT 123
```

## Disassembly

```asm
0000:   JUMP        10                  ; 1:5

;; RECURSE (BEGIN)
0001:   MOVE        R65, R64            ; 2:8
0002:   LOADI       R66, 5000           ; 2:12
0003:   CMPLTI      R65, R65, R66       ; 2:10
0004:   JMPF        R65, 9              ; 2:8
0005:   MOVE        R65, R64            ; 3:17
0006:   LOADI       R66, 1              ; 3:21
0007:   ADDI        R65, R65, R66       ; 3:19
0008:   CALL        R65, 1              ; 3:9, RECURSE
0009:   RETURN                          ; 5:1
;; RECURSE (END)

0010:   LOADI       R64, 0              ; 7:9
0011:   CALL        R64, 1              ; 7:1, RECURSE
0012:   LOADI       R65, 123            ; 8:5
0013:   LOADI       R64, 258            ; 8:5
0014:   UPCALL      0, R64              ; 8:1, OUT
0015:   EOF                             ; 0:0
```

## Runtime errors

```plain
3:9: Out of call stack space
```

# Test: Recursive GOSUB runs out of call stack

## Source

```basic
count% = 0
GOSUB @recurse
OUT 123

@recurse
count% = count% + 1
IF count < 5000 THEN GOSUB @recurse
RETURN
```

## Disassembly

```asm
0000:   LOADI       R64, 0              ; 1:10
0001:   GOSUB       5                   ; 2:7
0002:   LOADI       R66, 123            ; 3:5
0003:   LOADI       R65, 258            ; 3:5
0004:   UPCALL      0, R65              ; 3:1, OUT
0005:   MOVE        R65, R64            ; 6:10
0006:   LOADI       R66, 1              ; 6:19
0007:   ADDI        R65, R65, R66       ; 6:17
0008:   MOVE        R64, R65            ; 6:1
0009:   MOVE        R65, R64            ; 7:4
0010:   LOADI       R66, 5000           ; 7:12
0011:   CMPLTI      R65, R65, R66       ; 7:10
0012:   JMPF        R65, 14             ; 7:4
0013:   GOSUB       5                   ; 7:28
0014:   RETURN                          ; 8:1
0015:   EOF                             ; 0:0
```

## Runtime errors

```plain
7:28: Out of call stack space
```

# Test: ON ERROR GOTO can catch a stack overflow once

## Source

```basic
ON ERROR GOTO @handler
GOSUB @recurse
OUT 123
END

@recurse
count% = count% + 1
IF count% < 5000 THEN GOSUB @recurse
RETURN

@handler
OUT LAST_ERROR
```

## Disassembly

```asm
0000:   SETEH       JUMP, 16            ; 1:1
0001:   GOSUB       7                   ; 2:7
0002:   LOADI       R65, 123            ; 3:5
0003:   LOADI       R64, 258            ; 3:5
0004:   UPCALL      0, R64              ; 3:1, OUT
0005:   LOADI       R64, 0              ; 4:1
0006:   END         R64                 ; 4:1
0007:   MOVE        R64, R64            ; 7:10
0008:   LOADI       R65, 1              ; 7:19
0009:   ADDI        R64, R64, R65       ; 7:17
0010:   MOVE        R65, R64            ; 8:4
0011:   LOADI       R66, 5000           ; 8:13
0012:   CMPLTI      R65, R65, R66       ; 8:11
0013:   JMPF        R65, 15             ; 8:4
0014:   GOSUB       7                   ; 8:29
0015:   RETURN                          ; 9:1
0016:   UPCALL      1, R66              ; 12:5, LAST_ERROR
0017:   LOADI       R65, 259            ; 12:5
0018:   UPCALL      0, R65              ; 12:1, OUT
0019:   EOF                             ; 0:0
```

## Output

```plain
0=8:29: Out of call stack space$
```

# Test: ON ERROR GOTO must be re-armed after stack overflow

## Source

```basic
ON ERROR GOTO @handler1
GOSUB @recurse1
OUT 123
END

@recurse1
count1% = count1% + 1
IF count1% < 5000 THEN GOSUB @recurse1
RETURN

@handler1
OUT LAST_ERROR
ON ERROR GOTO @handler2
GOSUB @recurse2
END

@recurse2
count2% = count2% + 1
IF count2% < 5000 THEN GOSUB @recurse2
RETURN

@handler2
OUT LAST_ERROR
```

## Disassembly

```asm
0000:   SETEH       JUMP, 16            ; 1:1
0001:   GOSUB       7                   ; 2:7
0002:   LOADI       R65, 123            ; 3:5
0003:   LOADI       R64, 258            ; 3:5
0004:   UPCALL      0, R64              ; 3:1, OUT
0005:   LOADI       R64, 0              ; 4:1
0006:   END         R64                 ; 4:1
0007:   MOVE        R64, R64            ; 7:11
0008:   LOADI       R65, 1              ; 7:21
0009:   ADDI        R64, R64, R65       ; 7:19
0010:   MOVE        R65, R64            ; 8:4
0011:   LOADI       R66, 5000           ; 8:14
0012:   CMPLTI      R65, R65, R66       ; 8:12
0013:   JMPF        R65, 15             ; 8:4
0014:   GOSUB       7                   ; 8:30
0015:   RETURN                          ; 9:1
0016:   UPCALL      1, R66              ; 12:5, LAST_ERROR
0017:   LOADI       R65, 259            ; 12:5
0018:   UPCALL      0, R65              ; 12:1, OUT
0019:   SETEH       JUMP, 32            ; 13:1
0020:   GOSUB       23                  ; 14:7
0021:   LOADI       R65, 0              ; 15:1
0022:   END         R65                 ; 15:1
0023:   MOVE        R65, R65            ; 18:11
0024:   LOADI       R66, 1              ; 18:21
0025:   ADDI        R65, R65, R66       ; 18:19
0026:   MOVE        R66, R65            ; 19:4
0027:   LOADI       R67, 5000           ; 19:14
0028:   CMPLTI      R66, R66, R67       ; 19:12
0029:   JMPF        R66, 31             ; 19:4
0030:   GOSUB       23                  ; 19:30
0031:   RETURN                          ; 20:1
0032:   UPCALL      1, R67              ; 23:5, LAST_ERROR
0033:   LOADI       R66, 259            ; 23:5
0034:   UPCALL      0, R66              ; 23:1, OUT
0035:   EOF                             ; 0:0
```

## Output

```plain
0=8:30: Out of call stack space$
0=14:7: Out of call stack space$
```

# Test: ON ERROR GOTO is not reentrant after stack overflow

## Source

```basic
ON ERROR GOTO @handler
GOSUB @recurse1
OUT 123
END

@recurse1
count1% = count1% + 1
IF count1% < 5000 THEN GOSUB @recurse1
RETURN

@handler
OUT LAST_ERROR
GOSUB @recurse2
END

@recurse2
count2% = count2% + 1
IF count2% < 5000 THEN GOSUB @recurse2
RETURN
```

## Disassembly

```asm
0000:   SETEH       JUMP, 16            ; 1:1
0001:   GOSUB       7                   ; 2:7
0002:   LOADI       R65, 123            ; 3:5
0003:   LOADI       R64, 258            ; 3:5
0004:   UPCALL      0, R64              ; 3:1, OUT
0005:   LOADI       R64, 0              ; 4:1
0006:   END         R64                 ; 4:1
0007:   MOVE        R64, R64            ; 7:11
0008:   LOADI       R65, 1              ; 7:21
0009:   ADDI        R64, R64, R65       ; 7:19
0010:   MOVE        R65, R64            ; 8:4
0011:   LOADI       R66, 5000           ; 8:14
0012:   CMPLTI      R65, R65, R66       ; 8:12
0013:   JMPF        R65, 15             ; 8:4
0014:   GOSUB       7                   ; 8:30
0015:   RETURN                          ; 9:1
0016:   UPCALL      1, R66              ; 12:5, LAST_ERROR
0017:   LOADI       R65, 259            ; 12:5
0018:   UPCALL      0, R65              ; 12:1, OUT
0019:   GOSUB       22                  ; 13:7
0020:   LOADI       R65, 0              ; 14:1
0021:   END         R65                 ; 14:1
0022:   MOVE        R65, R65            ; 17:11
0023:   LOADI       R66, 1              ; 17:21
0024:   ADDI        R65, R65, R66       ; 17:19
0025:   MOVE        R66, R65            ; 18:4
0026:   LOADI       R67, 5000           ; 18:14
0027:   CMPLTI      R66, R66, R67       ; 18:12
0028:   JMPF        R66, 30             ; 18:4
0029:   GOSUB       22                  ; 18:30
0030:   RETURN                          ; 19:1
0031:   EOF                             ; 0:0
```

## Runtime errors

```plain
13:7: Out of call stack space
```

## Output

```plain
0=8:30: Out of call stack space$
```