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.
- checksums.yaml +7 -0
- data/.editorconfig +9 -0
- data/.github/workflows/rspec.yml +14 -0
- data/.gitignore +2 -0
- data/.prettierrc +3 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +31 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +70 -0
- data/LICENSE +7 -0
- data/README.md +103 -0
- data/TODO.md +1 -0
- data/bin/template +39 -0
- data/code-ruby.gemspec +22 -0
- data/docs/euler/1.template +14 -0
- data/docs/euler/2.template +16 -0
- data/docs/euler/3.template +16 -0
- data/docs/euler/4.template +11 -0
- data/docs/euler/5.template +14 -0
- data/docs/precedence.template +94 -0
- data/lib/code/error.rb +15 -0
- data/lib/code/node/base_10_decimal.rb +32 -0
- data/lib/code/node/base_10_integer.rb +32 -0
- data/lib/code/node/base_10_number.rb +19 -0
- data/lib/code/node/base_16_number.rb +19 -0
- data/lib/code/node/base_2_number.rb +19 -0
- data/lib/code/node/base_8_number.rb +19 -0
- data/lib/code/node/block.rb +17 -0
- data/lib/code/node/boolean.rb +22 -0
- data/lib/code/node/call.rb +52 -0
- data/lib/code/node/call_argument.rb +37 -0
- data/lib/code/node/chained_call.rb +38 -0
- data/lib/code/node/code.rb +16 -0
- data/lib/code/node/defined.rb +19 -0
- data/lib/code/node/dictionnary.rb +22 -0
- data/lib/code/node/dictionnary_key_value.rb +23 -0
- data/lib/code/node/equal.rb +36 -0
- data/lib/code/node/function.rb +17 -0
- data/lib/code/node/function_argument.rb +45 -0
- data/lib/code/node/group.rb +13 -0
- data/lib/code/node/if.rb +55 -0
- data/lib/code/node/if_modifier.rb +48 -0
- data/lib/code/node/keyword_call_argument.rb +30 -0
- data/lib/code/node/keyword_function_argument.rb +33 -0
- data/lib/code/node/list.rb +19 -0
- data/lib/code/node/name.rb +50 -0
- data/lib/code/node/negation.rb +33 -0
- data/lib/code/node/not_keyword.rb +13 -0
- data/lib/code/node/nothing.rb +12 -0
- data/lib/code/node/number.rb +23 -0
- data/lib/code/node/operation.rb +33 -0
- data/lib/code/node/or_keyword.rb +34 -0
- data/lib/code/node/power.rb +16 -0
- data/lib/code/node/range.rb +31 -0
- data/lib/code/node/regular_call_argument.rb +34 -0
- data/lib/code/node/regular_function_argument.rb +36 -0
- data/lib/code/node/rescue.rb +16 -0
- data/lib/code/node/statement.rb +81 -0
- data/lib/code/node/string.rb +17 -0
- data/lib/code/node/ternary.rb +26 -0
- data/lib/code/node/unary_minus.rb +22 -0
- data/lib/code/node/while.rb +42 -0
- data/lib/code/node.rb +14 -0
- data/lib/code/object/argument.rb +41 -0
- data/lib/code/object/boolean.rb +27 -0
- data/lib/code/object/decimal.rb +54 -0
- data/lib/code/object/dictionnary.rb +55 -0
- data/lib/code/object/function.rb +64 -0
- data/lib/code/object/integer.rb +116 -0
- data/lib/code/object/list.rb +217 -0
- data/lib/code/object/nothing.rb +23 -0
- data/lib/code/object/number.rb +6 -0
- data/lib/code/object/range.rb +158 -0
- data/lib/code/object/string.rb +68 -0
- data/lib/code/object.rb +130 -0
- data/lib/code/parser/addition.rb +29 -0
- data/lib/code/parser/and_operator.rb +28 -0
- data/lib/code/parser/bitwise_and.rb +28 -0
- data/lib/code/parser/bitwise_or.rb +29 -0
- data/lib/code/parser/boolean.rb +14 -0
- data/lib/code/parser/call.rb +90 -0
- data/lib/code/parser/code.rb +19 -0
- data/lib/code/parser/defined.rb +20 -0
- data/lib/code/parser/dictionnary.rb +41 -0
- data/lib/code/parser/equal.rb +42 -0
- data/lib/code/parser/equality.rb +36 -0
- data/lib/code/parser/function.rb +57 -0
- data/lib/code/parser/greater_than.rb +33 -0
- data/lib/code/parser/group.rb +17 -0
- data/lib/code/parser/if.rb +33 -0
- data/lib/code/parser/if_modifier.rb +28 -0
- data/lib/code/parser/list.rb +29 -0
- data/lib/code/parser/multiplication.rb +30 -0
- data/lib/code/parser/name.rb +89 -0
- data/lib/code/parser/negation.rb +19 -0
- data/lib/code/parser/not_keyword.rb +21 -0
- data/lib/code/parser/nothing.rb +17 -0
- data/lib/code/parser/number.rb +98 -0
- data/lib/code/parser/or_keyword.rb +29 -0
- data/lib/code/parser/or_operator.rb +28 -0
- data/lib/code/parser/power.rb +25 -0
- data/lib/code/parser/range.rb +25 -0
- data/lib/code/parser/rescue.rb +23 -0
- data/lib/code/parser/shift.rb +31 -0
- data/lib/code/parser/statement.rb +8 -0
- data/lib/code/parser/string.rb +72 -0
- data/lib/code/parser/ternary.rb +25 -0
- data/lib/code/parser/unary_minus.rb +13 -0
- data/lib/code/parser/while.rb +25 -0
- data/lib/code/parser.rb +4 -0
- data/lib/code-ruby.rb +11 -0
- data/lib/code.rb +29 -0
- data/lib/template/node/code_part.rb +13 -0
- data/lib/template/node/part.rb +19 -0
- data/lib/template/node/template.rb +15 -0
- data/lib/template/node/text_part.rb +13 -0
- data/lib/template/node.rb +4 -0
- data/lib/template/parser/template.rb +30 -0
- data/lib/template/parser.rb +4 -0
- data/lib/template/version.rb +3 -0
- data/lib/template-ruby.rb +11 -0
- data/lib/template.rb +34 -0
- data/spec/call_spec.rb +22 -0
- data/spec/code/error/type_error_spec.rb +65 -0
- data/spec/code/parser/boolean_spec.rb +18 -0
- data/spec/code/parser/call_spec.rb +66 -0
- data/spec/code/parser/dictionnary_spec.rb +46 -0
- data/spec/code/parser/function_spec.rb +32 -0
- data/spec/code/parser/list_spec.rb +29 -0
- data/spec/code/parser/name_spec.rb +15 -0
- data/spec/code/parser/nothing_spec.rb +19 -0
- data/spec/code/parser/number_spec.rb +117 -0
- data/spec/code/parser/string_spec.rb +30 -0
- data/spec/code_spec.rb +108 -0
- data/spec/function_spec.rb +26 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/template/parser/template_spec.rb +19 -0
- data/spec/template_spec.rb +27 -0
- data/template-ruby.gemspec +24 -0
- metadata +266 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Operation < Node
|
4
|
+
class Operation
|
5
|
+
attr_reader :operator, :statement
|
6
|
+
|
7
|
+
def initialize(operation)
|
8
|
+
@operator = operation.fetch(:operator).to_s
|
9
|
+
@statement = ::Code::Node::Statement.new(operation.fetch(:statement))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(operation)
|
14
|
+
@first = ::Code::Node::Statement.new(operation.fetch(:first))
|
15
|
+
@rest = operation.fetch(:rest)
|
16
|
+
@rest.map! do |operation|
|
17
|
+
::Code::Node::Operation::Operation.new(operation)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def evaluate(**args)
|
22
|
+
object = @first.evaluate(**args)
|
23
|
+
|
24
|
+
@rest.each do |operation|
|
25
|
+
other = operation.statement.evaluate(**args)
|
26
|
+
object = simple_call(object, operation.operator, other, **args)
|
27
|
+
end
|
28
|
+
|
29
|
+
object
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class OrKeyword < Node
|
4
|
+
OR_KEYWORD = "or"
|
5
|
+
AND_KEYWORD = "and"
|
6
|
+
|
7
|
+
def initialize(or_keyword)
|
8
|
+
@first = ::Code::Node::Statement.new(or_keyword.fetch(:first))
|
9
|
+
@rest = or_keyword.fetch(:rest)
|
10
|
+
@rest.map! do |operation|
|
11
|
+
::Code::Node::Operation::Operation.new(operation)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate(**args)
|
16
|
+
object = @first.evaluate(**args)
|
17
|
+
|
18
|
+
@rest.each do |operation|
|
19
|
+
if operation.operator == OR_KEYWORD
|
20
|
+
return object if object.truthy?
|
21
|
+
elsif operation.operator == AND_KEYWORD
|
22
|
+
return object unless object.truthy?
|
23
|
+
else
|
24
|
+
raise NotImplementedError.new(operation.operator.inspect)
|
25
|
+
end
|
26
|
+
|
27
|
+
object = operation.statement.evaluate(**args)
|
28
|
+
end
|
29
|
+
|
30
|
+
object
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Power < Node
|
4
|
+
def initialize(power)
|
5
|
+
@left = ::Code::Node::Statement.new(power.fetch(:left))
|
6
|
+
@right = ::Code::Node::Statement.new(power.fetch(:right))
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(**args)
|
10
|
+
right = @right.evaluate(**args)
|
11
|
+
left = @left.evaluate(**args)
|
12
|
+
simple_call(left, :**, right, **args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Range < Node
|
4
|
+
INCLUSIVE_RANGE = ".."
|
5
|
+
EXCLUSIVE_RANGE = "..."
|
6
|
+
|
7
|
+
def initialize(range)
|
8
|
+
@left = ::Code::Node::Statement.new(range.fetch(:left))
|
9
|
+
@operator = range.fetch(:operator)
|
10
|
+
@right = ::Code::Node::Statement.new(range.fetch(:right))
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate(**args)
|
14
|
+
left = @left.evaluate(**args)
|
15
|
+
right = @right.evaluate(**args)
|
16
|
+
|
17
|
+
if operator == INCLUSIVE_RANGE
|
18
|
+
::Code::Object::Range.new(left, right, exclude_end: false)
|
19
|
+
elsif operator == EXCLUSIVE_RANGE
|
20
|
+
::Code::Object::Range.new(left, right, exclude_end: true)
|
21
|
+
else
|
22
|
+
raise NotImplementedError.new(operator)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :operator
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class RegularCallArgument < Node
|
4
|
+
def initialize(argument)
|
5
|
+
@splat = argument.key?(:splat)
|
6
|
+
@keyword_splat = argument.key?(:keyword_splat)
|
7
|
+
@block = argument.key?(:block)
|
8
|
+
@value = ::Code::Node::Code.new(argument.fetch(:value))
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate(**args)
|
12
|
+
object = @value.evaluate(**args)
|
13
|
+
|
14
|
+
block? ? simple_call(object, :to_function, **args) : object
|
15
|
+
end
|
16
|
+
|
17
|
+
def block?
|
18
|
+
@block
|
19
|
+
end
|
20
|
+
|
21
|
+
def splat?
|
22
|
+
@splat
|
23
|
+
end
|
24
|
+
|
25
|
+
def keyword_splat?
|
26
|
+
@keyword_splat
|
27
|
+
end
|
28
|
+
|
29
|
+
def name
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class RegularFunctionArgument < Node
|
4
|
+
def initialize(argument)
|
5
|
+
@block = argument.key?(:block)
|
6
|
+
@splat = argument.key?(:splat)
|
7
|
+
@keyword_splat = argument.key?(:keyword_splat)
|
8
|
+
@name = argument.fetch(:name)
|
9
|
+
|
10
|
+
if argument.key?(:default)
|
11
|
+
@default = ::Code::Node::Code.new(argument.fetch(:default))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate(**args)
|
16
|
+
@default ? @default.evaluate(**args) : ::Code::Object::Nothing.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
::Code::Object::String.new(@name.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
def splat?
|
24
|
+
@splat
|
25
|
+
end
|
26
|
+
|
27
|
+
def keyword_splat?
|
28
|
+
@keyword_splat
|
29
|
+
end
|
30
|
+
|
31
|
+
def block?
|
32
|
+
@block
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Rescue < Node
|
4
|
+
def initialize(power)
|
5
|
+
@left = ::Code::Node::Statement.new(power.fetch(:left))
|
6
|
+
@right = ::Code::Node::Statement.new(power.fetch(:right))
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(**args)
|
10
|
+
@left.evaluate(**args)
|
11
|
+
rescue ::Code::Error
|
12
|
+
@right.evaluate(**args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Statement < Node
|
4
|
+
attr_reader :statement
|
5
|
+
|
6
|
+
def initialize(statement)
|
7
|
+
if statement.key?(:nothing)
|
8
|
+
@statement = ::Code::Node::Nothing.new
|
9
|
+
elsif statement.key?(:boolean)
|
10
|
+
@statement = ::Code::Node::Boolean.new(statement[:boolean])
|
11
|
+
elsif statement.key?(:number)
|
12
|
+
@statement = ::Code::Node::Number.new(statement[:number])
|
13
|
+
elsif statement.key?(:string)
|
14
|
+
@statement = ::Code::Node::String.new(statement[:string])
|
15
|
+
elsif statement.key?(:call)
|
16
|
+
@statement = ::Code::Node::Call.new(statement[:call])
|
17
|
+
elsif statement.key?(:name)
|
18
|
+
@statement = ::Code::Node::Name.new(statement[:name])
|
19
|
+
elsif statement.key?(:list)
|
20
|
+
@statement = ::Code::Node::List.new(statement[:list])
|
21
|
+
elsif statement.key?(:dictionnary)
|
22
|
+
@statement = ::Code::Node::Dictionnary.new(statement[:dictionnary])
|
23
|
+
elsif statement.key?(:negation)
|
24
|
+
@statement = ::Code::Node::Negation.new(statement[:negation])
|
25
|
+
elsif statement.key?(:power)
|
26
|
+
@statement = ::Code::Node::Power.new(statement[:power])
|
27
|
+
elsif statement.key?(:unary_minus)
|
28
|
+
@statement = ::Code::Node::UnaryMinus.new(statement[:unary_minus])
|
29
|
+
elsif statement.key?(:multiplication)
|
30
|
+
@statement = ::Code::Node::Operation.new(statement[:multiplication])
|
31
|
+
elsif statement.key?(:addition)
|
32
|
+
@statement = ::Code::Node::Operation.new(statement[:addition])
|
33
|
+
elsif statement.key?(:shift)
|
34
|
+
@statement = ::Code::Node::Operation.new(statement[:shift])
|
35
|
+
elsif statement.key?(:bitwise_and)
|
36
|
+
@statement = ::Code::Node::Operation.new(statement[:bitwise_and])
|
37
|
+
elsif statement.key?(:bitwise_or)
|
38
|
+
@statement = ::Code::Node::Operation.new(statement[:bitwise_or])
|
39
|
+
elsif statement.key?(:greater_than)
|
40
|
+
@statement = ::Code::Node::Operation.new(statement[:greater_than])
|
41
|
+
elsif statement.key?(:equality)
|
42
|
+
@statement = ::Code::Node::Operation.new(statement[:equality])
|
43
|
+
elsif statement.key?(:and_operator)
|
44
|
+
@statement = ::Code::Node::Operation.new(statement[:and_operator])
|
45
|
+
elsif statement.key?(:or_operator)
|
46
|
+
@statement = ::Code::Node::Operation.new(statement[:or_operator])
|
47
|
+
elsif statement.key?(:range)
|
48
|
+
@statement = ::Code::Node::Range.new(statement[:range])
|
49
|
+
elsif statement.key?(:ternary)
|
50
|
+
@statement = ::Code::Node::Ternary.new(statement[:ternary])
|
51
|
+
elsif statement.key?(:rescue)
|
52
|
+
@statement = ::Code::Node::Rescue.new(statement[:rescue])
|
53
|
+
elsif statement.key?(:equal)
|
54
|
+
@statement = ::Code::Node::Equal.new(statement[:equal])
|
55
|
+
elsif statement.key?(:defined)
|
56
|
+
@statement = ::Code::Node::Defined.new(statement[:defined])
|
57
|
+
elsif statement.key?(:not_keyword)
|
58
|
+
@statement = ::Code::Node::NotKeyword.new(statement[:not_keyword])
|
59
|
+
elsif statement.key?(:or_keyword)
|
60
|
+
@statement = ::Code::Node::OrKeyword.new(statement[:or_keyword])
|
61
|
+
elsif statement.key?(:if_modifier)
|
62
|
+
@statement = ::Code::Node::IfModifier.new(statement[:if_modifier])
|
63
|
+
elsif statement.key?(:if)
|
64
|
+
@statement = ::Code::Node::If.new(statement[:if])
|
65
|
+
elsif statement.key?(:while)
|
66
|
+
@statement = ::Code::Node::While.new(statement[:while])
|
67
|
+
elsif statement.key?(:group)
|
68
|
+
@statement = ::Code::Node::Group.new(statement[:group])
|
69
|
+
elsif statement.key?(:function)
|
70
|
+
@statement = ::Code::Node::Function.new(statement[:function])
|
71
|
+
else
|
72
|
+
raise NotImplementedError.new(statement.inspect)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def evaluate(**args)
|
77
|
+
@statement.evaluate(**args)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Ternary < Node
|
4
|
+
def initialize(ternary)
|
5
|
+
@left = ::Code::Node::Statement.new(ternary.fetch(:left))
|
6
|
+
@middle = ::Code::Node::Statement.new(ternary.fetch(:middle))
|
7
|
+
|
8
|
+
if ternary.key?(:right)
|
9
|
+
@right = ::Code::Node::Statement.new(ternary.fetch(:right))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate(**args)
|
14
|
+
left = @left.evaluate(**args)
|
15
|
+
|
16
|
+
if left.truthy?
|
17
|
+
@middle.evaluate(**args)
|
18
|
+
elsif @right
|
19
|
+
@right.evaluate(**args)
|
20
|
+
else
|
21
|
+
::Code::Object::Nothing.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class UnaryMinus < Node
|
4
|
+
def initialize(unary_minus)
|
5
|
+
@statement = ::Code::Node::Statement.new(unary_minus)
|
6
|
+
end
|
7
|
+
|
8
|
+
def evaluate(**args)
|
9
|
+
object = @statement.evaluate(**args)
|
10
|
+
|
11
|
+
case object
|
12
|
+
when ::Code::Object::Integer
|
13
|
+
::Code::Object::Integer.new(-object.raw)
|
14
|
+
when ::Code::Object::Decimal
|
15
|
+
::Code::Object::Decimal.new(-object.raw)
|
16
|
+
else
|
17
|
+
::Code::Object::Nothing.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class While < Node
|
4
|
+
WHILE_KEYWORD = :while
|
5
|
+
UNTIL_KEYWORD = :until
|
6
|
+
|
7
|
+
def initialize(while_parsed)
|
8
|
+
@operator = while_parsed.fetch(:operator)
|
9
|
+
@statement = ::Code::Node::Statement.new(while_parsed.fetch(:statement))
|
10
|
+
@body = ::Code::Node::Code.new(while_parsed.fetch(:body))
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate(**args)
|
14
|
+
if operator == WHILE_KEYWORD
|
15
|
+
object = ::Code::Object::Nothing.new
|
16
|
+
|
17
|
+
while @statement.evaluate(**args).truthy?
|
18
|
+
object = @body.evaluate(**args)
|
19
|
+
end
|
20
|
+
|
21
|
+
object
|
22
|
+
elsif operator == UNTIL_KEYWORD
|
23
|
+
object = ::Code::Object::Nothing.new
|
24
|
+
|
25
|
+
until @statement.evaluate(**args).truthy?
|
26
|
+
object = @body.evaluate(**args)
|
27
|
+
end
|
28
|
+
|
29
|
+
object
|
30
|
+
else
|
31
|
+
raise NotImplementedError.new(operator.inspect)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def operator
|
38
|
+
@operator.to_sym
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/code/node.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
private
|
4
|
+
|
5
|
+
def simple_call(object, operator = nil, value = nil, **args)
|
6
|
+
object.call(
|
7
|
+
operator: operator && ::Code::Object::String.new(operator.to_s),
|
8
|
+
arguments: [value && ::Code::Object::Argument.new(value)].compact,
|
9
|
+
context: args.fetch(:context),
|
10
|
+
io: args.fetch(:io),
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Code
|
2
|
+
class Object
|
3
|
+
class Argument < ::Code::Object
|
4
|
+
attr_reader :value, :name, :splat, :keyword_splat, :block
|
5
|
+
|
6
|
+
def initialize(
|
7
|
+
value,
|
8
|
+
name: nil,
|
9
|
+
splat: false,
|
10
|
+
keyword_splat: false,
|
11
|
+
block: false
|
12
|
+
)
|
13
|
+
@value = value
|
14
|
+
@name = name
|
15
|
+
@splat = !!splat
|
16
|
+
@keyword_splat = !!keyword_splat
|
17
|
+
@block = !!block
|
18
|
+
end
|
19
|
+
|
20
|
+
def regular?
|
21
|
+
!name
|
22
|
+
end
|
23
|
+
|
24
|
+
def keyword?
|
25
|
+
!regular?
|
26
|
+
end
|
27
|
+
|
28
|
+
def name_value
|
29
|
+
[name, value]
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"argument"
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Code
|
2
|
+
class Object
|
3
|
+
class Boolean < ::Code::Object
|
4
|
+
attr_reader :raw
|
5
|
+
|
6
|
+
def initialize(raw)
|
7
|
+
@raw = raw
|
8
|
+
end
|
9
|
+
|
10
|
+
def truthy?
|
11
|
+
raw
|
12
|
+
end
|
13
|
+
|
14
|
+
def succ
|
15
|
+
::Code::Object::Boolean.new(!raw)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
raw.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Code
|
2
|
+
class Object
|
3
|
+
class Decimal < ::Code::Object::Number
|
4
|
+
attr_reader :raw
|
5
|
+
|
6
|
+
def initialize(decimal, exponent: nil)
|
7
|
+
@raw = BigDecimal(decimal)
|
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 %w[% - + / * **].detect { |o| operator == o }
|
23
|
+
number_operation(operator.to_sym, arguments)
|
24
|
+
elsif %w[< <= > >=].detect { |o| operator == o }
|
25
|
+
comparaison(operator.to_sym, arguments)
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
raw.to_s("F")
|
33
|
+
end
|
34
|
+
|
35
|
+
def inspect
|
36
|
+
to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def number_operation(operator, arguments)
|
42
|
+
sig(arguments, ::Code::Object::Number)
|
43
|
+
other = arguments.first.value
|
44
|
+
::Code::Object::Decimal.new(raw.public_send(operator, other.raw))
|
45
|
+
end
|
46
|
+
|
47
|
+
def comparaison(operator, arguments)
|
48
|
+
sig(arguments, ::Code::Object::Number)
|
49
|
+
other = arguments.first.value
|
50
|
+
::Code::Object::Boolean.new(raw.public_send(operator, other.raw))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Code
|
2
|
+
class Object
|
3
|
+
class Dictionnary < ::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
|
+
|
14
|
+
if operator == "values"
|
15
|
+
values(arguments)
|
16
|
+
elsif key?(operator)
|
17
|
+
fetch(operator)
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch(key)
|
24
|
+
raw.fetch(key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](key)
|
28
|
+
raw[key]
|
29
|
+
end
|
30
|
+
|
31
|
+
def []=(key, value)
|
32
|
+
raw[key] = value
|
33
|
+
end
|
34
|
+
|
35
|
+
def key?(key)
|
36
|
+
raw.key?(key)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
"{#{raw.map { |key, value| "#{key.inspect} => #{value.inspect}" }.join(", ")}}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def inspect
|
44
|
+
to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def values(arguments)
|
50
|
+
sig(arguments)
|
51
|
+
::Code::Object::List.new(raw.values)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Code
|
2
|
+
class Object
|
3
|
+
class Function < ::Code::Object
|
4
|
+
def initialize(arguments:, body:)
|
5
|
+
@arguments = arguments
|
6
|
+
@body = body
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(**args)
|
10
|
+
operator = args.fetch(:operator, nil)
|
11
|
+
arguments = args.fetch(:arguments, [])
|
12
|
+
context = args.fetch(:context)
|
13
|
+
io = args.fetch(:io)
|
14
|
+
|
15
|
+
if operator.nil?
|
16
|
+
call_function(args: arguments, context: context, io: io)
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
""
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
"function"
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :arguments, :body
|
33
|
+
|
34
|
+
def call_function(args:, context:, io:)
|
35
|
+
new_context = context.dup
|
36
|
+
arguments.each.with_index do |argument, index|
|
37
|
+
if argument.regular?
|
38
|
+
if argument.splat?
|
39
|
+
new_context[argument.name] = ::Code::Object::List.new(
|
40
|
+
args.select(&:regular?).map(&:value),
|
41
|
+
)
|
42
|
+
elsif argument.keyword_splat?
|
43
|
+
new_context[argument.name] = ::Code::Object::Dictionnary.new(
|
44
|
+
args.select(&:keyword?).map(&:name_value).to_h,
|
45
|
+
)
|
46
|
+
else
|
47
|
+
arg = args[index]&.value
|
48
|
+
arg = argument.evaluate(context: new_context, io: io) if arg.nil?
|
49
|
+
new_context[argument.name] = arg
|
50
|
+
end
|
51
|
+
elsif argument.keyword?
|
52
|
+
arg = args.detect { |arg| arg.name == argument.name }&.value
|
53
|
+
arg = argument.evaluate(context: new_context, io: io) if arg.nil?
|
54
|
+
new_context[argument.name] = arg
|
55
|
+
else
|
56
|
+
raise NotImplementedError
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
body.evaluate(context: new_context, io: io)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|