omghax-einstein 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/Benchmarks.txt +48 -0
  2. data/History.txt +9 -0
  3. data/Manifest.txt +14 -21
  4. data/README.txt +1 -8
  5. data/Rakefile +26 -13
  6. data/einstein.gemspec +24 -0
  7. data/lib/einstein.rb +10 -41
  8. data/lib/einstein/evaluator.rb +102 -0
  9. data/lib/einstein/expression.rb +37 -0
  10. data/lib/einstein/parser.racc +41 -0
  11. data/lib/einstein/parser.racc.rb +333 -0
  12. data/lib/einstein/parser.rex +42 -0
  13. data/lib/einstein/parser.rex.rb +101 -0
  14. data/lib/einstein/pretty_printer.rb +98 -0
  15. data/lib/einstein/processor.rb +12 -0
  16. data/lib/einstein/version.rb +3 -3
  17. data/tasks/benchmark.rake +28 -0
  18. data/test/helper.rb +2 -1
  19. data/test/test_einstein.rb +20 -0
  20. data/test/test_evaluator.rb +86 -0
  21. data/test/test_parser.rb +35 -30
  22. data/test/test_pretty_printer.rb +81 -0
  23. metadata +31 -31
  24. data/config/hoe.rb +0 -62
  25. data/config/requirements.rb +0 -17
  26. data/lib/einstein/generated_parser.rb +0 -337
  27. data/lib/einstein/nodes.rb +0 -155
  28. data/lib/einstein/parser.rb +0 -60
  29. data/lib/einstein/tokenizer.rb +0 -112
  30. data/lib/einstein/visitors.rb +0 -303
  31. data/lib/parser.y +0 -79
  32. data/script/destroy +0 -14
  33. data/script/generate +0 -14
  34. data/script/txt2html +0 -74
  35. data/tasks/deployment.rake +0 -34
  36. data/tasks/environment.rake +0 -7
  37. data/tasks/website.rake +0 -17
  38. data/test/test_evaluate.rb +0 -127
  39. data/test/test_pretty_print.rb +0 -119
  40. data/test/test_tokenizer.rb +0 -68
  41. data/website/index.html +0 -120
  42. data/website/index.txt +0 -58
  43. data/website/javascripts/rounded_corners_lite.inc.js +0 -285
  44. data/website/stylesheets/screen.css +0 -138
  45. data/website/template.rhtml +0 -48
@@ -0,0 +1,98 @@
1
+ require 'einstein/processor'
2
+
3
+ module Einstein
4
+ # This processor walks the AST and builds a "pretty print" of the values.
5
+ # This means that it returns an unambiguous string representation of the
6
+ # tree. All binary expressions are wrapped in parentheses.
7
+ class PrettyPrinter < Processor
8
+ # Example: 4
9
+ def process_lit(exp)
10
+ exp[1].to_s
11
+ end
12
+
13
+ # Example: +4
14
+ def process_unary_plus(exp)
15
+ unary_op("+", exp)
16
+ end
17
+
18
+ # Example: -4
19
+ def process_unary_minus(exp)
20
+ unary_op("-", exp)
21
+ end
22
+
23
+ # Example: ~4
24
+ def process_bitwise_not(exp)
25
+ unary_op("~", exp)
26
+ end
27
+
28
+ # Example: (2 ** 3)
29
+ def process_exponent(exp)
30
+ binary_op("**", exp)
31
+ end
32
+
33
+ # Example: (2 * 3)
34
+ def process_multiply(exp)
35
+ binary_op("*", exp)
36
+ end
37
+
38
+ # Example: (6 / 3)
39
+ def process_divide(exp)
40
+ binary_op("/", exp)
41
+ end
42
+
43
+ # Example: (7 % 3)
44
+ def process_modulus(exp)
45
+ binary_op("%", exp)
46
+ end
47
+
48
+ # Example: (5 + 8)
49
+ def process_add(exp)
50
+ binary_op("+", exp)
51
+ end
52
+
53
+ # Example: (6 - 3)
54
+ def process_subtract(exp)
55
+ binary_op("-", exp)
56
+ end
57
+
58
+ # Example: (8 << 2)
59
+ def process_lshift(exp)
60
+ binary_op("<<", exp)
61
+ end
62
+
63
+ # Example: (8 >> 2)
64
+ def process_rshift(exp)
65
+ binary_op(">>", exp)
66
+ end
67
+
68
+ # Example: (4 & 16)
69
+ def process_bitwise_and(exp)
70
+ binary_op("&", exp)
71
+ end
72
+
73
+ # Example: (4 ^ 6)
74
+ def process_bitwise_xor(exp)
75
+ binary_op("^", exp)
76
+ end
77
+
78
+ # Example: (4 | 6)
79
+ def process_bitwise_or(exp)
80
+ binary_op("|", exp)
81
+ end
82
+
83
+ # Example: x
84
+ def process_resolve(exp)
85
+ exp[1]
86
+ end
87
+
88
+ private
89
+
90
+ def unary_op(operation, exp)
91
+ "#{operation}#{process(exp[1])}"
92
+ end
93
+
94
+ def binary_op(operation, exp)
95
+ "(#{process(exp[1])} #{operation} #{process(exp[2])})"
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,12 @@
1
+ module Einstein
2
+ class Processor
3
+ def process(node)
4
+ node ||= []
5
+ if respond_to?(method = "process_#{node.first}")
6
+ send(method, node)
7
+ else
8
+ raise "No process method for sexp: #{node.inspect}"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,8 +1,8 @@
1
- module Einstein #:nodoc:
1
+ module Einstein
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 1
5
- TINY = 1
4
+ MINOR = 2
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -0,0 +1,28 @@
1
+ task :benchmark => :parser do
2
+ require 'benchmark'
3
+ runs = (ENV['RUNS'] || 10_000).to_i
4
+
5
+ puts "Benchmarking #{runs} run(s) of Einstein.parse"
6
+ Benchmark.bm(23) do |b|
7
+ b.report('1') { runs.times { Einstein.parse('1') } }
8
+ b.report('2 + 5') { runs.times { Einstein.parse('2 + 5') } }
9
+ b.report('x * y') { runs.times { Einstein.parse('x * y') } }
10
+ b.report('(x ** 2) / 8 - (y << z)') { runs.times { Einstein.parse('(x ** 2) / 8 - (y << z)') } }
11
+ end
12
+
13
+ puts "Benchmarking #{runs} run(s) of Einstein.evaluate"
14
+ Benchmark.bm(23) do |b|
15
+ b.report('1') { runs.times { Einstein.evaluate('1') } }
16
+ b.report('2 + 5') { runs.times { Einstein.evaluate('2 + 5') } }
17
+ b.report('x * y') { runs.times { Einstein.evaluate('x * y', :x => 1, :y => 2) } }
18
+ b.report('(x ** 2) / 8 - (y << z)') { runs.times { Einstein.evaluate('(x ** 2) / 8 - (y << z)', :x => 4, :y => 2, :z => 2) } }
19
+ end
20
+
21
+ puts "Benchmarking #{runs} run(s) of evaluate on a pre-parsed expression"
22
+ Benchmark.bm(23) do |b|
23
+ b.report('1') { e = Einstein.parse('1'); runs.times { e.evaluate } }
24
+ b.report('2 + 5') { e = Einstein.parse('2 + 5'); runs.times { e.evaluate } }
25
+ b.report('x * y') { e = Einstein.parse('x * y'); runs.times { e.evaluate(:x => 1, :y => 2) } }
26
+ b.report('(x ** 2) / 8 - (y << z)') { e = Einstein.parse('(x ** 2) / 8 - (y << z)'); runs.times { e.evaluate(:x => 4, :y => 2, :z => 2) } }
27
+ end
28
+ end
data/test/helper.rb CHANGED
@@ -1,2 +1,3 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'einstein'
1
3
  require 'test/unit'
2
- require File.dirname(__FILE__) + '/../lib/einstein'
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestEinstein < Test::Unit::TestCase
4
+ def test_evaluate
5
+ assert_equal(1, Einstein.evaluate('1'))
6
+ assert_equal(35, Einstein.evaluate('(5 + 2) * (10 - 5)'))
7
+ end
8
+
9
+ def test_parse
10
+ exp = Einstein.parse('1')
11
+ assert_equal [:lit, 1], exp.to_sexp
12
+ assert_equal 1, exp.evaluate
13
+ assert_equal '1', exp.to_s
14
+
15
+ exp = Einstein.parse('2 + 5')
16
+ assert_equal [:add, [:lit, 2], [:lit, 5]], exp.to_sexp
17
+ assert_equal 7, exp.evaluate
18
+ assert_equal '(2 + 5)', exp.to_s
19
+ end
20
+ end
@@ -0,0 +1,86 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestEvaluator < Test::Unit::TestCase
4
+ def test_resolve_should_raise_on_undefined_variable
5
+ assert_raises(Einstein::ResolveError) { process([:resolve, "x"]) }
6
+ end
7
+
8
+ def test_resolve
9
+ assert_equal(10, process([:resolve, "x"], "x" => 10))
10
+ assert_equal(10, process([:resolve, "x"], :x => 10))
11
+ end
12
+
13
+ def test_bitwise_or
14
+ assert_equal(10 | 5, process([:bitwise_or, [:lit, 10], [:lit, 5]]))
15
+ end
16
+
17
+ def test_bitwise_xor
18
+ assert_equal(10 ^ 5, process([:bitwise_xor, [:lit, 10], [:lit, 5]]))
19
+ end
20
+
21
+ def test_bitwise_and
22
+ assert_equal(10 & 5, process([:bitwise_and, [:lit, 10], [:lit, 5]]))
23
+ end
24
+
25
+ def test_rshift
26
+ assert_equal(10 >> 5, process([:rshift, [:lit, 10], [:lit, 5]]))
27
+ end
28
+
29
+ def test_lshift
30
+ assert_equal(10 << 5, process([:lshift, [:lit, 10], [:lit, 5]]))
31
+ end
32
+
33
+ def test_subtract
34
+ assert_equal(10 - 5, process([:subtract, [:lit, 10], [:lit, 5]]))
35
+ end
36
+
37
+ def test_add
38
+ assert_equal(10 + 5, process([:add, [:lit, 10], [:lit, 5]]))
39
+ end
40
+
41
+ def test_modulus
42
+ assert_equal(10 % 5, process([:modulus, [:lit, 10], [:lit, 5]]))
43
+ end
44
+
45
+ def test_divide_should_raise_on_divide_by_zero
46
+ assert_raises(ZeroDivisionError) { process([:divide, [:lit, 10], [:lit, 0]]) }
47
+ end
48
+
49
+ def test_divide
50
+ assert_equal(10 / 5, process([:divide, [:lit, 10], [:lit, 5]]))
51
+ end
52
+
53
+ def test_multiply
54
+ assert_equal(10 * 5, process([:multiply, [:lit, 10], [:lit, 5]]))
55
+ end
56
+
57
+ def test_exponent
58
+ assert_equal(10 ** 5, process([:exponent, [:lit, 10], [:lit, 5]]))
59
+ end
60
+
61
+ def test_bitwise_not
62
+ assert_equal(~10, process([:bitwise_not, [:lit, 10]]))
63
+ end
64
+
65
+ def test_unary_minus
66
+ assert_equal(-10, process([:unary_minus, [:lit, 10]]))
67
+ end
68
+
69
+ def test_unary_plus
70
+ assert_equal(+10, process([:unary_plus, [:lit, 10]]))
71
+ end
72
+
73
+ def test_lit
74
+ assert_equal(0, process([:lit, 0]))
75
+ assert_equal(1, process([:lit, 1]))
76
+ assert_equal(10, process([:lit, 10]))
77
+
78
+ assert_equal(10.1, process([:lit, 10.1]))
79
+ end
80
+
81
+ private
82
+
83
+ def process(exp, scope = {})
84
+ Einstein::Evaluator.new(scope).process(exp)
85
+ end
86
+ end
data/test/test_parser.rb CHANGED
@@ -1,10 +1,8 @@
1
- require File.dirname(__FILE__) + "/helper"
2
- require "logger"
1
+ require File.dirname(__FILE__) + '/helper'
3
2
 
4
3
  class TestParser < Test::Unit::TestCase
5
4
  def setup
6
5
  @parser = Einstein::Parser.new
7
- @parser.logger = Logger.new(STDERR)
8
6
  end
9
7
 
10
8
  def test_parentheses
@@ -13,7 +11,7 @@ class TestParser < Test::Unit::TestCase
13
11
  [:add, [:lit, 5], [:lit, 2]],
14
12
  [:subtract, [:lit, 10], [:lit, 5]]
15
13
  ],
16
- parse("(5 + 2) * (10 - 5)").to_sexp
14
+ parse('(5 + 2) * (10 - 5)')
17
15
  end
18
16
 
19
17
  def test_order_of_operations
@@ -24,99 +22,106 @@ class TestParser < Test::Unit::TestCase
24
22
  [:multiply, [:lit, 4], [:lit, 2]]],
25
23
  [:lit, 5]
26
24
  ],
27
- parse("6 / 3 + 4 * 2 - 5").to_sexp
25
+ parse('6 / 3 + 4 * 2 - 5')
28
26
  end
29
27
 
30
28
  def test_resolve
31
- assert_equal [:resolve, "x"], parse("x").to_sexp
29
+ assert_equal [:resolve, 'x'], parse('x')
30
+ assert_equal [:resolve, 'with_underscores'], parse('with_underscores')
31
+ assert_equal [:resolve, '_leading_underscore'], parse('_leading_underscore')
32
+ assert_equal [:resolve, 'trailing_underscore_'], parse('trailing_underscore_')
32
33
  end
33
34
 
34
35
  def test_bitwise_or
35
- assert_equal [:bitwise_or, [:lit, 5], [:lit, 10]], parse("5 | 10").to_sexp
36
+ assert_equal [:bitwise_or, [:lit, 5], [:lit, 10]], parse('5 | 10')
36
37
  end
37
38
 
38
39
  def test_bitwise_xor
39
- assert_equal [:bitwise_xor, [:lit, 5], [:lit, 10]], parse("5 ^ 10").to_sexp
40
+ assert_equal [:bitwise_xor, [:lit, 5], [:lit, 10]], parse('5 ^ 10')
40
41
  end
41
42
 
42
43
  def test_bitwise_and
43
- assert_equal [:bitwise_and, [:lit, 5], [:lit, 10]], parse("5 & 10").to_sexp
44
+ assert_equal [:bitwise_and, [:lit, 5], [:lit, 10]], parse('5 & 10')
44
45
  end
45
46
 
46
47
  def test_rshift
47
- assert_equal [:rshift, [:lit, 2], [:lit, 3]], parse("2 >> 3").to_sexp
48
+ assert_equal [:rshift, [:lit, 2], [:lit, 3]], parse('2 >> 3')
48
49
  end
49
50
 
50
51
  def test_lshift
51
- assert_equal [:lshift, [:lit, 2], [:lit, 3]], parse("2 << 3").to_sexp
52
+ assert_equal [:lshift, [:lit, 2], [:lit, 3]], parse('2 << 3')
52
53
  end
53
54
 
54
55
  def test_subtraction
55
- assert_equal [:subtract, [:lit, 2], [:lit, 1]], parse("2 - 1").to_sexp
56
+ assert_equal [:subtract, [:lit, 2], [:lit, 1]], parse('2 - 1')
56
57
  end
57
58
 
58
59
  def test_addition
59
- assert_equal [:add, [:lit, 1], [:lit, 2]], parse("1 + 2").to_sexp
60
+ assert_equal [:add, [:lit, 1], [:lit, 2]], parse('1 + 2')
60
61
  end
61
62
 
62
63
  def test_modulus
63
- assert_equal [:modulus, [:lit, 10], [:lit, 5]], parse("10 % 5").to_sexp
64
+ assert_equal [:modulus, [:lit, 10], [:lit, 5]], parse('10 % 5')
64
65
  end
65
66
 
66
67
  def test_division
67
- assert_equal [:divide, [:lit, 10], [:lit, 5]], parse("10 / 5").to_sexp
68
+ assert_equal [:divide, [:lit, 10], [:lit, 5]], parse('10 / 5')
68
69
  end
69
70
 
70
71
  def test_multiplication
71
- assert_equal [:multiply, [:lit, 5], [:lit, 10]], parse("5 * 10").to_sexp
72
+ assert_equal [:multiply, [:lit, 5], [:lit, 10]], parse('5 * 10')
72
73
  end
73
74
 
74
75
  def test_exponent
75
- assert_equal [:raise, [:lit, 5], [:lit, 2]], parse("5 ** 2").to_sexp
76
- assert_equal [:raise, [:lit, 3], [:u_minus, [:lit, 6]]], parse("3 ** -6").to_sexp
77
- assert_equal [:raise, [:lit, 18], [:bitwise_not, [:lit, 4]]], parse("18 ** ~4").to_sexp
76
+ assert_equal [:exponent, [:lit, 5], [:lit, 2]], parse('5 ** 2')
77
+ assert_equal [:exponent, [:lit, 3], [:unary_minus, [:lit, 6]]], parse('3 ** -6')
78
+ assert_equal [:exponent, [:lit, 18], [:bitwise_not, [:lit, 4]]], parse('18 ** ~4')
78
79
  end
79
80
 
80
81
  def test_unary_bitwise_not
81
- assert_equal [:bitwise_not, [:lit, 10]], parse("~10").to_sexp
82
+ assert_equal [:bitwise_not, [:lit, 10]], parse('~10')
82
83
  end
83
84
 
84
85
  def test_unary_minus
85
- assert_equal [:u_minus, [:lit, 10]], parse("-10").to_sexp
86
+ assert_equal [:unary_minus, [:lit, 10]], parse('-10')
86
87
  end
87
88
 
88
89
  def test_unary_plus
89
- assert_equal [:u_plus, [:lit, 10]], parse("+10").to_sexp
90
+ assert_equal [:unary_plus, [:lit, 10]], parse('+10')
90
91
  end
91
92
 
92
93
  def test_float_scientific
93
- assert_equal [:lit, 10.10e-3], parse("10.10e-3").to_sexp
94
+ assert_equal [:lit, 10.10e-3], parse('10.10e-3')
95
+ assert_equal [:lit, 12.34E+4], parse('12.34E+4')
94
96
  end
95
97
 
96
98
  def test_float
97
- assert_equal [:lit, 10.10], parse("10.10").to_sexp
99
+ assert_equal [:lit, 10.10], parse('10.10')
98
100
  end
99
101
 
100
102
  def test_number_base2
101
- assert_equal [:lit, 0b1010], parse("0b1010").to_sexp
103
+ assert_equal [:lit, 0b1010], parse('0b1010')
104
+ assert_equal [:lit, 0B0101], parse('0B0101')
102
105
  end
103
106
 
104
107
  def test_number_base8
105
- assert_equal [:lit, 011], parse("011").to_sexp
108
+ assert_equal [:lit, 011], parse('011')
106
109
  end
107
110
 
108
111
  def test_number_base16
109
- assert_equal [:lit, 0xdeadbeef], parse("0xdeadbeef").to_sexp
110
- assert_equal [:lit, 0xCAFEBABE], parse("0xCAFEBABE").to_sexp
112
+ assert_equal [:lit, 0xdeadbeef], parse('0xdeadbeef')
113
+ assert_equal [:lit, 0Xdeadbeef], parse('0Xdeadbeef')
114
+ assert_equal [:lit, 0xCAFEBABE], parse('0xCAFEBABE')
115
+ assert_equal [:lit, 0XCAFEBABE], parse('0XCAFEBABE')
111
116
  end
112
117
 
113
118
  def test_number_base10
114
- assert_equal [:lit, 15], parse("15").to_sexp
119
+ assert_equal [:lit, 15], parse('15')
115
120
  end
116
121
 
117
122
  private
118
123
 
119
124
  def parse(stmt)
120
- @parser.parse(stmt)
125
+ @parser.scan_str(stmt)
121
126
  end
122
127
  end
@@ -0,0 +1,81 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestPrettyPrintProcessor < Test::Unit::TestCase
4
+ def setup
5
+ @printer = Einstein::PrettyPrinter.new
6
+ end
7
+
8
+ def test_resolve
9
+ assert_equal 'x', process([:resolve, 'x'])
10
+ end
11
+
12
+ def test_bitwise_or
13
+ assert_equal '(10 | 5)', process([:bitwise_or, [:lit, 10], [:lit, 5]])
14
+ end
15
+
16
+ def test_bitwise_xor
17
+ assert_equal '(10 ^ 5)', process([:bitwise_xor, [:lit, 10], [:lit, 5]])
18
+ end
19
+
20
+ def test_bitwise_and
21
+ assert_equal '(10 & 5)', process([:bitwise_and, [:lit, 10], [:lit, 5]])
22
+ end
23
+
24
+ def test_rshift
25
+ assert_equal '(10 >> 5)', process([:rshift, [:lit, 10], [:lit, 5]])
26
+ end
27
+
28
+ def test_lshift
29
+ assert_equal '(10 << 5)', process([:lshift, [:lit, 10], [:lit, 5]])
30
+ end
31
+
32
+ def test_subtract
33
+ assert_equal '(10 - 5)', process([:subtract, [:lit, 10], [:lit, 5]])
34
+ end
35
+
36
+ def test_add
37
+ assert_equal '(10 + 5)', process([:add, [:lit, 10], [:lit, 5]])
38
+ end
39
+
40
+ def test_modulus
41
+ assert_equal '(10 % 5)', process([:modulus, [:lit, 10], [:lit, 5]])
42
+ end
43
+
44
+ def test_divide
45
+ assert_equal '(10 / 5)', process([:divide, [:lit, 10], [:lit, 5]])
46
+ end
47
+
48
+ def test_multiply
49
+ assert_equal '(10 * 5)', process([:multiply, [:lit, 10], [:lit, 5]])
50
+ end
51
+
52
+ def test_exponent
53
+ assert_equal '(10 ** 5)', process([:exponent, [:lit, 10], [:lit, 5]])
54
+ end
55
+
56
+ def test_bitwise_not
57
+ assert_equal '~10', process([:bitwise_not, [:lit, 10]])
58
+ end
59
+
60
+ def test_unary_minus
61
+ assert_equal '-10', process([:unary_minus, [:lit, 10]])
62
+ end
63
+
64
+ def test_unary_plus
65
+ assert_equal '+10', process([:unary_plus, [:lit, 10]])
66
+ end
67
+
68
+ def test_lit
69
+ assert_equal '0', process([:lit, 0])
70
+ assert_equal '1', process([:lit, 1])
71
+ assert_equal '10', process([:lit, 10])
72
+
73
+ assert_equal '10.1', process([:lit, 10.1])
74
+ end
75
+
76
+ private
77
+
78
+ def process(exp)
79
+ @printer.process(exp)
80
+ end
81
+ end