code-ruby 0.2.4

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 (140) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +9 -0
  3. data/.github/workflows/rspec.yml +14 -0
  4. data/.gitignore +2 -0
  5. data/.prettierrc +3 -0
  6. data/.rspec +1 -0
  7. data/CHANGELOG.md +31 -0
  8. data/Gemfile +3 -0
  9. data/Gemfile.lock +70 -0
  10. data/LICENSE +7 -0
  11. data/README.md +103 -0
  12. data/TODO.md +1 -0
  13. data/bin/template +39 -0
  14. data/code-ruby.gemspec +22 -0
  15. data/docs/euler/1.template +14 -0
  16. data/docs/euler/2.template +16 -0
  17. data/docs/euler/3.template +16 -0
  18. data/docs/euler/4.template +11 -0
  19. data/docs/euler/5.template +14 -0
  20. data/docs/precedence.template +94 -0
  21. data/lib/code/error.rb +15 -0
  22. data/lib/code/node/base_10_decimal.rb +32 -0
  23. data/lib/code/node/base_10_integer.rb +32 -0
  24. data/lib/code/node/base_10_number.rb +19 -0
  25. data/lib/code/node/base_16_number.rb +19 -0
  26. data/lib/code/node/base_2_number.rb +19 -0
  27. data/lib/code/node/base_8_number.rb +19 -0
  28. data/lib/code/node/block.rb +17 -0
  29. data/lib/code/node/boolean.rb +22 -0
  30. data/lib/code/node/call.rb +52 -0
  31. data/lib/code/node/call_argument.rb +37 -0
  32. data/lib/code/node/chained_call.rb +38 -0
  33. data/lib/code/node/code.rb +16 -0
  34. data/lib/code/node/defined.rb +19 -0
  35. data/lib/code/node/dictionnary.rb +22 -0
  36. data/lib/code/node/dictionnary_key_value.rb +23 -0
  37. data/lib/code/node/equal.rb +36 -0
  38. data/lib/code/node/function.rb +17 -0
  39. data/lib/code/node/function_argument.rb +45 -0
  40. data/lib/code/node/group.rb +13 -0
  41. data/lib/code/node/if.rb +55 -0
  42. data/lib/code/node/if_modifier.rb +48 -0
  43. data/lib/code/node/keyword_call_argument.rb +30 -0
  44. data/lib/code/node/keyword_function_argument.rb +33 -0
  45. data/lib/code/node/list.rb +19 -0
  46. data/lib/code/node/name.rb +50 -0
  47. data/lib/code/node/negation.rb +33 -0
  48. data/lib/code/node/not_keyword.rb +13 -0
  49. data/lib/code/node/nothing.rb +12 -0
  50. data/lib/code/node/number.rb +23 -0
  51. data/lib/code/node/operation.rb +33 -0
  52. data/lib/code/node/or_keyword.rb +34 -0
  53. data/lib/code/node/power.rb +16 -0
  54. data/lib/code/node/range.rb +31 -0
  55. data/lib/code/node/regular_call_argument.rb +34 -0
  56. data/lib/code/node/regular_function_argument.rb +36 -0
  57. data/lib/code/node/rescue.rb +16 -0
  58. data/lib/code/node/statement.rb +81 -0
  59. data/lib/code/node/string.rb +17 -0
  60. data/lib/code/node/ternary.rb +26 -0
  61. data/lib/code/node/unary_minus.rb +22 -0
  62. data/lib/code/node/while.rb +42 -0
  63. data/lib/code/node.rb +14 -0
  64. data/lib/code/object/argument.rb +41 -0
  65. data/lib/code/object/boolean.rb +27 -0
  66. data/lib/code/object/decimal.rb +54 -0
  67. data/lib/code/object/dictionnary.rb +55 -0
  68. data/lib/code/object/function.rb +64 -0
  69. data/lib/code/object/integer.rb +116 -0
  70. data/lib/code/object/list.rb +217 -0
  71. data/lib/code/object/nothing.rb +23 -0
  72. data/lib/code/object/number.rb +6 -0
  73. data/lib/code/object/range.rb +158 -0
  74. data/lib/code/object/string.rb +68 -0
  75. data/lib/code/object.rb +130 -0
  76. data/lib/code/parser/addition.rb +29 -0
  77. data/lib/code/parser/and_operator.rb +28 -0
  78. data/lib/code/parser/bitwise_and.rb +28 -0
  79. data/lib/code/parser/bitwise_or.rb +29 -0
  80. data/lib/code/parser/boolean.rb +14 -0
  81. data/lib/code/parser/call.rb +90 -0
  82. data/lib/code/parser/code.rb +19 -0
  83. data/lib/code/parser/defined.rb +20 -0
  84. data/lib/code/parser/dictionnary.rb +41 -0
  85. data/lib/code/parser/equal.rb +42 -0
  86. data/lib/code/parser/equality.rb +36 -0
  87. data/lib/code/parser/function.rb +57 -0
  88. data/lib/code/parser/greater_than.rb +33 -0
  89. data/lib/code/parser/group.rb +17 -0
  90. data/lib/code/parser/if.rb +33 -0
  91. data/lib/code/parser/if_modifier.rb +28 -0
  92. data/lib/code/parser/list.rb +29 -0
  93. data/lib/code/parser/multiplication.rb +30 -0
  94. data/lib/code/parser/name.rb +89 -0
  95. data/lib/code/parser/negation.rb +19 -0
  96. data/lib/code/parser/not_keyword.rb +21 -0
  97. data/lib/code/parser/nothing.rb +17 -0
  98. data/lib/code/parser/number.rb +98 -0
  99. data/lib/code/parser/or_keyword.rb +29 -0
  100. data/lib/code/parser/or_operator.rb +28 -0
  101. data/lib/code/parser/power.rb +25 -0
  102. data/lib/code/parser/range.rb +25 -0
  103. data/lib/code/parser/rescue.rb +23 -0
  104. data/lib/code/parser/shift.rb +31 -0
  105. data/lib/code/parser/statement.rb +8 -0
  106. data/lib/code/parser/string.rb +72 -0
  107. data/lib/code/parser/ternary.rb +25 -0
  108. data/lib/code/parser/unary_minus.rb +13 -0
  109. data/lib/code/parser/while.rb +25 -0
  110. data/lib/code/parser.rb +4 -0
  111. data/lib/code-ruby.rb +11 -0
  112. data/lib/code.rb +29 -0
  113. data/lib/template/node/code_part.rb +13 -0
  114. data/lib/template/node/part.rb +19 -0
  115. data/lib/template/node/template.rb +15 -0
  116. data/lib/template/node/text_part.rb +13 -0
  117. data/lib/template/node.rb +4 -0
  118. data/lib/template/parser/template.rb +30 -0
  119. data/lib/template/parser.rb +4 -0
  120. data/lib/template/version.rb +3 -0
  121. data/lib/template-ruby.rb +11 -0
  122. data/lib/template.rb +34 -0
  123. data/spec/call_spec.rb +22 -0
  124. data/spec/code/error/type_error_spec.rb +65 -0
  125. data/spec/code/parser/boolean_spec.rb +18 -0
  126. data/spec/code/parser/call_spec.rb +66 -0
  127. data/spec/code/parser/dictionnary_spec.rb +46 -0
  128. data/spec/code/parser/function_spec.rb +32 -0
  129. data/spec/code/parser/list_spec.rb +29 -0
  130. data/spec/code/parser/name_spec.rb +15 -0
  131. data/spec/code/parser/nothing_spec.rb +19 -0
  132. data/spec/code/parser/number_spec.rb +117 -0
  133. data/spec/code/parser/string_spec.rb +30 -0
  134. data/spec/code_spec.rb +108 -0
  135. data/spec/function_spec.rb +26 -0
  136. data/spec/spec_helper.rb +3 -0
  137. data/spec/template/parser/template_spec.rb +19 -0
  138. data/spec/template_spec.rb +27 -0
  139. data/template-ruby.gemspec +24 -0
  140. metadata +266 -0
@@ -0,0 +1,116 @@
1
+ class Code
2
+ class Object
3
+ class Integer < ::Code::Object::Number
4
+ attr_reader :raw
5
+
6
+ def initialize(whole, exponent: nil)
7
+ @raw = whole.to_i
8
+
9
+ if exponent
10
+ if exponent.is_a?(::Code::Object::Number)
11
+ @raw = @raw * 10**exponent.raw
12
+ else
13
+ raise ::Code::Error::TypeError.new("exponent is not a number")
14
+ end
15
+ end
16
+ end
17
+
18
+ def call(**args)
19
+ operator = args.fetch(:operator, nil)
20
+ arguments = args.fetch(:arguments, [])
21
+
22
+ if operator == "even?"
23
+ even?(arguments)
24
+ elsif operator == "to_string"
25
+ code_to_s(arguments)
26
+ elsif operator == "*"
27
+ multiplication(arguments)
28
+ elsif operator == "/"
29
+ division(arguments)
30
+ elsif %w[% - + **].detect { |o| operator == o }
31
+ integer_or_decimal_operation(operator.to_sym, arguments)
32
+ elsif %w[> >= < <=].detect { |o| operator == o }
33
+ comparaison(operator.to_sym, arguments)
34
+ elsif %w[<< >> & | ^].detect { |o| operator == o }
35
+ integer_operation(operator.to_sym, arguments)
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ def +(other)
42
+ if other.is_a?(::Code::Object::Integer)
43
+ ::Code::Object::Integer.new(raw + other.raw)
44
+ elsif other.is_a?(::Code::Object::Decimal)
45
+ ::Code::Object::Decimal.new(raw + other.raw)
46
+ else
47
+ raise ::Code::Error::TypeError
48
+ end
49
+ end
50
+
51
+ def succ
52
+ ::Code::Object::Integer.new(raw + 1)
53
+ end
54
+
55
+ def to_s
56
+ raw.to_s
57
+ end
58
+
59
+ def inspect
60
+ to_s
61
+ end
62
+
63
+ private
64
+
65
+ def even?(arguments)
66
+ sig(arguments)
67
+ ::Code::Object::Boolean.new(raw.even?)
68
+ end
69
+
70
+ def code_to_s(arguments)
71
+ sig(arguments)
72
+ ::Code::Object::String.new(raw.to_s)
73
+ end
74
+
75
+ def multiplication(arguments)
76
+ sig(arguments, [::Code::Object::Number, ::Code::Object::String])
77
+ other = arguments.first.value
78
+ if other.is_a?(::Code::Object::Integer)
79
+ ::Code::Object::Integer.new(raw * other.raw)
80
+ elsif other.is_a?(::Code::Object::Decimal)
81
+ ::Code::Object::Decimal.new(raw * other.raw)
82
+ else
83
+ ::Code::Object::String.new(other.raw * raw)
84
+ end
85
+ end
86
+
87
+ def division(arguments)
88
+ sig(arguments, ::Code::Object::Number)
89
+ other = arguments.first.value
90
+ ::Code::Object::Decimal.new(BigDecimal(raw) / other.raw)
91
+ end
92
+
93
+ def integer_or_decimal_operation(operator, arguments)
94
+ sig(arguments, ::Code::Object::Number)
95
+ other = arguments.first.value
96
+ if other.is_a?(::Code::Object::Integer)
97
+ ::Code::Object::Integer.new(raw.public_send(operator, other.raw))
98
+ else
99
+ ::Code::Object::Decimal.new(raw.public_send(operator, other.raw))
100
+ end
101
+ end
102
+
103
+ def integer_operation(operator, arguments)
104
+ sig(arguments, ::Code::Object::Integer)
105
+ other = arguments.first.value
106
+ ::Code::Object::Integer.new(raw.public_send(operator, other.raw))
107
+ end
108
+
109
+ def comparaison(operator, arguments)
110
+ sig(arguments, ::Code::Object::Number)
111
+ other = arguments.first.value
112
+ ::Code::Object::Boolean.new(raw.public_send(operator, other.raw))
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,217 @@
1
+ class Code
2
+ class Object
3
+ class List < ::Code::Object
4
+ attr_reader :raw
5
+
6
+ def initialize(raw = [])
7
+ @raw = raw
8
+ end
9
+
10
+ def call(**args)
11
+ operator = args.fetch(:operator, nil)
12
+ arguments = args.fetch(:arguments, [])
13
+ context = args.fetch(:context)
14
+ io = args.fetch(:io)
15
+
16
+ if operator == "any?"
17
+ any?(arguments, context: context, io: io)
18
+ elsif operator == "none?"
19
+ none?(arguments, context: context, io: io)
20
+ elsif operator == "detect"
21
+ detect(arguments, context: context, io: io)
22
+ elsif operator == "reduce"
23
+ reduce(arguments, context: context, io: io)
24
+ elsif operator == "each"
25
+ each(arguments, context: context, io: io)
26
+ elsif operator == "select"
27
+ select(arguments, context: context, io: io)
28
+ elsif operator == "map"
29
+ map(arguments, context: context, io: io)
30
+ elsif operator == "max"
31
+ max(arguments)
32
+ elsif operator == "flatten"
33
+ flatten(arguments)
34
+ elsif operator == "reverse"
35
+ reverse(arguments)
36
+ elsif operator == "first"
37
+ first(arguments)
38
+ elsif operator == "last"
39
+ last(arguments)
40
+ elsif operator == "max_by"
41
+ max_by(arguments, context: context, io: io)
42
+ elsif operator == "<<"
43
+ append(arguments)
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ def <<(element)
50
+ raw << element
51
+ end
52
+
53
+ def flatten(arguments)
54
+ sig(arguments)
55
+ ::Code::Object::List.new(
56
+ raw.reduce([]) do |acc, element|
57
+ if element.is_a?(::Code::Object::List)
58
+ acc + element.flatten(arguments).raw
59
+ else
60
+ acc + [element]
61
+ end
62
+ end,
63
+ )
64
+ end
65
+
66
+ def to_s
67
+ "[#{raw.map(&:inspect).join(", ")}]"
68
+ end
69
+
70
+ def inspect
71
+ to_s
72
+ end
73
+
74
+ private
75
+
76
+ def any?(arguments, context:, io:)
77
+ sig(arguments, ::Code::Object::Function)
78
+ argument = arguments.first
79
+ ::Code::Object::Boolean.new(
80
+ raw.any? do |element|
81
+ argument
82
+ .value
83
+ .call(
84
+ arguments: [::Code::Object::Argument.new(element)],
85
+ context: context,
86
+ io: io,
87
+ )
88
+ .truthy?
89
+ end,
90
+ )
91
+ end
92
+
93
+ def none?(arguments, context:, io:)
94
+ sig(arguments, ::Code::Object::Function)
95
+ argument = arguments.first
96
+ ::Code::Object::Boolean.new(
97
+ raw.none? do |element|
98
+ argument
99
+ .value
100
+ .call(
101
+ arguments: [::Code::Object::Argument.new(element)],
102
+ context: context,
103
+ io: io,
104
+ )
105
+ .truthy?
106
+ end,
107
+ )
108
+ end
109
+
110
+ def max_by(arguments, context:, io:)
111
+ sig(arguments, ::Code::Object::Function)
112
+ argument = arguments.first.value
113
+ raw.max_by do |element|
114
+ argument.call(
115
+ arguments: [::Code::Object::Argument.new(element)],
116
+ context: context,
117
+ io: io,
118
+ )
119
+ end || ::Code::Object::Nothing.new
120
+ end
121
+
122
+ def detect(arguments, context:, io:)
123
+ sig(arguments, ::Code::Object::Function)
124
+ argument = arguments.first.value
125
+ raw.detect do |element|
126
+ argument.call(
127
+ arguments: [::Code::Object::Argument.new(element)],
128
+ context: context,
129
+ io: io,
130
+ ).truthy?
131
+ end || ::Code::Object::Nothing.new
132
+ end
133
+
134
+ def reduce(arguments, context:, io:)
135
+ sig(arguments, ::Code::Object::Function)
136
+ argument = arguments.first.value
137
+ raw.reduce do |acc, element|
138
+ argument.call(
139
+ arguments: [
140
+ ::Code::Object::Argument.new(acc),
141
+ ::Code::Object::Argument.new(element),
142
+ ],
143
+ context: context,
144
+ io: io,
145
+ )
146
+ end || ::Code::Object::Nothing.new
147
+ end
148
+
149
+ def each(arguments, context:, io:)
150
+ sig(arguments, ::Code::Object::Function)
151
+ argument = arguments.first.value
152
+ raw.each do |element|
153
+ argument.call(
154
+ arguments: [::Code::Object::Argument.new(element)],
155
+ context: context,
156
+ io: io,
157
+ )
158
+ end
159
+ self
160
+ end
161
+
162
+ def select(arguments, context:, io:)
163
+ sig(arguments, ::Code::Object::Function)
164
+ argument = arguments.first.value
165
+ ::Code::Object::List.new(
166
+ raw.select do |element|
167
+ argument.call(
168
+ arguments: [::Code::Object::Argument.new(element)],
169
+ context: context,
170
+ io: io,
171
+ ).truthy?
172
+ end,
173
+ )
174
+ end
175
+
176
+ def map(arguments, context:, io:)
177
+ sig(arguments, ::Code::Object::Function)
178
+ argument = arguments.first.value
179
+ ::Code::Object::List.new(
180
+ raw.map do |element|
181
+ argument.call(
182
+ arguments: [::Code::Object::Argument.new(element)],
183
+ context: context,
184
+ io: io,
185
+ )
186
+ end,
187
+ )
188
+ end
189
+
190
+ def append(arguments)
191
+ sig(arguments, ::Code::Object)
192
+ raw << arguments.first.value
193
+ self
194
+ end
195
+
196
+ def first(arguments)
197
+ sig(arguments)
198
+ raw.first
199
+ end
200
+
201
+ def max(arguments)
202
+ sig(arguments)
203
+ raw.max || ::Code::Object::Nothing.new
204
+ end
205
+
206
+ def reverse(arguments)
207
+ sig(arguments)
208
+ ::Code::Object::List.new(raw.reverse)
209
+ end
210
+
211
+ def last(arguments)
212
+ sig(arguments)
213
+ raw.last
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,23 @@
1
+ class Code
2
+ class Object
3
+ class Nothing < ::Code::Object
4
+ attr_reader :raw
5
+
6
+ def initialize
7
+ @raw = nil
8
+ end
9
+
10
+ def truthy?
11
+ false
12
+ end
13
+
14
+ def to_s
15
+ ""
16
+ end
17
+
18
+ def inspect
19
+ "nothing"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,6 @@
1
+ class Code
2
+ class Object
3
+ class Number < ::Code::Object
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,158 @@
1
+ class Code
2
+ class Object
3
+ class Range < ::Code::Object
4
+ attr_reader :raw
5
+
6
+ def initialize(left, right, exclude_end: false)
7
+ @left = left
8
+ @right = right
9
+ @exclude_end = exclude_end
10
+ @raw = ::Range.new(left, right, exclude_end)
11
+ end
12
+
13
+ def call(**args)
14
+ operator = args.fetch(:operator, nil)
15
+ arguments = args.fetch(:arguments, [])
16
+ context = args.fetch(:context)
17
+ io = args.fetch(:io)
18
+
19
+ if operator == "any?"
20
+ any?(arguments, context: context, io: io)
21
+ elsif operator == "all?"
22
+ all?(arguments, context: context, io: io)
23
+ elsif operator == "each"
24
+ each(arguments, context: context, io: io)
25
+ elsif operator == "select"
26
+ select(arguments, context: context, io: io)
27
+ elsif operator == "map"
28
+ map(arguments, context: context, io: io)
29
+ elsif operator == "step"
30
+ step(arguments)
31
+ elsif operator == "to_list"
32
+ to_list(arguments)
33
+ elsif operator == "first"
34
+ first(arguments)
35
+ elsif operator == "last"
36
+ last(arguments)
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ def to_s
43
+ raw.to_s
44
+ end
45
+
46
+ def inspect
47
+ to_s
48
+ end
49
+
50
+ private
51
+
52
+ def any?(arguments, context:, io:)
53
+ sig(arguments, ::Code::Object::Function)
54
+ argument = arguments.first.value
55
+ ::Code::Object::Boolean.new(
56
+ raw.any? do |element|
57
+ argument.call(
58
+ arguments: [::Code::Object::Argument.new(element)],
59
+ context: context,
60
+ io: io,
61
+ ).truthy?
62
+ end,
63
+ )
64
+ end
65
+
66
+ def all?(arguments, context:, io:)
67
+ sig(arguments, ::Code::Object::Function)
68
+ argument = arguments.first.value
69
+ ::Code::Object::Boolean.new(
70
+ raw.all? do |element|
71
+ argument.call(
72
+ arguments: [::Code::Object::Argument.new(element)],
73
+ context: context,
74
+ io: io,
75
+ ).truthy?
76
+ end,
77
+ )
78
+ end
79
+
80
+ def each(arguments, context:, io:)
81
+ sig(arguments, ::Code::Object::Function)
82
+ argument = arguments.first.value
83
+ raw.each do |element|
84
+ argument.call(
85
+ arguments: [::Code::Object::Argument.new(element)],
86
+ context: context,
87
+ io: io,
88
+ )
89
+ end
90
+ self
91
+ end
92
+
93
+ def select(arguments, context:, io:)
94
+ sig(arguments, ::Code::Object::Function)
95
+ argument = arguments.first.value
96
+ ::Code::Object::List.new(
97
+ raw.select do |element|
98
+ argument.call(
99
+ arguments: [::Code::Object::Argument.new(element)],
100
+ context: context,
101
+ io: io,
102
+ ).truthy?
103
+ end,
104
+ )
105
+ end
106
+
107
+ def map(arguments, context:, io:)
108
+ sig(arguments, ::Code::Object::Function)
109
+ argument = arguments.first.value
110
+ ::Code::Object::List.new(
111
+ raw.map do |element|
112
+ argument.call(
113
+ arguments: [::Code::Object::Argument.new(element)],
114
+ context: context,
115
+ io: io,
116
+ )
117
+ end,
118
+ )
119
+ end
120
+
121
+ def step(arguments)
122
+ sig(arguments, ::Code::Object::Number)
123
+ argument = arguments.first.value
124
+
125
+ list = ::Code::Object::List.new
126
+ element = @left
127
+ list << element
128
+
129
+ if @exlucde_end
130
+ while (element = element + argument) < @right
131
+ list << element
132
+ end
133
+ else
134
+ while (element = element + argument) <= @right
135
+ list << element
136
+ end
137
+ end
138
+
139
+ list
140
+ end
141
+
142
+ def to_list(arguments)
143
+ sig(arguments)
144
+ ::Code::Object::List.new(raw.to_a)
145
+ end
146
+
147
+ def first(arguments)
148
+ sig(arguments)
149
+ raw.first
150
+ end
151
+
152
+ def last(arguments)
153
+ sig(arguments)
154
+ raw.last
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,68 @@
1
+ class Code
2
+ class Object
3
+ class String < ::Code::Object
4
+ attr_reader :raw
5
+
6
+ def initialize(string)
7
+ @raw = string
8
+ end
9
+
10
+ def call(**args)
11
+ operator = args.fetch(:operator, nil)
12
+ arguments = args.fetch(:arguments, [])
13
+
14
+ if operator == "to_function"
15
+ to_function(arguments)
16
+ elsif operator == "+"
17
+ plus(arguments)
18
+ elsif operator == "*"
19
+ multiplication(arguments)
20
+ elsif operator == "reverse"
21
+ reverse(arguments)
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def succ
28
+ ::Code::Object::String.new(raw.succ)
29
+ end
30
+
31
+ def to_sym
32
+ raw.to_sym
33
+ end
34
+
35
+ def to_s
36
+ raw
37
+ end
38
+
39
+ def inspect
40
+ raw.inspect
41
+ end
42
+
43
+ private
44
+
45
+ def to_function(arguments)
46
+ sig(arguments)
47
+ Code.evaluate("(_) => { _.#{raw} }")
48
+ end
49
+
50
+ def plus(arguments)
51
+ sig(arguments, ::Code::Object::String)
52
+ other = arguments.first.value
53
+ ::Code::Object::String.new(raw + other.raw)
54
+ end
55
+
56
+ def multiplication(arguments)
57
+ sig(arguments, ::Code::Object::Number)
58
+ other = arguments.first.value
59
+ ::Code::Object::String.new(raw * other.raw)
60
+ end
61
+
62
+ def reverse(arguments)
63
+ sig(arguments)
64
+ ::Code::Object::String.new(raw.reverse)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,130 @@
1
+ class Code
2
+ class Object
3
+ include Comparable
4
+
5
+ def call(**args)
6
+ operator = args.fetch(:operator, nil)
7
+ arguments = args.fetch(:arguments, [])
8
+ if %w[== === !=].detect { |o| operator == o }
9
+ comparaison(operator.to_sym, arguments)
10
+ elsif operator == "<=>"
11
+ compare(arguments)
12
+ elsif operator == "&&"
13
+ and_operator(arguments)
14
+ elsif operator == "||"
15
+ or_operator(arguments)
16
+ else
17
+ raise ::Code::Error::Undefined.new(
18
+ "#{operator} not defined on #{inspect}",
19
+ )
20
+ end
21
+ end
22
+
23
+ def []=(key, value)
24
+ @attributes ||= {}
25
+ @attributes[key] = value
26
+ end
27
+
28
+ def [](key)
29
+ @attributes ||= {}
30
+ @attributes[key]
31
+ end
32
+
33
+ def key?(key)
34
+ @attributes ||= {}
35
+ @attributes.key?(key)
36
+ end
37
+
38
+ def truthy?
39
+ true
40
+ end
41
+
42
+ def falsy?
43
+ !truthy?
44
+ end
45
+
46
+ def <=>(other)
47
+ if respond_to?(:raw)
48
+ other.respond_to?(:raw) ? raw <=> other.raw : raw <=> other
49
+ else
50
+ other <=> self
51
+ end
52
+ end
53
+
54
+ def ==(other)
55
+ if respond_to?(:raw)
56
+ other.respond_to?(:raw) ? raw == other.raw : raw == other
57
+ else
58
+ other == self
59
+ end
60
+ end
61
+ alias_method :eql?, :==
62
+
63
+ def hash
64
+ if respond_to?(:raw)
65
+ [self.class, raw].hash
66
+ else
67
+ raise NotImplementedError
68
+ end
69
+ end
70
+
71
+ def to_s
72
+ raise NotImplementedError
73
+ end
74
+
75
+ private
76
+
77
+ def sig(actual_arguments, *expected_arguments)
78
+ if actual_arguments.size != expected_arguments.size
79
+ raise ::Code::Error::ArgumentError.new(
80
+ "Expected #{expected_arguments.size} arguments, " \
81
+ "got #{actual_arguments.size} arguments",
82
+ )
83
+ end
84
+
85
+ expected_arguments.each.with_index do |expected_argument, index|
86
+ actual_argument = actual_arguments[index].value
87
+
88
+ if expected_argument.is_a?(Array)
89
+ if expected_argument.none? { |expected_arg|
90
+ actual_argument.is_a?(expected_arg)
91
+ }
92
+ raise ::Code::Error::TypeError.new(
93
+ "Expected #{expected_argument}, got #{actual_argument.class}",
94
+ )
95
+ end
96
+ else
97
+ if !actual_argument.is_a?(expected_argument)
98
+ raise ::Code::Error::TypeError.new(
99
+ "Expected #{expected_argument}, got #{actual_argument.class}",
100
+ )
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ def comparaison(operator, arguments)
107
+ sig(arguments, ::Code::Object)
108
+ other = arguments.first.value
109
+ ::Code::Object::Boolean.new(public_send(operator, other))
110
+ end
111
+
112
+ def compare(arguments)
113
+ sig(arguments, ::Code::Object)
114
+ other = arguments.first.value
115
+ ::Code::Object::Integer.new(self <=> other)
116
+ end
117
+
118
+ def and_operator(arguments)
119
+ sig(arguments, ::Code::Object)
120
+ other = arguments.first.value
121
+ truthy? ? other : self
122
+ end
123
+
124
+ def or_operator(arguments)
125
+ sig(arguments, ::Code::Object)
126
+ other = arguments.first.value
127
+ truthy? ? self : other
128
+ end
129
+ end
130
+ end