Skip to content

Commit

Permalink
Bitwise shift left and right
Browse files Browse the repository at this point in the history
  • Loading branch information
BenTalagan authored and rubysolo committed Oct 24, 2022
1 parent 7de79b3 commit 7d99a4d
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ application, AST caching will consume more memory with each new formula.
BUILT-IN OPERATORS AND FUNCTIONS
---------------------------------

Math: `+`, `-`, `*`, `/`, `%`, `^`, `|`, `&`
Math: `+`, `-`, `*`, `/`, `%`, `^`, `|`, `&`, `<<`, `>>`

Also, all functions from Ruby's Math module, including `SIN`, `COS`, `TAN`, etc.

Expand Down
20 changes: 20 additions & 0 deletions lib/dentaku/ast/bitwise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,25 @@ def operator
:&
end
end

class BitwiseShiftLeft < Operation
def value(context = {})
left.value(context) << right.value(context)
end

def operator
:<<
end
end

class BitwiseShiftRight < Operation
def value(context = {})
left.value(context) >> right.value(context)
end

def operator
:>>
end
end
end
end
3 changes: 3 additions & 0 deletions lib/dentaku/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ class Parser
pow: AST::Exponentiation,
negate: AST::Negation,
mod: AST::Modulo,

bitor: AST::BitwiseOr,
bitand: AST::BitwiseAnd,
bitshiftleft: AST::BitwiseShiftLeft,
bitshiftright: AST::BitwiseShiftRight,

lt: AST::LessThan,
gt: AST::GreaterThan,
Expand Down
4 changes: 2 additions & 2 deletions lib/dentaku/token_scanner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ def negate

def operator
names = {
pow: '^', add: '+', subtract: '-', multiply: '*', divide: '/', mod: '%', bitor: '|', bitand: '&'
pow: '^', add: '+', subtract: '-', multiply: '*', divide: '/', mod: '%', bitor: '|', bitand: '&', bitshiftleft: '<<', bitshiftright: '>>'
}.invert
new(:operator, '\^|\+|-|\*|\/|%|\||&', lambda { |raw| names[raw] })
new(:operator, '\^|\+|-|\*|\/|%|\||&|<<|>>', lambda { |raw| names[raw] })
end

def grouping
Expand Down
2 changes: 2 additions & 0 deletions spec/calculator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
expect(calculator.evaluate("2 | 3 * 9")).to eq (27)
expect(calculator.evaluate("2 & 3 * 9")).to eq (2)
expect(calculator.evaluate("5%")).to eq (0.05)
expect(calculator.evaluate('1 << 3')).to eq (8)
expect(calculator.evaluate('0xFF >> 14')).to eq (3)
end

describe 'evaluate' do
Expand Down
12 changes: 12 additions & 0 deletions spec/tokenizer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@
expect(tokens.map(&:value)).to eq([2, :bitand, 3])
end

it 'tokenizes bitwise SHIFT LEFT' do
tokens = tokenizer.tokenize('2 << 3')
expect(tokens.map(&:category)).to eq([:numeric, :operator, :numeric])
expect(tokens.map(&:value)).to eq([2, :bitshiftleft, 3])
end

it 'tokenizes bitwise SHIFT RIGHT' do
tokens = tokenizer.tokenize('2 >> 3')
expect(tokens.map(&:category)).to eq([:numeric, :operator, :numeric])
expect(tokens.map(&:value)).to eq([2, :bitshiftright, 3])
end

it 'ignores whitespace' do
tokens = tokenizer.tokenize('1 / 1 ')
expect(tokens.map(&:category)).to eq([:numeric, :operator, :numeric])
Expand Down
2 changes: 1 addition & 1 deletion spec/visitor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def generic_subclasses
visit_nodes('1 < 2 and 3 <= 4 or 5 > 6 AND 7 >= 8 OR 9 != 10 and true')
visit_nodes('IF(a[0] = NULL, "five", \'seven\')')
visit_nodes('case (a % 5) when 0 then a else b end')
visit_nodes('0xCAFE & 0xDECAF | 0xBEEF')
visit_nodes('0xCAFE & (0xDECAF << 3) | (0xBEEF >> 5)')
visit_nodes('2017-12-24 23:59:59')
visit_nodes('ALL({1, 2, 3}, "val", val % 2 == 0)')
visit_nodes('ANY(vals, val, val > 1)')
Expand Down

0 comments on commit 7d99a4d

Please sign in to comment.