Skip to content

Commit 32f9903

Browse files
committed
Add RESIZE and FREE with test cases.
1 parent 6363093 commit 32f9903

File tree

4 files changed

+129
-1
lines changed

4 files changed

+129
-1
lines changed

pkg/forth/builtin/02_core.f

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,11 @@
361361
: /- /-REM NIP ;
362362
: -REM /-REM DROP ;
363363

364+
\ memory allocation is automatic in go, so
365+
\ we don't need to manually free
366+
: FREE ( addr io )
367+
@ \ try reading from this address, this will be caught by
368+
\ the host if attempting to run on something not an address
369+
DROP 0 \ drop the result, return 0
370+
;
371+

pkg/forth/primitive.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ func PrimitiveSetup(vm *VirtualMachine) error {
614614
if err != nil {
615615
return JoinEntryError(err, entry, "could not parse name")
616616
}
617-
// get global
617+
// get global flag
618618
nGlobal, err := vm.Stack.PopNumber()
619619
if err != nil {
620620
return PopError(err, entry)
@@ -625,6 +625,7 @@ func PrimitiveSetup(vm *VirtualMachine) error {
625625
if err != nil {
626626
return PopError(err, entry)
627627
}
628+
// create the new data, defaulted to 0
628629
var de DictionaryEntry // note that we don't put this entry into the dictionary
629630
w := WordForth{
630631
Cells: make([]Cell, n),
@@ -633,6 +634,7 @@ func PrimitiveSetup(vm *VirtualMachine) error {
633634
for i := range w.Cells {
634635
w.Cells[i] = CellNumber{0}
635636
}
637+
// create the entry for it
636638
de = DictionaryEntry{
637639
Name: string(name),
638640
Word: &w,
@@ -641,14 +643,60 @@ func PrimitiveSetup(vm *VirtualMachine) error {
641643
GlobalData: global,
642644
},
643645
}
646+
// create the cell for it
644647
newCell := CellAddress{
645648
Offset: 0,
646649
Entry: &de,
647650
}
651+
// push the cell onto the stack
648652
err = vm.Stack.Push(newCell)
649653
if err != nil {
650654
return PushError(err, entry)
651655
}
656+
// push 0 onto the stack
657+
err = vm.Stack.Push(CellNumber{0})
658+
if err != nil {
659+
return PushError(err, entry)
660+
}
661+
return nil
662+
},
663+
},
664+
{
665+
name: "RESIZE",
666+
goFunc: func(vm *VirtualMachine, entry *DictionaryEntry) error {
667+
// get size
668+
n, err := vm.Stack.PopNumber() // the number of inputs
669+
if err != nil {
670+
return PopError(err, entry)
671+
}
672+
// get address
673+
cell, err := vm.Stack.Pop()
674+
if err != nil {
675+
return PopError(err, entry)
676+
}
677+
cellAddress, ok := cell.(CellAddress)
678+
if !ok {
679+
return EntryError(entry, "can only resize an address, got %s type %T", cellAddress, cellAddress)
680+
}
681+
w, ok := cellAddress.Entry.Word.(*WordForth)
682+
if !ok {
683+
return EntryError(entry, "can only resize forth data words found %s type %T", w, w)
684+
}
685+
// create the new data, defaulted to 0
686+
newCells := make([]Cell, n)
687+
for i := range newCells {
688+
newCells[i] = CellNumber{0}
689+
}
690+
// copy the data over
691+
copy(newCells, w.Cells)
692+
// attach the new data to the word
693+
w.Cells = newCells
694+
// push the same cell onto the stack
695+
err = vm.Stack.Push(cellAddress)
696+
if err != nil {
697+
return PushError(err, entry)
698+
}
699+
// push 0 onto the stack
652700
err = vm.Stack.Push(CellNumber{0})
653701
if err != nil {
654702
return PushError(err, entry)

pkg/forth/suite_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,46 @@ func TestSuite(t *testing.T) {
15091509
// 2ROT
15101510
// 2VALUE
15111511
// 2VARIABLE
1512+
1513+
{
1514+
name: "ALLOCATE",
1515+
setup: `
1516+
T{ 50 CELLS ALLOCATE SWAP addr ! -> 0 }T
1517+
T{ addr @ ALIGNED -> addr @ }T \ Test address is aligned
1518+
// T{ HERE -> datsp @ }T \ Check data space pointer is unaffected
1519+
addr @ 50 write-cell-mem
1520+
addr @ 50 check-cell-mem \ Check we can access the heap
1521+
T{ addr @ FREE -> 0 }T
1522+
1523+
T{ 99 ALLOCATE SWAP addr ! -> 0 }T
1524+
T{ addr @ ALIGNED -> addr @ }T \ Test address is aligned
1525+
T{ addr @ FREE -> 0 }T
1526+
// T{ HERE -> datsp @ }T \ Data space pointer unaffected by FREE
1527+
T{ -1 ALLOCATE SWAP DROP 0= -> <TRUE> }T \ Memory allocation works with max size
1528+
`,
1529+
},
1530+
{
1531+
name: "RESIZE",
1532+
setup: `
1533+
T{ 50 CHARS ALLOCATE SWAP addr ! -> 0 }T
1534+
addr @ 50 write-char-mem addr @ 50 check-char-mem
1535+
\ Resize smaller does not change content.
1536+
T{ addr @ 28 CHARS RESIZE SWAP addr ! -> 0 }T
1537+
addr @ 28 check-char-mem
1538+
1539+
\ Resize larger does not change original content.
1540+
T{ addr @ 100 CHARS RESIZE SWAP addr ! -> 0 }T
1541+
addr @ 28 check-char-mem
1542+
1543+
\ We can resize to the maximum size
1544+
T{ addr @ -1 RESIZE 0= -> addr @ <TRUE> }T
1545+
1546+
T{ addr @ FREE -> 0 }T
1547+
// T{ HERE -> datsp @ }T \ Data space pointer is unaffected
1548+
`,
1549+
code: ``,
1550+
},
1551+
// FREE does not have any tests
15121552
}
15131553

15141554
r := asm.Runner{}

pkg/forth/test/suite_test.f

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,36 @@
122122
\ ' EXIT CONSTANT 1ST
123123
T{ VARIABLE 1ST -> }T \ not the same as the test suite
124124

125+
VARIABLE addr
126+
VARIABLE datsp
127+
: write-char-mem ( address n -- )
128+
\ from 0 to n
129+
0 ?DO
130+
I OVER ( address i address )
131+
C! \ write i to address
132+
CHAR+ ( address+1 ) \ increment address
133+
LOOP
134+
DROP ( )
135+
;
136+
137+
: write-cell-mem ( address n -- )
138+
2* write-char-mem
139+
;
140+
141+
: check-char-mem ( address n -- )
142+
\ from 0 to n
143+
0 ?DO
144+
DUP C@ ( address value )
145+
I <> IF \ if the value isn't equal to loop count
146+
UNLOOP ." char-char-mem failed " DROP EXIT
147+
THEN
148+
CHAR+ ( address+1 )
149+
LOOP
150+
DROP
151+
;
152+
153+
: check-cell-mem
154+
2* check-char-mem
155+
;
156+
125157
RESET-TEST

0 commit comments

Comments
 (0)