M internal/generator/visitor.go => internal/generator/visitor.go +7 -7
@@ 104,7 104,7 @@ func (v *RhumbVisitor) VisitLabelLiteral(ctx *P.LabelLiteralContext) interface{}
logger.Println("label:", text)
v.vm.WriteCodeToMain(
ctx.GetStart().GetLine(),
- word.FromAddress(int(ra.Id())),
+ word.FromAddress(ra.Id()),
vm.NewLocalRequest,
)
return v.VisitChildren(ctx)
@@ 127,7 127,7 @@ func (v *RhumbVisitor) VisitAssignment(ctx *P.AssignmentContext) interface{} {
v.vm.WriteCodeToMain(
addr.GetLine(),
- word.FromAddress(int(ra.Id())),
+ word.FromAddress(ra.Id()),
vm.NewLocalRequest,
)
} else {
@@ 139,7 139,7 @@ func (v *RhumbVisitor) VisitAssignment(ctx *P.AssignmentContext) interface{} {
ra = vm.NewRuneArray(&v.vm, word.FromAddress(0), []rune(text)...)
v.vm.WriteCodeToMain(
addrRef.GetStart().GetLine(),
- word.FromAddress(int(ra.Id())),
+ word.FromAddress(ra.Id()),
vm.NewLocalRequest,
)
}
@@ 155,7 155,7 @@ func (v *RhumbVisitor) VisitAssignment(ctx *P.AssignmentContext) interface{} {
)
v.vm.WriteCodeToMain(
op.GetStart().GetLine(),
- word.FromAddress(int(ra.Id())),
+ word.FromAddress(ra.Id()),
vm.NewOuterRequest,
)
return nil
@@ 240,7 240,7 @@ func (v *RhumbVisitor) VisitMultiplicative(ctx *P.MultiplicativeContext) interfa
v.vm.WriteCodeToMain(
mulOp.GetStart().GetLine(),
- word.FromAddress(int(ra.Id())),
+ word.FromAddress(ra.Id()),
vm.NewOuterRequest, // FIXME: re-implement as NewInnerRequest
)
return nil
@@ 264,7 264,7 @@ func (v *RhumbVisitor) VisitAdditive(ctx *P.AdditiveContext) interface{} {
v.vm.WriteCodeToMain(
addOp.GetStart().GetLine(),
- word.FromAddress(int(ra.Id())),
+ word.FromAddress(ra.Id()),
vm.NewOuterRequest, // FIXME: re-implement as NewInnerRequest
)
return nil
@@ 321,7 321,7 @@ func (v *RhumbVisitor) VisitPower(ctx *P.PowerContext) interface{} {
}
v.vm.WriteCodeToMain(
powOp.GetStart().GetLine(),
- word.FromAddress(int(ra.Id())),
+ word.FromAddress(ra.Id()),
vm.NewOuterRequest, // FIXME: re-implement as NewInnerRequest
)
return nil
M internal/vm/chunk.go => internal/vm/chunk.go +18 -19
@@ 26,8 26,8 @@ func NewChunk(vm *VirtualMachine) Chunk {
wa WordArray = NewWordArray(vm, word.FromAddress(0))
)
ch[0] = word.Word(word.CMP_UNIT)
- ch[1] = word.FromAddress(int(ca.id))
- ch[2] = word.FromAddress(int(wa.id))
+ ch[1] = word.FromAddress(ca.id)
+ ch[2] = word.FromAddress(wa.id)
id, err := vm.ReAllocate(ch[:]...)
if err != nil {
panic("failed to reallocate onto heap")
@@ 59,25 59,26 @@ func (ch *Chunk) WriteCode(vm *VirtualMachine, line int, codes []Code) {
}
func (ch Chunk) SetInstructionsAddress(vm *VirtualMachine, addr uint64) {
- vm.heap[ch.id+chunk_ca_offset] = word.FromAddress(int(addr))
+ vm.heap[ch.id+chunk_ca_offset] = word.FromAddress(addr)
}
func (ch Chunk) SetLiteralsAddress(vm *VirtualMachine, addr uint64) {
- vm.heap[ch.id+chunk_wa_offset] = word.FromAddress(int(addr))
+ vm.heap[ch.id+chunk_wa_offset] = word.FromAddress(addr)
}
func (ch *Chunk) AddLiteral(vm *VirtualMachine, lit word.Word) (uint64, error) {
literals := ch.ReviveLits(vm)
existingIndex, err := literals.IndexOf(vm, lit)
if err != nil {
- id, err := literals.Append(vm, lit)
+ waID, err := literals.Append(vm, lit)
if err != nil {
panic("literals append failed")
}
- if id != ch.Literals(vm).AsAddr() {
- ch.SetLiteralsAddress(vm, id)
+ if waID != ch.Literals(vm).AsAddr() {
+ ch.SetLiteralsAddress(vm, waID)
}
- return id, err
+ newLastID := uint64(literals.Length(vm)) - 1
+ return newLastID, err
} else {
return uint64(existingIndex), nil
}
@@ 131,12 132,8 @@ func (ch Chunk) Execute(vm *VirtualMachine) {
}
}
-func (ch Chunk) execTagIndex(vm *VirtualMachine, b byte, idx int) {
- var (
- code Code = Code(b)
- tag uint8 = code.Tag()
- literals = ch.ReviveLits(vm)
- )
+func (ch Chunk) execTagIndex(vm *VirtualMachine, tag byte, idx int) {
+ literals := ch.ReviveLits(vm)
fmt.Println("Executing chunk tag:", tag)
switch tag {
case TAG_VALUE_LITERAL:
@@ 149,10 146,12 @@ func (ch Chunk) execTagIndex(vm *VirtualMachine, b byte, idx int) {
vm.SubmitUnderRequest(literals.Get(vm, idx))
case TAG_OUTER_REQUEST:
vm.SubmitOuterRequest(literals.Get(vm, idx))
- // case TAG_EVENT_REQUEST:
- // vm.SubmitEventRequest(literals.Get(idx))
- // case TAG_REPLY_REQUEST:
- // vm.SubmitReplyRequest(literals.Get(idx))
+ // case TAG_EVENT_REQUEST:
+ // vm.SubmitEventRequest(literals.Get(idx))
+ // case TAG_REPLY_REQUEST:
+ // vm.SubmitReplyRequest(literals.Get(idx))
+ default:
+ panic("not a valid tag")
}
}
@@ 188,7 187,7 @@ func (ch Chunk) DisassembleCode(vm *VirtualMachine, currentLine, currentOffset i
}
default:
idx := uint32(i + int(Code(buf[o]).Index()))
- fmt.Printf("%s %d '%v'\n",
+ fmt.Printf("%s %d %v\n",
Code(buf[o]).String(),
idx,
ch.ReviveLits(vm).Get(vm, int(idx)).Debug(),
M internal/vm/code_array.go => internal/vm/code_array.go +28 -22
@@ 119,27 119,33 @@ func (ca *CodeArray) SetCodes(
cs ...Code,
) {
var (
- origLen uint64 = uint64(ca.Length(vm))
- newLen uint32 = uint32(len(cs))
- byteSz uint32 = 8
- codeID int
- code Code
- initSz uint32
- bs []byte = make([]byte, 0, byteSz)
- ws []word.Word = make([]word.Word, 0, newLen/8)
- lastWord word.Word = vm.heap[ca.id+uint64(ca.Size(vm))-1]
+ origLen uint64 = uint64(ca.Length(vm))
+ origSz uint32 = uint32(ca.Size(vm))
+ newLen uint32 = uint32(len(cs))
+ byteSz uint32 = 8
+ codeID int
+ code Code
+ initSz uint32
+ bs []byte = make([]byte, 0, byteSz)
+ ws []word.Word = make([]word.Word, 0, newLen/8)
+ lastWordID uint64 = ca.id + uint64(ca.Size(vm)) - 1
)
if newLine {
ws = append(ws, word.Sentinel())
} else {
if ca.lastWordVacancy(vm) {
- ca.getCodesFromWord(vm, lastWord, &bs)
+ ca.getCodesFromWord(vm, vm.heap[lastWordID], &bs)
+ vm.free[lastWordID] = true
+ origSz--
initSz = uint32(len(bs))
- for codeID, code = range cs {
+ tempCS := make([]Code, len(cs))
+ copy(tempCS, cs)
+ for codeID, code = range tempCS {
bs = append(bs, byte(code))
+ cs = cs[codeID+1:] // shift from main cs var
if initSz+uint32(codeID)+1 == byteSz {
- vm.heap[ca.id+ca.Size(vm)] = word.Word(
- binary.BigEndian.Uint64(bs))
+ ws = append(ws,
+ word.Word(binary.BigEndian.Uint64(bs)))
bs = make([]byte, 0, byteSz)
break
}
@@ 160,15 166,16 @@ func (ca *CodeArray) SetCodes(
for range bs[len(bs):byteSz] {
bs = append(bs, 0x0)
}
- ws = append(ws, word.Word(binary.BigEndian.Uint64(bs)))
+ bsWord := word.Word(binary.BigEndian.Uint64(bs))
+ ws = append(ws, bsWord)
}
wordsLen := uint32(len(ws))
- finalLength := uint32(origLen) + wordsLen
- ca.SetSize(vm, finalLength+4)
- ca.SetLength(vm, wordsLen)
+ finalLength := uint32(origLen) + newLen
+ ca.SetSize(vm, origSz+wordsLen)
+ ca.SetLength(vm, finalLength)
newId, _ := vm.Allocate(
int(ca.id),
- int(origLen)+int(code_arr_offset),
+ int(origSz),
ws...,
)
if newId != ca.id {
@@ 179,9 186,8 @@ func (ca *CodeArray) SetCodes(
func (ca *CodeArray) lastWordVacancy(vm *VirtualMachine) bool {
var (
- lastIndex uint64 = uint64(ca.Length(vm) - 1)
- id uint64 = ca.id + code_arr_offset + lastIndex
- word word.Word = vm.heap[id]
+ lastIndex uint64 = uint64(ca.Size(vm) - 1)
+ word word.Word = vm.heap[ca.id+lastIndex]
)
if word.IsSentinel() {
return false
@@ 230,7 236,7 @@ func (ca CodeArray) getWordCodeCount(vm *VirtualMachine, word word.Word) (count
func (ca CodeArray) GetCodes(vm *VirtualMachine) []byte {
var (
- cwLen uint64 = uint64(ca.Length(vm))
+ cwLen uint64 = uint64(ca.Size(vm))
buf []byte = make([]byte, 0, cwLen*8)
)
for wIndex := code_arr_offset; wIndex < cwLen; wIndex++ {
M internal/vm/primitives.go => internal/vm/primitives.go +1 -1
@@ 90,7 90,7 @@ func (vm *VirtualMachine) expTwoInts() {
// New scope and add a sentinel to the stack
func (vm *VirtualMachine) beginRoutine() {
- vm.scope = append(vm.scope, make(map[string]int))
+ vm.scope = append(vm.scope, make(map[string]uint64))
vm.stack = append(vm.stack, word.Sentinel())
}
M internal/vm/rune_array.go => internal/vm/rune_array.go +25 -23
@@ 47,35 47,33 @@ func NewRuneArray(
) RuneArray {
var (
runesLen uint32 = uint32(len(runes))
- runesSize uint32 = uint32(code_arr_offset) + runesLen
- raWords []word.Word = make([]word.Word, 0, runesSize)
+ runesRem uint32 = uint32(runesLen % 2)
+ runesCap uint32 = uint32(code_arr_offset) + (runesLen / 2) + runesRem
+ raWords []word.Word = make([]word.Word, 0, runesCap)
runeBytes []byte
wordBytes []byte
- offset uint32
)
raWords = append(raWords,
/* Mark: */ word.Word(word.RUNE_ARR),
/* Legend: */ legAddr,
- /* Size: */ word.FromInt(runesSize),
+ /* Size: */ word.FromInt(runesCap),
/* Length: */ word.FromInt(runesLen),
)
wordBytes = make([]byte, 8)
for i, r := range runes {
- offset = uint32(i) % 2
runeBytes = make([]byte, 4)
binary.LittleEndian.PutUint32(runeBytes, uint32(r))
- if offset == 0 {
+ if i%2 == 0 {
copy(wordBytes, runeBytes)
if i == len(runes)-1 {
- raWords = append(raWords,
- word.Word(binary.LittleEndian.Uint64(wordBytes)))
+ newWord := word.Word(binary.BigEndian.Uint64(wordBytes))
+ raWords = append(raWords, word.Word(newWord))
}
} else {
- for i, rb := range runeBytes {
- wordBytes[i+4] = rb
- }
- raWords = append(raWords,
- word.Word(binary.LittleEndian.Uint64(wordBytes)))
+ copy(wordBytes[4:], runeBytes)
+ newWord := word.Word(binary.BigEndian.Uint64(wordBytes))
+ raWords = append(raWords, newWord)
+ wordBytes = make([]byte, 8)
}
}
@@ 91,21 89,20 @@ func NewRuneArray(
// }
-func ReviveRuneArray(vm *VirtualMachine, addr word.Word) RuneArray {
- i := addr.AsAddr()
- mark := vm.heap[i]
+func ReviveRuneArray(vm *VirtualMachine, addr uint64) RuneArray {
+ mark := vm.heap[addr]
if !(mark.IsRuneArrayMark()) {
panic("not a rune array mark")
}
- legend := vm.heap[i+rune_lgd_offset]
+ legend := vm.heap[addr+rune_lgd_offset]
if !(legend.IsAddress()) {
panic("rune array legend word is not an address")
}
- size := vm.heap[i+rune_sze_offset]
+ size := vm.heap[addr+rune_sze_offset]
if !(size.IsInteger()) {
panic("rune array object size word is not an integer")
}
- return RuneArray{i}
+ return RuneArray{addr}
}
func (ra RuneArray) Id() uint64 { return ra.id }
@@ 120,12 117,17 @@ func (ra RuneArray) Length(vm *VirtualMachine) uint32 {
return vm.heap[ra.id+rune_len_offset].AsInt()
}
func (ra RuneArray) Runes(vm *VirtualMachine) []rune {
- buf := make([]rune, 0, ra.Length(vm))
- for i := range vm.heap[ra.id+rune_arr_offset:] {
+ raLen := uint64(ra.Length(vm))
+ buf := make([]rune, 0, raLen)
+ start := ra.id + rune_arr_offset
+ for i := range vm.heap[start : ra.id+ra.Size(vm)] {
bytes := make([]byte, 8)
- binary.LittleEndian.PutUint64(bytes, uint64(vm.heap[ra.id+uint64(i)]))
+ binary.BigEndian.PutUint64(bytes, uint64(vm.heap[start+uint64(i)]))
buf = append(buf, rune(binary.LittleEndian.Uint32(bytes[:4])))
- buf = append(buf, rune(binary.LittleEndian.Uint32(bytes[4:])))
+ secondRune := rune(binary.LittleEndian.Uint32(bytes[4:]))
+ if secondRune != 0 {
+ buf = append(buf, secondRune)
+ }
}
return buf
}
M internal/vm/vm.go => internal/vm/vm.go +82 -33
@@ 21,18 21,64 @@ type VirtualMachine struct {
heap []word.Word
free []bool
stack []word.Word
- scope []map[string]int
+ scope []map[string]uint64
main Chunk
}
+var DEBUG_WIDTH int = 10
+
+func incCheckNL(inc *int) {
+ val := *inc
+ val++
+ if val%DEBUG_WIDTH == 0 {
+ fmt.Println()
+ }
+ *inc = val
+}
+
func (vm VirtualMachine) DebugHeap() {
- width := 4
- for i := range vm.heap {
- if i%width == 0 {
+ for i := 0; i < len(vm.heap); i++ {
+ if i%DEBUG_WIDTH == 0 {
fmt.Println()
}
if vm.free[i] {
fmt.Printf("{%3v: }", i)
+ } else if vm.heap[i].IsRuneArrayMark() {
+ j := i
+ fmt.Printf("[%3v: %-9s ]", j, vm.heap[j].Debug())
+ incCheckNL(&j)
+ fmt.Printf("[%3v: %-9s ]", j, vm.heap[j].Debug())
+ incCheckNL(&j)
+ fmt.Printf("[%3v: %-9s ]", j, vm.heap[j].Debug())
+ incCheckNL(&j)
+ fmt.Printf("[%3v: %-9s ]", j, vm.heap[j].Debug())
+ incCheckNL(&j)
+ fmt.Printf("[%3v: ", j)
+ ra := ReviveRuneArray(&vm, uint64(i))
+ runes := ra.Runes(&vm)
+ if len(runes) <= 2 {
+ for _, r := range runes {
+ fmt.Printf("'%s'", string(r))
+ fmt.Print(" ")
+ }
+ } else {
+ for i, r := range runes {
+ fmt.Printf("'%s'", string(r))
+ if i%2 == 1 {
+ fmt.Print(" |")
+ incCheckNL(&j)
+ fmt.Print("| ")
+ } else {
+ fmt.Print(" ")
+ }
+ }
+ for range make([]int, (ra.Length(&vm) % 2)) {
+ fmt.Print(" ")
+ }
+
+ }
+ fmt.Print("]")
+ i += int(ra.Size(&vm)) - 1
} else {
fmt.Printf("[%3v: %-9s ]", i, vm.heap[i].Debug())
}
@@ 47,8 93,8 @@ func NewVirtualMachine() *VirtualMachine {
vm.free = make([]bool, 0, init_heap_len)
vm.ReAllocate(word.Word(word.SENTINEL))
vm.stack = make([]word.Word, 0)
- vm.scope = make([]map[string]int, 0)
- vm.scope = append(vm.scope, make(map[string]int))
+ vm.scope = make([]map[string]uint64, 0)
+ vm.scope = append(vm.scope, make(map[string]uint64))
vm.main = NewChunk(vm)
return vm
}
@@ 136,8 182,8 @@ func (vm *VirtualMachine) Allocate(
*vm = obj
return uint64(loc), nil
} else {
- last := i + newSize
- for i = i + 1; i < last; i++ {
+ last := i + newSize - 1
+ for i = i + 1; i <= last; i++ {
if !(obj.free[i]) {
break
} else if i == last {
@@ 179,7 225,7 @@ func appendRhumb(vm VirtualMachine, ws []word.Word) VirtualMachine {
// Only run this if you are absolutely sure there is room
// to allocate in the heap. Overwriting memory is possible.
func (vm VirtualMachine) allocInPlace(x, y int, ws ...word.Word) {
- for hID, wID := x, 0; hID < y; hID, wID = hID+1, wID+1 {
+ for hID, wID := x, 0; hID <= y; hID, wID = hID+1, wID+1 {
vm.heap[hID], vm.free[hID] = ws[wID], false
}
}
@@ 206,7 252,7 @@ func (vm *VirtualMachine) WriteCodeToMain(
}
func (vm *VirtualMachine) Disassemble() {
- // vm.main.Disassemble()
+ vm.main.Disassemble(vm)
}
func (vm *VirtualMachine) Execute() {
@@ 227,9 273,9 @@ func logAddedToStack(stack []word.Word, txt string) {
}
func locateScopeLabel(
- scopes []map[string]int, lbl string,
+ scopes []map[string]uint64, lbl string,
) (
- idx int, ok bool,
+ idx uint64, ok bool,
) {
topScope := len(scopes) - 1
for i := topScope; i >= 0; i-- {
@@ 275,25 321,25 @@ func (vm *VirtualMachine) AddLiteralToStack(literal word.Word) {
logAddedToStack(vm.stack, literal.Debug())
}
-func (vm *VirtualMachine) getStringFromRuneArray(labelAddr word.Word) {
-
-}
-
// Currently just for lexically traversing the scope
-func (vm *VirtualMachine) SubmitLocalRequest(label word.Word) {
- // labelValue := vm.getStringFromRuneArray(label)
- // idx, ok := locateScopeLabel(vm.scope, label)
- // if ok {
- // // TODO: Invoke address, skip addrRef
- // vm.stack = append(vm.stack, word.FromAddress(idx))
- // logAddedToStack(vm.stack, ir.text)
- // return
- // }
- // vm.heap = append(vm.heap, EmptyWord())
- // idx = len(vm.heap) - 1
- // vm.scope[len(vm.scope)-1][ir.text] = idx
- // vm.stack = append(vm.stack, word.FromAddress(idx))
- // logAddedToStack(vm.stack, ir.text)
+func (vm *VirtualMachine) SubmitLocalRequest(addr word.Word) {
+ target := vm.heap[addr.AsAddr()]
+ if target.IsRuneArrayMark() {
+ label := ReviveRuneArray(vm, addr.AsAddr()).String(vm)
+ idx, ok := locateScopeLabel(vm.scope, label)
+ if ok {
+ // TODO: Invoke address, skip addrRef
+ vm.stack = append(vm.stack, word.FromAddress(idx))
+ logAddedToStack(vm.stack, label)
+ } else {
+ vm.scope[len(vm.scope)-1][label] = addr.AsAddr()
+ vm.stack = append(vm.stack, addr)
+ logAddedToStack(vm.stack, label)
+ }
+ } else {
+ vm.stack = append(vm.stack, target)
+ logAddedToStack(vm.stack, target.Debug())
+ }
}
// Used for traversing maps and legends
@@ 308,15 354,18 @@ func (vm *VirtualMachine) SubmitUnderRequest(label word.Word) {
// Used for traversing primitives and compilations
func (vm *VirtualMachine) SubmitOuterRequest(label word.Word) {
// FIXME: locate text
- addr, err := vm.main.ReviveLits(vm).IndexOf(vm, label)
+ lits := vm.main.ReviveLits(vm)
+ addr, err := lits.IndexOf(vm, label)
if err != nil {
panic("unable to find word for outer request")
}
- ref := vm.heap[vm.main.ReviveInstrs(vm).id+rune_arr_offset+uint64(addr)]
+ refId := lits.id + word_arr_offset + uint64(addr)
+ refAddr := vm.heap[refId]
+ ref := vm.heap[refAddr.AsAddr()]
if !(ref.IsRuneArrayMark()) {
panic("outer request submitted with non-ra value")
}
- text := ReviveRuneArray(vm, ref).String(vm)
+ text := ReviveRuneArray(vm, refAddr.AsAddr()).String(vm)
fmt.Println(text)
switch text {
case ".=", ":=":
M internal/vm/word_array.go => internal/vm/word_array.go +6 -2
@@ 71,13 71,13 @@ func (wa WordArray) IndexOf(vm *VirtualMachine, x word.Word) (
if x.IsAddress() {
mkX := vm.heap[x.AsAddr()]
if mkX.IsRuneArrayMark() {
- rax := ReviveRuneArray(vm, x)
+ rax := ReviveRuneArray(vm, x.AsAddr())
for i := range make([]int, wa.Length(vm)) {
y := wa.Get(vm, i)
if y.IsAddress() {
mkY := vm.heap[y.AsAddr()]
if mkY.IsRuneArrayMark() {
- ray := ReviveRuneArray(vm, y)
+ ray := ReviveRuneArray(vm, y.AsAddr())
if rax.String(vm) == ray.String(vm) {
return i, nil
}
@@ 112,6 112,10 @@ func (wa *WordArray) Append(vm *VirtualMachine, newWords ...word.Word) (uint64,
}
func (wa WordArray) Get(vm *VirtualMachine, i int) word.Word {
+ waLen := wa.Length(vm)
+ if i < 0 || i >= waLen {
+ panic("index out of bounds")
+ }
return vm.heap[wa.id+word_arr_offset+uint64(i)]
}
M internal/word/word.go => internal/word/word.go +6 -6
@@ 117,10 117,10 @@ func FromBool(b bool) Word {
return Word(VAL_FALS)
}
}
-func FromInt(i uint32) Word { return Word(VAL_NUMB | uint64(i)) }
-func FromRune(r rune) Word { return Word(VAL_RUNE | uint64(r)) }
-func FromSym(a int) Word { return Word(VAL_SYMB | uint64(a)) }
-func FromAddress(a int) Word { return Word(VAL_ADDR | uint64(a)) }
+func FromInt(i uint32) Word { return Word(VAL_NUMB | uint64(i)) }
+func FromRune(r rune) Word { return Word(VAL_RUNE | uint64(r)) }
+func FromSym(a int) Word { return Word(VAL_SYMB | uint64(a)) }
+func FromAddress(a uint64) Word { return Word(VAL_ADDR | a) }
func (w Word) isVal(v uint64) bool { return uint64(w)&MASK_ONE == v }
@@ 191,7 191,7 @@ func (w Word) Debug() string {
} else if w.IsSym() {
return "S" // FIXME: Implement symbols
} else if w.IsAddress() { // must trigger before IsFloat for unknown reasons
- return fmt.Sprint("A ", w.AsAddr(), " ")
+ return fmt.Sprint("A ", w.AsAddr(), " ")
} else if w.IsFloat() {
// return fmt.Sprintf("F %.1e", w.AsFloat())
return ". . . . ."
@@ 215,7 215,7 @@ func (w Word) Debug() string {
}
func (x Word) Equals(y Word) bool {
- if x.IsNAN() {
+ if x.IsNAN() || x.IsSentinel() {
return false
} else if x.IsTrue() {
return y.IsTrue()