prefix expressions
This commit is contained in:
@@ -22,6 +22,8 @@ const (
|
|||||||
OpEqual
|
OpEqual
|
||||||
OpNotEqual
|
OpNotEqual
|
||||||
OpGreaterThan
|
OpGreaterThan
|
||||||
|
OpMinus
|
||||||
|
OpBang
|
||||||
)
|
)
|
||||||
|
|
||||||
type Definition struct {
|
type Definition struct {
|
||||||
@@ -41,6 +43,8 @@ var definitions = map[Opcode]*Definition{
|
|||||||
OpEqual: {"OpEqual", []int{}},
|
OpEqual: {"OpEqual", []int{}},
|
||||||
OpNotEqual: {"OpNotEqual", []int{}},
|
OpNotEqual: {"OpNotEqual", []int{}},
|
||||||
OpGreaterThan: {"OpGreaterThan", []int{}},
|
OpGreaterThan: {"OpGreaterThan", []int{}},
|
||||||
|
OpMinus: {"OpMinus", []int{}},
|
||||||
|
OpBang: {"OpBang", []int{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
func Lookup(op byte) (*Definition, error) {
|
func Lookup(op byte) (*Definition, error) {
|
||||||
|
|||||||
@@ -91,6 +91,21 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
c.emit(code.OpFalse)
|
c.emit(code.OpFalse)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case *ast.PrefixExpression:
|
||||||
|
err := c.Compile(node.Right)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch node.Operator {
|
||||||
|
case "!":
|
||||||
|
c.emit(code.OpBang)
|
||||||
|
case "-":
|
||||||
|
c.emit(code.OpMinus)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown operator %s", node.Operator)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -68,6 +68,15 @@ func TestIntegerArithmetic(t *testing.T) {
|
|||||||
code.Make(code.OpPop),
|
code.Make(code.OpPop),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: "-1",
|
||||||
|
expectedConstants: []interface{}{1},
|
||||||
|
expectedInstructions: []code.Instructions{
|
||||||
|
code.Make(code.OpConstant, 0),
|
||||||
|
code.Make(code.OpMinus),
|
||||||
|
code.Make(code.OpPop),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
runCompilerTests(t, tests)
|
runCompilerTests(t, tests)
|
||||||
@@ -151,6 +160,15 @@ func TestBooleanExpressions(t *testing.T) {
|
|||||||
code.Make(code.OpPop),
|
code.Make(code.OpPop),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: "!true",
|
||||||
|
expectedConstants: []interface{}{},
|
||||||
|
expectedInstructions: []code.Instructions{
|
||||||
|
code.Make(code.OpTrue),
|
||||||
|
code.Make(code.OpBang),
|
||||||
|
code.Make(code.OpPop),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
runCompilerTests(t, tests)
|
runCompilerTests(t, tests)
|
||||||
|
|||||||
37
vm/vm.go
37
vm/vm.go
@@ -74,6 +74,19 @@ func (vm *VM) Run() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case code.OpBang:
|
||||||
|
err := vm.executeBangOperator()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case code.OpMinus:
|
||||||
|
err := vm.executeMinusOperator()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +180,30 @@ func (vm *VM) executeIntegerComparison(op code.Opcode, left, right object.Object
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vm *VM) executeBangOperator() error {
|
||||||
|
operand := vm.pop()
|
||||||
|
|
||||||
|
switch operand {
|
||||||
|
case True:
|
||||||
|
return vm.push(False)
|
||||||
|
case False:
|
||||||
|
return vm.push(True)
|
||||||
|
default:
|
||||||
|
return vm.push(False)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vm *VM) executeMinusOperator() error {
|
||||||
|
operand := vm.pop()
|
||||||
|
|
||||||
|
if operand.Type() != object.INTEGER_OBJ {
|
||||||
|
return fmt.Errorf("unsupported type for negation: %s", operand.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
value := operand.(*object.Integer).Value
|
||||||
|
return vm.push(&object.Integer{Value: -value})
|
||||||
|
}
|
||||||
|
|
||||||
func nativeBoolToBooleanObject(input bool) *object.Boolean {
|
func nativeBoolToBooleanObject(input bool) *object.Boolean {
|
||||||
if input {
|
if input {
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -119,6 +119,10 @@ func TestIntegerArithmetic(t *testing.T) {
|
|||||||
{"(1 < 2) == false", false},
|
{"(1 < 2) == false", false},
|
||||||
{"(1 > 2) == true", false},
|
{"(1 > 2) == true", false},
|
||||||
{"(1 > 2) == false", true},
|
{"(1 > 2) == false", true},
|
||||||
|
{"-5", -5},
|
||||||
|
{"-10", -10},
|
||||||
|
{"-50 + 100 + -50", 0},
|
||||||
|
{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
|
||||||
}
|
}
|
||||||
|
|
||||||
runVmTests(t, tests)
|
runVmTests(t, tests)
|
||||||
@@ -128,6 +132,12 @@ func TestBooleanExpressions(t *testing.T) {
|
|||||||
tests := []vmTestCase{
|
tests := []vmTestCase{
|
||||||
{"true", true},
|
{"true", true},
|
||||||
{"false", false},
|
{"false", false},
|
||||||
|
{"!true", false},
|
||||||
|
{"!false", true},
|
||||||
|
{"!5", false},
|
||||||
|
{"!!true", true},
|
||||||
|
{"!!false", false},
|
||||||
|
{"!!5", true},
|
||||||
}
|
}
|
||||||
|
|
||||||
runVmTests(t, tests)
|
runVmTests(t, tests)
|
||||||
|
|||||||
Reference in New Issue
Block a user