class Prism::Translation::Parser
then translate.
the parser gem, and overrides the parse* methods to parse with prism and
whitequark/parser gem’s syntax tree. It inherits from the base parser for
This class is the entry-point for converting a prism syntax tree into the
def build_ast(program, offset_cache)
def build_ast(program, offset_cache) program.accept(Compiler.new(self, offset_cache)) end
def build_comments(comments, offset_cache)
def build_comments(comments, offset_cache) comments.map do |comment| ::Parser::Source::Comment.new(build_range(comment.location, offset_cache)) end end
def build_offset_cache(source)
translator. We could make this significantly faster by using a
has any multi-byte characters, this can tank the performance of the
This is a good opportunity for some optimizations. If the source file
as a cache for the conversion.
just use the offset directly. Otherwise, we build a hash that functions
If the bytesize of the source is the same as the length, then we can
build the parser gem AST.
offsets in characters. We need to handle this conversion in order to
Prism deals with offsets in bytes, while the parser gem deals with
def build_offset_cache(source) if source.bytesize == source.length -> (offset) { offset } else Hash.new do |hash, offset| hash[offset] = source.byteslice(0, offset).length end end end
def build_range(location, offset_cache)
def build_range(location, offset_cache) ::Parser::Source::Range.new( source_buffer, offset_cache[location.start_offset], offset_cache[location.end_offset] ) end
def build_tokens(tokens, offset_cache)
def build_tokens(tokens, offset_cache) Lexer.new(source_buffer, tokens.map(&:first), offset_cache).to_a end
def default_encoding
def default_encoding Encoding::UTF_8 end
def parse(source_buffer)
def parse(source_buffer) @source_buffer = source_buffer source = source_buffer.source offset_cache = build_offset_cache(source) result = unwrap(Prism.parse(source, filepath: source_buffer.name), offset_cache) build_ast(result.value, offset_cache) ensure @source_buffer = nil end
def parse_with_comments(source_buffer)
def parse_with_comments(source_buffer) @source_buffer = source_buffer source = source_buffer.source offset_cache = build_offset_cache(source) result = unwrap(Prism.parse(source, filepath: source_buffer.name), offset_cache) [ build_ast(result.value, offset_cache), build_comments(result.comments, offset_cache) ] ensure @source_buffer = nil end
def tokenize(source_buffer, recover = false)
Parses a source buffer and returns the AST, the source code comments,
def tokenize(source_buffer, recover = false) @source_buffer = source_buffer source = source_buffer.source offset_cache = build_offset_cache(source) result = begin unwrap(Prism.parse_lex(source, filepath: source_buffer.name), offset_cache) rescue ::Parser::SyntaxError raise if !recover end program, tokens = result.value ast = build_ast(program, offset_cache) if result.success? [ ast, build_comments(result.comments, offset_cache), build_tokens(tokens, offset_cache) ] ensure @source_buffer = nil end
def try_declare_numparam(node)
Since prism resolves num params for us, we don't need to support this
def try_declare_numparam(node) node.children[0].match?(/\A_[1-9]\z/) end
def unwrap(result, offset_cache)
If there was a error generated during the parse, then raise an
def unwrap(result, offset_cache) result.errors.each do |error| next unless valid_error?(error) location = build_range(error.location, offset_cache) diagnostics.process(Diagnostic.new(error.message, location)) end result end
def valid_error?(error)
This is a hook to allow consumers to disable some errors if they don't
def valid_error?(error) true end
def version # :nodoc:
def version # :nodoc: 34 end
def yyerror # :nodoc:
def yyerror # :nodoc: end