language-ruby 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) 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 +55 -0
  8. data/Gemfile +8 -0
  9. data/Gemfile.lock +48 -0
  10. data/LICENSE +7 -0
  11. data/README.md +103 -0
  12. data/TODO +17 -0
  13. data/bin/code +76 -0
  14. data/bin/format +3 -0
  15. data/bin/template +85 -0
  16. data/bin/test +17 -0
  17. data/code-ruby.gemspec +17 -0
  18. data/docs/class.code +9 -0
  19. data/docs/euler/1.template +10 -0
  20. data/docs/euler/2.template +16 -0
  21. data/docs/euler/3.template +16 -0
  22. data/docs/euler/4.template +10 -0
  23. data/docs/euler/5.template +13 -0
  24. data/docs/fibonnaci.template +14 -0
  25. data/docs/meetup.code +12 -0
  26. data/docs/precedence.template +36 -0
  27. data/docs/rain.code +22 -0
  28. data/docs/slack.code +17 -0
  29. data/docs/stripe.code +7 -0
  30. data/docs/twitter.code +9 -0
  31. data/language-ruby.gemspec +18 -0
  32. data/lib/code/error.rb +18 -0
  33. data/lib/code/node/base_10.rb +29 -0
  34. data/lib/code/node/base_16.rb +13 -0
  35. data/lib/code/node/base_2.rb +13 -0
  36. data/lib/code/node/base_8.rb +13 -0
  37. data/lib/code/node/boolean.rb +22 -0
  38. data/lib/code/node/call.rb +47 -0
  39. data/lib/code/node/call_argument.rb +21 -0
  40. data/lib/code/node/chained_call.rb +23 -0
  41. data/lib/code/node/code.rb +20 -0
  42. data/lib/code/node/decimal.rb +26 -0
  43. data/lib/code/node/dictionnary.rb +33 -0
  44. data/lib/code/node/equal.rb +34 -0
  45. data/lib/code/node/function.rb +20 -0
  46. data/lib/code/node/function_parameter.rb +31 -0
  47. data/lib/code/node/if.rb +59 -0
  48. data/lib/code/node/if_modifier.rb +47 -0
  49. data/lib/code/node/list.rb +16 -0
  50. data/lib/code/node/negation.rb +15 -0
  51. data/lib/code/node/not.rb +15 -0
  52. data/lib/code/node/nothing.rb +12 -0
  53. data/lib/code/node/number.rb +25 -0
  54. data/lib/code/node/operation.rb +38 -0
  55. data/lib/code/node/power.rb +20 -0
  56. data/lib/code/node/rescue.rb +17 -0
  57. data/lib/code/node/splat.rb +15 -0
  58. data/lib/code/node/statement.rb +59 -0
  59. data/lib/code/node/string.rb +53 -0
  60. data/lib/code/node/ternary.rb +24 -0
  61. data/lib/code/node/unary_minus.rb +15 -0
  62. data/lib/code/node/while.rb +35 -0
  63. data/lib/code/node.rb +13 -0
  64. data/lib/code/object/argument.rb +32 -0
  65. data/lib/code/object/boolean.rb +27 -0
  66. data/lib/code/object/decimal.rb +162 -0
  67. data/lib/code/object/dictionnary.rb +96 -0
  68. data/lib/code/object/function.rb +64 -0
  69. data/lib/code/object/global.rb +42 -0
  70. data/lib/code/object/integer.rb +221 -0
  71. data/lib/code/object/list.rb +200 -0
  72. data/lib/code/object/nothing.rb +23 -0
  73. data/lib/code/object/number.rb +6 -0
  74. data/lib/code/object/range.rb +146 -0
  75. data/lib/code/object/ruby_function.rb +31 -0
  76. data/lib/code/object/string.rb +88 -0
  77. data/lib/code/object.rb +197 -0
  78. data/lib/code/parser/addition.rb +21 -0
  79. data/lib/code/parser/and_operator.rb +17 -0
  80. data/lib/code/parser/bitwise_and.rb +17 -0
  81. data/lib/code/parser/bitwise_or.rb +21 -0
  82. data/lib/code/parser/boolean.rb +17 -0
  83. data/lib/code/parser/call.rb +122 -0
  84. data/lib/code/parser/chained_call.rb +47 -0
  85. data/lib/code/parser/class.rb +45 -0
  86. data/lib/code/parser/code.rb +25 -0
  87. data/lib/code/parser/dictionnary.rb +67 -0
  88. data/lib/code/parser/equal.rb +94 -0
  89. data/lib/code/parser/equality.rb +35 -0
  90. data/lib/code/parser/equality_lower.rb +9 -0
  91. data/lib/code/parser/function.rb +85 -0
  92. data/lib/code/parser/greater.rb +25 -0
  93. data/lib/code/parser/group.rb +22 -0
  94. data/lib/code/parser/if.rb +63 -0
  95. data/lib/code/parser/if_modifier.rb +55 -0
  96. data/lib/code/parser/list.rb +42 -0
  97. data/lib/code/parser/multiplication.rb +25 -0
  98. data/lib/code/parser/name.rb +101 -0
  99. data/lib/code/parser/negation.rb +30 -0
  100. data/lib/code/parser/not_keyword.rb +23 -0
  101. data/lib/code/parser/nothing.rb +22 -0
  102. data/lib/code/parser/number.rb +154 -0
  103. data/lib/code/parser/operation.rb +35 -0
  104. data/lib/code/parser/or_keyword.rb +21 -0
  105. data/lib/code/parser/or_operator.rb +17 -0
  106. data/lib/code/parser/power.rb +43 -0
  107. data/lib/code/parser/range.rb +17 -0
  108. data/lib/code/parser/rescue.rb +39 -0
  109. data/lib/code/parser/shift.rb +21 -0
  110. data/lib/code/parser/splat.rb +31 -0
  111. data/lib/code/parser/statement.rb +9 -0
  112. data/lib/code/parser/string.rb +78 -0
  113. data/lib/code/parser/ternary.rb +46 -0
  114. data/lib/code/parser/unary_minus.rb +31 -0
  115. data/lib/code/parser/while.rb +36 -0
  116. data/lib/code/parser/whitespace.rb +49 -0
  117. data/lib/code/parser.rb +19 -0
  118. data/lib/code/ruby.rb +162 -0
  119. data/lib/code-ruby.rb +10 -0
  120. data/lib/code.rb +47 -0
  121. data/lib/language/atom.rb +343 -0
  122. data/lib/language/output.rb +130 -0
  123. data/lib/language/parser/absent/present.rb +8 -0
  124. data/lib/language/parser/absent.rb +6 -0
  125. data/lib/language/parser/end_of_input.rb +6 -0
  126. data/lib/language/parser/interuption.rb +38 -0
  127. data/lib/language/parser/not_end_of_input.rb +6 -0
  128. data/lib/language/parser/str/not_found.rb +16 -0
  129. data/lib/language/parser/str.rb +6 -0
  130. data/lib/language/parser.rb +53 -0
  131. data/lib/language-ruby.rb +10 -0
  132. data/lib/language.rb +80 -0
  133. data/lib/template/node/code_part.rb +13 -0
  134. data/lib/template/node/part.rb +19 -0
  135. data/lib/template/node/template.rb +15 -0
  136. data/lib/template/node/text_part.rb +13 -0
  137. data/lib/template/node.rb +4 -0
  138. data/lib/template/parser/template.rb +39 -0
  139. data/lib/template/parser.rb +19 -0
  140. data/lib/template/version.rb +3 -0
  141. data/lib/template-ruby.rb +10 -0
  142. data/lib/template.rb +50 -0
  143. data/spec/code/addition_spec.rb +13 -0
  144. data/spec/code/and_operator_spec.rb +13 -0
  145. data/spec/code/bitwise_and_spec.rb +13 -0
  146. data/spec/code/bitwise_or_spec.rb +13 -0
  147. data/spec/code/boolean_spec.rb +13 -0
  148. data/spec/code/call_spec.rb +21 -0
  149. data/spec/code/chained_call_spec.rb +16 -0
  150. data/spec/code/dictionnary_spec.rb +17 -0
  151. data/spec/code/equal_spec.rb +26 -0
  152. data/spec/code/equality_spec.rb +13 -0
  153. data/spec/code/function_spec.rb +18 -0
  154. data/spec/code/greater_spec.rb +18 -0
  155. data/spec/code/group_spec.rb +12 -0
  156. data/spec/code/if_modifier_spec.rb +20 -0
  157. data/spec/code/if_spec.rb +25 -0
  158. data/spec/code/list_spec.rb +17 -0
  159. data/spec/code/multiplication_spec.rb +18 -0
  160. data/spec/code/negation_spec.rb +20 -0
  161. data/spec/code/not_keyword_spec.rb +13 -0
  162. data/spec/code/nothing_spec.rb +17 -0
  163. data/spec/code/number_spec.rb +22 -0
  164. data/spec/code/or_keyword_spec.rb +17 -0
  165. data/spec/code/or_operator_spec.rb +16 -0
  166. data/spec/code/parser/boolean_spec.rb +16 -0
  167. data/spec/code/parser/call_spec.rb +26 -0
  168. data/spec/code/parser/chained_call.rb +17 -0
  169. data/spec/code/parser/dictionnary_spec.rb +18 -0
  170. data/spec/code/parser/function_spec.rb +16 -0
  171. data/spec/code/parser/group_spec.rb +18 -0
  172. data/spec/code/parser/list_spec.rb +18 -0
  173. data/spec/code/parser/number_spec.rb +12 -0
  174. data/spec/code/parser/string_spec.rb +21 -0
  175. data/spec/code/parser_spec.rb +23 -0
  176. data/spec/code/power_spec.rb +13 -0
  177. data/spec/code/range_spec.rb +16 -0
  178. data/spec/code/rescue_spec.rb +13 -0
  179. data/spec/code/shift_spec.rb +13 -0
  180. data/spec/code/splat_spec.rb +13 -0
  181. data/spec/code/string_spec.rb +25 -0
  182. data/spec/code/ternary_spec.rb +18 -0
  183. data/spec/code/unary_minus_spec.rb +13 -0
  184. data/spec/code/while_spec.rb +18 -0
  185. data/spec/spec_helper.rb +6 -0
  186. data/template-ruby.gemspec +19 -0
  187. metadata +284 -0
data/docs/stripe.code ADDED
@@ -0,0 +1,7 @@
1
+ event = Stripe::Webhook.event
2
+
3
+ if event.type == "payment_intent.succeeded"
4
+ payment_intent = event.data.object
5
+ amount = Money.format(payment_intent.amount, payment_intent.currency)
6
+ Sms.send("You got paid {amount}")
7
+ end
data/docs/twitter.code ADDED
@@ -0,0 +1,9 @@
1
+ twitter_username = fetch(:twitter_username) { "dorianmariefr" }
2
+
3
+ Twitter
4
+ .search("to:{twitter_username}", type: :recent)
5
+ .each do |tweet|
6
+ next if Storage.exists?(tweet.id)
7
+ Storage.create!(tweet.id)
8
+ Sms.send("New mention: {tweet.user.screen_name}: {tweet.text}")
9
+ end
@@ -0,0 +1,18 @@
1
+ require_relative "lib/template/version"
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "language-ruby"
5
+ s.version = ::Template::Version
6
+ s.summary = "A Parsing Expression Grammar (PEG)"
7
+ s.description =
8
+ 'A Parsing Expression Grammar (PEG) for making parsers'
9
+ s.authors = ["Dorian Marié"]
10
+ s.email = "dorian@dorianmarie.fr"
11
+ s.files = `git ls-files`.split($/)
12
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
13
+ s.require_paths = ["lib"]
14
+ s.homepage = "https://github.com/dorianmariefr/template-ruby"
15
+ s.license = "MIT"
16
+
17
+ s.add_dependency "zeitwerk", "~> 2"
18
+ end
data/lib/code/error.rb ADDED
@@ -0,0 +1,18 @@
1
+ class Code
2
+ class Error < StandardError
3
+ class TypeError < ::Code::Error
4
+ end
5
+
6
+ class Undefined < ::Code::Error
7
+ end
8
+
9
+ class UndefinedVariable < ::Code::Error
10
+ end
11
+
12
+ class ArgumentError < ::Code::Error
13
+ end
14
+
15
+ class IncompatibleContext < ::Code::Error
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ class Code
2
+ class Node
3
+ class Base10 < Node
4
+ def initialize(parsed)
5
+ @whole = parsed.delete(:whole)
6
+
7
+ if parsed.key?(:exponent)
8
+ @exponent = Node::Statement.new(parsed.delete(:exponent))
9
+ end
10
+
11
+ super(parsed)
12
+ end
13
+
14
+ def evaluate(**args)
15
+ if @exponent
16
+ exponent = @exponent.evaluate(**args)
17
+
18
+ if exponent.is_a?(::Code::Object::Integer)
19
+ ::Code::Object::Integer.new(@whole.to_i, exponent: exponent)
20
+ else
21
+ ::Code::Object::Decimal.new(@whole, exponent: exponent)
22
+ end
23
+ else
24
+ ::Code::Object::Integer.new(@whole.to_i)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Node
3
+ class Base16 < Node
4
+ def initialize(parsed)
5
+ @base_16 = parsed
6
+ end
7
+
8
+ def evaluate(**args)
9
+ ::Code::Object::Integer.new(@base_16.to_i(16))
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Node
3
+ class Base2 < Node
4
+ def initialize(parsed)
5
+ @base_2 = parsed
6
+ end
7
+
8
+ def evaluate(**args)
9
+ ::Code::Object::Integer.new(@base_2.to_i(2))
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Node
3
+ class Base8 < Node
4
+ def initialize(parsed)
5
+ @base_8 = parsed
6
+ end
7
+
8
+ def evaluate(**args)
9
+ ::Code::Object::Integer.new(@base_8.to_i(8))
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ class Code
2
+ class Node
3
+ class Boolean < Node
4
+ TRUE_KEYWORD = "true"
5
+ FALSE_KEYWORD = "false"
6
+
7
+ def initialize(parsed)
8
+ @boolean = parsed
9
+ end
10
+
11
+ def evaluate(**args)
12
+ if @boolean == TRUE_KEYWORD
13
+ ::Code::Object::Boolean.new(true)
14
+ elsif @boolean == FALSE_KEYWORD
15
+ ::Code::Object::Boolean.new(false)
16
+ else
17
+ raise NotImplementedError.new(@boolean)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ class Code
2
+ class Node
3
+ class Call < Node
4
+ class Block < Node
5
+ def initialize(parsed)
6
+ @parameters =
7
+ parsed
8
+ .delete(:parameters) { [] }
9
+ .map { |parameter| Node::FunctionParameter.new(parameter) }
10
+
11
+ @body = Node::Code.new(parsed.delete(:body))
12
+
13
+ super(parsed)
14
+ end
15
+
16
+ def evaluate(**args)
17
+ ::Code::Object::Argument.new(
18
+ ::Code::Object::Function.new(parameters: @parameters, body: @body)
19
+ )
20
+ end
21
+ end
22
+
23
+ def initialize(parsed)
24
+ @name = parsed.delete(:name)
25
+ @arguments =
26
+ parsed
27
+ .delete(:arguments) { [] }
28
+ .map { |argument| Node::CallArgument.new(argument) }
29
+
30
+ if parsed.key?(:block)
31
+ @block = Node::Call::Block.new(parsed.delete(:block))
32
+ end
33
+
34
+ super(parsed)
35
+ end
36
+
37
+ def evaluate(**args)
38
+ arguments = @arguments.map { |argument| argument.evaluate(**args) }
39
+ arguments << @block.evaluate(**args) if @block
40
+
41
+ name = ::Code::Object::String.new(@name)
42
+
43
+ args.fetch(:object).call(operator: name, arguments: arguments, **args)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ class Code
2
+ class Node
3
+ class CallArgument < Node
4
+ def initialize(parsed)
5
+ @value = Node::Code.new(parsed.delete(:value))
6
+ @name = parsed.delete(:name)
7
+ end
8
+
9
+ def evaluate(**args)
10
+ if @name
11
+ ::Code::Object::Argument.new(
12
+ @value.evaluate(**args),
13
+ name: ::Code::Object::String.new(@name)
14
+ )
15
+ else
16
+ ::Code::Object::Argument.new(@value.evaluate(**args))
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ class Code
2
+ class Node
3
+ class ChainedCall < Node
4
+ def initialize(parsed)
5
+ @first = Node::Statement.new(parsed.delete(:first))
6
+ @others =
7
+ parsed
8
+ .delete(:others)
9
+ .map { |operator| Node::Statement.new(operator) }
10
+
11
+ super(parsed)
12
+ end
13
+
14
+ def evaluate(**args)
15
+ first = @first.evaluate(**args)
16
+
17
+ @others.reduce(first) do |acc, element|
18
+ element.evaluate(**args.merge(object: acc))
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ class Code
2
+ class Node
3
+ class Code < Node
4
+ def initialize(parsed)
5
+ @statements = parsed.map { |statement| Node::Statement.new(statement) }
6
+ end
7
+
8
+ def evaluate(**args)
9
+ last = ::Code::Object::Nothing.new
10
+
11
+ @statements.each do |statement|
12
+ last =
13
+ statement.evaluate(**args.merge(object: ::Code::Object::Global.new))
14
+ end
15
+
16
+ last
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ class Code
2
+ class Node
3
+ class Decimal < Node
4
+ def initialize(parsed)
5
+ @decimal = parsed.delete(:decimal)
6
+
7
+ if parsed.key?(:exponent)
8
+ @exponent = Node::Statement.new(parsed.delete(:exponent))
9
+ end
10
+
11
+ super(parsed)
12
+ end
13
+
14
+ def evaluate(**args)
15
+ if @exponent
16
+ ::Code::Object::Decimal.new(
17
+ @decimal,
18
+ exponent: @exponent.evaluate(**args)
19
+ )
20
+ else
21
+ ::Code::Object::Decimal.new(@decimal)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ class Code
2
+ class Node
3
+ class Dictionnary < Node
4
+ class KeyValue < Node
5
+ def initialize(parsed)
6
+ if parsed.key?(:statement)
7
+ @key = Node::Statement.new(parsed.delete(:statement))
8
+ elsif parsed.key?(:name)
9
+ @key = Node::String.new([{ text: parsed.delete(:name) }])
10
+ end
11
+
12
+ @value = Node::Code.new(parsed.delete(:value))
13
+ end
14
+
15
+ def evaluate(**args)
16
+ [@key.evaluate(**args), @value.evaluate(**args)]
17
+ end
18
+ end
19
+
20
+ def initialize(parsed)
21
+ parsed = [] if parsed == ""
22
+ @key_values =
23
+ parsed.map { |key_value| Node::Dictionnary::KeyValue.new(key_value) }
24
+ end
25
+
26
+ def evaluate(**args)
27
+ ::Code::Object::Dictionnary.new(
28
+ @key_values.map { |key_value| key_value.evaluate(**args) }.to_h
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ class Code
2
+ class Node
3
+ class Equal < Node
4
+ def initialize(parsed)
5
+ @operator = parsed.delete(:operator)
6
+ @left = parsed.delete(:left)
7
+ @right = Node::Statement.new(parsed.delete(:right))
8
+ super(parsed)
9
+ end
10
+
11
+ def evaluate(**args)
12
+ right = @right.evaluate(**args)
13
+ left = ::Code::Object::String.new(@left)
14
+ context = args.fetch(:context)
15
+
16
+ if @operator == ""
17
+ context[left] = right
18
+ else
19
+ if context[left].nil?
20
+ raise ::Code::Error::Undefined.new("#{left} is not defined")
21
+ end
22
+
23
+ context[left] = context.fetch(left).call(
24
+ operator: @operator,
25
+ arguments: [::Code::Object::Argument.new(right)],
26
+ **args
27
+ )
28
+ end
29
+
30
+ args[:context][left]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ class Code
2
+ class Node
3
+ class Function < Node
4
+ def initialize(parsed)
5
+ @parameters =
6
+ parsed
7
+ .delete(:parameters) { [] }
8
+ .map { |parameter| Node::FunctionParameter.new(parameter) }
9
+
10
+ @body = Node::Code.new(parsed.delete(:body))
11
+
12
+ super(parsed)
13
+ end
14
+
15
+ def evaluate(**args)
16
+ ::Code::Object::Function.new(parameters: @parameters, body: @body)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ class Code
2
+ class Node
3
+ class FunctionParameter < Node
4
+ def initialize(parsed)
5
+ @name = parsed.delete(:name)
6
+ @keyword = !!parsed.delete(:keyword)
7
+ super(parsed)
8
+ end
9
+
10
+ def name
11
+ ::Code::Object::String.new(@name)
12
+ end
13
+
14
+ def regular?
15
+ !@keyword
16
+ end
17
+
18
+ def keyword?
19
+ !!@keyword
20
+ end
21
+
22
+ def regular_splat?
23
+ false
24
+ end
25
+
26
+ def keyword_splat?
27
+ false
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,59 @@
1
+ class Code
2
+ class Node
3
+ class If < Node
4
+ IF_KEYWORD = "if"
5
+ UNLESS_KEYWORD = "unless"
6
+ ELSIF_KEYWORD = "elsif"
7
+ ELSE_KEYWORD = "else"
8
+
9
+ class Else < Node
10
+ attr_reader :operator, :statement, :body
11
+
12
+ def initialize(parsed)
13
+ @operator = parsed.delete(:operator)
14
+ @body = Node::Code.new(parsed.delete(:body))
15
+
16
+ if parsed.key?(:statement)
17
+ @statement = Node::Statement.new(parsed.delete(:statement))
18
+ end
19
+ end
20
+ end
21
+
22
+ def initialize(parsed)
23
+ @first_operator = parsed.delete(:first_operator)
24
+ @first_statement = Node::Statement.new(parsed.delete(:first_statement))
25
+ @first_body = Node::Code.new(parsed.delete(:first_body))
26
+ @elses =
27
+ parsed.delete(:elses) { [] }.map { |elses| Node::If::Else.new(elses) }
28
+ super(parsed)
29
+ end
30
+
31
+ def evaluate(**args)
32
+ if @first_operator == IF_KEYWORD &&
33
+ @first_statement.evaluate(**args).truthy?
34
+ @first_body.evaluate(**args)
35
+ elsif @first_operator == UNLESS_KEYWORD &&
36
+ @first_statement.evaluate(**args).falsy?
37
+ @first_body.evaluate(**args)
38
+ else
39
+ @elses.each do |elses|
40
+ if elses.operator == ELSIF_KEYWORD &&
41
+ elses.statement.evaluate(**args).truthy?
42
+ return elses.body.evaluate(**args)
43
+ elsif elses.operator == IF_KEYWORD &&
44
+ elses.statement.evaluate(**args).truthy?
45
+ return elses.body.evaluate(**args)
46
+ elsif elses.operator == UNLESS_KEYWORD &&
47
+ elses.statement.evaluate(**args).falsy?
48
+ return elses.body.evaluate(**args)
49
+ elsif elses.operator == ELSE_KEYWORD
50
+ return elses.body.evaluate(**args)
51
+ end
52
+ end
53
+
54
+ ::Code::Object::Nothing.new
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,47 @@
1
+ class Code
2
+ class Node
3
+ class IfModifier < Node
4
+ IF_KEYWORD = "if"
5
+ UNLESS_KEYWORD = "unless"
6
+ WHILE_KEYWORD = "while"
7
+ UNTIL_KEYWORD = "until"
8
+
9
+ def initialize(parsed)
10
+ @operator = parsed.delete(:operator)
11
+ @left = Node::Statement.new(parsed.delete(:left))
12
+ @right = Node::Statement.new(parsed.delete(:right))
13
+ super(parsed)
14
+ end
15
+
16
+ def evaluate(**args)
17
+ if @operator == IF_KEYWORD
18
+ if @right.evaluate(**args).truthy?
19
+ @left.evaluate(**args)
20
+ else
21
+ ::Code::Object::Nothing.new
22
+ end
23
+ elsif @operator == UNLESS_KEYWORD
24
+ if @right.evaluate(**args).falsy?
25
+ @left.evaluate(**args)
26
+ else
27
+ ::Code::Object::Nothing.new
28
+ end
29
+ elsif @operator == WHILE_KEYWORD
30
+ last = ::Code::Object::Nothing.new
31
+
32
+ last = @left.evaluate(**args) while @right.evaluate(**args).truthy?
33
+
34
+ last
35
+ elsif @operator == UNTIL_KEYWORD
36
+ last = ::Code::Object::Nothing.new
37
+
38
+ last = @left.evaluate(**args) while @right.evaluate(**args).falsy?
39
+
40
+ last
41
+ else
42
+ raise NotImplementedError.new(@operator)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,16 @@
1
+ class Code
2
+ class Node
3
+ class List < Node
4
+ def initialize(parsed)
5
+ parsed = [] if parsed == ""
6
+ @elements = parsed.map { |element| Node::Code.new(element) }
7
+ end
8
+
9
+ def evaluate(**args)
10
+ ::Code::Object::List.new(
11
+ @elements.map { |element| element.evaluate(**args) }
12
+ )
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ class Code
2
+ class Node
3
+ class Negation < Node
4
+ def initialize(parsed)
5
+ @operator = parsed.delete(:operator)
6
+ @right = Node::Statement.new(parsed.delete(:right))
7
+ super(parsed)
8
+ end
9
+
10
+ def evaluate(**args)
11
+ @right.evaluate(**args).call(operator: @operator, arguments: [], **args)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class Code
2
+ class Node
3
+ class Not < Node
4
+ def initialize(parsed)
5
+ @operator = parsed.delete(:operator)
6
+ @right = Node::Statement.new(parsed.delete(:right))
7
+ super(parsed)
8
+ end
9
+
10
+ def evaluate(**args)
11
+ @right.evaluate(**args).call(operator: @operator, arguments: [], **args)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ class Code
2
+ class Node
3
+ class Nothing < Node
4
+ def initialize(parsed)
5
+ end
6
+
7
+ def evaluate(**args)
8
+ ::Code::Object::Nothing.new
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ class Code
2
+ class Node
3
+ class Number < Node
4
+ def initialize(parsed)
5
+ if parsed.key?(:decimal)
6
+ @statement = Node::Decimal.new(parsed.delete(:decimal))
7
+ elsif parsed.key?(:base_16)
8
+ @statement = Node::Base16.new(parsed.delete(:base_16))
9
+ elsif parsed.key?(:base_10)
10
+ @statement = Node::Base10.new(parsed.delete(:base_10))
11
+ elsif parsed.key?(:base_8)
12
+ @statement = Node::Base8.new(parsed.delete(:base_8))
13
+ elsif parsed.key?(:base_2)
14
+ @statement = Node::Base2.new(parsed.delete(:base_2))
15
+ end
16
+
17
+ super(parsed)
18
+ end
19
+
20
+ def evaluate(**args)
21
+ @statement.evaluate(**args)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ class Code
2
+ class Node
3
+ class Operation < Node
4
+ class Operator < Node
5
+ attr_reader :operator, :statement
6
+
7
+ def initialize(parsed)
8
+ @operator = parsed.delete(:operator)
9
+ @statement = Node::Statement.new(parsed.delete(:statement))
10
+ end
11
+ end
12
+
13
+ def initialize(parsed)
14
+ @first = Node::Statement.new(parsed.delete(:first))
15
+ @others =
16
+ parsed
17
+ .delete(:others)
18
+ .map { |operator| Node::Operation::Operator.new(operator) }
19
+
20
+ super(parsed)
21
+ end
22
+
23
+ def evaluate(**args)
24
+ first = @first.evaluate(**args)
25
+
26
+ @others.reduce(first) do |left, right|
27
+ statement = right.statement.evaluate(**args)
28
+
29
+ left.call(
30
+ operator: right.operator,
31
+ arguments: [::Code::Object::Argument.new(statement)],
32
+ **args
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ class Code
2
+ class Node
3
+ class Power < Node
4
+ def initialize(parsed)
5
+ @operator = parsed.delete(:operator)
6
+ @left = Node::Statement.new(parsed.delete(:left))
7
+ @right = Node::Statement.new(parsed.delete(:right))
8
+ super(parsed)
9
+ end
10
+
11
+ def evaluate(**args)
12
+ @left.evaluate(**args).call(
13
+ operator: @operator,
14
+ arguments: [::Code::Object::Argument.new(@right.evaluate(**args))],
15
+ **args
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end