diff options
| author | Marc Vertes <mvertes@free.fr> | 2026-01-16 12:30:31 +0100 |
|---|---|---|
| committer | Marc Vertes <mvertes@free.fr> | 2026-01-16 12:30:31 +0100 |
| commit | ee9397bc031dc33e4f735b3331643bbf60a0d17a (patch) | |
| tree | 42087d58e916904af3e70de6171e0f1c9c894d8f | |
| parent | 31e3793202402fda21905027c18ebfa5c8d8c832 (diff) | |
feat: handle slice expressions
| -rw-r--r-- | comp/compiler.go | 20 | ||||
| -rw-r--r-- | interp/interpreter.go | 3 | ||||
| -rw-r--r-- | interp/interpreter_test.go | 17 | ||||
| -rw-r--r-- | lang/token.go | 4 | ||||
| -rw-r--r-- | lang/token_string.go | 12 | ||||
| -rw-r--r-- | parser/expr.go | 47 | ||||
| -rw-r--r-- | symbol/symbol.go | 3 | ||||
| -rw-r--r-- | vm/op_string.go | 76 | ||||
| -rw-r--r-- | vm/vm.go | 30 | ||||
| -rw-r--r-- | vm/vm_test.go | 139 |
10 files changed, 189 insertions, 162 deletions
diff --git a/comp/compiler.go b/comp/compiler.go index 8a7db22..4c691b2 100644 --- a/comp/compiler.go +++ b/comp/compiler.go @@ -178,7 +178,6 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { emit(t, vm.CallX, t.Beg) case lang.Colon: - showStack() pop() ks := pop() ts := top() @@ -242,7 +241,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { } emit(t, vm.Vassign) - case lang.MapAssign: + case lang.IndexAssign: s := stack[len(stack)-3] switch s.Type.Rtype.Kind() { case reflect.Array, reflect.Slice: @@ -318,6 +317,10 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { c.Symbols[t.Str] = &symbol.Symbol{Kind: symbol.Label, Value: vm.ValueOf(lc)} } + case lang.Len: + push(&symbol.Symbol{Type: c.Symbols["int"].Type}) + emit(t, vm.Len, t.Beg) + case lang.JumpFalse: var i int if s, ok := c.Symbols[t.Str]; !ok { @@ -393,8 +396,6 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { case symbol.Unset: return errorf("invalid symbol: %s", s.Name) default: - // FIXME: handle pointer indirection here - log.Println("## XXX", s.Type, s.Type.IsPtr()) typ := s.Type.Rtype isPtr := typ.Kind() == reflect.Pointer if isPtr { @@ -416,6 +417,15 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { case lang.Return: emit(t, vm.Return, t.Beg, t.End) + case lang.Slice: + if stack[len(stack)-3].IsInt() { + emit(t, vm.Slice3) + stack = stack[:len(stack)-4] + } else { + emit(t, vm.Slice) + stack = stack[:len(stack)-3] + } + default: return fmt.Errorf("generate: unsupported token %v", t) } @@ -457,7 +467,7 @@ func (c *Compiler) PrintCode() { } extra := "" switch l.Op { - case vm.Jump, vm.JumpFalse, vm.JumpTrue, vm.JumpSetFalse, vm.JumpSetTrue, vm.Calli: + case vm.Jump, vm.JumpFalse, vm.JumpTrue, vm.JumpSetFalse, vm.JumpSetTrue: if d, ok := labels[i+l.Arg[0]]; ok { extra = "// " + d[0] } diff --git a/interp/interpreter.go b/interp/interpreter.go index 8d372c3..4faba28 100644 --- a/interp/interpreter.go +++ b/interp/interpreter.go @@ -42,7 +42,8 @@ func (i *Interp) Eval(src string) (res reflect.Value, err error) { i.Push(i.Data[dataOffset:]...) i.PushCode(i.Code[codeOffset:]...) if s, ok := i.Symbols["main"]; ok { - i.PushCode(vm.Instruction{Op: vm.Calli, Arg: []int{int(i.Data[s.Index].Int())}}) + i.PushCode(vm.Instruction{Op: vm.Push, Arg: []int{int(i.Data[s.Index].Int())}}) + i.PushCode(vm.Instruction{Op: vm.Call, Arg: []int{0}}) } i.PushCode(vm.Instruction{Op: vm.Exit}) i.SetIP(max(codeOffset, i.Entry)) diff --git a/interp/interpreter_test.go b/interp/interpreter_test.go index bf90357..7a974d1 100644 --- a/interp/interpreter_test.go +++ b/interp/interpreter_test.go @@ -230,6 +230,23 @@ func TestMap(t *testing.T) { }) } +func TestSlice(t *testing.T) { + src0 := `s := []int{0, 1, 2, 3};` + run(t, []etest{ + {src: src0 + `s`, res: `[0 1 2 3]`}, // #00 + {src: src0 + `s[:]`, res: `[0 1 2 3]`}, // #01 + {src: src0 + `s[1:3]`, res: `[1 2]`}, // #02 + {src: src0 + `s[1:3:4]`, res: `[1 2]`}, // #03 + {src: src0 + `s[:3:4]`, res: `[0 1 2]`}, // #04 + {src: src0 + `s[:2:]`, err: `final index required in 3-index slice`}, // #05 + {src: src0 + `s[:3:4:]`, err: `expected ']', found ':'`}, // #06 + {src: src0 + `s[2:]`, res: `[2 3]`}, // #07 + {src: src0 + `s[:0]`, res: `[]`}, // #08 + {src: `"Hello"[1:3]`, res: `el`}, // #09 + {src: `s := "Hello"; s[1:3]`, res: `el`}, // #10 + }) +} + func TestType(t *testing.T) { src0 := `type ( I int diff --git a/lang/token.go b/lang/token.go index 46a5bb4..9800599 100644 --- a/lang/token.go +++ b/lang/token.go @@ -59,7 +59,7 @@ const ( AndNotAssign // &^= Inc // ++ Dec // -- - MapAssign + IndexAssign // a[i] = // Unary operations. Plus // unary + @@ -120,7 +120,9 @@ const ( JumpSetFalse JumpSetTrue Label + Len New + Slice // This must be the last token value. MaxTok diff --git a/lang/token_string.go b/lang/token_string.go index 7f06092..cf17584 100644 --- a/lang/token_string.go +++ b/lang/token_string.go @@ -51,7 +51,7 @@ func _() { _ = x[AndNotAssign-40] _ = x[Inc-41] _ = x[Dec-42] - _ = x[MapAssign-43] + _ = x[IndexAssign-43] _ = x[Plus-44] _ = x[Minus-45] _ = x[Addr-46] @@ -102,13 +102,15 @@ func _() { _ = x[JumpSetFalse-91] _ = x[JumpSetTrue-92] _ = x[Label-93] - _ = x[New-94] - _ = x[MaxTok-95] + _ = x[Len-94] + _ = x[New-95] + _ = x[Slice-96] + _ = x[MaxTok-97] } -const _Token_name = "IllegalCommentIdentCharFloatImagIntStringAddSubMulQuoRemAndOrXorShlShrAndNotPeriodEqualGreaterGreaterEqualLandLessLessEqualLorNotEqualDefineAssignAddAssignSubAssignMulAssignQuoAssignRemAssignAndAssignOrAssignXorAssignShlAssignShrAssignAndNotAssignIncDecMapAssignPlusMinusAddrDerefBitCompArrowEllipsisNotTildeCommaSemicolonColonParenBlockBracketBlockBraceBlockBreakCaseChanConstContinueDefaultDeferElseFallthroughForFuncGoGotoIfImportInterfaceMapPackageRangeReturnSelectStructSwitchTypeVarCallCallXCompositeEqualSetGrowIndexJumpFalseJumpSetFalseJumpSetTrueLabelNewMaxTok" +const _Token_name = "IllegalCommentIdentCharFloatImagIntStringAddSubMulQuoRemAndOrXorShlShrAndNotPeriodEqualGreaterGreaterEqualLandLessLessEqualLorNotEqualDefineAssignAddAssignSubAssignMulAssignQuoAssignRemAssignAndAssignOrAssignXorAssignShlAssignShrAssignAndNotAssignIncDecIndexAssignPlusMinusAddrDerefBitCompArrowEllipsisNotTildeCommaSemicolonColonParenBlockBracketBlockBraceBlockBreakCaseChanConstContinueDefaultDeferElseFallthroughForFuncGoGotoIfImportInterfaceMapPackageRangeReturnSelectStructSwitchTypeVarCallCallXCompositeEqualSetGrowIndexJumpFalseJumpSetFalseJumpSetTrueLabelLenNewSliceMaxTok" -var _Token_index = [...]uint16{0, 7, 14, 19, 23, 28, 32, 35, 41, 44, 47, 50, 53, 56, 59, 61, 64, 67, 70, 76, 82, 87, 94, 106, 110, 114, 123, 126, 134, 140, 146, 155, 164, 173, 182, 191, 200, 208, 217, 226, 235, 247, 250, 253, 262, 266, 271, 275, 280, 287, 292, 300, 303, 308, 313, 322, 327, 337, 349, 359, 364, 368, 372, 377, 385, 392, 397, 401, 412, 415, 419, 421, 425, 427, 433, 442, 445, 452, 457, 463, 469, 475, 481, 485, 488, 492, 497, 506, 514, 518, 523, 532, 544, 555, 560, 563, 569} +var _Token_index = [...]uint16{0, 7, 14, 19, 23, 28, 32, 35, 41, 44, 47, 50, 53, 56, 59, 61, 64, 67, 70, 76, 82, 87, 94, 106, 110, 114, 123, 126, 134, 140, 146, 155, 164, 173, 182, 191, 200, 208, 217, 226, 235, 247, 250, 253, 264, 268, 273, 277, 282, 289, 294, 302, 305, 310, 315, 324, 329, 339, 351, 361, 366, 370, 374, 379, 387, 394, 399, 403, 414, 417, 421, 423, 427, 429, 435, 444, 447, 454, 459, 465, 471, 477, 483, 487, 490, 494, 499, 508, 516, 520, 525, 534, 546, 557, 562, 565, 568, 573, 579} func (i Token) String() string { idx := int(i) - 0 diff --git a/parser/expr.go b/parser/expr.go index 5a1c670..1944827 100644 --- a/parser/expr.go +++ b/parser/expr.go @@ -1,6 +1,7 @@ package parser import ( + "errors" "log" "strconv" @@ -105,7 +106,7 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) { } case lang.ParenBlock: - toks, err := p.parseExprStr(t.Block(), typeStr) + toks, err := p.parseBlock(t, typeStr) if err != nil { return out, err } @@ -149,17 +150,20 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) { i += n - 1 break } - toks, err := p.parseExprStr(t.Block(), typeStr) + toks, err := p.parseBlock(t, typeStr) if err != nil { return out, err } + if len(toks) == 0 { + break + } out = append(out, toks...) if i < len(in)-2 && in[i+1].Tok == lang.Assign { - // A bracket block followed by assign implies a MapAssing token, + // A bracket block followed by assign implies an IndexAssign token, // as assignement to a map element cannot be implemented through a normal Assign. - ops = append(ops, scanner.Token{Tok: lang.MapAssign, Pos: t.Pos}) + ops = append(ops, scanner.Token{Tok: lang.IndexAssign, Pos: t.Pos}) i++ - } else { + } else if toks[len(toks)-1].Tok != lang.Slice { ops = append(ops, scanner.Token{Tok: lang.Index, Pos: t.Pos}) } @@ -225,17 +229,44 @@ func (p *Parser) parseComposite(s, typ string) (Tokens, error) { return result, nil } -func (p *Parser) parseExprStr(s, typ string) (tokens Tokens, err error) { - if tokens, err = p.Scan(s, false); err != nil { +func (p *Parser) parseBlock(t scanner.Token, typ string) (result Tokens, err error) { + tokens, err := p.Scan(t.Block(), false) + if err != nil { return tokens, err } - var result Tokens + if tokens.Index(lang.Colon) >= 0 { + // Slice expression, a[low : high] or a[low : high : max] + for i, sub := range tokens.Split(lang.Colon) { + if i > 2 { + return nil, errors.New("expected ']', found ':'") + } + if len(sub) == 0 { + if i == 0 { + result = append(result, scanner.Token{Tok: lang.Int, Str: "0"}) + continue + } else if i == 2 { + return nil, errors.New("final index required in 3-index slice") + } + result = append(result, scanner.Token{Tok: lang.Len, Beg: 1}) + continue + } + toks, err := p.parseExpr(sub, typ) + if err != nil { + return result, err + } + result = append(result, toks...) + } + result = append(result, scanner.Token{Tok: lang.Slice, Pos: t.Pos}) + return result, err + } + for _, sub := range tokens.Split(lang.Comma) { toks, err := p.parseExpr(sub, typ) if err != nil { return result, err } + // Inverse sub list order (func call parameters) result = append(toks, result...) } diff --git a/symbol/symbol.go b/symbol/symbol.go index 5e8610a..8f261e3 100644 --- a/symbol/symbol.go +++ b/symbol/symbol.go @@ -60,6 +60,9 @@ func (s *Symbol) IsFunc() bool { return s.Kind == Func } // IsPtr returns true if symbol is a pointer. func (s *Symbol) IsPtr() bool { return s.Type.Rtype.Kind() == reflect.Pointer } +// IsInt returns true if symbol is an int. +func (s *Symbol) IsInt() bool { return s.Type.Rtype.Kind() == reflect.Int } + // Vtype returns the VM type of a symbol. func Vtype(s *Symbol) *vm.Type { if s.Type != nil { diff --git a/vm/op_string.go b/vm/op_string.go index 5542c6e..f53ce5e 100644 --- a/vm/op_string.go +++ b/vm/op_string.go @@ -15,48 +15,48 @@ func _() { _ = x[Fassign-4] _ = x[Vassign-5] _ = x[Call-6] - _ = x[Calli-7] - _ = x[CallX-8] - _ = x[Deref-9] - _ = x[Dup-10] - _ = x[Fdup-11] - _ = x[Fnew-12] - _ = x[FnewE-13] - _ = x[Equal-14] - _ = x[EqualSet-15] - _ = x[Exit-16] - _ = x[Field-17] - _ = x[FieldE-18] - _ = x[FieldSet-19] - _ = x[FieldFset-20] - _ = x[Greater-21] - _ = x[Grow-22] - _ = x[Index-23] - _ = x[IndexSet-24] - _ = x[MapIndex-25] - _ = x[MapSet-26] - _ = x[Jump-27] - _ = x[JumpTrue-28] - _ = x[JumpFalse-29] - _ = x[JumpSetTrue-30] - _ = x[JumpSetFalse-31] - _ = x[Lower-32] - _ = x[Loweri-33] - _ = x[Mul-34] - _ = x[New-35] - _ = x[Negate-36] - _ = x[Not-37] - _ = x[Pop-38] - _ = x[Push-39] - _ = x[Return-40] - _ = x[Sub-41] - _ = x[Subi-42] + _ = x[CallX-7] + _ = x[Deref-8] + _ = x[Dup-9] + _ = x[Fdup-10] + _ = x[Fnew-11] + _ = x[FnewE-12] + _ = x[Equal-13] + _ = x[EqualSet-14] + _ = x[Exit-15] + _ = x[Field-16] + _ = x[FieldE-17] + _ = x[FieldSet-18] + _ = x[FieldFset-19] + _ = x[Greater-20] + _ = x[Grow-21] + _ = x[Index-22] + _ = x[IndexSet-23] + _ = x[Jump-24] + _ = x[JumpTrue-25] + _ = x[JumpFalse-26] + _ = x[JumpSetTrue-27] + _ = x[JumpSetFalse-28] + _ = x[Len-29] + _ = x[Lower-30] + _ = x[MapIndex-31] + _ = x[MapSet-32] + _ = x[Mul-33] + _ = x[New-34] + _ = x[Negate-35] + _ = x[Not-36] + _ = x[Pop-37] + _ = x[Push-38] + _ = x[Return-39] + _ = x[Slice-40] + _ = x[Slice3-41] + _ = x[Sub-42] _ = x[Swap-43] } -const _Op_name = "NopAddAddrAssignFassignVassignCallCalliCallXDerefDupFdupFnewFnewEEqualEqualSetExitFieldFieldEFieldSetFieldFsetGreaterGrowIndexIndexSetMapIndexMapSetJumpJumpTrueJumpFalseJumpSetTrueJumpSetFalseLowerLoweriMulNewNegateNotPopPushReturnSubSubiSwap" +const _Op_name = "NopAddAddrAssignFassignVassignCallCallXDerefDupFdupFnewFnewEEqualEqualSetExitFieldFieldEFieldSetFieldFsetGreaterGrowIndexIndexSetJumpJumpTrueJumpFalseJumpSetTrueJumpSetFalseLenLowerMapIndexMapSetMulNewNegateNotPopPushReturnSliceSlice3SubSwap" -var _Op_index = [...]uint8{0, 3, 6, 10, 16, 23, 30, 34, 39, 44, 49, 52, 56, 60, 65, 70, 78, 82, 87, 93, 101, 110, 117, 121, 126, 134, 142, 148, 152, 160, 169, 180, 192, 197, 203, 206, 209, 215, 218, 221, 225, 231, 234, 238, 242} +var _Op_index = [...]uint8{0, 3, 6, 10, 16, 23, 30, 34, 39, 44, 47, 51, 55, 60, 65, 73, 77, 82, 88, 96, 105, 112, 116, 121, 129, 133, 141, 150, 161, 173, 176, 181, 189, 195, 198, 201, 207, 210, 213, 217, 223, 228, 234, 237, 241} func (i Op) String() string { idx := int(i) - 0 @@ -26,7 +26,6 @@ const ( Fassign // val -- ; mem[$1] = val Vassign // dest val -- ; dest.Set(val) Call // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...) - Calli // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...) CallX // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = mem[f](a1, ...) Deref // x -- *x ; Dup // addr -- value ; value = mem[addr] @@ -44,15 +43,15 @@ const ( Grow // -- ; sp += $1 Index // a i -- a[i] ; IndexSet // a i v -- a; a[i] = v - MapIndex // a i -- a[i] - MapSet // a i v -- a; a[i] = v Jump // -- ; ip += $1 JumpTrue // cond -- ; if cond { ip += $1 } JumpFalse // cond -- ; if cond { ip += $1 } JumpSetTrue // JumpSetFalse // + Len // -- x; x = mem[sp-$1] Lower // n1 n2 -- cond ; cond = n1 < n2 - Loweri // n1 -- cond ; cond = n1 < $1 + MapIndex // a i -- a[i] + MapSet // a i v -- a; a[i] = v Mul // n1 n2 -- prod ; prod = n1*n2 New // -- x; mem[fp+$1] = new mem[$2] Negate // -- ; - mem[fp] @@ -60,8 +59,9 @@ const ( Pop // v -- Push // -- v Return // [r1 .. ri] -- ; exit frame: sp = fp, fp = pop + Slice // a l h -- a; a = a [l:h] + Slice3 // a l h m -- a; a = a[l:h:m] Sub // n1 n2 -- diff ; diff = n1 - n2 - Subi // n1 -- diff ; diff = n1 - $1 Swap // -- ) @@ -126,19 +126,11 @@ func (m *Machine) Run() (err error) { mem[fp+c.Arg[0]-1].Set(mem[sp-1].Value) mem = mem[:sp-1] case Call: - // nip := int(mem[sp-1].Int()) - // mem = append(mem[:sp-1], ValueOf(ip+1), ValueOf(fp)) nip := int(mem[sp-1-c.Arg[0]].Int()) mem = append(mem, ValueOf(ip+1), ValueOf(fp)) ip = nip - // fp = sp + 1 fp = sp + 2 continue - case Calli: - mem = append(mem, ValueOf(ip+1), ValueOf(fp)) - fp = sp + 2 - ip = c.Arg[0] - continue case CallX: // Should be made optional. in := make([]reflect.Value, c.Arg[0]) for i := range in { @@ -246,8 +238,8 @@ func (m *Machine) Run() (err error) { case Lower: mem[sp-2] = ValueOf(mem[sp-2].Int() < mem[sp-1].Int()) mem = mem[:sp-1] - case Loweri: - mem[sp-1] = ValueOf(mem[sp-1].Int() < int64(c.Arg[0])) + case Len: + mem = append(mem, ValueOf(mem[sp-1-c.Arg[0]].Len())) case Negate: mem[sp-1] = ValueOf(-mem[sp-1].Int()) case Not: @@ -265,11 +257,15 @@ func (m *Machine) Run() (err error) { fp = int(mem[fp-1].Int()) mem = append(mem[:ofp-c.Arg[0]-c.Arg[1]-2], mem[sp-c.Arg[0]:]...) continue + case Slice: + mem[sp-3].Value = mem[sp-3].Slice(int(mem[sp-2].Int()), int(mem[sp-1].Int())) + mem = mem[:sp-2] + case Slice3: + mem[sp-4].Value = mem[sp-4].Slice3(int(mem[sp-3].Int()), int(mem[sp-2].Int()), int(mem[sp-1].Int())) + mem = mem[:sp-3] case Sub: mem[sp-2] = ValueOf(int(mem[sp-2].Int() - mem[sp-1].Int())) mem = mem[:sp-1] - case Subi: - mem[sp-1] = ValueOf(int(mem[sp-1].Int()) - c.Arg[0]) case Swap: a, b := sp-c.Arg[0]-1, sp-c.Arg[1]-1 mem[a], mem[b] = mem[b], mem[a] diff --git a/vm/vm_test.go b/vm/vm_test.go index 6c1e4ff..94bba2c 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -154,90 +154,55 @@ var tests = []struct { {Op: Exit}, }, start: 2, end: 4, mem: "[6 <nil>]", -}, /* - { // #12 -- Defining and calling a function in VM. - code: []Instruction{ - {Op: Jump, Arg: []int{3}}, // 0 - {Op: Push, Arg: []int{3}}, // 1 - {Op: Return, Arg: []int{1, 1}}, // 2 - {Op: Push, Arg: []int{1}}, // 3 - {Op: Calli, Arg: []int{1}}, // 4 - {Op: Exit}, // 5 - }, - start: 0, end: 1, mem: "[3]", - }, - */{ // #13 -- Defining and calling a function in VM. - code: []Instruction{ - {Op: Jump, Arg: []int{3}}, // 0 - {Op: Push, Arg: []int{3}}, // 1 - {Op: Return, Arg: []int{1, 1}}, // 2 - {Op: Push, Arg: []int{1}}, // 3 - {Op: Push, Arg: []int{1}}, // 4 - {Op: Call, Arg: []int{0}}, // 5 - {Op: Exit}, // 6 - }, - start: 0, end: 1, mem: "[3]", - }, { // #14 -- Defining and calling a function in VM. - code: []Instruction{ - {Op: Jump, Arg: []int{5}}, // 0 - {Op: Push, Arg: []int{3}}, // 1 - {Op: Fassign, Arg: []int{-2}}, // 2 - {Op: Fdup, Arg: []int{-2}}, // 3 - {Op: Return, Arg: []int{1, 1}}, // 4 - {Op: Push, Arg: []int{1}}, // 5 - {Op: Push, Arg: []int{1}}, // 6 - {Op: Call, Arg: []int{0}}, // 7 - {Op: Exit}, // 8 - }, - start: 1, end: 2, mem: "[3]", - }, { // #15 -- Fibonacci numbers, hand written. Showcase recursivity. - code: []Instruction{ - {Op: Jump, Arg: []int{19}}, // 0 - {Op: Fdup, Arg: []int{-2}}, // 1 [2 i] - {Op: Push, Arg: []int{2}}, // 2 [2] - {Op: Lower}, // 3 [true/false] - {Op: JumpTrue, Arg: []int{13}}, // 4 [], goto 17 - {Op: Push, Arg: []int{1}}, // 5 - {Op: Fdup, Arg: []int{-2}}, // 6 [i] - {Op: Push, Arg: []int{2}}, // 7 [i 2] - {Op: Sub}, // 8 [(i-2)] - {Op: Call, Arg: []int{1}}, // 9 [fib(i-2)] - {Op: Push, Arg: []int{1}}, // 10 - {Op: Fdup, Arg: []int{-2}}, // 11 [fib(i-2) i] - {Op: Push, Arg: []int{1}}, // 12 [(i-2) i 1] - {Op: Sub}, // 13 [(i-2) (i-1)] - {Op: Call, Arg: []int{1}}, // 14 [fib(i-2) fib(i-1)] - {Op: Add}, // 15 [fib(i-2)+fib(i-1)] - {Op: Return, Arg: []int{1, 1}}, // 16 return i - {Op: Fdup, Arg: []int{-2}}, // 17 [i] - {Op: Return, Arg: []int{1, 1}}, // 18 return i - {Op: Push, Arg: []int{1}}, // 19 - {Op: Push, Arg: []int{6}}, // 20 [1] - {Op: Call, Arg: []int{1}}, // 21 [fib(*1)] - {Op: Exit}, // 22 - }, - start: 0, end: 1, mem: "[8]", - /* - }, { // #16 -- Fibonacci with some immediate instructions. - code: []Instruction{ - {Op: Jump, Arg: []int{14}}, // 0 - {Op: Fdup, Arg: []int{-2}}, // 1 [i] - {Op: Loweri, Arg: []int{2}}, // 2 [true/false] - {Op: JumpTrue, Arg: []int{9}}, // 3 [], goto 12 - {Op: Fdup, Arg: []int{-2}}, // 4 [i] - {Op: Subi, Arg: []int{2}}, // 5 [(i-2)] - {Op: Calli, Arg: []int{1}}, // 6 [fib(i-2)] - {Op: Fdup, Arg: []int{-2}}, // 7 [fib(i-2) i] - {Op: Subi, Arg: []int{1}}, // 8 [(i-2) (i-1)] - {Op: Calli, Arg: []int{1}}, // 9 [fib(i-2) fib(i-1)], call 1 - {Op: Add}, // 10 [fib(i-2)+fib(i-1)] - {Op: Return, Arg: []int{1, 1}}, // 11 return i - {Op: Fdup, Arg: []int{-2}}, // 12 [i] - {Op: Return, Arg: []int{1, 1}}, // 13 return i - {Op: Push, Arg: []int{6}}, // 14 [1] - {Op: Calli, Arg: []int{1}}, // 15 [fib(*1)], call 1 - {Op: Exit}, // 16 - }, - start: 0, end: 1, mem: "[8]", - */ - }} +}, { // #12 -- Defining and calling a function in VM. + code: []Instruction{ + {Op: Jump, Arg: []int{3}}, // 0 + {Op: Push, Arg: []int{3}}, // 1 + {Op: Return, Arg: []int{1, 1}}, // 2 + {Op: Push, Arg: []int{1}}, // 3 + {Op: Push, Arg: []int{1}}, // 4 + {Op: Call, Arg: []int{0}}, // 5 + {Op: Exit}, // 6 + }, + start: 0, end: 1, mem: "[3]", +}, { // #13 -- Defining and calling a function in VM. + code: []Instruction{ + {Op: Jump, Arg: []int{5}}, // 0 + {Op: Push, Arg: []int{3}}, // 1 + {Op: Fassign, Arg: []int{-2}}, // 2 + {Op: Fdup, Arg: []int{-2}}, // 3 + {Op: Return, Arg: []int{1, 1}}, // 4 + {Op: Push, Arg: []int{1}}, // 5 + {Op: Push, Arg: []int{1}}, // 6 + {Op: Call, Arg: []int{0}}, // 7 + {Op: Exit}, // 8 + }, + start: 1, end: 2, mem: "[3]", +}, { // #14 -- Fibonacci numbers, hand written. Showcase recursivity. + code: []Instruction{ + {Op: Jump, Arg: []int{19}}, // 0 + {Op: Fdup, Arg: []int{-2}}, // 1 [2 i] + {Op: Push, Arg: []int{2}}, // 2 [2] + {Op: Lower}, // 3 [true/false] + {Op: JumpTrue, Arg: []int{13}}, // 4 [], goto 17 + {Op: Push, Arg: []int{1}}, // 5 + {Op: Fdup, Arg: []int{-2}}, // 6 [i] + {Op: Push, Arg: []int{2}}, // 7 [i 2] + {Op: Sub}, // 8 [(i-2)] + {Op: Call, Arg: []int{1}}, // 9 [fib(i-2)] + {Op: Push, Arg: []int{1}}, // 10 + {Op: Fdup, Arg: []int{-2}}, // 11 [fib(i-2) i] + {Op: Push, Arg: []int{1}}, // 12 [(i-2) i 1] + {Op: Sub}, // 13 [(i-2) (i-1)] + {Op: Call, Arg: []int{1}}, // 14 [fib(i-2) fib(i-1)] + {Op: Add}, // 15 [fib(i-2)+fib(i-1)] + {Op: Return, Arg: []int{1, 1}}, // 16 return i + {Op: Fdup, Arg: []int{-2}}, // 17 [i] + {Op: Return, Arg: []int{1, 1}}, // 18 return i + {Op: Push, Arg: []int{1}}, // 19 + {Op: Push, Arg: []int{6}}, // 20 [1] + {Op: Call, Arg: []int{1}}, // 21 [fib(*1)] + {Op: Exit}, // 22 + }, + start: 0, end: 1, mem: "[8]", +}} |
