prefix expressions

This commit is contained in:
Chuck Smith
2024-02-07 10:51:09 -05:00
parent dcc869a6e2
commit cff4375649
5 changed files with 84 additions and 0 deletions

View File

@@ -22,6 +22,8 @@ const (
OpEqual
OpNotEqual
OpGreaterThan
OpMinus
OpBang
)
type Definition struct {
@@ -41,6 +43,8 @@ var definitions = map[Opcode]*Definition{
OpEqual: {"OpEqual", []int{}},
OpNotEqual: {"OpNotEqual", []int{}},
OpGreaterThan: {"OpGreaterThan", []int{}},
OpMinus: {"OpMinus", []int{}},
OpBang: {"OpBang", []int{}},
}
func Lookup(op byte) (*Definition, error) {

View File

@@ -91,6 +91,21 @@ func (c *Compiler) Compile(node ast.Node) error {
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

View File

@@ -68,6 +68,15 @@ func TestIntegerArithmetic(t *testing.T) {
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)
@@ -151,6 +160,15 @@ func TestBooleanExpressions(t *testing.T) {
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)

View File

@@ -74,6 +74,19 @@ func (vm *VM) Run() error {
if err != nil {
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 {
if input {
return True

View File

@@ -119,6 +119,10 @@ func TestIntegerArithmetic(t *testing.T) {
{"(1 < 2) == false", false},
{"(1 > 2) == true", false},
{"(1 > 2) == false", true},
{"-5", -5},
{"-10", -10},
{"-50 + 100 + -50", 0},
{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
}
runVmTests(t, tests)
@@ -128,6 +132,12 @@ func TestBooleanExpressions(t *testing.T) {
tests := []vmTestCase{
{"true", true},
{"false", false},
{"!true", false},
{"!false", true},
{"!5", false},
{"!!true", true},
{"!!false", false},
{"!!5", true},
}
runVmTests(t, tests)