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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +19 -0
- data/README.md +188 -0
- data/Rakefile +6 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/keisan.gemspec +31 -0
- data/lib/keisan.rb +118 -0
- data/lib/keisan/ast/arithmetic_operator.rb +9 -0
- data/lib/keisan/ast/bitwise_and.rb +21 -0
- data/lib/keisan/ast/bitwise_operator.rb +9 -0
- data/lib/keisan/ast/bitwise_or.rb +21 -0
- data/lib/keisan/ast/bitwise_xor.rb +21 -0
- data/lib/keisan/ast/boolean.rb +15 -0
- data/lib/keisan/ast/builder.rb +141 -0
- data/lib/keisan/ast/exponent.rb +25 -0
- data/lib/keisan/ast/function.rb +19 -0
- data/lib/keisan/ast/indexing.rb +16 -0
- data/lib/keisan/ast/list.rb +10 -0
- data/lib/keisan/ast/literal.rb +6 -0
- data/lib/keisan/ast/logical_and.rb +21 -0
- data/lib/keisan/ast/logical_greater_than.rb +17 -0
- data/lib/keisan/ast/logical_greater_than_or_equal_to.rb +17 -0
- data/lib/keisan/ast/logical_less_than.rb +17 -0
- data/lib/keisan/ast/logical_less_than_or_equal_to.rb +17 -0
- data/lib/keisan/ast/logical_operator.rb +9 -0
- data/lib/keisan/ast/logical_or.rb +21 -0
- data/lib/keisan/ast/node.rb +9 -0
- data/lib/keisan/ast/null.rb +12 -0
- data/lib/keisan/ast/number.rb +15 -0
- data/lib/keisan/ast/operator.rb +50 -0
- data/lib/keisan/ast/parent.rb +15 -0
- data/lib/keisan/ast/plus.rb +49 -0
- data/lib/keisan/ast/string.rb +15 -0
- data/lib/keisan/ast/times.rb +36 -0
- data/lib/keisan/ast/unary_bitwise_not.rb +9 -0
- data/lib/keisan/ast/unary_identity.rb +9 -0
- data/lib/keisan/ast/unary_inverse.rb +9 -0
- data/lib/keisan/ast/unary_logical_not.rb +9 -0
- data/lib/keisan/ast/unary_minus.rb +9 -0
- data/lib/keisan/ast/unary_operator.rb +13 -0
- data/lib/keisan/ast/unary_plus.rb +9 -0
- data/lib/keisan/ast/variable.rb +16 -0
- data/lib/keisan/calculator.rb +30 -0
- data/lib/keisan/context.rb +36 -0
- data/lib/keisan/exceptions.rb +19 -0
- data/lib/keisan/function.rb +15 -0
- data/lib/keisan/functions/default_registry.rb +58 -0
- data/lib/keisan/functions/rand.rb +22 -0
- data/lib/keisan/functions/registry.rb +50 -0
- data/lib/keisan/functions/sample.rb +20 -0
- data/lib/keisan/parser.rb +211 -0
- data/lib/keisan/parsing/argument.rb +6 -0
- data/lib/keisan/parsing/arithmetic_operator.rb +6 -0
- data/lib/keisan/parsing/bitwise_and.rb +9 -0
- data/lib/keisan/parsing/bitwise_not.rb +9 -0
- data/lib/keisan/parsing/bitwise_not_not.rb +9 -0
- data/lib/keisan/parsing/bitwise_operator.rb +6 -0
- data/lib/keisan/parsing/bitwise_or.rb +9 -0
- data/lib/keisan/parsing/bitwise_xor.rb +9 -0
- data/lib/keisan/parsing/boolean.rb +11 -0
- data/lib/keisan/parsing/component.rb +6 -0
- data/lib/keisan/parsing/divide.rb +9 -0
- data/lib/keisan/parsing/element.rb +6 -0
- data/lib/keisan/parsing/exponent.rb +9 -0
- data/lib/keisan/parsing/function.rb +12 -0
- data/lib/keisan/parsing/group.rb +11 -0
- data/lib/keisan/parsing/indexing.rb +14 -0
- data/lib/keisan/parsing/list.rb +10 -0
- data/lib/keisan/parsing/logical_and.rb +9 -0
- data/lib/keisan/parsing/logical_greater_than.rb +9 -0
- data/lib/keisan/parsing/logical_greater_than_or_equal_to.rb +9 -0
- data/lib/keisan/parsing/logical_less_than.rb +9 -0
- data/lib/keisan/parsing/logical_less_than_or_equal_to.rb +9 -0
- data/lib/keisan/parsing/logical_not.rb +9 -0
- data/lib/keisan/parsing/logical_not_not.rb +9 -0
- data/lib/keisan/parsing/logical_operator.rb +6 -0
- data/lib/keisan/parsing/logical_or.rb +9 -0
- data/lib/keisan/parsing/minus.rb +9 -0
- data/lib/keisan/parsing/null.rb +6 -0
- data/lib/keisan/parsing/number.rb +10 -0
- data/lib/keisan/parsing/operator.rb +13 -0
- data/lib/keisan/parsing/plus.rb +9 -0
- data/lib/keisan/parsing/round_group.rb +6 -0
- data/lib/keisan/parsing/square_group.rb +6 -0
- data/lib/keisan/parsing/string.rb +10 -0
- data/lib/keisan/parsing/times.rb +9 -0
- data/lib/keisan/parsing/unary_minus.rb +9 -0
- data/lib/keisan/parsing/unary_operator.rb +9 -0
- data/lib/keisan/parsing/unary_plus.rb +9 -0
- data/lib/keisan/parsing/variable.rb +11 -0
- data/lib/keisan/token.rb +25 -0
- data/lib/keisan/tokenizer.rb +41 -0
- data/lib/keisan/tokens/arithmetic_operator.rb +29 -0
- data/lib/keisan/tokens/bitwise_operator.rb +29 -0
- data/lib/keisan/tokens/boolean.rb +20 -0
- data/lib/keisan/tokens/comma.rb +11 -0
- data/lib/keisan/tokens/group.rb +28 -0
- data/lib/keisan/tokens/logical_operator.rb +38 -0
- data/lib/keisan/tokens/null.rb +15 -0
- data/lib/keisan/tokens/number.rb +24 -0
- data/lib/keisan/tokens/operator.rb +9 -0
- data/lib/keisan/tokens/string.rb +15 -0
- data/lib/keisan/tokens/word.rb +11 -0
- data/lib/keisan/variables/default_registry.rb +20 -0
- data/lib/keisan/variables/registry.rb +41 -0
- data/lib/keisan/version.rb +3 -0
- metadata +238 -0
data/lib/keisan/token.rb
ADDED
@@ -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,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
|