riml 0.3.1 → 0.3.2
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/Gemfile.lock +3 -2
- data/Rakefile +2 -0
- data/bin/riml +15 -5
- data/lib/backtrace_filter.rb +14 -0
- data/lib/compiler.rb +36 -10
- data/lib/nodes.rb +59 -24
- data/lib/repl.rb +5 -3
- data/lib/riml.rb +32 -12
- data/version.rb +2 -2
- metadata +3 -2
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
data/bin/riml
CHANGED
@@ -20,7 +20,8 @@ module Riml
|
|
20
20
|
options.check_syntax_files = []
|
21
21
|
options.repl = false
|
22
22
|
options.vi_readline = false
|
23
|
-
options.
|
23
|
+
options.readable = DEFAULT_COMPILE_OPTIONS[:readable]
|
24
|
+
options.output_dir = DEFAULT_COMPILE_FILES_OPTIONS[:output_dir]
|
24
25
|
|
25
26
|
OptionParser.new do |opts|
|
26
27
|
opts.banner = "Usage: riml [options] [file1][,file2]..."
|
@@ -59,6 +60,10 @@ module Riml
|
|
59
60
|
options.output_dir = dir
|
60
61
|
end
|
61
62
|
|
63
|
+
opts.on("-d", "--condensed", "Compiled VimL contains no extraneous newlines") do
|
64
|
+
options.readable = false
|
65
|
+
end
|
66
|
+
|
62
67
|
opts.on("-i", "--interactive", "Start an interactive riml session (REPL).") do
|
63
68
|
options.repl = true
|
64
69
|
end
|
@@ -101,11 +106,16 @@ module Riml
|
|
101
106
|
class << self
|
102
107
|
def start
|
103
108
|
options = Options.parse(ARGV)
|
104
|
-
|
109
|
+
compile_options = {
|
110
|
+
:readable => options.readable
|
111
|
+
}
|
112
|
+
compile_files_options = compile_options.merge(
|
113
|
+
:output_dir => options.output_dir
|
114
|
+
)
|
105
115
|
if options.stdio
|
106
|
-
puts Riml.compile($stdin.read)
|
116
|
+
puts Riml.compile($stdin.read, compile_options)
|
107
117
|
elsif options.compile_files.any?
|
108
|
-
Riml.compile_files(*options.compile_files,
|
118
|
+
Riml.compile_files(*options.compile_files, compile_files_options)
|
109
119
|
elsif options.check_syntax_files.any?
|
110
120
|
files = options.check_syntax_files
|
111
121
|
Riml.check_syntax_files(*files)
|
@@ -114,7 +124,7 @@ module Riml
|
|
114
124
|
puts "ok (#{size} file#{'s' if size > 1})"
|
115
125
|
elsif options.repl
|
116
126
|
require 'repl'
|
117
|
-
Riml::Repl.new(options.vi_readline).run
|
127
|
+
Riml::Repl.new(options.vi_readline, compile_options).run
|
118
128
|
else
|
119
129
|
ARGV.replace ['--help']
|
120
130
|
start
|
data/lib/compiler.rb
CHANGED
@@ -3,7 +3,22 @@ require File.expand_path('../nodes', __FILE__)
|
|
3
3
|
# visits AST nodes and translates them into VimL
|
4
4
|
module Riml
|
5
5
|
class Compiler
|
6
|
-
attr_accessor :parser
|
6
|
+
attr_accessor :parser
|
7
|
+
attr_writer :options
|
8
|
+
|
9
|
+
# compiler options
|
10
|
+
|
11
|
+
def options
|
12
|
+
@options ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def output_dir
|
16
|
+
options[:output_dir]
|
17
|
+
end
|
18
|
+
|
19
|
+
def readable
|
20
|
+
options.has_key?(:readable) and options[:readable]
|
21
|
+
end
|
7
22
|
|
8
23
|
# Base abstract visitor
|
9
24
|
class Visitor
|
@@ -19,6 +34,8 @@ module Riml
|
|
19
34
|
propagate_up_tree(node, output)
|
20
35
|
end
|
21
36
|
|
37
|
+
protected
|
38
|
+
|
22
39
|
def propagate_up_tree(node, output)
|
23
40
|
node.parent_node.compiled_output << output.to_s unless @propagate_up_tree == false || node.parent_node.nil?
|
24
41
|
end
|
@@ -26,6 +43,17 @@ module Riml
|
|
26
43
|
def visitor_for_node(node, params={})
|
27
44
|
Compiler.const_get("#{node.class.name.split('::').last}Visitor").new(params)
|
28
45
|
end
|
46
|
+
|
47
|
+
def root_node(node)
|
48
|
+
@root_node ||= begin
|
49
|
+
node = node.parent until node.parent.nil?
|
50
|
+
node
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def current_compiler(node)
|
55
|
+
root_node(node).current_compiler
|
56
|
+
end
|
29
57
|
end
|
30
58
|
|
31
59
|
class IfNodeVisitor < Visitor
|
@@ -452,6 +480,11 @@ module Riml
|
|
452
480
|
end
|
453
481
|
end
|
454
482
|
node.compiled_output = declaration << body << "endfunction\n"
|
483
|
+
if current_compiler(node).readable
|
484
|
+
node.compiled_output << "\n"
|
485
|
+
else
|
486
|
+
node.compiled_output
|
487
|
+
end
|
455
488
|
end
|
456
489
|
|
457
490
|
private
|
@@ -565,7 +598,7 @@ module Riml
|
|
565
598
|
if node.name == 'riml_source'
|
566
599
|
node.name = 'source'
|
567
600
|
node.each_existing_file! do |basename, full_path|
|
568
|
-
|
601
|
+
current_compiler(node).compile_queue << full_path
|
569
602
|
end
|
570
603
|
elsif node.name == 'riml_include'
|
571
604
|
# riml_include has to be top-level
|
@@ -575,7 +608,7 @@ module Riml
|
|
575
608
|
end
|
576
609
|
node.each_existing_file! do |basename, full_path|
|
577
610
|
riml_src = File.read(full_path)
|
578
|
-
node.compiled_output <<
|
611
|
+
node.compiled_output << current_compiler(node).compile_include(riml_src, basename)
|
579
612
|
end
|
580
613
|
return node.compiled_output
|
581
614
|
end
|
@@ -585,13 +618,6 @@ module Riml
|
|
585
618
|
node.compiled_output.sub!('.riml', '.vim')
|
586
619
|
node.compiled_output
|
587
620
|
end
|
588
|
-
|
589
|
-
def root_node(node)
|
590
|
-
@root_node ||= begin
|
591
|
-
node = node.parent until node.parent.nil?
|
592
|
-
node
|
593
|
-
end
|
594
|
-
end
|
595
621
|
end
|
596
622
|
|
597
623
|
class ForNodeVisitor < Visitor
|
data/lib/nodes.rb
CHANGED
@@ -45,15 +45,19 @@ module Riml
|
|
45
45
|
alias walk each
|
46
46
|
|
47
47
|
def previous
|
48
|
-
idx =
|
49
|
-
|
50
|
-
|
48
|
+
idx = index_by_member
|
49
|
+
if idx && parent.members[idx - 1]
|
50
|
+
attr = parent.members[idx - 1]
|
51
|
+
return send(attr)
|
52
|
+
else
|
53
|
+
idx = index_by_children
|
54
|
+
return unless idx
|
55
|
+
parent.children.fetch(idx - 1)
|
56
|
+
end
|
51
57
|
end
|
52
58
|
|
53
59
|
def child_previous_to(node)
|
54
|
-
|
55
|
-
return unless idx
|
56
|
-
children.fetch(idx - 1)
|
60
|
+
node.previous
|
57
61
|
end
|
58
62
|
|
59
63
|
def insert_before(node, new_node)
|
@@ -63,15 +67,19 @@ module Riml
|
|
63
67
|
end
|
64
68
|
|
65
69
|
def next
|
66
|
-
idx =
|
67
|
-
|
68
|
-
|
70
|
+
idx = index_by_member
|
71
|
+
if idx && parent.members[idx + 1]
|
72
|
+
attr = parent.members[idx + 1]
|
73
|
+
return parent.send(attr)
|
74
|
+
else
|
75
|
+
idx = index_by_children
|
76
|
+
return unless idx
|
77
|
+
parent.children.fetch(idx + 1)
|
78
|
+
end
|
69
79
|
end
|
70
80
|
|
71
81
|
def child_after(node)
|
72
|
-
|
73
|
-
return unless idx
|
74
|
-
children.fetch(idx + 1)
|
82
|
+
node.next
|
75
83
|
end
|
76
84
|
|
77
85
|
def insert_after(node, new_node)
|
@@ -80,21 +88,44 @@ module Riml
|
|
80
88
|
children.insert(idx + 1, new_node)
|
81
89
|
end
|
82
90
|
|
83
|
-
def
|
91
|
+
def index_by_member
|
92
|
+
attrs = parent.members
|
93
|
+
attrs.each_with_index do |attr, i|
|
94
|
+
if parent.send(attr) == self
|
95
|
+
return i
|
96
|
+
end
|
97
|
+
end
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
def index_by_children
|
84
102
|
parent.children.find_index(self)
|
85
103
|
end
|
86
104
|
|
87
105
|
def remove
|
88
|
-
idx =
|
89
|
-
|
106
|
+
idx = index_by_member
|
107
|
+
if idx
|
108
|
+
attr = parent.members[idx]
|
109
|
+
parent.send("#{attr}=", nil)
|
110
|
+
else
|
111
|
+
idx = index_by_children
|
112
|
+
parent.children.slice!(idx) if idx
|
113
|
+
end
|
90
114
|
end
|
91
115
|
|
92
116
|
def replace_with(new_node)
|
93
|
-
idx =
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
117
|
+
idx = index_by_member
|
118
|
+
if idx
|
119
|
+
attr = parent.members[idx]
|
120
|
+
new_node.parent = parent
|
121
|
+
parent.send("#{attr}=", new_node)
|
122
|
+
else
|
123
|
+
idx = index_by_children
|
124
|
+
return unless idx
|
125
|
+
new_node.parent = parent
|
126
|
+
parent.children.insert(idx, new_node)
|
127
|
+
parent.children.slice!(idx + 1)
|
128
|
+
end
|
98
129
|
end
|
99
130
|
end
|
100
131
|
|
@@ -539,9 +570,13 @@ module Riml
|
|
539
570
|
end
|
540
571
|
|
541
572
|
def children
|
542
|
-
|
543
|
-
|
544
|
-
|
573
|
+
if !interpolated?
|
574
|
+
[]
|
575
|
+
elsif nested?
|
576
|
+
value
|
577
|
+
else
|
578
|
+
[value]
|
579
|
+
end
|
545
580
|
end
|
546
581
|
end
|
547
582
|
|
@@ -740,7 +775,7 @@ module Riml
|
|
740
775
|
end
|
741
776
|
class WhileNode < ControlStructure; end
|
742
777
|
|
743
|
-
class UnlessNode <
|
778
|
+
class UnlessNode < IfNode
|
744
779
|
def initialize(*)
|
745
780
|
super
|
746
781
|
wrap_condition_in_parens!
|
data/lib/repl.rb
CHANGED
@@ -9,7 +9,7 @@ require_relative 'riml'
|
|
9
9
|
module Riml
|
10
10
|
class Repl
|
11
11
|
attr_reader :line
|
12
|
-
attr_reader :parser, :compiler
|
12
|
+
attr_reader :parser, :compiler, :compiler_options
|
13
13
|
private :parser, :compiler
|
14
14
|
|
15
15
|
COMPILE_ON = %w(compile c)
|
@@ -22,9 +22,10 @@ clear previous class definitions: #{RELOAD_ON.join(', ')}
|
|
22
22
|
exit repl: #{EXIT_ON.join(', ')}
|
23
23
|
msg
|
24
24
|
|
25
|
-
def initialize(vi_readline = false)
|
25
|
+
def initialize(vi_readline = false, compile_options = {})
|
26
26
|
@indent_amount = 0
|
27
27
|
@line = nil
|
28
|
+
@compiler_options = DEFAULT_COMPILE_OPTIONS.merge(compile_options)
|
28
29
|
prepare_new_context
|
29
30
|
Readline.vi_editing_mode if vi_readline
|
30
31
|
trap(:INT) { reset!; puts }
|
@@ -55,6 +56,7 @@ msg
|
|
55
56
|
|
56
57
|
def prepare_new_context
|
57
58
|
@compiler = Compiler.new
|
59
|
+
@compiler.options = compiler_options
|
58
60
|
@parser = Parser.new
|
59
61
|
end
|
60
62
|
alias reload! prepare_new_context
|
@@ -76,7 +78,7 @@ msg
|
|
76
78
|
end
|
77
79
|
|
78
80
|
def compile_unit!
|
79
|
-
viml = Riml.
|
81
|
+
viml = Riml.do_compile(current_compilation_unit.join("\n"), parser, compiler).chomp
|
80
82
|
puts viml, "\n"
|
81
83
|
rescue => e
|
82
84
|
print_error(e)
|
data/lib/riml.rb
CHANGED
@@ -7,8 +7,15 @@ require 'lexer'
|
|
7
7
|
require 'parser'
|
8
8
|
require 'compiler'
|
9
9
|
require 'warning_buffer'
|
10
|
+
require 'backtrace_filter'
|
10
11
|
|
11
12
|
module Riml
|
13
|
+
|
14
|
+
DEFAULT_COMPILE_OPTIONS = { :readable => true }
|
15
|
+
DEFAULT_COMPILE_FILES_OPTIONS = DEFAULT_COMPILE_OPTIONS.merge(
|
16
|
+
:output_dir => nil
|
17
|
+
)
|
18
|
+
|
12
19
|
# lex code (String) into tokens (Array)
|
13
20
|
def self.lex(code)
|
14
21
|
Lexer.new(code).tokenize
|
@@ -23,10 +30,17 @@ module Riml
|
|
23
30
|
Parser.new.parse(input, ast_rewriter, filename)
|
24
31
|
end
|
25
32
|
|
33
|
+
def self.compile(input, options = {})
|
34
|
+
parser = Parser.new
|
35
|
+
compiler = Compiler.new
|
36
|
+
compiler.options = DEFAULT_COMPILE_OPTIONS.merge(options)
|
37
|
+
do_compile(input, parser, compiler)
|
38
|
+
end
|
39
|
+
|
26
40
|
# compile AST (Nodes), tokens (Array), code (String) or object that returns
|
27
41
|
# String from :read to output code (String). Writes file(s) if `input` is a
|
28
42
|
# File.
|
29
|
-
def self.
|
43
|
+
def self.do_compile(input, parser = Parser.new, compiler = Compiler.new)
|
30
44
|
if input.is_a?(Nodes)
|
31
45
|
nodes = input
|
32
46
|
elsif input.is_a?(String) || input.is_a?(Array)
|
@@ -59,16 +73,15 @@ module Riml
|
|
59
73
|
process_compile_queue!(compiler)
|
60
74
|
end
|
61
75
|
|
62
|
-
# expects `filenames` (String) arguments, to be readable files.
|
63
|
-
# last argument.
|
76
|
+
# expects `filenames` (String) arguments, to be readable files.
|
77
|
+
# Optional options (Hash) as last argument.
|
64
78
|
def self.compile_files(*filenames)
|
65
79
|
parser, compiler = Parser.new, Compiler.new
|
66
80
|
|
67
81
|
if filenames.last.is_a?(Hash)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
82
|
+
compiler.options = DEFAULT_COMPILE_FILES_OPTIONS.merge(filenames.pop)
|
83
|
+
else
|
84
|
+
compiler.options = DEFAULT_COMPILE_FILES_OPTIONS.dup
|
72
85
|
end
|
73
86
|
|
74
87
|
if filenames.size > 1
|
@@ -78,22 +91,26 @@ module Riml
|
|
78
91
|
_parser, _compiler = parser, compiler
|
79
92
|
else
|
80
93
|
_parser, _compiler = Parser.new, Compiler.new
|
81
|
-
_compiler.
|
94
|
+
_compiler.options = compiler.options
|
82
95
|
end
|
83
96
|
threads << Thread.new do
|
84
97
|
f = File.open(fname)
|
85
|
-
|
98
|
+
# `do_compile` will close file handle
|
99
|
+
do_compile(f, _parser, _compiler)
|
86
100
|
end
|
87
101
|
end
|
88
102
|
threads.each {|t| t.join}
|
89
103
|
elsif filenames.size == 1
|
90
104
|
fname = filenames.first
|
91
105
|
f = File.open(fname)
|
92
|
-
# `
|
93
|
-
|
106
|
+
# `do_compile` will close file handle
|
107
|
+
do_compile(f, parser, compiler)
|
94
108
|
else
|
95
109
|
raise ArgumentError, "need filenames to compile"
|
96
110
|
end
|
111
|
+
rescue Riml::ParseError => pe
|
112
|
+
BacktraceFilter.new(pe).filter!
|
113
|
+
raise
|
97
114
|
ensure
|
98
115
|
flush_warnings
|
99
116
|
end
|
@@ -183,7 +200,7 @@ module Riml
|
|
183
200
|
while full_path = compiler.compile_queue.shift
|
184
201
|
unless compiler.sourced_files_compiled.include?(full_path)
|
185
202
|
compiler.sourced_files_compiled << full_path
|
186
|
-
|
203
|
+
do_compile(File.open(full_path), compiler.parser, compiler)
|
187
204
|
end
|
188
205
|
end
|
189
206
|
end
|
@@ -210,6 +227,9 @@ module Riml
|
|
210
227
|
basename_without_riml_ext = File.basename(fname).sub(/\.riml\Z/i, '')
|
211
228
|
FileUtils.mkdir_p(output_dir) unless File.directory?(output_dir)
|
212
229
|
full_path = File.join(output_dir, "#{basename_without_riml_ext}.vim")
|
230
|
+
if output[-2..-1] == "\n\n"
|
231
|
+
output.chomp!
|
232
|
+
end
|
213
233
|
File.open(full_path, 'w') do |f|
|
214
234
|
f.write FILE_HEADER + output
|
215
235
|
end
|
data/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: riml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: racc
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- lib/included.vim
|
65
65
|
- lib/constants.rb
|
66
66
|
- lib/parser.output
|
67
|
+
- lib/backtrace_filter.rb
|
67
68
|
- lib/lexer.rb
|
68
69
|
- lib/grammar.y
|
69
70
|
- lib/compiler.rb
|