code-ruby 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -2
  3. data/bin/code +6 -0
  4. data/lib/code/node/base_10.rb +2 -2
  5. data/lib/code/node/base_16.rb +1 -5
  6. data/lib/code/node/base_2.rb +1 -5
  7. data/lib/code/node/base_8.rb +1 -5
  8. data/lib/code/node/call.rb +4 -4
  9. data/lib/code/node/code.rb +2 -1
  10. data/lib/code/node/decimal.rb +1 -4
  11. data/lib/code/node/dictionary.rb +6 -2
  12. data/lib/code/node/function.rb +3 -3
  13. data/lib/code/node/function_parameter.rb +5 -1
  14. data/lib/code/node/if.rb +2 -1
  15. data/lib/code/node/list.rb +2 -1
  16. data/lib/code/node/statement.rb +23 -23
  17. data/lib/code/node/string.rb +2 -1
  18. data/lib/code/object/argument.rb +4 -3
  19. data/lib/code/object/boolean.rb +5 -4
  20. data/lib/code/object/class.rb +4 -3
  21. data/lib/code/object/code.rb +33 -0
  22. data/lib/code/object/context.rb +7 -5
  23. data/lib/code/object/date.rb +31 -6
  24. data/lib/code/object/decimal.rb +36 -31
  25. data/lib/code/object/dictionary.rb +4 -4
  26. data/lib/code/object/duration.rb +8 -5
  27. data/lib/code/object/function.rb +42 -26
  28. data/lib/code/object/global.rb +58 -38
  29. data/lib/code/object/integer.rb +23 -26
  30. data/lib/code/object/list.rb +5 -5
  31. data/lib/code/object/nothing.rb +2 -4
  32. data/lib/code/object/parameter.rb +43 -0
  33. data/lib/code/object/range.rb +13 -11
  34. data/lib/code/object/string.rb +7 -7
  35. data/lib/code/object/time.rb +15 -8
  36. data/lib/code/object.rb +102 -5
  37. data/lib/code/parser.rb +1 -1
  38. data/lib/code/type.rb +10 -2
  39. data/lib/code/version.rb +1 -1
  40. data/lib/code-ruby.rb +6 -0
  41. data/lib/code.rb +8 -5
  42. data/spec/code/object/dictionary_spec.rb +0 -2
  43. data/spec/code_spec.rb +122 -16
  44. metadata +4 -3
  45. data/lib/code/object/number.rb +0 -11
@@ -2,12 +2,30 @@
2
2
 
3
3
  class Code
4
4
  class Object
5
- class Function < ::Code::Object
5
+ class Function < Object
6
6
  attr_reader :parameters, :body
7
7
 
8
- def initialize(parameters:, body:)
9
- @parameters = parameters.presence || []
10
- @body = body.presence || Node::Code.new
8
+ def initialize(*args, **_kargs, &_block)
9
+ parameters = args.first.presence || List.new
10
+ parameters = parameters.raw if parameters.is_an?(Object)
11
+ @parameters = List.new(parameters)
12
+ @parameters.raw.map! do |parameter|
13
+ if parameter.is_a?(Node::FunctionParameter)
14
+ Parameter.new(
15
+ Dictionary.new({
16
+ String.new(:name) => String.new(parameter.name),
17
+ String.new(:keyword) => Boolean.new(parameter.keyword?),
18
+ String.new(:regular_splat) => Boolean.new(parameter.regular_splat?),
19
+ String.new(:keyword_splat) => Boolean.new(parameter.keyword_splat?),
20
+ String.new(:default) => Code.new(parameter.default),
21
+ })
22
+ )
23
+ else
24
+ Parameter.new(parameter)
25
+ end
26
+ end
27
+ @body = Code.new(args.second.presence || Nothing.new)
28
+ super
11
29
  end
12
30
 
13
31
  def self.name
@@ -17,7 +35,7 @@ class Code
17
35
  def call(**args)
18
36
  operator = args.fetch(:operator, nil)
19
37
  arguments = args.fetch(:arguments, [])
20
- globals = multi_fetch(args, *::Code::GLOBALS)
38
+ globals = multi_fetch(args, *GLOBALS)
21
39
 
22
40
  case operator.to_s
23
41
  when "", "call"
@@ -29,27 +47,21 @@ class Code
29
47
  end
30
48
 
31
49
  def code_call(*arguments, **globals)
32
- context = Context.new({}, parent: globals[:context])
50
+ context = Context.new({}, globals[:context])
33
51
 
34
- parameters.each.with_index do |parameter, index|
35
- if parameter.regular?
36
- if parameter.regular_splat?
37
- context.code_set(
38
- parameter.name,
39
- List.new(arguments.select(&:regular?).map(&:value))
40
- )
41
- elsif parameter.keyword_splat?
42
- context.code_set(
43
- parameter.name,
44
- Dictionary.new(
45
- arguments.select(&:keyword?).map(&:name_value).to_h
46
- )
52
+ parameters.raw.each.with_index do |parameter, index|
53
+ if parameter.regular_splat?
54
+ context.code_set(
55
+ parameter.name,
56
+ List.new(arguments.select(&:regular?).map(&:value))
57
+ )
58
+ elsif parameter.keyword_splat?
59
+ context.code_set(
60
+ parameter.name,
61
+ Dictionary.new(
62
+ arguments.select(&:keyword?).map(&:name_value).to_h
47
63
  )
48
- else
49
- argument = arguments[index]&.value
50
- argument = parameter.evaluate(**globals) if argument.nil?
51
- context.code_set(parameter.name, argument)
52
- end
64
+ )
53
65
  elsif parameter.keyword?
54
66
  argument =
55
67
  arguments
@@ -57,6 +69,10 @@ class Code
57
69
  &.value
58
70
  argument = parameter.evaluate(**globals) if argument.nil?
59
71
  context.code_set(parameter.name, argument)
72
+ elsif parameter.regular?
73
+ argument = arguments[index]&.value
74
+ argument = parameter.evaluate(**globals) if argument.nil?
75
+ context.code_set(parameter.name, argument)
60
76
  end
61
77
  end
62
78
 
@@ -68,10 +84,10 @@ class Code
68
84
  end
69
85
 
70
86
  def signature_for_call
71
- parameters.inject([]) do |signature, parameter|
87
+ parameters.raw.inject([]) do |signature, parameter|
72
88
  if parameter.keyword?
73
89
  if signature.last.is_a?(::Hash)
74
- signature.last[parameter.name] = Object
90
+ signature.last.code_set(parameter.name, Object)
75
91
  signature
76
92
  else
77
93
  signature + [{ parameter.name => Object }]
@@ -2,11 +2,15 @@
2
2
 
3
3
  class Code
4
4
  class Object
5
- class Global < ::Code::Object
5
+ class Global < Object
6
6
  def self.name
7
7
  "Global"
8
8
  end
9
9
 
10
+ def initialize(...)
11
+ super
12
+ end
13
+
10
14
  def call(**args)
11
15
  operator = args.fetch(:operator, nil)
12
16
  arguments = args.fetch(:arguments, [])
@@ -14,62 +18,78 @@ class Code
14
18
  context = args.fetch(:context)
15
19
  globals = multi_fetch(args, *GLOBALS)
16
20
  value = arguments.first&.value
21
+ values = arguments.map(&:value)
17
22
 
18
23
  case operator.to_s
19
24
  when "Boolean"
20
- sig(args) { Object.maybe }
21
- value ? value.code_to_boolean : Class.new(Boolean)
25
+ sig(args) { Object.repeat }
26
+ value ? Boolean.new(*values) : Class.new(Boolean)
22
27
  when "break"
23
- sig(args) { Object.maybe }
28
+ sig(args) { Object.repeat }
24
29
  raise Error::Break, value || Nothing.new
25
30
  when "next"
26
- sig(args) { Object.maybe }
31
+ sig(args) { Object.repeat }
27
32
  raise Error::Next, value || Nothing.new
28
33
  when "Class"
29
- sig(args) { Object.maybe }
30
- value ? value.code_to_class : Class.new(Class)
34
+ sig(args) { Object.repeat }
35
+ value ? Class.new(*values) : Class.new(Class)
31
36
  when "Date"
32
- sig(args) { Object.maybe }
33
- value ? value.code_to_date : Class.new(Date)
37
+ sig(args) { Object.repeat }
38
+ value ? Date.new(*values) : Class.new(Date)
34
39
  when "Decimal"
35
- sig(args) { Object.maybe }
36
- value ? value.code_to_decimal : Class.new(Decimal)
40
+ sig(args) { Object.repeat }
41
+ value ? Decimal.new(*values) : Class.new(Decimal)
37
42
  when "Dictionary"
38
- sig(args) { Object.maybe }
39
- value ? value.code_to_dictionnary : Class.new(Dictionary)
40
- when "fetch"
41
- sig(args) { [Object, Function.maybe] }
42
- context.code_fetch(*arguments.map(&:value), **globals)
43
+ sig(args) { Object.repeat }
44
+ value ? Dictionary.new(*values) : Class.new(Dictionary)
45
+ when "Duration"
46
+ sig(args) { Object.repeat }
47
+ value ? Duration.new(*values) : Class.new(Duration)
43
48
  when "Function"
44
- sig(args) { Object.maybe }
45
- value ? value.code_to_function : Class.new(Function)
49
+ sig(args)
50
+ Class.new(Function)
46
51
  when "Integer"
47
- sig(args) { Object.maybe }
48
- value ? value.code_to_integer : Class.new(Integer)
52
+ sig(args) { Object.repeat }
53
+ value ? Integer.new(*values) : Class.new(Integer)
49
54
  when "List"
50
- sig(args) { Object.maybe }
51
- value ? value.code_to_list : Class.new(List)
55
+ sig(args) { Object.repeat }
56
+ value ? List.new(*values) : Class.new(List)
52
57
  when "Nothing"
53
- sig(args) { Object.maybe }
54
- value ? value.code_to_nothing : Class.new(Nothing)
55
- when "Number"
56
- sig(args) { Object.maybe }
57
- value ? value.code_to_number : Class.new(Number)
58
+ sig(args) { Object.repeat }
59
+ value ? Nothing.new(*values) : Class.new(Nothing)
60
+ when "context"
61
+ sig(args)
62
+ context
58
63
  when "Object"
59
- sig(args) { Object.maybe }
60
- value ? value.code_to_object : Class.new(Object)
64
+ sig(args)
65
+ Class.new(Object)
61
66
  when "Range"
62
- sig(args) { Object.maybe }
63
- value ? value.code_to_range : Class.new(Range)
67
+ sig(args) { Object.repeat }
68
+ value ? Range.new(*values) : Class.new(Range)
64
69
  when "String"
65
- sig(args) { Object.maybe }
66
- value ? value.code_to_string : Class.new(String)
70
+ sig(args) { Object.repeat }
71
+ value ? String.new(*values) : Class.new(String)
67
72
  when "Time"
68
- sig(args) { Object.maybe }
69
- value ? value.code_to_time : Class.new(Time)
70
- when "context"
71
- sig(args) { String.maybe }
72
- value ? context.code_get(value) || Nothing.new : context
73
+ sig(args) { Object.repeat }
74
+ value ? Time.new(*values) : Class.new(Time)
75
+ when "Context"
76
+ sig(args) { Object.repeat }
77
+ value ? Context.new(*values) : Class.new(Context)
78
+ when "Code"
79
+ sig(args) { Object.repeat }
80
+ value ? Code.new(*values) : Class.new(Code)
81
+ when "Argument"
82
+ sig(args) { Object.repeat }
83
+ value ? Argument.new(*values) : Class.new(Argument)
84
+ when "Parameter"
85
+ sig(args) { Object.repeat }
86
+ value ? Parameter.new(*values) : Class.new(Parameter)
87
+ when "Range"
88
+ sig(args) { Object.repeat }
89
+ value ? Range.new(*values) : Class.new(Range)
90
+ when "IdentifierList"
91
+ sig(args) { Object.repeat }
92
+ value ? IdentifierList.new(*values) : Class.new(IdentifierList)
73
93
  when "evaluate"
74
94
  sig(args) { Object }
75
95
  Code.evaluate(value.to_s)
@@ -2,18 +2,15 @@
2
2
 
3
3
  class Code
4
4
  class Object
5
- class Integer < Number
6
- attr_reader :raw
7
-
8
- def initialize(whole, exponent: nil)
9
- whole = whole.raw if whole.is_a?(Integer)
10
- @raw = whole.to_i
11
- return unless exponent
12
-
13
- exponent = exponent.raw if exponent.is_a?(Number)
14
- @raw *= 10**exponent
5
+ class Integer < Object
6
+ def initialize(*args, **_kargs, &_block)
7
+ whole = args.first || 0
8
+ exponent = args.second || 0
9
+ whole = whole.raw if whole.is_an?(Object)
10
+ exponent = exponent.raw if exponent.is_an?(Object)
11
+ @raw = whole.to_i * 10**exponent
15
12
  rescue FloatDomainError => e
16
- raise Error, e.message
13
+ raise Error, "#{decimal.inspect} * 10**#{exponent.inspect} is invalid"
17
14
  end
18
15
 
19
16
  def self.name
@@ -28,49 +25,49 @@ class Code
28
25
 
29
26
  case operator.to_s
30
27
  when "%", "modulo"
31
- sig(args) { Number }
28
+ sig(args) { Integer | Decimal }
32
29
  code_modulo(value)
33
30
  when "&", "bitwise_and"
34
- sig(args) { Number }
31
+ sig(args) { Integer | Decimal }
35
32
  code_bitwise_and(value)
36
33
  when "*", "multiplication", "×"
37
- sig(args) { Number | String }
34
+ sig(args) { Integer | Decimal | String }
38
35
  code_multiplication(value)
39
36
  when "**", "power"
40
- sig(args) { Number }
37
+ sig(args) { Integer | Decimal }
41
38
  code_power(value)
42
39
  when "+", "plus", "self"
43
40
  sig(args) { Object.maybe }
44
41
  value ? code_plus(value) : code_self
45
42
  when "-", "minus", "unary_minus"
46
- sig(args) { Number.maybe }
43
+ sig(args) { Integer | Decimal.maybe }
47
44
  value ? code_minus(value) : code_unary_minus
48
45
  when "/", "division", "÷"
49
- sig(args) { Number }
46
+ sig(args) { Integer | Decimal }
50
47
  code_division(value)
51
48
  when "<", "inferior"
52
- sig(args) { Number }
49
+ sig(args) { Integer | Decimal }
53
50
  code_inferior(value)
54
51
  when "<<", "left_shift"
55
- sig(args) { Number }
52
+ sig(args) { Integer | Decimal }
56
53
  code_left_shift(value)
57
54
  when "<=", "inferior_or_equal"
58
- sig(args) { Number }
55
+ sig(args) { Integer | Decimal }
59
56
  code_inferior_or_equal(value)
60
57
  when "<=>", "compare"
61
- sig(args) { Number }
58
+ sig(args) { Integer | Decimal }
62
59
  code_compare(value)
63
60
  when ">", "superior"
64
- sig(args) { Number }
61
+ sig(args) { Integer | Decimal }
65
62
  code_superior(value)
66
63
  when ">=", "superior_or_equal"
67
- sig(args) { Number }
64
+ sig(args) { Integer | Decimal }
68
65
  code_superior_or_equal(value)
69
66
  when ">>", "right_shift"
70
- sig(args) { Number }
67
+ sig(args) { Integer | Decimal }
71
68
  code_right_shift(value)
72
69
  when "^", "bitwise_xor"
73
- sig(args) { Number }
70
+ sig(args) { Integer | Decimal }
74
71
  code_bitwise_xor(value)
75
72
  when "abs"
76
73
  sig(args)
@@ -163,7 +160,7 @@ class Code
163
160
  sig(args)
164
161
  code_zero?
165
162
  when "|", "bitwise_or"
166
- sig(args) { Number }
163
+ sig(args) { Integer | Decimal }
167
164
  code_bitwise_or(value)
168
165
  else
169
166
  super
@@ -2,12 +2,12 @@
2
2
 
3
3
  class Code
4
4
  class Object
5
- class List < ::Code::Object
6
- attr_reader :raw
7
-
8
- def initialize(raw = [])
9
- raw = raw.raw if raw.is_a?(List)
5
+ class List < Object
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first || Nothing.new
8
+ raw = raw.raw if raw.is_an?(Object)
10
9
  @raw = raw.to_a
10
+ super
11
11
  end
12
12
 
13
13
  def self.name
@@ -2,10 +2,8 @@
2
2
 
3
3
  class Code
4
4
  class Object
5
- class Nothing < ::Code::Object
6
- attr_reader :raw
7
-
8
- def initialize
5
+ class Nothing < Object
6
+ def initialize(*_args, **_kargs, &_block)
9
7
  @raw = nil
10
8
  end
11
9
 
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Code
4
+ class Object
5
+ class Parameter < Object
6
+ attr_reader :name, :keyword, :regular_splat, :keyword_splat, :default
7
+
8
+ def self.name
9
+ "Parameter"
10
+ end
11
+
12
+ def initialize(*args, **_kargs, &_block)
13
+ @raw = Dictionary.new(args.first.presence || {})
14
+ @name = String.new(@raw.code_get(String.new(:name)))
15
+ @keyword = Boolean.new(@raw.code_get(String.new(:keyword)))
16
+ @regular_splat = Boolean.new(@raw.code_get(String.new(:regular_splat)))
17
+ @keyword_splat = Boolean.new(@raw.code_get(String.new(:keyword_splat)))
18
+ @default = Code.new(@raw.code_get(String.new(:default)))
19
+ super
20
+ end
21
+
22
+ def evaluate(...)
23
+ default.evaluate(...)
24
+ end
25
+
26
+ def regular?
27
+ !keyword?
28
+ end
29
+
30
+ def keyword?
31
+ keyword.truthy?
32
+ end
33
+
34
+ def regular_splat?
35
+ regular_splat.truthy?
36
+ end
37
+
38
+ def keyword_splat?
39
+ keyword_splat.truthy?
40
+ end
41
+ end
42
+ end
43
+ end
@@ -3,13 +3,15 @@
3
3
  class Code
4
4
  class Object
5
5
  class Range < Object
6
- attr_reader :raw, :exclude_end, :left, :right
6
+ attr_reader :left, :right, :options, :exclude_end
7
7
 
8
- def initialize(left, right, exclude_end: false)
9
- @left = left
10
- @right = right
11
- @exclude_end = !exclude_end.nil?
12
- @raw = ::Range.new(left, right, exclude_end)
8
+ def initialize(*args, **_kargs, &_block)
9
+ @left = args.first.presence || Integer.new(0)
10
+ @right = args.second.presence || Integer.new(0)
11
+ @options = Dictionary.new(args.third.presence || Dictionary.new)
12
+ @exclude_end = Boolean.new(@options.code_get(String.new(:exclude_end)))
13
+ @raw = ::Range.new(left, right, exclude_end?)
14
+ super
13
15
  end
14
16
 
15
17
  def self.name
@@ -45,7 +47,7 @@ class Code
45
47
  sig(args) { Function }
46
48
  code_select(value, **globals)
47
49
  when "step"
48
- sig(args) { Number }
50
+ sig(args) { Integer | Decimal }
49
51
  code_step(value)
50
52
  when "to_list"
51
53
  sig(args)
@@ -102,6 +104,10 @@ class Code
102
104
  )
103
105
  end
104
106
 
107
+ def exclude_end?
108
+ exclude_end.truthy?
109
+ end
110
+
105
111
  def code_step(argument)
106
112
  list = List.new
107
113
  element = left
@@ -127,10 +133,6 @@ class Code
127
133
  List.new(raw.to_a)
128
134
  end
129
135
 
130
- def exclude_end?
131
- !!exclude_end
132
- end
133
-
134
136
  def inspect
135
137
  to_s
136
138
  end
@@ -3,11 +3,11 @@
3
3
  class Code
4
4
  class Object
5
5
  class String < Object
6
- attr_reader :raw
7
-
8
- def initialize(string)
9
- string = string.raw if string.is_a?(String)
10
- @raw = string.to_s
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first || Nothing.new
8
+ raw = raw.raw if raw.is_a?(Object)
9
+ @raw = raw.to_s
10
+ super
11
11
  end
12
12
 
13
13
  def self.name
@@ -25,7 +25,7 @@ class Code
25
25
  sig(args)
26
26
  code_to_function(**globals)
27
27
  when "*"
28
- sig(args) { Number }
28
+ sig(args) { Integer | Decimal }
29
29
  code_multiplication(value)
30
30
  when "+"
31
31
  sig(args) { Object }
@@ -65,7 +65,7 @@ class Code
65
65
  end
66
66
 
67
67
  def code_to_function(**globals)
68
- Code::Node::Code.new(
68
+ Node::Code.new(
69
69
  [
70
70
  {
71
71
  function: {
@@ -5,13 +5,12 @@ class Code
5
5
  class Time < Object
6
6
  DEFAULT_ZONE = "Etc/UTC"
7
7
 
8
- attr_reader :raw
9
-
10
- def initialize(time)
8
+ def initialize(*args, **_kargs, &_block)
11
9
  ::Time.zone ||= DEFAULT_ZONE
12
- time = time.raw if time.is_a?(Time)
13
- time = time.to_s if time.is_a?(::Time)
14
- @raw = ::Time.zone.parse(time)
10
+ raw = args.first.presence || ::Time.zone.now
11
+ raw = raw.raw if raw.is_an?(Object)
12
+ @raw = ::Time.zone.parse(raw.to_s)
13
+ super
15
14
  end
16
15
 
17
16
  def self.name
@@ -28,6 +27,9 @@ class Code
28
27
  when "tomorrow"
29
28
  sig(args)
30
29
  code_tomorrow
30
+ when "yesterday"
31
+ sig(args)
32
+ code_yesterday
31
33
  else
32
34
  super
33
35
  end
@@ -35,12 +37,17 @@ class Code
35
37
 
36
38
  def self.code_tomorrow
37
39
  ::Time.zone ||= DEFAULT_ZONE
38
- new(::Time.zone.tomorrow.beginning_of_day)
40
+ new(::Time.zone.tomorrow)
41
+ end
42
+
43
+ def self.code_yesterday
44
+ ::Time.zone ||= DEFAULT_ZONE
45
+ new(::Time.zone.yesterday)
39
46
  end
40
47
 
41
48
  def self.code_now
42
49
  ::Time.zone ||= DEFAULT_ZONE
43
- new(::Time.zone.now.beginning_of_day)
50
+ new(::Time.zone.now)
44
51
  end
45
52
 
46
53
  def call(**args)