summaryrefslogtreecommitdiff
path: root/ext/ripper/lib
Commit message (Collapse)AuthorAgeFilesLines
* [Bug #19399] Parsing invalid heredoc inside block parameterNobuyoshi Nakada2023-02-021-1/+1
| | | | | Although this is of course invalid as Ruby code, allow to just parse and tokenize.
* ext/ripper/lib/ripper/lexer.rb: Do not deprecate Ripper::Lexer::State#[]Yusuke Endoh2021-12-091-14/+11
| | | | | | | | | | | The old code of IRB still uses this method. The warning is noisy on rails console. In principle, Ruby 3.1 deprecates nothing, so let's avoid the deprecation for the while. I think It is not so hard to continue to maintain it as it is a trivial shim. https://github.com/ruby/ruby/pull/5093
* Define Ripper::Lexer::Elem#to_sNobuyoshi Nakada2021-12-021-0/+2
| | | | | | Alias `#inspect` as `#to_s` also in the new `Ripper::Lexer::Elem` class, so that `puts Ripper::Lexer.new(code).scan` shows the attributes.
* Deprecate `Lexer::Elem#[]` and `Lexer::State#[]`schneems2021-12-021-0/+31
| | | | | | | Discussed in https://github.com/ruby/ruby/pull/5093#issuecomment-964426481. > it would be enough to mimic only [] for almost all cases This adds back the `Lexer::Elem#[]` and `Lexer::State#[]` and adds deprecation warnings for them.
* Only iterate Lexer heredoc arraysschneems2021-12-021-10/+12
| | | | The last element in the `@buf` may be either an array or an `Elem`. In the case it is an `Elem` we iterate over every element, when we do not need to. This check guards that case by ensuring that we only iterate over an array of elements.
* ~1.10x faster Change Ripper.lex structs to classesschneems2021-12-021-8/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ## Concept I am proposing we replace the Struct implementation of data structures inside of ripper with real classes. This will improve performance and the implementation is not meaningfully more complicated. ## Example Struct versus class comparison: ```ruby Elem = Struct.new(:pos, :event, :tok, :state, :message) do def initialize(pos, event, tok, state, message = nil) super(pos, event, tok, State.new(state), message) end # ... def to_a a = super a.pop unless a.empty? a end end class ElemClass attr_accessor :pos, :event, :tok, :state, :message def initialize(pos, event, tok, state, message = nil) @pos = pos @event = event @tok = tok @state = State.new(state) @message = message end def to_a if @message [@pos, @event, @tok, @state, @message] else [@pos, @event, @tok, @state] end end end # stub state class creation for now class State; def initialize(val); end; end ``` ## MicroBenchmark creation ```ruby require 'benchmark/ips' require 'ripper' pos = [1, 2] event = :on_nl tok = "\n".freeze state = Ripper::EXPR_BEG Benchmark.ips do |x| x.report("struct") { Elem.new(pos, event, tok, state) } x.report("class ") { ElemClass.new(pos, event, tok, state) } x.compare! end; nil ``` Gives ~1.2x faster creation: ``` Warming up -------------------------------------- struct 263.983k i/100ms class 303.367k i/100ms Calculating ------------------------------------- struct 2.638M (± 5.9%) i/s - 13.199M in 5.023460s class 3.171M (± 4.6%) i/s - 16.078M in 5.082369s Comparison: class : 3170690.2 i/s struct: 2638493.5 i/s - 1.20x (± 0.00) slower ``` ## MicroBenchmark `to_a` (Called by Ripper.lex for every element) ```ruby require 'benchmark/ips' require 'ripper' pos = [1, 2] event = :on_nl tok = "\n".freeze state = Ripper::EXPR_BEG struct = Elem.new(pos, event, tok, state) from_class = ElemClass.new(pos, event, tok, state) Benchmark.ips do |x| x.report("struct") { struct.to_a } x.report("class ") { from_class.to_a } x.compare! end; nil ``` Gives 1.46x faster `to_a`: ``` Warming up -------------------------------------- struct 612.094k i/100ms class 893.233k i/100ms Calculating ------------------------------------- struct 6.121M (± 5.4%) i/s - 30.605M in 5.015851s class 8.931M (± 7.9%) i/s - 44.662M in 5.039733s Comparison: class : 8930619.0 i/s struct: 6121358.9 i/s - 1.46x (± 0.00) slower ``` ## MicroBenchmark data access ```ruby require 'benchmark/ips' require 'ripper' pos = [1, 2] event = :on_nl tok = "\n".freeze state = Ripper::EXPR_BEG struct = Elem.new(pos, event, tok, state) from_class = ElemClass.new(pos, event, tok, state) Benchmark.ips do |x| x.report("struct") { struct.pos[1] } x.report("class ") { from_class.pos[1] } x.compare! end; nil ``` Gives ~1.17x faster data access: ``` Warming up -------------------------------------- struct 1.694M i/100ms class 1.868M i/100ms Calculating ------------------------------------- struct 16.149M (± 6.8%) i/s - 81.318M in 5.060633s class 18.886M (± 2.9%) i/s - 95.262M in 5.048359s Comparison: class : 18885669.6 i/s struct: 16149255.8 i/s - 1.17x (± 0.00) slower ``` ## Full benchmark integration of this inside of Ripper.lex Inside of this repo with this commit ``` $ cd ext/ripper $ make $ cat test.rb file = File.join(__dir__, "../../array.rb") source = File.read(file) bench = Benchmark.measure do 10_000.times.each do Ripper.lex(source) end end puts bench ``` Then execute with and without this change 50 times: ``` rm new.txt rm old.txt for i in {0..50} do `ruby -Ilib -rripper -rbenchmark ./test.rb >> new.txt` `ruby -rripper -rbenchmark ./test.rb >> old.txt` done ``` I used derailed benchmarks internals to compare the results: ``` dir = Pathname(".") branch_info = {} branch_info["old"] = { desc: "Struct lex", time: Time.now, file: dir.join("old.txt"), name: "old" } branch_info["new"] = { desc: "Class lex", time: Time.now, file: dir.join("new.txt"), name: "new" } stats = DerailedBenchmarks::StatsFromDir.new(branch_info) stats.call.banner ``` Which gave us: ``` ❤️ ❤️ ❤️ (Statistically Significant) ❤️ ❤️ ❤️ [new] (3.3139 seconds) "Class lex" ref: "new" FASTER 🚀🚀🚀 by: 1.1046x [older/newer] 9.4700% [(older - newer) / older * 100] [old] (3.6606 seconds) "Struct lex" ref: "old" Iterations per sample: Samples: 51 Test type: Kolmogorov Smirnov Confidence level: 99.0 % Is significant? (max > critical): true D critical: 0.30049534876137013 D max: 0.9607843137254902 Histograms (time ranges are in seconds): [new] description: [old] description: "Class lex" "Struct lex" ┌ ┐ ┌ ┐ [3.0, 3.3) ┤▇ 1 [3.0, 3.3) ┤ 0 [3.3, 3.6) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 47 [3.3, 3.6) ┤ 0 [3.5, 3.8) ┤▇▇ 2 [3.5, 3.8) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 46 [3.8, 4.1) ┤▇ 1 [3.8, 4.1) ┤▇▇▇ 4 [4.0, 4.3) ┤ 0 [4.0, 4.3) ┤ 0 [4.3, 4.6) ┤ 0 [4.3, 4.6) ┤▇ 1 └ ┘ └ ┘ # of runs in range # of runs in range ``` To sum this up, the "new" version of this code (using real classes instead of structs) is 10% faster across 50 runs with a statistical significance confidence level of 99%. Histograms are for visual checksum.
* ripper: fix a bug of Ripper::Lexer with syntax error and heredoc [Bug #17644]Shugo Maeda2021-02-191-1/+1
|
* Fix Ripper with heredoc.manga_osyo2021-01-171-0/+1
|
* ripper: call #pretty_print on also `state`Nobuyoshi Nakada2021-01-041-1/+1
|
* ripper: fix `#tok` on some error events [Bug 17345]Nobuhiro IMAI2020-12-191-4/+9
| | | | sorting alias target by event arity, and setup suitable `Elem` for error.
* Ripper: Refined error callbacks [Bug #17345]Nobuyoshi Nakada2020-12-151-2/+2
|
* ripper: return pushed new token instead of the token listNobuyoshi Nakada2020-12-151-1/+3
|
* Store all kinds of syntax errors [Bug #17345]Nobuyoshi Nakada2020-11-261-1/+3
|
* [DOC] Ripper.{lex,tokenize} now always return full tokens. [ci skip]Nobuhiro IMAI2020-11-201-4/+2
|
* [Feature #17276] Moved raise_errors support to Ripper::Lexer#parseNobuyoshi Nakada2020-11-201-35/+19
|
* Ripper.{lex,tokenize} return full tokens even if syntax errorNobuhiro IMAI2020-11-201-0/+8
| | | | yet another implements [Feature #17276]
* Update documentation for Ripper.{lex,tokenize,sexp,sexp_raw} [ci skip]Jeremy Evans2020-11-172-0/+17
|
* Support raise_errors keyword for Ripper.{lex,tokenize,sexp,sexp_raw}Jeremy Evans2020-11-172-8/+43
| | | Implements [Feature #17276]
* Update comment of Ripper.lexYuichiro Kaneko2019-11-131-10/+10
| | | | This is follow up of 1f7cb4bee9.
* [DOC] Update output of Ripper.sexp [ci skip]Kazuhiro NISHIYAMA2019-09-071-1/+1
|
* ext/ripper/lib/ripper/lexer.rb: Consistently use `Array#push`Yusuke Endoh2019-08-071-1/+1
| | | | instead of <<. All the other callsites use `push`.
* ext/ripper/lib/ripper/lexer.rb: fix a wrong delegationYusuke Endoh2019-08-071-1/+1
| | | | The target method name is a typo.
* Show the parser states in pretty_print tooNobuyoshi Nakada2019-06-271-0/+2
|
* Ripper::Lexer: fallback parse error token to the previous oneNobuyoshi Nakada2019-06-121-1/+11
|
* Include stack elements left after errorsNobuyoshi Nakada2019-05-301-1/+1
|
* ripper: Ripper::Lexer#scanNobuyoshi Nakada2019-05-291-4/+29
| | | | | | * ext/ripper/lib/ripper/lexer.rb (Ripper::Lexer#scan): parses the code and returns the result elements including errors. [EXPERIMENTAL]
* Fix typos in Ripper::Lexer#inspect and Ripper::Lexer#pretty_printNobuyoshi Nakada2019-05-281-2/+2
|
* Added #inspect and #pretty_inspect to Ripper::Lexer::ElemNobuyoshi Nakada2019-05-271-1/+16
|
* Ripper: no documents of fallback methodsNobuyoshi Nakada2019-05-221-0/+2
|
* Add ignored_sp eventnobu2019-03-091-0/+6
| | | | | | | | * ext/ripper/lib/ripper/lexer.rb (Ripper::Lexer): add ignored_sp event which will be fired from Ripper::Lexer#on_heredoc_dedent method. [ruby-core:91727] [Bug #15648] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67200 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* Use delete_prefix instead of `sub(/\Afixed-pattern/, '')`kazu2018-12-041-2/+2
| | | | git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66189 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* Fix FrozenError on `Ripper.slice`k0kubun2018-03-131-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Currently `Ripper.slice` raises a FrozenError ```ruby require 'ripper' p Ripper.slice('foo', 'ident') ``` ``` /path/to/g/lib/ruby/2.6.0/ripper/lexer.rb:193:in `concat': can't modify frozen String (FrozenError) from /path/to/g/lib/ruby/2.6.0/ripper/lexer.rb:193:in `block in compile' from /path/to/g/lib/ruby/2.6.0/ripper/lexer.rb:190:in `scan' from /path/to/g/lib/ruby/2.6.0/ripper/lexer.rb:190:in `compile' from /path/to/g/lib/ruby/2.6.0/ripper/lexer.rb:169:in `initialize' from /path/to/g/lib/ruby/2.6.0/ripper/lexer.rb:151:in `new' from /path/to/g/lib/ruby/2.6.0/ripper/lexer.rb:151:in `token_match' from /path/to/g/lib/ruby/2.6.0/ripper/lexer.rb:144:in `slice' from /tmp/tmp.kb4cnhvum2/test.rb:2:in `<main>' ``` This patch will fix the problem. [Fix GH-1837] From: Masataka Pocke Kuwabara <kuwabara@pocke.me> git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62743 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* Ripper::Lexer bit predicatesnobu2017-12-131-0/+3
| | | | | | | | * ext/ripper/lib/ripper/lexer.rb (Ripper::Lexer): added allbits?, anybits? and nobits? methods, as well as Integer. a patch by aycabta. [Feature #14170] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61205 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lexer.rb: Ripper::Lexer::Statenobu2017-11-051-27/+13
| | | | | | | | | | * ext/ripper/lib/ripper/lexer.rb (Ripper::Lexer::State): wrapper of lex_state values. * parse.y (rb_parser_lex_state_name): return shared strings. lex state combinations are very restricted. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60665 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lexer.rb: no dedent strings in middlenobu2017-10-191-1/+1
| | | | | | | | * ext/ripper/lib/ripper/lexer.rb (on_heredoc_dedent): dedent only strings at the beginning, not strings in middle. [ruby-core:83343] [Bug #14027] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60212 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* ripper/lexer.rb: remove double quotesnobu2017-09-301-2/+1
| | | | git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60069 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* fix up r59949nobu2017-09-201-0/+2
| | | | | | | * ext/ripper/lib/ripper/lexer.rb (List#inspect): splat self data to local variables same as members of Elem. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59972 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* parse.y: ripper_lex_state_namenobu2017-09-181-0/+27
| | | | | | | | | | * parse.y (ripper_lex_state_name): represent lex_state as OR-ed form. * ext/ripper/lib/ripper/lexer.rb (Ripper::Lexer::Elem#to_a): lex_state for inspection. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59949 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* ripper: add states of scannernobu2017-09-142-17/+26
| | | | | | | | | | | * parse.y (ripper_state): add states of scanner to tokens from Ripper.lex and Ripper::Filter#on_*. based on the patch by aycabta (Code Ahss) at [ruby-core:81789]. [Feature #13686] * ext/ripper/tools/preproc.rb (prelude, usercode): generate EXPR_* constants from enums. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59896 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* ripper.rb: fix License format [ci skip]nobu2017-08-151-4/+4
| | | | | | | | * ext/ripper/lib/ripper.rb: [DOC] fix format of the License description and the author. patched by aycabta (Code Ahss) at [ruby-core:82376]. [Bug #13813] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59597 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lexer.rb: ignore dedented spacenobu2017-07-061-0/+5
| | | | | | | | * ext/ripper/lib/ripper/lexer.rb (on_heredoc_dedent): replace an empty string content because of dedentation with :on_ignored_sp. an empty token makes the sorted order unstable. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59269 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* parse.y: f_margs parser eventsnobu2017-07-011-0/+12
| | | | | | | * parse.y (f_margs): implemented parser events for massign formal arguments. [ruby-core:81848] [Bug #13701] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59246 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* ripper/lexer.rb: nested indented heredocnobu2017-05-061-1/+8
| | | | | | | | | * ext/ripper/lib/ripper/lexer.rb (on_heredoc_dedent): insert stripped leading spaces as `on_ignored_sp` elements, so that the original source can be reconsructed. [ruby-core:80977] [Bug #13536] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58584 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* ripper/lexer.rb: nested indented heredocnobu2017-05-021-1/+1
| | | | | | | | * ext/ripper/lib/ripper/lexer.rb (on_heredoc_dedent): fix for nested indedented here documents, where `Elem`s are nested too. [ruby-core:80977] [Bug #13536] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58545 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* {ext,test}/ripper: Specify frozen_string_literal: true.kazu2017-02-055-5/+5
| | | | git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57538 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* Fix Ripper.lex error in dedenting squiggly heredocnobu2016-02-021-1/+1
| | | | | | | | * ext/ripper/lib/ripper/lexer.rb (on_heredoc_dedent): Fix Ripper.lex error in dedenting squiggly heredoc. heredoc tree is also an array of Elem in the outer tree. [Fix GH-1234] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53722 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* handle ext/ as r53141naruse2015-12-165-0/+5
| | | | | | | | g -L frozen_string_literal ext/**/*.rb|xargs ruby -Ka -e'ARGV.each{|fn|puts fn;open(fn,"r+"){|f|s=f.read.sub(/\A(#!.*\n)?(#.*coding.*\n)?/,"\\&# frozen_string_literal: false\n");f.rewind;f.write s}}' git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53143 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* parse.y: indented hereocnobu2015-12-072-6/+75
| | | | | | * parse.y: add heredoc <<~ syntax. [Feature #9098] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52916 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* ripper/lexer.rb: dispatch aliasnobu2015-11-281-5/+5
| | | | | | | * ext/ripper/lib/ripper/lexer.rb: alias same methods instead of eval for each events. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52776 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* ripper/core.rb: share handlersnobu2015-11-281-35/+21
| | | | | | | | * ext/ripper/lib/ripper/sexp.rb (SexpBuilderPP): share scanner event handlers and most of parser event handlers with SexpBuilder. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52775 b2dd03c8-39d4-4d8f-98ff-823fe69b080e