Skip to content

Commit 27bd22c

Browse files
committed
Add VALUE 2VALUE TO FIND words.
1 parent 3bb16e1 commit 27bd22c

File tree

7 files changed

+160
-15
lines changed

7 files changed

+160
-15
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,9 +797,11 @@ Missing words may be implemented in the future.
797797
* `OF`
798798
* `PICK`
799799
* `ROLL`
800+
* `TO`
800801
* `TRUE`
801802
* `TUCK`
802803
* `U>`
804+
* `VALUE`
803805
* `WITHIN`
804806
* `[COMPILE]`
805807
* `\`
@@ -826,6 +828,7 @@ all can be in the future.
826828

827829
# Standard Double extension words
828830

831+
* `2VALUE`
829832
* `DU<`
830833

831834
# Optimizations

pkg/forth/builtin/01_compile.f

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
\ ' (tick) parses the next name and places the execution token of that name
2222
\ onto the stack.
23-
BL WORD ' --CREATE-FORTH ] BL WORD FIND-WORD EXIT [
23+
BL WORD ' --CREATE-FORTH ] BL WORD -1 FIND-WORD DROP EXIT [
2424

2525
\ POSTPONE parses the next name and compiles the compilation semantics of that word
2626
\ onto the latest word. Immediate.

pkg/forth/builtin/02_core.f

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,42 @@
210210
POSTPONE ;
211211
;
212212

213+
: VALUE
214+
1 ALLOCATE DROP
215+
SWAP OVER !
216+
:
217+
POSTPONE LITERAL
218+
POSTPONE @
219+
POSTPONE ;
220+
;
221+
222+
: TO
223+
' \ find the next word
224+
>BODY DUP \ get the first address
225+
DUP LAST-ADDRESS SWAP - 1+ \ find the length of this allocated space
226+
1 = IF \ if it's a VALUE
227+
STATE @ IF
228+
POSTPONE LITERAL POSTPONE !
229+
ELSE
230+
!
231+
THEN
232+
ELSE \ if it's a 2VALUE
233+
STATE @ IF
234+
DUP 1+
235+
POSTPONE LITERAL POSTPONE !
236+
POSTPONE LITERAL POSTPONE !
237+
ELSE
238+
SWAP OVER 1+
239+
!
240+
!
241+
THEN
242+
THEN
243+
; IMMEDIATE
244+
245+
: FIND ( caddr -- caddr 0 | xt 1 | xt -1 )
246+
FALSE FIND-WORD
247+
;
248+
213249
: ACTION-OF
214250
STATE @ IF
215251
POSTPONE ['] POSTPONE DEFER@

pkg/forth/builtin/03_double.f

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,18 @@
7979

8080
: 2VARIABLE 2 BUFFER: ;
8181
: GLOBAL-2VARIABLE 2 GLOBAL-BUFFER: ;
82+
83+
: 2VALUE ( x y "<spaces>name" -- )
84+
2 ALLOCATE DROP ( x y addr )
85+
SWAP OVER 1+ ( x addr y addr+1 )
86+
! ( x addr )
87+
SWAP OVER ( addr x addr )
88+
! ( addr )
89+
DUP 1+ SWAP ( addr+1 addr )
90+
:
91+
POSTPONE LITERAL
92+
POSTPONE @
93+
POSTPONE LITERAL
94+
POSTPONE @
95+
POSTPONE ;
96+
;

pkg/forth/primitive.go

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func PrimitiveSetup(vm *VirtualMachine) error {
7474
if !ok {
7575
return EntryError(entry, "requires an address cell")
7676
}
77-
name, err := countedCellsToString(cellAddr.Entry.Word.(*WordForth).Cells)
77+
name, err := addrToString(cellAddr)
7878
if err != nil {
7979
return JoinEntryError(err, entry, "could not parse name")
8080
}
@@ -169,7 +169,7 @@ func PrimitiveSetup(vm *VirtualMachine) error {
169169
if !ok {
170170
return EntryError(entry, "requires an address cell")
171171
}
172-
name, err := countedCellsToString(cellAddr.Entry.Word.(*WordForth).Cells)
172+
name, err := addrToString(cellAddr)
173173
if err != nil {
174174
return JoinEntryError(err, entry, "could not parse name")
175175
}
@@ -539,8 +539,13 @@ func PrimitiveSetup(vm *VirtualMachine) error {
539539
},
540540
},
541541
{
542-
name: "FIND-WORD",
542+
name: "FIND-WORD", // ( caddr errorIfMissing -- caddr 0 | xt 1 | xt -1 )
543543
goFunc: func(vm *VirtualMachine, entry *DictionaryEntry) error {
544+
num, err := vm.Stack.PopNumber()
545+
if err != nil {
546+
return PopError(err, entry)
547+
}
548+
errorIfMissing := num != 0
544549
cell, err := vm.Stack.Pop()
545550
if err != nil {
546551
return PopError(err, entry)
@@ -549,19 +554,39 @@ func PrimitiveSetup(vm *VirtualMachine) error {
549554
if !ok {
550555
return EntryError(entry, "requires an address cell")
551556
}
552-
name, err := countedCellsToString(cellAddr.Entry.Word.(*WordForth).Cells)
557+
name, err := addrToString(cellAddr)
553558
if err != nil {
554559
return JoinEntryError(err, entry, "could not convert input to string")
555560
}
556561
found, err := vm.Dictionary.FindName(string(name))
557-
if err != nil {
558-
return JoinEntryError(err, entry, "could not find name: %s", name)
562+
missing := err != nil
563+
if missing {
564+
if errorIfMissing {
565+
return JoinEntryError(err, entry, "could not find name: %s", name)
566+
}
567+
err = vm.Stack.Push(cellAddr)
568+
if err != nil {
569+
return PushError(err, entry)
570+
}
571+
err = vm.Stack.Push(CellNumber{0})
572+
if err != nil {
573+
return PushError(err, entry)
574+
}
575+
return nil
559576
}
560577
newCell := CellAddress{found, 0, false}
561578
err = vm.Stack.Push(newCell)
562579
if err != nil {
563580
return PushError(err, entry)
564581
}
582+
ret := -1
583+
if found.Flag.Immediate {
584+
ret = 1
585+
}
586+
err = vm.Stack.Push(CellNumber{uint16(ret)})
587+
if err != nil {
588+
return PushError(err, entry)
589+
}
565590
return nil
566591
},
567592
},
@@ -688,7 +713,7 @@ func PrimitiveSetup(vm *VirtualMachine) error {
688713
if !ok {
689714
return EntryError(entry, "requires a name")
690715
}
691-
name, err := countedCellsToString(cellAddr.Entry.Word.(*WordForth).Cells)
716+
name, err := addrToString(cellAddr)
692717
if err != nil {
693718
return JoinEntryError(err, entry, "could not parse name")
694719
}
@@ -2618,7 +2643,7 @@ func parseWord(vm *VirtualMachine, entry *DictionaryEntry) (string, error) {
26182643
if !ok {
26192644
return "", EntryError(entry, "name argument needs to be an address to a string")
26202645
}
2621-
name, err := countedCellsToString(cellAddr.Entry.Word.(*WordForth).Cells)
2646+
name, err := addrToString(cellAddr)
26222647
if err != nil {
26232648
return "", JoinEntryError(err, entry, "could not parse name")
26242649
}
@@ -2638,7 +2663,7 @@ func parseAssembly(vm *VirtualMachine, entry *DictionaryEntry) ([]string, error)
26382663
}
26392664
switch c := cell.(type) {
26402665
case CellAddress:
2641-
substr, err := countedCellsToString(c.Entry.Word.(*WordForth).Cells)
2666+
substr, err := addrToString(c)
26422667
if err != nil {
26432668
return nil, JoinEntryError(err, entry, "could not convert input to string")
26442669
}

pkg/forth/suite_test.go

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,17 @@ UNSIGNED: 0 FFFF
700700
T{ SEEBUF -> 20 20 20 }T
701701
`,
702702
},
703-
// FIND is not implemented
703+
{
704+
name: "FIND",
705+
setup: `
706+
HERE 3 C, CHAR G C, CHAR T C, CHAR 1 C, CONSTANT GT1STRING
707+
HERE 3 C, CHAR G C, CHAR T C, CHAR 2 C, CONSTANT GT2STRING
708+
HERE 3 ALLOT CONSTANT GT3STRING \ empty string size 3
709+
T{ GT1STRING FIND -> ' GT1 -1 }T
710+
T{ GT2STRING FIND -> ' GT2 1 }T
711+
T{ GT3STRING FIND -> GT3STRING 0 }T
712+
`,
713+
},
704714
// FM/MOD is not implemented
705715
// HERE see , ALLOT C,
706716
// HOLD is not implemented
@@ -1537,7 +1547,32 @@ func TestCoreExtensionSuite(t *testing.T) {
15371547
`,
15381548
},
15391549
// UNUSED not implemented
1540-
// VALUE not implemented
1550+
{
1551+
name: "VALUE",
1552+
setup: `
1553+
T{ 111 VALUE v1 -> }T
1554+
T{ -999 VALUE v2 -> }T
1555+
T{ : vd1 v1 ; -> }T
1556+
T{ : vd2 TO v2 ; -> }T
1557+
1558+
T{ 123 VALUE v3 -> }T
1559+
T{ v3 -> 123 }T
1560+
T{ 456 TO v3 -> }T
1561+
T{ v3 -> 456 }T
1562+
`,
1563+
code: `
1564+
T{ v1 -> 111 }T
1565+
T{ v2 -> -999 }T
1566+
T{ 222 TO v1 -> }T
1567+
T{ v1 -> 222 }T
1568+
T{ vd1 -> 222 }T
1569+
1570+
T{ v2 -> -999 }T
1571+
T{ -333 vd2 -> }T
1572+
T{ v2 -> -333 }T
1573+
T{ v1 -> 222 }T
1574+
`,
1575+
},
15411576
// WITHIN does not have test cases
15421577
{
15431578
name: "[COMPILE]",
@@ -1854,7 +1889,24 @@ func TestDoubleSuite(t *testing.T) {
18541889
func TestDoubleExtensionSuite(t *testing.T) {
18551890
tests := []suiteTest{
18561891
// 2ROT not implemented
1857-
// 2VALUE not implemented
1892+
{
1893+
name: "2VALUE",
1894+
setup: `
1895+
T{ 1 2 2VALUE t2val -> }T
1896+
: sett2val t2val 2SWAP TO t2val ;
1897+
1898+
T{ 1 2 2VALUE t2val2 -> }T
1899+
T{ t2val2 -> 1 2 }T
1900+
T{ 3 4 to t2val2 -> }T
1901+
T{ t2val2 -> 3 4 }T
1902+
`,
1903+
code: `
1904+
T{ t2val -> 1 2 }T
1905+
T{ 3 4 TO t2val -> }T
1906+
T{ t2val -> 3 4 }T
1907+
T{ 5 6 sett2val t2val -> 3 4 5 6 }T
1908+
`,
1909+
},
18581910
{
18591911
name: "DU<",
18601912
code: `

pkg/forth/utils.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,25 @@ func cellsToBytes(cells []Cell) ([]byte, error) {
5151
return out, nil
5252
}
5353

54-
func countedCellsToString(cells []Cell) (string, error) {
55-
bytes, err := cellsToBytes(cells)
54+
func addrToString(addr CellAddress) (string, error) {
55+
word, ok := addr.Entry.Word.(*WordForth)
56+
if !ok {
57+
return "", fmt.Errorf("can only read string of forth word found %T", addr.Entry.Word)
58+
}
59+
cells := word.Cells
60+
offset := addr.Offset
61+
upper := addr.UpperByte
62+
return countedCellsToString(cells, offset, upper)
63+
}
64+
65+
func countedCellsToString(cells []Cell, offset int, upper bool) (string, error) {
66+
bytes, err := cellsToBytes(cells[offset:])
5667
if err != nil {
5768
return "", err
5869
}
70+
if upper {
71+
bytes = bytes[1:]
72+
}
5973
length := bytes[0]
6074
return bytesToString(bytes[1:], int(length))
6175
}

0 commit comments

Comments
 (0)