Bitshift
Some checks failed
Test / build (push) Waiting to run
Build / build (push) Has been cancelled

This commit is contained in:
Chuck Smith
2024-03-24 16:22:11 -04:00
parent a08fc1520c
commit 3c66b980e7
11 changed files with 76 additions and 12 deletions

View File

@@ -33,6 +33,8 @@ const (
OpBitwiseXOR OpBitwiseXOR
OpBitwiseAND OpBitwiseAND
OpBitwiseNOT OpBitwiseNOT
OpLeftShift
OpRightShift
OpTrue OpTrue
OpFalse OpFalse
OpEqual OpEqual
@@ -84,6 +86,8 @@ var definitions = map[Opcode]*Definition{
OpBitwiseXOR: {"OpBitwiseXOR", []int{}}, OpBitwiseXOR: {"OpBitwiseXOR", []int{}},
OpBitwiseAND: {"OpBitwiseAND", []int{}}, OpBitwiseAND: {"OpBitwiseAND", []int{}},
OpBitwiseNOT: {"OpBitwiseNOT", []int{}}, OpBitwiseNOT: {"OpBitwiseNOT", []int{}},
OpLeftShift: {"OpLeftShift", []int{}},
OpRightShift: {"OpRightShift", []int{}},
OpTrue: {"OpTrue", []int{}}, OpTrue: {"OpTrue", []int{}},
OpFalse: {"OpFalse", []int{}}, OpFalse: {"OpFalse", []int{}},
OpEqual: {"OpEqual", []int{}}, OpEqual: {"OpEqual", []int{}},

View File

@@ -148,6 +148,10 @@ func (c *Compiler) Compile(node ast.Node) error {
c.emit(code.OpBitwiseXOR) c.emit(code.OpBitwiseXOR)
case "&": case "&":
c.emit(code.OpBitwiseAND) c.emit(code.OpBitwiseAND)
case "<<":
c.emit(code.OpLeftShift)
case ">>":
c.emit(code.OpRightShift)
case "||": case "||":
c.emit(code.OpOr) c.emit(code.OpOr)
case "&&": case "&&":

View File

@@ -87,6 +87,26 @@ func TestIntegerArithmetic(t *testing.T) {
code.Make(code.OpPop), code.Make(code.OpPop),
}, },
}, },
{
input: "1 << 2",
expectedConstants: []interface{}{1, 2},
expectedInstructions: []code.Instructions{
code.Make(code.OpConstant, 0),
code.Make(code.OpConstant, 1),
code.Make(code.OpLeftShift),
code.Make(code.OpPop),
},
},
{
input: "4 >> 2",
expectedConstants: []interface{}{4, 2},
expectedInstructions: []code.Instructions{
code.Make(code.OpConstant, 0),
code.Make(code.OpConstant, 1),
code.Make(code.OpRightShift),
code.Make(code.OpPop),
},
},
{ {
input: "-1", input: "-1",
expectedConstants: []interface{}{1}, expectedConstants: []interface{}{1},

View File

@@ -434,6 +434,10 @@ func evalIntegerInfixExpression(operator string, left, right object.Object) obje
return &object.Integer{Value: leftVal ^ rightVal} return &object.Integer{Value: leftVal ^ rightVal}
case "&": case "&":
return &object.Integer{Value: leftVal & rightVal} return &object.Integer{Value: leftVal & rightVal}
case "<<":
return &object.Integer{Value: leftVal << uint64(rightVal)}
case ">>":
return &object.Integer{Value: leftVal >> uint64(rightVal)}
case "<": case "<":
return nativeBoolToBooleanObject(leftVal < rightVal) return nativeBoolToBooleanObject(leftVal < rightVal)
case "<=": case "<=":

View File

@@ -38,6 +38,8 @@ func TestEvalExpressions(t *testing.T) {
{"3 & 6", 2}, {"3 & 6", 2},
{`" " * 4`, " "}, {`" " * 4`, " "},
{`4 * " "`, " "}, {`4 * " "`, " "},
{"1 << 2", 4},
{"4 >> 2", 1},
} }
for _, tt := range tests { for _, tt := range tests {

View File

@@ -116,6 +116,11 @@ func (l *Lexer) NextToken() token.Token {
l.readChar() l.readChar()
tok = newToken(token.LTE, l.ch) tok = newToken(token.LTE, l.ch)
tok.Literal = "<=" tok.Literal = "<="
} else if l.peekChar() == '<' {
ch := l.ch
l.readChar()
literal := string(ch) + string(l.ch)
tok = token.Token{Type: token.LEFT_SHIFT, Literal: literal}
} else { } else {
tok = newToken(token.LT, l.ch) tok = newToken(token.LT, l.ch)
} }
@@ -124,6 +129,11 @@ func (l *Lexer) NextToken() token.Token {
l.readChar() l.readChar()
tok = newToken(token.GTE, l.ch) tok = newToken(token.GTE, l.ch)
tok.Literal = ">=" tok.Literal = ">="
} else if l.peekChar() == '>' {
ch := l.ch
l.readChar()
literal := string(ch) + string(l.ch)
tok = token.Token{Type: token.RIGHT_SHIFT, Literal: literal}
} else { } else {
tok = newToken(token.GT, l.ch) tok = newToken(token.GT, l.ch)
} }

View File

@@ -35,6 +35,7 @@ func TestNextToken(t *testing.T) {
d.foo d.foo
&|^~ &|^~
!&&|| !&&||
<<>>
` `
tests := []struct { tests := []struct {
@@ -146,6 +147,8 @@ func TestNextToken(t *testing.T) {
{token.NOT, "!"}, {token.NOT, "!"},
{token.AND, "&&"}, {token.AND, "&&"},
{token.OR, "||"}, {token.OR, "||"},
{token.LEFT_SHIFT, "<<"},
{token.RIGHT_SHIFT, ">>"},
{token.EOF, ""}, {token.EOF, ""},
} }

View File

@@ -14,17 +14,18 @@ const (
OR OR
AND AND
NOT NOT
ASSIGN // := or = ASSIGN // := or =
EQUALS // == EQUALS // ==
LESSGREATER // > or < LESSGREATER // > or <
BITWISE_OR // | BITWISE_OR // |
BITWISE_XOR // ^ BITWISE_XOR // ^
BITWISE_AND // & BITWISE_AND // &
SUM // + or - BITWISE_SHIFT // << or >>
PRODUCT // * or / or % SUM // + or -
PREFIX // -X or !X PRODUCT // * or / or %
CALL // myFunction(X) PREFIX // -X or !X
INDEX // array[index] CALL // myFunction(X)
INDEX // array[index]
) )
var precedences = map[token.TokenType]int{ var precedences = map[token.TokenType]int{
@@ -42,6 +43,8 @@ var precedences = map[token.TokenType]int{
token.BITWISE_OR: BITWISE_OR, token.BITWISE_OR: BITWISE_OR,
token.BITWISE_XOR: BITWISE_XOR, token.BITWISE_XOR: BITWISE_XOR,
token.BITWISE_AND: BITWISE_AND, token.BITWISE_AND: BITWISE_AND,
token.LEFT_SHIFT: BITWISE_SHIFT,
token.RIGHT_SHIFT: BITWISE_SHIFT,
token.PLUS: SUM, token.PLUS: SUM,
token.MINUS: SUM, token.MINUS: SUM,
token.DIVIDE: PRODUCT, token.DIVIDE: PRODUCT,
@@ -112,6 +115,9 @@ func New(l *lexer.Lexer) *Parser {
p.registerInfix(token.BITWISE_XOR, p.parseInfixExpression) p.registerInfix(token.BITWISE_XOR, p.parseInfixExpression)
p.registerInfix(token.BITWISE_AND, p.parseInfixExpression) p.registerInfix(token.BITWISE_AND, p.parseInfixExpression)
p.registerInfix(token.LEFT_SHIFT, p.parseInfixExpression)
p.registerInfix(token.RIGHT_SHIFT, p.parseInfixExpression)
p.registerPrefix(token.NOT, p.parsePrefixExpression) p.registerPrefix(token.NOT, p.parsePrefixExpression)
p.registerInfix(token.OR, p.parseInfixExpression) p.registerInfix(token.OR, p.parseInfixExpression)
p.registerInfix(token.AND, p.parseInfixExpression) p.registerInfix(token.AND, p.parseInfixExpression)

View File

@@ -38,6 +38,10 @@ const (
BITWISE_XOR = "^" BITWISE_XOR = "^"
// BITWISE_NOT NOT // BITWISE_NOT NOT
BITWISE_NOT = "~" BITWISE_NOT = "~"
// LeftShift
LEFT_SHIFT = "<<"
// RightShift
RIGHT_SHIFT = ">>"
// //
// Comparision operators // Comparision operators

View File

@@ -114,7 +114,8 @@ func (vm *VM) Run() error {
} }
case code.OpAdd, code.OpSub, code.OpMul, code.OpDiv, code.OpMod, code.OpOr, case code.OpAdd, code.OpSub, code.OpMul, code.OpDiv, code.OpMod, code.OpOr,
code.OpAnd, code.OpBitwiseOR, code.OpBitwiseXOR, code.OpBitwiseAND: code.OpAnd, code.OpBitwiseOR, code.OpBitwiseXOR, code.OpBitwiseAND,
code.OpLeftShift, code.OpRightShift:
err := vm.executeBinaryOperation(op) err := vm.executeBinaryOperation(op)
if err != nil { if err != nil {
return err return err
@@ -631,6 +632,10 @@ func (vm *VM) executeBinaryIntegerOperation(op code.Opcode, left, right object.O
result = leftValue ^ rightValue result = leftValue ^ rightValue
case code.OpBitwiseAND: case code.OpBitwiseAND:
result = leftValue & rightValue result = leftValue & rightValue
case code.OpLeftShift:
result = leftValue << uint64(rightValue)
case code.OpRightShift:
result = leftValue >> uint64(rightValue)
default: default:
return fmt.Errorf("unknown integer operator: %d", op) return fmt.Errorf("unknown integer operator: %d", op)

View File

@@ -230,6 +230,8 @@ func TestIntegerArithmetic(t *testing.T) {
{"1 | 2", 3}, {"1 | 2", 3},
{"2 ^ 4", 6}, {"2 ^ 4", 6},
{"3 & 6", 2}, {"3 & 6", 2},
{"1 << 2", 4},
{"4 >> 2", 1},
} }
runVmTests(t, tests) runVmTests(t, tests)