Module: Riml
- Defined in:
- lib/riml/compiler.rb,
lib/riml.rb,
lib/riml/repl.rb,
lib/riml/lexer.rb,
lib/riml/nodes.rb,
lib/riml/errors.rb,
lib/riml/parser.rb,
lib/riml/walker.rb,
lib/riml/walkable.rb,
lib/riml/class_map.rb,
lib/riml/constants.rb,
lib/riml/path_cache.rb,
lib/riml/environment.rb,
lib/riml/ast_rewriter.rb,
lib/riml/file_rollback.rb,
lib/riml/include_cache.rb,
lib/riml/imported_class.rb,
lib/riml/warning_buffer.rb,
lib/riml/backtrace_filter.rb,
lib/riml/rewritten_ast_cache.rb,
lib/riml/class_dependency_graph.rb
Overview
visits AST nodes and translates them into VimL
Defined Under Namespace
Modules: Constants, Environment, ErrorWithoutNodeAvailable, FullyNameable, Indentable, NotNestedUnder, QuestionVariableExistence, Visitable, Walkable Classes: AST_Rewriter, AssignNode, BacktraceFilter, BinaryOperatorNode, BreakNode, CallNode, CatchNode, ClassDefinitionNode, ClassDependencyGraph, ClassMap, Compiler, ContinueNode, ControlStructure, CurlyBracePart, CurlyBraceVariable, DefMethodNode, DefNode, DefaultParamNode, DictGetBracketNode, DictGetDotNode, DictGetNode, DictionaryNode, ElseNode, ElseifNode, ExLiteralNode, ExplicitCallNode, FalseNode, FileRollback, FinishNode, ForNode, GetCurlyBraceNameNode, GetSpecialVariableNode, GetVariableByScopeAndDictNameNode, GetVariableNode, IfNode, ImportedClass, IncludeCache, KeywordNode, Lexer, ListNode, ListOrDictGetNode, ListUnpackNode, LiteralNode, MultiAssignNode, Nodes, NumberNode, ObjectInstantiationNode, OperatorNode, ParseError, Parser, PathCache, RegexpNode, Repl, ReturnNode, RewrittenASTCache, RimlClassCommandNode, RimlCommandNode, RimlError, RimlFileCommandNode, SIDNode, ScopeModifierLiteralNode, ScopeNode, SplatNode, StringLiteralConcatNode, StringNode, SublistNode, SuperNode, SyntaxError, TernaryOperatorNode, TrueNode, TryNode, UnaryOperatorNode, UnlessNode, UnletVariableNode, UntilNode, Walker, WarningBuffer, WhileNode, WrapInParensNode
Constant Summary collapse
- DEFAULT_COMPILE_OPTIONS =
{ :readable => true }
- DEFAULT_COMPILE_FILES_OPTIONS =
DEFAULT_COMPILE_OPTIONS.merge( :output_dir => nil )
- DEFAULT_PARSE_OPTIONS =
{ :allow_undefined_global_classes => false, :include_reordering => true }
- EXTRACT_PARSE_OPTIONS =
lambda { |k,_| DEFAULT_PARSE_OPTIONS.keys.include?(k.to_sym) }
- EXTRACT_COMPILE_OPTIONS =
lambda { |k,_| DEFAULT_COMPILE_OPTIONS.keys.include?(k.to_sym) }
- EXTRACT_COMPILE_FILES_OPTIONS =
lambda { |k,_| DEFAULT_COMPILE_FILES_OPTIONS.keys.include?(k.to_sym) }
- FILENAME_OPTION_KEYS =
[:commandline_filename, :sourced_filename]
- EXTRACT_FILENAME_OPTIONS =
lambda { |k,_| FILENAME_OPTION_KEYS.include?(k.to_sym) }
- CompileError =
Class.new(RimlError)
- FileNotFound =
Class.new(RimlError)
- IncludeFileLoop =
Class.new(RimlError)
- SourceFileLoop =
Class.new(RimlError)
- IncludeNotTopLevel =
Class.new(RimlError)
- UserArgumentError =
bad user arguments to Riml functions
Class.new(RimlError)
- InvalidSuper =
super is called in invalid context
Class.new(RimlError)
- ClassNotFound =
Class.new(RimlError)
- ClassRedefinitionError =
Class.new(RimlError)
Class Attribute Summary collapse
-
.debug ⇒ Object
Returns the value of attribute debug.
-
.warnings ⇒ Object
Returns the value of attribute warnings.
Class Method Summary collapse
-
.check_syntax(input) ⇒ Object
checks syntax of ‘input` (String).
- .check_syntax_files(*filenames) ⇒ Object
- .clear_caches ⇒ Object
- .compile(input, options = {}) ⇒ Object
-
.compile_files(*filenames) ⇒ Object
expects ‘filenames` (String) arguments, to be readable files.
-
.config ⇒ Object
OpenStruct|nil.
-
.config=(config) ⇒ Object
possible values: OpenStruct|nil.
-
.do_compile(input, parser = Parser.new, compiler = Compiler.new, filename_options = {}) ⇒ Object
compile AST (Nodes), tokens (Array), code (String) or object that returns String from :read to output code (String).
- .include_cache ⇒ Object
- .include_path ⇒ Object
- .include_path=(path, force_cache_bust = false) ⇒ Object
-
.lex(code) ⇒ Object
lex code (String) into tokens (Array).
-
.parse(input, ast_rewriter = AST_Rewriter.new, filename = nil) ⇒ Object
parse tokens (Array) or code (String) into AST (Nodes).
- .path_cache ⇒ Object
- .rewritten_ast_cache ⇒ Object
- .source_path ⇒ Object
- .source_path=(path, force_cache_bust = false) ⇒ Object
- .warn(warning) ⇒ Object
-
.with_file_rollback(&block) ⇒ Object
if error is thrown, all files that were created will be rolled back to their previous state.
Class Attribute Details
.debug ⇒ Object
Returns the value of attribute debug.
228 229 230 |
# File 'lib/riml.rb', line 228 def debug @debug end |
.warnings ⇒ Object
Returns the value of attribute warnings.
228 229 230 |
# File 'lib/riml.rb', line 228 def warnings @warnings end |
Class Method Details
.check_syntax(input) ⇒ Object
checks syntax of ‘input` (String). lexes + parses without going through AST rewriting or compilation
164 165 166 167 168 |
# File 'lib/riml.rb', line 164 def self.check_syntax(input) raise ArgumentError.new(input) unless input.is_a?(String) parse(input, nil) true end |
.check_syntax_files(*filenames) ⇒ Object
170 171 172 173 174 175 |
# File 'lib/riml.rb', line 170 def self.check_syntax_files(*filenames) filenames.each do |fname| File.open(fname) {|f| check_syntax(f.read)} end true end |
.clear_caches ⇒ Object
212 213 214 215 216 217 |
# File 'lib/riml.rb', line 212 def self.clear_caches @include_cache.clear @path_cache.clear @rewritten_ast_cache.clear Parser.ast_cache.clear end |
.compile(input, options = {}) ⇒ Object
53 54 55 56 57 58 59 60 61 62 |
# File 'lib/riml.rb', line 53 def self.compile(input, = {}) = Hash[.select(&EXTRACT_PARSE_OPTIONS)] = Hash[.select(&EXTRACT_COMPILE_OPTIONS)] parser = Parser.new parser. = DEFAULT_PARSE_OPTIONS.merge() compiler = Compiler.new compiler. = DEFAULT_COMPILE_OPTIONS.merge() = Hash[.select(&EXTRACT_FILENAME_OPTIONS)] do_compile(input, parser, compiler, ) end |
.compile_files(*filenames) ⇒ Object
expects ‘filenames` (String) arguments, to be readable files. Optional options (Hash) as last argument.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/riml.rb', line 111 def self.compile_files(*filenames) filenames = filenames.dup parser, compiler = Parser.new, Compiler.new # extract parser and compiler options from last argument, or use default # options if filenames.last.is_a?(Hash) = filenames.pop = Hash[.select(&EXTRACT_COMPILE_FILES_OPTIONS)] = Hash[.select(&EXTRACT_PARSE_OPTIONS)] compiler. = DEFAULT_COMPILE_FILES_OPTIONS.merge() parser. = DEFAULT_PARSE_OPTIONS.merge() else compiler. = DEFAULT_COMPILE_FILES_OPTIONS.dup parser. = DEFAULT_PARSE_OPTIONS.dup end filenames.uniq! # compile files using one thread per file, max 4 threads at once if filenames.size > 1 threads = [] with_file_rollback do while filenames.any? to_compile = filenames.shift(4) to_compile.each do |fname| _parser, _compiler = Parser.new, Compiler.new _compiler. = compiler..dup _parser. = parser..dup threads << Thread.new do f = File.open(fname) # `do_compile` will close file handle do_compile(f, _parser, _compiler, :commandline_filename => fname) end end threads.each(&:join) threads.clear end end elsif filenames.size == 1 fname = filenames.first f = File.open(fname) # `do_compile` will close file handle with_file_rollback { do_compile(f, parser, compiler, :commandline_filename => fname) } else raise ArgumentError, "need filenames to compile" end true ensure flush_warnings end |
.config ⇒ Object
Returns OpenStruct|nil.
234 235 236 |
# File 'lib/riml.rb', line 234 def self.config @config end |
.config=(config) ⇒ Object
possible values: OpenStruct|nil
239 240 241 242 243 244 |
# File 'lib/riml.rb', line 239 def self.config=(config) unless config.nil? || OpenStruct === config raise ArgumentError, "config must be OpenStruct or NilClass, is #{config.class}" end @config = config end |
.do_compile(input, parser = Parser.new, compiler = Compiler.new, filename_options = {}) ⇒ Object
compile AST (Nodes), tokens (Array), code (String) or object that returns String from :read to output code (String). Writes file(s) if ‘input` is a File.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/riml.rb', line 67 def self.do_compile(input, parser = Parser.new, compiler = Compiler.new, = {}) if input.is_a?(Nodes) nodes = input elsif input.is_a?(String) || input.is_a?(Array) nodes = parser.parse(input) elsif input.respond_to?(:read) source = input.read path = input.respond_to?(:path) ? input.path : nil nodes = parser.parse(source, parser.ast_rewriter || AST_Rewriter.new, path) else raise ArgumentError, "input must be one of AST (Nodes), tokens (Array), " \ "code (String) or respond_to?(:read), is #{input.inspect}" end compiler.parser = parser # This is to avoid cases where the file we're compiling from the # commandline gets recompiled but put in a different location because # it's also sourced, and `Riml.source_path` is set to a non-default value. if input.is_a?(File) pathname = Pathname.new(input.path) full_path = if pathname.absolute? pathname.to_s else File.(input.path, compiler.output_dir || Dir.getwd) end compiler.sourced_files_compiled << full_path end output = compiler.compile(nodes) if input.is_a?(File) write_file(compiler, output, input.path, ) else output end ensure input.close if input.is_a?(File) process_compile_queue!(compiler) end |
.include_cache ⇒ Object
195 196 197 |
# File 'lib/riml.rb', line 195 def self.include_cache @include_cache end |
.include_path ⇒ Object
184 185 186 |
# File 'lib/riml.rb', line 184 def self.include_path get_path(:include_path) end |
.include_path=(path, force_cache_bust = false) ⇒ Object
187 188 189 |
# File 'lib/riml.rb', line 187 def self.include_path=(path, force_cache_bust = false) set_path(:include_path, path, force_cache_bust) end |
.lex(code) ⇒ Object
lex code (String) into tokens (Array)
40 41 42 |
# File 'lib/riml.rb', line 40 def self.lex(code) Lexer.new(code).tokenize end |
.parse(input, ast_rewriter = AST_Rewriter.new, filename = nil) ⇒ Object
parse tokens (Array) or code (String) into AST (Nodes)
45 46 47 48 49 50 51 |
# File 'lib/riml.rb', line 45 def self.parse(input, ast_rewriter = AST_Rewriter.new, filename = nil) unless input.is_a?(Array) || input.is_a?(String) raise ArgumentError, "input must be tokens (Array) or code (String), " \ "is #{input.inspect}" end Parser.new.parse(input, ast_rewriter, filename) end |
.path_cache ⇒ Object
202 203 204 |
# File 'lib/riml.rb', line 202 def self.path_cache @path_cache end |
.rewritten_ast_cache ⇒ Object
207 208 209 |
# File 'lib/riml.rb', line 207 def self.rewritten_ast_cache @rewritten_ast_cache end |
.source_path ⇒ Object
177 178 179 |
# File 'lib/riml.rb', line 177 def self.source_path get_path(:source_path) end |
.source_path=(path, force_cache_bust = false) ⇒ Object
180 181 182 |
# File 'lib/riml.rb', line 180 def self.source_path=(path, force_cache_bust = false) set_path(:source_path, path, force_cache_bust) end |
.warn(warning) ⇒ Object
191 192 193 |
# File 'lib/riml.rb', line 191 def self.warn(warning) warning_buffer << warning end |
.with_file_rollback(&block) ⇒ Object
if error is thrown, all files that were created will be rolled back to their previous state. If the file existed previously, it will be the same as it was. If the file didn’t exist, it will be removed if it was created.
223 224 225 |
# File 'lib/riml.rb', line 223 def self.with_file_rollback(&block) FileRollback.guard(&block) end |