riml 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|