riml 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/bin/riml CHANGED
@@ -1,12 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
  # vim: syntax=ruby
3
3
 
4
- require File.expand_path("../../config/environment", __FILE__)
4
+ require File.expand_path("../../lib/environment", __FILE__)
5
5
 
6
6
  module Riml
7
7
  include Environment
8
- require File.join(ROOTDIR, 'version')
9
- require File.join(LIBDIR, "helper")
8
+ require 'riml'
10
9
 
11
10
  require 'optparse'
12
11
  require 'ostruct'
@@ -16,32 +15,41 @@ module Riml
16
15
 
17
16
  # defaults
18
17
  options = OpenStruct.new
19
- options.compile = []
20
- options.riml_source_path = Dir.getwd
18
+ options.compile_files = []
21
19
 
22
20
  OptionParser.new do |opts|
23
21
  opts.banner = "Usage: riml [options]"
24
22
  opts.separator ""
25
23
  opts.separator "Specific options:"
26
24
 
27
- opts.on("-c", "--compile FILE", "Compile riml file to VimL") do |file|
25
+ opts.on("-c", "--compile FILE", "Compile riml file to VimL.") do |file|
28
26
  if File.exists?(file)
29
- options.compile << file
27
+ options.compile_files << file
30
28
  else
31
- warn "Couldn't find file #{file.inspect}"
29
+ warn "Couldn't find file #{file.inspect}."
30
+ exit 1
32
31
  end
33
32
  end
34
33
 
35
- opts.on("-s", "--stdio", "pipe in riml to STDIN and get back VimL on STDOUT") do
34
+ opts.on("-t", "--source-path PATH", "Path riml uses for `riml_source` to find files. Defaults to pwd.") do |path|
35
+ if Dir.exists?(path)
36
+ Riml.source_path = path
37
+ else
38
+ warn "Couldn't find directory #{path.inspect}."
39
+ exit 1
40
+ end
41
+ end
42
+
43
+ opts.on("-s", "--stdio", "Pipe in riml to STDIN and get back VimL on STDOUT.") do
36
44
  options.stdio = true
37
45
  end
38
46
 
39
- opts.on_tail("-v", "--version", "Show riml version") do
47
+ opts.on_tail("-v", "--version", "Show riml version.") do
40
48
  puts VERSION.join('.')
41
49
  exit
42
50
  end
43
51
 
44
- opts.on_tail("-h", "--help", "Show this message") do
52
+ opts.on_tail("-h", "--help", "Show this message.") do
45
53
  puts opts
46
54
  exit
47
55
  end
@@ -55,12 +63,11 @@ module Riml
55
63
  class << self
56
64
  def start
57
65
  options = Options.parse(ARGV)
66
+
58
67
  if options.stdio
59
68
  puts Riml.compile($stdin.gets)
60
- elsif options.compile.any?
61
- options.compile.each do |file|
62
- Riml.compile_file(file)
63
- end
69
+ elsif options.compile_files.any?
70
+ Riml.compile_files(*options.compile_files)
64
71
  end
65
72
  end
66
73
  end
data/lib/ast_rewriter.rb CHANGED
@@ -6,8 +6,8 @@ module Riml
6
6
  class AST_Rewriter
7
7
  include Riml::Constants
8
8
 
9
- attr_reader :ast
10
- def initialize(ast)
9
+ attr_accessor :ast
10
+ def initialize(ast = nil)
11
11
  @ast = ast
12
12
  end
13
13
 
@@ -134,11 +134,12 @@ module Riml
134
134
  def replace(node)
135
135
  def_node = node.to_def_node
136
136
  node.parent_node = ast.expressions
137
+ def_node.parent_node = ast.expressions
137
138
  node.remove
138
139
  def_node.name.insert(0, "#{dict_name}.")
139
140
  def_node.parent_node = constructor.expressions
140
141
  constructor.expressions << def_node
141
- reestablish_parents(node)
142
+ reestablish_parents(def_node)
142
143
  end
143
144
  end
144
145
 
@@ -259,8 +260,8 @@ module Riml
259
260
  end
260
261
 
261
262
  def replace(node)
262
- node.replace_with(ExplicitCallNode.new(node[0], node[1], node[2]))
263
- reestablish_parents(node)
263
+ explicit = node.replace_with(ExplicitCallNode.new(node[0], node[1], node[2]))
264
+ reestablish_parents(explicit)
264
265
  end
265
266
  end
266
267
 
data/lib/compiler.rb CHANGED
@@ -14,7 +14,6 @@ module Riml
14
14
  end
15
15
 
16
16
  def visit(node)
17
- node.compiled_output.clear
18
17
  @value = compile(node)
19
18
  @value << "\n" if node.force_newline and @value[-1] != "\n"
20
19
  propagate_up_tree(node, @value)
@@ -33,12 +32,11 @@ module Riml
33
32
  def compile(node)
34
33
  condition_visitor = visitor_for_node(node.condition)
35
34
  node.condition.parent_node = node
36
- node.body.parent_node = node
37
- node.compiled_output = "if ("
35
+ node.condition.force_newline = true
36
+ node.compiled_output = "if "
38
37
  node.compiled_output << "!" if UnlessNode === node
39
38
 
40
39
  node.condition.accept(condition_visitor)
41
- node.compiled_output << ")\n"
42
40
  node.body.accept(NodesVisitor.new(:propagate_up_tree => false))
43
41
 
44
42
  node.body.compiled_output.each_line do |line|
@@ -69,12 +67,10 @@ module Riml
69
67
 
70
68
  class WhileNodeVisitor < Visitor
71
69
  def compile(node)
72
- node.condition.parent_node = node
73
- node.compiled_output = "while ("
70
+ node.condition.force_newline = true
71
+ node.compiled_output = "while "
74
72
  node.compiled_output << "!" if UntilNode === node
75
-
76
73
  node.condition.accept visitor_for_node(node.condition)
77
- node.compiled_output << ")\n"
78
74
 
79
75
  node.body.accept NodesVisitor.new(:propagate_up_tree => false)
80
76
 
@@ -92,19 +88,18 @@ module Riml
92
88
  class ElseNodeVisitor < Visitor
93
89
  def compile(node)
94
90
  node.compiled_output = "else\n"
95
- expressions_visitor = NodesVisitor.new
96
- node.expressions.parent_node = node
97
- node.expressions.accept(expressions_visitor)
91
+ node.expressions.parent = node
92
+ node.expressions.accept(visitor_for_node(node.expressions))
98
93
  node.compiled_output
99
94
  end
100
95
  end
101
96
 
102
97
  class ElseifNodeVisitor < Visitor
103
98
  def compile(node)
104
- node.compiled_output = "elseif ("
99
+ node.compiled_output = "elseif "
105
100
  node.condition.parent_node = node
101
+ node.condition.force_newline = true
106
102
  node.condition.accept(visitor_for_node(node.condition))
107
- node.compiled_output << ")\n"
108
103
  node.expressions.parent_node = node
109
104
  node.expressions.accept(visitor_for_node(node.expressions))
110
105
  node.force_newline = true
@@ -127,6 +122,8 @@ module Riml
127
122
  end
128
123
  end
129
124
 
125
+ SublistNodeVisitor = NodesVisitor
126
+
130
127
  class LiteralNodeVisitor < Visitor
131
128
  def compile(node)
132
129
  value = case node.value
@@ -208,6 +205,15 @@ module Riml
208
205
  end
209
206
  end
210
207
 
208
+ class WrapInParensNodeVisitor < Visitor
209
+ def compile(node)
210
+ node.compiled_output << "("
211
+ node.expression.parent_node = node
212
+ node.expression.accept(visitor_for_node(node.expression))
213
+ node.compiled_output << ")"
214
+ end
215
+ end
216
+
211
217
  # common visiting methods for nodes that are scope modified with variable
212
218
  # name prefixes
213
219
  class ScopedVisitor < Visitor
@@ -305,19 +311,15 @@ module Riml
305
311
  class BinaryOperatorNodeVisitor < Visitor
306
312
  def compile(node)
307
313
  op1, op2 = node.operand1, node.operand2
308
- op1_visitor, op2_visitor = visitor_for_node(op1), visitor_for_node(op2)
309
- node.operands.each {|n| n.parent_node = node}
310
- op1.accept(op1_visitor)
311
- op2_visitor.propagate_up_tree = false
312
- op2.accept(op2_visitor)
314
+ [op1, op2].each {|n| n.parent = node}
315
+ op1.accept(visitor_for_node(op1))
313
316
  if node.ignorecase_capable_operator?(node.operator)
314
317
  operator_suffix = "# "
315
318
  else
316
319
  operator_suffix = " "
317
320
  end
318
321
  node.compiled_output << " #{node.operator}#{operator_suffix}"
319
- op2_visitor.propagate_up_tree = true
320
- op2.accept(op2_visitor)
322
+ op2.accept(visitor_for_node(op2))
321
323
  node.compiled_output
322
324
  end
323
325
  end
@@ -405,34 +407,40 @@ module Riml
405
407
 
406
408
  class CallNodeVisitor < ScopedVisitor
407
409
  def compile(node)
408
- set_modifier(node) unless node.builtin_function?
410
+ set_modifier(node) if node.name && !node.builtin_function?
409
411
  node.compiled_output =
410
- if node.name.respond_to?(:variable)
411
- node.name.accept(visitor_for_node(node.name))
412
- node.scope_modifier + node.name.compiled_output
413
- elsif DictGetDotNode === node.name
414
- node.name.accept(visitor_for_node(node.name))
415
- node.name.compiled_output
416
- else
417
- "#{node.full_name}"
418
- end
419
- node.compiled_output << (node.no_parens_necessary? ? " " : "(")
412
+ if node.name.respond_to?(:variable)
413
+ node.name.accept(visitor_for_node(node.name))
414
+ node.scope_modifier + node.name.compiled_output
415
+ elsif DictGetDotNode === node.name
416
+ node.name.accept(visitor_for_node(node.name))
417
+ node.name.compiled_output
418
+ else
419
+ "#{node.full_name}"
420
+ end
421
+ compile_arguments(node)
422
+ node.compiled_output
423
+ end
424
+
425
+ def compile_arguments(node)
426
+ node.compiled_output << (node.builtin_command? ? " " : "(")
420
427
  node.arguments.each_with_index do |arg, i|
421
428
  arg.parent_node = node
422
429
  arg_visitor = visitor_for_node(arg)
423
430
  arg.accept(arg_visitor)
424
431
  node.compiled_output << ", " unless last_arg?(node.arguments, i)
425
432
  end
426
- node.compiled_output << ")" unless node.no_parens_necessary?
433
+ node.compiled_output << ")" unless node.builtin_command?
427
434
 
428
435
  unless node.descendant_of_control_structure? ||
429
436
  node.descendant_of_call_node? ||
430
437
  node.descendant_of_list_node? ||
431
438
  node.descendant_of_list_or_dict_get_node? ||
432
- node.descendant_of_operator_node?
439
+ node.descendant_of_operator_node? ||
440
+ node.descendant_of_wrap_in_parens_node? ||
441
+ node.descendant_of_sublist_node?
433
442
  node.force_newline = true
434
443
  end
435
- node.compiled_output
436
444
  end
437
445
 
438
446
  private
@@ -443,9 +451,36 @@ module Riml
443
451
 
444
452
  class ExplicitCallNodeVisitor < CallNodeVisitor
445
453
  def compile(node)
446
- pre = "call "
447
- post = super
448
- node.compiled_output = pre << post
454
+ if node.scope_modifier || node.name
455
+ node.compiled_output = "call " << super
456
+ else
457
+ node.compiled_output = "call"
458
+ compile_arguments(node)
459
+ end
460
+ node.compiled_output
461
+ end
462
+ end
463
+
464
+ class RimlCommandNodeVisitor < CallNodeVisitor
465
+ def compile(node)
466
+ if node.name == 'riml_source'
467
+ node.arguments.map(&:value).each do |file|
468
+ unless File.exists?(File.join(Riml.source_path, file))
469
+ raise Riml::FileNotFound, "#{file.inspect} could not be found in " \
470
+ "source path (#{Riml.source_path.inspect})"
471
+ end
472
+
473
+ root_node(node).current_compiler.compile_queue << file
474
+ end
475
+ node.compiled_output << 'source'
476
+ compile_arguments(node)
477
+ node.compiled_output.gsub(/['"]/, '').gsub('.riml', '.vim')
478
+ end
479
+ end
480
+
481
+ def root_node(node)
482
+ node = node.parent until node.parent.nil?
483
+ node
449
484
  end
450
485
  end
451
486
 
@@ -568,10 +603,21 @@ module Riml
568
603
  end
569
604
  end
570
605
 
606
+ module CompilerAccessible
607
+ attr_accessor :current_compiler
608
+ end
609
+
610
+ def compile_queue
611
+ @compile_queue ||= []
612
+ end
613
+
571
614
  # compiles nodes into output code
572
615
  def compile(root_node)
573
- root_visitor = NodesVisitor.new
574
- root_node.accept(root_visitor)
616
+ # so we can compile concurrently, as some nodes have access to the
617
+ # compiler instance itself
618
+ root_node.extend CompilerAccessible
619
+ root_node.current_compiler = self
620
+ root_node.accept(NodesVisitor.new)
575
621
  root_node.compiled_output
576
622
  end
577
623
 
data/lib/constants.rb CHANGED
@@ -11,10 +11,14 @@ module Riml
11
11
  class new)
12
12
  DEFINE_KEYWORDS = %w(def def! defm defm! function function!)
13
13
  KEYWORDS = VIML_KEYWORDS + VIML_END_KEYWORDS + RIML_KEYWORDS
14
+
14
15
  SPECIAL_VARIABLE_PREFIXES =
15
16
  %w(& @ $)
16
17
  BUILTIN_COMMANDS =
17
18
  %w(echo echon echohl execute sleep)
19
+ RIML_COMMANDS =
20
+ %w(riml_source)
21
+
18
22
  IGNORECASE_CAPABLE_OPERATORS =
19
23
  %w(== != >= > <= < =~ !~)
20
24
  COMPARISON_OPERATORS = IGNORECASE_CAPABLE_OPERATORS.map do |o|
@@ -1,9 +1,10 @@
1
1
  module Riml
2
2
  module Environment
3
3
  ROOTDIR = File.expand_path('../../', __FILE__)
4
+ require File.join(ROOTDIR, 'version')
4
5
 
5
- LIBDIR = File.join(ROOTDIR, "lib")
6
- BINDIR = File.join(ROOTDIR, "bin")
6
+ LIBDIR = File.join(ROOTDIR, 'lib')
7
+ BINDIR = File.join(ROOTDIR, 'bin')
7
8
 
8
9
  $:.unshift(LIBDIR) unless $:.include? LIBDIR
9
10
  end
data/lib/errors.rb CHANGED
@@ -1,4 +1,9 @@
1
1
  module Riml
2
- class ParseError < StandardError; end
3
- class SyntaxError < ::SyntaxError; end
2
+ RimlError = Class.new(StandardError)
3
+
4
+ SyntaxError = Class.new(RimlError)
5
+ ParseError = Class.new(RimlError)
6
+ CompileError = Class.new(RimlError)
7
+
8
+ FileNotFound = Class.new(RimlError)
4
9
  end
data/lib/grammar.y CHANGED
@@ -5,7 +5,7 @@ token WHILE UNTIL BREAK CONTINUE
5
5
  token TRY CATCH ENSURE
6
6
  token FOR IN
7
7
  token DEF DEF_BANG SPLAT CALL BUILTIN_COMMAND # such as echo "hi"
8
- token CLASS NEW DEFM DEFM_BANG SUPER
8
+ token CLASS NEW DEFM DEFM_BANG SUPER RIML_COMMAND
9
9
  token RETURN
10
10
  token NEWLINE
11
11
  token NUMBER
@@ -21,14 +21,14 @@ token FINISH
21
21
  prechigh
22
22
  right '!'
23
23
  left '*' '/' '%'
24
- left '+' '+=' '-' '-=' '.'
24
+ left '+' '-' '.'
25
25
  left '>' '>#' '>?' '<' '<#' '<?' '>=' '>=#' '>=?' '<=' '<=#' '<=?'
26
26
  left '==' '==?' '==#' '=~' '=~?' '=~#' '!~' '!~?' '!~#' '!=' '!=?' '!=#'
27
27
  left IS ISNOT
28
28
  left '&&'
29
29
  left '||'
30
30
  right '?'
31
- right '='
31
+ right '=' '+=' '-=' '.='
32
32
  left ','
33
33
  left IF UNLESS
34
34
  preclow
@@ -43,40 +43,47 @@ rule
43
43
 
44
44
  # any list of expressions
45
45
  Expressions:
46
- Expression { result = Nodes.new([ val[0] ]) }
47
- | Expressions Terminator Expression { result = val[0] << val[2] }
46
+ AnyExpression { result = Nodes.new([ val[0] ]) }
47
+ | Expressions Terminator AnyExpression { result = val[0] << val[2] }
48
48
  | Expressions Terminator { result = val[0] }
49
49
  | Terminator { result = Nodes.new([]) }
50
50
  ;
51
51
 
52
52
  # All types of expressions in Riml
53
- Expression:
54
- BinaryOperator { result = val[0] }
55
- | UnaryOperator { result = val[0] }
56
- | Call { result = val[0] }
57
- | Assign { result = val[0] }
58
- | DictGet { result = val[0] }
59
- | ListOrDictGet { result = val[0] }
53
+ AnyExpression:
54
+ ExplicitCall { result = val[0] }
60
55
  | Def { result = val[0] }
61
56
  | Return { result = val[0] }
62
- | VariableRetrieval { result = val[0] }
63
57
  | UnletVariable { result = val[0] }
64
- | Literal { result = val[0] }
65
58
  | ExLiteral { result = val[0] }
66
- | Heredoc { result = val[0] }
67
59
  | If { result = val[0] }
68
60
  | Unless { result = val[0] }
69
- | Ternary { result = val[0] }
61
+ | For { result = val[0] }
70
62
  | While { result = val[0] }
71
63
  | Until { result = val[0] }
72
- | For { result = val[0] }
73
64
  | Try { result = val[0] }
74
65
  | ClassDefinition { result = val[0] }
75
- | ObjectInstantiation { result = val[0] }
76
66
  | Super { result = val[0] }
77
67
  | LoopKeyword { result = val[0] }
78
68
  | EndScript { result = val[0] }
79
- | '(' Expression ')' { result = val[1] }
69
+ | ValueExpression { result = val[0] }
70
+ | RimlCommand { result = val[0] }
71
+ ;
72
+
73
+ # Expressions that evaluate to a value
74
+ ValueExpression:
75
+ UnaryOperator { result = val[0] }
76
+ | Assign { result = val[0] }
77
+ | DictGet { result = val[0] }
78
+ | ListOrDictGet { result = val[0] }
79
+ | VariableRetrieval { result = val[0] }
80
+ | Literal { result = val[0] }
81
+ | Call { result = val[0] }
82
+ | Heredoc { result = val[0] }
83
+ | Ternary { result = val[0] }
84
+ | ObjectInstantiation { result = val[0] }
85
+ | BinaryOperator { result = val[0] }
86
+ | '(' ValueExpression ')' { result = WrapInParensNode.new(val[1]) }
80
87
  ;
81
88
 
82
89
  Terminator:
@@ -100,8 +107,6 @@ rule
100
107
 
101
108
  Number:
102
109
  NUMBER { result = NumberNode.new(val[0]) }
103
- | '-' NUMBER { result = NumberNode.new(val[1].insert(0, val[0])) }
104
- | '+' NUMBER { result = NumberNode.new(val[1].insert(0, val[0])) }
105
110
  ;
106
111
 
107
112
  String:
@@ -132,8 +137,8 @@ rule
132
137
 
133
138
  ListItems:
134
139
  /* nothing */ { result = [] }
135
- | Expression { result = [val[0]] }
136
- | ListItems ',' Expression { result = val[0] << val[2] }
140
+ | ValueExpression { result = [val[0]] }
141
+ | ListItems ',' ValueExpression { result = val[0] << val[2] }
137
142
  ;
138
143
 
139
144
  Dictionary:
@@ -159,30 +164,27 @@ rule
159
164
  ;
160
165
 
161
166
  DictGet:
162
- Dictionary ListOrDictGetWithBrackets { result = DictGetBracketNode.new(val[0], val[1]) }
163
- | Dictionary DictGetWithDotLiteral { result = DictGetDotNode.new(val[0], val[1]) }
167
+ Dictionary DictGetWithDotLiteral { result = DictGetDotNode.new(val[0], val[1]) }
164
168
  | VariableRetrieval DictGetWithDot { result = DictGetDotNode.new(val[0], val[1]) }
165
169
  | ListOrDictGet DictGetWithDot { result = DictGetDotNode.new(val[0], val[1]) }
166
170
  ;
167
171
 
168
172
  ListOrDictGet:
169
- VariableRetrieval ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
170
- | DictGet ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
171
- | Call ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
173
+ ValueExpression ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
172
174
  ;
173
175
 
174
176
  ListOrDictGetWithBrackets:
175
- '[' Expression ']' { result = [val[1]] }
176
- | '[' SubList ']' { result = [val[1]] }
177
- | ListOrDictGetWithBrackets '[' Expression ']' { result = val[0] << val[2] }
178
- | ListOrDictGetWithBrackets '[' SubList ']' { result = val[0] << val[2] }
177
+ '[' ValueExpression ']' { result = [val[1]] }
178
+ | '[' SubList ']' { result = [val[1]] }
179
+ | ListOrDictGetWithBrackets '[' ValueExpression ']' { result = val[0] << val[2] }
180
+ | ListOrDictGetWithBrackets '[' SubList ']' { result = val[0] << val[2] }
179
181
  ;
180
182
 
181
183
  SubList:
182
- Expression ':' Expression { result = Nodes.new([val[0], LiteralNode.new(' : '), val[2]]) }
183
- | Expression ':' { result = Nodes.new([val[0], LiteralNode.new(' :')]) }
184
- | ':' Expression { result = Nodes.new([LiteralNode.new(': '), val[1]]) }
185
- | ':' { result = Nodes.new([LiteralNode.new(':')]) }
184
+ ValueExpression ':' ValueExpression { result = SublistNode.new([val[0], LiteralNode.new(' : '), val[2]]) }
185
+ | ValueExpression ':' { result = SublistNode.new([val[0], LiteralNode.new(' :')]) }
186
+ | ':' ValueExpression { result = SublistNode.new([LiteralNode.new(': '), val[1]]) }
187
+ | ':' { result = SublistNode.new([LiteralNode.new(':')]) }
186
188
  ;
187
189
 
188
190
  DictGetWithDot:
@@ -198,10 +200,19 @@ rule
198
200
  Call:
199
201
  Scope DefCallIdentifier '(' ArgList ')' { result = CallNode.new(val[0], val[1], val[3]) }
200
202
  | DictGet '(' ArgList ')' { result = CallNode.new(nil, val[0], val[2]) }
201
- | CALL Scope DefCallIdentifier '(' ArgList ')' { result = ExplicitCallNode.new(val[1], val[2], val[4]) }
202
- | CALL DictGet '(' ArgList ')' { result = ExplicitCallNode.new(nil, val[1], val[3]) }
203
203
  | BUILTIN_COMMAND '(' ArgList ')' { result = CallNode.new(nil, val[0], val[2]) }
204
204
  | BUILTIN_COMMAND ArgList { result = CallNode.new(nil, val[0], val[1]) }
205
+ | CALL '(' ArgList ')' { result = ExplicitCallNode.new(nil, nil, val[2]) }
206
+ ;
207
+
208
+ RimlCommand:
209
+ RIML_COMMAND '(' ArgList ')' { result = RimlCommandNode.new(nil, val[0], val[2]) }
210
+ | RIML_COMMAND ArgList { result = RimlCommandNode.new(nil, val[0], val[1]) }
211
+ ;
212
+
213
+ ExplicitCall:
214
+ CALL Scope DefCallIdentifier '(' ArgList ')' { result = ExplicitCallNode.new(val[1], val[2], val[4]) }
215
+ | CALL DictGet '(' ArgList ')' { result = ExplicitCallNode.new(nil, val[1], val[3]) }
205
216
  ;
206
217
 
207
218
  Scope:
@@ -211,101 +222,103 @@ rule
211
222
 
212
223
  ArgList:
213
224
  /* nothing */ { result = [] }
214
- | Expression { result = val }
215
- | ArgList "," Expression { result = val[0] << val[2] }
225
+ | ValueExpression { result = val }
226
+ | ArgList "," ValueExpression { result = val[0] << val[2] }
216
227
  ;
217
228
 
218
229
  BinaryOperator:
219
- Expression '||' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
220
- | Expression '&&' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
230
+ ValueExpression '||' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
231
+ | ValueExpression '&&' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
221
232
 
222
- | Expression '==' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
223
- | Expression '==#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
224
- | Expression '==?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
233
+ | ValueExpression '==' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
234
+ | ValueExpression '==#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
235
+ | ValueExpression '==?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
225
236
 
226
237
  # added by riml
227
- | Expression '===' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
238
+ | ValueExpression '===' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
228
239
 
229
- | Expression '!=' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
230
- | Expression '!=#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
231
- | Expression '!=?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
240
+ | ValueExpression '!=' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
241
+ | ValueExpression '!=#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
242
+ | ValueExpression '!=?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
232
243
 
233
- | Expression '=~' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
234
- | Expression '=~#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
235
- | Expression '=~?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
244
+ | ValueExpression '=~' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
245
+ | ValueExpression '=~#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
246
+ | ValueExpression '=~?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
236
247
 
237
- | Expression '!~' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
238
- | Expression '!~#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
239
- | Expression '!~?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
248
+ | ValueExpression '!~' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
249
+ | ValueExpression '!~#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
250
+ | ValueExpression '!~?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
240
251
 
241
- | Expression '>' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
242
- | Expression '>#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
243
- | Expression '>?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
252
+ | ValueExpression '>' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
253
+ | ValueExpression '>#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
254
+ | ValueExpression '>?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
244
255
 
245
- | Expression '>=' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
246
- | Expression '>=#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
247
- | Expression '>=?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
256
+ | ValueExpression '>=' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
257
+ | ValueExpression '>=#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
258
+ | ValueExpression '>=?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
248
259
 
249
- | Expression '<' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
250
- | Expression '<#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
251
- | Expression '<?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
260
+ | ValueExpression '<' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
261
+ | ValueExpression '<#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
262
+ | ValueExpression '<?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
252
263
 
253
- | Expression '<=' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
254
- | Expression '<=#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
255
- | Expression '<=?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
264
+ | ValueExpression '<=' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
265
+ | ValueExpression '<=#' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
266
+ | ValueExpression '<=?' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
256
267
 
257
- | Expression '+' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
258
- | Expression '-' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
259
- | Expression '*' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
260
- | Expression '/' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
261
- | Expression '.' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
268
+ | ValueExpression '+' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
269
+ | ValueExpression '-' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
270
+ | ValueExpression '*' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
271
+ | ValueExpression '/' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
272
+ | ValueExpression '.' ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
262
273
 
263
- | Expression IS Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
264
- | Expression ISNOT Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
274
+ | ValueExpression IS ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
275
+ | ValueExpression ISNOT ValueExpression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
265
276
  ;
266
277
 
267
278
  UnaryOperator:
268
- '!' Expression { result = UnaryOperatorNode.new(val[0], val[1]) }
279
+ '!' ValueExpression { result = UnaryOperatorNode.new(val[0], val[1]) }
280
+ | '+' ValueExpression { result = UnaryOperatorNode.new(val[0], val[1]) }
281
+ | '-' ValueExpression { result = UnaryOperatorNode.new(val[0], val[1]) }
269
282
  ;
270
283
 
271
284
  # ['=', LHS, RHS]
272
285
  Assign:
273
- LET AssignExpression { result = AssignNode.new(val[1][0], val[1][1], val[1][2]) }
274
- | AssignExpression { result = AssignNode.new(val[0][0], val[0][1], val[0][2]) }
286
+ LET AssignExpression { result = AssignNode.new(val[1][0], val[1][1], val[1][2]) }
287
+ | AssignExpression { result = AssignNode.new(val[0][0], val[0][1], val[0][2]) }
275
288
  ;
276
289
 
277
290
  # ['=', AssignLHS, Expression]
278
291
  AssignExpression:
279
- AssignLHS '=' Expression { result = [val[1], val[0], val[2]] }
280
- | AssignLHS '+=' Expression { result = [val[1], val[0], val[2]] }
281
- | AssignLHS '-=' Expression { result = [val[1], val[0], val[2]] }
282
- | AssignLHS '.=' Expression { result = [val[1], val[0], val[2]] }
292
+ AssignLHS '=' ValueExpression { result = [val[1], val[0], val[2]] }
293
+ | AssignLHS '+=' ValueExpression { result = [val[1], val[0], val[2]] }
294
+ | AssignLHS '-=' ValueExpression { result = [val[1], val[0], val[2]] }
295
+ | AssignLHS '.=' ValueExpression { result = [val[1], val[0], val[2]] }
283
296
  ;
284
297
 
285
298
  AssignLHS:
286
- VariableRetrieval { result = val[0] }
287
- | DictGet { result = val[0] }
288
- | List { result = val[0] }
289
- | ListOrDictGet { result = val[0] }
299
+ VariableRetrieval { result = val[0] }
300
+ | DictGet { result = val[0] }
301
+ | List { result = val[0] }
302
+ | ListOrDictGet { result = val[0] }
290
303
  ;
291
304
 
292
305
  # retrieving the value of a variable
293
306
  VariableRetrieval:
294
- Scope IDENTIFIER { result = GetVariableNode.new(val[0], val[1]) }
295
- | SPECIAL_VAR_PREFIX IDENTIFIER { result = GetSpecialVariableNode.new(val[0], val[1]) }
296
- | Scope CurlyBraceName { result = GetCurlyBraceNameNode.new(val[0], val[1])}
307
+ Scope IDENTIFIER { result = GetVariableNode.new(val[0], val[1]) }
308
+ | SPECIAL_VAR_PREFIX IDENTIFIER { result = GetSpecialVariableNode.new(val[0], val[1]) }
309
+ | Scope CurlyBraceName { result = GetCurlyBraceNameNode.new(val[0], val[1]) }
297
310
  ;
298
311
 
299
312
  UnletVariable:
300
- UNLET VariableRetrieval { result = UnletVariableNode.new('!', [ val[1] ]) }
301
- | UNLET_BANG VariableRetrieval { result = UnletVariableNode.new('!', [ val[1] ]) }
302
- | UnletVariable VariableRetrieval { result = val[0] << val[1] }
313
+ UNLET VariableRetrieval { result = UnletVariableNode.new('!', [ val[1] ]) }
314
+ | UNLET_BANG VariableRetrieval { result = UnletVariableNode.new('!', [ val[1] ]) }
315
+ | UnletVariable VariableRetrieval { result = val[0] << val[1] }
303
316
  ;
304
317
 
305
318
  CurlyBraceName:
306
- IDENTIFIER '{' VariableRetrieval '}' { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[0]), CurlyBracePart.new(val[2]) ]) }
307
- | '{' VariableRetrieval '}' IDENTIFIER { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[1]), CurlyBracePart.new(val[3]) ]) }
308
- | CurlyBraceName IDENTIFIER { result = val[0] << CurlyBracePart.new(val[1]) }
319
+ IDENTIFIER '{' VariableRetrieval '}' { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[0]), CurlyBracePart.new(val[2]) ]) }
320
+ | '{' VariableRetrieval '}' IDENTIFIER { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[1]), CurlyBracePart.new(val[3]) ]) }
321
+ | CurlyBraceName IDENTIFIER { result = val[0] << CurlyBracePart.new(val[1]) }
309
322
  ;
310
323
 
311
324
  # Method definition
@@ -325,11 +338,11 @@ rule
325
338
 
326
339
  DefCallIdentifier:
327
340
  # use '' for first argument instead of nil in order to avoid a double scope-modifier
328
- CurlyBraceName { result = GetCurlyBraceNameNode.new('', val[0])}
341
+ CurlyBraceName { result = GetCurlyBraceNameNode.new('', val[0]) }
329
342
  | IDENTIFIER { result = val[0] }
330
343
  ;
331
344
 
332
- # Example: 'range' or 'dict' after function definition
345
+ # Example: 'range', 'dict' or 'abort' after function definition
333
346
  Keyword:
334
347
  IDENTIFIER { result = val[0] }
335
348
  | /* nothing */ { result = nil }
@@ -342,7 +355,7 @@ rule
342
355
  ;
343
356
 
344
357
  Return:
345
- RETURN Expression { result = ReturnNode.new(val[1]) }
358
+ RETURN ValueExpression { result = ReturnNode.new(val[1]) }
346
359
  | RETURN Terminator { result = ReturnNode.new(nil) }
347
360
  ;
348
361
 
@@ -352,23 +365,23 @@ rule
352
365
 
353
366
  # [expression, expressions]
354
367
  If:
355
- IF Expression IfBlock END { result = IfNode.new(val[1], val[2]) }
356
- | IF Expression THEN Expression END { result = IfNode.new(val[1], Nodes.new([val[3]])) }
357
- | Expression IF Expression { result = IfNode.new(val[2], Nodes.new([val[0]])) }
368
+ IF ValueExpression IfBlock END { result = IfNode.new(val[1], val[2]) }
369
+ | IF ValueExpression THEN ValueExpression END { result = IfNode.new(val[1], Nodes.new([val[3]])) }
370
+ | ValueExpression IF ValueExpression { result = IfNode.new(val[2], Nodes.new([val[0]])) }
358
371
  ;
359
372
 
360
373
  Unless:
361
- UNLESS Expression IfBlock END { result = UnlessNode.new(val[1], val[2]) }
362
- | UNLESS Expression THEN Expression END { result = UnlessNode.new(val[1], Nodes.new([val[3]])) }
363
- | Expression UNLESS Expression { result = UnlessNode.new(val[2], Nodes.new([val[0]])) }
374
+ UNLESS ValueExpression IfBlock END { result = UnlessNode.new(val[1], val[2]) }
375
+ | UNLESS ValueExpression THEN ValueExpression END { result = UnlessNode.new(val[1], Nodes.new([val[3]])) }
376
+ | ValueExpression UNLESS ValueExpression { result = UnlessNode.new(val[2], Nodes.new([val[0]])) }
364
377
  ;
365
378
 
366
379
  Ternary:
367
- Expression '?' Expression ':' Expression { result = TernaryOperatorNode.new([val[0], val[2], val[4]]) }
380
+ ValueExpression '?' ValueExpression ':' ValueExpression { result = TernaryOperatorNode.new([val[0], val[2], val[4]]) }
368
381
  ;
369
382
 
370
383
  While:
371
- WHILE Expression Block END { result = WhileNode.new(val[1], val[2]) }
384
+ WHILE ValueExpression Block END { result = WhileNode.new(val[1], val[2]) }
372
385
  ;
373
386
 
374
387
  LoopKeyword:
@@ -377,12 +390,12 @@ rule
377
390
  ;
378
391
 
379
392
  Until:
380
- UNTIL Expression Block END { result = UntilNode.new(val[1], val[2]) }
393
+ UNTIL ValueExpression Block END { result = UntilNode.new(val[1], val[2]) }
381
394
  ;
382
395
 
383
396
  For:
384
- FOR IDENTIFIER IN Expression Block END { result = ForNode.new(val[1], val[3], val[4]) }
385
- | FOR List IN Expression Block END { result = ForNode.new(val[1], val[3], val[4]) }
397
+ FOR IDENTIFIER IN ValueExpression Block END { result = ForNode.new(val[1], val[3], val[4]) }
398
+ | FOR List IN ValueExpression Block END { result = ForNode.new(val[1], val[3], val[4]) }
386
399
  ;
387
400
 
388
401
  Try:
@@ -409,17 +422,18 @@ rule
409
422
 
410
423
  IfBlock:
411
424
  Block { result = val[0] }
412
- | NEWLINE Expressions ElseBlock { result = val[1].concat(val[2]) }
425
+ | NEWLINE Expressions ElseBlock { result = val[1] << val[2] }
426
+ | NEWLINE Expressions ElseifBlock { result = val[1] << val[2] }
427
+ | NEWLINE Expressions ElseifBlock ElseBlock { result = val[1] << val[2] << val[3] }
413
428
  ;
414
429
 
415
430
  ElseBlock:
416
- ElseifBlock ELSE NEWLINE Expressions { result = [val[0], ElseNode.new(val[3])].compact }
431
+ ELSE NEWLINE Expressions { result = ElseNode.new(val[2]) }
417
432
  ;
418
433
 
419
434
  ElseifBlock:
420
- ELSEIF Expression NEWLINE Expressions { result = Nodes.new([ElseifNode.new(val[1], val[3])]) }
421
- | ElseifBlock ELSEIF Expression NEWLINE Expressions { result = val[0] << ElseifNode.new(val[2], val[4]) }
422
- | /* nothing */ { result = nil }
435
+ ELSEIF ValueExpression NEWLINE Expressions { result = Nodes.new([ElseifNode.new(val[1], val[3])]) }
436
+ | ElseifBlock ELSEIF ValueExpression NEWLINE Expressions { result = val[0] << ElseifNode.new(val[2], val[4]) }
423
437
  ;
424
438
 
425
439
  ClassDefinition:
@@ -449,27 +463,31 @@ end
449
463
  ---- inner
450
464
  # This code will be put as-is in the parser class
451
465
 
466
+ attr_accessor :ast_rewriter
467
+
452
468
  # parses tokens or code into output nodes
453
- def parse(object, rewrite_ast = true)
469
+ def parse(object, ast_rewriter = AST_Rewriter.new)
454
470
  if tokens?(object)
455
471
  @tokens = object
456
472
  elsif code?(object)
457
473
  @lexer = Riml::Lexer.new(object)
458
474
  end
459
- ast = do_parse
460
- return ast if rewrite_ast == false
461
- AST_Rewriter.new(ast).rewrite
462
- end
463
475
 
464
- alias do_parse_without_error_handling do_parse
465
- def do_parse_with_error_handling
466
- do_parse_without_error_handling
467
- rescue Racc::ParseError => e
468
- raise unless @lexer
469
- raise Riml::ParseError, "line #{@lexer.lineno}: #{e.message}"
476
+ begin
477
+ ast = do_parse
478
+ rescue Racc::ParseError => e
479
+ raise unless @lexer
480
+ raise Riml::ParseError, "line #{@lexer.lineno}: #{e.message}"
481
+ end
482
+
483
+ @ast_rewriter = ast_rewriter
484
+ return ast unless @ast_rewriter
485
+ @ast_rewriter.ast = ast
486
+ @ast_rewriter.rewrite
470
487
  end
471
- alias do_parse do_parse_with_error_handling
472
488
 
489
+ # get the next token from either the list of tokens provided, or
490
+ # the lexer getting the next token
473
491
  def next_token
474
492
  return @tokens.shift unless @lexer
475
493
  @lexer.next_token