keisan 0.1.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 (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