kaiser-ruby 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b9d062d700db52c37367a613f89ff577927d8b013bfea6d994e0eda03e26758
4
- data.tar.gz: 6082e82328bdb866c38c50eb2765984bbded0c29c81ef2ca14fdaaee87f83a21
3
+ metadata.gz: e49970a2460c4b355e49a2dd465dae3035c135caa619d11b43b7b47b09166676
4
+ data.tar.gz: cde51c100d01c71158aa70b10af6e91400cd53322165b2a34c2d85db994a1aab
5
5
  SHA512:
6
- metadata.gz: 470d1fd4008cae879d727e0de6f99abe5f3261067dbf738e70f9431f4e2c7cd04100ea64621fffefb8c6c1830821f020767d7b83209cf9f9304f4df098b0faf4
7
- data.tar.gz: 41825a7a6f9bad109f36c3a2984960c9d7c4b23d27fa7aef2f60ef2ecdc6872f49898aba9793cb3c1ae8a0728c93b34d772e75da147c7f6ebae4cdd94ceb630d
6
+ metadata.gz: b2a0a4d21511e943449860b4058be59f186937447c7accd22fc44d8487792392baee54d33f76f6248c27478d82ef5d1702e352826d5066677f04c89cd795ce2f
7
+ data.tar.gz: 9f7aa127cd0a2aa13c9ba523073ea96d01aaa6ebcc104a7c1974bd8387dcba176dfa6bb1089b846f2d753693b19ed5fdd7f4bb302769dc389bbfa51034da21a8
@@ -0,0 +1,32 @@
1
+ # 0.1
2
+
3
+ - [x] Initial implementation of the Rockstar Language based using `Parslet::Parser`
4
+
5
+ # 0.2
6
+
7
+ - [x] Rewrote the Parser and Transform classes from scratch
8
+ - [x] basic CLI and REPL
9
+ - [x] Metal umlauts
10
+ - [x] Most variable types, assignmnents, output, conditionals are working.
11
+
12
+ # 0.3
13
+
14
+ Language Implementation:
15
+
16
+ - [x] Handle null type differently - nil in Ruby isn't really comparable to 0
17
+ - [x] Handle mysterious type - probably this should be nil and what is now nil should be 0 instead
18
+ - [x] Handle gt, gte, lt, lte comparisons
19
+ - [x] Handle inequality
20
+ - [x] While loop
21
+ - [x] Until loop
22
+ - [x] Break and continue
23
+ - [x] And/Or keywords for conditionals
24
+ - [x] Define functions
25
+ - [x] Handle function calls
26
+ - [x] Return can return math operations directly
27
+
28
+ Other stuff:
29
+
30
+ - [x] FizzBuzz example is working
31
+ - [x] Fibonacci example is working
32
+ - [x] Added comments to resulting ruby code flow control statements, so it's easier to see where what ends. This should help making the code more readable (and easier to figure out if it's actually correct), at least while the indentation feature is not fully working yet.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kaiser-ruby (0.2.3)
4
+ kaiser-ruby (0.3.0)
5
5
  parslet (~> 1.8)
6
6
  thor (~> 0.20)
7
7
 
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  This tool translates a file containing a program written in the [Rockstar language](https://github.com/dylanbeattie/rockstar) to Ruby code.
4
4
 
5
- This is still a work in progress. For details on that, see the TODO.md file.
5
+ This is still a work in progress, however most of the language implementation is already finished and working (as are the fibonacci sequence and fizzbuzz examples in the repository). For details on what is done, see the TODO.md and CHANGELOG.md files.
6
6
 
7
7
  ## Installation
8
8
 
@@ -73,6 +73,38 @@ $ kaiser-ruby execute ./examples/assignment.rock
73
73
 
74
74
  ```
75
75
 
76
+ Or even better, this:
77
+
78
+ ```
79
+ $ kaiser-ruby execute ./examples/fibonacci.rock
80
+ 1
81
+ 1
82
+ 2
83
+ 3
84
+ 5
85
+ 8
86
+ 13
87
+ 21
88
+ 34
89
+ 55
90
+ 89
91
+ 144
92
+ 233
93
+ 377
94
+ 610
95
+ 987
96
+ 1597
97
+ 2584
98
+ 4181
99
+ 6765
100
+ 10946
101
+ 17711
102
+ 28657
103
+ 46368
104
+
105
+ $
106
+ ```
107
+
76
108
  ## Contributing
77
109
 
78
110
  Bug reports and pull requests are welcome on GitHub at https://github.com/marcinruszkiewicz/kaiser-ruby.
data/TODO.md CHANGED
@@ -1,48 +1,28 @@
1
1
  # TODO notes for KaiserRuby transpiler
2
2
 
3
- ## Variables
3
+ ## Language Implementation
4
4
 
5
5
  - [ ] Handle pronouns - he, she, it, and others should refer to the last used variable
6
-
7
- ## Types
8
-
9
- - [x] Handle null type differently - nil in Ruby isn't really comparable to 0
10
- - [x] Handle mysterious type - probably this should be nil and what is now nil should be 0 instead
6
+ - [ ] Handle "Janie's got a gun"
7
+ - [ ] Ignore comments in parentheses
11
8
  - [ ] Handle object type
12
-
13
- ## Comparisons
14
-
15
- - [ ] Handle gt, gte, lt, lte comparisons
16
- - [ ] Handle negation
17
-
18
- ## Input
19
-
20
9
  - [ ] Handle input from STDIN
21
-
22
- ## Flow Control
23
-
24
- - [ ] While loop
25
- - [ ] Until loop
26
- - [ ] Break and continue
27
-
28
- ## Functions
29
-
30
- - [ ] Define functions
31
- - [ ] Handle function calls
10
+ - [ ] Function calls can be used as expressions in flow statements
11
+ - [ ] Handle ',' instead of 'and' in function calls
12
+ - [ ] Somehow handle function variable scope
32
13
 
33
14
  ## Examples
34
15
 
35
- - [ ] FizzBuzz example (should also be in tests to check if it runs)
36
16
  - [ ] Should be able to run the [Cellular Rockomata](https://github.com/Rifhutch/cellular-rocktomata)
37
17
  - [ ] Fibonacci example https://github.com/dylanbeattie/rockstar/issues/94#issuecomment-408217504
38
18
  - [ ] Math module https://gist.github.com/wrenoud/6be6f7509c88a3d8f9867ae782fb768f
39
19
  - [ ] Primality checker https://www.reddit.com/r/RockstarDevs/comments/92i6sm/primality_checker_in_rockstar/
20
+ - [ ] Make a demo command in the CLI that runs all examples (would that even work as a gem? it should be doable somehow)
40
21
 
41
22
  ## Other stuff
42
23
 
43
- - [x] Test if it handles metal umlauts (Ruby shouldn't care much, but tests should be made)
44
- - [ ] Ignore comments in parentheses
45
- - [x] Nicely indent blocks
46
24
  - [ ] Fix indenting of nested blocks that doesn't really work well
47
- - [x] Working basic REPL
48
- - [ ] Add code history to the REPL
25
+ - [ ] Add code history to the REPL
26
+ - [ ] Make REPL work with multiline input also, not only singular lines
27
+ - [ ] Better error handling
28
+ - [ ] Suppress warnign about eval from Thor
@@ -18,6 +18,7 @@ module KaiserRuby
18
18
  end
19
19
 
20
20
  def self.parse(input)
21
+ # strings without a line ending (or single lines) should be fed into the alternative parser
21
22
  if input.split("\n").size == 1
22
23
  KaiserRuby::RockstarSingleLineParser.new.parse(input.chomp)
23
24
  else
@@ -39,6 +39,8 @@ module KaiserRuby
39
39
  def rock
40
40
  say "Type 'exit' to exit the console. Otherwise, rock on!"
41
41
 
42
+ # grab the outside block's binding, so that we can use it to eval code
43
+ # this makes it not lose local variables throughout the loop
42
44
  b = binding
43
45
 
44
46
  begin
@@ -1,10 +1,15 @@
1
1
  module KaiserRuby
2
2
  class RockstarParser < Parslet::Parser
3
+ # ORDER OF THESE RULES ABSOLUTELY MATTERS
4
+ # DON'T MESS WITH IT
5
+
6
+ # all the keywords separately, so that variable names can't use them
7
+
3
8
  rule(:reserved) do
4
9
  mysterious_value_keywords | null_value_keywords | true_value_keywords | false_value_keywords |
5
- plus_keywords | minus_keywords | times_keywords | over_keywords |
6
- str('Knock') | str('Build') | str('Put') | str('into') | str('says') |
7
- poetic_number_keywords | say_keywords
10
+ plus_keywords | minus_keywords | times_keywords | over_keywords | increment_keywords |
11
+ assignment_keywords | poetic_string_keywords | poetic_number_keywords |
12
+ say_keywords | flow_keywords | comparison_keywords | function_keywords
8
13
  end
9
14
 
10
15
  rule(:mysterious_value_keywords) { str('mysterious') }
@@ -19,6 +24,14 @@ module KaiserRuby
19
24
  rule(:poetic_number_keywords) { str('is') | str('was') | str('were') }
20
25
  rule(:say_keywords) { str('Say') | str('Shout') | str('Scream') | str('Whisper') }
21
26
  rule(:flow_keywords) { str('If') | str('Else') | str('While') | str('Until') }
27
+ rule(:increment_keywords) { str('Knock') | str('Build') }
28
+ rule(:assignment_keywords) { str('Put') | str('into') }
29
+ rule(:poetic_string_keywords) { str('says') }
30
+ rule(:comparison_keywords) { str("is") | not_keywords | gt_keywords | gte_keywords | lt_keywords | lte_keywords }
31
+ rule(:function_keywords) { str('Break it down') | str('Take it to the top') | str('Give back') | str('takes') | str('taking') }
32
+
33
+ # variable names
34
+ # using [[:upper:]] etc here allows for metal umlauts and other UTF characters
22
35
 
23
36
  rule(:proper_word) { reserved.absent? >> match['[[:upper:]]'] >> match['[[:alpha:]]'].repeat }
24
37
  rule(:common_variable_name) do
@@ -28,16 +41,18 @@ module KaiserRuby
28
41
  str('The ') | str('the ') |
29
42
  str('My ') | str('my ') |
30
43
  str('Your ') | str('your ')
31
- ) >> reserved.absent? >> match['[[:lower:]]'].repeat
44
+ ) >> reserved.absent? >> match['[[:lower:]]'].repeat >> match[','].maybe.ignore
32
45
  end
33
46
  rule(:proper_variable_name) do
34
- (proper_word >> (space >> proper_word).repeat).repeat(1)
47
+ (proper_word >> (space >> proper_word).repeat) >> match[','].maybe.ignore
35
48
  end
36
49
 
37
50
  rule(:variable_names) do
38
51
  (common_variable_name | proper_variable_name).as(:variable_name)
39
52
  end
40
53
 
54
+ # all the different value types (except Object for now)
55
+
41
56
  rule(:mysterious_value) { mysterious_value_keywords.as(:mysterious_value) }
42
57
  rule(:null_value) { null_value_keywords.as(:null_value) }
43
58
  rule(:true_value) { true_value_keywords.as(:true_value) }
@@ -47,6 +62,8 @@ module KaiserRuby
47
62
  rule(:unquoted_string) { match['^\n'].repeat.as(:unquoted_string) }
48
63
  rule(:string_as_number) { reserved.absent? >> match['^\n'].repeat.as(:string_as_number) }
49
64
 
65
+ # assignment
66
+
50
67
  rule(:basic_assignment_expression) do
51
68
  match('Put ').present? >>
52
69
  (
@@ -54,6 +71,8 @@ module KaiserRuby
54
71
  ).as(:assignment)
55
72
  end
56
73
 
74
+ # math operations
75
+
57
76
  rule(:increment) do
58
77
  (
59
78
  str('Build ') >> variable_names.as(:variable_name) >> str(' up')
@@ -66,8 +85,6 @@ module KaiserRuby
66
85
  ).as(:decrement)
67
86
  end
68
87
 
69
- # math operations
70
-
71
88
  rule(:addition) do
72
89
  (match('.*? plus') | match('.*? with')).present? >>
73
90
  (
@@ -96,6 +113,27 @@ module KaiserRuby
96
113
  ).as(:multiplication)
97
114
  end
98
115
 
116
+ # functions
117
+
118
+ rule(:function) do
119
+ match('.*? takes').present? >>
120
+ (
121
+ variable_names.as(:function_name) >> str(' takes') >>
122
+ (space >> str('and ').maybe >> variable_names.as(:argument_name)).repeat.as(:arguments) >> eol >>
123
+ scope {
124
+ inner_block_line.repeat.as(:function_block) >>
125
+ (eol | eof).as(:enddef)
126
+ }
127
+ ).as(:function_definition)
128
+ end
129
+
130
+ rule(:function_call) do
131
+ (
132
+ variable_names.as(:function_name) >> str(' taking') >>
133
+ (space >> str('and ').maybe >> variable_names.as(:argument_name)).repeat.as(:arguments)
134
+ ).as(:function_call)
135
+ end
136
+
99
137
  # poetic assignments
100
138
 
101
139
  rule(:poetic_type_literal) do
@@ -118,35 +156,85 @@ module KaiserRuby
118
156
  ).as(:assignment)
119
157
  end
120
158
 
159
+ # single statements
160
+
121
161
  rule(:print_function) do
122
162
  (
123
163
  say_keywords >> space >> value_or_variable.as(:output)
124
164
  ).as(:print)
125
165
  end
126
166
 
167
+ rule(:break_function) do
168
+ str('Break it down').as(:break)
169
+ end
170
+
171
+ rule(:continue_function) do
172
+ str('Take it to the top').as(:continue)
173
+ end
174
+
175
+ rule(:return_function) do
176
+ str('Give back ') >> (math_operations | value_or_variable).as(:return_value)
177
+ end
178
+
127
179
  # comparisons
128
180
 
129
181
  rule(:equality) do
130
182
  (
131
- value_or_variable.as(:left) >> str(' is ') >> (string_as_number | value_or_variable).as(:right)
183
+ value_or_variable.as(:left) >> str(' is ') >> value_or_variable.as(:right)
132
184
  ).as(:equals)
133
185
  end
134
186
 
135
- # flow control
187
+ rule(:not_keywords) { str(' is not ') | str(" ain't ")}
188
+ rule(:inequality) do
189
+ (
190
+ value_or_variable.as(:left) >> not_keywords >> value_or_variable.as(:right)
191
+ ).as(:not_equals)
192
+ end
193
+
194
+ rule(:gt_keywords) { str(' is ') >> (str('higher') | str('greater') | str('bigger') | str('stronger')) >> str(' than ') }
195
+ rule(:gt) do
196
+ (
197
+ value_or_variable.as(:left) >> gt_keywords >> value_or_variable.as(:right)
198
+ ).as(:gt)
199
+ end
200
+
201
+ rule(:lt_keywords) { str(' is ') >> (str('lower') | str('less') | str('smaller') | str('weaker')) >> str(' than ') }
202
+ rule(:lt) do
203
+ (
204
+ value_or_variable.as(:left) >> lt_keywords >> value_or_variable.as(:right)
205
+ ).as(:lt)
206
+ end
207
+
208
+ rule(:gte_keywords) { str(' is as ') >> (str('high') | str('great') | str('big') | str('strong')) >> str(' as ') }
209
+ rule(:gte) do
210
+ (
211
+ value_or_variable.as(:left) >> gte_keywords >> value_or_variable.as(:right)
212
+ ).as(:gte)
213
+ end
214
+
215
+ rule(:lte_keywords) { str(' is as ') >> (str('low') | str('little') | str('small') | str('weak')) >> str(' as ') }
216
+ rule(:lte) do
217
+ (
218
+ value_or_variable.as(:left) >> lte_keywords >> value_or_variable.as(:right)
219
+ ).as(:lte)
220
+ end
221
+
222
+ # flow control - if, else, while, until
136
223
 
137
224
  rule(:if_block) do
138
225
  (
139
- str('If ') >> comparisons.as(:if_condition) >> eol >>
226
+ str('If ') >> comparisons.as(:if_condition) >>
227
+ (space >> (str('and') | str('or')).as(:and_or) >> space >> comparisons.as(:second_condition)).maybe >> eol >>
140
228
  scope {
141
- inner_block_line.repeat.as(:if_block) >>
142
- (eol | eof).as(:endif)
143
- }
229
+ inner_block_line.repeat.as(:if_block)
230
+ } >> (eol | eof).as(:endif)
144
231
  ).as(:if)
145
232
  end
146
233
 
147
234
  rule(:if_else_block) do
148
235
  (
149
- str('If ') >> comparisons.as(:if_condition) >> eol >>
236
+ str('If ') >> comparisons.as(:if_condition) >>
237
+ (space >> (str('and') | str('or')).as(:and_or) >> space >> comparisons.as(:second_condition)).maybe >> eol >>
150
238
  scope {
151
239
  inner_block_line.repeat.as(:if_block)
152
240
  } >>
@@ -158,26 +246,58 @@ module KaiserRuby
158
246
  ).as(:if_else)
159
247
  end
160
248
 
249
+ rule(:while_block) do
250
+ (
251
+ str('While ') >> comparisons.as(:while_condition) >>
252
+ (space >> (str('and') | str('or')).as(:and_or) >> space >> comparisons.as(:second_condition)).maybe >> eol >>
253
+ scope {
254
+ inner_block_line.repeat.as(:while_block) >>
255
+ (eol | eof).as(:endwhile)
256
+ }
257
+ ).as(:while)
258
+ end
259
+
260
+ rule(:until_block) do
261
+ (
262
+ str('Until ') >> comparisons.as(:until_condition) >>
263
+ (space >> (str('and') | str('or')).as(:and_or) >> space >> comparisons.as(:second_condition)).maybe >> eol >>
264
+ scope {
265
+ inner_block_line.repeat.as(:until_block)
266
+
267
+ } >> (eol | eof).as(:enduntil)
268
+ ).as(:until)
269
+ end
270
+
271
+ # sets of rules
272
+
161
273
  rule(:simple_values) { mysterious_value | null_value | false_value | true_value | string_value | numeric_value }
162
274
  rule(:value_or_variable) { variable_names | simple_values }
163
- rule(:expressions) { basic_assignment_expression | increment | decrement | addition | subtraction | multiplication | division }
164
- rule(:comparisons) { equality }
165
- rule(:flow_control) { if_block | if_else_block }
275
+ rule(:math_operations) { increment | decrement | addition | subtraction | multiplication | division }
276
+ rule(:expressions) { basic_assignment_expression | math_operations }
277
+ rule(:comparisons) { gte | gt | lte | lt | inequality | equality }
278
+ rule(:flow_control) { if_block | if_else_block | while_block | until_block }
166
279
  rule(:poetics) { poetic_type_literal | poetic_string_literal | poetic_number_literal }
167
- rule(:functions) { print_function }
280
+ rule(:functions) { function_call | function | print_function | break_function | continue_function | return_function }
168
281
  rule(:line_elements) { flow_control | poetics | expressions | functions | eol }
169
282
 
283
+ # handle multiple lines in a file
284
+
170
285
  rule(:string_input) { line_elements | value_or_variable }
171
286
  rule(:line) { (line_elements >> eol.maybe).as(:line) }
172
287
  rule(:inner_block_line) { ( (flow_control | poetics | expressions | functions) >> eol.maybe).as(:line) }
173
288
  rule(:lyrics) { line.repeat.as(:lyrics) }
174
289
  root(:lyrics)
175
290
 
291
+ # DRY helpers
292
+
176
293
  rule(:eol) { match["\n"] }
177
294
  rule(:eof) { any.absent? }
178
295
  rule(:space) { match[' \t'].repeat(1) }
179
296
  end
180
297
 
298
+ # this is an alternative parser that enables all the RSpec tests to pass
299
+ # it specifically has a single line rule that matches a string instead of lines
300
+ # it also matches the value_or_variable rule, so that the value creation can be tested
181
301
  class RockstarSingleLineParser < KaiserRuby::RockstarParser
182
302
  root(:string_input)
183
303
  end
@@ -29,18 +29,51 @@ module KaiserRuby
29
29
  rule(division: { left: simple(:left), right: simple(:right) }) { "#{left} / #{right}" }
30
30
 
31
31
  rule(print: { output: simple(:output) }) { "puts #{output}" }
32
+ rule(continue: simple(:_)) { "next" }
33
+ rule(break: simple(:_)) { "break" }
32
34
 
33
35
  rule(equals: { left: simple(:left), right: simple(:right) }) { "#{left} == #{right}" }
34
- rule(if: { if_condition: simple(:if_condition), if_block: sequence(:if_block_lines), endif: simple(:_)} ) do
36
+ rule(not_equals: { left: simple(:left), right: simple(:right) }) { "#{left} != #{right}" }
37
+ rule(gt: { left: simple(:left), right: simple(:right) }) { "#{left} > #{right}" }
38
+ rule(gte: { left: simple(:left), right: simple(:right) }) { "#{left} >= #{right}" }
39
+ rule(lte: { left: simple(:left), right: simple(:right) }) { "#{left} <= #{right}" }
40
+ rule(lt: { left: simple(:left), right: simple(:right) }) { "#{left} < #{right}" }
41
+
42
+ rule(if: {
43
+ if_condition: simple(:if_condition),
44
+ if_block: sequence(:if_block_lines),
45
+ endif: simple(:_)
46
+ } ) do
35
47
  output = "#{' ' * KaiserRuby.indent}if #{if_condition}\n"
36
48
  KaiserRuby.up_indent
37
49
  output += if_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
38
50
  KaiserRuby.down_indent
39
- output += "#{' ' * KaiserRuby.indent}end"
51
+ output += "#{' ' * KaiserRuby.indent}end # endif"
52
+ output
53
+ end
54
+
55
+ rule(if: {
56
+ if_condition: simple(:if_condition),
57
+ and_or: simple(:and_or),
58
+ second_condition: simple(:second_condition),
59
+ if_block: sequence(:if_block_lines),
60
+ endif: simple(:_)
61
+ } ) do
62
+ proper_and_or = and_or == 'and' ? '&&' : '||'
63
+ output = "#{' ' * KaiserRuby.indent}if #{if_condition} #{proper_and_or} #{second_condition}\n"
64
+ KaiserRuby.up_indent
65
+ output += if_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
66
+ KaiserRuby.down_indent
67
+ output += "#{' ' * KaiserRuby.indent}end # endif"
40
68
  output
41
69
  end
42
70
 
43
- rule(if_else: { if_condition: simple(:if_condition), if_block: sequence(:if_block_lines), else_block: sequence(:else_block_lines), endif: simple(:_)} ) do
71
+ rule(if_else: {
72
+ if_condition: simple(:if_condition),
73
+ if_block: sequence(:if_block_lines),
74
+ else_block: sequence(:else_block_lines),
75
+ endif: simple(:_)
76
+ } ) do
44
77
  output = "#{' ' * KaiserRuby.indent}if #{if_condition}\n"
45
78
  KaiserRuby.up_indent
46
79
  output += if_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
@@ -49,10 +82,113 @@ module KaiserRuby
49
82
  KaiserRuby.up_indent
50
83
  output += else_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
51
84
  KaiserRuby.down_indent
52
- output += "#{' ' * KaiserRuby.indent}end"
85
+ output += "#{' ' * KaiserRuby.indent}end # endifelse"
53
86
  output
54
87
  end
55
88
 
89
+ rule(if_else: {
90
+ if_condition: simple(:if_condition),
91
+ and_or: simple(:and_or),
92
+ second_condition: simple(:second_condition),
93
+ if_block: sequence(:if_block_lines),
94
+ else_block: sequence(:else_block_lines),
95
+ endif: simple(:_)
96
+ } ) do
97
+ proper_and_or = and_or == 'and' ? '&&' : '||'
98
+ output = "#{' ' * KaiserRuby.indent}if #{if_condition} #{proper_and_or} #{second_condition}\n"
99
+ KaiserRuby.up_indent
100
+ output += if_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
101
+ KaiserRuby.down_indent
102
+ output += "#{' ' * KaiserRuby.indent}else\n"
103
+ KaiserRuby.up_indent
104
+ output += else_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
105
+ KaiserRuby.down_indent
106
+ output += "#{' ' * KaiserRuby.indent}end # endifelse"
107
+ output
108
+ end
109
+
110
+ rule(while: {
111
+ while_condition: simple(:while_condition),
112
+ while_block: sequence(:while_block_lines),
113
+ endwhile: simple(:_)
114
+ } ) do
115
+ output = "#{' ' * KaiserRuby.indent}while #{while_condition}\n"
116
+ KaiserRuby.up_indent
117
+ output += while_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
118
+ KaiserRuby.down_indent
119
+ output += "#{' ' * KaiserRuby.indent}end # endwhile"
120
+ output
121
+ end
122
+
123
+ rule(while: {
124
+ while_condition: simple(:while_condition),
125
+ and_or: simple(:and_or),
126
+ second_condition: simple(:second_condition),
127
+ while_block: sequence(:while_block_lines),
128
+ endwhile: simple(:_)
129
+ } ) do
130
+ proper_and_or = and_or == 'and' ? '&&' : '||'
131
+ output = "#{' ' * KaiserRuby.indent}while #{while_condition} #{proper_and_or} #{second_condition}\n"
132
+ KaiserRuby.up_indent
133
+ output += while_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
134
+ KaiserRuby.down_indent
135
+ output += "#{' ' * KaiserRuby.indent}end # endwhile"
136
+ output
137
+ end
138
+
139
+ rule(until: {
140
+ until_condition: simple(:until_condition),
141
+ until_block: sequence(:until_block_lines),
142
+ enduntil: simple(:_)
143
+ } ) do
144
+ output = "#{' ' * KaiserRuby.indent}until #{until_condition}\n"
145
+ KaiserRuby.up_indent
146
+ output += until_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
147
+ KaiserRuby.down_indent
148
+ output += "#{' ' * KaiserRuby.indent}end # enduntil"
149
+ output
150
+ end
151
+
152
+ rule(until: {
153
+ until_condition: simple(:until_condition),
154
+ and_or: simple(:and_or),
155
+ second_condition: simple(:second_condition),
156
+ until_block: sequence(:until_block_lines),
157
+ enduntil: simple(:_)
158
+ } ) do
159
+ proper_and_or = and_or == 'and' ? '&&' : '||'
160
+ output = "#{' ' * KaiserRuby.indent}until #{until_condition} #{proper_and_or} #{second_condition}\n"
161
+ KaiserRuby.up_indent
162
+ output += until_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
163
+ KaiserRuby.down_indent
164
+ output += "#{' ' * KaiserRuby.indent}end # enduntil"
165
+ output
166
+ end
167
+
168
+ rule(argument_name: simple(:str)) { str }
169
+ rule(return_value: simple(:value)) { "return #{value}" }
170
+
171
+ rule(function_definition: {
172
+ function_name: simple(:function_name),
173
+ arguments: sequence(:arguments),
174
+ function_block: sequence(:function_block_lines),
175
+ enddef: simple(:_)
176
+ } ) do
177
+ output = "#{' ' * KaiserRuby.indent}def #{function_name}(#{arguments.join(', ')})\n"
178
+ KaiserRuby.up_indent
179
+ output += function_block_lines.map { |l| "#{' ' * KaiserRuby.indent}#{l}\n" }.join
180
+ KaiserRuby.down_indent
181
+ output += "#{' ' * KaiserRuby.indent}end # enddef"
182
+ output
183
+ end
184
+
185
+ rule(function_call: {
186
+ function_name: simple(:function_name),
187
+ arguments: sequence(:arguments)
188
+ } ) do
189
+ "#{function_name}(#{arguments.join(', ')})"
190
+ end
191
+
56
192
  rule(line: simple(:line)) { line == "\n" ? nil : line }
57
193
  rule(lyrics: sequence(:lines)) { lines.join("\n") + "\n" }
58
194
 
@@ -1,3 +1,3 @@
1
1
  module KaiserRuby
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kaiser-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcin Ruszkiewicz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-03 00:00:00.000000000 Z
11
+ date: 2018-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -105,6 +105,7 @@ files:
105
105
  - ".gitignore"
106
106
  - ".rspec"
107
107
  - ".travis.yml"
108
+ - CHANGELOG.md
108
109
  - Gemfile
109
110
  - Gemfile.lock
110
111
  - LICENSE.txt