code-ruby 0.10.3 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/bin/console +5 -0
  4. data/lib/code/node/base_10.rb +10 -10
  5. data/lib/code/node/base_16.rb +7 -2
  6. data/lib/code/node/base_2.rb +7 -2
  7. data/lib/code/node/base_8.rb +7 -2
  8. data/lib/code/node/boolean.rb +5 -4
  9. data/lib/code/node/call.rb +10 -16
  10. data/lib/code/node/call_argument.rb +8 -4
  11. data/lib/code/node/code.rb +3 -2
  12. data/lib/code/node/decimal.rb +8 -7
  13. data/lib/code/node/dictionary.rb +11 -8
  14. data/lib/code/node/function.rb +4 -8
  15. data/lib/code/node/function_parameter.rb +3 -3
  16. data/lib/code/node/if.rb +13 -12
  17. data/lib/code/node/left_operation.rb +10 -10
  18. data/lib/code/node/list.rb +3 -3
  19. data/lib/code/node/negation.rb +8 -4
  20. data/lib/code/node/not.rb +8 -4
  21. data/lib/code/node/nothing.rb +4 -3
  22. data/lib/code/node/number.rb +3 -3
  23. data/lib/code/node/right_operation.rb +19 -16
  24. data/lib/code/node/splat.rb +8 -4
  25. data/lib/code/node/square_bracket.rb +8 -11
  26. data/lib/code/node/statement.rb +4 -4
  27. data/lib/code/node/string.rb +13 -11
  28. data/lib/code/node/ternary.rb +8 -8
  29. data/lib/code/node/unary_minus.rb +8 -4
  30. data/lib/code/node/while.rb +15 -11
  31. data/lib/code/node.rb +1 -7
  32. data/lib/code/object/function.rb +2 -4
  33. data/lib/code/object.rb +2 -6
  34. data/lib/code/parser/code.rb +1 -1
  35. data/lib/code/parser/left_operation.rb +2 -2
  36. data/lib/code/parser/list.rb +2 -2
  37. data/lib/code/parser/right_operation.rb +2 -2
  38. data/lib/code/parser/whitespace.rb +2 -2
  39. data/lib/code/type/sig.rb +2 -2
  40. data/lib/code/type.rb +3 -3
  41. data/lib/code/version.rb +1 -1
  42. data/lib/code-ruby.rb +1 -0
  43. data/spec/code_spec.rb +4 -4
  44. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2dd4424b79963258ea77a3734a26c4cd194b1ac5dfad75a477ac3895b55e9670
4
- data.tar.gz: c19bdf30ba96aac04bdbbb3bb6ed865628df14e603fca28e2be603a65da2a351
3
+ metadata.gz: 97ce31f3a36a57e14f607ded3383aa3c71866824c6e57541c70d48962c77b9ef
4
+ data.tar.gz: '0229023c391084763f03d2ffbfd82af81da2d996666719a49ad169d7740c4d6c'
5
5
  SHA512:
6
- metadata.gz: ba860b7dda88832c4ff30bfe8ec1ac0ab0fe7fba3b037e25a88141b6756734197f6355c07d8001611980dc5cba989d05bd74ef62842d8aba1883c8ecd32b94ce
7
- data.tar.gz: 35c7d530ebd9a4393b7255a84887330fcc1f8be8f5e79ba8872e2aaac035aef1d8e8e824c4bce25b0fcd5f8e4d40fdb23a31d16cf98f8128f3e0d7720ea18bfa
6
+ metadata.gz: 996b1594dbc1192dbad2b0c64d605d9eccff6d5622437ef5974464648e5f2cd2ee57aad50fce9279f8027f1378fc7c2652106265a2fc79bbe21b224210228c9d
7
+ data.tar.gz: ec405b4bc88648344f4860fb7350695aa447a5905e9a56e7230c771d5ea76e22515fe74ac0fc30771e27a9d67f4eda85b0d2475484d81a5d2c604c5a901913ae
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- code-ruby (0.10.2)
4
+ code-ruby (0.10.4)
5
5
  activesupport (~> 7)
6
6
  bigdecimal (~> 3)
7
7
  json (~> 2)
data/bin/console ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/code-ruby"
4
+
5
+ binding.irb
@@ -4,26 +4,26 @@ class Code
4
4
  class Node
5
5
  class Base10 < Node
6
6
  def initialize(parsed)
7
- @whole = parsed.delete(:whole)
7
+ return if parsed.blank?
8
+ @whole = parsed.delete(:whole).presence
8
9
 
9
10
  if parsed.key?(:exponent)
10
- @exponent = Node::Statement.new(parsed.delete(:exponent))
11
+ @exponent = Node::Statement.new(parsed.delete(:exponent).presence)
11
12
  end
12
-
13
- super(parsed)
14
13
  end
15
14
 
16
15
  def evaluate(**args)
17
- if @exponent
16
+ if @exponent && @whole
18
17
  exponent = @exponent.evaluate(**args)
19
-
20
- if exponent.is_a?(::Code::Object::Integer)
21
- ::Code::Object::Integer.new(@whole.to_i, exponent:)
18
+ if exponent.is_a?(Object::Integer)
19
+ Object::Integer.new(@whole, exponent:)
22
20
  else
23
- ::Code::Object::Decimal.new(@whole, exponent:)
21
+ Object::Decimal.new(@whole, exponent:)
24
22
  end
23
+ elsif @whole
24
+ Object::Integer.new(@whole.to_i)
25
25
  else
26
- ::Code::Object::Integer.new(@whole.to_i)
26
+ Object::Nothing.new
27
27
  end
28
28
  end
29
29
  end
@@ -4,11 +4,16 @@ class Code
4
4
  class Node
5
5
  class Base16 < Node
6
6
  def initialize(parsed)
7
- @base_16 = parsed
7
+ return if parsed.blank?
8
+ @base_16 = parsed.presence
8
9
  end
9
10
 
10
11
  def evaluate(**_args)
11
- ::Code::Object::Integer.new(@base_16.to_i(16))
12
+ if @base_16
13
+ Object::Integer.new(@base_16.to_i(16))
14
+ else
15
+ Object::Nothing.new
16
+ end
12
17
  end
13
18
  end
14
19
  end
@@ -4,11 +4,16 @@ class Code
4
4
  class Node
5
5
  class Base2 < Node
6
6
  def initialize(parsed)
7
- @base_2 = parsed
7
+ return if parsed.blank?
8
+ @base_2 = parsed.presence
8
9
  end
9
10
 
10
11
  def evaluate(**_args)
11
- ::Code::Object::Integer.new(@base_2.to_i(2))
12
+ if @base_2
13
+ Object::Integer.new(@base_2.to_i(2))
14
+ else
15
+ Object::Nothing.new
16
+ end
12
17
  end
13
18
  end
14
19
  end
@@ -4,11 +4,16 @@ class Code
4
4
  class Node
5
5
  class Base8 < Node
6
6
  def initialize(parsed)
7
- @base_8 = parsed
7
+ return if parsed.blank?
8
+ @base_8 = parsed.presence
8
9
  end
9
10
 
10
11
  def evaluate(**_args)
11
- ::Code::Object::Integer.new(@base_8.to_i(8))
12
+ if @base_8
13
+ Object::Integer.new(@base_8.to_i(8))
14
+ else
15
+ Object::Nothing.new
16
+ end
12
17
  end
13
18
  end
14
19
  end
@@ -7,16 +7,17 @@ class Code
7
7
  FALSE_KEYWORD = "false"
8
8
 
9
9
  def initialize(parsed)
10
- @boolean = parsed
10
+ return if parsed.blank?
11
+ @boolean = parsed.presence
11
12
  end
12
13
 
13
14
  def evaluate(**_args)
14
15
  if @boolean == TRUE_KEYWORD
15
- ::Code::Object::Boolean.new(true)
16
+ Object::Boolean.new(true)
16
17
  elsif @boolean == FALSE_KEYWORD
17
- ::Code::Object::Boolean.new(false)
18
+ Object::Boolean.new(false)
18
19
  else
19
- raise NotImplementedError, @boolean
20
+ Object::Nothing.new
20
21
  end
21
22
  end
22
23
  end
@@ -5,14 +5,11 @@ class Code
5
5
  class Call < Node
6
6
  class Block < Node
7
7
  def initialize(parsed)
8
- @parameters =
9
- parsed
10
- .delete(:parameters) { [] }
11
- .map { |parameter| FunctionParameter.new(parameter) }
8
+ return if parsed.blank?
9
+ @parameters = parsed.delete(:parameters) { [] }.presence || []
10
+ @parameters.map! { |parameter| FunctionParameter.new(parameter) }
12
11
 
13
- @body = Code.new(parsed.delete(:body))
14
-
15
- super(parsed)
12
+ @body = Code.new(parsed.delete(:body).presence)
16
13
  end
17
14
 
18
15
  def evaluate(**_args)
@@ -23,21 +20,18 @@ class Code
23
20
  end
24
21
 
25
22
  def initialize(parsed)
26
- @name = parsed.delete(:name)
27
- @arguments =
28
- parsed
29
- .delete(:arguments) { [] }
30
- .map { |argument| CallArgument.new(argument) }
31
-
32
- @block = Call::Block.new(parsed.delete(:block)) if parsed.key?(:block)
23
+ return if parsed.blank?
24
+ @name = parsed.delete(:name).presence
25
+ @arguments = parsed.delete(:arguments).presence || []
26
+ @arguments.map! { |argument| CallArgument.new(argument) }
33
27
 
34
- super(parsed)
28
+ @block = Call::Block.new(parsed.delete(:block).presence) if parsed.key?(:block)
35
29
  end
36
30
 
37
31
  def evaluate(**args)
38
32
  arguments = []
39
33
 
40
- @arguments.each do |argument|
34
+ (@arguments || []).each do |argument|
41
35
  if argument.keyword?
42
36
  if arguments.last&.value.is_a?(Object::Dictionary)
43
37
  arguments.last.value.code_set(
@@ -4,15 +4,19 @@ class Code
4
4
  class Node
5
5
  class CallArgument < Node
6
6
  def initialize(parsed)
7
- @value = Node::Code.new(parsed.delete(:value))
8
- @name = parsed.delete(:name)
7
+ return if parsed.blank?
8
+ @value = Node::Code.new(parsed.delete(:value).presence)
9
+ @name = parsed.delete(:name).presence
9
10
  end
10
11
 
11
12
  def evaluate(**args)
12
13
  if @name
13
- Object::Argument.new(@value.evaluate(**args), name:)
14
+ Object::Argument.new(
15
+ @value&.evaluate(**args) || Object::Nothing.new,
16
+ name:
17
+ )
14
18
  else
15
- Object::Argument.new(@value.evaluate(**args))
19
+ Object::Argument.new(@value&.evaluate(**args) || Object::Nothing.new)
16
20
  end
17
21
  end
18
22
 
@@ -4,13 +4,14 @@ class Code
4
4
  class Node
5
5
  class Code < Node
6
6
  def initialize(parsed)
7
- @statements = parsed.map { |statement| Statement.new(statement) }
7
+ return if parsed.blank?
8
+ @statements = (parsed.presence || []).map { |statement| Statement.new(statement) }
8
9
  end
9
10
 
10
11
  def evaluate(**args)
11
12
  last = Object::Nothing.new
12
13
 
13
- @statements.each do |statement|
14
+ (@statements || []).each do |statement|
14
15
  last = statement.evaluate(**args.merge(object: Object::Global.new))
15
16
  end
16
17
 
@@ -4,23 +4,24 @@ class Code
4
4
  class Node
5
5
  class Decimal < Node
6
6
  def initialize(parsed)
7
- @decimal = parsed.delete(:decimal)
7
+ return if parsed.blank?
8
+ @decimal = parsed.delete(:decimal).presence
8
9
 
9
10
  if parsed.key?(:exponent)
10
- @exponent = Node::Statement.new(parsed.delete(:exponent))
11
+ @exponent = Statement.new(parsed.delete(:exponent).presence)
11
12
  end
12
-
13
- super(parsed)
14
13
  end
15
14
 
16
15
  def evaluate(**args)
17
- if @exponent
18
- ::Code::Object::Decimal.new(
16
+ if @exponent && @decimal
17
+ Object::Decimal.new(
19
18
  @decimal,
20
19
  exponent: @exponent.evaluate(**args)
21
20
  )
21
+ elsif @decimal
22
+ Object::Decimal.new(@decimal)
22
23
  else
23
- ::Code::Object::Decimal.new(@decimal)
24
+ Object::Nothing.new
24
25
  end
25
26
  end
26
27
  end
@@ -5,17 +5,20 @@ class Code
5
5
  class Dictionary < Node
6
6
  class KeyValue < Node
7
7
  def initialize(parsed)
8
+ return if parsed.blank?
8
9
  if parsed.key?(:statement)
9
- @key = Node::Statement.new(parsed.delete(:statement))
10
+ @key = Node::Statement.new(parsed.delete(:statement).presence)
10
11
  elsif parsed.key?(:name)
11
- @key = Node::String.new([{ text: parsed.delete(:name) }])
12
+ @key = Node::String.new([{ text: parsed.delete(:name).presence }])
12
13
  end
13
14
 
14
- @value = Node::Code.new(parsed.delete(:value)) if parsed[:value]
15
+ if parsed[:value].presence
16
+ @value = Node::Code.new(parsed.delete(:value).presence)
17
+ end
15
18
  end
16
19
 
17
20
  def evaluate(**args)
18
- key = @key.evaluate(**args)
21
+ key = @key&.evaluate(**args) || Object::Nothing.new
19
22
 
20
23
  if @value
21
24
  value = @value.evaluate(**args)
@@ -27,14 +30,14 @@ class Code
27
30
  end
28
31
 
29
32
  def initialize(parsed)
30
- parsed = [] if parsed == ""
31
- @key_values =
32
- parsed.map { |key_value| Node::Dictionary::KeyValue.new(key_value) }
33
+ return if parsed.blank?
34
+ @key_values = parsed.presence || []
35
+ @key_values.map! { |key_value| Node::Dictionary::KeyValue.new(key_value) }
33
36
  end
34
37
 
35
38
  def evaluate(**args)
36
39
  ::Code::Object::Dictionary.new(
37
- @key_values.map { |key_value| key_value.evaluate(**args) }.to_h
40
+ (@key_values || []).map { |key_value| key_value.evaluate(**args) }.to_h
38
41
  )
39
42
  end
40
43
  end
@@ -4,15 +4,11 @@ class Code
4
4
  class Node
5
5
  class Function < Node
6
6
  def initialize(parsed)
7
- @parameters = parsed.delete(:parameters) { [] }
8
- @parameters = [] if @parameters.empty?
7
+ return if parsed.blank?
8
+ @parameters = parsed.delete(:parameters).presence || []
9
+ @parameters.map! { |parameter| Node::FunctionParameter.new(parameter) }
9
10
 
10
- @parameters =
11
- @parameters.map { |parameter| Node::FunctionParameter.new(parameter) }
12
-
13
- @body = Node::Code.new(parsed.delete(:body))
14
-
15
- super(parsed)
11
+ @body = Node::Code.new(parsed.delete(:body).presence)
16
12
  end
17
13
 
18
14
  def evaluate(**_args)
@@ -4,9 +4,9 @@ class Code
4
4
  class Node
5
5
  class FunctionParameter < Node
6
6
  def initialize(parsed)
7
- @name = parsed.delete(:name)
8
- @keyword = !parsed.delete(:keyword).nil?
9
- super(parsed)
7
+ return if parsed.blank?
8
+ @name = parsed.delete(:name).presence
9
+ @keyword = parsed.delete(:keyword).present?
10
10
  end
11
11
 
12
12
  def name
data/lib/code/node/if.rb CHANGED
@@ -12,22 +12,23 @@ class Code
12
12
  attr_reader :operator, :statement, :body
13
13
 
14
14
  def initialize(parsed)
15
- @operator = parsed.delete(:operator)
16
- @body = Node::Code.new(parsed.delete(:body))
15
+ return if parsed.blank?
16
+ @operator = parsed.delete(:operator).presence
17
+ @body = Node::Code.new(parsed.delete(:body).presence)
17
18
 
18
- return unless parsed.key?(:statement)
19
-
20
- @statement = Node::Statement.new(parsed.delete(:statement))
19
+ if parsed.key?(:statement)
20
+ @statement = Node::Statement.new(parsed.delete(:statement).presence)
21
+ end
21
22
  end
22
23
  end
23
24
 
24
25
  def initialize(parsed)
25
- @first_operator = parsed.delete(:first_operator)
26
- @first_statement = Node::Statement.new(parsed.delete(:first_statement))
27
- @first_body = Node::Code.new(parsed.delete(:first_body))
28
- @elses =
29
- parsed.delete(:elses) { [] }.map { |elses| Node::If::Else.new(elses) }
30
- super(parsed)
26
+ return if parsed.blank?
27
+ @first_operator = parsed.delete(:first_operator).presence
28
+ @first_statement = Node::Statement.new(parsed.delete(:first_statement).presence)
29
+ @first_body = Node::Code.new(parsed.delete(:first_body).presence)
30
+ @elses = (parsed.delete(:elses).presence || [])
31
+ @elses.map! { |elses| Node::If::Else.new(elses) }
31
32
  end
32
33
 
33
34
  def evaluate(**args)
@@ -38,7 +39,7 @@ class Code
38
39
  @first_statement.evaluate(**args).falsy?
39
40
  @first_body.evaluate(**args)
40
41
  else
41
- @elses.each do |elses|
42
+ (@elses || []).each do |elses|
42
43
  if elses.operator == ELSIF_KEYWORD &&
43
44
  elses.statement.evaluate(**args).truthy?
44
45
  return elses.body.evaluate(**args)
@@ -10,8 +10,9 @@ class Code
10
10
  attr_reader :operator, :statement
11
11
 
12
12
  def initialize(parsed)
13
- @operator = parsed.delete(:operator)
14
- @statement = Statement.new(parsed.delete(:statement))
13
+ return if parsed.blank?
14
+ @operator = parsed.delete(:operator).presence
15
+ @statement = Statement.new(parsed.delete(:statement).presence)
15
16
  end
16
17
 
17
18
  def call?
@@ -20,15 +21,14 @@ class Code
20
21
  end
21
22
 
22
23
  def initialize(parsed)
23
- @first = Statement.new(parsed.delete(:first))
24
- @others =
25
- parsed.delete(:others).map { |operator| Operator.new(operator) }
26
-
27
- super(parsed)
24
+ return if parsed.blank?
25
+ @first = Statement.new(parsed.delete(:first).presence)
26
+ @others = parsed.delete(:others).presence || []
27
+ @others.map! { |operator| Operator.new(operator) }
28
28
  end
29
29
 
30
30
  def evaluate(**args)
31
- first = @first.evaluate(**args)
31
+ first = @first&.evaluate(**args) || Object::Nothing.new
32
32
 
33
33
  @others.reduce(first) do |left, right|
34
34
  if right.call?
@@ -46,11 +46,11 @@ class Code
46
46
  end
47
47
 
48
48
  def resolve(**args)
49
- first = @first.resolve(**args)
49
+ first = @first&.resolve(**args) || Object::Nothing.new
50
50
 
51
51
  list = Object::IdentifierList.new([first])
52
52
 
53
- @others.each do |other|
53
+ (@others || []).each do |other|
54
54
  list.code_append(
55
55
  other.statement.resolve(**args, object: list.code_last)
56
56
  )
@@ -4,13 +4,13 @@ class Code
4
4
  class Node
5
5
  class List < Node
6
6
  def initialize(parsed)
7
- parsed = [] if parsed == ""
8
- @elements = parsed.map { |element| Node::Code.new(element) }
7
+ return if parsed.blank?
8
+ @elements = (parsed.presence || []).map { |element| Node::Code.new(element) }
9
9
  end
10
10
 
11
11
  def evaluate(**args)
12
12
  ::Code::Object::List.new(
13
- @elements.map { |element| element.evaluate(**args) }
13
+ (@elements || []).map { |element| element.evaluate(**args) }
14
14
  )
15
15
  end
16
16
  end
@@ -4,13 +4,17 @@ class Code
4
4
  class Node
5
5
  class Negation < Node
6
6
  def initialize(parsed)
7
- @operator = parsed.delete(:operator)
8
- @right = Node::Statement.new(parsed.delete(:right))
9
- super(parsed)
7
+ return if parsed.blank?
8
+ @operator = parsed.delete(:operator).presence
9
+ @right = Node::Statement.new(parsed.delete(:right).presence)
10
10
  end
11
11
 
12
12
  def evaluate(**args)
13
- @right.evaluate(**args).call(operator: @operator, arguments: [], **args)
13
+ if @right
14
+ @right.evaluate(**args).call(operator: @operator, **args)
15
+ else
16
+ Object::Nothing.new
17
+ end
14
18
  end
15
19
  end
16
20
  end
data/lib/code/node/not.rb CHANGED
@@ -4,13 +4,17 @@ class Code
4
4
  class Node
5
5
  class Not < Node
6
6
  def initialize(parsed)
7
- @operator = parsed.delete(:operator)
8
- @right = Node::Statement.new(parsed.delete(:right))
9
- super(parsed)
7
+ return if parsed.blank?
8
+ @operator = parsed.delete(:operator).presence
9
+ @right = Node::Statement.new(parsed.delete(:right).presence)
10
10
  end
11
11
 
12
12
  def evaluate(**args)
13
- @right.evaluate(**args).call(operator: @operator, arguments: [], **args)
13
+ if @right
14
+ @right.evaluate(**args).call(operator: @operator, **args)
15
+ else
16
+ Object::Nothing.new
17
+ end
14
18
  end
15
19
  end
16
20
  end
@@ -3,12 +3,13 @@
3
3
  class Code
4
4
  class Node
5
5
  class Nothing < Node
6
- def initialize(nothing)
7
- @nothing = nothing
6
+ def initialize(parsed)
7
+ return if parsed.blank?
8
+ @nothing = parsed.presence
8
9
  end
9
10
 
10
11
  def evaluate(**_args)
11
- ::Code::Object::Nothing.new
12
+ Object::Nothing.new
12
13
  end
13
14
  end
14
15
  end
@@ -4,6 +4,8 @@ class Code
4
4
  class Node
5
5
  class Number < Node
6
6
  def initialize(parsed)
7
+ return if parsed.blank?
8
+
7
9
  if parsed.key?(:decimal)
8
10
  @statement = Node::Decimal.new(parsed.delete(:decimal))
9
11
  elsif parsed.key?(:base_16)
@@ -15,12 +17,10 @@ class Code
15
17
  elsif parsed.key?(:base_2)
16
18
  @statement = Node::Base2.new(parsed.delete(:base_2))
17
19
  end
18
-
19
- super(parsed)
20
20
  end
21
21
 
22
22
  def evaluate(**args)
23
- @statement.evaluate(**args)
23
+ @statement&.evaluate(**args) || Object::Nothing.new
24
24
  end
25
25
  end
26
26
  end
@@ -6,23 +6,22 @@ class Code
6
6
  EQUAL = "="
7
7
 
8
8
  def initialize(parsed)
9
- @left = Statement.new(parsed.delete(:left))
10
- @operator = parsed.delete(:operator)
11
- @right = Statement.new(parsed.delete(:right))
12
-
13
- super(parsed)
9
+ return if parsed.blank?
10
+ @left = Statement.new(parsed.delete(:left).presence)
11
+ @operator = parsed.delete(:operator).presence
12
+ @right = Statement.new(parsed.delete(:right).presence)
14
13
  end
15
14
 
16
15
  def evaluate(**args)
17
16
  case @operator
18
17
  when "if"
19
- if @right.evaluate(**args).truthy?
20
- @left.evaluate(**args)
18
+ if (@right&.evaluate(**args) || Object::Nothing.new).truthy?
19
+ @left&.evaluate(**args) || Object::Nothing.new
21
20
  else
22
21
  Object::Nothing.new
23
22
  end
24
23
  when "unless"
25
- if @right.evaluate(**args).truthy?
24
+ if (@right&.evaluate(**args) || Object::Nothing.new).truthy?
26
25
  Object::Nothing.new
27
26
  else
28
27
  @left.evaluate(**args)
@@ -30,24 +29,28 @@ class Code
30
29
  when "while"
31
30
  left = Object::Nothing.new
32
31
 
33
- left = @left.evaluate(**args) while @right.evaluate(**args).truthy?
32
+ while (@right&.evaluate(**args) || Object::Nothing.new).truthy?
33
+ left = @left&.evaluate(**args) || Object::Nothing.new
34
+ end
34
35
 
35
36
  left
36
37
  when "until"
37
38
  left = Object::Nothing.new
38
39
 
39
- left = @left.evaluate(**args) while @right.evaluate(**args).falsy?
40
+ while (@right&.evaluate(**args) || Object::Nothing.new).falsy?
41
+ left = @left&.evaluate(**args) || Object::Nothing.new
42
+ end
40
43
 
41
44
  left
42
45
  when "rescue"
43
46
  begin
44
- @left.evaluate(**args)
47
+ @left&.evaluate(**args) || Object::Nothing.new
45
48
  rescue Error
46
- @right.evaluate(**args)
49
+ @right&.evaluate(**args) || Object::Nothing.new
47
50
  end
48
51
  when /=$/
49
- right = @right.evaluate(**args)
50
- left = @left.resolve(**args)
52
+ right = @right&.evaluate(**args) || Object::Nothing.new
53
+ left = @left&.resolve(**args) || Object::Nothing.new
51
54
 
52
55
  left.call(
53
56
  operator: @operator,
@@ -55,8 +58,8 @@ class Code
55
58
  **args
56
59
  )
57
60
  else
58
- right = @right.evaluate(**args)
59
- left = @left.evaluate(**args)
61
+ right = @right&.evaluate(**args) || Object::Nothing.new
62
+ left = @left&.evaluate(**args) || Object::Nothing.new
60
63
 
61
64
  left.call(
62
65
  operator: @operator,
@@ -4,13 +4,17 @@ class Code
4
4
  class Node
5
5
  class Splat < Node
6
6
  def initialize(parsed)
7
- @operator = parsed.delete(:operator)
8
- @right = Node::Statement.new(parsed.delete(:right))
9
- super(parsed)
7
+ return if parsed.blank?
8
+ @operator = parsed.delete(:operator).presence
9
+ @right = Node::Statement.new(parsed.delete(:right).presence)
10
10
  end
11
11
 
12
12
  def evaluate(**args)
13
- @right.evaluate(**args).call(operator: @operator, arguments: [], **args)
13
+ if @right
14
+ @right.evaluate(**args).call(operator: @operator, **args)
15
+ else
16
+ Object::Nothing.new
17
+ end
14
18
  end
15
19
  end
16
20
  end
@@ -4,29 +4,26 @@ class Code
4
4
  class Node
5
5
  class SquareBracket < Node
6
6
  def initialize(parsed)
7
- @left = Node::Statement.new(parsed.delete(:left))
8
- @statements =
9
- parsed
10
- .delete(:statements)
11
- .map { |statement| Node::Statement.new(statement) }
12
-
13
- super(parsed)
7
+ return if parsed.blank?
8
+ @left = Node::Statement.new(parsed.delete(:left).presence)
9
+ @statements = parsed.delete(:statements).presence || []
10
+ @statements.map! { |statement| Node::Statement.new(statement) }
14
11
  end
15
12
 
16
13
  def evaluate(**args)
17
- left = @left.evaluate(**args)
14
+ left = @left&.evaluate(**args) || Object::Nothing.new
18
15
 
19
- @statements.reduce(left) do |object, statement|
16
+ (@statements || []).reduce(left) do |object, statement|
20
17
  object.code_fetch(statement.evaluate(**args))
21
18
  end
22
19
  end
23
20
 
24
21
  def resolve(**args)
25
- left = @left.resolve(**args)
22
+ left = @left&.resolve(**args) || Object::Nothing.new
26
23
 
27
24
  list = Object::IdentifierList.new([left])
28
25
 
29
- @statements.each do |statement|
26
+ (@statements || []).each do |statement|
30
27
  list.code_append(statement.evaluate(**args))
31
28
  end
32
29
 
@@ -4,6 +4,8 @@ class Code
4
4
  class Node
5
5
  class Statement < Node
6
6
  def initialize(parsed)
7
+ return if parsed.blank?
8
+
7
9
  if parsed.key?(:nothing)
8
10
  @statement = Node::Nothing.new(parsed.delete(:nothing))
9
11
  elsif parsed.key?(:boolean)
@@ -51,16 +53,14 @@ class Code
51
53
  elsif parsed.key?(:square_bracket)
52
54
  @statement = Node::SquareBracket.new(parsed.delete(:square_bracket))
53
55
  end
54
-
55
- super(parsed)
56
56
  end
57
57
 
58
58
  def evaluate(**args)
59
- @statement.evaluate(**args)
59
+ @statement&.evaluate(**args) || Object::Nothing.new
60
60
  end
61
61
 
62
62
  def resolve(**args)
63
- @statement.resolve(**args)
63
+ @statement&.resolve(**args) || Object::Nothing.new
64
64
  end
65
65
  end
66
66
  end
@@ -6,22 +6,25 @@ class Code
6
6
  class Part < Node
7
7
  class Code < Node
8
8
  def initialize(parsed)
9
- @code = Node::Code.new(parsed)
9
+ return if parsed.blank?
10
+ @code = Node::Code.new(parsed.presence)
10
11
  end
11
12
 
12
13
  def evaluate(**args)
13
- @code.evaluate(**args)
14
+ @code&.evaluate(**args) || Object::Nothing.new
14
15
  end
15
16
  end
16
17
 
17
18
  class Text < Node
18
19
  def initialize(parsed)
20
+ return if parsed.blank?
19
21
  @text = parsed
20
22
  end
21
23
 
22
24
  def evaluate(**_args)
23
25
  ::Code::Object::String.new(
24
26
  @text
27
+ .to_s
25
28
  .gsub('\n', "\n")
26
29
  .gsub('\r', "\r")
27
30
  .gsub('\t', "\t")
@@ -34,29 +37,28 @@ class Code
34
37
  end
35
38
 
36
39
  def initialize(parsed)
40
+ return if parsed.blank?
41
+
37
42
  if parsed.key?(:text)
38
- @part = Node::String::Part::Text.new(parsed.delete(:text))
43
+ @part = Node::String::Part::Text.new(parsed.delete(:text).presence)
39
44
  elsif parsed.key?(:code)
40
- @part = Node::String::Part::Code.new(parsed.delete(:code))
45
+ @part = Node::String::Part::Code.new(parsed.delete(:code).presence)
41
46
  end
42
-
43
- super(parsed)
44
47
  end
45
48
 
46
49
  def evaluate(**args)
47
- @part.evaluate(**args)
50
+ @part&.evaluate(**args) || Object::Nothing.new
48
51
  end
49
52
  end
50
53
 
51
54
  def initialize(parsed)
52
- parsed = [] if parsed == ""
53
-
54
- @parts = parsed.map { |part| Node::String::Part.new(part) }
55
+ return if parsed.blank?
56
+ @parts = (parsed.presence || []).map { |part| Node::String::Part.new(part) }
55
57
  end
56
58
 
57
59
  def evaluate(**args)
58
60
  ::Code::Object::String.new(
59
- @parts.map { |part| part.evaluate(**args) }.map(&:to_s).join
61
+ (@parts || []).map { |part| part.evaluate(**args) }.map(&:to_s).join
60
62
  )
61
63
  end
62
64
  end
@@ -4,17 +4,17 @@ class Code
4
4
  class Node
5
5
  class Ternary < Node
6
6
  def initialize(parsed)
7
- @left = Node::Statement.new(parsed.delete(:left))
8
- @middle = Node::Statement.new(parsed.delete(:middle))
9
- @right = Node::Statement.new(parsed.delete(:right)) if parsed.key?(
10
- :right
11
- )
12
- super(parsed)
7
+ return if parsed.blank?
8
+ @left = Node::Statement.new(parsed.delete(:left).presence)
9
+ @middle = Node::Statement.new(parsed.delete(:middle).presence)
10
+ if parsed.key?(:right)
11
+ @right = Node::Statement.new(parsed.delete(:right).presence)
12
+ end
13
13
  end
14
14
 
15
15
  def evaluate(**args)
16
- if @left.evaluate(**args).truthy?
17
- @middle.evaluate(**args)
16
+ if (@left&.evaluate(**args) || Object::Nothing.new).truthy?
17
+ @middle&.evaluate(**args) || Object::Nothing.new
18
18
  elsif @right
19
19
  @right.evaluate(**args)
20
20
  else
@@ -4,13 +4,17 @@ class Code
4
4
  class Node
5
5
  class UnaryMinus < Node
6
6
  def initialize(parsed)
7
- @operator = parsed.delete(:operator)
8
- @right = Node::Statement.new(parsed.delete(:right))
9
- super(parsed)
7
+ return if parsed.blank?
8
+ @operator = parsed.delete(:operator).presence
9
+ @right = Node::Statement.new(parsed.delete(:right).presence)
10
10
  end
11
11
 
12
12
  def evaluate(**args)
13
- @right.evaluate(**args).call(operator: @operator, arguments: [], **args)
13
+ if @right
14
+ @right.evaluate(**args).call(operator: @operator, **args)
15
+ else
16
+ Object::Nothing.new
17
+ end
14
18
  end
15
19
  end
16
20
  end
@@ -8,10 +8,12 @@ class Code
8
8
  LOOP_KEYWORD = "loop"
9
9
 
10
10
  def initialize(parsed)
11
- @operator = parsed.delete(:operator)
12
- @statement = Statement.new(parsed.delete(:statement)) if parsed[:statement]
13
- @body = Code.new(parsed.delete(:body))
14
- super(parsed)
11
+ return if parsed.blank?
12
+ @operator = parsed.delete(:operator).presence
13
+ if parsed.key?(:statement)
14
+ @statement = Statement.new(parsed.delete(:statement))
15
+ end
16
+ @body = Code.new(parsed.delete(:body).presence)
15
17
  end
16
18
 
17
19
  def evaluate(**args)
@@ -19,22 +21,24 @@ class Code
19
21
  when WHILE_KEYWORD
20
22
  last = Object::Nothing.new
21
23
 
22
- last = @body.evaluate(**args) while @statement.evaluate(
23
- **args
24
- ).truthy?
24
+ while (@statement&.evaluate(**args) || Object::Nothing.new).truthy?
25
+ last = @body&.evaluate(**args) || Object::Nothing.new
26
+ end
25
27
 
26
28
  last
27
29
  when UNTIL_KEYWORD
28
30
  last = Object::Nothing.new
29
31
 
30
- last = @body.evaluate(**args) while @statement.evaluate(**args).falsy?
32
+ while (@statement&.evaluate(**args) || Object::Nothing.new).falsy?
33
+ last = @body&.evaluate(**args) || Object::Nothing.new
34
+ end
31
35
 
32
36
  last
33
37
  when LOOP_KEYWORD
34
- loop { @body.evaluate(**args) }
35
- raise NotImplementedError
38
+ loop { @body&.evaluate(**args) || Object::Nothing.new }
39
+ Object::Nothing.new
36
40
  else
37
- raise NotImplementedError, @operator
41
+ Object::Nothing.new
38
42
  end
39
43
  rescue Error::Break => e
40
44
  e.value || Object::Nothing.new
data/lib/code/node.rb CHANGED
@@ -2,14 +2,8 @@
2
2
 
3
3
  class Code
4
4
  class Node
5
- def initialize(parsed)
6
- return if parsed.nil? || parsed.empty?
7
-
8
- raise NotImplementedError, "#{self.class.name}: #{parsed.inspect}"
9
- end
10
-
11
5
  def evaluate(**_args)
12
- raise NotImplementedError, "#{self.class.name}#evaluate"
6
+ Object::Nothing.new
13
7
  end
14
8
 
15
9
  def resolve(...)
@@ -6,8 +6,8 @@ class Code
6
6
  attr_reader :parameters, :body
7
7
 
8
8
  def initialize(parameters:, body:)
9
- @parameters = parameters
10
- @body = body
9
+ @parameters = parameters.presence || []
10
+ @body = body.presence || Node::Code.new
11
11
  end
12
12
 
13
13
  def self.name
@@ -57,8 +57,6 @@ class Code
57
57
  &.value
58
58
  argument = parameter.evaluate(**globals) if argument.nil?
59
59
  context.code_set(parameter.name, argument)
60
- else
61
- raise NotImplementedError
62
60
  end
63
61
  end
64
62
 
data/lib/code/object.rb CHANGED
@@ -292,10 +292,6 @@ class Code
292
292
  end
293
293
 
294
294
  def hash
295
- unless respond_to?(:raw)
296
- raise NotImplementedError, "#{self.class.name}#hash"
297
- end
298
-
299
295
  [self.class, raw].hash
300
296
  end
301
297
 
@@ -309,7 +305,7 @@ class Code
309
305
  end
310
306
 
311
307
  def to_s
312
- raise NotImplementedError, "#{self.class.name}#to_s"
308
+ raw.to_s
313
309
  end
314
310
 
315
311
  def inspect
@@ -325,7 +321,7 @@ class Code
325
321
  end
326
322
 
327
323
  def as_json(...)
328
- raise NotImplementedError, "#{self.class}#as_json"
324
+ raw.as_json
329
325
  end
330
326
  end
331
327
  end
@@ -20,7 +20,7 @@ class Code
20
20
  end
21
21
 
22
22
  def root
23
- present | whitespace?.then { [] }
23
+ present | whitespace?
24
24
  end
25
25
  end
26
26
  end
@@ -4,7 +4,7 @@ class Code
4
4
  class Parser
5
5
  class LeftOperation < Language
6
6
  def statement
7
- raise NotImplementedError
7
+ Statement
8
8
  end
9
9
 
10
10
  def whitespace
@@ -16,7 +16,7 @@ class Code
16
16
  end
17
17
 
18
18
  def operator
19
- raise NotImplementedError
19
+ str("")
20
20
  end
21
21
 
22
22
  def right_statement
@@ -32,8 +32,8 @@ class Code
32
32
  end
33
33
 
34
34
  def element
35
- (whitespace? << code_present << (whitespace? << comma).maybe) |
36
- (whitespace? << code << whitespace? << comma)
35
+ (whitespace? << code_present << (whitespace? << comma.ignore).maybe) |
36
+ (whitespace? << code << whitespace? << comma.ignore)
37
37
  end
38
38
 
39
39
  def root
@@ -4,7 +4,7 @@ class Code
4
4
  class Parser
5
5
  class RightOperation < Language
6
6
  def statement
7
- raise NotImplementedError
7
+ Statement
8
8
  end
9
9
 
10
10
  def whitespace
@@ -16,7 +16,7 @@ class Code
16
16
  end
17
17
 
18
18
  def operator
19
- raise NotImplementedError
19
+ str("")
20
20
  end
21
21
 
22
22
  def right_statement
@@ -37,14 +37,14 @@ class Code
37
37
  end
38
38
 
39
39
  def without_newline
40
- (space | multi_line_comment).repeat(1)
40
+ (space | multi_line_comment).repeat(1).ignore
41
41
  end
42
42
 
43
43
  def root
44
44
  (
45
45
  space | newline | hash_comment | double_slash_comment |
46
46
  multi_line_comment
47
- ).repeat(1) | any.absent
47
+ ).repeat(1).ignore | any.absent
48
48
  end
49
49
  end
50
50
  end
data/lib/code/type/sig.rb CHANGED
@@ -40,11 +40,11 @@ class Code
40
40
  end
41
41
 
42
42
  def actual_arguments
43
- args[:arguments].map(&:value)
43
+ args.fetch(:arguments, []).map(&:value)
44
44
  end
45
45
 
46
46
  def operator
47
- args[:operator] || "call"
47
+ args.fetch(:operator, nil) || "call"
48
48
  end
49
49
 
50
50
  def function
data/lib/code/type.rb CHANGED
@@ -3,11 +3,11 @@
3
3
  class Code
4
4
  class Type
5
5
  def name
6
- raise NotImplementedError, "#{self.class}#name"
6
+ "Type"
7
7
  end
8
8
 
9
- def valid?(argument)
10
- raise NotImplementedError, "#{self.class}#valid?"
9
+ def valid?(_argument)
10
+ false
11
11
  end
12
12
 
13
13
  def valid_for?(expected:, actual:)
data/lib/code/version.rb CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  require_relative "../code"
4
4
 
5
- Code::Version = Gem::Version.new("0.10.3")
5
+ Code::Version = Gem::Version.new("0.11.0")
data/lib/code-ruby.rb CHANGED
@@ -4,6 +4,7 @@ require "active_support"
4
4
  require "active_support/core_ext/date/conversions"
5
5
  require "active_support/core_ext/numeric/time"
6
6
  require "active_support/core_ext/object/json"
7
+ require "active_support/core_ext/object/blank"
7
8
  require "bigdecimal"
8
9
  require "json"
9
10
  require "language-ruby"
data/spec/code_spec.rb CHANGED
@@ -146,10 +146,10 @@ RSpec.describe Code do
146
146
  ["a = 0 [1, 2, 3].each { |i| next if i == 2 a += i } a", "4"],
147
147
  ["[1, 2, 3].map { |i| next if i == 2 i ** 2}", "[1, nothing, 9]"],
148
148
  ["[1, 2, 3].map { |i| next(0) if i.even? i ** 2}", "[1, 0, 9]"],
149
- ["2.days.ago.past?", "true"],
150
- ["2.days.from_now.past?", "false"],
151
- ["2.days.ago.future?", "false"],
152
- ["2.days.from_now.future?", "true"],
149
+ %w[2.days.ago.past? true],
150
+ %w[2.days.from_now.past? false],
151
+ %w[2.days.ago.future? false],
152
+ %w[2.days.from_now.future? true]
153
153
  ].each do |input, expected|
154
154
  it "#{input} == #{expected}" do
155
155
  expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.3
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Marié
@@ -95,6 +95,7 @@ files:
95
95
  - Gemfile.lock
96
96
  - README.md
97
97
  - bin/code
98
+ - bin/console
98
99
  - code-ruby.gemspec
99
100
  - lib/code-ruby.rb
100
101
  - lib/code.rb