~madcapjake/rhi

0eaf7eb0a53dcde1b9f0a95021f8bbedb1079afc — Jake Russo 1 year, 8 months ago 38be5b2
more work towards rune arrays and literals
M internal/generator/visitor.go => internal/generator/visitor.go +7 -11
@@ 99,11 99,7 @@ func (v *RhumbVisitor) VisitMutableLabel(ctx *P.MutableLabelContext) interface{}
func (v *RhumbVisitor) VisitLabelLiteral(ctx *P.LabelLiteralContext) interface{} {
	var (
		text string       = ctx.GetText()
		ra   vm.RuneArray = vm.NewRuneArray(
			&v.vm,
			word.FromAddress(0),
			vm.RuneWords(text)...,
		)
		ra   vm.RuneArray = vm.NewRuneArray(&v.vm, word.FromAddress(0), []rune(text)...)
	)
	logger.Println("label:", text)
	v.vm.WriteCodeToMain(


@@ 127,7 123,7 @@ func (v *RhumbVisitor) VisitAssignment(ctx *P.AssignmentContext) interface{} {
		// TODO: check for a matching subroutine and invoke
		// TODO: check for matching outer scoped label

		ra = vm.NewRuneArray(&v.vm, word.FromAddress(0), vm.RuneWords(text)...)
		ra = vm.NewRuneArray(&v.vm, word.FromAddress(0), []rune(text)...)

		v.vm.WriteCodeToMain(
			addr.GetLine(),


@@ 140,7 136,7 @@ func (v *RhumbVisitor) VisitAssignment(ctx *P.AssignmentContext) interface{} {
		logger.Printf("addrRef.Accept(v): %v\n", addrRef.Accept(v))
		text = addrRef.GetText()
		logger.Println("AddressRef:", text)
		ra = vm.NewRuneArray(&v.vm, word.FromAddress(0), vm.RuneWords(text)...)
		ra = vm.NewRuneArray(&v.vm, word.FromAddress(0), []rune(text)...)
		v.vm.WriteCodeToMain(
			addrRef.GetStart().GetLine(),
			word.FromAddress(int(ra.Id())),


@@ 155,7 151,7 @@ func (v *RhumbVisitor) VisitAssignment(ctx *P.AssignmentContext) interface{} {
	ra = vm.NewRuneArray(
		&v.vm,
		word.FromAddress(0),
		vm.RuneWords(op.GetText())...,
		[]rune(op.GetText())...,
	)
	v.vm.WriteCodeToMain(
		op.GetStart().GetLine(),


@@ 234,7 230,7 @@ func (v *RhumbVisitor) VisitMultiplicative(ctx *P.MultiplicativeContext) interfa
		ra    vm.RuneArray               = vm.NewRuneArray(
			&v.vm,
			word.FromAddress(0),
			vm.RuneWords(mulOp.GetText())...,
			[]rune(mulOp.GetText())...,
		)
	)



@@ 258,7 254,7 @@ func (v *RhumbVisitor) VisitAdditive(ctx *P.AdditiveContext) interface{} {
		ra    vm.RuneArray           = vm.NewRuneArray(
			&v.vm,
			word.FromAddress(0),
			vm.RuneWords(addOp.GetText())...,
			[]rune(addOp.GetText())...,
		)
	)



@@ 317,7 313,7 @@ func (v *RhumbVisitor) VisitPower(ctx *P.PowerContext) interface{} {
		ra    vm.RuneArray               = vm.NewRuneArray(
			&v.vm,
			word.FromAddress(0),
			vm.RuneWords(powOp.GetText())...,
			[]rune(powOp.GetText())...,
		)
	)
	for i := range exprs {

M internal/vm/chunk.go => internal/vm/chunk.go +39 -17
@@ 46,29 46,36 @@ func ReviveChunk(vm *VirtualMachine, addr word.Word) Chunk {

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

	instructions := ch.Instructions(vm)
	instructions := ch.ReviveInstrs(vm)
	if line > ch.line {
		instructions.SetCodes(vm, true, codes...)
		ch.line = line
	} else {
		instructions.SetCodes(vm, false, codes...)
	}
	caId := ch.id + chunk_ca_offset
	if instructions.id != vm.heap[caId].AsAddr() {
		vm.heap[caId] = word.FromAddress(int(instructions.id))
	if instructions.id != ch.Instructions(vm).AsAddr() {
		ch.SetInstructionsAddress(vm, instructions.id)
	}
}

func (ch Chunk) SetInstructionsAddress(vm *VirtualMachine, addr uint64) {
	vm.heap[ch.id+chunk_ca_offset] = word.FromAddress(int(addr))
}

func (ch Chunk) SetLiteralsAddress(vm *VirtualMachine, addr uint64) {
	vm.heap[ch.id+chunk_wa_offset] = word.FromAddress(int(addr))
}

func (ch *Chunk) AddLiteral(vm *VirtualMachine, lit word.Word) (uint64, error) {
	literals := ch.Literals(vm)
	literals := ch.ReviveLits(vm)
	existingIndex, err := literals.IndexOf(vm, lit)
	if err != nil {
		id, err := literals.Append(vm, lit)
		if err != nil {
			panic("literals append failed")
		}
		if id != vm.heap[ch.id+chunk_wa_offset].AsAddr() {
			vm.heap[ch.id+chunk_wa_offset] = word.FromAddress(int(id))
		if id != ch.Literals(vm).AsAddr() {
			ch.SetLiteralsAddress(vm, id)
		}
		return id, err
	} else {


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

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

func (ch Chunk) Literals(vm *VirtualMachine) WordArray {
	return ReviveWordArray(vm, vm.heap[ch.id+chunk_wa_offset])
func (ch Chunk) 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 Chunk) ReviveLits(vm *VirtualMachine) WordArray {
	return ReviveWordArray(vm, ch.Literals(vm))
}

func (ch Chunk) Execute(vm *VirtualMachine) {
	var (
		instructions        = ch.Instructions(vm)
		cwLen        int    = int(instructions.Length(vm))
		instructions        = ch.ReviveInstrs(vm)
		cwLen        int    = int(instructions.Size(vm) - code_arr_offset)
		idx          uint64 = 0
		buf          []byte = make([]byte, 0, cwLen*8)
	)
	for wordIndex := 0; wordIndex < cwLen; wordIndex++ {
		instructions.getCodesFromWord(vm, uint64(wordIndex), &buf)
		w := vm.heap[instructions.id+code_arr_offset+uint64(wordIndex)]
		if w.IsSentinel() {
			ch.line++
			continue
		}
		instructions.getCodesFromWord(vm, w, &buf)
		for b := range buf {
			if buf[b] == 0 {
				break


@@ 102,6 122,7 @@ func (ch Chunk) Execute(vm *VirtualMachine) {
			if code.IsIndexExtension() {
				continue
			} else {
				// FIXME: something is wrong here
				ch.execTagIndex(vm, code.Tag(), int(idx))
				idx = 0
			}


@@ 114,8 135,9 @@ func (ch Chunk) execTagIndex(vm *VirtualMachine, b byte, idx int) {
	var (
		code     Code  = Code(b)
		tag      uint8 = code.Tag()
		literals       = ch.Literals(vm)
		literals       = ch.ReviveLits(vm)
	)
	fmt.Println("Executing chunk tag:", tag)
	switch tag {
	case TAG_VALUE_LITERAL:
		vm.AddLiteralToStack(literals.Get(vm, idx))


@@ 137,7 159,7 @@ func (ch Chunk) execTagIndex(vm *VirtualMachine, b byte, idx int) {
func (ch Chunk) Disassemble(vm *VirtualMachine) {
	fmt.Println("============= Chunk =============")
	var line int
	instructions := ch.Instructions(vm)
	instructions := ch.ReviveInstrs(vm)
	buf := instructions.GetCodes(vm)
	for offset := 0; offset < int(instructions.Length(vm)); {
		if line < instructions.GetLine(vm, offset) {


@@ 169,7 191,7 @@ func (ch Chunk) DisassembleCode(vm *VirtualMachine, currentLine, currentOffset i
			fmt.Printf("%s %d '%v'\n",
				Code(buf[o]).String(),
				idx,
				ch.Literals(vm).Get(vm, int(idx)).Debug(),
				ch.ReviveLits(vm).Get(vm, int(idx)).Debug(),
			)
			return l, o + 1
		}

M internal/vm/code_array.go => internal/vm/code_array.go +48 -38
@@ 98,7 98,9 @@ func (ca CodeArray) NewSize(vm *VirtualMachine, newLine bool, cs ...Code) (size 
		}
	} else {
		size = origSize
		remainder = ca.getWordCodeCount(vm, uint64(ca.Size(vm)-1))
		id := ca.id + code_arr_offset + uint64(ca.Size(vm)-1)
		word := vm.heap[id]
		remainder = ca.getWordCodeCount(vm, word)
		freshLength = newLength - remainder
		wholeWords = freshLength / 8
		remainder = freshLength % 8


@@ 119,49 121,51 @@ func (ca *CodeArray) SetCodes(
	var (
		origLen  uint64 = uint64(ca.Length(vm))
		newLen   uint32 = uint32(len(cs))
		byteSize uint32 = 8
		codeID   uint32
		initSize uint32
		bs       []byte      = make([]byte, 0, byteSize)
		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]
	)
	if newLine {
		ws = append(ws, word.Sentinel())
	} else {
		if ca.lastWordVacancy(vm) {
			ca.getCodesFromWord(vm, uint64(ca.Length(vm))-1, &bs)
			initSize = uint32(len(bs))
			for ; codeID < newLen; codeID++ {
				bs = append(bs, byte(cs[codeID]))
				if initSize+codeID+1 == byteSize {
			ca.getCodesFromWord(vm, lastWord, &bs)
			initSz = uint32(len(bs))
			for codeID, code = range cs {
				bs = append(bs, byte(code))
				if initSz+uint32(codeID)+1 == byteSz {
					vm.heap[ca.id+ca.Size(vm)] = word.Word(
						binary.BigEndian.Uint64(bs))
					bs = make([]byte, 0, byteSize)
					bs = make([]byte, 0, byteSz)
					break
				}
			}

		}
	}
	for ; codeID < newLen; codeID++ {
		bs = append(bs, byte(cs[codeID]))
		if codeID+1 == byteSize {
	for codeID, code = range cs {
		bs = append(bs, byte(code))
		if codeID+1 == int(byteSz) {
			ws = append(ws, word.Word(binary.BigEndian.Uint64(bs)))
			bs = make([]byte, 0, byteSize)
			bs = make([]byte, 0, byteSz)
		}
	}

	if len(bs) > 0 {
		caLogger.Println(bs)
		for range bs[len(bs):byteSize] {
		for range bs[len(bs):byteSz] {
			bs = append(bs, 0x0)
		}
		ws = append(ws, word.Word(binary.BigEndian.Uint64(bs)))
	}

	finalLength := uint32(origLen) + uint32(len(ws))
	wordsLen := uint32(len(ws))
	finalLength := uint32(origLen) + wordsLen
	ca.SetSize(vm, finalLength+4)
	ca.SetLength(vm, finalLength)
	ca.SetLength(vm, wordsLen)
	newId, _ := vm.Allocate(
		int(ca.id),
		int(origLen)+int(code_arr_offset),


@@ 174,8 178,15 @@ func (ca *CodeArray) SetCodes(
}

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

// func (ca *CodeArray) currentIndex(vm *VirtualMachine) int {


@@ 186,11 197,8 @@ func (ca *CodeArray) lastWordVacancy(vm *VirtualMachine) bool {
// 	}
// }

func (ca CodeArray) getCodesFromWord(vm *VirtualMachine, wi uint64, b *[]byte) {
	var (
		buf  []byte    = *b
		word word.Word = vm.heap[ca.id+code_arr_offset+wi]
	)
func (ca CodeArray) getCodesFromWord(vm *VirtualMachine, word word.Word, b *[]byte) {
	var buf []byte = *b
	if word.IsSentinel() {
		panic("cannot get codes from sentinel")
	}


@@ 205,12 213,7 @@ func (ca CodeArray) getCodesFromWord(vm *VirtualMachine, wi uint64, b *[]byte) {
	*b = buf
}

func (ca CodeArray) getWordCodeCount(vm *VirtualMachine, wi uint64) int {
	var (
		count int
		id    uint64    = ca.id + code_arr_offset + wi
		word  word.Word = vm.heap[id]
	)
func (ca CodeArray) getWordCodeCount(vm *VirtualMachine, word word.Word) (count int) {
	if word.IsSentinel() {
		panic("cannot get codes from sentinel")
	}


@@ 222,15 225,18 @@ func (ca CodeArray) getWordCodeCount(vm *VirtualMachine, wi uint64) int {
		}
		count = count + 1
	}
	return count
	return
}

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


@@ 245,7 251,11 @@ func (ca *CodeArray) GetLine(vm *VirtualMachine, codeIndex int) (lines int) {
		if vm.heap[ca.id+code_arr_offset+i].IsSentinel() {
			lines += 1
		} else {
			codes += ca.getWordCodeCount(vm, i)
			var (
				id   uint64    = ca.id + code_arr_offset + i
				word word.Word = vm.heap[id]
			)
			codes += ca.getWordCodeCount(vm, word)
		}
	}
	return

M internal/vm/rune_array.go => internal/vm/rune_array.go +37 -9
@@ 43,18 43,42 @@ func RuneWords(str string) (words []word.Word) {
func NewRuneArray(
	vm *VirtualMachine,
	legAddr word.Word,
	words ...word.Word,
	runes ...rune,
) RuneArray {
	wordsLen := uint32(len(words))
	wordsSize := uint32(code_arr_offset) + wordsLen
	raWords := make([]word.Word, 0, wordsSize)
	var (
		runesLen  uint32      = uint32(len(runes))
		runesSize uint32      = uint32(code_arr_offset) + runesLen
		raWords   []word.Word = make([]word.Word, 0, runesSize)
		runeBytes []byte
		wordBytes []byte
		offset    uint32
	)
	raWords = append(raWords,
		/* Mark:   */ word.Word(word.RUNE_ARR),
		/* Legend: */ legAddr,
		/* Size:   */ word.FromInt(wordsSize),
		/* Length: */ word.FromInt(wordsLen),
		/* Size:   */ word.FromInt(runesSize),
		/* Length: */ word.FromInt(runesLen),
	)
	raWords = append(raWords, words...)
	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 {
			copy(wordBytes, runeBytes)
			if i == len(runes)-1 {
				raWords = append(raWords,
					word.Word(binary.LittleEndian.Uint64(wordBytes)))
			}
		} else {
			for i, rb := range runeBytes {
				wordBytes[i+4] = rb
			}
			raWords = append(raWords,
				word.Word(binary.LittleEndian.Uint64(wordBytes)))
		}

	}

	loc, err := vm.ReAllocate(raWords...)
	if err != nil {


@@ 63,6 87,10 @@ func NewRuneArray(
	return RuneArray{uint64(loc)}
}

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

// }

func ReviveRuneArray(vm *VirtualMachine, addr word.Word) RuneArray {
	i := addr.AsAddr()
	mark := vm.heap[i]


@@ 139,8 167,8 @@ func (ra RuneArray) SetRune(vm *VirtualMachine, i uint32, r rune) {
	if offset == 0 {
		copy(wordBytes, runeBytes)
	} else {
		for i := range runeBytes {
			wordBytes[i+4] = runeBytes[i]
		for i, rb := range runeBytes {
			wordBytes[i+4] = rb
		}
	}
	vm.heap[id] = word.Word(binary.LittleEndian.Uint64(wordBytes))

M internal/vm/vm.go => internal/vm/vm.go +11 -2
@@ 210,7 210,7 @@ func (vm *VirtualMachine) Disassemble() {
}

func (vm *VirtualMachine) Execute() {
	// vm.main.Execute(vm)
	vm.main.Execute(vm)
}

func logAddedToStack(stack []word.Word, txt string) {


@@ 308,7 308,16 @@ func (vm *VirtualMachine) SubmitUnderRequest(label word.Word) {
// Used for traversing primitives and compilations
func (vm *VirtualMachine) SubmitOuterRequest(label word.Word) {
	// FIXME: locate text
	text := ""
	addr, err := vm.main.ReviveLits(vm).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)]
	if !(ref.IsRuneArrayMark()) {
		panic("outer request submitted with non-ra value")
	}
	text := ReviveRuneArray(vm, ref).String(vm)
	fmt.Println(text)
	switch text {
	case ".=", ":=":
		vm.assignLabel()

M internal/vm/word_array.go => internal/vm/word_array.go +42 -15
@@ 24,14 24,6 @@ type WordArray struct {
	id uint64
}

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

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

func NewWordArray(
	vm *VirtualMachine,
	legAddr word.Word,


@@ 72,26 64,49 @@ func ReviveWordArray(vm *VirtualMachine, addr word.Word) WordArray {
	return WordArray{i}
}

func (wa WordArray) IndexOf(vm *VirtualMachine, w word.Word) (idx int, err error) {
	len := wa.Length(vm)
	for i := range make([]int, len) {
		found := w.Equals(wa.Get(vm, i))
		if found {
			return i, nil
func (wa WordArray) IndexOf(vm *VirtualMachine, x word.Word) (
	idx int,
	err error,
) {
	if x.IsAddress() {
		mkX := vm.heap[x.AsAddr()]
		if mkX.IsRuneArrayMark() {
			rax := ReviveRuneArray(vm, x)
			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)
						if rax.String(vm) == ray.String(vm) {
							return i, nil
						}
					}
				}
			}
		}
	} else {
		for i := range make([]int, wa.Length(vm)) {
			if x.Equals(wa.Get(vm, i)) {
				return i, nil
			}
		}

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

func (wa *WordArray) Append(vm *VirtualMachine, newWords ...word.Word) (uint64, error) {
	oldLen := uint32(wa.Length(vm))
	newLen := oldLen + uint32(len(newWords))
	id, err := vm.Allocate(int(wa.id), wa.Size(vm), newWords...)
	if err != nil {
		panic("word array append failed")
	} else {
		if id != wa.id {
			// vm.UpdateAddresses(wa.id, id)
			wa.id = id
		}
		wa.SetLength(vm, newLen)
		return id, err
	}
}


@@ 100,6 115,18 @@ func (wa WordArray) Get(vm *VirtualMachine, i int) word.Word {
	return vm.heap[wa.id+word_arr_offset+uint64(i)]
}

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

func (wa WordArray) SetLength(vm *VirtualMachine, l uint32) {
	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())
}

func (wa WordArray) Size(vm *VirtualMachine) int {
	return wa.Length(vm) + 3
}