M .vscode/launch.json => .vscode/launch.json +1 -1
@@ 25,7 25,7 @@
"foo ** bar // 6"
],
"env": {
- "RHUMB_VISITOR_DEBUG": "1",
+ "RHUMB_VISITOR_DEBUG": "0",
"RHUMB_CODE_ARRAY_DEBUG": "1",
"RHUMB_VM_DEBUG": "1"
}
M internal/generator/visitor.go => internal/generator/visitor.go +159 -117
@@ 9,8 9,9 @@ import (
"reflect"
"strconv"
- "git.sr.ht/~madcapjake/grhumb/internal/parser"
+ P "git.sr.ht/~madcapjake/grhumb/internal/parser"
"git.sr.ht/~madcapjake/grhumb/internal/vm"
+ "git.sr.ht/~madcapjake/grhumb/internal/word"
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
)
@@ 43,7 44,7 @@ type RhumbReturn struct {
}
type RhumbVisitor struct {
- parser.BaseRhumbParserVisitor
+ P.BaseRhumbParserVisitor
vm vm.VirtualMachine
}
@@ 79,45 80,58 @@ func (v *RhumbVisitor) VisitChildren(node antlr.RuleNode) interface{} {
return nil
}
-func (v *RhumbVisitor) VisitSequence(ctx *parser.SequenceContext) interface{} {
+func (v *RhumbVisitor) VisitSequence(ctx *P.SequenceContext) interface{} {
logger.Println("sequence!")
// logger.Println(ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitSimple(ctx *parser.SimpleContext) interface{} {
+func (v *RhumbVisitor) VisitSimple(ctx *P.SimpleContext) interface{} {
logger.Println("simple:", ctx.GetText())
return v.Visit(ctx.GetChild(0).(antlr.ParseTree))
}
-func (v *RhumbVisitor) VisitMutableLabel(ctx *parser.MutableLabelContext) interface{} {
+func (v *RhumbVisitor) VisitMutableLabel(ctx *P.MutableLabelContext) interface{} {
logger.Println("mutable label:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitLabelLiteral(ctx *parser.LabelLiteralContext) interface{} {
- text := ctx.GetText()
+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)...,
+ )
+ )
logger.Println("label:", text)
v.vm.WriteCodeToMain(
ctx.GetStart().GetLine(),
- vm.NewInstrRef(vm.RefLabel, text, nil),
+ word.FromAddress(int(ra.Id())),
vm.NewLocalRequest,
)
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitAssignment(ctx *parser.AssignmentContext) interface{} {
+func (v *RhumbVisitor) VisitAssignment(ctx *P.AssignmentContext) interface{} {
logger.Println("assignment!")
// TODO: implement map assignment
- var text string
+ var (
+ text string
+ ra vm.RuneArray
+ )
if addr := ctx.GetAddress(); addr != nil {
text = addr.GetText()
logger.Println("Address:", text)
// 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)...)
+
v.vm.WriteCodeToMain(
addr.GetLine(),
- vm.NewInstrRef(vm.RefLabel, text, nil),
+ word.FromAddress(int(ra.Id())),
vm.NewLocalRequest,
)
} else {
@@ 126,9 140,10 @@ func (v *RhumbVisitor) VisitAssignment(ctx *parser.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)...)
v.vm.WriteCodeToMain(
addrRef.GetStart().GetLine(),
- vm.NewInstrRef(vm.RefLabel, text, nil),
+ word.FromAddress(int(ra.Id())),
vm.NewLocalRequest,
)
}
@@ 136,22 151,27 @@ func (v *RhumbVisitor) VisitAssignment(ctx *parser.AssignmentContext) interface{
logger.Println("ctx.Expression().Accept...")
logger.Println("ctx.Expression().Accept:", ctx.Expression().Accept(v))
logger.Println("INNER:")
- assignOp := ctx.AssignmentOp()
+ op := ctx.AssignmentOp()
+ ra = vm.NewRuneArray(
+ &v.vm,
+ word.FromAddress(0),
+ vm.RuneWords(op.GetText())...,
+ )
v.vm.WriteCodeToMain(
- assignOp.GetStart().GetLine(),
- vm.NewInstrRef(vm.RefLabel, assignOp.GetText(), nil),
+ op.GetStart().GetLine(),
+ word.FromAddress(int(ra.Id())),
vm.NewOuterRequest,
)
return nil
}
-func (v *RhumbVisitor) VisitFloatLiteral(ctx *parser.FloatLiteralContext) interface{} {
+func (v *RhumbVisitor) VisitFloatLiteral(ctx *P.FloatLiteralContext) interface{} {
// logger.Println("float-lit!")
logger.Println(ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitIntegerLiteral(ctx *parser.IntegerLiteralContext) interface{} {
+func (v *RhumbVisitor) VisitIntegerLiteral(ctx *P.IntegerLiteralContext) interface{} {
text := ctx.GetText()
val, err := strconv.ParseInt(text, 10, 32)
if err != nil {
@@ 160,462 180,484 @@ func (v *RhumbVisitor) VisitIntegerLiteral(ctx *parser.IntegerLiteralContext) in
logger.Println("VALUE:", val)
v.vm.WriteCodeToMain(
ctx.GetStart().GetLine(),
- vm.NewInstrRef(vm.RefInt, text, val),
+ word.FromInt(uint32(val)),
vm.NewValueLiteral,
)
return RhumbReturn{val, nil}
}
-func (v *RhumbVisitor) VisitStringLiteral(ctx *parser.StringLiteralContext) interface{} {
+func (v *RhumbVisitor) VisitStringLiteral(ctx *P.StringLiteralContext) interface{} {
logger.Println("string-lit:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitReferenceLiteral(ctx *parser.ReferenceLiteralContext) interface{} {
+func (v *RhumbVisitor) VisitReferenceLiteral(ctx *P.ReferenceLiteralContext) interface{} {
logger.Println("ref-lit:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitConjunctive(ctx *parser.ConjunctiveContext) interface{} {
+func (v *RhumbVisitor) VisitConjunctive(ctx *P.ConjunctiveContext) interface{} {
logger.Println("conj:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitAccess(ctx *parser.AccessContext) interface{} {
+func (v *RhumbVisitor) VisitAccess(ctx *P.AccessContext) interface{} {
logger.Println("access:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitApplicative(ctx *parser.ApplicativeContext) interface{} {
+func (v *RhumbVisitor) VisitApplicative(ctx *P.ApplicativeContext) interface{} {
logger.Println("applicative:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitConditional(ctx *parser.ConditionalContext) interface{} {
+func (v *RhumbVisitor) VisitConditional(ctx *P.ConditionalContext) interface{} {
logger.Println("cond:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitPrefix(ctx *parser.PrefixContext) interface{} {
+func (v *RhumbVisitor) VisitPrefix(ctx *P.PrefixContext) interface{} {
logger.Println("prefix:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitComparative(ctx *parser.ComparativeContext) interface{} {
+func (v *RhumbVisitor) VisitComparative(ctx *P.ComparativeContext) interface{} {
logger.Println("compare:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitMultiplicative(ctx *parser.MultiplicativeContext) interface{} {
+func (v *RhumbVisitor) VisitMultiplicative(ctx *P.MultiplicativeContext) interface{} {
logger.Println("multiply:", ctx.GetText())
- exprs := ctx.AllExpression()
+ var (
+ exprs []P.IExpressionContext = ctx.AllExpression()
+ mulOp P.IMultiplicativeOpContext = ctx.MultiplicativeOp()
+ ra vm.RuneArray = vm.NewRuneArray(
+ &v.vm,
+ word.FromAddress(0),
+ vm.RuneWords(mulOp.GetText())...,
+ )
+ )
+
for i := range exprs {
exprs[i].Accept(v)
}
- mulOp := ctx.MultiplicativeOp()
+
v.vm.WriteCodeToMain(
mulOp.GetStart().GetLine(),
- vm.NewInstrRef(vm.RefLabel, mulOp.GetText(), nil),
- // FIXME: re-implement as NewInnerRequest
- vm.NewOuterRequest,
+ word.FromAddress(int(ra.Id())),
+ vm.NewOuterRequest, // FIXME: re-implement as NewInnerRequest
)
return nil
}
-func (v *RhumbVisitor) VisitAdditive(ctx *parser.AdditiveContext) interface{} {
+func (v *RhumbVisitor) VisitAdditive(ctx *P.AdditiveContext) interface{} {
logger.Println("additive:", ctx.GetText())
- exprs := ctx.AllExpression()
+ var (
+ exprs []P.IExpressionContext = ctx.AllExpression()
+ addOp P.IAdditiveOpContext = ctx.AdditiveOp()
+ ra vm.RuneArray = vm.NewRuneArray(
+ &v.vm,
+ word.FromAddress(0),
+ vm.RuneWords(addOp.GetText())...,
+ )
+ )
+
for i := range exprs {
exprs[i].Accept(v)
}
- addOp := ctx.AdditiveOp()
+
v.vm.WriteCodeToMain(
addOp.GetStart().GetLine(),
- vm.NewInstrRef(vm.RefLabel, addOp.GetText(), nil),
- // FIXME: re-implement as NewInnerRequest
- vm.NewOuterRequest,
+ word.FromAddress(int(ra.Id())),
+ vm.NewOuterRequest, // FIXME: re-implement as NewInnerRequest
)
return nil
}
-func (v *RhumbVisitor) VisitInvocation(ctx *parser.InvocationContext) interface{} {
+func (v *RhumbVisitor) VisitInvocation(ctx *P.InvocationContext) interface{} {
logger.Println("invoke:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitRoutine(ctx *parser.RoutineContext) interface{} {
+func (v *RhumbVisitor) VisitRoutine(ctx *P.RoutineContext) interface{} {
logger.Println("routine:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitDisjunctive(ctx *parser.DisjunctiveContext) interface{} {
+func (v *RhumbVisitor) VisitDisjunctive(ctx *P.DisjunctiveContext) interface{} {
logger.Println("disjunct:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitIdentity(ctx *parser.IdentityContext) interface{} {
+func (v *RhumbVisitor) VisitIdentity(ctx *P.IdentityContext) interface{} {
logger.Println("identify:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitEffect(ctx *parser.EffectContext) interface{} {
+func (v *RhumbVisitor) VisitEffect(ctx *P.EffectContext) interface{} {
logger.Println("effect:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitMember(ctx *parser.MemberContext) interface{} {
+func (v *RhumbVisitor) VisitMember(ctx *P.MemberContext) interface{} {
logger.Println("member:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitSelector(ctx *parser.SelectorContext) interface{} {
+func (v *RhumbVisitor) VisitSelector(ctx *P.SelectorContext) interface{} {
logger.Println("selector:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitPower(ctx *parser.PowerContext) interface{} {
+func (v *RhumbVisitor) VisitPower(ctx *P.PowerContext) interface{} {
logger.Println("power:", ctx.GetText())
- exprs := ctx.AllExpression()
+ var (
+ exprs []P.IExpressionContext = ctx.AllExpression()
+ powOp P.IExponentiationOpContext = ctx.ExponentiationOp()
+ ra vm.RuneArray = vm.NewRuneArray(
+ &v.vm,
+ word.FromAddress(0),
+ vm.RuneWords(powOp.GetText())...,
+ )
+ )
for i := range exprs {
exprs[i].Accept(v)
}
- powOp := ctx.ExponentiationOp()
v.vm.WriteCodeToMain(
powOp.GetStart().GetLine(),
- vm.NewInstrRef(vm.RefLabel, powOp.GetText(), nil),
- // FIXME: re-implement as NewInnerRequest
- vm.NewOuterRequest,
+ word.FromAddress(int(ra.Id())),
+ vm.NewOuterRequest, // FIXME: re-implement as NewInnerRequest
)
return nil
}
-func (v *RhumbVisitor) VisitMap(ctx *parser.MapContext) interface{} {
+func (v *RhumbVisitor) VisitMap(ctx *P.MapContext) interface{} {
logger.Println("map:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitFreeze(ctx *parser.FreezeContext) interface{} {
+func (v *RhumbVisitor) VisitFreeze(ctx *P.FreezeContext) interface{} {
logger.Println("freeze:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitInner(ctx *parser.InnerContext) interface{} {
+func (v *RhumbVisitor) VisitInner(ctx *P.InnerContext) interface{} {
logger.Println("inner:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitLength(ctx *parser.LengthContext) interface{} {
+func (v *RhumbVisitor) VisitLength(ctx *P.LengthContext) interface{} {
logger.Println("length:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitFunction(ctx *parser.FunctionContext) interface{} {
+func (v *RhumbVisitor) VisitFunction(ctx *P.FunctionContext) interface{} {
logger.Println("function:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitJunction(ctx *parser.JunctionContext) interface{} {
+func (v *RhumbVisitor) VisitJunction(ctx *P.JunctionContext) interface{} {
logger.Println("junction:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitGreaterThan(ctx *parser.GreaterThanContext) interface{} {
+func (v *RhumbVisitor) VisitGreaterThan(ctx *P.GreaterThanContext) interface{} {
logger.Println("greater-than:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitGreaterThanOrEqualTo(ctx *parser.GreaterThanOrEqualToContext) interface{} {
+func (v *RhumbVisitor) VisitGreaterThanOrEqualTo(ctx *P.GreaterThanOrEqualToContext) interface{} {
logger.Println("greater-than-or-equal-to:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitLessThan(ctx *parser.LessThanContext) interface{} {
+func (v *RhumbVisitor) VisitLessThan(ctx *P.LessThanContext) interface{} {
logger.Println("less-than:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitLessThanOrEqualTo(ctx *parser.LessThanOrEqualToContext) interface{} {
+func (v *RhumbVisitor) VisitLessThanOrEqualTo(ctx *P.LessThanOrEqualToContext) interface{} {
logger.Println("less-than-or-equal-to:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitIsEqual(ctx *parser.IsEqualContext) interface{} {
+func (v *RhumbVisitor) VisitIsEqual(ctx *P.IsEqualContext) interface{} {
logger.Println("is-equal:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitIsLike(ctx *parser.IsLikeContext) interface{} {
+func (v *RhumbVisitor) VisitIsLike(ctx *P.IsLikeContext) interface{} {
logger.Println("is-like:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitIsIn(ctx *parser.IsInContext) interface{} {
+func (v *RhumbVisitor) VisitIsIn(ctx *P.IsInContext) interface{} {
logger.Println("is-in:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitIsOverlayed(ctx *parser.IsOverlayedContext) interface{} {
+func (v *RhumbVisitor) VisitIsOverlayed(ctx *P.IsOverlayedContext) interface{} {
logger.Println("is-overlayed:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitIsTopmost(ctx *parser.IsTopmostContext) interface{} {
+func (v *RhumbVisitor) VisitIsTopmost(ctx *P.IsTopmostContext) interface{} {
logger.Println("is-topmost:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNotEqual(ctx *parser.NotEqualContext) interface{} {
+func (v *RhumbVisitor) VisitNotEqual(ctx *P.NotEqualContext) interface{} {
logger.Println("not-equal:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNotLike(ctx *parser.NotLikeContext) interface{} {
+func (v *RhumbVisitor) VisitNotLike(ctx *P.NotLikeContext) interface{} {
logger.Println("not-like:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNotIn(ctx *parser.NotInContext) interface{} {
+func (v *RhumbVisitor) VisitNotIn(ctx *P.NotInContext) interface{} {
logger.Println("not-in:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNotOverlayed(ctx *parser.NotOverlayedContext) interface{} {
+func (v *RhumbVisitor) VisitNotOverlayed(ctx *P.NotOverlayedContext) interface{} {
logger.Println("not-overlayed:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNotTopmost(ctx *parser.NotTopmostContext) interface{} {
+func (v *RhumbVisitor) VisitNotTopmost(ctx *P.NotTopmostContext) interface{} {
logger.Println("not-topmost:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitConjunctiveOp(ctx *parser.ConjunctiveOpContext) interface{} {
+func (v *RhumbVisitor) VisitConjunctiveOp(ctx *P.ConjunctiveOpContext) interface{} {
logger.Println("conj-op:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitDisjunctiveOp(ctx *parser.DisjunctiveOpContext) interface{} {
+func (v *RhumbVisitor) VisitDisjunctiveOp(ctx *P.DisjunctiveOpContext) interface{} {
logger.Println("disjunct-op:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitOtherwise(ctx *parser.OtherwiseContext) interface{} {
+func (v *RhumbVisitor) VisitOtherwise(ctx *P.OtherwiseContext) interface{} {
logger.Println("otherwise:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitDefault(ctx *parser.DefaultContext) interface{} {
+func (v *RhumbVisitor) VisitDefault(ctx *P.DefaultContext) interface{} {
logger.Println("default:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitForeach(ctx *parser.ForeachContext) interface{} {
+func (v *RhumbVisitor) VisitForeach(ctx *P.ForeachContext) interface{} {
logger.Println("for-each:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitWhile(ctx *parser.WhileContext) interface{} {
+func (v *RhumbVisitor) VisitWhile(ctx *P.WhileContext) interface{} {
logger.Println("while:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitThen(ctx *parser.ThenContext) interface{} {
+func (v *RhumbVisitor) VisitThen(ctx *P.ThenContext) interface{} {
logger.Println("then:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitElse(ctx *parser.ElseContext) interface{} {
+func (v *RhumbVisitor) VisitElse(ctx *P.ElseContext) interface{} {
logger.Println("else:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitAddition(ctx *parser.AdditionContext) interface{} {
+func (v *RhumbVisitor) VisitAddition(ctx *P.AdditionContext) interface{} {
logger.Println("addition:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitDeviation(ctx *parser.DeviationContext) interface{} {
+func (v *RhumbVisitor) VisitDeviation(ctx *P.DeviationContext) interface{} {
logger.Println("deviation:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitSubtraction(ctx *parser.SubtractionContext) interface{} {
+func (v *RhumbVisitor) VisitSubtraction(ctx *P.SubtractionContext) interface{} {
logger.Println("subtraction:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitMultiplication(ctx *parser.MultiplicationContext) interface{} {
+func (v *RhumbVisitor) VisitMultiplication(ctx *P.MultiplicationContext) interface{} {
logger.Println("mupltication:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitDivision(ctx *parser.DivisionContext) interface{} {
+func (v *RhumbVisitor) VisitDivision(ctx *P.DivisionContext) interface{} {
logger.Println("division:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitIntegerDivision(ctx *parser.IntegerDivisionContext) interface{} {
+func (v *RhumbVisitor) VisitIntegerDivision(ctx *P.IntegerDivisionContext) interface{} {
logger.Println("int-division:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitModulo(ctx *parser.ModuloContext) interface{} {
+func (v *RhumbVisitor) VisitModulo(ctx *P.ModuloContext) interface{} {
logger.Println("modulo:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitBind(ctx *parser.BindContext) interface{} {
+func (v *RhumbVisitor) VisitBind(ctx *P.BindContext) interface{} {
logger.Println("bind:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitExponent(ctx *parser.ExponentContext) interface{} {
+func (v *RhumbVisitor) VisitExponent(ctx *P.ExponentContext) interface{} {
logger.Println("exponenet:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitRootExtraction(ctx *parser.RootExtractionContext) interface{} {
+func (v *RhumbVisitor) VisitRootExtraction(ctx *P.RootExtractionContext) interface{} {
logger.Println("root-extract:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitScientific(ctx *parser.ScientificContext) interface{} {
+func (v *RhumbVisitor) VisitScientific(ctx *P.ScientificContext) interface{} {
logger.Println("scientific:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitImmutablePair(ctx *parser.ImmutablePairContext) interface{} {
+func (v *RhumbVisitor) VisitImmutablePair(ctx *P.ImmutablePairContext) interface{} {
logger.Println("immutable-pair:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitImmutableLabel(ctx *parser.ImmutableLabelContext) interface{} {
+func (v *RhumbVisitor) VisitImmutableLabel(ctx *P.ImmutableLabelContext) interface{} {
logger.Println("immutable-label:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitMutablePair(ctx *parser.MutablePairContext) interface{} {
+func (v *RhumbVisitor) VisitMutablePair(ctx *P.MutablePairContext) interface{} {
logger.Println("mutable-pair:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNumericalNegate(ctx *parser.NumericalNegateContext) interface{} {
+func (v *RhumbVisitor) VisitNumericalNegate(ctx *P.NumericalNegateContext) interface{} {
logger.Println("numerical-negate:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitOuterScope(ctx *parser.OuterScopeContext) interface{} {
+func (v *RhumbVisitor) VisitOuterScope(ctx *P.OuterScopeContext) interface{} {
logger.Println("outer-scope:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitLogicalNegate(ctx *parser.LogicalNegateContext) interface{} {
+func (v *RhumbVisitor) VisitLogicalNegate(ctx *P.LogicalNegateContext) interface{} {
logger.Println("logical-negate:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitAssert(ctx *parser.AssertContext) interface{} {
+func (v *RhumbVisitor) VisitAssert(ctx *P.AssertContext) interface{} {
logger.Println("assert:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitArgument(ctx *parser.ArgumentContext) interface{} {
+func (v *RhumbVisitor) VisitArgument(ctx *P.ArgumentContext) interface{} {
logger.Println("argument:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitSlurpSpread(ctx *parser.SlurpSpreadContext) interface{} {
+func (v *RhumbVisitor) VisitSlurpSpread(ctx *P.SlurpSpreadContext) interface{} {
logger.Println("slurp-spread:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitBaseClone(ctx *parser.BaseCloneContext) interface{} {
+func (v *RhumbVisitor) VisitBaseClone(ctx *P.BaseCloneContext) interface{} {
logger.Println("base-clone:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNumericalPosit(ctx *parser.NumericalPositContext) interface{} {
+func (v *RhumbVisitor) VisitNumericalPosit(ctx *P.NumericalPositContext) interface{} {
logger.Println("numerical-posit:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitLogicalPosit(ctx *parser.LogicalPositContext) interface{} {
+func (v *RhumbVisitor) VisitLogicalPosit(ctx *P.LogicalPositContext) interface{} {
logger.Println("logical-posit:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitOverlay(ctx *parser.OverlayContext) interface{} {
+func (v *RhumbVisitor) VisitOverlay(ctx *P.OverlayContext) interface{} {
logger.Println("overlay:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitExistentialPosit(ctx *parser.ExistentialPositContext) interface{} {
+func (v *RhumbVisitor) VisitExistentialPosit(ctx *P.ExistentialPositContext) interface{} {
logger.Println("existential-posit:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitImmutableDestruct(ctx *parser.ImmutableDestructContext) interface{} {
+func (v *RhumbVisitor) VisitImmutableDestruct(ctx *P.ImmutableDestructContext) interface{} {
logger.Println("immutable-destruct:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitMutableDestruct(ctx *parser.MutableDestructContext) interface{} {
+func (v *RhumbVisitor) VisitMutableDestruct(ctx *P.MutableDestructContext) interface{} {
logger.Println("mutable-destruct:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNestedLabel(ctx *parser.NestedLabelContext) interface{} {
+func (v *RhumbVisitor) VisitNestedLabel(ctx *P.NestedLabelContext) interface{} {
logger.Println("nested-label:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNestedOverlay(ctx *parser.NestedOverlayContext) interface{} {
+func (v *RhumbVisitor) VisitNestedOverlay(ctx *P.NestedOverlayContext) interface{} {
logger.Println("nested-overlay:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitRange(ctx *parser.RangeContext) interface{} {
+func (v *RhumbVisitor) VisitRange(ctx *P.RangeContext) interface{} {
logger.Println("range:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitString(ctx *parser.StringContext) interface{} {
+func (v *RhumbVisitor) VisitString(ctx *P.StringContext) interface{} {
logger.Println("string:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitLabelInterp(ctx *parser.LabelInterpContext) interface{} {
+func (v *RhumbVisitor) VisitLabelInterp(ctx *P.LabelInterpContext) interface{} {
logger.Println("label-interp!")
logger.Println(ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitRoutineInterp(ctx *parser.RoutineInterpContext) interface{} {
+func (v *RhumbVisitor) VisitRoutineInterp(ctx *P.RoutineInterpContext) interface{} {
logger.Println("routine-interp:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitSelectorInterp(ctx *parser.SelectorInterpContext) interface{} {
+func (v *RhumbVisitor) VisitSelectorInterp(ctx *P.SelectorInterpContext) interface{} {
logger.Println("selector-interp:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitNamedRef(ctx *parser.NamedRefContext) interface{} {
+func (v *RhumbVisitor) VisitNamedRef(ctx *P.NamedRefContext) interface{} {
logger.Println("named-ref:", ctx.GetText())
return ctx.Label().GetText()
}
-func (v *RhumbVisitor) VisitFunctionRef(ctx *parser.FunctionRefContext) interface{} {
+func (v *RhumbVisitor) VisitFunctionRef(ctx *P.FunctionRefContext) interface{} {
logger.Println("function-ref:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitComputedRef(ctx *parser.ComputedRefContext) interface{} {
+func (v *RhumbVisitor) VisitComputedRef(ctx *P.ComputedRefContext) interface{} {
logger.Println("computed-ref:", ctx.GetText())
return v.VisitChildren(ctx)
}
-func (v *RhumbVisitor) VisitJunctionRef(ctx *parser.JunctionRefContext) interface{} {
+func (v *RhumbVisitor) VisitJunctionRef(ctx *P.JunctionRefContext) interface{} {
logger.Println("junction-ref:", ctx.GetText())
return v.VisitChildren(ctx)
}
M internal/vm/chunk.go => internal/vm/chunk.go +92 -81
@@ 2,99 2,107 @@ package vm
import (
"fmt"
-)
-type RefType uint8
+ "git.sr.ht/~madcapjake/grhumb/internal/word"
+)
const (
- RefInt RefType = iota
- RefFloat
- RefRune
- RefBool
- RefAddr
- RefLabel
+ chunk_ca_offset uint64 = 1
+ chunk_wa_offset uint64 = 2
)
-type InstrRef struct {
- kind RefType
- text string
- value interface{}
-}
-
-func NewInstrRef(kind RefType, text string, value interface{}) InstrRef {
- return InstrRef{kind, text, value}
-}
-
-func (ir InstrRef) equals(other InstrRef) bool {
- return ir.text == other.text
-}
-
type Chunk struct {
- instructions CodeArray
-
- // FIXME: Find a less memory intensive line tracking system
- lines []int
+ // address in vm's heap
+ id uint64
- // FIXME: Convert to array of refs & literals for true compilation
- prestack []InstrRef
+ // temp line tracking
+ line int
}
-func NewChunk(codes, refs []Word) Chunk {
- return Chunk{
- instructions: NewCodeArray(codes...),
- prestack: make([]InstrRef, len(codes)/2),
- lines: make([]int, len(codes)),
+func NewChunk(vm *VirtualMachine) Chunk {
+ var (
+ ch [3]word.Word = [3]word.Word{}
+ ca CodeArray = NewCodeArray(vm, word.FromAddress(0))
+ wa WordArray = NewWordArray(vm, word.FromAddress(0))
+ )
+ ch[0] = word.Word(word.CMP_UNIT)
+ ch[1] = word.FromAddress(int(ca.id))
+ ch[2] = word.FromAddress(int(wa.id))
+ id, err := vm.ReAllocate(ch[:]...)
+ if err != nil {
+ panic("failed to reallocate onto heap")
}
+ return Chunk{id, 0}
}
-func (ch *Chunk) WriteCode(line int, codes []Code) {
- for c := range codes {
- ch.instructions.SetCodes(codes[c])
- ch.lines = append(ch.lines, line)
+func ReviveChunk(vm *VirtualMachine, addr word.Word) Chunk {
+ i := addr.AsAddr()
+ mark := vm.heap[i]
+ if !(mark.IsCodeArrayMark()) {
+ panic("not a chunk mark")
}
+ return Chunk{i, 0}
}
-func (ch *Chunk) AddReference(ref InstrRef) uint32 {
- for r := range ch.prestack {
- if ch.prestack[r].equals(ref) {
- return uint32(r)
- }
+func (ch *Chunk) WriteCode(vm *VirtualMachine, line int, codes []Code) {
+
+ instructions := ch.Instructions(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))
}
- newId := len(ch.prestack)
- ch.prestack = append(ch.prestack, ref)
- return uint32(newId)
}
-func (ch Chunk) CodeWords() []Word {
- return ch.instructions.CodeWords
+func (ch *Chunk) AddLiteral(vm *VirtualMachine, lit word.Word) (uint64, error) {
+ literals := ch.Literals(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))
+ }
+ return id, err
+ } else {
+ return uint64(existingIndex), nil
+ }
}
-func (ch Chunk) CodeWordsCount() int {
- return len(ch.instructions.CodeWords)
+func (ch Chunk) Instructions(vm *VirtualMachine) CodeArray {
+ return ReviveCodeArray(vm, vm.heap[ch.id+chunk_ca_offset])
}
-func (ch Chunk) CodesFromWord(wordIndex int, buf *[]byte) {
- ch.instructions.getCodesFromWord(wordIndex, buf)
+func (ch Chunk) Literals(vm *VirtualMachine) WordArray {
+ return ReviveWordArray(vm, vm.heap[ch.id+chunk_wa_offset])
}
func (ch Chunk) Execute(vm *VirtualMachine) {
var (
- cwLen int = len(ch.instructions.CodeWords)
- idx int = 0
- buf []byte = make([]byte, 0, cwLen*8)
+ instructions = ch.Instructions(vm)
+ cwLen int = int(instructions.Length(vm))
+ idx uint64 = 0
+ buf []byte = make([]byte, 0, cwLen*8)
)
for wordIndex := 0; wordIndex < cwLen; wordIndex++ {
- ch.instructions.getCodesFromWord(wordIndex, &buf)
+ instructions.getCodesFromWord(vm, uint64(wordIndex), &buf)
for b := range buf {
if buf[b] == 0 {
break
}
code := Code(buf[b])
- idx += int(code.Index())
+ idx += uint64(code.Index())
if code.IsIndexExtension() {
continue
} else {
- ch.execTagIndex(vm, code.Tag(), idx)
+ ch.execTagIndex(vm, code.Tag(), int(idx))
idx = 0
}
}
@@ 103,45 111,48 @@ func (ch Chunk) Execute(vm *VirtualMachine) {
}
func (ch Chunk) execTagIndex(vm *VirtualMachine, b byte, idx int) {
- code := Code(b)
- tag := code.Tag()
+ var (
+ code Code = Code(b)
+ tag uint8 = code.Tag()
+ literals = ch.Literals(vm)
+ )
switch tag {
case TAG_VALUE_LITERAL:
- vm.AddValueToStack(ch.prestack[idx])
+ vm.AddLiteralToStack(literals.Get(vm, idx))
case TAG_LOCAL_REQUEST:
- vm.SubmitLocalRequest(ch.prestack[idx])
+ vm.SubmitLocalRequest(literals.Get(vm, idx))
case TAG_INNER_REQUEST:
- vm.SubmitInnerRequest(ch.prestack[idx])
+ vm.SubmitInnerRequest(literals.Get(vm, idx))
case TAG_UNDER_REQUEST:
- vm.SubmitUnderRequest(ch.prestack[idx])
+ vm.SubmitUnderRequest(literals.Get(vm, idx))
case TAG_OUTER_REQUEST:
- vm.SubmitOuterRequest(ch.prestack[idx])
- case TAG_EVENT_REQUEST:
- vm.SubmitEventRequest(ch.prestack[idx])
- case TAG_REPLY_REQUEST:
- vm.SubmitReplyRequest(ch.prestack[idx])
+ vm.SubmitOuterRequest(literals.Get(vm, idx))
+ // case TAG_EVENT_REQUEST:
+ // vm.SubmitEventRequest(literals.Get(idx))
+ // case TAG_REPLY_REQUEST:
+ // vm.SubmitReplyRequest(literals.Get(idx))
}
}
-func (ch Chunk) Disassemble() {
+func (ch Chunk) Disassemble(vm *VirtualMachine) {
fmt.Println("============= Chunk =============")
var line int
- buf := ch.instructions.GetCodes()
- for offset := 0; offset < ch.instructions.Len(); {
- line, offset = ch.DisassembleCode(line, offset, &buf)
+ instructions := ch.Instructions(vm)
+ buf := instructions.GetCodes(vm)
+ for offset := 0; offset < int(instructions.Length(vm)); {
+ if line < instructions.GetLine(vm, offset) {
+ line += 1
+ fmt.Printf("%4d ", line)
+ } else {
+ fmt.Printf(" | ")
+ }
+ line, offset = ch.DisassembleCode(vm, line, offset, &buf)
}
}
-func (ch Chunk) DisassembleCode(currentLine, currentOffset int, bufPtr *[]byte) (int, int) {
+func (ch Chunk) DisassembleCode(vm *VirtualMachine, currentLine, currentOffset int, bufPtr *[]byte) (int, int) {
buf := *bufPtr
fmt.Printf("%04d ", currentOffset)
- if currentOffset > 0 &&
- ch.lines[currentOffset] == ch.lines[currentOffset-1] {
- fmt.Printf(" | ")
- } else {
- fmt.Printf("%4d ", ch.lines[currentOffset])
- }
-
var recurse func(l, o, i int) (int, int)
recurse = func(l, o, i int) (int, int) {
tag := Code(buf[o]).Tag()
@@ 158,7 169,7 @@ func (ch Chunk) DisassembleCode(currentLine, currentOffset int, bufPtr *[]byte)
fmt.Printf("%s %d '%v'\n",
Code(buf[o]).String(),
idx,
- ch.prestack[idx].text,
+ ch.Literals(vm).Get(vm, int(idx)).Debug(),
)
return l, o + 1
}
M internal/vm/code.go => internal/vm/code.go +9 -9
@@ 11,7 11,7 @@ const TAG_UNDER_REQUEST uint8 = 0b10000000
const TAG_OUTER_REQUEST uint8 = 0b10100000
const TAG_EVENT_REQUEST uint8 = 0b11000000
const TAG_REPLY_REQUEST uint8 = 0b11100000
-const MAX_IDX_SIZE uint32 = 31
+const MAX_IDX_SIZE uint64 = 31
func (c Code) String() (result string) {
switch c.Tag() {
@@ 35,7 35,7 @@ func (c Code) String() (result string) {
return
}
-func generateCodes(tag uint8, idx uint32) []Code {
+func generateCodes(tag uint8, idx uint64) []Code {
codeWithExtensions := make([]Code, (idx/MAX_IDX_SIZE)+1)
remaining := idx
for i := range codeWithExtensions {
@@ 67,7 67,7 @@ func (c Code) IsIndexExtension() bool {
return c.Tag() == TAG_IDX_EXTENSION
}
-func NewValueLiteral(idx uint32) []Code {
+func NewValueLiteral(idx uint64) []Code {
return generateCodes(TAG_VALUE_LITERAL, idx)
}
@@ 75,7 75,7 @@ func (c Code) IsValueLiteral() bool {
return c.Tag() == TAG_VALUE_LITERAL
}
-func NewLocalRequest(idx uint32) []Code {
+func NewLocalRequest(idx uint64) []Code {
return generateCodes(TAG_LOCAL_REQUEST, idx)
}
@@ 83,7 83,7 @@ func (c Code) IsLocalRequest() bool {
return c.Tag() == TAG_LOCAL_REQUEST
}
-func NewInnerRequest(idx uint32) []Code {
+func NewInnerRequest(idx uint64) []Code {
return generateCodes(TAG_INNER_REQUEST, idx)
}
@@ 91,7 91,7 @@ func (c Code) IsInnerRequest() bool {
return c.Tag() == TAG_INNER_REQUEST
}
-func NewUnderRequest(idx uint32) []Code {
+func NewUnderRequest(idx uint64) []Code {
return generateCodes(TAG_UNDER_REQUEST, idx)
}
@@ 99,7 99,7 @@ func (c Code) IsUnderRequest() bool {
return c.Tag() == TAG_UNDER_REQUEST
}
-func NewOuterRequest(idx uint32) []Code {
+func NewOuterRequest(idx uint64) []Code {
return generateCodes(TAG_OUTER_REQUEST, idx)
}
@@ 107,7 107,7 @@ func (c Code) IsOuterRequest() bool {
return c.Tag() == TAG_OUTER_REQUEST
}
-func NewEventRequest(idx uint32) []Code {
+func NewEventRequest(idx uint64) []Code {
return generateCodes(TAG_EVENT_REQUEST, idx)
}
@@ 115,7 115,7 @@ func (c Code) IsEventRequest() bool {
return c.Tag() == TAG_EVENT_REQUEST
}
-func NewReplyRequest(idx uint32) []Code {
+func NewReplyRequest(idx uint64) []Code {
return generateCodes(TAG_REPLY_REQUEST, idx)
}
M internal/vm/code_array.go => internal/vm/code_array.go +218 -61
@@ 5,6 5,8 @@ import (
"io"
"log"
"os"
+
+ "git.sr.ht/~madcapjake/grhumb/internal/word"
)
var caLogger = log.New(io.Discard, "", log.LstdFlags)
@@ 15,79 17,183 @@ func init() {
}
}
+// type CodeArray struct {
+// Mark word.Word
+// Legend word.Word // Address
+// Size word.Word
+// Length word.Word
+// CodeWords []word.Word // Words are packed 8-elem Codes
+// }
+
+const (
+ code_lgd_offset uint64 = 1
+ code_sze_offset uint64 = 2
+ code_len_offset uint64 = 3
+ code_arr_offset uint64 = 4
+)
+
type CodeArray struct {
- Mark Word
- Legend Word // Address
- Length Word
- CodeWords []Word // Words are packed 8-elem Codes
-}
-
-func NewCodeArray(words ...Word) CodeArray {
- return CodeArray{
- Mark: Word(CODE_ARR),
- Legend: Word(VAL_ADDR),
- Length: WordFromInt(uint32(len(words))),
- CodeWords: words,
- }
-}
-
-func (ca *CodeArray) SetCodes(cs ...Code) {
- origLen := ca.Length.AsInt()
- newLen := uint32(len(cs))
- byteSize := uint32(8)
- bs := make([]byte, 0, byteSize)
- currWordVacancy := ca.currentVacancy()
- if currWordVacancy {
- ca.getCodesFromWord(ca.currentIndex(), &bs)
- }
- for c := uint32(0); c < newLen; c++ {
- bs = append(bs, byte(cs[c]))
- if (c+1)%byteSize == 0 {
- ca.CodeWords = append(
- ca.CodeWords,
- Word(binary.BigEndian.Uint64(bs)),
- )
+ // address in vm's heap
+ id uint64
+}
+
+func NewCodeArray(
+ vm *VirtualMachine,
+ legAddr word.Word,
+ words ...word.Word,
+) CodeArray {
+ wordsLen := uint32(len(words))
+ wordsSize := uint32(code_arr_offset) + wordsLen
+ caWords := make([]word.Word, 0, wordsSize)
+ caWords = append(caWords,
+ /* Mark: */ word.Word(word.CODE_ARR),
+ /* Legend: */ legAddr,
+ /* Size: */ word.FromInt(wordsSize),
+ /* Length: */ word.FromInt(wordsLen),
+ )
+ caWords = append(caWords, words...)
+
+ loc, err := vm.ReAllocate(caWords...)
+ if err != nil {
+ panic("allocation failed")
+ }
+ return CodeArray{uint64(loc)}
+}
+
+func ReviveCodeArray(vm *VirtualMachine, addr word.Word) CodeArray {
+ i := addr.AsAddr()
+ mark := vm.heap[i]
+ if !(mark.IsCodeArrayMark()) {
+ panic("not a code array mark")
+ }
+ 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]
+ if !(size.IsInteger()) {
+ panic("code array object size word is not an integer")
+ }
+ return CodeArray{i}
+}
+
+// Given a possible new line and some new codes, what
+// will the new total word size of this object?
+func (ca CodeArray) NewSize(vm *VirtualMachine, newLine bool, cs ...Code) (size uint64) {
+ var (
+ origSize uint64 = ca.Size(vm)
+ newLength int = len(cs)
+ freshLength int
+ wholeWords int
+ remainder int
+ )
+ if newLine {
+ size = origSize + 1
+ wholeWords = newLength / 8
+ remainder = newLength % 8
+ if remainder == 0 {
+ size += uint64(wholeWords)
+ } else {
+ size += uint64(wholeWords + 1)
+ }
+ } else {
+ size = origSize
+ remainder = ca.getWordCodeCount(vm, uint64(ca.Size(vm)-1))
+ freshLength = newLength - remainder
+ wholeWords = freshLength / 8
+ remainder = freshLength % 8
+ if remainder == 0 {
+ size += uint64(wholeWords)
+ } else {
+ size += uint64(wholeWords + 1)
+ }
+ }
+ return
+}
+
+func (ca *CodeArray) SetCodes(
+ vm *VirtualMachine,
+ newLine bool,
+ cs ...Code,
+) {
+ 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)
+ ws []word.Word = make([]word.Word, 0, newLen/8)
+ )
+ 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 {
+ vm.heap[ca.id+ca.Size(vm)] = word.Word(
+ binary.BigEndian.Uint64(bs))
+ bs = make([]byte, 0, byteSize)
+ break
+ }
+ }
+
+ }
+ }
+ for ; codeID < newLen; codeID++ {
+ bs = append(bs, byte(cs[codeID]))
+ if codeID+1 == byteSize {
+ ws = append(ws, word.Word(binary.BigEndian.Uint64(bs)))
bs = make([]byte, 0, byteSize)
}
}
+
if len(bs) > 0 {
caLogger.Println(bs)
for range bs[len(bs):byteSize] {
bs = append(bs, 0x0)
}
- newCodeWord := Word(binary.BigEndian.Uint64(bs))
- if currWordVacancy {
- ca.CodeWords[ca.currentIndex()] = newCodeWord
- } else {
- ca.CodeWords = append(ca.CodeWords, newCodeWord)
- }
+ ws = append(ws, word.Word(binary.BigEndian.Uint64(bs)))
}
- ca.Length = WordFromInt(origLen + newLen)
-}
-func (ca *CodeArray) vacancy() uint32 {
- caLen := ca.Length.AsInt()
- modByte := caLen % 8
- return modByte
+ finalLength := uint32(origLen) + uint32(len(ws))
+ ca.SetSize(vm, finalLength+4)
+ ca.SetLength(vm, finalLength)
+ newId, _ := vm.Allocate(
+ int(ca.id),
+ int(origLen)+int(code_arr_offset),
+ ws...,
+ )
+ if newId != ca.id {
+ // vm.UpdateAddresses(ca.id, newId)
+ ca.id = newId
+ }
}
-func (ca *CodeArray) currentVacancy() bool {
- return ca.vacancy() != 0
+func (ca *CodeArray) lastWordVacancy(vm *VirtualMachine) bool {
+ lastIndex := uint64(ca.Length(vm) - 1)
+ return ca.getWordCodeCount(vm, lastIndex) != 0
}
-func (ca *CodeArray) currentIndex() int {
- if ca.currentVacancy() {
- return len(ca.CodeWords) - 1
- } else {
- return len(ca.CodeWords)
- }
-}
+// 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(wi int, b *[]byte) {
+func (ca CodeArray) getCodesFromWord(vm *VirtualMachine, wi uint64, b *[]byte) {
var (
- buf []byte = *b
- word Word = ca.CodeWords[wi]
+ buf []byte = *b
+ word word.Word = vm.heap[ca.id+code_arr_offset+wi]
)
+ if word.IsSentinel() {
+ panic("cannot get codes from sentinel")
+ }
for offset := 56; offset >= 0; offset -= 8 {
i := uint64(word) >> offset
subByte := byte(i)
@@ 99,15 205,66 @@ func (ca *CodeArray) getCodesFromWord(wi int, b *[]byte) {
*b = buf
}
-func (ca *CodeArray) GetCodes() []byte {
- cwLen := len(ca.CodeWords)
+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]
+ )
+ if word.IsSentinel() {
+ panic("cannot get codes from sentinel")
+ }
+ for offset := 56; offset >= 0; offset -= 8 {
+ i := uint64(word) >> offset
+ subByte := byte(i)
+ if subByte == 0 {
+ break
+ }
+ count = count + 1
+ }
+ return count
+}
+
+func (ca CodeArray) GetCodes(vm *VirtualMachine) []byte {
+ cwLen := uint64(ca.Length(vm))
buf := make([]byte, 0, cwLen*8)
- for wordIndex := 0; wordIndex < cwLen; wordIndex++ {
- ca.getCodesFromWord(wordIndex, &buf)
+ for wIndex := code_arr_offset; wIndex < cwLen; wIndex++ {
+ if !(vm.heap[ca.id+wIndex].IsSentinel()) {
+ ca.getCodesFromWord(vm, wIndex, &buf)
+ }
}
return buf
}
-func (ca *CodeArray) Len() int {
- return int(ca.Length.AsInt())
+func (ca *CodeArray) GetLine(vm *VirtualMachine, codeIndex int) (lines int) {
+ codes, cwLen, cwSize := 0, ca.Length(vm), ca.Size(vm)
+ if uint32(codeIndex) > cwLen {
+ panic("index greater than length")
+ }
+ for i := uint64(0); i < cwSize && codes <= codeIndex; i++ {
+ if vm.heap[ca.id+code_arr_offset+i].IsSentinel() {
+ lines += 1
+ } else {
+ codes += ca.getWordCodeCount(vm, i)
+ }
+ }
+ return
+}
+
+func (ca CodeArray) Legend(vm *VirtualMachine) uint64 {
+ 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())
+}
+func (ca CodeArray) Length(vm *VirtualMachine) uint32 {
+ 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)
+}
+
+func (ca *CodeArray) SetLength(vm *VirtualMachine, l uint32) {
+ vm.heap[ca.id+code_len_offset] = word.FromInt(l)
}
A internal/vm/descriptor.go => internal/vm/descriptor.go +47 -0
@@ 0,0 1,47 @@
+package vm
+
+import "git.sr.ht/~madcapjake/grhumb/internal/word"
+
+// type Descriptor struct {
+// Mark Word // immutable, mutable, submap
+// Name Word // address to TextMap
+// Data Word // constant, field offset, or
+// }
+
+const (
+ desc_name_offset uint64 = 1
+ desc_data_offset uint64 = 2
+)
+
+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]}
+}
+
+func ReviveDescriptor(vm *VirtualMachine, addr word.Word) Descriptor {
+ i := addr.AsAddr()
+ mark := vm.heap[i]
+ if !(mark.IsDescMark()) {
+ panic("not a descriptor mark")
+ }
+ name := vm.heap[i+desc_name_offset]
+ if !(name.IsAddress()) {
+ panic("desciptor name word is not an address")
+ }
+ return Descriptor{vm, i, vm.heap[i : i+2]}
+}
A internal/vm/legend.go => internal/vm/legend.go +180 -0
@@ 0,0 1,180 @@
+package vm
+
+import "git.sr.ht/~madcapjake/grhumb/internal/word"
+
+// 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
+
+const (
+ base_lgd_offset uint64 = 1
+ base_swp_offset uint64 = 2
+ base_sze_offset uint64 = 3
+ base_len_offset uint64 = 3
+ base_req_offset uint64 = 4
+ base_dep_offset uint64 = 5
+ main_fld_offset uint64 = 6
+ list_arr_offset uint64 = 6
+ list_fld_offset uint64 = 7
+ text_arr_offset uint64 = 6
+ text_fld_offset uint64 = 7
+ func_chu_offset uint64 = 6
+ func_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
+}
+
+func wordsFromDescriptors(
+ d ...Descriptor,
+) (buf []word.Word) {
+ // buf = make([]word.Word, 0, len(d)*3)
+ // for descIndex := range d {
+ // buf = append(buf, d[descIndex]...)
+ // }
+ return
+}
+
+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 NewListMapLegend(
+ legAddr word.Word,
+ descs ...Descriptor,
+) ListMapLegend {
+ descCount := uint32(len(descs))
+ dWords := wordsFromDescriptors(descs...)
+ return NewBaseMapLegend(
+ word.Word(word.LIST_LGD),
+ legAddr,
+ descCount,
+ dWords,
+ )
+}
+
+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,
+ )
+}
+
+func NewFuncMapLegend(
+ legAddr word.Word,
+ descs ...Descriptor,
+) FuncMapLegend {
+ descCount := uint32(len(descs))
+ dWords := wordsFromDescriptors(descs...)
+ return NewBaseMapLegend(
+ word.Word(word.FUNC_LGD),
+ legAddr,
+ descCount,
+ dWords,
+ )
+}
+
+func NewMetaMapLegend(descs ...Descriptor) MetaMapLegend {
+ descCount := uint32(len(descs))
+ dWords := wordsFromDescriptors(descs...)
+ return NewBaseMapLegend(
+ word.Word(word.META_LGD),
+ word.FromAddress(0),
+ descCount,
+ dWords,
+ )
+}
+
+type ArrayLegend struct {
+ Mark word.Word
+ MetaLegend word.Word
+ TrashSweep word.Word
+ Field []Descriptor
+}
+
+func NewArrayLegend(mark word.Word) ArrayLegend {
+ return ArrayLegend{
+ Mark: mark,
+ MetaLegend: word.FromAddress(0),
+ TrashSweep: word.Empty(),
+ Field: make([]Descriptor, 0),
+ }
+}
M internal/vm/map.go => internal/vm/map.go +24 -52
@@ 1,66 1,38 @@
package vm
-type Map struct {
- Mark Word
- Legend Word // Address
- Field []Word
-}
+import "git.sr.ht/~madcapjake/grhumb/internal/word"
-func NewMap(count uint32, legAddr Word) Map {
- return Map{
- Word(MAIN_MAP),
- WordFromAddress(0),
- make([]Word, count),
- }
-}
+// type RhumbMap struct {
+// Mark word.Word
+// Legend word.Word
+// Field []word.Word
+// }
-type MapLegend struct {
- Mark Word
- MetaLegend Word
- TrashSweep Word
- Length Word
- Count Word
- PrevLegend Word // pointer, circular dependency list
- NextLegend Word // pointer, circular dependency list
- Field []LegendFieldDescriptor
+type RhumbMap []word.Word
+
+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 NewMapLegend() MapLegend {
- return MapLegend{
- Word(MAIN_LGD),
- WordFromAddress(0),
- EmptyWord(),
- WordFromInt(0),
- WordFromInt(0),
- WordFromAddress(0),
- WordFromAddress(0),
- make([]LegendFieldDescriptor, 0),
- }
+func NewMainMap(count uint32, legAddr word.Word) RhumbMap {
+ return NewMap(word.Word(word.MAIN_MAP), legAddr)
}
-type RoutineLegend struct {
- Mark Word
- MetaLegend Word // pointer to the toplevel MapLegend
- TrashSweep Word
- Length Word
- Count Word
- PrevLegend Word // pointer, circular dependency list
- NextLegend Word // pointer, circular dependency list
- Code Word // pointer to CodeArray
- Field []LegendFieldDescriptor
+func NewListMap(count uint32, legAddr word.Word) RhumbMap {
+ return NewMap(word.Word(word.LIST_MAP), legAddr)
}
-type ArrayLegend struct {
- Mark Word
- MetaLegend Word
- TrashSweep Word
- Parent LegendFieldDescriptor
+func NewTextMap(count uint32, legAddr word.Word) RhumbMap {
+ return NewMap(word.Word(word.TEXT_MAP), legAddr)
}
-// T
+func NewFuncMap(count uint32, legAddr word.Word) RhumbMap {
+ return NewMap(word.Word(word.FUNC_MAP), legAddr)
+}
-type LegendFieldDescriptor struct {
- Mark Word // immutable, mutable, subfield
- Name Word // address to TextMap
- Data Word // constant, field offset, or
+func NewMetaMap(count uint32, legAddr word.Word) RhumbMap {
+ return NewMap(word.Word(word.META_MAP), legAddr)
}
M internal/vm/primitives.go => internal/vm/primitives.go +9 -22
@@ 2,6 2,8 @@ package vm
import (
"fmt"
+
+ "git.sr.ht/~madcapjake/grhumb/internal/word"
)
/* Phase 1
@@ 9,21 11,6 @@ import (
* _-/_
*/
-func locateScopeLabel(
- scopes []map[string]int, lbl string,
-) (
- idx int, ok bool,
-) {
- topScope := len(scopes) - 1
- for i := topScope; i >= 0; i-- {
- idx, ok = scopes[i][lbl]
- if ok {
- return
- }
- }
- return
-}
-
func expBySquaring(x, n uint32) uint32 {
if n == 0 {
return 1
@@ 42,7 29,7 @@ func expBySquaring(x, n uint32) uint32 {
return x * y
}
-func (vm *VirtualMachine) popStack() (popped Word) {
+func (vm *VirtualMachine) popStack() (popped word.Word) {
idx := len(vm.stack) - 1
popped = vm.stack[idx]
vm.stack = vm.stack[:idx]
@@ 73,38 60,38 @@ func (vm *VirtualMachine) assignLabel() {
func (vm *VirtualMachine) addTwoInts() {
val1, val2 := vm.gatherTwoInts()
- vm.stack = append(vm.stack, WordFromInt(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, WordFromInt(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, WordFromInt(val1*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, WordFromInt(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, WordFromInt(expBySquaring(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]int))
- vm.stack = append(vm.stack, Word(SENTINEL))
+ vm.stack = append(vm.stack, word.Sentinel())
}
// Same as routine
M internal/vm/rune_array.go => internal/vm/rune_array.go +130 -36
@@ 1,53 1,147 @@
package vm
import (
- "bytes"
"encoding/binary"
- "fmt"
+ "unicode/utf8"
+
+ "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
+ rune_len_offset uint64 = 3
+ rune_arr_offset uint64 = 4
)
type RuneArray struct {
- Mark Word
- Legend Word // Address
- Length Word
- Runes []Word // Words are packed 2-elem runes
+ // address in vm's heap
+ id uint64
}
-func NewRuneArray(addr Word, words ...Word) RuneArray {
- return RuneArray{
- Word(RUNE_ARR),
- addr,
- WordFromInt(uint32(len(words))),
- words,
+func RuneWords(str string) (words []word.Word) {
+ var (
+ rn rune
+ sz, length int
+ )
+ for id := 0; id < len(str); id += sz {
+ rn, sz = utf8.DecodeRuneInString(str[id:])
+ words = append(words, word.FromRune(rn))
+ length++
}
+ return
}
-func (ra *RuneArray) SetRunes(rs []rune) {
- var buf bytes.Buffer
- ra.Runes = nil
- for r := range rs {
- _, err := buf.WriteRune(rs[r])
- if err != nil {
- fmt.Println("buf.WriteRune failed:", err)
- }
- if (r+1)%2 == 0 {
- ra.Runes = append(
- ra.Runes,
- Word(binary.LittleEndian.Uint64(buf.Bytes())),
- )
- buf.Reset()
- }
+func NewRuneArray(
+ vm *VirtualMachine,
+ legAddr word.Word,
+ words ...word.Word,
+) RuneArray {
+ wordsLen := uint32(len(words))
+ wordsSize := uint32(code_arr_offset) + wordsLen
+ raWords := make([]word.Word, 0, wordsSize)
+ raWords = append(raWords,
+ /* Mark: */ word.Word(word.RUNE_ARR),
+ /* Legend: */ legAddr,
+ /* Size: */ word.FromInt(wordsSize),
+ /* Length: */ word.FromInt(wordsLen),
+ )
+ raWords = append(raWords, words...)
+
+ loc, err := vm.ReAllocate(raWords...)
+ if err != nil {
+ panic("allocation failed")
}
- ra.Length = WordFromInt(uint32(len(ra.Runes)))
+ return RuneArray{uint64(loc)}
}
-func (ra *RuneArray) GetRunes() []rune {
- b := make([]byte, 8)
- buf := new(bytes.Buffer)
- for word := range ra.Runes {
- binary.LittleEndian.PutUint64(b, uint64(word))
- buf.Write(b)
- b = nil
+func ReviveRuneArray(vm *VirtualMachine, addr word.Word) RuneArray {
+ i := addr.AsAddr()
+ mark := vm.heap[i]
+ if !(mark.IsRuneArrayMark()) {
+ panic("not a rune array mark")
+ }
+ legend := vm.heap[i+rune_lgd_offset]
+ if !(legend.IsAddress()) {
+ panic("rune array legend word is not an address")
+ }
+ size := vm.heap[i+rune_sze_offset]
+ if !(size.IsInteger()) {
+ panic("rune array object size word is not an integer")
+ }
+ return RuneArray{i}
+}
+
+func (ra RuneArray) Id() uint64 { return ra.id }
+
+func (ra RuneArray) Legend(vm *VirtualMachine) uint64 {
+ 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())
+}
+func (ra RuneArray) Length(vm *VirtualMachine) uint32 {
+ return vm.heap[ra.id+rune_len_offset].AsInt()
+}
+func (ra RuneArray) Runes(vm *VirtualMachine) []rune {
+ buf := make([]rune, 0, ra.Length(vm))
+ for i := range vm.heap[ra.id+rune_arr_offset:] {
+ bytes := make([]byte, 8)
+ binary.LittleEndian.PutUint64(bytes, uint64(vm.heap[ra.id+uint64(i)]))
+ buf = append(buf, rune(binary.LittleEndian.Uint32(bytes[:4])))
+ buf = append(buf, rune(binary.LittleEndian.Uint32(bytes[4:])))
+ }
+ return buf
+}
+
+func (ra RuneArray) String(vm *VirtualMachine) string {
+ return string(ra.Runes(vm))
+}
+
+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)]))
+ if offset == 0 {
+ return rune(binary.LittleEndian.Uint32(bytes[:4]))
+ } else {
+ return rune(binary.LittleEndian.Uint32(bytes[4:]))
+ }
+}
+
+func (ra RuneArray) SetSize(vm *VirtualMachine, s uint32) {
+ 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)
+}
+
+func (ra RuneArray) SetRune(vm *VirtualMachine, i uint32, r rune) {
+ var (
+ addr uint64 = uint64(i) / 2
+ id uint64 = ra.id + addr
+ offset uint32 = i % 2
+ runeBytes []byte = make([]byte, 4)
+ wordBytes []byte = make([]byte, 8)
+ )
+ binary.LittleEndian.PutUint32(runeBytes, uint32(r))
+ binary.LittleEndian.PutUint64(wordBytes, uint64(vm.heap[id]))
+ if offset == 0 {
+ copy(wordBytes, runeBytes)
+ } else {
+ for i := range runeBytes {
+ wordBytes[i+4] = runeBytes[i]
+ }
}
- return []rune(buf.String())
+ vm.heap[id] = word.Word(binary.LittleEndian.Uint64(wordBytes))
}
M internal/vm/vm.go => internal/vm/vm.go +250 -38
@@ 5,6 5,8 @@ import (
"io"
"log"
"os"
+
+ "git.sr.ht/~madcapjake/grhumb/internal/word"
)
var vmLogger = log.New(io.Discard, "", log.LstdFlags)
@@ 16,43 18,202 @@ func init() {
}
type VirtualMachine struct {
- heap []Word
+ heap []word.Word
free []bool
- stack []Word
+ stack []word.Word
scope []map[string]int
main Chunk
}
+func (vm VirtualMachine) DebugHeap() {
+ width := 4
+ for i := range vm.heap {
+ if i%width == 0 {
+ fmt.Println()
+ }
+ if vm.free[i] {
+ fmt.Printf("{%3v: }", i)
+ } else {
+ fmt.Printf("[%3v: %-9s ]", i, vm.heap[i].Debug())
+ }
+ }
+ fmt.Println()
+}
+
func NewVirtualMachine() *VirtualMachine {
vm := new(VirtualMachine)
- vm.heap = make([]Word, 0)
- vm.free = make([]bool, 0)
- vm.stack = make([]Word, 0)
+ const init_heap_len int = 10
+ 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]int, 0)
vm.scope = append(vm.scope, make(map[string]int))
- vm.main = NewChunk(nil, nil)
+ vm.main = NewChunk(vm)
+ return vm
+}
+
+// Traverses the free list until a sufficiently-sized chunk
+// of free slots is available to place the word arguments.
+//
+// Returns the index of the final heap location.
+func (vm *VirtualMachine) ReAllocate(ws ...word.Word) (uint64, error) {
+ obj := *vm
+ size := len(ws)
+ if size == 0 {
+ return 0, fmt.Errorf("no words provided")
+ }
+ var first, next int
+ for first = 0; first < len(obj.free); first += next {
+ next = 0
+ if obj.free[first] {
+ if size == 1 {
+ vmLogger.Println("adding word to index:", first)
+ 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]) {
+ next++
+ break
+ } else if next == last {
+ vmLogger.Println("appending words to index:", first)
+ obj.allocInPlace(first, last, ws...)
+ obj.DebugHeap()
+ *vm = obj
+ return uint64(first), nil
+ }
+ }
+ }
+ } else {
+ next = 1
+ }
+ }
+ // no available chunk in existing memory locations.
+ first = len(obj.heap)
+ vmLogger.Println("appending words to end:", first)
+ obj = appendRhumb(obj, ws)
+ *vm = obj
+ return uint64(first), nil
+}
+
+// Traverses the free list directly after the current
+// used memory for this object. If there is sufficient free
+// slots, then allocInPlace. Otherwise, call ReAllocate.
+//
+// Returns the index of the final heap location.
+func (vm *VirtualMachine) Allocate(
+ loc int,
+ oldSize int,
+ ws ...word.Word,
+) (uint64, error) {
+ var (
+ obj VirtualMachine = *vm
+ newSize int = len(ws)
+ lastOldId int = loc + oldSize
+ )
+ if newSize == 0 {
+ return 0, fmt.Errorf("no words provided")
+ }
+ var i int = lastOldId
+ 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 newSize == 1 {
+ vmLogger.Println("appending word to index:", i)
+ obj.heap[i] = ws[0]
+ obj.free[i] = false
+ obj.DebugHeap()
+ *vm = obj
+ return uint64(loc), nil
+ } else {
+ last := i + newSize
+ for i = i + 1; i < last; i++ {
+ if !(obj.free[i]) {
+ break
+ } else if i == last {
+ first := lastOldId
+ vmLogger.Println("appending words to index:", first)
+ obj.allocInPlace(first, last, ws...)
+ obj.DebugHeap()
+ *vm = obj
+ return uint64(loc), nil
+ }
+ }
+ }
+ }
+ // 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, ws...)
+
+ for f := range obj.free[loc:lastOldId] {
+ obj.free[loc+f] = true
+ }
+
+ id, err := obj.ReAllocate(totalWords...)
+ *vm = obj
+ return id, err
+}
+
+// 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.DebugHeap()
return vm
}
+// Only run this if you are absolutely sure there is room
+// to allocate in the heap. Overwriting memory is possible.
+func (vm VirtualMachine) allocInPlace(x, y int, ws ...word.Word) {
+ for hID, wID := x, 0; hID < y; hID, wID = hID+1, wID+1 {
+ vm.heap[hID], vm.free[hID] = ws[wID], false
+ }
+}
+
+// func (vm VirtualMachine) UpdateAddresses(oldId, newId uint64) {
+// for i, free := range vm.free {
+// if !(free) {
+// w := vm.heap[i]
+// if w.IsAddress() && w.AsAddr() == oldId {
+// vm.heap[i] = word.FromAddress(int(newId))
+// }
+// }
+// }
+// }
+
func (vm *VirtualMachine) WriteCodeToMain(
line int,
- ref InstrRef,
- codeFactory func(i uint32) []Code,
+ lit word.Word,
+ codeFactory func(i uint64) []Code,
) {
- id := vm.main.AddReference(ref)
+ id, _ := vm.main.AddLiteral(vm, lit)
codes := codeFactory(id)
- vm.main.WriteCode(line, codes)
+ vm.main.WriteCode(vm, line, codes)
}
func (vm *VirtualMachine) Disassemble() {
- vm.main.Disassemble()
+ // vm.main.Disassemble()
}
func (vm *VirtualMachine) Execute() {
- vm.main.Execute(vm)
+ // vm.main.Execute(vm)
}
-func logAddedToStack(stack []Word, txt string) {
+func logAddedToStack(stack []word.Word, txt string) {
logStr := fmt.Sprintf("▏ %-7s ⇾ [", txt)
for s := range stack {
logStr = fmt.Sprint(logStr, " ")
@@ 65,39 226,90 @@ func logAddedToStack(stack []Word, txt string) {
vmLogger.Println(logStr, " ]")
}
-func (vm *VirtualMachine) AddValueToStack(ir InstrRef) {
- vm.stack = append(vm.stack, NewWord(ir.value))
- logAddedToStack(vm.stack, ir.text)
+func locateScopeLabel(
+ scopes []map[string]int, lbl string,
+) (
+ idx int, ok bool,
+) {
+ topScope := len(scopes) - 1
+ for i := topScope; i >= 0; i-- {
+ idx, ok = scopes[i][lbl]
+ if ok {
+ return
+ }
+ }
+ return
}
-// Currently just for traversing the scope outwardly
-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, 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, WordFromAddress(idx))
- logAddedToStack(vm.stack, ir.text)
+// func (vm *VirtualMachine) TextMapFromString(s string) word.Word {
+// var first word.Word
+// var rn rune
+// var sz, runeCount int
+// for si := 0; si < len(s); si += sz {
+// rn, sz = utf8.DecodeRuneInString(s[si:])
+// vm.heap = append(vm.heap, word.FromRune(rn))
+// if si == 0 {
+// first = word.FromAddress(len(vm.heap) - 1)
+// }
+// runeCount += 1
+// }
+// last := int(first.AsInt()) + runeCount
+// legend := TextMapLegend{
+// BaseMapLegend: BaseMapLegend{
+// Legend: Legend{
+// Mark: word.Word(word.TEXT_LGD),
+// MetaLegend: word.FromAddress(0),
+// },
+// TrashSweep: Empty(),
+// Length: word.FromInt(0),
+// Count: word.FromInt(0),
+// ReqLink: word.FromAddress(0),
+// DepLink: word.FromAddress(0),
+// },
+// Runes: NewRuneArray(first, vm.heap[first.AsInt():last]...),
+// }
+// }
+
+func (vm *VirtualMachine) AddLiteralToStack(literal word.Word) {
+ vm.stack = append(vm.stack, literal)
+ logAddedToStack(vm.stack, literal.Debug())
+}
+
+func (vm *VirtualMachine) getStringFromRuneArray(labelAddr word.Word) {
+
+}
+
+// Currently just for lexically traversing the scope
+func (vm *VirtualMachine) SubmitLocalRequest(label word.Word) {
+ // labelValue := vm.getStringFromRuneArray(label)
+ // idx, ok := locateScopeLabel(vm.scope, label)
+ // if ok {
+ // // TODO: Invoke address, skip addrRef
+ // vm.stack = append(vm.stack, word.FromAddress(idx))
+ // logAddedToStack(vm.stack, ir.text)
+ // return
+ // }
+ // vm.heap = append(vm.heap, EmptyWord())
+ // idx = len(vm.heap) - 1
+ // vm.scope[len(vm.scope)-1][ir.text] = idx
+ // vm.stack = append(vm.stack, word.FromAddress(idx))
+ // logAddedToStack(vm.stack, ir.text)
}
// Used for traversing maps and legends
-func (vm *VirtualMachine) SubmitInnerRequest(ir InstrRef) {
+func (vm *VirtualMachine) SubmitInnerRequest(label word.Word) {
}
// Used for traversing submaps and legends
-func (vm *VirtualMachine) SubmitUnderRequest(ir InstrRef) {
+func (vm *VirtualMachine) SubmitUnderRequest(label word.Word) {
}
// Used for traversing primitives and compilations
-func (vm *VirtualMachine) SubmitOuterRequest(ir InstrRef) {
- switch ir.text {
+func (vm *VirtualMachine) SubmitOuterRequest(label word.Word) {
+ // FIXME: locate text
+ text := ""
+ switch text {
case ".=", ":=":
vm.assignLabel()
case "++":
@@ 124,8 336,8 @@ func (vm *VirtualMachine) SubmitOuterRequest(ir InstrRef) {
}
}
-// Used for signalling across Rhumb
-func (vm *VirtualMachine) SubmitEventRequest(ir InstrRef) {}
+// // Used for signalling across Rhumb
+// func (vm *VirtualMachine) SubmitEventRequest(ir InstrRef) {}
-// Used for replying to signals across Rhumb
-func (vm *VirtualMachine) SubmitReplyRequest(ir InstrRef) {}
+// // Used for replying to signals across Rhumb
+// func (vm *VirtualMachine) SubmitReplyRequest(ir InstrRef) {}
M internal/vm/word_array.go => internal/vm/word_array.go +88 -28
@@ 1,45 1,105 @@
package vm
-import "fmt"
+import (
+ "fmt"
+
+ "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
+ word_arr_offset uint64 = 3
+)
type WordArray struct {
- Mark Word
- Legend Word // Address
- Length Word
- Words []Word // Words are normal single words
-}
-
-func NewWordArray(words ...Word) WordArray {
- return WordArray{
- Word(MAIN_ARR),
- Word(VAL_ADDR),
- WordFromInt(uint32(len(words))),
- words,
+ // address in vm's heap
+ 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,
+ words ...word.Word,
+) WordArray {
+ wordsLen := uint32(len(words))
+ wordsSize := uint32(code_arr_offset) + wordsLen
+ waWords := make([]word.Word, 0, wordsSize)
+ waWords = append(waWords,
+ /* Mark: */ word.Word(word.MAIN_ARR),
+ /* Legend: */ legAddr,
+ /* Length: */ word.FromInt(wordsLen),
+ )
+ waWords = append(waWords, words...)
+
+ loc, err := vm.ReAllocate(waWords...)
+ if err != nil {
+ panic("allocation failed")
}
+ return WordArray{uint64(loc)}
}
-func (wa *WordArray) IndexOf(w Word) (idx int, err error) {
- for i := range wa.Words {
- if wa.Words[i] == w {
- return i, nil
- }
+func ReviveWordArray(vm *VirtualMachine, addr word.Word) WordArray {
+ i := addr.AsAddr()
+ mark := vm.heap[i]
+ if !(mark.IsMainArrayMark()) {
+ panic("not a word array mark")
+ }
+ legend := vm.heap[i+word_lgd_offset]
+ if !(legend.IsAddress()) {
+ // fmt.Println(legend.Debug())
+ panic("word array legend word is not an address")
}
- return 0, fmt.Errorf("couldn't find word")
+ length := vm.heap[i+word_len_offset]
+ if !(length.IsInteger()) {
+ panic("word array object length word is not an integer")
+ }
+ return WordArray{i}
}
-func (wa *WordArray) Add(w Word) {
- wa.Words = append(wa.Words, w)
- wa.Length = WordFromInt(uint32(len(wa.Words)))
+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
+ }
+ }
+ return -1, fmt.Errorf("couldn't find word")
}
-func (wa *WordArray) Get(i uint32) Word {
- return wa.Words[i]
+func (wa *WordArray) Append(vm *VirtualMachine, newWords ...word.Word) (uint64, error) {
+ 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
+ }
+ return id, err
+ }
}
-func (wa *WordArray) All() []Word {
- return wa.Words
+func (wa WordArray) Get(vm *VirtualMachine, i int) word.Word {
+ return vm.heap[wa.id+word_arr_offset+uint64(i)]
}
-func (wa *WordArray) Count() int {
- return int(wa.Length.AsInt())
+func (wa WordArray) Size(vm *VirtualMachine) int {
+ return wa.Length(vm) + 3
}
R internal/vm/word.go => internal/word/word.go +107 -52
@@ 1,4 1,4 @@
-package vm
+package word
import (
"bytes"
@@ 41,7 41,7 @@ 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 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
@@ 50,6 50,7 @@ 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 ARRA_LGD uint64 = 0x7F_FE_C0_50_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
@@ 75,26 76,27 @@ const MASK_TWO uint64 = 0x7F_FF_C0_F0_00_00_00_00
func NewWord(a any) Word {
switch a := a.(type) {
case float64:
- return WordFromFloat(a)
+ return FromFloat(a)
case float32:
- return WordFromFloat(float64(a))
+ return FromFloat(float64(a))
case bool:
- return WordFromBool(a)
+ return FromBool(a)
case int:
- return WordFromInt(uint32(a))
+ return FromInt(uint32(a))
case int64:
- return WordFromInt(uint32(a))
+ return FromInt(uint32(a))
case rune:
- return WordFromRune(a)
+ return FromRune(a)
default:
- return EmptyWord()
+ return Empty()
}
}
-func EmptyWord() Word { return Word(VAL_EMPT) }
-func NotANumberWord() Word { return Word(ERR_NUMB) }
+func Empty() Word { return Word(VAL_EMPT) }
+func NAN() Word { return Word(ERR_NUMB) }
+func Sentinel() Word { return Word(SENTINEL) }
-func WordFromFloat(f float64) Word {
+func FromFloat(f float64) Word {
var bytes [8]byte
fbits := math.Float64bits(f)
bytes[0] = byte(fbits >> 56)
@@ 108,17 110,17 @@ func WordFromFloat(f float64) Word {
return Word(binary.LittleEndian.Uint64(bytes[:]))
}
-func WordFromBool(b bool) Word {
+func FromBool(b bool) Word {
if b {
return Word(VAL_TRUE)
} else {
return Word(VAL_FALS)
}
}
-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 FromInt(i uint32) Word { return Word(VAL_NUMB | uint64(i)) }
+func FromRune(r rune) Word { return Word(VAL_RUNE | uint64(r)) }
+func FromSym(a int) Word { return Word(VAL_SYMB | uint64(a)) }
+func FromAddress(a int) Word { return Word(VAL_ADDR | uint64(a)) }
func (w Word) isVal(v uint64) bool { return uint64(w)&MASK_ONE == v }
@@ 135,43 137,45 @@ 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) isMark(m uint64) bool { return uint64(w)&MASK_ONE == m }
+func (w Word) isMark2(m uint64) bool { return uint64(w)&MASK_TWO == 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) 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(FUNC_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.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) IsMainArrayMark() bool { return w.isMark2(MAIN_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.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) 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(FUNC_LGD) }
+func (w Word) IsArraLegendMark() bool { return w.isMark2(ARRA_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.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) 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) IsChunk() bool { return w.isMark(CMP_UNIT) }
+func (w Word) IsCmpUnit() bool { return w.isMark(CMP_UNIT) }
-func (w Word) Debug() any {
+func (w Word) Debug() string {
if w.IsNAN() {
return "NAN"
} else if w.IsTrue() {
@@ 181,25 185,76 @@ func (w Word) Debug() any {
} else if w.IsEmpty() {
return "EMPTY"
} else if w.IsInteger() {
- return fmt.Sprint("{INT: ", w.AsInt(), "}")
+ return fmt.Sprint("N ", w.AsInt(), " ")
} else if w.IsRune() {
- return fmt.Sprint("{RUNE: ", w.AsRune(), "}")
+ return fmt.Sprint("R '", string(w.AsRune()), "'")
} else if w.IsSym() {
- return "SYMBOL" // FIXME: Implement symbols
+ return "S" // FIXME: Implement symbols
} else if w.IsAddress() { // must trigger before IsFloat for unknown reasons
- return fmt.Sprint("{ADDR: ", w.AsAddr(), "}")
+ return fmt.Sprint("A ", w.AsAddr(), " ")
} else if w.IsFloat() {
- return fmt.Sprint("{FLOAT: ", w.AsFloat(), "}")
+ // return fmt.Sprintf("F %.1e", w.AsFloat())
+ return ". . . . ."
} else if w.IsMapMark() {
- return "MAP"
- } else if w.IsArrayMark() {
- return "ARRAY"
+ return "MAP MARK"
+ } else if w.IsCodeArrayMark() {
+ return "CODE MARK"
+ } else if w.IsMainArrayMark() {
+ return "LIST MARK"
+ } else if w.IsRuneArrayMark() {
+ return "RUNE MARK"
} else if w.IsFuncMapMark() {
return "ROUTINE"
- } else if w.IsChunk() {
- return "CHUNK"
+ } else if w.IsCmpUnit() {
+ return "CMPUNIT"
+ } else if w.IsSentinel() {
+ return "SENTINEL"
} else {
- return nil
+ return "..."
+ }
+}
+
+func (x Word) Equals(y Word) bool {
+ if x.IsNAN() {
+ return false
+ } else if x.IsTrue() {
+ return y.IsTrue()
+ } else if x.IsFalse() {
+ return y.IsFalse()
+ } else if x.IsEmpty() {
+ return y.IsEmpty()
+ } else if x.IsInteger() {
+ if y.IsInteger() {
+ return x.IsInteger() == y.IsInteger()
+ } else {
+ return false
+ }
+ } else if x.IsRune() {
+ if y.IsRune() {
+ return x.AsRune() == y.AsRune()
+ } else {
+ return false
+ }
+ } else if x.IsSym() {
+ panic("symbols are not yet implemented")
+ } else if x.IsAddress() { // must trigger before IsFloat for unknown reasons
+ if y.IsAddress() {
+ return x.AsAddr() == y.AsAddr()
+ } else {
+ return false
+ }
+ } else if x.IsFloat() {
+ if y.IsFloat() {
+ return x.AsFloat() == y.AsFloat()
+ } else {
+ return false
+ }
+ } else if x.IsAnyMark() {
+ panic("should not compare marks")
+ } else if x.IsCmpUnit() {
+ panic("should not compare chunks")
+ } else {
+ panic("unknown object comparison")
}
}