~madcapjake/rhi

84384506d24bb9dab2dc7ea80a7cfcaadd7808f8 — Jake Russo 1 year, 9 months ago a169f91
add prelim updates to support maps and scopes
M internal/vm/code_array.go => internal/vm/code_array.go +2 -2
@@ 24,8 24,8 @@ type CodeArray struct {

func NewCodeArray(words ...Word) CodeArray {
	return CodeArray{
		Mark:      Word(TAG_OBJ_ARR),
		Legend:    Word(TAG_ADDRESS),
		Mark:      Word(CODE_ARR),
		Legend:    Word(VAL_ADDR),
		Length:    WordFromInt(uint32(len(words))),
		CodeWords: words,
	}

M internal/vm/map.go => internal/vm/map.go +21 -6
@@ 6,11 6,11 @@ type Map struct {
	Field  []Word
}

func NewMap() Map {
func NewMap(count uint32, legAddr Word) Map {
	return Map{
		Word(TAG_OBJ_MAP),
		Word(TAG_ADDRESS), // FIXME: Empty Address
		make([]Word, 0),
		Word(MAIN_MAP),
		WordFromAddress(0),
		make([]Word, count),
	}
}



@@ 25,6 25,19 @@ type MapLegend struct {
	Field      []LegendFieldDescriptor
}

func NewMapLegend() MapLegend {
	return MapLegend{
		Word(MAIN_LGD),
		WordFromAddress(0),
		EmptyWord(),
		WordFromInt(0),
		WordFromInt(0),
		WordFromAddress(0),
		WordFromAddress(0),
		make([]LegendFieldDescriptor, 0),
	}
}

type RoutineLegend struct {
	Mark       Word
	MetaLegend Word // pointer to the toplevel MapLegend


@@ 44,8 57,10 @@ type ArrayLegend struct {
	Parent     LegendFieldDescriptor
}

// T

type LegendFieldDescriptor struct {
	Name Word
	Type Word // immutable, mutable, subfield
	Mark Word // immutable, mutable, subfield
	Name Word // address to TextMap
	Data Word // constant, field offset, or
}

M internal/vm/primitives.go => internal/vm/primitives.go +40 -12
@@ 52,14 52,14 @@ func (vm *VirtualMachine) popStack() (popped Word) {
func (vm *VirtualMachine) gatherTwoInts() (val1, val2 uint32) {
	stackVal2 := vm.popStack()
	stackVal1 := vm.popStack()
	if stackVal1.IsAddr() {
	if stackVal1.IsAddress() {
		val1 = vm.heap[stackVal1.AsAddr()].AsInt()
	} else if stackVal1.IsInt() {
	} else if stackVal1.IsInteger() {
		val1 = stackVal1.AsInt()
	}
	if stackVal2.IsAddr() {
	if stackVal2.IsAddress() {
		val2 = vm.heap[stackVal2.AsAddr()].AsInt()
	} else if stackVal2.IsInt() {
	} else if stackVal2.IsInteger() {
		val2 = stackVal2.AsInt()
	}
	return


@@ 101,29 101,57 @@ func (vm *VirtualMachine) expTwoInts() {
	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]int))
	vm.stack = append(vm.stack, Word(TAG_MRK_STL))
	vm.stack = append(vm.stack, Word(SENTINEL))
}

func (vm *VirtualMachine) endRoutine() {
	// TODO: try to delete things?
	vm.scope = vm.scope[:len(vm.scope)-1]
// Same as routine
func (vm *VirtualMachine) beginMap() {
	vm.beginRoutine()
}

func (vm *VirtualMachine) unwindToSentinel() error {
	for back := len(vm.stack); back > 0; back-- {
		if vm.stack[back].IsSentinel() {
			last := vm.stack[len(vm.stack)-1]
			vm.stack = vm.stack[:back]
			vm.stack[back] = last
			vm.stack = vm.stack[:back-1]
			return nil
		}
	}
	return fmt.Errorf("No sentinel found")
}

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

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

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

	vm.stack = append(vm.stack, last)
}

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

	vm.scope = vm.scope[:scopeCount-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)
}

/* Phase 2

M internal/vm/rune_array.go => internal/vm/rune_array.go +1 -1
@@ 15,7 15,7 @@ type RuneArray struct {

func NewRuneArray(addr Word, words ...Word) RuneArray {
	return RuneArray{
		Word(TAG_OBJ_ARR),
		Word(RUNE_ARR),
		addr,
		WordFromInt(uint32(len(words))),
		words,

M internal/vm/vm.go => internal/vm/vm.go +2 -2
@@ 75,14 75,14 @@ func (vm *VirtualMachine) SubmitLocalRequest(ir InstrRef) {
	idx, ok := locateScopeLabel(vm.scope, ir.text)
	if ok {
		// TODO: Invoke address, skip addrRef
		vm.stack = append(vm.stack, WordFromAddr(idx))
		vm.stack = append(vm.stack, WordFromAddress(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, WordFromAddr(idx))
	vm.stack = append(vm.stack, WordFromAddress(idx))
	logAddedToStack(vm.stack, ir.text)
}


M internal/vm/word.go => internal/vm/word.go +130 -65
@@ 9,36 9,68 @@ import (

type Word uint64

const TAG_SLT_NAN uint64 = 0x7F_FC_00_00_00_00_00_00
const MASK_NAN uint64 = 0x7F_FC_00_00_00_00_00_00

const TAG_ADDRESS uint64 = 0x80_00_00_00_00_00_00_00
const VAL_ADDR uint64 = 0xFF_FC_00_00_00_00_00_00

const TAG_LIT_NAN uint64 = 0x7F_FC_00_00_00_00_00_00
const TAG_LIT_TRU uint64 = 0x7F_FC_40_00_00_00_00_00
const TAG_LIT_FLS uint64 = 0x7F_FC_80_00_00_00_00_00
const TAG_LIT_ETY uint64 = 0x7F_FC_C0_00_00_00_00_00
const MARK_ERR uint64 = 0x7F_FC_00_00_00_00_00_00

const TAG_LIT_INT uint64 = 0x7F_FD_00_00_00_00_00_00
const TAG_LIT_RNE uint64 = 0x7F_FD_40_00_00_00_00_00
const TAG_LIT_SYM uint64 = 0x7F_FD_80_00_00_00_00_00
const ERR_MAIN uint64 = 0x7F_FC_00_10_00_00_00_00
const ERR_NUMB uint64 = 0x7F_FC_00_20_00_00_00_00

const TAG_OBJ_MAP uint64 = 0x7F_FE_00_00_00_00_00_00
const TAG_OBJ_ARR uint64 = 0x7F_FE_40_00_00_00_00_00
const TAG_OBJ_ROU uint64 = 0x7F_FE_80_00_00_00_00_00
const TAG_OBJ_CHU uint64 = 0x7F_FE_C0_00_00_00_00_00
const VAL_TRUE uint64 = 0x7F_FC_40_00_00_00_00_00
const VAL_FALS uint64 = 0x7F_FC_80_00_00_00_00_00
const VAL_EMPT uint64 = 0x7F_FC_C0_00_00_00_00_00

const TAG_LEG_MAP uint64 = 0x7F_FF_00_00_00_00_00_00
const TAG_LEG_ARR uint64 = 0x7F_FF_10_00_00_00_00_00
const TAG_LEG_ROU uint64 = 0x7F_FF_C0_00_00_00_00_00
const VAL_NUMB uint64 = 0x7F_FD_00_00_00_00_00_00
const VAL_RUNE uint64 = 0x7F_FD_40_00_00_00_00_00
const VAL_SYMB uint64 = 0x7F_FD_80_00_00_00_00_00
const VAL_DATE uint64 = 0x7F_FD_C0_00_00_00_00_00

const TAG_MRK_STL uint64 = 0x7F_FD_C0_00_00_00_00_00
const SENTINEL uint64 = 0x7F_FE_00_00_00_00_00_00

const TAG_ALLMARK uint64 = TAG_LEG_ROU
const MARK_MAP uint64 = 0x7F_FE_40_00_00_00_00_00

const TAG_SWP_WHT uint64 = 0x00_00_00_00_00_00_00_00
const TAG_SWP_GRY uint64 = 0x00_00_00_00_00_00_00_01
const TAG_SWP_BLK uint64 = 0x00_00_00_00_00_00_00_02
const TAG_SWPMASK uint64 = 0x00_00_00_00_00_00_00_03
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 FUNC_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 RUNE_ARR uint64 = 0x7F_FE_80_30_00_00_00_00
const CODE_ARR uint64 = 0x7F_FE_40_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 FUNC_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 CMP_UNIT uint64 = 0x7F_FF_40_00_00_00_00_00

const TAG_IMMU uint64 = 0x00_00_08_00_00_00_00_00
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 MASK_ONE uint64 = 0x7F_FF_C0_00_00_00_00_00
const MASK_TWO uint64 = 0x7F_FF_C0_F0_00_00_00_00

func NewWord(a any) Word {
	switch a := a.(type) {


@@ 59,7 91,8 @@ func NewWord(a any) Word {
	}
}

func EmptyWord() Word { return Word(TAG_LIT_ETY) }
func EmptyWord() Word      { return Word(VAL_EMPT) }
func NotANumberWord() Word { return Word(ERR_NUMB) }

func WordFromFloat(f float64) Word {
	var bytes [8]byte


@@ 77,34 110,66 @@ func WordFromFloat(f float64) Word {

func WordFromBool(b bool) Word {
	if b {
		return Word(TAG_LIT_TRU)
		return Word(VAL_TRUE)
	} else {
		return Word(TAG_LIT_FLS)
		return Word(VAL_FALS)
	}
}
func WordFromInt(i uint32) Word { return Word(TAG_LIT_INT | uint64(i)) }
func WordFromRune(r rune) Word  { return Word(TAG_LIT_RNE | uint64(r)) }
func WordFromSym(a int) Word    { return Word(TAG_LIT_SYM | uint64(a)) }
func WordFromAddr(a int) Word   { return Word(TAG_ADDRESS | uint64(a)) }

func (w Word) IsFloat() bool    { return uint64(w)&TAG_SLT_NAN != TAG_SLT_NAN }
func (w Word) IsAddr() bool     { return uint64(w)&TAG_ADDRESS == TAG_ADDRESS }
func (w Word) IsNAN() bool      { return uint64(w) == TAG_LIT_NAN }
func (w Word) IsTrue() bool     { return uint64(w) == TAG_LIT_TRU }
func (w Word) IsFalse() bool    { return uint64(w) == TAG_LIT_FLS }
func (w Word) IsBool() bool     { return w.IsTrue() || w.IsFalse() }
func (w Word) IsEmpty() bool    { return uint64(w) == TAG_LIT_ETY }
func (w Word) IsInt() bool      { return uint64(w)&TAG_LIT_INT == TAG_LIT_INT }
func (w Word) IsRune() bool     { return uint64(w)&TAG_LIT_RNE == TAG_LIT_RNE }
func (w Word) IsSym() bool      { return uint64(w)&TAG_LIT_SYM == TAG_LIT_SYM }
func (w Word) IsSentinel() bool { return uint64(w)&TAG_MRK_STL == TAG_MRK_STL }
func (w Word) IsMark() bool     { return uint64(w)&TAG_OBJ_MAP == TAG_OBJ_MAP }

func (w Word) isMrkT(t uint64) bool { return uint64(w)&TAG_ALLMARK == t }
func (w Word) IsMap() bool          { return w.isMrkT(TAG_OBJ_MAP) }
func (w Word) IsArray() bool        { return w.isMrkT(TAG_OBJ_ARR) }
func (w Word) IsRoutine() bool      { return w.isMrkT(TAG_OBJ_ROU) }
func (w Word) IsChunk() bool        { return w.isMrkT(TAG_OBJ_CHU) }
func WordFromInt(i uint32) Word  { return Word(VAL_NUMB | uint64(i)) }
func WordFromRune(r rune) Word   { return Word(VAL_RUNE | uint64(r)) }
func WordFromSym(a int) Word     { return Word(VAL_SYMB | uint64(a)) }
func WordFromAddress(a int) Word { return Word(VAL_ADDR | uint64(a)) }

func (w Word) isVal(v uint64) bool { return uint64(w)&MASK_ONE == v }

func (w Word) IsFloat() bool   { return uint64(w)&MASK_NAN != MASK_NAN }
func (w Word) IsAddress() bool { return w.isVal(VAL_ADDR) }
func (w Word) IsTrue() bool    { return uint64(w) == VAL_TRUE }
func (w Word) IsFalse() bool   { return uint64(w) == VAL_FALS }
func (w Word) IsBool() bool    { return w.IsTrue() || w.IsFalse() }
func (w Word) IsEmpty() bool   { return uint64(w) == VAL_EMPT }
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) IsSentinel() bool { return uint64(w) == SENTINEL }

func (w Word) isMark(m uint64) bool { return uint64(w)&MASK_ONE == m }

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.isMark(MAIN_MAP) }
func (w Word) IsListMapMark() bool { return w.isMark(LIST_MAP) }
func (w Word) IsTextMapMark() bool { return w.isMark(TEXT_MAP) }
func (w Word) IsFuncMapMark() bool { return w.isMark(FUNC_MAP) }
func (w Word) IsMetaMapMark() bool { return w.isMark(META_MAP) }

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

func (w Word) IsLegendMark() bool     { return w.isMark(MARK_LGD) }
func (w Word) IsMainLegendMark() bool { return w.isMark(MAIN_LGD) }
func (w Word) IsListLegendMark() bool { return w.isMark(LIST_LGD) }
func (w Word) IsTextLegendMark() bool { return w.isMark(TEXT_LGD) }
func (w Word) IsFuncLegendMark() bool { return w.isMark(FUNC_LGD) }
func (w Word) IsMetaLegendMark() bool { return w.isMark(META_LGD) }

func (w Word) IsDescMark() bool        { return w.isMark(MARK_DES) }
func (w Word) IsIntegerDescMark() bool { return w.isMark(DES_NUMB) }
func (w Word) IsFloatDescMark() bool   { return w.isMark(DES_FLOA) }
func (w Word) IsBoolDescMark() bool    { return w.isMark(DES_BOOL) }
func (w Word) IsRuneDescMark() bool    { return w.isMark(DES_RUNE) }
func (w Word) IsSymbolDescMark() bool  { return w.isMark(DES_SYMB) }
func (w Word) IsDateDescMark() bool    { return w.isMark(DES_DATE) }
func (w Word) IsAddressDescMark() bool { return w.isMark(DES_ADDR) }

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

func (w Word) Debug() any {
	if w.IsNAN() {


@@ 115,21 180,21 @@ func (w Word) Debug() any {
		return "FALSE"
	} else if w.IsEmpty() {
		return "EMPTY"
	} else if w.IsInt() {
	} else if w.IsInteger() {
		return fmt.Sprint("{INT: ", w.AsInt(), "}")
	} else if w.IsRune() {
		return fmt.Sprint("{RUNE: ", w.AsRune(), "}")
	} else if w.IsSym() {
		return "SYMBOL" // FIXME: Implement symbols
	} else if w.IsAddr() { // must trigger before IsFloat for unknown reasons
	} else if w.IsAddress() { // must trigger before IsFloat for unknown reasons
		return fmt.Sprint("{ADDR: ", w.AsAddr(), "}")
	} else if w.IsFloat() {
		return fmt.Sprint("{FLOAT: ", w.AsFloat(), "}")
	} else if w.IsMap() {
	} else if w.IsMapMark() {
		return "MAP"
	} else if w.IsArray() {
	} else if w.IsArrayMark() {
		return "ARRAY"
	} else if w.IsRoutine() {
	} else if w.IsFuncMapMark() {
		return "ROUTINE"
	} else if w.IsChunk() {
		return "CHUNK"


@@ 138,20 203,20 @@ func (w Word) Debug() any {
	}
}

func (w Word) isSwpT(t uint64) bool {
	return uint64(w)&(TAG_OBJ_MAP|TAG_SWPMASK) == t
}
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) isSwpT(t uint64) bool {
// 	return uint64(w)&(TAG_OBJ_MAP|TAG_SWPMASK) == t
// }
// 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) AsBool() bool {
	switch uint64(w) {
	case TAG_LIT_TRU:
	case VAL_TRUE:
		return true
	case TAG_LIT_FLS, TAG_LIT_ETY, TAG_LIT_NAN:
	case VAL_FALS, VAL_EMPT, ERR_NUMB:
		return false
	default:
		return w.IsAddr()
		return w.IsAddress()
	}

}


@@ 164,7 229,7 @@ func (w Word) AsFloat() float64 {
	float := math.Float64frombits(bits)
	return float
}
func (w Word) AsInt() uint32  { return uint32(uint64(w) & ^TAG_LIT_INT) }
func (w Word) AsRune() rune   { return rune(uint64(w) & ^TAG_LIT_RNE) }
func (w Word) AsSym() uint64  { return uint64(w) & ^TAG_LIT_SYM }
func (w Word) AsAddr() uint64 { return uint64(w) & ^TAG_ADDRESS }
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 }

M internal/vm/word_array.go => internal/vm/word_array.go +2 -2
@@ 11,8 11,8 @@ type WordArray struct {

func NewWordArray(words ...Word) WordArray {
	return WordArray{
		Word(TAG_OBJ_ARR),
		Word(TAG_ADDRESS),
		Word(MAIN_ARR),
		Word(VAL_ADDR),
		WordFromInt(uint32(len(words))),
		words,
	}