diff --git a/.gitignore b/.gitignore index 2ee3c973..9a02ca89 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,11 @@ ext/redcloth_scan/*.so ext/redcloth_scan/*.jar ext/redcloth_scan/*.class ext/redcloth_scan/*.java +ext/redcloth_scan/redcloth_*.rb lib/*.bundle lib/*.so lib/*.jar +lib/redcloth_scan.rb doc/rdoc/* tmp/* pkg/* diff --git a/CHANGELOG b/CHANGELOG index dd396f61..043a2aa2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ === Edge +* Added a pure-ruby version of the parser for times when you can't compile the C or Java extensions. You should avoid using it if at all possible because it is 32 times slower (and has some other problems, too)! [Jason Garber] + * Ignore spaces and tabs on blank lines between blocks. #120 [Jason Garber] * Allow HTML tags with quoted attributes to be inside link text. To do this, I had to remove the possibility that attributes in HTML tags could have spaces around the equals sign or unquoted attributes. This change also greatly expands the complexity of the state machine, so compilation takes a long time. Sorry. [Jason Garber] diff --git a/Manifest b/Manifest index d867f388..04808da8 100644 --- a/Manifest +++ b/Manifest @@ -6,15 +6,19 @@ ext/redcloth_scan/extconf.rb ext/redcloth_scan/redcloth.h ext/redcloth_scan/redcloth_attributes.c.rl ext/redcloth_scan/redcloth_attributes.java.rl +ext/redcloth_scan/redcloth_attributes.rb.rl ext/redcloth_scan/redcloth_attributes.rl ext/redcloth_scan/redcloth_common.c.rl ext/redcloth_scan/redcloth_common.java.rl +ext/redcloth_scan/redcloth_common.rb.rl ext/redcloth_scan/redcloth_common.rl ext/redcloth_scan/redcloth_inline.c.rl ext/redcloth_scan/redcloth_inline.java.rl +ext/redcloth_scan/redcloth_inline.rb.rl ext/redcloth_scan/redcloth_inline.rl ext/redcloth_scan/redcloth_scan.c.rl ext/redcloth_scan/redcloth_scan.java.rl +ext/redcloth_scan/redcloth_scan.rb.rl ext/redcloth_scan/redcloth_scan.rl extras/ragel_profiler.rb lib/case_sensitive_require/RedCloth.rb @@ -26,6 +30,7 @@ lib/redcloth/formatters/latex_entities.yml lib/redcloth/textile_doc.rb lib/redcloth/version.rb lib/redcloth.rb +lib/tasks/pureruby.rake Manifest Rakefile README diff --git a/Rakefile b/Rakefile index 7ef708a9..604bceee 100644 --- a/Rakefile +++ b/Rakefile @@ -2,12 +2,13 @@ require 'lib/redcloth/version' require 'rubygems' gem 'echoe', '>= 3.0.1' require 'echoe' +Dir["#{File.dirname(__FILE__)}/lib/tasks/*.rake"].sort.each { |ext| load(ext) } e = Echoe.new('RedCloth', RedCloth::VERSION.to_s) do |p| p.summary = RedCloth::DESCRIPTION p.author = "Jason Garber" p.email = 'redcloth-upwards@rubyforge.org' - p.clean_pattern += ['ext/redcloth_scan/**/*.{bundle,so,obj,pdb,lib,def,exp,c,o,xml,class,jar,java}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp,jar}', 'ext/redcloth_scan/Makefile'] + p.clean_pattern += ['ext/redcloth_scan/**/*.{bundle,so,obj,pdb,lib,def,exp,c,o,xml,class,jar,java}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp,jar}', 'ext/redcloth_scan/**/redcloth_*.rb', 'lib/redcloth_scan.rb', 'ext/redcloth_scan/Makefile'] p.url = "http://redcloth.org" p.project = "redcloth" p.rdoc_pattern = ['README', 'COPING', 'CHANGELOG', 'lib/**/*.rb', 'doc/**/*.rdoc'] @@ -20,10 +21,14 @@ e = Echoe.new('RedCloth', RedCloth::VERSION.to_s) do |p| p.platform = 'x86-mswin32-60' elsif Platform.java? p.platform = 'universal-java' + elsif RUBY_PLATFORM == 'pureruby' + p.platform = 'ruby' end if RUBY_PLATFORM =~ /mingw|mswin|java/ p.need_tar_gz = false + elsif RUBY_PLATFORM == 'pureruby' + p.need_gem = false else p.need_zip = true p.need_tar_gz = true @@ -36,6 +41,8 @@ e = Echoe.new('RedCloth', RedCloth::VERSION.to_s) do |p| self.files += ['lib/redcloth_scan.so'] when /java/ self.files += ['lib/redcloth_scan.jar'] + when 'pureruby' + self.files += ['lib/redcloth_scan.rb'] else self.files += %w[attributes inline scan].map {|f| "ext/redcloth_scan/redcloth_#{f}.c"} end @@ -45,7 +52,9 @@ e = Echoe.new('RedCloth', RedCloth::VERSION.to_s) do |p| end -#### Pre-compiled extensions for alternative platforms +def remove_other_platforms + Dir["lib/redcloth_scan.{bundle,so,jar,rb}"].each { |file| rm file } +end def move_extensions Dir["ext/**/*.{bundle,so,jar}"].each { |file| mv file, "lib/" } @@ -75,6 +84,7 @@ when /mingw/ ruby "-I. extconf.rb" system(PLATFORM =~ /mswin/ ? 'nmake' : 'make') end + remove_other_platforms move_extensions rm "#{ext}/rbconfig.rb" end @@ -86,9 +96,19 @@ when /java/ sources = FileList["#{ext}/**/*.java"].join(' ') sh "javac -target 1.5 -source 1.5 -d #{ext} #{java_classpath_arg} #{sources}" sh "jar cf lib/redcloth_scan.jar -C #{ext} ." + remove_other_platforms move_extensions end +when /pureruby/ + filename = "lib/redcloth_scan.rb" + file filename => FileList["#{ext}/redcloth_scan.rb", "#{ext}/redcloth_inline.rb", "#{ext}/redcloth_attributes.rb"] do |task| + + remove_other_platforms + sources = task.prerequisites.join(' ') + sh "cat #{sources} > #{filename}" + end + else filename = "#{ext}/redcloth_scan.#{Config::CONFIG['DLEXT']}" file filename => FileList["#{ext}/redcloth_scan.c", "#{ext}/redcloth_inline.c", "#{ext}/redcloth_attributes.c"] @@ -97,8 +117,21 @@ end task :compile => [filename] def ragel(target_file, source_file) - host_language = (target_file =~ /java$/) ? "J" : "C" - code_style = (host_language == "C") ? " -" + (@code_style || "T0") : "" + host_language = case target_file + when /java$/ + "J" + when /rb$/ + "R" + else + "C" + end + preferred_code_style = case host_language + when "R" + "F1" + else + "T0" + end + code_style = " -" + (@code_style || preferred_code_style) ensure_ragel_version(target_file) do sh %{ragel #{source_file} -#{host_language}#{code_style} -o #{target_file}} end @@ -129,23 +162,39 @@ file "#{ext}/RedclothAttributes.java" => ["#{ext}/redcloth_attributes.java.rl", ragel "#{ext}/RedclothAttributes.java", "#{ext}/redcloth_attributes.java.rl" end +# Ragel-generated pureruby files +file "#{ext}/redcloth_scan.rb" => ["#{ext}/redcloth_scan.rb.rl", "#{ext}/redcloth_scan.rl", "#{ext}/redcloth_common.rb.rl", "#{ext}/redcloth_common.rl"] do + ragel "#{ext}/redcloth_scan.rb", "#{ext}/redcloth_scan.rb.rl" +end +file "#{ext}/redcloth_inline.rb" => ["#{ext}/redcloth_inline.rb.rl", "#{ext}/redcloth_inline.rl", "#{ext}/redcloth_common.rb.rl", "#{ext}/redcloth_common.rl"] do + ragel "#{ext}/redcloth_inline.rb", "#{ext}/redcloth_inline.rb.rl" +end +file "#{ext}/redcloth_attributes.rb" => ["#{ext}/redcloth_attributes.rb.rl", "#{ext}/redcloth_attributes.rl", "#{ext}/redcloth_common.rb.rl", "#{ext}/redcloth_common.rl"] do + ragel "#{ext}/redcloth_attributes.rb", "#{ext}/redcloth_attributes.rb.rl" +end + #### Optimization +# C/Ruby code styles RAGEL_CODE_GENERATION_STYLES = { 'T0' => "Table driven FSM (default)", 'T1' => "Faster table driven FSM", 'F0' => "Flat table driven FSM", - 'F1' => "Faster flat table-driven FSM", + 'F1' => "Faster flat table-driven FSM" +} +# C only code styles +RAGEL_CODE_GENERATION_STYLES.merge!({ 'G0' => "Goto-driven FSM", 'G1' => "Faster goto-driven FSM", 'G2' => "Really fast goto-driven FSM" -} +}) if RUBY_PLATFORM !~ /pureruby/ desc "Find the fastest code generation style for Ragel" task :optimize do require 'extras/ragel_profiler' results = [] + RAGEL_CODE_GENERATION_STYLES.each do |style, name| @code_style = style profiler = RagelProfiler.new(style + " " + name) @@ -162,7 +211,7 @@ task :optimize do profiler.measure(:test) do Rake::Task['test'].invoke end - profiler.ext_size(ext_so) + profiler.ext_size(filename) end puts RagelProfiler.results diff --git a/ext/redcloth_scan/redcloth.h b/ext/redcloth_scan/redcloth.h index a66bc02f..7a6e75ae 100644 --- a/ext/redcloth_scan/redcloth.h +++ b/ext/redcloth_scan/redcloth.h @@ -51,6 +51,8 @@ VALUE red_pass_code(VALUE, VALUE, VALUE, ID); /* parser macros */ #define CLEAR_REGS() regs = rb_hash_new(); #define RESET_REG() reg = NULL +#define MARK() reg = p; +#define MARK_B() bck = p; #define CAT(H) rb_str_cat(H, ts, te-ts) #define CLEAR(H) H = STR_NEW2("") #define RSTRIP_BANG(H) rb_funcall(H, rb_intern("rstrip!"), 0) @@ -62,7 +64,7 @@ VALUE red_pass_code(VALUE, VALUE, VALUE, ID); #define PARSE_ATTR(A) red_parse_attr(self, regs, ID2SYM(rb_intern(A))) #define PARSE_LINK_ATTR(A) red_parse_link_attr(self, regs, ID2SYM(rb_intern(A))) #define PARSE_IMAGE_ATTR(A) red_parse_image_attr(self, regs, ID2SYM(rb_intern(A))) -#define PASS_CODE(H, A, T, O) rb_str_append(H, red_pass_code(self, regs, ID2SYM(rb_intern(A)), rb_intern(T))) +#define PASS_CODE(H, A, T) rb_str_append(H, red_pass_code(self, regs, ID2SYM(rb_intern(A)), rb_intern(T))) #define ADD_BLOCK() \ rb_str_append(html, red_block(self, regs, block, refs)); \ extend = Qnil; \ @@ -70,11 +72,11 @@ VALUE red_pass_code(VALUE, VALUE, VALUE, ID); CLEAR_REGS() #define ADD_EXTENDED_BLOCK() rb_str_append(html, red_block(self, regs, block, refs)); CLEAR(block); #define END_EXTENDED() extend = Qnil; CLEAR_REGS(); -#define IS_NOT_EXTENDED() NIL_P(extend) #define ADD_BLOCKCODE() rb_str_append(html, red_blockcode(self, regs, block)); CLEAR(block); CLEAR_REGS() #define ADD_EXTENDED_BLOCKCODE() rb_str_append(html, red_blockcode(self, regs, block)); CLEAR(block); #define ASET(T, V) rb_hash_aset(regs, ID2SYM(rb_intern(T)), STR_NEW2(V)); #define AINC(T) red_inc(regs, ID2SYM(rb_intern(T))); +#define INC(N) N++; #define SET_ATTRIBUTES() \ SET_ATTRIBUTE("class_buf", "class"); \ SET_ATTRIBUTE("id_buf", "id"); \ @@ -141,6 +143,9 @@ VALUE red_pass_code(VALUE, VALUE, VALUE, ID); #define STORE_LINK_ALIAS() \ rb_hash_aset(refs_found, rb_hash_aref(regs, ID2SYM(rb_intern("text"))), rb_hash_aref(regs, ID2SYM(rb_intern("href")))) #define CLEAR_LIST() list_layout = rb_ary_new() +#define SET_LIST_TYPE(T) list_type = T; +#define NEST() nest ++; +#define RESET_NEST() nest = 0; #define LIST_ITEM() \ int aint = 0; \ VALUE aval = rb_ary_entry(list_index, nest-1); \ @@ -152,9 +157,9 @@ VALUE red_pass_code(VALUE, VALUE, VALUE, ID); if (nest > RARRAY_LEN(list_layout)) \ { \ sprintf(listm, "%s_open", list_type); \ - if (list_continue == 1) \ + if (!NIL_P(rb_hash_aref(regs, ID2SYM(rb_intern("list_continue"))))) \ { \ - list_continue = 0; \ + rb_hash_aset(regs, ID2SYM(rb_intern("list_continue")), Qnil); \ rb_hash_aset(regs, ID2SYM(rb_intern("start")), rb_ary_entry(list_index, nest-1)); \ } \ else \ diff --git a/ext/redcloth_scan/redcloth_attributes.rb.rl b/ext/redcloth_scan/redcloth_attributes.rb.rl new file mode 100644 index 00000000..311fba13 --- /dev/null +++ b/ext/redcloth_scan/redcloth_attributes.rb.rl @@ -0,0 +1,63 @@ +# +# redcloth_attributes.rb.rl +# +# Copyright (C) 2009 Jason Garber +# + +%%{ + + machine redcloth_attributes; + include redcloth_common "redcloth_common.rb.rl"; + include redcloth_attributes "redcloth_attributes.rl"; + +}%% + +module RedCloth + class RedclothAttributes < BaseScanner + def self.redcloth_attributes(str) + self.new.redcloth_attributes(str) + end + + def self.redcloth_link_attributes(str) + self.new.redcloth_link_attributes(str) + end + + def redcloth_attribute_parser(cs, data) + @data = data + "\0" + @regs = {} + @p = 0 + @pe = @data.length + + %% write init; #% + + @cs = cs + + %% write exec; #% + + return @regs + end + + def redcloth_attributes(str) + self.cs = self.redcloth_attributes_en_inline + return redcloth_attribute_parser(cs, str) + end + + def redcloth_link_attributes(str) + self.cs = self.redcloth_attributes_en_link_says; + return redcloth_attribute_parser(cs, str) + end + + def initialize + %%{ + variable data @data; + variable p @p; + variable pe @pe; + variable cs @cs; + variable ts @ts; + variable te @te; + + write data nofinal; + }%% + end + end +end \ No newline at end of file diff --git a/ext/redcloth_scan/redcloth_common.c.rl b/ext/redcloth_scan/redcloth_common.c.rl index 1e8084a7..0c63755e 100644 --- a/ext/redcloth_scan/redcloth_common.c.rl +++ b/ext/redcloth_scan/redcloth_common.c.rl @@ -14,5 +14,7 @@ action starts_phrase { p == orig_p || *(p-1) == '\r' || *(p-1) == '\n' || *(p-1) == '\f' || *(p-1) == ' ' } + action extended { !NIL_P(extend) } + action not_extended { NIL_P(extend) } }%%; \ No newline at end of file diff --git a/ext/redcloth_scan/redcloth_common.java.rl b/ext/redcloth_scan/redcloth_common.java.rl index a9d2bcec..6a081faa 100644 --- a/ext/redcloth_scan/redcloth_common.java.rl +++ b/ext/redcloth_scan/redcloth_common.java.rl @@ -14,5 +14,7 @@ action starts_phrase { p == orig_p || data[(p-1)] == '\r' || data[(p-1)] == '\n' || data[(p-1)] == '\f' || data[(p-1)] == ' ' } + action extended { !extend.isNil() } + action not_extended { extend.isNil() } }%%; diff --git a/ext/redcloth_scan/redcloth_common.rb.rl b/ext/redcloth_scan/redcloth_common.rb.rl new file mode 100644 index 00000000..ddd10483 --- /dev/null +++ b/ext/redcloth_scan/redcloth_common.rb.rl @@ -0,0 +1,20 @@ +%%{ + + machine redcloth_common; + include redcloth_common "redcloth_common.rl"; + + action esc { rb_str_cat_escaped(@block, @ts, @te); } + action esc_pre { rb_str_cat_escaped_for_preformatted(@block, STR_NEW(@ts, @te-@ts)); } + action ignore { @block << @textile_doc.ignore(@regs); } + + # conditionals + action starts_line { + @p == 0 || @data[(@p-1), 1] == "\r" || @data[(@p-1), 1] == "\n" || @data[(@p-1), 1] == "\f" + } + action starts_phrase { + @p == 0 || @data[(@p-1), 1] == "\r" || @data[(@p-1), 1] == "\n" || @data[(@p-1), 1] == "\f" || @data[(@p-1), 1] == " " + } + action extended { !@extend.nil? } + action not_extended { @extend.nil? } + +}%%; \ No newline at end of file diff --git a/ext/redcloth_scan/redcloth_common.rl b/ext/redcloth_scan/redcloth_common.rl index 79d97c56..9232a1bf 100644 --- a/ext/redcloth_scan/redcloth_common.rl +++ b/ext/redcloth_scan/redcloth_common.rl @@ -2,8 +2,8 @@ machine redcloth_common; - action A { reg = p; } - action B { bck = p; } + action A { MARK(); } + action B { MARK_B(); } action T { STORE("text"); } action X { CLEAR_REGS(); RESET_REG(); } action cat { CAT(block); } @@ -34,7 +34,7 @@ S = ( S_CSPN | S_RSPN )* ; C = ( C_CLAS | C_STYL | C_LNGE )* ; D = ( D_HEADER ) ; - N_CONT = "_" %{ list_continue = 1; }; + N_CONT = "_" %{ ASET("list_continue", "true"); }; N_NUM = digit+ >A %{ STORE("start"); }; N = ( N_CONT | N_NUM )? ; PUNCT = ( "!" | '"' | "#" | "$" | "%" | "&" | "'" | "," | "-" | "." | "/" | ":" | ";" | "=" | "?" | "\\" | "^" | "`" | "|" | "~" | "[" | "]" | "(" | ")" | "<" ) ; diff --git a/ext/redcloth_scan/redcloth_inline.c.rl b/ext/redcloth_scan/redcloth_inline.c.rl index df63cfec..a1a043c5 100644 --- a/ext/redcloth_scan/redcloth_inline.c.rl +++ b/ext/redcloth_scan/redcloth_inline.c.rl @@ -29,7 +29,7 @@ red_parse_attr(VALUE self, VALUE regs, VALUE ref) { VALUE txt = rb_hash_aref(regs, ref); VALUE new_regs = redcloth_attributes(self, txt); - return rb_funcall(regs, rb_intern("update"), 1, new_regs); + return rb_funcall(regs, rb_intern("merge!"), 1, new_regs); } VALUE @@ -38,7 +38,7 @@ red_parse_link_attr(VALUE self, VALUE regs, VALUE ref) VALUE txt = rb_hash_aref(regs, ref); VALUE new_regs = red_parse_title(redcloth_link_attributes(self, txt), ref); - return rb_funcall(regs, rb_intern("update"), 1, new_regs); + return rb_funcall(regs, rb_intern("merge!"), 1, new_regs); } VALUE diff --git a/ext/redcloth_scan/redcloth_inline.java.rl b/ext/redcloth_scan/redcloth_inline.java.rl index 33290996..f0e3d936 100644 --- a/ext/redcloth_scan/redcloth_inline.java.rl +++ b/ext/redcloth_scan/redcloth_inline.java.rl @@ -48,13 +48,13 @@ public class RedclothInline extends RedclothScanService.Base { public IRubyObject red_parse_attr(IRubyObject self, IRubyObject regs, IRubyObject ref) { IRubyObject txt = ((RubyHash)regs).aref(ref); IRubyObject new_regs = RedclothAttributes.attributes(self, txt); - return regs.callMethod(runtime.getCurrentContext(), "update", new_regs); + return regs.callMethod(runtime.getCurrentContext(), "merge!", new_regs); } public IRubyObject red_parse_link_attr(IRubyObject self, IRubyObject regs, IRubyObject ref) { IRubyObject txt = ((RubyHash)regs).aref(ref); IRubyObject new_regs = red_parse_title(RedclothAttributes.link_attributes(self, txt), ref); - return regs.callMethod(runtime.getCurrentContext(), "update", new_regs); + return regs.callMethod(runtime.getCurrentContext(), "merge!", new_regs); } public IRubyObject red_parse_image_attr(IRubyObject self, IRubyObject regs, IRubyObject ref) { diff --git a/ext/redcloth_scan/redcloth_inline.rb.rl b/ext/redcloth_scan/redcloth_inline.rb.rl new file mode 100644 index 00000000..bd4a9b0c --- /dev/null +++ b/ext/redcloth_scan/redcloth_inline.rb.rl @@ -0,0 +1,110 @@ +# +# redcloth_inline.rb.rl +# +# Copyright (C) 2009 Jason Garber +# + +%%{ + + machine redcloth_inline; + include redcloth_common "redcloth_common.rb.rl"; + include redcloth_inline "redcloth_inline.rl"; + +}%% +module RedCloth + class RedclothInline < BaseScanner + def self.redcloth_inline2(textile_doc, data, refs) + self.new.redcloth_inline(textile_doc, data, refs) + end + + def red_parse_attr(regs, ref) + txt = regs[ref.to_sym] + new_regs = redcloth_attributes(txt) + return regs.merge!(new_regs) + end + + def red_parse_link_attr(regs, ref) + txt = regs[ref.to_sym] + new_regs = red_parse_title(redcloth_link_attributes(txt), ref) + return regs.merge!(new_regs) + end + + def red_parse_image_attr(regs, ref) + return red_parse_title(regs, ref); + end + + def red_parse_title(regs, ref) + # Store title/alt + name = regs[ref.to_sym] + if ( !name.nil? ) + s = name.to_s + p = s.length + if (s[p - 1,1] == ')') + level = -1 + p -= 1 + while (p > 0 && level < 0) do + case s[p - 1, 1] + when '('; level += 1 + when ')'; level -= 1 + end + p -= 1 + end + title = s[p + 1, (s.length - 1) - (p + 1)] + p -= 1 if (p > 0 && s[p - 1, 1] == ' ') + if (p != 0) + regs[ref.to_sym] = s[0, p] + regs[:title] = title + end + end + end + return regs; + end + + def red_pass_code(regs, ref, meth) + txt = regs[ref.to_sym] + if (!txt.nil?) + txt2 = "" + rb_str_cat_escaped_for_preformatted(txt2, txt) + regs[ref.to_sym] = txt2 + end + return @textile_doc.send(meth, regs) + end + + def redcloth_inline(textile_doc, data, refs) + @textile_doc = textile_doc + @data = data + "\0" + @refs = refs + @p = 0 + @pe = @data.length + @orig_data = @data.dup + CLEAR_REGS() + @block = "" + + %% write init; + %% write exec; + ##% + + return block + end + + def redcloth_attributes(str) + return RedCloth::RedclothAttributes.redcloth_attributes(str) + end + def redcloth_link_attributes(str) + return RedCloth::RedclothAttributes.redcloth_link_attributes(str) + end + + def initialize + %%{ + variable data @data; + variable p @p; + variable pe @pe; + variable cs @cs; + variable ts @ts; + variable te @te; + + write data nofinal; + }%% + end + end +end \ No newline at end of file diff --git a/ext/redcloth_scan/redcloth_inline.rl b/ext/redcloth_scan/redcloth_inline.rl index 7ba0e417..7f82ac41 100644 --- a/ext/redcloth_scan/redcloth_inline.rl +++ b/ext/redcloth_scan/redcloth_inline.rl @@ -109,7 +109,7 @@ link { PARSE_LINK_ATTR("name"); PASS(block, "name", "link"); }; bracketed_link { PARSE_LINK_ATTR("name"); PASS(block, "name", "link"); }; - code { PARSE_ATTR("text"); PASS_CODE(block, "text", "code", opts); }; + code { PARSE_ATTR("text"); PASS_CODE(block, "text", "code"); }; code_tag_start { CAT(block); fgoto code_tag; }; notextile { INLINE(block, "notextile"); }; strong { PARSE_ATTR("text"); PASS(block, "text", "strong"); }; diff --git a/ext/redcloth_scan/redcloth_scan.c.rl b/ext/redcloth_scan/redcloth_scan.c.rl index a26157a2..ff43cb3d 100644 --- a/ext/redcloth_scan/redcloth_scan.c.rl +++ b/ext/redcloth_scan/redcloth_scan.c.rl @@ -42,7 +42,6 @@ redcloth_transform(self, p, pe, refs) VALUE list_layout = Qnil; char *list_type = NULL; VALUE list_index = rb_ary_new(); - int list_continue = 0; VALUE plain_block; SET_PLAIN_BLOCK("p"); VALUE extend = Qnil; char listm[10] = ""; diff --git a/ext/redcloth_scan/redcloth_scan.java.rl b/ext/redcloth_scan/redcloth_scan.java.rl index dec31428..8ebbf2d2 100644 --- a/ext/redcloth_scan/redcloth_scan.java.rl +++ b/ext/redcloth_scan/redcloth_scan.java.rl @@ -31,6 +31,18 @@ public class RedclothScanService implements BasicLibraryService { list_layout = runtime.newArray(); } + public void SET_LIST_TYPE(String T) { + list_type = T; + } + + public void NEST() { + nest ++; + } + + public void RESET_NEST() { + nest = 0; + } + public void LIST_ITEM() { int aint = 0; IRubyObject aval = ((RubyArray)list_index).entry(nest-1); @@ -41,8 +53,8 @@ public class RedclothScanService implements BasicLibraryService { if(nest > ((RubyArray)list_layout).getLength()) { listm = list_type + "_open"; - if(list_continue == 1) { - list_continue = 0; + if( !((RubyHash)regs).aref(runtime.newSymbol("list_continue")).isNil() ) { + ((RubyHash)regs).aset(runtime.newSymbol("list_continue"), runtime.getNil()); ((RubyHash)regs).aset(runtime.newSymbol("start"), ((RubyArray)list_index).entry(nest-1)); } else { IRubyObject start = ((RubyHash)regs).aref(runtime.newSymbol("start")); @@ -226,6 +238,14 @@ public class RedclothScanService implements BasicLibraryService { reg = -1; } + public void MARK() { + reg = p; + } + + public void MARK_B() { + bck = p; + } + public void CAT(IRubyObject H) { ((RubyString)H).cat(data, ts, te-ts); } @@ -272,15 +292,15 @@ public class RedclothScanService implements BasicLibraryService { red_inc(regs, runtime.newSymbol(T)); } + public void INC(int N) { + N++; + } + public void END_EXTENDED() { extend = runtime.getNil(); CLEAR_REGS(); } - public boolean IS_NOT_EXTENDED() { - return extend.isNil(); - } - public void ASET(String T, String V) { ((RubyHash)regs).aset(runtime.newSymbol(T), runtime.newString(V)); } @@ -326,7 +346,6 @@ public class RedclothScanService implements BasicLibraryService { public IRubyObject list_layout; public String list_type = null; public IRubyObject list_index; - public int list_continue = 0; public IRubyObject plain_block; public IRubyObject extend; public String listm = ""; diff --git a/ext/redcloth_scan/redcloth_scan.rb.rl b/ext/redcloth_scan/redcloth_scan.rb.rl new file mode 100644 index 00000000..25b7d7c7 --- /dev/null +++ b/ext/redcloth_scan/redcloth_scan.rb.rl @@ -0,0 +1,410 @@ +# +# redcloth_scan.rb.rl +# +# Copyright (C) 2009 Jason Garber +# + + +%%{ + + machine redcloth_scan; + include redcloth_common "redcloth_common.rb.rl"; + + action extend { @extend = @regs[:type] } + + include redcloth_scan "redcloth_scan.rl"; + +}%% + +module RedCloth + class TextileDoc < String + def to(formatter) + self.delete!("\r") + working_copy = self.clone + working_copy.extend(formatter) + + if (working_copy.lite_mode) + return working_copy.redcloth_inline2(self, {}) + else + return working_copy.redcloth_transform2(self) + end + end + + class ParseError < Exception; end + + def redcloth_transform2(textile_doc) + before_transform(textile_doc) + return RedCloth::RedclothScan.transform(self, textile_doc, nil) + end + + def redcloth_inline2(textile_doc, refs) + return RedCloth::RedclothInline.redcloth_inline2(self, textile_doc, refs) + end + + def html_esc(input, level=nil) + return "" if input.nil? || input.empty? + + str = input.dup + str.gsub!('&') { amp({}) } + str.gsub!('>') { gt({}) } + str.gsub!('<') { lt({}) } + if (level != :html_escape_preformatted) + str.gsub!("\n") { br({}) } + str.gsub!('"') { quot({}) } + str.gsub!("'") { level == :html_escape_attributes ? apos({}) : squot({}) } + end + return str; + end + + LATEX_ESCAPE_CHARACTERS = { + '{' => "#123", + '}' => "#125", + '\\' => "#92", + '#' => "#35", + '$' => "#36", + '%' => "#37", + '&' => "amp", + '_' => "#95", + '^' => "circ", + '~' => "tilde", + '<' => "lt", + '>' => "gt", + '\n'=> "#10" + } + def latex_esc(str) + return "" if str.nil? || str.empty? + + ch_regex = Regexp.new(LATEX_ESCAPE_CHARACTERS.keys.map {|ch| Regexp.escape(ch) }.join("|")) + str.gsub(ch_regex) {|ch| entity({:text => LATEX_ESCAPE_CHARACTERS[ch]}) } + end + end + + class BaseScanner + attr_accessor :p, :pe, :refs + attr_reader :data + attr_accessor :orig_data, :cs, :act, :ts, :te, :reg, :bck, :eof, + :html, :table, :block, :regs + attr_accessor :list_layout, :list_type, :list_index, :list_continue, :listm, + :refs_found, :plain_block + + def STR_NEW(p,n) + @data[p, n] + end + def MARK() + @reg = @p + end + def MARK_B() + @bck = @p + end + def CLEAR_REGS() + @regs = {} + end + def RESET_REG() + @reg = nil + end + def CAT(h) + h << @data[@ts, @te - @ts] + end + def CLEAR(h) + h.replace("") + end + def RSTRIP_BANG(h) + h.rstrip! + end + def SET_PLAIN_BLOCK(t) + @plain_block = t + end + def RESET_TYPE() + @regs[:type] = @plain_block + end + def INLINE(h, t) + h << @textile_doc.send(t, @regs) + end + def DONE(h) + @html << h + CLEAR(h) + CLEAR_REGS() + end + def PASS(h, a, t) + h << red_pass(@regs, a.to_sym, t, @refs) + end + def PARSE_ATTR(a) + red_parse_attr(@regs, a) + end + def PARSE_LINK_ATTR(a) + red_parse_link_attr(@regs, a) + end + def PARSE_IMAGE_ATTR(a) + red_parse_image_attr(@regs, a) + end + def PASS_CODE(h, a, t) + h << red_pass_code(@regs, a, t) + end + def ADD_BLOCK() + @html << red_block(@regs, @block, @refs) + @extend = nil + CLEAR(@block) + CLEAR_REGS() + end + def ADD_EXTENDED_BLOCK() + @html << red_block(@regs, @block, @refs) + CLEAR(@block) + end + def END_EXTENDED() + @extend = nil + CLEAR_REGS() + end + def ADD_BLOCKCODE() + @html << red_blockcode(@regs, @block) + CLEAR(@block) + CLEAR_REGS() + end + def ADD_EXTENDED_BLOCKCODE() + @html << red_blockcode(@regs, @block) + CLEAR(@block) + end + def ASET(t, v) + @regs[t.to_sym] = v + end + def AINC(t) + red_inc(@regs, t.to_sym) + end + def SET_ATTRIBUTES() + SET_ATTRIBUTE("class_buf", "class") + SET_ATTRIBUTE("id_buf", "id") + SET_ATTRIBUTE("lang_buf", "lang") + SET_ATTRIBUTE("style_buf", "style") + end + def SET_ATTRIBUTE(b, a) + @regs[a.to_sym] = @regs[b.to_sym] unless @regs[b.to_sym].nil? + end + def TRANSFORM(t) + if (@reg && @p > @reg && @reg >= @ts) + str = self.class.transform(@textile_doc, STR_NEW(reg, p-reg), @refs) + @regs[t.to_sym] = str + # /*printf("TRANSFORM(" T ") '%s' (p:'%s' reg:'%s')\n", RSTRING_PTR(str), p, reg);*/ \ + else + @regs[t.to_sym] = nil + end + end + def STORE(t) + if (@reg && @p > @reg && @reg >= @ts) + str = @data[@reg, @p - @reg] + @regs[t.to_sym] = str + # /*printf("STORE(" T ") '%s' (p:'%s' reg:'%s')\n", RSTRING_PTR(str), p, reg);*/ \ + else + @regs[t.to_sym] = nil + end + end + def STORE_B(t) + if (@bck && @p > @bck && @bck >= @ts) + str = @data[@bck, @p - @bck] + @regs[t.to_sym] = str + # /*printf("STORE_B(" T ") '%s' (p:'%s' reg:'%s')\n", RSTRING_PTR(str), p, reg);*/ \ + else + @regs[t.to_sym] = nil + end + end + def STORE_URL(t) + if (@reg && @p > @reg && @reg >= @ts) + punct = true + while (@p > @reg && punct) + case @data[@p - 1, 1] + when ')' + temp_p = @p - 1 + level = -1 + while (temp_p > @reg) + case @data[temp_p - 1, 1] + when '('; level += 1 + when ')'; level -= 1 + end + temp_p -= 1 + end + if (level == 0) + punct = false + else + @p -= 1 + end + when '!', '"', '#', '$', '%', ']', '[', '&', '\'', + '*', '+', ',', '-', '.', '(', ':', ';', '=', + '?', '@', '\\', '^', '_', '`', '|', '~' + @p -= 1 + else + punct = false + end + end + @te = @p + end + STORE(t) + if ( ! @refs.nil? && @refs.has_key?(@regs[t.to_sym]) ) + @regs[t.to_sym] = @refs[@regs[t.to_sym]] + end + end + def STORE_LINK_ALIAS() + @refs_found[@regs[:text]] = @regs[:href] + end + def CLEAR_LIST() + @list_layout = [] + end + def SET_LIST_TYPE(t) + @list_type = t + end + def NEST() + @nest += 1 + end + def RESET_NEST() + @nest = 0 + end + def LIST_ITEM() + aint = 0 + aval = @list_index[@nest-1] + aint = aval.to_i unless aval.nil? + if (@list_type == "ol") + @list_index[@nest-1] = aint + 1 + end + if (@nest > @list_layout.length) + listm = sprintf("%s_open", @list_type) + if (@regs[:list_continue]) + @regs[:list_continue] = nil + @regs[:start] = @list_index[@nest-1] + else + start = @regs[:start] + if (start.nil?) + @list_index[@nest-1] = 1 + else + start_num = start.to_i + @list_index[@nest-1] = start_num + end + end + @regs[:nest] = @nest + @html << @textile_doc.send(listm, @regs) + @list_layout[@nest-1] = @list_type + CLEAR_REGS() + ASET("first", true) + end + LIST_CLOSE() + @regs[:nest] = @list_layout.length + ASET("type", "li_open") + end + def LIST_CLOSE() + while (@nest < @list_layout.length) + @regs[:nest] = @list_layout.length + end_list = @list_layout.pop + if (!end_list.nil?) + listm = sprintf("%s_close", end_list) + @html << @textile_doc.send(listm, @regs) + end + end + end + + def red_pass(regs, ref, meth, refs) + txt = regs[ref] + regs[ref] = RedCloth::RedclothInline.redcloth_inline2(@textile_doc, txt, refs) if (!txt.nil?) + return @textile_doc.send(meth, regs) + end + + def red_inc(regs, ref) + aint = 0 + aval = regs[ref] + aint = aval.to_i if (!aval.nil?) + regs[ref] = aint + 1 + end + + def red_block(regs, block, refs) + sym_text = :text + btype = @regs[:type] + block = block.strip + if (!block.nil? && !btype.nil?) + method = btype.intern + if (method == :notextile) + @regs[sym_text] = block + else + @regs[sym_text] = RedCloth::RedclothInline.redcloth_inline2(@textile_doc, block, refs) + end + if (@textile_doc.send(:formatter_methods).include? method) #FIXME: This is a hack to get around private method. + block = @textile_doc.send(method, @regs) + else + fallback = @regs[:fallback] + if (!fallback.nil?) + fallback << @regs[sym_text] + CLEAR_REGS() + @regs[sym_text] = fallback + end + block = @textile_doc.p(@regs); + end + end + return block + end + + def red_blockcode(regs, block) + btype = regs[:type] + if (block.length > 0) + regs[:text] = block + block = @textile_doc.send(btype, regs) + end + return block + end + + def rb_str_cat_escaped(str, ts, te) + source_str = STR_NEW(ts, te-ts); + escaped_str = @textile_doc.send(:escape, source_str) #FIXME: This is a hack to get around private method. + str << escaped_str + end + + def rb_str_cat_escaped_for_preformatted(str, text) + escaped_str = @textile_doc.send(:escape_pre, text) #FIXME: This is a hack to get around private method. + str << escaped_str + end + end + + class RedclothScan < BaseScanner + def self.transform(textile_doc, data, refs) + self.new.transform(textile_doc, data, refs) + end + + def transform(textile_doc, data, refs) + @textile_doc = textile_doc + @data = data + "\0" + @refs = refs + @p = 0 + @pe = @data.length + @orig_data = data.dup + @html = "" + @table = "" + @block = "" + CLEAR_REGS() + + @list_layout = nil + @list_index = []; + SET_PLAIN_BLOCK("p") + @extend = nil + @listm = [] + @refs_found = {} + + %% write init; + %% write exec; + + ADD_BLOCK() if (block.length > 0) + + if ( refs.nil? && !refs_found.empty? ) + return transform(@textile_doc, orig_data, refs_found) + else + @textile_doc.send(:after_transform, html) + return html + end + end + + def initialize + %%{ + variable data @data; + variable p @p; + variable pe @pe; + variable cs @cs; + variable ts @ts; + variable te @te; + + write data nofinal; + }%% + end + end +end \ No newline at end of file diff --git a/ext/redcloth_scan/redcloth_scan.rl b/ext/redcloth_scan/redcloth_scan.rl index 6584adcc..823c92e4 100644 --- a/ext/redcloth_scan/redcloth_scan.rl +++ b/ext/redcloth_scan/redcloth_scan.rl @@ -16,20 +16,20 @@ pre_block_start = ( "pre" >A %{ STORE("type"); } A C :> "." ( "." %extend | "" ) " "+ ) ; bc_start = ( "bc" >A %{ STORE("type"); } A C :> "." ( "." %extend | "" ) " "+ ) ; bq_start = ( "bq" >A %{ STORE("type"); } A C :> "." ( "." %extend | "" ) ( ":" %A uri %{ STORE("cite"); } )? " "+ ) ; - non_ac_btype = ( "bq" | "bc" | "pre" | "notextile" ); + non_ac_btype = ( "bq" | "bc" | "pre" | "notextile" | "table" ); btype = (alpha alnum*) -- (non_ac_btype | "fn" digit+); block_start = ( btype >A %{ STORE("type"); } A C :> "." ( "." %extend | "" ) " "+ ) >B %{ STORE_B("fallback"); }; all_btypes = btype | non_ac_btype; - next_block_start = ( all_btypes A_noactions C_noactions :> "."+ " " ) >A @{ p = reg - 1; } ; + next_block_start = ( all_btypes A_noactions C_noactions :> "."+ " " ) >A @{ fexec(reg); } ; double_return = LF [ \t]* LF ; block_end = ( double_return | EOF ); ftype = ( "fn" >A %{ STORE("type"); } digit+ >A %{ STORE("id"); } ) ; footnote_start = ( ftype A C :> dotspace ) ; - ul = "*" %{nest++; list_type = "ul";}; - ol = "#" %{nest++; list_type = "ol";}; + ul = "*" %{NEST(); SET_LIST_TYPE("ul");}; + ol = "#" %{NEST(); SET_LIST_TYPE("ol");}; ul_start = ( ul | ol )* ul A C :> " "+ ; ol_start = ( ul | ol )* ol N A C :> " "+ ; - list_start = " "* ( ul_start | ol_start ) >{nest = 0;} ; + list_start = " "* ( ul_start | ol_start ) >{RESET_NEST();} ; dt_start = "-" . " "+ ; dd_start = ":=" ; long_dd = dd_start " "* LF %{ ADD_BLOCK(); ASET("type", "dd"); } any+ >A %{ TRANSFORM("text"); } :>> "=:" ; @@ -41,7 +41,7 @@ # image lookahead IMG_A_LEFT = "<" %{ ASET("float", "left"); } ; IMG_A_RIGHT = ">" %{ ASET("float", "right"); } ; - aligned_image = ( "["? "!" (IMG_A_LEFT | IMG_A_RIGHT) ) >A @{ p = reg - 1; } ; + aligned_image = ( "["? "!" (IMG_A_LEFT | IMG_A_RIGHT) ) >A @{ fexec(reg); } ; # html blocks BlockTagName = Name - ("pre" | "notextile" | "a" | "applet" | "basefont" | "bdo" | "br" | "font" | "iframe" | "img" | "map" | "object" | "param" | "embed" | "q" | "script" | "span" | "sub" | "sup" | "abbr" | "acronym" | "cite" | "code" | "del" | "dfn" | "em" | "ins" | "kbd" | "samp" | "strong" | "var" | "b" | "big" | "i" | "s" | "small" | "strike" | "tt" | "u"); @@ -51,7 +51,7 @@ html_start = indent >B %{STORE_B("indent_before_start");} block_start_tag >B %{STORE_B("start_tag");} indent >B %{STORE_B("indent_after_start");} ; html_end = indent >B %{STORE_B("indent_before_end");} block_end_tag >B %{STORE_B("end_tag");} (indent LF?) >B %{STORE_B("indent_after_end");} ; standalone_html = indent (block_start_tag | block_empty_tag | block_end_tag) indent (LF+ | EOF); - html_end_terminating_block = ( LF indent block_end_tag ) >A @{ p = reg - 1; } ; + html_end_terminating_block = ( LF indent block_end_tag ) >A @{ fexec(reg); } ; # tables para = ( default+ ) -- LF ; @@ -73,28 +73,11 @@ *|; pre_block := |* - EOF { - ADD_BLOCKCODE(); - fgoto main; - }; - double_return { - if (IS_NOT_EXTENDED()) { - ADD_BLOCKCODE(); - fgoto main; - } else { - ADD_EXTENDED_BLOCKCODE(); - } - }; - double_return next_block_start { - if (IS_NOT_EXTENDED()) { - ADD_BLOCKCODE(); - fgoto main; - } else { - ADD_EXTENDED_BLOCKCODE(); - END_EXTENDED(); - fgoto main; - } - }; + EOF { ADD_BLOCKCODE(); fgoto main; }; + double_return when extended { ADD_EXTENDED_BLOCKCODE(); }; + double_return when not_extended { ADD_BLOCKCODE(); fgoto main; } ; + double_return next_block_start when extended { ADD_EXTENDED_BLOCKCODE(); END_EXTENDED(); fgoto main; }; + double_return next_block_start when not_extended { ADD_BLOCKCODE(); fgoto main; }; default => esc_pre; *|; @@ -110,33 +93,11 @@ *|; notextile_block := |* - EOF { - ADD_BLOCK(); - fgoto main; - }; - double_return { - if (IS_NOT_EXTENDED()) { - ADD_BLOCK(); - CAT(html); - fgoto main; - } else { - CAT(block); - ADD_EXTENDED_BLOCK(); - CAT(html); - } - }; - double_return next_block_start { - if (IS_NOT_EXTENDED()) { - ADD_BLOCK(); - CAT(html); - fgoto main; - } else { - CAT(block); - ADD_EXTENDED_BLOCK(); - END_EXTENDED(); - fgoto main; - } - }; + EOF { ADD_BLOCK(); fgoto main; }; + double_return when extended { CAT(block); ADD_EXTENDED_BLOCK(); CAT(html); }; + double_return when not_extended { ADD_BLOCK(); CAT(html); fgoto main; } ; + double_return next_block_start when extended { CAT(block); ADD_EXTENDED_BLOCK(); END_EXTENDED(); fgoto main; }; + double_return next_block_start when not_extended { ADD_BLOCK(); CAT(html); fgoto main; }; default => cat; *|; @@ -146,123 +107,34 @@ *|; bc := |* - EOF { - ADD_BLOCKCODE(); - INLINE(html, "bc_close"); - SET_PLAIN_BLOCK("p"); - fgoto main; - }; - double_return { - if (IS_NOT_EXTENDED()) { - ADD_BLOCKCODE(); - INLINE(html, "bc_close"); - SET_PLAIN_BLOCK("p"); - fgoto main; - } else { - ADD_EXTENDED_BLOCKCODE(); - CAT(html); - } - }; - double_return next_block_start { - if (IS_NOT_EXTENDED()) { - ADD_BLOCKCODE(); - INLINE(html, "bc_close"); - SET_PLAIN_BLOCK("p"); - fgoto main; - } else { - ADD_EXTENDED_BLOCKCODE(); - CAT(html); - RSTRIP_BANG(html); - INLINE(html, "bc_close"); - SET_PLAIN_BLOCK("p"); - END_EXTENDED(); - fgoto main; - } - }; + EOF { ADD_BLOCKCODE(); INLINE(html, "bc_close"); SET_PLAIN_BLOCK("p"); fgoto main; }; + double_return when extended { ADD_EXTENDED_BLOCKCODE(); CAT(html); }; + double_return when not_extended { ADD_BLOCKCODE(); INLINE(html, "bc_close"); SET_PLAIN_BLOCK("p"); fgoto main; }; + double_return next_block_start when extended { ADD_EXTENDED_BLOCKCODE(); CAT(html); RSTRIP_BANG(html); INLINE(html, "bc_close"); SET_PLAIN_BLOCK("p"); END_EXTENDED(); fgoto main; }; + double_return next_block_start when not_extended { ADD_BLOCKCODE(); INLINE(html, "bc_close"); SET_PLAIN_BLOCK("p"); fgoto main; }; default => esc_pre; *|; bq := |* - EOF { - ADD_BLOCK(); - INLINE(html, "bq_close"); - fgoto main; - }; - double_return { - if (IS_NOT_EXTENDED()) { - ADD_BLOCK(); - INLINE(html, "bq_close"); - fgoto main; - } else { - ADD_EXTENDED_BLOCK(); - } - }; - double_return next_block_start { - if (IS_NOT_EXTENDED()) { - ADD_BLOCK(); - INLINE(html, "bq_close"); - fgoto main; - } else { - ADD_EXTENDED_BLOCK(); - INLINE(html, "bq_close"); - END_EXTENDED(); - fgoto main; - } - }; - html_end_terminating_block { - if (IS_NOT_EXTENDED()) { - ADD_BLOCK(); - INLINE(html, "bq_close"); - fgoto main; - } else { - ADD_EXTENDED_BLOCK(); - INLINE(html, "bq_close"); - END_EXTENDED(); - fgoto main; - } - }; + EOF { ADD_BLOCK(); INLINE(html, "bq_close"); fgoto main; }; + double_return when extended { ADD_EXTENDED_BLOCK(); }; + double_return when not_extended { ADD_BLOCK(); INLINE(html, "bq_close"); fgoto main; }; + double_return next_block_start when extended { ADD_EXTENDED_BLOCK(); INLINE(html, "bq_close"); END_EXTENDED(); fgoto main; }; + double_return next_block_start when not_extended { ADD_BLOCK(); INLINE(html, "bq_close"); fgoto main; }; + html_end_terminating_block when extended { ADD_EXTENDED_BLOCK(); INLINE(html, "bq_close"); END_EXTENDED(); fgoto main; }; + html_end_terminating_block when not_extended { ADD_BLOCK(); INLINE(html, "bq_close"); fgoto main; }; default => cat; *|; block := |* - EOF { - ADD_BLOCK(); - fgoto main; - }; - double_return { - if (IS_NOT_EXTENDED()) { - ADD_BLOCK(); - fgoto main; - } else { - ADD_EXTENDED_BLOCK(); - } - }; - double_return next_block_start { - if (IS_NOT_EXTENDED()) { - ADD_BLOCK(); - fgoto main; - } else { - ADD_EXTENDED_BLOCK(); - END_EXTENDED(); - fgoto main; - } - }; - html_end_terminating_block { - if (IS_NOT_EXTENDED()) { - ADD_BLOCK(); - fgoto main; - } else { - ADD_EXTENDED_BLOCK(); - END_EXTENDED(); - fgoto main; - } - }; - LF list_start { - ADD_BLOCK(); - CLEAR_LIST(); - LIST_ITEM(); - fgoto list; - }; + EOF { ADD_BLOCK(); fgoto main; }; + double_return when extended { ADD_EXTENDED_BLOCK(); }; + double_return when not_extended { ADD_BLOCK(); fgoto main; }; + double_return next_block_start when extended { ADD_EXTENDED_BLOCK(); END_EXTENDED(); fgoto main; }; + double_return next_block_start when not_extended { ADD_BLOCK(); fgoto main; }; + html_end_terminating_block when extended { ADD_EXTENDED_BLOCK(); END_EXTENDED(); fgoto main; }; + html_end_terminating_block when not_extended { ADD_BLOCK(); fgoto main; }; + LF list_start { ADD_BLOCK(); CLEAR_LIST(); LIST_ITEM(); fgoto list; }; default => cat; *|; @@ -274,7 +146,7 @@ list := |* LF list_start { ADD_BLOCK(); LIST_ITEM(); }; - block_end { ADD_BLOCK(); nest = 0; LIST_CLOSE(); fgoto main; }; + block_end { ADD_BLOCK(); RESET_NEST(); LIST_CLOSE(); fgoto main; }; default => cat; *|; @@ -301,7 +173,7 @@ footnote_start { fgoto footnote; }; horizontal_rule { INLINE(html, "hr"); }; list_start { CLEAR_LIST(); LIST_ITEM(); fgoto list; }; - dl_start { p = ts; INLINE(html, "dl_open"); ASET("type", "dt"); fgoto dl; }; + dl_start { fexec(ts + 1); INLINE(html, "dl_open"); ASET("type", "dt"); fgoto dl; }; table { INLINE(table, "table_close"); DONE(table); fgoto block; }; link_alias { STORE_LINK_ALIAS(); DONE(block); }; aligned_image { RESET_TYPE(); fgoto block; }; diff --git a/extras/ragel_profiler.rb b/extras/ragel_profiler.rb index 9d84b6aa..3cc94be5 100644 --- a/extras/ragel_profiler.rb +++ b/extras/ragel_profiler.rb @@ -4,7 +4,7 @@ class RagelProfiler COMMANDS = { :compile => %w(ragel rlgen-cd gcc-4.0 gnumake cc1), :test => %w(ruby) } - FIELDS = %w(compile_time compile_max_rss test_time test_max_rss ext_so_size) + FIELDS = %w(compile_time compile_max_rss test_time test_max_rss file_size) @@results = {} @@ -32,8 +32,8 @@ def measure(type) store_result(type, "max_rss", t[:max]) end - def ext_size(ext_so) - store_result(:ext_so, "size", File.size(ext_so) / MEM_CONVERSION) + def ext_size(file) + store_result(:file, "size", File.size(file) / MEM_CONVERSION) end def self.results diff --git a/lib/redcloth/formatters/latex.rb b/lib/redcloth/formatters/latex.rb index 871b3dd6..9b318a8b 100644 --- a/lib/redcloth/formatters/latex.rb +++ b/lib/redcloth/formatters/latex.rb @@ -267,7 +267,12 @@ def dim(opts) period = opts[:text].slice!(/\.$/) "$#{opts[:text]}$#{period}" end - + + # TODO: what do we do with HTML? + def inline_html(opts) + opts[:text] || "" + end + private def escape(text) diff --git a/lib/tasks/pureruby.rake b/lib/tasks/pureruby.rake new file mode 100644 index 00000000..1f7a8244 --- /dev/null +++ b/lib/tasks/pureruby.rake @@ -0,0 +1,12 @@ +Gem::Specification::PLATFORM_CROSS_TARGETS << "pureruby" + +task 'pureruby' do + reset_target 'pureruby' +end + +if target = ARGV.detect do |arg| + # Hack to get the platform set before the Rakefile evaluates + Gem::Specification::PLATFORM_CROSS_TARGETS.include? arg + end + reset_target target +end