~madcapjake/rhi

8c2bb0338a0e6868b713a49184ffa00b20e2e802 — Jake Russo 1 year, 6 months ago 0792f73
implement basic list map syntax
M .vscode/launch.json => .vscode/launch.json +9 -9
@@ 24,14 24,14 @@

                // "foo := 1; bar .= 2; foo ++ bar",


                "foo .= 10",
                "bar .= 3",
                "foo ++ 5"
                "foo .= [1;2;3]"
                // "foo .= 10",
                // "bar .= 3",
                // "foo ++ 5"
            ],
            "env": {
                "RHUMB_VISITOR_DEBUG": "0",
                "RHUMB_CODE_ARRAY_DEBUG": "0",
                "RHUMB_VISITOR_DEBUG": "1",
                "RHUMB_CODE_ARRAY_DEBUG": "1",
                "RHUMB_VM_DEBUG": "1"
            }
        },


@@ 46,9 46,9 @@
                "repl"
            ],
            "env": {
                "RHUMB_VISITOR_DEBUG": "1",
                "RHUMB_CODE_ARRAY_DEBUG": "1",
                "RHUMB_VM_DEBUG": "1"
                "RHUMB_VISITOR_DEBUG": "0",
                "RHUMB_CODE_ARRAY_DEBUG": "0",
                "RHUMB_VM_DEBUG": "0"
            }
        }


M internal/generator/visitor.go => internal/generator/visitor.go +42 -1
@@ 347,7 347,48 @@ func (v *RhumbVisitor) VisitPower(ctx *P.PowerContext) interface{} {

func (v *RhumbVisitor) VisitMap(ctx *P.MapContext) interface{} {
	viLogger.Println("map:", ctx.GetText())
	return v.VisitChildren(ctx)
	var (
		ra                           vm.RuneArray
		oBrcktIdx, cBrcktIdx         uint64
		oBrcktFindErr, cBrcktFindErr error
		lits                         vm.WordArray = v.vm.CurrentChunk.ReviveLits(&v.vm)
		bracket                      antlr.Token
		line                         int
		text                         string
	)
	bracket = ctx.OpenBracket().GetSymbol()
	text = bracket.GetText()
	line = bracket.GetLine()
	oBrcktIdx, oBrcktFindErr = lits.Find(&v.vm, text)
	if oBrcktFindErr != nil {
		ra = vm.NewRuneArray(&v.vm, word.FromAddress(0), []rune(text)...)
		oBrcktIdx = ra.Id()
	}

	v.vm.WriteCodeToCurrentChunk(
		line,
		word.FromAddress(oBrcktIdx),
		vm.NewOuterRequest, // FIXME: re-implement as NewInnerRequest
	)

	v.VisitChildren(ctx.Sequence())

	bracket = ctx.CloseBracket().GetSymbol()
	text = bracket.GetText()
	line = bracket.GetLine()
	cBrcktIdx, cBrcktFindErr = lits.Find(&v.vm, text)
	if cBrcktFindErr != nil {
		ra = vm.NewRuneArray(&v.vm, word.FromAddress(0), []rune(text)...)
		cBrcktIdx = ra.Id()
	}

	v.vm.WriteCodeToCurrentChunk(
		line,
		word.FromAddress(cBrcktIdx),
		vm.NewOuterRequest, // FIXME: re-implement as NewInnerRequest
	)

	return nil
}

func (v *RhumbVisitor) VisitFreeze(ctx *P.FreezeContext) interface{} {

R internal/vm/code_array.go => internal/vm/array-code.go +15 -35
@@ 57,20 57,20 @@ func NewCodeArray(
	if err != nil {
		panic("allocation failed")
	}
	return CodeArray{uint64(loc)}
	return CodeArray{loc}
}

func ReviveCodeArray(vm *VirtualMachine, addr word.Word) CodeArray {
	i := addr.AsAddr()
	mark := vm.heap[i]
	mark := vm.Heap[i]
	if !(mark.IsCodeArrayMark()) {
		panic("not a code array mark")
	}
	legend := vm.heap[i+code_lgd_offset]
	legend := vm.Heap[i+code_lgd_offset]
	if !(legend.IsAddress()) {
		panic("code array legend word is not an address")
	}
	size := vm.heap[i+code_sze_offset]
	size := vm.Heap[i+code_sze_offset]
	if !(size.IsInteger()) {
		panic("code array object size word is not an integer")
	}


@@ 99,7 99,7 @@ func (ca CodeArray) NewSize(vm *VirtualMachine, newLine bool, cs ...Code) (size 
	} else {
		size = origSize
		id := ca.id + code_arr_offset + uint64(ca.Size(vm)-1)
		word := vm.heap[id]
		word := vm.Heap[id]
		remainder = ca.getWordCodeCount(vm, word)
		freshLength = newLength - remainder
		wholeWords = freshLength / 8


@@ 132,9 132,9 @@ func (ca *CodeArray) SetCodes(
	if newLine {
		ws = append(ws, word.Sentinel())
	} else {
		ca.getCodesFromWord(vm, vm.heap[lastWordID], &bs)
		ca.getCodesFromWord(vm, vm.Heap[lastWordID], &bs)
		if len(bs) < 8 {
			vm.free[lastWordID] = true
			vm.Free[lastWordID] = true
			origSz--
			tempCS := make([]Code, len(cs))
			copy(tempCS, cs)


@@ 176,30 176,10 @@ func (ca *CodeArray) SetCodes(
		ws...,
	)
	if newId != ca.id {
		// vm.UpdateAddresses(ca.id, newId)
		ca.id = newId
	}
}

func (ca *CodeArray) lastWordVacancy(vm *VirtualMachine) bool {
	var (
		lastIndex uint64    = uint64(ca.Size(vm) - 1)
		word      word.Word = vm.heap[ca.id+lastIndex]
	)
	if word.IsSentinel() {
		return false
	}
	return ca.getWordCodeCount(vm, word) != 0
}

// func (ca *CodeArray) currentIndex(vm *VirtualMachine) int {
// 	if ca.lastWordVacancy(vm) {
// 		return int(ca.Length(vm)) - 1
// 	} else {
// 		return int(ca.Length(vm))
// 	}
// }

func (ca CodeArray) getCodesFromWord(vm *VirtualMachine, word word.Word, b *[]byte) {
	var buf []byte = *b
	if word.IsSentinel() {


@@ 237,7 217,7 @@ func (ca CodeArray) GetCodes(vm *VirtualMachine) []byte {
		buf   []byte = make([]byte, 0, cwLen*8)
	)
	for wIndex := code_arr_offset; wIndex < cwLen; wIndex++ {
		w := vm.heap[ca.id+wIndex]
		w := vm.Heap[ca.id+wIndex]
		if !(w.IsSentinel()) {
			ca.getCodesFromWord(vm, w, &buf)
		}


@@ 251,12 231,12 @@ func (ca *CodeArray) GetLine(vm *VirtualMachine, codeIndex int) (lines int) {
		panic("index greater than length")
	}
	for i := uint64(0); i < cwSize && codes <= codeIndex; i++ {
		if vm.heap[ca.id+code_arr_offset+i].IsSentinel() {
		if vm.Heap[ca.id+code_arr_offset+i].IsSentinel() {
			lines += 1
		} else {
			var (
				id   uint64    = ca.id + code_arr_offset + i
				word word.Word = vm.heap[id]
				word word.Word = vm.Heap[id]
			)
			codes += ca.getWordCodeCount(vm, word)
		}


@@ 265,19 245,19 @@ func (ca *CodeArray) GetLine(vm *VirtualMachine, codeIndex int) (lines int) {
}

func (ca CodeArray) Legend(vm *VirtualMachine) uint64 {
	return vm.heap[ca.id+code_lgd_offset].AsAddr()
	return vm.Heap[ca.id+code_lgd_offset].AsAddr()
}
func (ca CodeArray) Size(vm *VirtualMachine) uint64 {
	return uint64(vm.heap[ca.id+code_sze_offset].AsInt())
	return uint64(vm.Heap[ca.id+code_sze_offset].AsInt())
}
func (ca CodeArray) Length(vm *VirtualMachine) uint32 {
	return vm.heap[ca.id+code_len_offset].AsInt()
	return vm.Heap[ca.id+code_len_offset].AsInt()
}

func (ca *CodeArray) SetSize(vm *VirtualMachine, s uint32) {
	vm.heap[ca.id+code_sze_offset] = word.FromInt(s)
	vm.Heap[ca.id+code_sze_offset] = word.FromInt(s)
}

func (ca *CodeArray) SetLength(vm *VirtualMachine, l uint32) {
	vm.heap[ca.id+code_len_offset] = word.FromInt(l)
	vm.Heap[ca.id+code_len_offset] = word.FromInt(l)
}

R internal/vm/rune_array.go => internal/vm/array-rune.go +13 -25
@@ 7,14 7,6 @@ import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

// type RuneArray struct {
// 	Mark   word.Word
// 	Legend word.Word // Address
// 	Size   word.Word
// 	Length word.Word
// 	Runes  []word.Word // Words are packed 2-elem runes
// }

const (
	rune_lgd_offset uint64 = 1
	rune_sze_offset uint64 = 2


@@ 85,20 77,16 @@ func NewRuneArray(
	return RuneArray{uint64(loc)}
}

// func GetOrMakeLabelRA(vm *VirtualMachine, text string) RuneArray {

// }

func ReviveRuneArray(vm *VirtualMachine, addr uint64) RuneArray {
	mark := vm.heap[addr]
	mark := vm.Heap[addr]
	if !(mark.IsRuneArrayMark()) {
		panic("not a rune array mark")
	}
	legend := vm.heap[addr+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[addr+rune_sze_offset]
	size := vm.Heap[addr+rune_sze_offset]
	if !(size.IsInteger()) {
		panic("rune array object size word is not an integer")
	}


@@ 108,21 96,21 @@ func ReviveRuneArray(vm *VirtualMachine, addr uint64) RuneArray {
func (ra RuneArray) Id() uint64 { return ra.id }

func (ra RuneArray) Legend(vm *VirtualMachine) uint64 {
	return vm.heap[ra.id+rune_lgd_offset].AsAddr()
	return vm.Heap[ra.id+rune_lgd_offset].AsAddr()
}
func (ra RuneArray) Size(vm *VirtualMachine) uint64 {
	return uint64(vm.heap[ra.id+rune_sze_offset].AsInt())
	return uint64(vm.Heap[ra.id+rune_sze_offset].AsInt())
}
func (ra RuneArray) Length(vm *VirtualMachine) uint32 {
	return vm.heap[ra.id+rune_len_offset].AsInt()
	return vm.Heap[ra.id+rune_len_offset].AsInt()
}
func (ra RuneArray) Runes(vm *VirtualMachine) []rune {
	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)] {
	for i := range vm.Heap[start : ra.id+ra.Size(vm)] {
		bytes := make([]byte, 8)
		binary.BigEndian.PutUint64(bytes, uint64(vm.heap[start+uint64(i)]))
		binary.BigEndian.PutUint64(bytes, uint64(vm.Heap[start+uint64(i)]))
		buf = append(buf, rune(binary.LittleEndian.Uint32(bytes[:4])))
		secondRune := rune(binary.LittleEndian.Uint32(bytes[4:]))
		if secondRune != 0 {


@@ 140,7 128,7 @@ func (ra RuneArray) Rune(vm *VirtualMachine, i uint32) rune {
	addr := i / 2
	offset := i % 2
	bytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(bytes, uint64(vm.heap[ra.id+uint64(addr)]))
	binary.LittleEndian.PutUint64(bytes, uint64(vm.Heap[ra.id+uint64(addr)]))
	if offset == 0 {
		return rune(binary.LittleEndian.Uint32(bytes[:4]))
	} else {


@@ 149,11 137,11 @@ func (ra RuneArray) Rune(vm *VirtualMachine, i uint32) rune {
}

func (ra RuneArray) SetSize(vm *VirtualMachine, s uint32) {
	vm.heap[ra.id+rune_sze_offset] = word.FromInt(s)
	vm.Heap[ra.id+rune_sze_offset] = word.FromInt(s)
}

func (ra RuneArray) SetLength(vm *VirtualMachine, l uint32) {
	vm.heap[ra.id+rune_len_offset] = word.FromInt(l)
	vm.Heap[ra.id+rune_len_offset] = word.FromInt(l)
}

func (ra RuneArray) SetRune(vm *VirtualMachine, i uint32, r rune) {


@@ 165,7 153,7 @@ func (ra RuneArray) SetRune(vm *VirtualMachine, i uint32, r rune) {
		wordBytes []byte = make([]byte, 8)
	)
	binary.LittleEndian.PutUint32(runeBytes, uint32(r))
	binary.LittleEndian.PutUint64(wordBytes, uint64(vm.heap[id]))
	binary.LittleEndian.PutUint64(wordBytes, uint64(vm.Heap[id]))
	if offset == 0 {
		copy(wordBytes, runeBytes)
	} else {


@@ 173,5 161,5 @@ func (ra RuneArray) SetRune(vm *VirtualMachine, i uint32, r rune) {
			wordBytes[i+4] = rb
		}
	}
	vm.heap[id] = word.Word(binary.LittleEndian.Uint64(wordBytes))
	vm.Heap[id] = word.Word(binary.LittleEndian.Uint64(wordBytes))
}

R internal/vm/word_array.go => internal/vm/array-word.go +15 -22
@@ 6,13 6,6 @@ import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

// type WordArray struct {
// 	Mark   word.Word
// 	Legend word.Word // Address
// 	Length word.Word // Integer
// 	Words  []word.Word
// }

const (
	word_lgd_offset uint64 = 1
	word_len_offset uint64 = 2


@@ 33,7 26,7 @@ func NewWordArray(
	wordsSize := uint32(code_arr_offset) + wordsLen
	waWords := make([]word.Word, 0, wordsSize)
	waWords = append(waWords,
		/* Mark:   */ word.Word(word.MAIN_ARR),
		/* Mark:   */ word.Word(word.LIST_ARR),
		/* Legend: */ legAddr,
		/* Length: */ word.FromInt(wordsLen),
	)


@@ 48,16 41,16 @@ func NewWordArray(

func ReviveWordArray(vm *VirtualMachine, addr word.Word) WordArray {
	i := addr.AsAddr()
	mark := vm.heap[i]
	if !(mark.IsMainArrayMark()) {
	mark := vm.Heap[i]
	if !(mark.IsListArrayMark()) {
		panic("not a word array mark")
	}
	legend := vm.heap[i+word_lgd_offset]
	legend := vm.Heap[i+word_lgd_offset]
	if !(legend.IsAddress()) {
		// fmt.Println(legend.Debug())
		panic("word array legend word is not an address")
	}
	length := vm.heap[i+word_len_offset]
	length := vm.Heap[i+word_len_offset]
	if !(length.IsInteger()) {
		panic("word array object length word is not an integer")
	}


@@ 71,13 64,13 @@ func (wa WordArray) Find(vm *VirtualMachine, s string) (
	for i := range make([]int, wa.Length(vm)) {
		waVal := wa.Get(vm, i)
		if waVal.IsAddress() {
			heapVal := vm.heap[waVal.AsAddr()]
			heapVal := vm.Heap[waVal.AsAddr()]
			if heapVal.IsRuneArrayMark() {
				heapRA := ReviveRuneArray(vm, waVal.AsAddr())
				strVal := heapRA.String(vm)
				if strVal == s {
					heapIdx := wa.id + word_arr_offset + uint64(i)
					idx = vm.heap[heapIdx].AsAddr()
					idx = vm.Heap[heapIdx].AsAddr()
					return
				}
			}


@@ 92,16 85,16 @@ func (wa WordArray) IndexOf(vm *VirtualMachine, x word.Word) (
	err error,
) {
	if x.IsAddress() {
		mkX := vm.heap[x.AsAddr()]
		mkX := vm.Heap[x.AsAddr()]
		if mkX.IsRuneArrayMark() {
			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()]
					mkY := vm.Heap[y.AsAddr()]
					if mkY.IsRuneArrayMark() {
						ray := ReviveRuneArray(vm, y.AsAddr())
						if raX.String(vm) == ray.String(vm) {
						raY := ReviveRuneArray(vm, y.AsAddr())
						if raX.String(vm) == raY.String(vm) {
							return i, nil
						}
					}


@@ 139,19 132,19 @@ func (wa WordArray) Get(vm *VirtualMachine, i int) word.Word {
	if i < 0 || i >= waLen {
		panic("index out of bounds")
	}
	return vm.heap[wa.id+word_arr_offset+uint64(i)]
	return vm.Heap[wa.id+word_arr_offset+uint64(i)]
}

func (wa WordArray) Legend(vm *VirtualMachine, i int) word.Word {
	return vm.heap[i]
	return vm.Heap[i]
}

func (wa WordArray) SetLength(vm *VirtualMachine, l uint32) {
	vm.heap[wa.id+word_len_offset] = word.FromInt(l)
	vm.Heap[wa.id+word_len_offset] = word.FromInt(l)
}

func (wa WordArray) Length(vm *VirtualMachine) int {
	return int(vm.heap[wa.id+word_len_offset].AsInt())
	return int(vm.Heap[wa.id+word_len_offset].AsInt())
}

func (wa WordArray) Size(vm *VirtualMachine) int {

M internal/vm/chunk.go => internal/vm/chunk.go +42 -30
@@ 11,7 11,7 @@ const (
	chunk_wa_offset uint64 = 2
)

type Chunk struct {
type RhumbChunk struct {
	// address in vm's heap
	id uint64



@@ 19,7 19,7 @@ type Chunk struct {
	line int
}

func NewChunk(vm *VirtualMachine) Chunk {
func NewChunk(vm *VirtualMachine) RhumbChunk {
	var (
		ch [3]word.Word = [3]word.Word{}
		ca CodeArray    = NewCodeArray(vm, word.FromAddress(0))


@@ 32,19 32,19 @@ func NewChunk(vm *VirtualMachine) Chunk {
	if err != nil {
		panic("failed to reallocate onto heap")
	}
	return Chunk{id, 0}
	return RhumbChunk{id, 0}
}

func ReviveChunk(vm *VirtualMachine, addr word.Word) Chunk {
func ReviveChunk(vm *VirtualMachine, addr word.Word) RhumbChunk {
	i := addr.AsAddr()
	mark := vm.heap[i]
	mark := vm.Heap[i]
	if !(mark.IsCodeArrayMark()) {
		panic("not a chunk mark")
	}
	return Chunk{i, 0}
	return RhumbChunk{i, 0}
}

func (ch *Chunk) WriteCode(vm *VirtualMachine, line int, codes []Code) {
func (ch *RhumbChunk) WriteCode(vm *VirtualMachine, line int, codes []Code) {

	instructions := ch.ReviveInstrs(vm)
	if line > ch.line {


@@ 58,15 58,15 @@ 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(addr)
func (ch RhumbChunk) SetInstructionsAddress(vm *VirtualMachine, addr uint64) {
	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(addr)
func (ch RhumbChunk) SetLiteralsAddress(vm *VirtualMachine, addr uint64) {
	vm.Heap[ch.id+chunk_wa_offset] = word.FromAddress(addr)
}

func (ch *Chunk) AddLiteral(vm *VirtualMachine, lit word.Word) (uint64, error) {
func (ch *RhumbChunk) AddLiteral(vm *VirtualMachine, lit word.Word) (uint64, error) {
	literals := ch.ReviveLits(vm)
	existingIndex, err := literals.IndexOf(vm, lit)
	if err != nil {


@@ 84,23 84,23 @@ func (ch *Chunk) AddLiteral(vm *VirtualMachine, lit word.Word) (uint64, error) {
	}
}

func (ch Chunk) Instructions(vm *VirtualMachine) word.Word {
	return vm.heap[ch.id+chunk_ca_offset]
func (ch RhumbChunk) Instructions(vm *VirtualMachine) word.Word {
	return vm.Heap[ch.id+chunk_ca_offset]
}

func (ch Chunk) ReviveInstrs(vm *VirtualMachine) CodeArray {
func (ch RhumbChunk) ReviveInstrs(vm *VirtualMachine) CodeArray {
	return ReviveCodeArray(vm, ch.Instructions(vm))
}

func (ch Chunk) Literals(vm *VirtualMachine) word.Word {
	return vm.heap[ch.id+chunk_wa_offset]
func (ch RhumbChunk) Literals(vm *VirtualMachine) word.Word {
	return vm.Heap[ch.id+chunk_wa_offset]
}

func (ch Chunk) ReviveLits(vm *VirtualMachine) WordArray {
func (ch RhumbChunk) ReviveLits(vm *VirtualMachine) WordArray {
	return ReviveWordArray(vm, ch.Literals(vm))
}

func (ch Chunk) Execute(vm *VirtualMachine) {
func (ch RhumbChunk) Execute(vm *VirtualMachine) {
	var (
		instructions        = ch.ReviveInstrs(vm)
		cwLen        int    = int(instructions.Size(vm) - code_arr_offset)


@@ 108,7 108,7 @@ func (ch Chunk) Execute(vm *VirtualMachine) {
		buf          []byte = make([]byte, 0, cwLen*8)
	)
	for wordIndex := 0; wordIndex < cwLen; wordIndex++ {
		w := vm.heap[instructions.id+code_arr_offset+uint64(wordIndex)]
		w := vm.Heap[instructions.id+code_arr_offset+uint64(wordIndex)]
		if w.IsSentinel() {
			ch.line++
			continue


@@ 131,20 131,32 @@ func (ch Chunk) Execute(vm *VirtualMachine) {
	}
}

func (ch Chunk) execTagIndex(vm *VirtualMachine, tag byte, idx int) {
	literals := ch.ReviveLits(vm)
	// fmt.Println("Executing chunk tag:", tag)
func (ch RhumbChunk) execTagIndex(vm *VirtualMachine, tag byte, idx int) {
	var (
		literals WordArray = ch.ReviveLits(vm)
		lit      word.Word
	)
	switch tag {
	case TAG_VALUE_LITERAL:
		vm.AddLiteralToStack(literals.Get(vm, idx))
		lit = literals.Get(vm, idx)
		fmt.Println("Executing literal tag:", lit.Debug())
		vm.AddLiteralToStack(lit)
	case TAG_LOCAL_REQUEST:
		vm.SubmitLocalRequest(literals.Get(vm, idx))
		lit = literals.Get(vm, idx)
		fmt.Println("Executing local tag:", lit.Debug())
		vm.SubmitLocalRequest(lit)
	case TAG_INNER_REQUEST:
		vm.SubmitInnerRequest(literals.Get(vm, idx))
		lit = literals.Get(vm, idx)
		fmt.Println("Executing inner tag:", lit.Debug())
		vm.SubmitInnerRequest(lit)
	case TAG_UNDER_REQUEST:
		vm.SubmitUnderRequest(literals.Get(vm, idx))
		lit = literals.Get(vm, idx)
		fmt.Println("Executing under tag:", lit.Debug())
		vm.SubmitUnderRequest(lit)
	case TAG_OUTER_REQUEST:
		vm.SubmitOuterRequest(literals.Get(vm, idx))
		lit = literals.Get(vm, idx)
		fmt.Println("Executing outer tag:", lit.Debug())
		vm.SubmitOuterRequest(lit)
	// case TAG_EVENT_REQUEST:
	// 	vm.SubmitEventRequest(literals.Get(idx))
	// case TAG_REPLY_REQUEST:


@@ 154,7 166,7 @@ func (ch Chunk) execTagIndex(vm *VirtualMachine, tag byte, idx int) {
	}
}

func (ch Chunk) Disassemble(vm *VirtualMachine) {
func (ch RhumbChunk) Disassemble(vm *VirtualMachine) {
	fmt.Println("============= Chunk =============")
	var line int
	instructions := ch.ReviveInstrs(vm)


@@ 170,7 182,7 @@ func (ch Chunk) Disassemble(vm *VirtualMachine) {
	}
}

func (ch Chunk) DisassembleCode(vm *VirtualMachine, currentLine, currentOffset int, bufPtr *[]byte) (int, int) {
func (ch RhumbChunk) DisassembleCode(vm *VirtualMachine, currentLine, currentOffset int, bufPtr *[]byte) (int, int) {
	buf := *bufPtr
	fmt.Printf("%04d ", currentOffset)
	var recurse func(l, o, i int) (int, int)

M internal/vm/descriptor.go => internal/vm/descriptor.go +33 -23
@@ 5,43 5,53 @@ import "git.sr.ht/~madcapjake/grhumb/internal/word"
//	type Descriptor struct {
//		Mark Word // immutable, mutable, submap
//		Name Word // address to TextMap
//      Req  Word // requirement linked list
//      Dep  Word // dependency linked list
//		Data Word // constant, field offset, or
//	}

const (
	desc_name_offset uint64 = 1
	desc_data_offset uint64 = 2
	desc_nme_offset uint64 = 1
	desc_req_offset uint64 = 2
	desc_dep_offset uint64 = 3
	desc_dat_offset uint64 = 4
)

type Descriptor struct {
	vm *VirtualMachine
	id uint64
	at []word.Word
}

func NewDescriptor(
	vm *VirtualMachine,
	name word.Word, // string address
	kind uint64,
	value word.Word,
) Descriptor {
	descWords := make([]word.Word, 0, 2)
	descWords = append(descWords, word.Word(kind))
	descWords = append(descWords, name)
	descWords = append(descWords, value)
	loc, _ := vm.ReAllocate(descWords...)
	return Descriptor{vm, loc, vm.heap[loc : loc+2]}
	Id uint64
}

func ReviveDescriptor(vm *VirtualMachine, addr word.Word) Descriptor {
	i := addr.AsAddr()
	mark := vm.heap[i]
	mark := vm.Heap[i]
	if !(mark.IsDescMark()) {
		panic("not a descriptor mark")
	}
	name := vm.heap[i+desc_name_offset]
	if !(name.IsAddress()) {
	nameAddr := vm.Heap[i+desc_nme_offset]
	if !(nameAddr.IsAddress()) {
		panic("desciptor name word is not an address")
	}
	return Descriptor{vm, i, vm.heap[i : i+2]}
	if !(vm.Heap[nameAddr].IsRuneArrayMark()) {
		panic("descriptor name address does not point to rune array")
	}

	return Descriptor{i}
}

func (d Descriptor) Name(vm *VirtualMachine) string {
	nameAddr := vm.Heap[d.Id+desc_nme_offset]
	if !(nameAddr.IsAddress()) {
		panic("desciptor name word is not an address")
	}
	addr := nameAddr.AsAddr()
	pointedAt := vm.Heap[addr]
	if !(pointedAt.IsRuneArrayMark()) {
		panic("word provided does not point to a rune array")
	}
	name := ReviveRuneArray(vm, addr)
	return name.String(vm)
}

func (d Descriptor) Data(vm *VirtualMachine) word.Word {
	return vm.Heap[d.Id+desc_dat_offset]
}

A internal/vm/legend-list.go => internal/vm/legend-list.go +37 -0
@@ 0,0 1,37 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewListLegend(virtualMachine *VirtualMachine) Legend {
	words := make([]word.Word, 0, 8)
	init_size := uint32(lgd_fld_offset)
	words = append(words,
		/* Mark:    */ word.Word(word.LIST_LGD),
		/* Legend:  */ word.FromAddress(0), // TODO: Implement Meta Legend
		/* Sweep:   */ word.FromAddress(0),
		/* Size:    */ word.FromInt(init_size),
		/* Length:  */ word.FromInt(0),
		/* ReqLink: */ word.FromAddress(0),
		/* DepLink: */ word.FromAddress(0),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Legend{Id: loc}
}

func ReviveListLegend(virtualMachine *VirtualMachine, addr word.Word) Legend {
	i := addr.AsAddr()
	CheckBaseLegendWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsListLegendMark() },
		i,
	)
	if !(virtualMachine.Heap[i+lgd_dat_offset].IsAddress()) {
		panic("list array word is not an address")
	}
	return Legend{Id: i}
}

A internal/vm/legend-meta.go => internal/vm/legend-meta.go +34 -0
@@ 0,0 1,34 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewMetaLegend(virtualMachine *VirtualMachine) Legend {
	words := make([]word.Word, 0, 8)
	init_size := uint32(lgd_fld_offset)
	words = append(words,
		/* Mark:    */ word.Word(word.LIST_LGD),
		/* Legend:  */ word.FromAddress(0), // TODO: Implement Meta Legend
		/* Sweep:   */ word.FromAddress(0),
		/* Size:    */ word.FromInt(init_size),
		/* Length:  */ word.FromInt(0),
		/* ReqLink: */ word.FromAddress(0),
		/* DepLink: */ word.FromAddress(0),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Legend{Id: loc}
}

func ReviveMetaLegend(virtualMachine *VirtualMachine, addr word.Word) Legend {
	i := addr.AsAddr()
	CheckBaseLegendWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsMetaLegendMark() },
		i,
	)
	return Legend{Id: i}
}

A internal/vm/legend-routine.go => internal/vm/legend-routine.go +37 -0
@@ 0,0 1,37 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewRoutLegend(virtualMachine *VirtualMachine) Legend {
	words := make([]word.Word, 0, 8)
	init_size := uint32(lgd_fld_offset)
	words = append(words,
		/* Mark:    */ word.Word(word.LIST_LGD),
		/* Legend:  */ word.FromAddress(0), // TODO: Implement Meta Legend
		/* Sweep:   */ word.FromAddress(0),
		/* Size:    */ word.FromInt(init_size),
		/* Length:  */ word.FromInt(0),
		/* ReqLink: */ word.FromAddress(0),
		/* DepLink: */ word.FromAddress(0),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Legend{Id: loc}
}

func ReviveRoutLegend(virtualMachine *VirtualMachine, addr word.Word) Legend {
	i := addr.AsAddr()
	CheckBaseLegendWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsRoutLegendMark() },
		i,
	)
	if !(virtualMachine.Heap[i+lgd_dat_offset].IsAddress()) {
		panic("routine chunk word is not an address")
	}
	return Legend{Id: i}
}

A internal/vm/legend-selector.go => internal/vm/legend-selector.go +37 -0
@@ 0,0 1,37 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewSeleLegend(virtualMachine *VirtualMachine) Legend {
	words := make([]word.Word, 0, 8)
	init_size := uint32(lgd_fld_offset)
	words = append(words,
		/* Mark:    */ word.Word(word.LIST_LGD),
		/* Legend:  */ word.FromAddress(0), // TODO: Implement Meta Legend
		/* Sweep:   */ word.FromAddress(0),
		/* Size:    */ word.FromInt(init_size),
		/* Length:  */ word.FromInt(0),
		/* ReqLink: */ word.FromAddress(0),
		/* DepLink: */ word.FromAddress(0),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Legend{Id: loc}
}

func ReviveSeleLegend(virtualMachine *VirtualMachine, addr word.Word) Legend {
	i := addr.AsAddr()
	CheckBaseLegendWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsSeleLegendMark() },
		i,
	)
	if !(virtualMachine.Heap[i+lgd_dat_offset].IsAddress()) {
		panic("selector chunk word is not an address")
	}
	return Legend{Id: i}
}

A internal/vm/legend-text.go => internal/vm/legend-text.go +37 -0
@@ 0,0 1,37 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewTextLegend(virtualMachine *VirtualMachine) Legend {
	words := make([]word.Word, 0, 8)
	init_size := uint32(lgd_fld_offset)
	words = append(words,
		/* Mark:    */ word.Word(word.TEXT_LGD),
		/* Legend:  */ word.FromAddress(0), // TODO: Implement Meta Legend
		/* Sweep:   */ word.FromAddress(0),
		/* Size:    */ word.FromInt(init_size),
		/* Length:  */ word.FromInt(0),
		/* ReqLink: */ word.FromAddress(0),
		/* DepLink: */ word.FromAddress(0),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Legend{Id: loc}
}

func ReviveTextLegend(virtualMachine *VirtualMachine, addr word.Word) Legend {
	i := addr.AsAddr()
	CheckBaseLegendWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsTextLegendMark() },
		i,
	)
	if !(virtualMachine.Heap[i+lgd_dat_offset].IsAddress()) {
		panic("text array word is not an address")
	}
	return Legend{Id: i}
}

M internal/vm/legend.go => internal/vm/legend.go +88 -143
@@ 1,164 1,109 @@
package vm

import "git.sr.ht/~madcapjake/grhumb/internal/word"
import (
	"fmt"

// type Legend struct {
// 	Mark       Word
// 	MetaLegend Word
// }

// type BaseMapLegend struct {
// 	Legend
// 	TrashSweep Word
// 	Size       Word
// 	Length     Word
// 	ReqLink    Word // pointer, circular dependency list
// 	DepLink    Word // pointer, circular dependency list
// }

// type MainMapLegend struct {
// 	BaseMapLegend
// 	Field []Descriptor
// }

// type ListMapLegend struct {
// 	BaseMapLegend
// 	Items Word
// 	Field []Descriptor
// }

// type TextMapLegend struct {
// 	BaseMapLegend
// 	Runes Word
// 	Field []Descriptor
// }

// type FuncMapLegend struct {
// 	BaseMapLegend
// 	Chunk Word
// 	Field []Descriptor
// }

// type MetaMapLegend struct {
// 	BaseMapLegend
// 	Field []Descriptor
// }

type MainMapLegend []word.Word
type ListMapLegend []word.Word
type TextMapLegend []word.Word
type FuncMapLegend []word.Word
type MetaMapLegend []word.Word
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

const (
	base_lgd_offset uint64 = 1
	base_swp_offset uint64 = 2
	base_sze_offset uint64 = 3
	base_len_offset uint64 = 4
	base_req_offset uint64 = 5
	base_dep_offset uint64 = 6
	main_fld_offset uint64 = 7
	text_arr_offset uint64 = 8
	text_fld_offset uint64 = 9
	rout_chu_offset uint64 = 10
	rout_fld_offset uint64 = 11
	lgd_lgd_offset uint64 = 1
	lgd_swp_offset uint64 = 2
	lgd_sze_offset uint64 = 3
	lgd_len_offset uint64 = 3
	lgd_req_offset uint64 = 4
	lgd_dep_offset uint64 = 5
	lgd_dat_offset uint64 = 6
	lgd_fld_offset uint64 = 7
)

func NewBaseMapLegend(
	mark word.Word,
	legAddr word.Word,
	length uint32,
	dWords []word.Word,
) []word.Word {
	words := make([]word.Word, 0, 8)
	words = append(words,
		/* Mark:    */ mark,
		/* Legend:  */ legAddr,
		/* Sweep:   */ word.FromAddress(0),
		/* Size:    */ word.FromInt(7+length),
		/* Length:  */ word.FromInt(length),
		/* ReqLink: */ word.FromAddress(0),
		/* DepLink: */ word.FromAddress(0),
	)
	words = append(words, dWords...)
	return words
}
type Legend struct{ Id uint64 }

func wordsFromDescriptors(
	d ...Descriptor,
) (buf []word.Word) {
	// buf = make([]word.Word, 0, len(d)*3)
	// for _, desc := range d {
	// 	buf = append(buf, d[descIndex]...)
	// }
	return
func CheckBaseLegendWords(
	vm *VirtualMachine,
	isCorrectKindOf func(m word.Word) bool,
	i uint64,
) {
	if !(isCorrectKindOf(vm.Heap[i])) {
		panic("not correct kind of legend mark")
	}
	if !(vm.Heap[i+lgd_lgd_offset].IsAddress()) {
		panic("meta legend word is not an address")
	}
	if !(vm.Heap[i+lgd_swp_offset].IsAddress()) {
		panic("gc sweep word is not an address")
	}
	if !(vm.Heap[i+lgd_sze_offset].IsInteger()) {
		panic("object size word is not an integer")
	}
	if !(vm.Heap[i+lgd_len_offset].IsInteger()) {
		panic("object length word is not an integer")
	}
	if !(vm.Heap[i+lgd_req_offset].IsAddress()) {
		panic("requirement link word is not an address")
	}
	if !(vm.Heap[i+lgd_dep_offset].IsAddress()) {
		panic("dependency link word is not an address")
	}
}

func NewMainMapLegend(
	legAddr word.Word,
	descs ...Descriptor,
) MainMapLegend {
	descCount := uint32(len(descs))
	dWords := wordsFromDescriptors(descs...)
	return NewBaseMapLegend(
		word.Word(word.MAIN_LGD),
		legAddr,
		descCount,
		dWords,
	)
func (l Legend) NewDescriptor(
	vm *VirtualMachine,
	kind uint64,
	name RuneArray,
	offset int,
) Legend {
	oldLen := l.Length(vm)
	oldSze := l.Size(vm)
	descWords := []word.Word{
		word.Word(kind),
		word.FromAddress(name.id),
		word.FromAddress(0), // TODO: Req link
		word.FromAddress(0), // TODO: Dep link
		word.FromInt(uint32(offset)),
	}
	loc, _ := vm.Allocate(int(l.Id), int(l.Size(vm)), descWords...)
	if loc != l.Id {
		l.Id = loc
	}
	l.SetLength(vm, oldLen+1)
	l.SetSize(vm, oldSze+5)
	return l
}

func NewTextMapLegend(
	legAddr word.Word,
	descs ...Descriptor,
) TextMapLegend {
	descCount := uint32(len(descs))
	dWords := wordsFromDescriptors(descs...)
	return NewBaseMapLegend(
		word.Word(word.TEXT_LGD),
		legAddr,
		descCount,
		dWords,
	)
// Returns the location of the name provided
//
// TODO: Update to return word which is either address or constant
func (l Legend) Get(vm *VirtualMachine, name RuneArray) (
	idx int,
	err error,
) {
	// traverse the 5-word descriptors
	for i := range make([]int, l.Length(vm)*5) {
		if i%5 == 0 {
			descMark := vm.Heap[l.Id+lgd_fld_offset+uint64(i)]
			desc := ReviveDescriptor(vm, descMark)
			if desc.Name(vm) == name.String(vm) {
				return int(desc.Data(vm).AsInt()), nil
			}
		}
	}

	return -1, fmt.Errorf("couldn't find word")
}

func NewRoutMapLegend(
	legAddr word.Word,
	descs ...Descriptor,
) FuncMapLegend {
	descCount := uint32(len(descs))
	dWords := wordsFromDescriptors(descs...)
	return NewBaseMapLegend(
		word.Word(word.ROUT_LGD),
		legAddr,
		descCount,
		dWords,
	)
func (l Legend) Length(vm *VirtualMachine) uint32 {
	return vm.Heap[l.Id+lgd_len_offset].AsInt()
}

func NewMetaMapLegend(descs ...Descriptor) MetaMapLegend {
	descCount := uint32(len(descs))
	dWords := wordsFromDescriptors(descs...)
	return NewBaseMapLegend(
		word.Word(word.META_LGD),
		word.FromAddress(0),
		descCount,
		dWords,
	)
func (l Legend) SetLength(vm *VirtualMachine, i uint32) {
	vm.Heap[l.Id+lgd_len_offset] = word.FromInt(i)
}

type ArrayLegend struct {
	Mark       word.Word
	MetaLegend word.Word
	TrashSweep word.Word
	Field      []Descriptor
func (l Legend) Size(vm *VirtualMachine) uint32 {
	return vm.Heap[l.Id+lgd_sze_offset].AsInt()
}

func NewArrayLegend(mark word.Word) ArrayLegend {
	return ArrayLegend{
		Mark:       mark,
		MetaLegend: word.FromAddress(0),
		TrashSweep: word.Empty(),
		Field:      make([]Descriptor, 0),
	}
func (l Legend) SetSize(vm *VirtualMachine, i uint32) {
	vm.Heap[l.Id+lgd_sze_offset] = word.FromInt(i)
}

A internal/vm/map-list.go => internal/vm/map-list.go +29 -0
@@ 0,0 1,29 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewListMap(virtualMachine *VirtualMachine) Map {
	legend := NewListLegend(virtualMachine)
	words := make([]word.Word, 0, map_fld_offset)
	words = append(words,
		/* Mark:   */ word.Word(word.LIST_MAP),
		/* Legend: */ word.Word(legend.Id),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Map{Id: loc}
}

func ReviveListMap(virtualMachine *VirtualMachine, addr word.Word) Map {
	i := addr.AsAddr()
	CheckMapWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsListMapMark() },
		i,
	)
	return Map{Id: i}
}

A internal/vm/map-meta.go => internal/vm/map-meta.go +29 -0
@@ 0,0 1,29 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewMetaMap(virtualMachine *VirtualMachine) Map {
	legend := NewMetaLegend(virtualMachine)
	words := make([]word.Word, 0, map_fld_offset)
	words = append(words,
		/* Mark:   */ word.Word(word.META_MAP),
		/* Legend: */ word.Word(legend.Id),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Map{Id: loc}
}

func ReviveMetaMap(virtualMachine *VirtualMachine, addr word.Word) Map {
	i := addr.AsAddr()
	CheckMapWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsMetaMapMark() },
		i,
	)
	return Map{Id: i}
}

A internal/vm/map-routine.go => internal/vm/map-routine.go +29 -0
@@ 0,0 1,29 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewRoutMap(virtualMachine *VirtualMachine) Map {
	legend := NewRoutLegend(virtualMachine)
	words := make([]word.Word, 0, map_fld_offset)
	words = append(words,
		/* Mark:   */ word.Word(word.ROUT_MAP),
		/* Legend: */ word.Word(legend.Id),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Map{Id: loc}
}

func ReviveRoutMap(virtualMachine *VirtualMachine, addr word.Word) Map {
	i := addr.AsAddr()
	CheckMapWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsRoutMapMark() },
		i,
	)
	return Map{Id: i}
}

A internal/vm/map-selector.go => internal/vm/map-selector.go +29 -0
@@ 0,0 1,29 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewSeleMap(virtualMachine *VirtualMachine) Map {
	legend := NewSeleLegend(virtualMachine)
	words := make([]word.Word, 0, map_fld_offset)
	words = append(words,
		/* Mark:   */ word.Word(word.SELE_MAP),
		/* Legend: */ word.Word(legend.Id),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Map{Id: loc}
}

func ReviveSeleMap(virtualMachine *VirtualMachine, addr word.Word) Map {
	i := addr.AsAddr()
	CheckMapWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsSeleMapMark() },
		i,
	)
	return Map{Id: i}
}

A internal/vm/map-text.go => internal/vm/map-text.go +29 -0
@@ 0,0 1,29 @@
package vm

import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

func NewTextMap(virtualMachine *VirtualMachine) Map {
	legend := NewTextLegend(virtualMachine)
	words := make([]word.Word, 0, map_fld_offset)
	words = append(words,
		/* Mark:   */ word.Word(word.TEXT_MAP),
		/* Legend: */ word.Word(legend.Id),
	)
	loc, err := virtualMachine.ReAllocate(words...)
	if err != nil {
		panic("allocation failed")
	}
	return Map{Id: loc}
}

func ReviveTextMap(virtualMachine *VirtualMachine, addr word.Word) Map {
	i := addr.AsAddr()
	CheckMapWords(
		virtualMachine,
		func(m word.Word) bool { return m.IsTextMapMark() },
		i,
	)
	return Map{Id: i}
}

M internal/vm/map.go => internal/vm/map.go +118 -22
@@ 1,38 1,134 @@
package vm

import "git.sr.ht/~madcapjake/grhumb/internal/word"
import (
	"git.sr.ht/~madcapjake/grhumb/internal/word"
)

// type RhumbMap struct {
// 	Mark   word.Word
// 	Legend word.Word
// 	Field  []word.Word
// }
const (
	map_lgd_offset uint64 = 1
	map_fld_offset uint64 = 2
)

type RhumbMap []word.Word
type Map struct{ Id uint64 }

func NewMap(mark word.Word, legend word.Word, fields ...word.Word) RhumbMap {
	rmap := make([]word.Word, 0, 2+len(fields))
	rmap = append(rmap, mark, legend)
	rmap = append(rmap, fields...)
	return rmap
func CheckMapWords(
	vm *VirtualMachine,
	isCorrectKindOf func(m word.Word) bool,
	i uint64,
) {
	if !(isCorrectKindOf(vm.Heap[i])) {
		panic("not correct kind of legend mark")
	}
	if !(vm.Heap[i+map_lgd_offset].IsAddress()) {
		panic("map legend word is not an address")
	}
}

func NewMainMap(count uint32, legAddr word.Word) RhumbMap {
	return NewMap(word.Word(word.MAIN_MAP), legAddr)
func (m Map) Append(vm *VirtualMachine, newWord word.Word) Map {
	oldLen := m.Length(vm)
	oldSze := m.Size(vm)
	id, err := vm.Allocate(int(m.Id), int(m.Size(vm)), newWord)
	if err != nil {
		panic("word array append failed")
	} else {
		if id != m.Id {
			m.Id = id
		}
		m.SetLength(vm, oldLen+1)
		m.SetSize(vm, oldSze+1)
		return m
	}
}

func NewListMap(count uint32, legAddr word.Word) RhumbMap {
	return NewMap(word.Word(word.LIST_MAP), legAddr)
func (m Map) Get(vm *VirtualMachine, name RuneArray) word.Word {
	legend := m.ReviveLegend(vm)
	if i, err := legend.Get(vm, name); err != nil {
		return word.Empty()
	} else {
		return m.At(vm, i)
	}

}

func (m Map) Set(vm *VirtualMachine, name RuneArray, value word.Word) (
	result Map,
) {
	legend := m.ReviveLegend(vm)
	if i, err := legend.Get(vm, name); err != nil {
		// New label name
		result = m.Append(vm, value)
		legend = legend.NewDescriptor(
			vm,
			value.AsDesc(),
			name,
			int(result.Length(vm))-1,
		)
		if legend.Id != m.Legend(vm) {
			m.SetLegend(vm, legend.Id)
		}
	} else {
		// Existing label name, i = value offset
		vm.Heap[m.Locate(vm, i)] = value
		result = m
	}
	return
}

func (m Map) Locate(vm *VirtualMachine, i int) uint64 {
	return m.Id + lgd_dat_offset + uint64(i)
}

func (m Map) At(vm *VirtualMachine, i int) word.Word {
	mLen := m.Length(vm)
	if i < 0 || uint32(i) >= mLen {
		panic("index out of bounds")
	}
	return vm.Heap[m.Locate(vm, i)]
}

func (m Map) Legend(vm *VirtualMachine) uint64 {
	return vm.Heap[m.Id+map_lgd_offset].AsAddr()
}

func (m Map) SetLegend(vm *VirtualMachine, l uint64) {
	vm.Heap[m.Id+map_lgd_offset] = word.FromAddress(l)
}

func (m Map) Length(vm *VirtualMachine) uint32 {
	legend := m.ReviveLegend(vm)
	return legend.Length(vm)
}

func (m Map) SetLength(vm *VirtualMachine, i uint32) {
	legend := m.ReviveLegend(vm)
	legend.SetLength(vm, i)
}

func NewTextMap(count uint32, legAddr word.Word) RhumbMap {
	return NewMap(word.Word(word.TEXT_MAP), legAddr)
func (m Map) Size(vm *VirtualMachine) uint32 {
	legend := m.ReviveLegend(vm)
	return legend.Size(vm)
}

func NewRoutMap(count uint32, legAddr word.Word) RhumbMap {
	return NewMap(word.Word(word.ROUT_MAP), legAddr)
func (m Map) SetSize(vm *VirtualMachine, i uint32) {
	legend := m.ReviveLegend(vm)
	legend.SetSize(vm, i)
}

func NewMetaMap(count uint32, legAddr word.Word) RhumbMap {
	return NewMap(word.Word(word.META_MAP), legAddr)
func (m Map) ReviveLegend(vm *VirtualMachine) (legend Legend) {
	legendAddr := vm.Heap[m.Id+map_lgd_offset]
	switch vm.Heap[legendAddr.AsAddr()] {
	case word.Word(word.LIST_LGD):
		legend = ReviveListLegend(vm, legendAddr)
	case word.Word(word.TEXT_LGD):
		legend = ReviveTextLegend(vm, legendAddr)
	case word.Word(word.ROUT_LGD):
		legend = ReviveRoutLegend(vm, legendAddr)
	case word.Word(word.SELE_LGD):
		legend = ReviveSeleLegend(vm, legendAddr)
	case word.Word(word.META_LGD):
		legend = ReviveMetaLegend(vm, legendAddr)
	default:
		panic("Not a map legend")
	}
	return
}

M internal/vm/primitives.go => internal/vm/primitives.go +51 -38
@@ 30,9 30,9 @@ func expBySquaring(x, n uint32) uint32 {
}

func (vm *VirtualMachine) popStack() (popped word.Word) {
	idx := len(vm.stack) - 1
	popped = vm.stack[idx]
	vm.stack = vm.stack[:idx]
	idx := len(vm.Stack) - 1
	popped = vm.Stack[idx]
	vm.Stack = vm.Stack[:idx]
	return
}



@@ 40,69 40,81 @@ func (vm *VirtualMachine) gatherTwoInts() (val1, val2 uint32) {
	stackVal2 := vm.popStack()
	stackVal1 := vm.popStack()
	if stackVal1.IsAddress() {
		val1 = vm.heap[stackVal1.AsAddr()].AsInt()
		val1 = vm.Heap[stackVal1.AsAddr()].AsInt()
	} else if stackVal1.IsInteger() {
		val1 = stackVal1.AsInt()
	}
	if stackVal2.IsAddress() {
		val2 = vm.heap[stackVal2.AsAddr()].AsInt()
		val2 = vm.Heap[stackVal2.AsAddr()].AsInt()
	} else if stackVal2.IsInteger() {
		val2 = stackVal2.AsInt()
	}
	return
}

func (vm *VirtualMachine) assignLabel() {
func (vm *VirtualMachine) assignScopeLabel(mut bool) {
	valWord := vm.popStack()
	addrWord := vm.popStack()
	vm.heap[addrWord.AsAddr()] = valWord
	vm.Heap[addrWord.AsAddr()] = valWord
}

func (vm *VirtualMachine) assignMapLabel(mut bool) {
	valWord := vm.popStack()
	lblWord := vm.popStack()
	label := ReviveRuneArray(vm, lblWord.AsAddr())
	lastMap := len(vm.MapScope) - 1
	vm.MapScope[lastMap] = vm.MapScope[lastMap].Set(vm, label, valWord)
	logAddedToStack(vm.Stack, fmt.Sprint(label, " set to '", valWord))
}

func (vm *VirtualMachine) addTwoInts() {
	val1, val2 := vm.gatherTwoInts()
	vm.stack = append(vm.stack, word.FromInt(val1+val2))
	logAddedToStack(vm.stack, fmt.Sprint(val1, " + ", val2))
	vm.Stack = append(vm.Stack, word.FromInt(val1+val2))
	logAddedToStack(vm.Stack, fmt.Sprint(val1, " + ", val2))
}

func (vm *VirtualMachine) subTwoInts() {
	val1, val2 := vm.gatherTwoInts()
	vm.stack = append(vm.stack, word.FromInt(val1-val2))
	logAddedToStack(vm.stack, fmt.Sprint(val1, " - ", val2))
	vm.Stack = append(vm.Stack, word.FromInt(val1-val2))
	logAddedToStack(vm.Stack, fmt.Sprint(val1, " - ", val2))
}

func (vm *VirtualMachine) mulTwoInts() {
	val1, val2 := vm.gatherTwoInts()
	vm.stack = append(vm.stack, word.FromInt(val1*val2))
	logAddedToStack(vm.stack, fmt.Sprint(val1, " x ", val2, "  "))
	vm.Stack = append(vm.Stack, word.FromInt(val1*val2))
	logAddedToStack(vm.Stack, fmt.Sprint(val1, " x ", val2, "  "))
}

func (vm *VirtualMachine) divTwoInts() {
	val1, val2 := vm.gatherTwoInts()
	vm.stack = append(vm.stack, word.FromInt(val1/val2))
	logAddedToStack(vm.stack, fmt.Sprint(val1, " / ", val2))
	vm.Stack = append(vm.Stack, word.FromInt(val1/val2))
	logAddedToStack(vm.Stack, fmt.Sprint(val1, " / ", val2))
}

func (vm *VirtualMachine) expTwoInts() {
	val1, val2 := vm.gatherTwoInts()
	vm.stack = append(vm.stack, word.FromInt(expBySquaring(val1, val2)))
	logAddedToStack(vm.stack, fmt.Sprint(val1, " ^ ", val2))
	vm.Stack = append(vm.Stack, word.FromInt(expBySquaring(val1, val2)))
	logAddedToStack(vm.Stack, fmt.Sprint(val1, " ^ ", val2))
}

// New scope and add a sentinel to the stack
func (vm *VirtualMachine) beginRoutine() {
	vm.scope = append(vm.scope, make(map[string]uint64))
	vm.stack = append(vm.stack, word.Sentinel())
	vm.LexScope = append(vm.LexScope, make(map[string]uint64))
	vm.Stack = append(vm.Stack, word.Sentinel())
	logAddedToStack(vm.Stack, "'('")
}

// Same as routine
// New CurrentMap
func (vm *VirtualMachine) beginMap() {
	vm.beginRoutine()
	vm.MapScope = append(vm.MapScope, NewListMap(vm))
	vm.Stack = append(vm.Stack, word.Sentinel())
	logAddedToStack(vm.Stack, "*Map")
}

func (vm *VirtualMachine) unwindToSentinel() error {
	for back := len(vm.stack); back > 0; back-- {
		if vm.stack[back].IsSentinel() {
			vm.stack = vm.stack[:back-1]
	for back := len(vm.Stack) - 1; back > 0; back-- {
		if vm.Stack[back].IsSentinel() {
			vm.Stack = vm.Stack[:back]
			return nil
		}
	}


@@ 111,34 123,35 @@ func (vm *VirtualMachine) unwindToSentinel() error {

// Replace all sub stack values with one final result
func (vm *VirtualMachine) endRoutine() {
	stackLen := len(vm.stack)
	last := vm.stack[stackLen-1]
	stackLen := len(vm.Stack)
	last := vm.Stack[stackLen-1]

	vm.scope = vm.scope[:len(vm.scope)-1]
	vm.LexScope = vm.LexScope[:len(vm.LexScope)-1]

	if err := vm.unwindToSentinel(); err != nil {
		panic(err)
	}

	vm.stack = append(vm.stack, last)
	vm.Stack = append(vm.Stack, last)
	logAddedToStack(vm.Stack, last.Debug())
}

// Delete all sub stack values and turn scope into map
// Delete all sub stack values and place map address on stack
func (vm *VirtualMachine) endMap() {
	scopeCount := len(vm.scope)
	// mapScope := vm.scope[scopeCount-1]

	vm.scope = vm.scope[:scopeCount-1]
	last := len(vm.MapScope) - 1
	currMap := vm.MapScope[last]
	if last == 0 {
		vm.MapScope = nil
	} else {
		vm.MapScope = vm.MapScope[:last-1]
	}

	if err := vm.unwindToSentinel(); err != nil {
		panic(err)
	}

	// mapLeg := NewMapLegend(mapScope)
	// legAddr := vm.heap[len(vm.heap)-1]
	// vm.heap = append(vm.heap, mapLeg.AsWords())
	// mapObj := NewMapObject(legAddr, mapScope)
	// vm.heap = append(vm.heap)
	vm.Stack = append(vm.Stack, word.FromAddress(currMap.Id))
	logAddedToStack(vm.Stack, fmt.Sprint("Map@", currMap.Id))
}

/* Phase 2

M internal/vm/vm.go => internal/vm/vm.go +59 -56
@@ 18,11 18,12 @@ func init() {
}

type VirtualMachine struct {
	heap         []word.Word
	free         []bool
	stack        []word.Word
	scope        []map[string]uint64
	CurrentChunk Chunk
	Heap         []word.Word
	Free         []bool
	Stack        []word.Word
	LexScope     []map[string]uint64
	MapScope     []Map
	CurrentChunk RhumbChunk
}

var DEBUG_WIDTH int = 10


@@ 39,21 40,21 @@ func incCheckNL(inc *int) {
func (vm VirtualMachine) DebugHeap() {
	if os.Getenv("RHUMB_VM_DEBUG") == "1" {
		vmLogger.Println("Dumping memory...")
		for i := 0; i < len(vm.heap); i++ {
		for i := 0; i < len(vm.Heap); i++ {
			if i > 0 && i%DEBUG_WIDTH == 0 {
				fmt.Println()
			}
			if vm.free[i] {
			if vm.Free[i] {
				fmt.Printf("{%3v:           }", i)
			} else if vm.heap[i].IsRuneArrayMark() {
			} else if vm.Heap[i].IsRuneArrayMark() {
				j := i
				fmt.Printf("[%3v: %-9s ]", j, vm.heap[j].Debug())
				fmt.Printf("[%3v: %-9s ]", j, vm.Heap[j].Debug())
				incCheckNL(&j)
				fmt.Printf("[%3v: %-9s ]", j, vm.heap[j].Debug())
				fmt.Printf("[%3v: %-9s ]", j, vm.Heap[j].Debug())
				incCheckNL(&j)
				fmt.Printf("[%3v: %-9s ]", j, vm.heap[j].Debug())
				fmt.Printf("[%3v: %-9s ]", j, vm.Heap[j].Debug())
				incCheckNL(&j)
				fmt.Printf("[%3v: %-9s ]", j, vm.heap[j].Debug())
				fmt.Printf("[%3v: %-9s ]", j, vm.Heap[j].Debug())
				incCheckNL(&j)
				fmt.Printf("[%3v: ", j)
				ra := ReviveRuneArray(&vm, uint64(i))


@@ 82,7 83,7 @@ func (vm VirtualMachine) DebugHeap() {
				fmt.Print("]")
				i += int(ra.Size(&vm)) - 1
			} else {
				fmt.Printf("[%3v: %-9s ]", i, vm.heap[i].Debug())
				fmt.Printf("[%3v: %-9s ]", i, vm.Heap[i].Debug())
			}
		}
		fmt.Println()


@@ 92,12 93,12 @@ func (vm VirtualMachine) DebugHeap() {
func NewVirtualMachine() *VirtualMachine {
	vm := new(VirtualMachine)
	const init_heap_len int = 10
	vm.heap = make([]word.Word, 0, init_heap_len)
	vm.free = make([]bool, 0, init_heap_len)
	vm.Heap = make([]word.Word, 0, init_heap_len)
	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]uint64, 0)
	vm.scope = append(vm.scope, make(map[string]uint64))
	vm.Stack = make([]word.Word, 0)
	vm.LexScope = make([]map[string]uint64, 0)
	vm.LexScope = append(vm.LexScope, make(map[string]uint64))

	// TODO: convert to actual routine
	vm.ResetCurrentChunk()


@@ 120,20 121,20 @@ func (vm *VirtualMachine) ReAllocate(ws ...word.Word) (uint64, error) {
		return 0, fmt.Errorf("no words provided")
	}
	var first, next int
	for first = 0; first < len(obj.free); first += next {
	for first = 0; first < len(obj.Free); first += next {
		next = 0
		if obj.free[first] {
		if obj.Free[first] {
			if size == 1 {
				vmLogger.Println("moving word to index:", first)
				obj.heap[first] = ws[0]
				obj.free[first] = false
				obj.Heap[first] = ws[0]
				obj.Free[first] = false
				obj.DebugHeap()
				*vm = obj
				return uint64(first), nil
			} else {
				last := first + size
				for next = range obj.free[first+1 : last] {
					if !(obj.free[next]) {
				for next = range obj.Free[first+1 : last] {
					if !(obj.Free[next]) {
						next++
						break
					} else if next == last {


@@ 150,7 151,7 @@ func (vm *VirtualMachine) ReAllocate(ws ...word.Word) (uint64, error) {
		}
	}
	// no available chunk in existing memory locations.
	first = len(obj.heap)
	first = len(obj.Heap)
	vmLogger.Println("moving words to end:", first)
	obj = appendRhumb(obj, ws)
	*vm = obj


@@ 176,25 177,25 @@ func (vm *VirtualMachine) Allocate(
		return 0, fmt.Errorf("no words provided")
	}
	var i int = lastOldId
	if i == len(obj.free) {
	if i == len(obj.Free) {
		vmLogger.Println("appending words to end:", i)
		obj = appendRhumb(obj, ws)
		*vm = obj
		return uint64(loc), nil
	}

	if obj.free[i] {
	if obj.Free[i] {
		if newSize == 1 {
			vmLogger.Println("appending word to index:", i)
			obj.heap[i] = ws[0]
			obj.free[i] = false
			obj.Heap[i] = ws[0]
			obj.Free[i] = false
			obj.DebugHeap()
			*vm = obj
			return uint64(loc), nil
		} else {
			last := i + newSize - 1
			for i = i + 1; i <= last; i++ {
				if !(obj.free[i]) {
				if !(obj.Free[i]) {
					break
				} else if i == last {
					first := lastOldId


@@ 210,11 211,11 @@ func (vm *VirtualMachine) Allocate(
	// Subsequent memory spots unavailable, search for any
	// available memory spot across heap
	totalWords := make([]word.Word, 0, oldSize+newSize)
	totalWords = append(totalWords, obj.heap[loc:lastOldId]...)
	totalWords = append(totalWords, obj.Heap[loc:lastOldId]...)
	totalWords = append(totalWords, ws...)

	for f := range obj.free[loc:lastOldId] {
		obj.free[loc+f] = true
	for f := range obj.Free[loc:lastOldId] {
		obj.Free[loc+f] = true
	}

	id, err := obj.ReAllocate(totalWords...)


@@ 225,8 226,8 @@ func (vm *VirtualMachine) Allocate(
// Appends to heap and free slices, used in allocate and reallocate
func appendRhumb(vm VirtualMachine, ws []word.Word) VirtualMachine {
	for i := range ws {
		vm.heap = append(vm.heap, ws[i])
		vm.free = append(vm.free, false)
		vm.Heap = append(vm.Heap, ws[i])
		vm.Free = append(vm.Free, false)
	}
	vm.DebugHeap()
	return vm


@@ 236,7 237,7 @@ func appendRhumb(vm VirtualMachine, ws []word.Word) VirtualMachine {
// 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 {
		vm.heap[hID], vm.free[hID] = ws[wID], false
		vm.Heap[hID], vm.Free[hID] = ws[wID], false
	}
}



@@ 268,10 269,10 @@ func (vm *VirtualMachine) Disassemble() {
func (vm *VirtualMachine) Execute(lastValueFlag bool) {
	vm.CurrentChunk.Execute(vm)
	if lastValueFlag {
		if len(vm.stack) == 0 {
		if len(vm.Stack) == 0 {
			fmt.Println("()")
		} else {
			fmt.Println(vm.stack[len(vm.stack)-1].AsInt())
			fmt.Println(vm.Stack[len(vm.Stack)-1].AsInt())
		}
	}
}


@@ 334,28 335,28 @@ func locateScopeLabel(
// }

func (vm *VirtualMachine) AddLiteralToStack(literal word.Word) {
	vm.stack = append(vm.stack, literal)
	logAddedToStack(vm.stack, literal.Debug())
	vm.Stack = append(vm.Stack, literal)
	logAddedToStack(vm.Stack, literal.Debug())
}

// Currently just for lexically traversing the scope
func (vm *VirtualMachine) SubmitLocalRequest(addr word.Word) {
	target := vm.heap[addr.AsAddr()]
	target := vm.Heap[addr.AsAddr()]
	if target.IsRuneArrayMark() {
		label := ReviveRuneArray(vm, addr.AsAddr()).String(vm)
		idx, ok := locateScopeLabel(vm.scope, label)
		idx, ok := locateScopeLabel(vm.LexScope, label)
		if ok {
			// TODO: Invoke address, skip addrRef
			vm.stack = append(vm.stack, word.FromAddress(idx))
			logAddedToStack(vm.stack, label)
			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)
			vm.LexScope[len(vm.LexScope)-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())
		vm.Stack = append(vm.Stack, target)
		logAddedToStack(vm.Stack, target.Debug())
	}
}



@@ 377,15 378,17 @@ func (vm *VirtualMachine) SubmitOuterRequest(label word.Word) {
		panic("unable to find word for outer request")
	}
	refId := lits.id + word_arr_offset + uint64(addr)
	refAddr := vm.heap[refId]
	ref := vm.heap[refAddr.AsAddr()]
	refAddr := vm.Heap[refId]
	ref := vm.Heap[refAddr.AsAddr()]
	if !(ref.IsRuneArrayMark()) {
		panic("outer request submitted with non-ra value")
	}
	text := ReviveRuneArray(vm, refAddr.AsAddr()).String(vm)
	switch text {
	case ".=", ":=":
		vm.assignLabel()
		vm.assignScopeLabel(text[0] != '.')
	case "..", "::":
		vm.assignMapLabel(text[0] != '.')
	case "++":
		vm.addTwoInts()
	case "--":


@@ 396,13 399,13 @@ func (vm *VirtualMachine) SubmitOuterRequest(label word.Word) {
		vm.divTwoInts()
	case "^^":
		vm.expTwoInts()
	case "[[":
	case "[":
		vm.beginMap()
	case "]]":
	case "]":
		vm.endMap()
	case "((":
	case "(":
		vm.beginRoutine()
	case "))":
	case ")":
		vm.endRoutine()

	default:

M internal/word/word.go => internal/word/word.go +73 -32
@@ 31,37 31,39 @@ const SENTINEL uint64 = 0x7F_FE_00_00_00_00_00_00

const MARK_MAP uint64 = 0x7F_FE_40_00_00_00_00_00

const MAIN_MAP uint64 = 0x7F_FE_40_10_00_00_00_00
const LIST_MAP uint64 = 0x7F_FE_40_20_00_00_00_00
const TEXT_MAP uint64 = 0x7F_FE_40_30_00_00_00_00
const ROUT_MAP uint64 = 0x7F_FE_40_40_00_00_00_00
const LIST_MAP uint64 = 0x7F_FE_40_10_00_00_00_00
const TEXT_MAP uint64 = 0x7F_FE_40_20_00_00_00_00
const ROUT_MAP uint64 = 0x7F_FE_40_30_00_00_00_00
const SELE_MAP uint64 = 0x7F_FE_40_40_00_00_00_00
const META_MAP uint64 = 0x7F_FE_40_F0_00_00_00_00

const MARK_ARR uint64 = 0x7F_FE_80_00_00_00_00_00

const MAIN_ARR uint64 = 0x7F_FE_80_20_00_00_00_00
const LIST_ARR uint64 = 0x7F_FE_80_20_00_00_00_00
const RUNE_ARR uint64 = 0x7F_FE_80_30_00_00_00_00
const CODE_ARR uint64 = 0x7F_FE_80_40_00_00_00_00
const META_ARR uint64 = 0x7F_FE_80_F0_00_00_00_00

const MARK_LGD uint64 = 0x7F_FE_C0_00_00_00_00_00

const MAIN_LGD uint64 = 0x7F_FE_C0_10_00_00_00_00
const LIST_LGD uint64 = 0x7F_FE_C0_20_00_00_00_00
const TEXT_LGD uint64 = 0x7F_FE_C0_30_00_00_00_00
const ROUT_LGD uint64 = 0x7F_FE_C0_40_00_00_00_00
const ARRA_LGD uint64 = 0x7F_FE_C0_50_00_00_00_00
const LIST_LGD uint64 = 0x7F_FE_C0_10_00_00_00_00
const TEXT_LGD uint64 = 0x7F_FE_C0_20_00_00_00_00
const ROUT_LGD uint64 = 0x7F_FE_C0_30_00_00_00_00
const SELE_LGD uint64 = 0x7F_FE_C0_40_00_00_00_00
const META_LGD uint64 = 0x7F_FE_C0_F0_00_00_00_00

const MARK_DES uint64 = 0x7F_FF_00_00_00_00_00_00

const DES_NUMB uint64 = 0x7F_FF_00_10_00_00_00_00
const DES_FLOA uint64 = 0x7F_FF_00_20_00_00_00_00
const DES_BOOL uint64 = 0x7F_FF_00_30_00_00_00_00
const DES_RUNE uint64 = 0x7F_FF_00_40_00_00_00_00
const DES_SYMB uint64 = 0x7F_FF_00_50_00_00_00_00
const DES_DATE uint64 = 0x7F_FF_00_60_00_00_00_00
const DES_ADDR uint64 = 0x7F_FF_00_70_00_00_00_00
const DESC_BLE uint64 = 0x7F_FF_00_10_00_00_00_00
const DESC_ETY uint64 = 0x7F_FF_00_20_00_00_00_00
const DESC_INT uint64 = 0x7F_FF_00_30_00_00_00_00
const DESC_RNE uint64 = 0x7F_FF_00_40_00_00_00_00
const DESC_SYM uint64 = 0x7F_FF_00_50_00_00_00_00
const DESC_VER uint64 = 0x7F_FF_00_60_00_00_00_00
const DESC_DTE uint64 = 0x7F_FF_00_70_00_00_00_00
const DESC_ADD uint64 = 0x7F_FF_00_80_00_00_00_00
const DESC_MAP uint64 = 0x7F_FF_00_90_00_00_00_00
const DESC_FLT uint64 = 0x7F_FF_00_F0_00_00_00_00

const CMP_UNIT uint64 = 0x7F_FF_40_00_00_00_00_00



@@ 70,6 72,8 @@ const TAG_MUTA uint64 = 0x00_00_0C_00_00_00_00_00
const TAG_GREY uint64 = 0x00_00_02_00_00_00_00_00
const TAG_BLAK uint64 = 0x00_00_03_00_00_00_00_00

const LINE_NUM uint64 = 0x7F_FF_80_00_00_00_00_00

const MASK_ONE uint64 = 0x7F_FF_C0_00_00_00_00_00
const MASK_TWO uint64 = 0x7F_FF_C0_F0_00_00_00_00



@@ 134,6 138,7 @@ func (w Word) IsInteger() bool { return w.isVal(VAL_NUMB) }
func (w Word) IsRune() bool    { return w.isVal(VAL_RUNE) }
func (w Word) IsDate() bool    { return w.isVal(VAL_DATE) }
func (w Word) IsSym() bool     { return w.isVal(VAL_SYMB) }
func (w Word) IsLineNum() bool { return w.isVal(LINE_NUM) }

func (w Word) IsSentinel() bool { return uint64(w) == SENTINEL }



@@ 144,34 149,36 @@ func (w Word) IsNAN() bool { return w.isMark(ERR_NUMB) }

func (w Word) IsAnyMark() bool     { return uint64(w)&MASK_ONE > MARK_MAP }
func (w Word) IsMapMark() bool     { return w.isMark(MARK_MAP) }
func (w Word) IsMainMapMark() bool { return w.isMark2(MAIN_MAP) }
func (w Word) IsListMapMark() bool { return w.isMark2(LIST_MAP) }
func (w Word) IsTextMapMark() bool { return w.isMark2(TEXT_MAP) }
func (w Word) IsFuncMapMark() bool { return w.isMark2(ROUT_MAP) }
func (w Word) IsRoutMapMark() bool { return w.isMark2(ROUT_MAP) }
func (w Word) IsSeleMapMark() bool { return w.isMark2(SELE_MAP) }
func (w Word) IsMetaMapMark() bool { return w.isMark2(META_MAP) }

func (w Word) IsArrayMark() bool     { return w.isMark(MARK_ARR) }
func (w Word) IsMainArrayMark() bool { return w.isMark2(MAIN_ARR) }
func (w Word) IsListArrayMark() bool { return w.isMark2(LIST_ARR) }
func (w Word) IsRuneArrayMark() bool { return w.isMark2(RUNE_ARR) }
func (w Word) IsCodeArrayMark() bool { return w.isMark2(CODE_ARR) }
func (w Word) IsMetaArrayMark() bool { return w.isMark2(META_ARR) }

func (w Word) IsLegendMark() bool     { return w.isMark(MARK_LGD) }
func (w Word) IsMainLegendMark() bool { return w.isMark2(MAIN_LGD) }
func (w Word) IsListLegendMark() bool { return w.isMark2(LIST_LGD) }
func (w Word) IsTextLegendMark() bool { return w.isMark2(TEXT_LGD) }
func (w Word) IsFuncLegendMark() bool { return w.isMark2(ROUT_LGD) }
func (w Word) IsArraLegendMark() bool { return w.isMark2(ARRA_LGD) }
func (w Word) IsRoutLegendMark() bool { return w.isMark2(ROUT_LGD) }
func (w Word) IsSeleLegendMark() bool { return w.isMark2(SELE_LGD) }
func (w Word) IsMetaLegendMark() bool { return w.isMark2(META_LGD) }

func (w Word) IsDescMark() bool        { return w.isMark(MARK_DES) }
func (w Word) IsIntegerDescMark() bool { return w.isMark2(DES_NUMB) }
func (w Word) IsFloatDescMark() bool   { return w.isMark2(DES_FLOA) }
func (w Word) IsBoolDescMark() bool    { return w.isMark2(DES_BOOL) }
func (w Word) IsRuneDescMark() bool    { return w.isMark2(DES_RUNE) }
func (w Word) IsSymbolDescMark() bool  { return w.isMark2(DES_SYMB) }
func (w Word) IsDateDescMark() bool    { return w.isMark2(DES_DATE) }
func (w Word) IsAddressDescMark() bool { return w.isMark2(DES_ADDR) }
func (w Word) IsBooleanDescMark() bool { return w.isMark2(DESC_BLE) }
func (w Word) IsEmptyDescMark() bool   { return w.isMark2(DESC_ETY) }
func (w Word) IsIntegerDescMark() bool { return w.isMark2(DESC_INT) }
func (w Word) IsRuneDescMark() bool    { return w.isMark2(DESC_RNE) }
func (w Word) IsSymbolDescMark() bool  { return w.isMark2(DESC_SYM) }
func (w Word) IsVersionDescMark() bool { return w.isMark2(DESC_VER) }
func (w Word) IsDateDescMark() bool    { return w.isMark2(DESC_DTE) }
func (w Word) IsAddressDescMark() bool { return w.isMark2(DESC_ADD) }
func (w Word) IsMapDescMark() bool     { return w.isMark2(DESC_MAP) }
func (w Word) IsFloatDescMark() bool   { return w.isMark2(DESC_FLT) }

func (w Word) IsCmpUnit() bool { return w.isMark(CMP_UNIT) }



@@ 199,11 206,11 @@ func (w Word) Debug() string {
		return "MAP MARK"
	} else if w.IsCodeArrayMark() {
		return "CODE MARK"
	} else if w.IsMainArrayMark() {
	} else if w.IsListArrayMark() {
		return "LIST MARK"
	} else if w.IsRuneArrayMark() {
		return "RUNE MARK"
	} else if w.IsFuncMapMark() {
	} else if w.IsRoutMapMark() {
		return "ROUTINE"
	} else if w.IsCmpUnit() {
		return "CMPUNIT"


@@ 264,6 271,38 @@ func (x Word) Equals(y Word) bool {
// func (w Word) IsGrey() bool  { return w.isSwpT(TAG_OBJ_MAP | TAG_SWP_GRY) }
// func (w Word) IsBlack() bool { return w.isSwpT(TAG_OBJ_MAP | TAG_SWP_BLK) }

func (w Word) AsDesc() uint64 {
	if w.IsNAN() {
		return DESC_FLT
	} else if w.IsTrue() {
		return DESC_BLE
	} else if w.IsFalse() {
		return DESC_BLE
	} else if w.IsEmpty() {
		return DESC_ETY
	} else if w.IsInteger() {
		return DESC_INT
	} else if w.IsRune() {
		return DESC_RNE
	} else if w.IsSym() {
		return DESC_SYM
	} else if w.IsAddress() { // must trigger before IsFloat for unknown reasons
		return DESC_ADD
	} else if w.IsFloat() {
		return DESC_FLT
	} else if w.IsMapMark() {
		return DESC_MAP
	} else if w.IsArrayMark() {
		panic("Array mark cannot be placed as value")
	} else if w.IsCmpUnit() {
		panic("CompUnit cannot be placed as value")
	} else if w.IsSentinel() {
		panic("Sentinel cannot be placed as value")
	} else {
		panic("Unknown value provided")
	}
}

func (w Word) AsBool() bool {
	switch uint64(w) {
	case VAL_TRUE:


@@ 288,3 327,5 @@ func (w Word) AsInt() uint32  { return uint32(uint64(w) & ^VAL_NUMB) }
func (w Word) AsRune() rune   { return rune(uint64(w) & ^VAL_RUNE) }
func (w Word) AsSym() uint64  { return uint64(w) & ^VAL_SYMB }
func (w Word) AsAddr() uint64 { return uint64(w) & ^VAL_ADDR }

func (w Word) AsLineNum() uint32 { return uint32(uint64(w) & ^LINE_NUM) }