code-ruby 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
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