code-ruby 0.5.6 → 0.6.1
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 +4 -4
- data/Gemfile +1 -3
- data/Gemfile.lock +11 -21
- data/README.md +2 -102
- data/bin/code +34 -16
- data/code-ruby.gemspec +5 -3
- data/lib/code/error.rb +16 -5
- data/lib/code/node/base_10.rb +4 -2
- data/lib/code/node/base_16.rb +3 -1
- data/lib/code/node/base_2.rb +3 -1
- data/lib/code/node/base_8.rb +3 -1
- data/lib/code/node/boolean.rb +4 -2
- data/lib/code/node/call.rb +35 -12
- data/lib/code/node/call_argument.rb +16 -5
- data/lib/code/node/code.rb +5 -4
- data/lib/code/node/decimal.rb +2 -0
- data/lib/code/node/{dictionnary.rb → dictionary.rb} +14 -5
- data/lib/code/node/function.rb +7 -4
- data/lib/code/node/function_parameter.rb +3 -1
- data/lib/code/node/if.rb +5 -3
- data/lib/code/node/left_operation.rb +63 -0
- data/lib/code/node/list.rb +2 -0
- data/lib/code/node/negation.rb +2 -0
- data/lib/code/node/not.rb +2 -0
- data/lib/code/node/nothing.rb +3 -1
- data/lib/code/node/number.rb +2 -0
- data/lib/code/node/right_operation.rb +70 -0
- data/lib/code/node/splat.rb +2 -0
- data/lib/code/node/square_bracket.rb +37 -0
- data/lib/code/node/statement.rb +13 -5
- data/lib/code/node/string.rb +3 -1
- data/lib/code/node/ternary.rb +5 -3
- data/lib/code/node/unary_minus.rb +2 -0
- data/lib/code/node/while.rb +6 -4
- data/lib/code/node.rb +11 -5
- data/lib/code/object/argument.rb +13 -7
- data/lib/code/object/boolean.rb +43 -5
- data/lib/code/object/class.rb +17 -0
- data/lib/code/object/context.rb +36 -0
- data/lib/code/object/decimal.rb +252 -100
- data/lib/code/object/dictionary.rb +641 -0
- data/lib/code/object/function.rb +54 -27
- data/lib/code/object/global.rb +65 -19
- data/lib/code/object/identifier_list.rb +47 -0
- data/lib/code/object/integer.rb +320 -137
- data/lib/code/object/list.rb +140 -138
- data/lib/code/object/nothing.rb +10 -4
- data/lib/code/object/number.rb +6 -1
- data/lib/code/object/range.rb +85 -88
- data/lib/code/object/ruby_function.rb +11 -6
- data/lib/code/object/string.rb +51 -48
- data/lib/code/object.rb +117 -139
- data/lib/code/parser/addition.rb +4 -2
- data/lib/code/parser/and_operator.rb +4 -2
- data/lib/code/parser/bitwise_and.rb +4 -2
- data/lib/code/parser/bitwise_or.rb +4 -2
- data/lib/code/parser/boolean.rb +3 -1
- data/lib/code/parser/call.rb +17 -11
- data/lib/code/parser/chained_call.rb +10 -22
- data/lib/code/parser/class.rb +9 -6
- data/lib/code/parser/code.rb +6 -4
- data/lib/code/parser/{dictionnary.rb → dictionary.rb} +16 -13
- data/lib/code/parser/equal.rb +9 -36
- data/lib/code/parser/equality.rb +4 -2
- data/lib/code/parser/function.rb +24 -9
- data/lib/code/parser/greater.rb +6 -3
- data/lib/code/parser/group.rb +4 -2
- data/lib/code/parser/if.rb +6 -4
- data/lib/code/parser/if_modifier.rb +5 -25
- data/lib/code/parser/left_operation.rb +40 -0
- data/lib/code/parser/list.rb +6 -5
- data/lib/code/parser/multiplication.rb +4 -2
- data/lib/code/parser/name.rb +19 -4
- data/lib/code/parser/negation.rb +4 -2
- data/lib/code/parser/not_keyword.rb +5 -3
- data/lib/code/parser/nothing.rb +3 -10
- data/lib/code/parser/number.rb +4 -2
- data/lib/code/parser/or_keyword.rb +4 -2
- data/lib/code/parser/or_operator.rb +4 -2
- data/lib/code/parser/power.rb +4 -28
- data/lib/code/parser/range.rb +4 -2
- data/lib/code/parser/rescue.rb +6 -26
- data/lib/code/parser/right_operation.rb +40 -0
- data/lib/code/parser/shift.rb +4 -2
- data/lib/code/parser/splat.rb +5 -3
- data/lib/code/parser/square_bracket.rb +48 -0
- data/lib/code/parser/statement.rb +3 -1
- data/lib/code/parser/string.rb +12 -10
- data/lib/code/parser/ternary.rb +10 -11
- data/lib/code/parser/unary_minus.rb +5 -3
- data/lib/code/parser/while.rb +5 -3
- data/lib/code/parser/whitespace.rb +2 -0
- data/lib/code/parser.rb +10 -3
- data/lib/code/ruby.rb +4 -2
- data/lib/code/type/hash.rb +38 -0
- data/lib/code/type/maybe.rb +29 -0
- data/lib/code/type/or.rb +38 -0
- data/lib/code/type/repeat.rb +38 -0
- data/lib/code/type/sig.rb +130 -0
- data/lib/code/type.rb +25 -0
- data/lib/code/version.rb +3 -0
- data/lib/code-ruby.rb +1 -2
- data/lib/code.rb +15 -16
- data/spec/code/node/call_spec.rb +39 -0
- data/spec/code/object/boolean_spec.rb +18 -0
- data/spec/code/object/decimal_spec.rb +51 -0
- data/spec/code/object/dictionary_spec.rb +98 -0
- data/spec/code/object/function_spec.rb +42 -0
- data/spec/code/object/integer_spec.rb +43 -0
- data/spec/code/object/nothing_spec.rb +14 -0
- data/spec/code/object/range_spec.rb +23 -0
- data/spec/code/parser/boolean_spec.rb +5 -10
- data/spec/code/parser/chained_call.rb +4 -5
- data/spec/code/parser/{dictionnary_spec.rb → dictionary_spec.rb} +5 -6
- data/spec/code/parser/function_spec.rb +4 -5
- data/spec/code/parser/group_spec.rb +5 -12
- data/spec/code/parser/if_modifier_spec.rb +18 -0
- data/spec/code/parser/list_spec.rb +4 -5
- data/spec/code/parser/number_spec.rb +4 -5
- data/spec/code/parser/string_spec.rb +4 -5
- data/spec/code/parser_spec.rb +22 -16
- data/spec/code/type_spec.rb +21 -0
- data/spec/code_spec.rb +171 -0
- data/spec/spec_helper.rb +1 -6
- metadata +63 -136
- data/.cherry.js +0 -21
- data/.editorconfig +0 -9
- data/.github/workflows/rspec.yml +0 -14
- data/.gitignore +0 -2
- data/.prettierrc +0 -3
- data/.tool-versions +0 -1
- data/CHANGELOG.md +0 -55
- data/LICENSE +0 -7
- data/TODO +0 -17
- data/bin/format +0 -3
- data/bin/publish +0 -19
- data/bin/template +0 -85
- data/bin/test +0 -17
- data/docs/class.code +0 -9
- data/docs/euler/1.template +0 -10
- data/docs/euler/2.template +0 -16
- data/docs/euler/3.template +0 -16
- data/docs/euler/4.template +0 -10
- data/docs/euler/5.template +0 -13
- data/docs/fibonnaci.template +0 -14
- data/docs/meetup.code +0 -12
- data/docs/precedence.template +0 -36
- data/docs/rain.code +0 -22
- data/docs/slack.code +0 -17
- data/docs/stripe.code +0 -7
- data/docs/twitter.code +0 -9
- data/language-ruby.gemspec +0 -17
- data/lib/code/node/chained_call.rb +0 -23
- data/lib/code/node/equal.rb +0 -34
- data/lib/code/node/if_modifier.rb +0 -47
- data/lib/code/node/operation.rb +0 -38
- data/lib/code/node/power.rb +0 -20
- data/lib/code/node/rescue.rb +0 -17
- data/lib/code/object/dictionnary.rb +0 -96
- data/lib/code/parser/equality_lower.rb +0 -9
- data/lib/code/parser/operation.rb +0 -35
- data/lib/language/atom.rb +0 -342
- data/lib/language/output.rb +0 -130
- data/lib/language/parser/absent/present.rb +0 -8
- data/lib/language/parser/absent.rb +0 -6
- data/lib/language/parser/end_of_input.rb +0 -6
- data/lib/language/parser/interuption.rb +0 -38
- data/lib/language/parser/not_end_of_input.rb +0 -6
- data/lib/language/parser/str/not_found.rb +0 -16
- data/lib/language/parser/str.rb +0 -6
- data/lib/language/parser.rb +0 -53
- data/lib/language-ruby.rb +0 -10
- data/lib/language.rb +0 -80
- data/lib/template/node/code_part.rb +0 -13
- data/lib/template/node/part.rb +0 -19
- data/lib/template/node/template.rb +0 -15
- data/lib/template/node/text_part.rb +0 -13
- data/lib/template/node.rb +0 -4
- data/lib/template/parser/template.rb +0 -39
- data/lib/template/parser.rb +0 -19
- data/lib/template/version.rb +0 -3
- data/lib/template-ruby.rb +0 -10
- data/lib/template.rb +0 -50
- data/spec/code/addition_spec.rb +0 -13
- data/spec/code/and_operator_spec.rb +0 -13
- data/spec/code/bitwise_and_spec.rb +0 -13
- data/spec/code/bitwise_or_spec.rb +0 -13
- data/spec/code/boolean_spec.rb +0 -13
- data/spec/code/call_spec.rb +0 -21
- data/spec/code/chained_call_spec.rb +0 -16
- data/spec/code/code_spec.rb +0 -29
- data/spec/code/dictionnary_spec.rb +0 -17
- data/spec/code/equal_spec.rb +0 -26
- data/spec/code/equality_spec.rb +0 -13
- data/spec/code/function_spec.rb +0 -18
- data/spec/code/greater_spec.rb +0 -18
- data/spec/code/group_spec.rb +0 -12
- data/spec/code/if_modifier_spec.rb +0 -20
- data/spec/code/if_spec.rb +0 -25
- data/spec/code/list_spec.rb +0 -19
- data/spec/code/multiplication_spec.rb +0 -18
- data/spec/code/negation_spec.rb +0 -20
- data/spec/code/not_keyword_spec.rb +0 -13
- data/spec/code/nothing_spec.rb +0 -17
- data/spec/code/number_spec.rb +0 -22
- data/spec/code/or_keyword_spec.rb +0 -17
- data/spec/code/or_operator_spec.rb +0 -16
- data/spec/code/parser/call_spec.rb +0 -26
- data/spec/code/power_spec.rb +0 -13
- data/spec/code/range_spec.rb +0 -16
- data/spec/code/rescue_spec.rb +0 -13
- data/spec/code/shift_spec.rb +0 -13
- data/spec/code/splat_spec.rb +0 -13
- data/spec/code/string_spec.rb +0 -27
- data/spec/code/ternary_spec.rb +0 -18
- data/spec/code/unary_minus_spec.rb +0 -13
- data/spec/code/while_spec.rb +0 -18
- data/template-ruby.gemspec +0 -19
data/lib/code/parser/range.rb
CHANGED
data/lib/code/parser/rescue.rb
CHANGED
@@ -1,38 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Code
|
2
4
|
class Parser
|
3
|
-
class Rescue <
|
5
|
+
class Rescue < RightOperation
|
4
6
|
def statement
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
def rescue_class
|
9
|
-
::Code::Parser::Rescue
|
10
|
-
end
|
11
|
-
|
12
|
-
def whitespace
|
13
|
-
::Code::Parser::Whitespace
|
14
|
-
end
|
15
|
-
|
16
|
-
def whitespace?
|
17
|
-
whitespace.maybe
|
7
|
+
Ternary
|
18
8
|
end
|
19
9
|
|
20
10
|
def rescue_keyword
|
21
11
|
str("rescue")
|
22
12
|
end
|
23
13
|
|
24
|
-
def
|
25
|
-
|
26
|
-
statement.aka(:left) <<
|
27
|
-
(
|
28
|
-
whitespace? << rescue_keyword << whitespace? <<
|
29
|
-
rescue_class.aka(:right)
|
30
|
-
).maybe
|
31
|
-
)
|
32
|
-
.aka(:rescue)
|
33
|
-
.then do |output|
|
34
|
-
output[:rescue][:right] ? output : output[:rescue][:left]
|
35
|
-
end
|
14
|
+
def operator
|
15
|
+
rescue_keyword
|
36
16
|
end
|
37
17
|
end
|
38
18
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Code
|
4
|
+
class Parser
|
5
|
+
class RightOperation < Language
|
6
|
+
def statement
|
7
|
+
raise NotImplementedError
|
8
|
+
end
|
9
|
+
|
10
|
+
def whitespace
|
11
|
+
Whitespace
|
12
|
+
end
|
13
|
+
|
14
|
+
def whitespace?
|
15
|
+
whitespace.maybe
|
16
|
+
end
|
17
|
+
|
18
|
+
def operator
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
|
22
|
+
def root
|
23
|
+
(
|
24
|
+
statement.aka(:left) << (
|
25
|
+
whitespace? << operator.aka(:operator) << whitespace? <<
|
26
|
+
self.class.aka(:right)
|
27
|
+
).maybe
|
28
|
+
)
|
29
|
+
.aka(:right_operation)
|
30
|
+
.then do |output|
|
31
|
+
if output[:right_operation][:right]
|
32
|
+
output
|
33
|
+
else
|
34
|
+
output[:right_operation][:left]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/code/parser/shift.rb
CHANGED
data/lib/code/parser/splat.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Code
|
2
4
|
class Parser
|
3
5
|
class Splat < Language
|
4
6
|
def statement
|
5
|
-
|
7
|
+
Class
|
6
8
|
end
|
7
9
|
|
8
10
|
def splat
|
9
|
-
|
11
|
+
Splat
|
10
12
|
end
|
11
13
|
|
12
14
|
def whitespace
|
13
|
-
|
15
|
+
Whitespace
|
14
16
|
end
|
15
17
|
|
16
18
|
def whitespace?
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Code
|
4
|
+
class Parser
|
5
|
+
class SquareBracket < Language
|
6
|
+
def statement
|
7
|
+
UnaryMinus
|
8
|
+
end
|
9
|
+
|
10
|
+
def square_bracket
|
11
|
+
SquareBracket
|
12
|
+
end
|
13
|
+
|
14
|
+
def whitespace
|
15
|
+
Whitespace
|
16
|
+
end
|
17
|
+
|
18
|
+
def whitespace?
|
19
|
+
whitespace.maybe
|
20
|
+
end
|
21
|
+
|
22
|
+
def left_square_bracket
|
23
|
+
str("[")
|
24
|
+
end
|
25
|
+
|
26
|
+
def right_square_bracket
|
27
|
+
str("]")
|
28
|
+
end
|
29
|
+
|
30
|
+
def root
|
31
|
+
(
|
32
|
+
statement.aka(:left) << (
|
33
|
+
left_square_bracket << whitespace? << square_bracket <<
|
34
|
+
(whitespace? << right_square_bracket).maybe
|
35
|
+
).repeat(1).aka(:statements).maybe
|
36
|
+
)
|
37
|
+
.aka(:square_bracket)
|
38
|
+
.then do |output|
|
39
|
+
if output[:square_bracket][:statements]
|
40
|
+
output
|
41
|
+
else
|
42
|
+
output[:square_bracket][:left]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/code/parser/string.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Code
|
2
4
|
class Parser
|
3
5
|
class String < Language
|
4
6
|
def code
|
5
|
-
|
7
|
+
Code
|
6
8
|
end
|
7
9
|
|
8
10
|
def name
|
9
|
-
|
11
|
+
Name
|
10
12
|
end
|
11
13
|
|
12
14
|
def single_quote
|
@@ -18,7 +20,7 @@ class Code
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def backslash
|
21
|
-
str(
|
23
|
+
str('\\')
|
22
24
|
end
|
23
25
|
|
24
26
|
def opening_curly_bracket
|
@@ -54,15 +56,15 @@ class Code
|
|
54
56
|
end
|
55
57
|
|
56
58
|
def single_quoted_string
|
57
|
-
single_quote.ignore <<
|
58
|
-
|
59
|
-
|
59
|
+
single_quote.ignore << (
|
60
|
+
code_part.aka(:code) | single_quoted_text_part.aka(:text)
|
61
|
+
).repeat << single_quote.ignore.maybe
|
60
62
|
end
|
61
63
|
|
62
64
|
def double_quoted_string
|
63
|
-
double_quote.ignore <<
|
64
|
-
|
65
|
-
|
65
|
+
double_quote.ignore << (
|
66
|
+
code_part.aka(:code) | double_quoted_text_part.aka(:text)
|
67
|
+
).repeat << double_quote.ignore.maybe
|
66
68
|
end
|
67
69
|
|
68
70
|
def symbol
|
@@ -71,7 +73,7 @@ class Code
|
|
71
73
|
|
72
74
|
def root
|
73
75
|
(single_quoted_string | double_quoted_string | symbol).aka(:string) |
|
74
|
-
|
76
|
+
Number
|
75
77
|
end
|
76
78
|
end
|
77
79
|
end
|
data/lib/code/parser/ternary.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Code
|
2
4
|
class Parser
|
3
5
|
class Ternary < Language
|
4
6
|
def statement
|
5
|
-
|
7
|
+
Range
|
6
8
|
end
|
7
9
|
|
8
10
|
def ternary
|
9
|
-
|
11
|
+
Ternary
|
10
12
|
end
|
11
13
|
|
12
14
|
def whitespace
|
13
|
-
|
15
|
+
Whitespace
|
14
16
|
end
|
15
17
|
|
16
18
|
def whitespace?
|
@@ -27,14 +29,11 @@ class Code
|
|
27
29
|
|
28
30
|
def root
|
29
31
|
(
|
30
|
-
statement.aka(:left) <<
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
whitespace? << colon << whitespace? << ternary.aka(:right)
|
36
|
-
).maybe
|
37
|
-
).maybe
|
32
|
+
statement.aka(:left) << (
|
33
|
+
whitespace? << question_mark << whitespace? <<
|
34
|
+
ternary.aka(:middle) <<
|
35
|
+
(whitespace? << colon << whitespace? << ternary.aka(:right)).maybe
|
36
|
+
).maybe
|
38
37
|
)
|
39
38
|
.aka(:ternary)
|
40
39
|
.then do |output|
|
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Code
|
2
4
|
class Parser
|
3
5
|
class UnaryMinus < Language
|
4
6
|
def unary_minus
|
5
|
-
|
7
|
+
UnaryMinus
|
6
8
|
end
|
7
9
|
|
8
10
|
def whitespace
|
9
|
-
|
11
|
+
Whitespace
|
10
12
|
end
|
11
13
|
|
12
14
|
def whitespace?
|
@@ -24,7 +26,7 @@ class Code
|
|
24
26
|
def root
|
25
27
|
(operator.aka(:operator) << whitespace? << unary_minus.aka(:right)).aka(
|
26
28
|
:unary_minus
|
27
|
-
) |
|
29
|
+
) | Power
|
28
30
|
end
|
29
31
|
end
|
30
32
|
end
|
data/lib/code/parser/while.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Code
|
2
4
|
class Parser
|
3
5
|
class While < Language
|
4
6
|
def statement
|
5
|
-
|
7
|
+
If
|
6
8
|
end
|
7
9
|
|
8
10
|
def whitespace
|
9
|
-
|
11
|
+
Whitespace
|
10
12
|
end
|
11
13
|
|
12
14
|
def code
|
13
|
-
|
15
|
+
Code
|
14
16
|
end
|
15
17
|
|
16
18
|
def while_keyword
|
data/lib/code/parser.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Code
|
2
4
|
class Parser
|
5
|
+
class Error < StandardError
|
6
|
+
end
|
7
|
+
|
3
8
|
def initialize(input)
|
4
9
|
@input = input
|
5
10
|
end
|
6
11
|
|
7
|
-
def self.parse(
|
8
|
-
new(
|
12
|
+
def self.parse(...)
|
13
|
+
new(...).parse
|
9
14
|
end
|
10
15
|
|
11
16
|
def parse
|
12
|
-
|
17
|
+
Code.parse(input)
|
18
|
+
rescue Language::Parser::NotEndOfInput => e
|
19
|
+
raise Error, e.message
|
13
20
|
end
|
14
21
|
|
15
22
|
private
|
data/lib/code/ruby.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Code
|
2
4
|
class Ruby
|
3
5
|
def initialize(raw = {})
|
@@ -32,7 +34,7 @@ class Code
|
|
32
34
|
elsif big_decimal?
|
33
35
|
::Code::Object::Decimal.new(raw)
|
34
36
|
elsif hash?
|
35
|
-
::Code::Object::
|
37
|
+
::Code::Object::Dictionary.new(
|
36
38
|
raw
|
37
39
|
.map do |key, value|
|
38
40
|
[::Code::Ruby.to_code(key), ::Code::Ruby.to_code(value)]
|
@@ -164,7 +166,7 @@ class Code
|
|
164
166
|
end
|
165
167
|
|
166
168
|
def code_dictionnary?
|
167
|
-
raw.is_a?(::Code::Object::
|
169
|
+
raw.is_a?(::Code::Object::Dictionary)
|
168
170
|
end
|
169
171
|
|
170
172
|
def code_list?
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Code
|
4
|
+
class Type
|
5
|
+
class Hash < Type
|
6
|
+
attr_reader :hash
|
7
|
+
|
8
|
+
def initialize(hash)
|
9
|
+
@hash = hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(argument)
|
13
|
+
return false unless argument.is_a?(Object::Dictionary)
|
14
|
+
argument = argument.raw
|
15
|
+
(argument.keys + hash.keys).uniq.all? do |key|
|
16
|
+
next false unless hash[key] && argument[key]
|
17
|
+
valid_for?(expected: hash[key], actual: argument[key])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def min_arguments
|
22
|
+
hash.sum do |_, value|
|
23
|
+
min_arguments_of(value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def max_arguments
|
28
|
+
hash.sum do |_, value|
|
29
|
+
max_arguments_of(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def name
|
34
|
+
"{#{hash.map { |key, value| "#{key.inspect} => #{value.name}" }.join(", ")}}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Code
|
4
|
+
class Type
|
5
|
+
class Maybe < Type
|
6
|
+
attr_reader :clazz
|
7
|
+
|
8
|
+
def initialize(clazz)
|
9
|
+
@clazz = clazz
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(argument)
|
13
|
+
!argument || valid_for?(expected: clazz, actual: argument)
|
14
|
+
end
|
15
|
+
|
16
|
+
def min_arguments
|
17
|
+
0
|
18
|
+
end
|
19
|
+
|
20
|
+
def max_arguments
|
21
|
+
max_arguments_of(clazz)
|
22
|
+
end
|
23
|
+
|
24
|
+
def name
|
25
|
+
"#{clazz.name}.maybe"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/code/type/or.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Code
|
4
|
+
class Type
|
5
|
+
class Or < Type
|
6
|
+
attr_reader :left, :right
|
7
|
+
|
8
|
+
def initialize(left, right)
|
9
|
+
@left = left
|
10
|
+
@right = right
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid?(argument)
|
14
|
+
valid_for?(expected: left, actual: argument) ||
|
15
|
+
valid_for?(expected: right, actual: argument)
|
16
|
+
end
|
17
|
+
|
18
|
+
def min_arguments
|
19
|
+
[min_arguments_of(left), min_arguments_of(right)].min
|
20
|
+
end
|
21
|
+
|
22
|
+
def max_arguments
|
23
|
+
left_max_arguments = max_arguments_of(left)
|
24
|
+
right_max_arguments = max_arguments_of(right)
|
25
|
+
|
26
|
+
if left_max_arguments.nil? || right_max_arguments.nil?
|
27
|
+
nil
|
28
|
+
else
|
29
|
+
[left_max_arguments, right_max_arguments].max
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def name
|
34
|
+
"(#{left.name} | #{right.name})"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Code
|
4
|
+
class Type
|
5
|
+
class Repeat < Type
|
6
|
+
attr_reader :clazz, :minimum, :maximum
|
7
|
+
|
8
|
+
def initialize(clazz, minimum: 0, maximum: nil)
|
9
|
+
@clazz = clazz
|
10
|
+
@minimum = minimum
|
11
|
+
@maximum = maximum
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?(argument)
|
15
|
+
valid_for?(expected: clazz, actual: argument)
|
16
|
+
end
|
17
|
+
|
18
|
+
def min_arguments
|
19
|
+
minimum * min_arguments_of(clazz)
|
20
|
+
end
|
21
|
+
|
22
|
+
def max_arguments
|
23
|
+
max_arguments = max_arguments_of(clazz)
|
24
|
+
max_arguments.nil? || maximum.nil? ? nil : maximum * max_arguments
|
25
|
+
end
|
26
|
+
|
27
|
+
def name
|
28
|
+
if minimum.zero? && maximum.nil?
|
29
|
+
"#{clazz.name}.repeat"
|
30
|
+
elsif maximum.nil?
|
31
|
+
"#{clazz.name}.repeat(#{minimum})"
|
32
|
+
else
|
33
|
+
"#{clazz.name}.repeaa(#{minimum}, #{maximum})"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Code
|
4
|
+
class Type
|
5
|
+
class Sig
|
6
|
+
def initialize(args, object:, &block)
|
7
|
+
@args = args
|
8
|
+
@block = block
|
9
|
+
@object = object
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.sig(...)
|
13
|
+
new(...).sig
|
14
|
+
end
|
15
|
+
|
16
|
+
def sig
|
17
|
+
check_number_of_arguments!
|
18
|
+
check_types_of_arguments!
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :args, :block, :object
|
24
|
+
|
25
|
+
def expected_arguments
|
26
|
+
@expected_arguments ||= Array(block&.call || []).map do |clazz|
|
27
|
+
clazz.is_a?(::Hash) ? Hash.new(clazz) : clazz
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def min_arguments_of(clazz)
|
32
|
+
clazz.is_a?(Type) ? clazz.min_arguments : 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def max_arguments_of(clazz)
|
36
|
+
clazz.is_a?(Type) ? clazz.max_arguments : 1
|
37
|
+
end
|
38
|
+
|
39
|
+
def actual_arguments
|
40
|
+
args[:arguments].map(&:value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def operator
|
44
|
+
args[:operator] || "call"
|
45
|
+
end
|
46
|
+
|
47
|
+
def function
|
48
|
+
"#{object.class.name}##{operator}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def min_arguments
|
52
|
+
expected_arguments.sum { |clazz| min_arguments_of(clazz) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def max_arguments
|
56
|
+
max_arguments = expected_arguments.map { |clazz| max_arguments_of(clazz) }
|
57
|
+
max_arguments.include?(nil) ? nil : max_arguments.sum
|
58
|
+
end
|
59
|
+
|
60
|
+
def actual_count
|
61
|
+
if actual_arguments.one?
|
62
|
+
"1 argument"
|
63
|
+
else
|
64
|
+
"#{actual_arguments.size} arguments"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def expected_count
|
69
|
+
if min_arguments == max_arguments
|
70
|
+
if min_arguments == 1
|
71
|
+
"1 argument"
|
72
|
+
else
|
73
|
+
"#{min_arguments} arguments"
|
74
|
+
end
|
75
|
+
elsif max_arguments.nil?
|
76
|
+
"#{min_arguments}+ arguments"
|
77
|
+
else
|
78
|
+
"#{min_arguments}-#{max_arguments} arguments"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def expected_range
|
83
|
+
max_arguments.nil? ? min_arguments.. : min_arguments..max_arguments
|
84
|
+
end
|
85
|
+
|
86
|
+
def check_number_of_arguments!
|
87
|
+
return if expected_range.include?(actual_arguments.size)
|
88
|
+
|
89
|
+
raise(
|
90
|
+
Error::ArityError,
|
91
|
+
"#{function}: Expected #{expected_count} but got #{actual_count}"
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def valid_for?(expected:, actual:)
|
96
|
+
expected.is_a?(Type) ? expected.valid?(actual) : actual.is_a?(expected)
|
97
|
+
end
|
98
|
+
|
99
|
+
def check_types_of_arguments!
|
100
|
+
expected_index = 0
|
101
|
+
repeat_index = 0
|
102
|
+
|
103
|
+
actual_arguments.each do |actual|
|
104
|
+
expected = expected_arguments[expected_index]
|
105
|
+
if expected.is_a?(Repeat)
|
106
|
+
if valid_for?(expected:, actual:)
|
107
|
+
repeat_index += 1
|
108
|
+
elsif repeat_index >= expected.min_arguments
|
109
|
+
expected_index += 1
|
110
|
+
repeat_index = 0
|
111
|
+
else
|
112
|
+
raise(
|
113
|
+
Error::TypeError,
|
114
|
+
"#{function}: expected #{expected.name}, got #{actual.inspect}"
|
115
|
+
)
|
116
|
+
end
|
117
|
+
elsif valid_for?(expected:, actual:)
|
118
|
+
expected_index += 1
|
119
|
+
repeat_index = 0
|
120
|
+
else
|
121
|
+
raise(
|
122
|
+
Error::TypeError,
|
123
|
+
"#{function}: expected #{expected.name}, got #{actual.inspect}"
|
124
|
+
)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|