Skip to content

Commit d7653f2

Browse files
committed
compile: Implement if expression and JUMP_FORWARD
1 parent 6fa5265 commit d7653f2

File tree

3 files changed

+108
-4
lines changed

3 files changed

+108
-4
lines changed

compile/compile.go

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func (c *compiler) Jump(Op byte, Dest *Label) {
173173
case vm.JUMP_IF_FALSE_OR_POP, vm.JUMP_IF_TRUE_OR_POP, vm.JUMP_ABSOLUTE, vm.POP_JUMP_IF_FALSE, vm.POP_JUMP_IF_TRUE: // Absolute
174174
c.OpCodes.Add(&JumpAbs{OpArg: OpArg{Op: Op}, Dest: Dest})
175175
case vm.JUMP_FORWARD: // Relative
176-
panic("FIXME JUMP_FORWARD NOT implemented")
176+
c.OpCodes.Add(&JumpRel{OpArg: OpArg{Op: Op}, Dest: Dest})
177177
default:
178178
panic("Jump called with non jump instruction")
179179
}
@@ -368,7 +368,15 @@ func (c *compiler) compileExpr(expr ast.Expr) {
368368
// Test Expr
369369
// Body Expr
370370
// Orelse Expr
371-
panic("FIXME not implemented")
371+
elseBranch := new(Label)
372+
endifBranch := new(Label)
373+
c.compileExpr(node.Test)
374+
c.Jump(vm.POP_JUMP_IF_FALSE, elseBranch)
375+
c.compileExpr(node.Body)
376+
c.Jump(vm.JUMP_FORWARD, endifBranch)
377+
c.Label(elseBranch)
378+
c.compileExpr(node.Body)
379+
c.Label(endifBranch)
372380
case *ast.Dict:
373381
// Keys []Expr
374382
// Values []Expr
@@ -471,7 +479,8 @@ func (is Instructions) Pass(pass int) bool {
471479
addr := uint32(0)
472480
changed := false
473481
for _, i := range is {
474-
changed = changed || i.SetPos(addr)
482+
posChanged := i.SetPos(addr)
483+
changed = changed || posChanged
475484
if pass > 0 {
476485
// Only resolve addresses on 2nd pass
477486
if resolver, ok := i.(Resolver); ok {
@@ -595,4 +604,25 @@ func (o *JumpAbs) Resolve() {
595604
o.OpArg.Arg = o.Dest.Pos()
596605
}
597606

598-
// FIXME Jump Relative
607+
// A relative JUMP with destination label
608+
type JumpRel struct {
609+
pos
610+
OpArg
611+
Dest *Label
612+
}
613+
614+
// Set the Arg from the Jump Label
615+
func (o *JumpRel) Resolve() {
616+
currentSize := o.Size()
617+
currentPos := o.Pos() + currentSize
618+
if o.Dest.Pos() < currentPos {
619+
panic("Attempt use JUMP_FORWARD to jump backwards")
620+
}
621+
o.OpArg.Arg = o.Dest.Pos() - currentPos
622+
if o.Size() != currentSize {
623+
// There is an awkward moment where jump forwards is
624+
// between 0x1000 and 0x1002 where the Arg oscillates
625+
// between 2 and 4 bytes
626+
panic("FIXME JUMP_FOWARDS size changed")
627+
}
628+
}

compile/compile_data_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,4 +403,72 @@ var compileTestData = []struct {
403403
Firstlineno: 1,
404404
Lnotab: "",
405405
}, " 1 0 LOAD_CONST 0 (1)\n 3 JUMP_IF_TRUE_OR_POP 21\n 6 LOAD_CONST 1 (2)\n 9 JUMP_IF_TRUE_OR_POP 21\n 12 LOAD_CONST 2 (3)\n 15 JUMP_IF_TRUE_OR_POP 21\n 18 LOAD_CONST 3 (4)\n >> 21 RETURN_VALUE\n"},
406+
{"\"1\"+\"2\"*\"3\"", "eval", py.Code{
407+
Argcount: 0,
408+
Kwonlyargcount: 0,
409+
Nlocals: 0,
410+
Stacksize: 3,
411+
Flags: 64,
412+
Code: "\x64\x00\x00\x64\x01\x00\x64\x02\x00\x14\x17\x53",
413+
Consts: []py.Object{py.String("1"), py.String("2"), py.String("3")},
414+
Names: []string{},
415+
Varnames: []string{},
416+
Freevars: []string{},
417+
Cellvars: []string{},
418+
Filename: "<string>",
419+
Name: "<module>",
420+
Firstlineno: 1,
421+
Lnotab: "",
422+
}, " 1 0 LOAD_CONST 0 ('1')\n 3 LOAD_CONST 1 ('2')\n 6 LOAD_CONST 2 ('3')\n 9 BINARY_MULTIPLY\n 10 BINARY_ADD\n 11 RETURN_VALUE\n"},
423+
{"\"1\"+(\"2\"*\"3\")", "eval", py.Code{
424+
Argcount: 0,
425+
Kwonlyargcount: 0,
426+
Nlocals: 0,
427+
Stacksize: 3,
428+
Flags: 64,
429+
Code: "\x64\x00\x00\x64\x01\x00\x64\x02\x00\x14\x17\x53",
430+
Consts: []py.Object{py.String("1"), py.String("2"), py.String("3")},
431+
Names: []string{},
432+
Varnames: []string{},
433+
Freevars: []string{},
434+
Cellvars: []string{},
435+
Filename: "<string>",
436+
Name: "<module>",
437+
Firstlineno: 1,
438+
Lnotab: "",
439+
}, " 1 0 LOAD_CONST 0 ('1')\n 3 LOAD_CONST 1 ('2')\n 6 LOAD_CONST 2 ('3')\n 9 BINARY_MULTIPLY\n 10 BINARY_ADD\n 11 RETURN_VALUE\n"},
440+
{"(1+\"2\")*\"3\"", "eval", py.Code{
441+
Argcount: 0,
442+
Kwonlyargcount: 0,
443+
Nlocals: 0,
444+
Stacksize: 2,
445+
Flags: 64,
446+
Code: "\x64\x00\x00\x64\x01\x00\x17\x64\x02\x00\x14\x53",
447+
Consts: []py.Object{py.Int(1), py.String("2"), py.String("3")},
448+
Names: []string{},
449+
Varnames: []string{},
450+
Freevars: []string{},
451+
Cellvars: []string{},
452+
Filename: "<string>",
453+
Name: "<module>",
454+
Firstlineno: 1,
455+
Lnotab: "",
456+
}, " 1 0 LOAD_CONST 0 (1)\n 3 LOAD_CONST 1 ('2')\n 6 BINARY_ADD\n 7 LOAD_CONST 2 ('3')\n 10 BINARY_MULTIPLY\n 11 RETURN_VALUE\n"},
457+
{"(\"true\" if 1+\"2\" else \"false\")+\"a\"", "eval", py.Code{
458+
Argcount: 0,
459+
Kwonlyargcount: 0,
460+
Nlocals: 0,
461+
Stacksize: 2,
462+
Flags: 64,
463+
Code: "\x64\x00\x00\x64\x01\x00\x17\x72\x10\x00\x64\x02\x00\x6e\x03\x00\x64\x03\x00\x64\x04\x00\x17\x53",
464+
Consts: []py.Object{py.Int(1), py.String("2"), py.String("true"), py.String("false"), py.String("a")},
465+
Names: []string{},
466+
Varnames: []string{},
467+
Freevars: []string{},
468+
Cellvars: []string{},
469+
Filename: "<string>",
470+
Name: "<module>",
471+
Firstlineno: 1,
472+
Lnotab: "",
473+
}, " 1 0 LOAD_CONST 0 (1)\n 3 LOAD_CONST 1 ('2')\n 6 BINARY_ADD\n 7 POP_JUMP_IF_FALSE 16\n 10 LOAD_CONST 2 ('true')\n 13 JUMP_FORWARD 3 (to 19)\n >> 16 LOAD_CONST 3 ('false')\n >> 19 LOAD_CONST 4 ('a')\n 22 BINARY_ADD\n 23 RETURN_VALUE\n"},
406474
}

compile/make_compile_test.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@
3535
('''1 and 2''', "eval"),
3636
('''1 or 2''', "eval"),
3737
('''1 or 2 or 3 or 4''', "eval"),
38+
# With brackets
39+
('''"1"+"2"*"3"''', "eval"),
40+
('''"1"+("2"*"3")''', "eval"),
41+
('''(1+"2")*"3"''', "eval"),
42+
# If expression
43+
('''("true" if 1+"2" else "false")+"a"''', "eval"),
3844

3945
]
4046

0 commit comments

Comments
 (0)