riml 0.1.3 → 0.1.5

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.
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