class Interscript::Interpreter::Stage
Public Class Methods
new(map, str)
click to toggle source
# File lib/interscript/interpreter.rb, line 73 def initialize(map, str) @str = str @map = map end
Public Instance Methods
build_item(i, target=nil, doc=@map)
click to toggle source
# File lib/interscript/interpreter.rb, line 171 def build_item i, target=nil, doc=@map i = i.nth_string if %i[str parstr].include? target i = Interscript::Node::Item.try_convert(i) target = :par if target == :parstr out = case i when Interscript::Node::Item::Alias if i.map d = doc.dep_aliases[i.map].document a = d.imported_aliases[i.name] raise ArgumentError, "Alias #{i.name} of #{i.stage.map} not found" unless a build_item(a.data, target, d) elsif Interscript::Stdlib::ALIASES.include?(i.name) if target != :re && Interscript::Stdlib.re_only_alias?(i.name) raise ArgumentError, "Can't use #{i.name} in a #{target} context" end Interscript::Stdlib::ALIASES[i.name] else a = doc.imported_aliases[i.name] raise ArgumentError, "Alias #{i.name} not found" unless a build_item(a.data, target, doc) end when Interscript::Node::Item::String if [:str, :par].include? target i.data else#if target == :re Regexp.escape(i.data) end when Interscript::Node::Item::Group if target == :par i.children.map do |j| build_item(j, target, doc) end.reduce([""]) do |j,k| Array(j).product(Array(k)).map(&:join) end else i.children.map { |j| build_item(j, target, doc) }.join end when Interscript::Node::Item::CaptureGroup if target == :par raise ArgumentError, "Can't use a CaptureGroup in a #{target} context" end "(" + build_item(i.data, target, doc) + ")" when Interscript::Node::Item::Maybe, Interscript::Node::Item::MaybeSome, Interscript::Node::Item::Some resuffix = { Interscript::Node::Item::Maybe => "?" , Interscript::Node::Item::Some => "+" , Interscript::Node::Item::MaybeSome => "*" }[i.class] if target == :par raise ArgumentError, "Can't use a MaybeSome in a #{target} context" end if Interscript::Node::Item::String === i.data && i.data.data.length != 1 "(?:" + build_item(i.data, target, doc) + ")" + resuffix else build_item(i.data, target, doc) + resuffix end when Interscript::Node::Item::CaptureRef if target == :par raise ArgumentError, "Can't use CaptureRef in parallel mode" end "\\#{i.id}" when Interscript::Node::Item::Any if target == :str # We may never reach this point raise ArgumentError, "Can't use Any in a string context" elsif target == :par i.data.map(&:data) elsif target == :re case i.value when Array data = i.data.map { |j| build_item(j, target, doc) } "(?:"+data.join("|")+")" when String "[#{Regexp.escape(i.value)}]" when Range "[#{Regexp.escape(i.value.first)}-#{Regexp.escape(i.value.last)}]" end end end end
build_regexp(r)
click to toggle source
# File lib/interscript/interpreter.rb, line 155 def build_regexp(r) from = build_item(r.from, :re) before = build_item(r.before, :re) if r.before after = build_item(r.after, :re) if r.after not_before = build_item(r.not_before, :re) if r.not_before not_after = build_item(r.not_after, :re) if r.not_after re = "" re += "(?<=#{before})" if before re += "(?<!#{not_before})" if not_before re += from re += "(?!#{not_after})" if not_after re += "(?=#{after})" if after re end
execute_rule(r)
click to toggle source
# File lib/interscript/interpreter.rb, line 78 def execute_rule r return if r.reverse_run == true case r when Interscript::Node::Group::Parallel if r.cached_tree @str = Interscript::Stdlib.parallel_replace_tree(@str, r.cached_tree) elsif r.subs_regexp && r.subs_replacements if $DEBUG_RE @str = Interscript::Stdlib.parallel_regexp_gsub_debug(@str, r.subs_regexp, r.subs_replacements) else @str = Interscript::Stdlib.parallel_regexp_gsub(@str, r.subs_regexp, r.subs_replacements) end else begin # Try to build a tree subs_array = [] r.children.each do |i| raise ArgumentError, "Can't parallelize #{i.class}" unless Interscript::Node::Rule::Sub === i raise ArgumentError, "Can't parallelize rules with :before" if i.before raise ArgumentError, "Can't parallelize rules with :after" if i.after raise ArgumentError, "Can't parallelize rules with :not_before" if i.not_before raise ArgumentError, "Can't parallelize rules with :not_after" if i.not_after next if i.reverse_run == true subs_array << [build_item(i.from, :par), build_item(i.to, :parstr)] end tree = Interscript::Stdlib.parallel_replace_compile_tree(subs_array) #.sort_by{|k,v| -k.length}) @str = Interscript::Stdlib.parallel_replace_tree(@str, tree) r.cached_tree = tree # $using_tree = true rescue # $using_tree = false # Otherwise let's build a megaregexp subs_array = [] Interscript::Stdlib.deterministic_sort_by_max_length(r.children).each do |i| # rule.from.max_length gives somewhat better test results, why is that raise ArgumentError, "Can't parallelize #{i.class}" unless Interscript::Node::Rule::Sub === i next if i.reverse_run == true subs_array << [build_regexp(i), build_item(i.to, :parstr)] end r.subs_regexp = Interscript::Stdlib.parallel_regexp_compile(subs_array) r.subs_replacements = subs_array.map(&:last) if $DEBUG_RE # puts subs_array.inspect $subs_array = subs_array @str = Interscript::Stdlib.parallel_regexp_gsub_debug(@str, r.subs_regexp, r.subs_replacements) else @str = Interscript::Stdlib.parallel_regexp_gsub(@str, r.subs_regexp, r.subs_replacements) end end end when Interscript::Node::Group r.children.each do |t| execute_rule(t) end when Interscript::Node::Rule::Sub if r.to == :upcase @str = @str.gsub(Regexp.new(build_regexp(r)), &:upcase) elsif r.to == :downcase @str = @str.gsub(Regexp.new(build_regexp(r)), &:downcase) else @str = @str.gsub(Regexp.new(build_regexp(r)), build_item(r.to, :str)) end when Interscript::Node::Rule::Funcall @str = Interscript::Stdlib::Functions.public_send(r.name, @str, **r.kwargs) when Interscript::Node::Rule::Run if r.stage.map doc = @map.dep_aliases[r.stage.map].document stage = doc.imported_stages[r.stage.name] @str = Stage.new(doc, @str).execute_rule(stage) else stage = @map.imported_stages[r.stage.name] @str = Stage.new(@map, @str).execute_rule(stage) end end @str end