keisan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +4 -0
  6. data/MIT-LICENSE +19 -0
  7. data/README.md +188 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +10 -0
  10. data/bin/setup +8 -0
  11. data/keisan.gemspec +31 -0
  12. data/lib/keisan.rb +118 -0
  13. data/lib/keisan/ast/arithmetic_operator.rb +9 -0
  14. data/lib/keisan/ast/bitwise_and.rb +21 -0
  15. data/lib/keisan/ast/bitwise_operator.rb +9 -0
  16. data/lib/keisan/ast/bitwise_or.rb +21 -0
  17. data/lib/keisan/ast/bitwise_xor.rb +21 -0
  18. data/lib/keisan/ast/boolean.rb +15 -0
  19. data/lib/keisan/ast/builder.rb +141 -0
  20. data/lib/keisan/ast/exponent.rb +25 -0
  21. data/lib/keisan/ast/function.rb +19 -0
  22. data/lib/keisan/ast/indexing.rb +16 -0
  23. data/lib/keisan/ast/list.rb +10 -0
  24. data/lib/keisan/ast/literal.rb +6 -0
  25. data/lib/keisan/ast/logical_and.rb +21 -0
  26. data/lib/keisan/ast/logical_greater_than.rb +17 -0
  27. data/lib/keisan/ast/logical_greater_than_or_equal_to.rb +17 -0
  28. data/lib/keisan/ast/logical_less_than.rb +17 -0
  29. data/lib/keisan/ast/logical_less_than_or_equal_to.rb +17 -0
  30. data/lib/keisan/ast/logical_operator.rb +9 -0
  31. data/lib/keisan/ast/logical_or.rb +21 -0
  32. data/lib/keisan/ast/node.rb +9 -0
  33. data/lib/keisan/ast/null.rb +12 -0
  34. data/lib/keisan/ast/number.rb +15 -0
  35. data/lib/keisan/ast/operator.rb +50 -0
  36. data/lib/keisan/ast/parent.rb +15 -0
  37. data/lib/keisan/ast/plus.rb +49 -0
  38. data/lib/keisan/ast/string.rb +15 -0
  39. data/lib/keisan/ast/times.rb +36 -0
  40. data/lib/keisan/ast/unary_bitwise_not.rb +9 -0
  41. data/lib/keisan/ast/unary_identity.rb +9 -0
  42. data/lib/keisan/ast/unary_inverse.rb +9 -0
  43. data/lib/keisan/ast/unary_logical_not.rb +9 -0
  44. data/lib/keisan/ast/unary_minus.rb +9 -0
  45. data/lib/keisan/ast/unary_operator.rb +13 -0
  46. data/lib/keisan/ast/unary_plus.rb +9 -0
  47. data/lib/keisan/ast/variable.rb +16 -0
  48. data/lib/keisan/calculator.rb +30 -0
  49. data/lib/keisan/context.rb +36 -0
  50. data/lib/keisan/exceptions.rb +19 -0
  51. data/lib/keisan/function.rb +15 -0
  52. data/lib/keisan/functions/default_registry.rb +58 -0
  53. data/lib/keisan/functions/rand.rb +22 -0
  54. data/lib/keisan/functions/registry.rb +50 -0
  55. data/lib/keisan/functions/sample.rb +20 -0
  56. data/lib/keisan/parser.rb +211 -0
  57. data/lib/keisan/parsing/argument.rb +6 -0
  58. data/lib/keisan/parsing/arithmetic_operator.rb +6 -0
  59. data/lib/keisan/parsing/bitwise_and.rb +9 -0
  60. data/lib/keisan/parsing/bitwise_not.rb +9 -0
  61. data/lib/keisan/parsing/bitwise_not_not.rb +9 -0
  62. data/lib/keisan/parsing/bitwise_operator.rb +6 -0
  63. data/lib/keisan/parsing/bitwise_or.rb +9 -0
  64. data/lib/keisan/parsing/bitwise_xor.rb +9 -0
  65. data/lib/keisan/parsing/boolean.rb +11 -0
  66. data/lib/keisan/parsing/component.rb +6 -0
  67. data/lib/keisan/parsing/divide.rb +9 -0
  68. data/lib/keisan/parsing/element.rb +6 -0
  69. data/lib/keisan/parsing/exponent.rb +9 -0
  70. data/lib/keisan/parsing/function.rb +12 -0
  71. data/lib/keisan/parsing/group.rb +11 -0
  72. data/lib/keisan/parsing/indexing.rb +14 -0
  73. data/lib/keisan/parsing/list.rb +10 -0
  74. data/lib/keisan/parsing/logical_and.rb +9 -0
  75. data/lib/keisan/parsing/logical_greater_than.rb +9 -0
  76. data/lib/keisan/parsing/logical_greater_than_or_equal_to.rb +9 -0
  77. data/lib/keisan/parsing/logical_less_than.rb +9 -0
  78. data/lib/keisan/parsing/logical_less_than_or_equal_to.rb +9 -0
  79. data/lib/keisan/parsing/logical_not.rb +9 -0
  80. data/lib/keisan/parsing/logical_not_not.rb +9 -0
  81. data/lib/keisan/parsing/logical_operator.rb +6 -0
  82. data/lib/keisan/parsing/logical_or.rb +9 -0
  83. data/lib/keisan/parsing/minus.rb +9 -0
  84. data/lib/keisan/parsing/null.rb +6 -0
  85. data/lib/keisan/parsing/number.rb +10 -0
  86. data/lib/keisan/parsing/operator.rb +13 -0
  87. data/lib/keisan/parsing/plus.rb +9 -0
  88. data/lib/keisan/parsing/round_group.rb +6 -0
  89. data/lib/keisan/parsing/square_group.rb +6 -0
  90. data/lib/keisan/parsing/string.rb +10 -0
  91. data/lib/keisan/parsing/times.rb +9 -0
  92. data/lib/keisan/parsing/unary_minus.rb +9 -0
  93. data/lib/keisan/parsing/unary_operator.rb +9 -0
  94. data/lib/keisan/parsing/unary_plus.rb +9 -0
  95. data/lib/keisan/parsing/variable.rb +11 -0
  96. data/lib/keisan/token.rb +25 -0
  97. data/lib/keisan/tokenizer.rb +41 -0
  98. data/lib/keisan/tokens/arithmetic_operator.rb +29 -0
  99. data/lib/keisan/tokens/bitwise_operator.rb +29 -0
  100. data/lib/keisan/tokens/boolean.rb +20 -0
  101. data/lib/keisan/tokens/comma.rb +11 -0
  102. data/lib/keisan/tokens/group.rb +28 -0
  103. data/lib/keisan/tokens/logical_operator.rb +38 -0
  104. data/lib/keisan/tokens/null.rb +15 -0
  105. data/lib/keisan/tokens/number.rb +24 -0
  106. data/lib/keisan/tokens/operator.rb +9 -0
  107. data/lib/keisan/tokens/string.rb +15 -0
  108. data/lib/keisan/tokens/word.rb +11 -0
  109. data/lib/keisan/variables/default_registry.rb +20 -0
  110. data/lib/keisan/variables/registry.rb +41 -0
  111. data/lib/keisan/version.rb +3 -0
  112. metadata +238 -0
@@ -0,0 +1,11 @@
1
+ module Keisan
2
+ module Parsing
3
+ class Group < Element
4
+ attr_reader :components
5
+
6
+ def initialize(sub_tokens)
7
+ @components = Keisan::Parser.new(tokens: sub_tokens).components
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module Keisan
2
+ module Parsing
3
+ class Indexing < SquareGroup
4
+ attr_reader :arguments
5
+ def initialize(arguments)
6
+ @arguments = arguments
7
+ end
8
+
9
+ def node_class
10
+ Keisan::AST::Indexing
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module Keisan
2
+ module Parsing
3
+ class List < SquareGroup
4
+ attr_reader :arguments
5
+ def initialize(arguments)
6
+ @arguments = arguments
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class LogicalAnd < LogicalOperator
4
+ def node_class
5
+ Keisan::AST::LogicalAnd
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class LogicalGreaterThan < LogicalOperator
4
+ def node_class
5
+ Keisan::AST::LogicalGreaterThan
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class LogicalGreaterThanOrEqualTo < LogicalOperator
4
+ def node_class
5
+ Keisan::AST::LogicalGreaterThanOrEqualTo
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class LogicalLessThan < LogicalOperator
4
+ def node_class
5
+ Keisan::AST::LogicalLessThan
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class LogicalLessThanOrEqualTo < LogicalOperator
4
+ def node_class
5
+ Keisan::AST::LogicalLessThanOrEqualTo
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class LogicalNot < UnaryOperator
4
+ def node_class
5
+ Keisan::AST::UnaryLogicalNot
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class LogicalNotNot < UnaryOperator
4
+ def node_class
5
+ Keisan::AST::UnaryIdentity
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Keisan
2
+ module Parsing
3
+ class LogicalOperator < Operator
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class LogicalOr < LogicalOperator
4
+ def node_class
5
+ Keisan::AST::LogicalOr
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class Minus < ArithmeticOperator
4
+ def node_class
5
+ Keisan::AST::Plus
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Keisan
2
+ module Parsing
3
+ class Null < Element
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ module Keisan
2
+ module Parsing
3
+ class Number < Element
4
+ attr_reader :value
5
+ def initialize(value)
6
+ @value = value
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module Keisan
2
+ module Parsing
3
+ class Operator < Component
4
+ def priority
5
+ node_class.priority
6
+ end
7
+
8
+ def node_class
9
+ raise Keisan::Exceptions::NotImplementedError.new
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class Plus < ArithmeticOperator
4
+ def node_class
5
+ Keisan::AST::Plus
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Keisan
2
+ module Parsing
3
+ class RoundGroup < Group
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Keisan
2
+ module Parsing
3
+ class SquareGroup < Group
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ module Keisan
2
+ module Parsing
3
+ class String < Element
4
+ attr_reader :value
5
+ def initialize(value)
6
+ @value = value
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class Times < ArithmeticOperator
4
+ def node_class
5
+ Keisan::AST::Times
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class UnaryMinus < UnaryOperator
4
+ def node_class
5
+ Keisan::AST::UnaryMinus
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class UnaryOperator < Component
4
+ def node_class
5
+ raise Keisan::Exponent::NotImplementedError.new
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Keisan
2
+ module Parsing
3
+ class UnaryPlus < UnaryOperator
4
+ def node_class
5
+ Keisan::AST::UnaryPlus
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Keisan
2
+ module Parsing
3
+ class Variable < Element
4
+ attr_reader :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ module Keisan
2
+ class Token
3
+ attr_reader :string
4
+ def initialize(string)
5
+ raise Exceptions::InvalidToken.new(string) unless string.match(regex)
6
+ @string = string
7
+ end
8
+
9
+ def type
10
+ self.class.type
11
+ end
12
+
13
+ def self.type
14
+ @type ||= self.to_s.split("::").last.underscore.to_sym
15
+ end
16
+
17
+ def regex
18
+ self.class.regex
19
+ end
20
+
21
+ def self.regex
22
+ raise Exceptions::NotImplementedError.new(:regex)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ module Keisan
2
+ class Tokenizer
3
+ TOKEN_CLASSES = [
4
+ Tokens::Group,
5
+ Tokens::String,
6
+ Tokens::Null,
7
+ Tokens::Boolean,
8
+ Tokens::Word,
9
+ Tokens::Number,
10
+ Tokens::ArithmeticOperator,
11
+ Tokens::LogicalOperator,
12
+ Tokens::BitwiseOperator,
13
+ Tokens::Comma
14
+ ]
15
+
16
+ TOKEN_REGEX = Regexp::new(
17
+ TOKEN_CLASSES.map(&:regex).join("|")
18
+ )
19
+
20
+ attr_reader :expression, :tokens
21
+
22
+ def initialize(expression)
23
+ @expression = expression.split(Keisan::Tokens::String.regex).map.with_index {|s,i| i.even? ? s.gsub(/\s+/, "") : s}.join
24
+
25
+ @scan = @expression.scan(TOKEN_REGEX)
26
+
27
+ tokenizing_check = ""
28
+
29
+ @tokens = @scan.map do |scan_result|
30
+ i = scan_result.find_index {|token| !token.nil?}
31
+ token_string = scan_result[i]
32
+ tokenizing_check << token_string
33
+ token_class = TOKEN_CLASSES[i].new(token_string)
34
+ end
35
+
36
+ unless tokenizing_check == @expression
37
+ raise Keisan::Exceptions::TokenizingError.new("Expected \"#{@expression}\", tokenized \"#{tokenizing_check}\"")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,29 @@
1
+ module Keisan
2
+ module Tokens
3
+ class ArithmeticOperator < Operator
4
+ EXPONENT = /(?:\*\*)/
5
+ TIMES = /(?:\*)/
6
+ DIVIDE = /(?:\/)/
7
+ PLUS_OR_MINUS = /(?:[\+\-]+)/
8
+ REGEX = /(#{EXPONENT}|#{TIMES}|#{DIVIDE}|#{PLUS_OR_MINUS})/
9
+
10
+ def self.regex
11
+ REGEX
12
+ end
13
+
14
+ def operator_type
15
+ case string
16
+ when EXPONENT
17
+ # Must match first to override matching against single "*"
18
+ :**
19
+ when TIMES
20
+ :*
21
+ when DIVIDE
22
+ :/
23
+ when PLUS_OR_MINUS
24
+ string.count("-").even? ? :+ : :-
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ module Keisan
2
+ module Tokens
3
+ class BitwiseOperator < Operator
4
+ AND = /(?:\&)/
5
+ OR = /(?:\|)/
6
+ XOR = /(?:\^)/
7
+ NOT = /(?:\~+)/
8
+
9
+ REGEX = /(#{AND}|#{OR}|#{XOR}|#{NOT})/
10
+
11
+ def self.regex
12
+ REGEX
13
+ end
14
+
15
+ def operator_type
16
+ case string
17
+ when AND
18
+ :"&"
19
+ when OR
20
+ :"|"
21
+ when XOR
22
+ :"^"
23
+ when NOT
24
+ string.count("~").even? ? :"~~" : :"~"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ module Keisan
2
+ module Tokens
3
+ class Boolean < Token
4
+ REGEX = /((?:\btrue\b)|(?:\bfalse\b))/
5
+
6
+ def self.regex
7
+ REGEX
8
+ end
9
+
10
+ def value
11
+ case string
12
+ when "true"
13
+ true
14
+ else
15
+ false
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module Keisan
2
+ module Tokens
3
+ class Comma < Token
4
+ REGEX = /(\,)/
5
+
6
+ def self.regex
7
+ REGEX
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ module Keisan
2
+ module Tokens
3
+ class Group < Token
4
+ REGEX = /(\((?:[^\[\]\(\)]*\g<0>*)*\)|\[(?:[^\[\]\(\)]*\g<0>*)*\])/
5
+
6
+ attr_reader :sub_tokens
7
+
8
+ def initialize(string)
9
+ super
10
+ @sub_tokens = Tokenizer.new(string[1...-1]).tokens
11
+ end
12
+
13
+ def self.regex
14
+ REGEX
15
+ end
16
+
17
+ # Either :round, :square
18
+ def group_type
19
+ case string[0]
20
+ when "("
21
+ :round
22
+ when "["
23
+ :square
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end