Skip to content

Commit

Permalink
Merge branch 'olabini/master' into jruby2
Browse files Browse the repository at this point in the history
  • Loading branch information
jgarber committed Oct 23, 2008
2 parents ae11dfc + 11e3005 commit fd82982
Show file tree
Hide file tree
Showing 7 changed files with 1,304 additions and 280 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Expand Up @@ -2,9 +2,14 @@ ext/redcloth_scan/Makefile
ext/redcloth_scan/*.[co]
ext/redcloth_scan/*.bundle
ext/redcloth_scan/*.so
ext/redcloth_scan/*.jar
ext/redcloth_scan/*.class
ext/redcloth_scan/*.java
lib/*.bundle
lib/*.so
lib/*.jar
doc/rdoc/*
tmp/*
pkg/*
.DS_Store
.DS_Store
*.log
52 changes: 31 additions & 21 deletions Rakefile
Expand Up @@ -251,11 +251,11 @@ end

# Here are the jruby tasks, stolen from Hpricot. If this jruby version catches on, I'd like these tasks to be unified with the C tasks and use echoe's platform detection, like Mongrel.
namespace "jruby" do

def ant(*args)
system "ant #{args.join(' ')}"
end

desc "Installs jruby in a subdirectory of ./test/"
task :install do
sh %{svn export http://svn.codehaus.org/jruby/trunk/jruby test/jruby}
Expand All @@ -265,44 +265,35 @@ namespace "jruby" do
sh %{jruby -S gem install rake}
Rake::Task['add_path'].invoke
end

desc "Adds jruby to your PATH"
task :add_path do
ENV['PATH'] = ENV['PATH'] + ":" + File.join(File.dirname(__FILE__), "test/jruby/bin")
end

# Java only supports the table-driven code
# generation style at this point.
# Java only supports the table-driven code
# generation style at this point.
desc "Generates the Java scanner code using the Ragel table-driven code generation style."
task :ragel_java => [:ragel_version] do
ensure_ragel_version("RedClothScanService.java") do
ensure_ragel_version("RedclothScanService.java") do
puts "compiling with ragel version #{@ragel_v}"
sh %{ragel -J -o ext/redcloth_scan/RedClothScanService.java ext/redcloth_scan/redcloth_scan.java.rl}
sh %{ragel -J -o ext/redcloth_scan/RedclothScanService.java ext/redcloth_scan/redcloth_scan.java.rl}
sh %{ragel -J -o ext/redcloth_scan/RedclothAttributes.java ext/redcloth_scan/redcloth_attributes.java.rl}
sh %{ragel -J -o ext/redcloth_scan/RedclothInline.java ext/redcloth_scan/redcloth_inline.java.rl}
end
end

def java_classpath_arg
def java_classpath_arg
# A myriad of ways to discover the JRuby classpath
classpath = begin
require 'java'
require 'java'
# Already running in a JRuby JVM
Java::java.lang.System.getProperty('java.class.path')
rescue LoadError
ENV['JRUBY_PARENT_CLASSPATH'] || ENV['JRUBY_HOME'] && FileList["#{ENV['JRUBY_HOME']}/lib/*.jar"].join(File::PATH_SEPARATOR)
end
classpath ? "-cp #{classpath}" : ""
end

def compile_java(filename, jarname)
sh %{javac -source 1.4 -target 1.4 #{java_classpath_arg} #{filename}}
sh %{jar cf #{jarname} *.class}
end

task :redcloth_scan_java => [:ragel_java] do
Dir.chdir "ext/redcloth_scan" do
compile_java("RedClothScanService.java", "redcloth_scan.jar")
end
end

JRubySpec = spec.dup
JRubySpec.platform = 'jruby'
Expand All @@ -316,6 +307,25 @@ namespace "jruby" do
sh "tar zxf pkg/#{PKG}.tgz"
mv PKG, JRUBY_PKG_DIR
end

def compile_java(filenames, jarname)
sh %{javac -source 1.5 -target 1.5 #{java_classpath_arg} #{filenames.join(" ")}}
sh %{jar cf #{jarname} *.class}
end

task :redcloth_scan_java => [:ragel_java] do
Dir.chdir "ext/redcloth_scan" do
compile_java(["RedclothAttributes.java", "RedclothInline.java", "RedclothScanService.java"], "redcloth_scan.jar")
end
cp "ext/redcloth_scan/redcloth_scan.jar", "lib"
end

desc "Run all the tests using JRuby"
Rake::TestTask.new(:test => [:redcloth_scan_java]) do |t|
t.libs << "test"
t.test_files = FileList['test/test_*.rb']
t.verbose = true
end

desc "Build the RubyGems package for JRuby"
task :package_jruby => JRUBY_PKG_DIR do
Expand All @@ -340,4 +350,4 @@ def ensure_ragel_version(name)
STDERR.puts "Ragel 6.3 or greater is required to generate #{name}."
exit(1)
end
end
end
118 changes: 118 additions & 0 deletions ext/redcloth_scan/redcloth_attributes.java.rl
@@ -0,0 +1,118 @@
/*
* redcloth_attributes.rl
*
* Copyright (C) 2008 Jason Garber
*/
import java.io.IOException;

import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
import org.jruby.RubyHash;
import org.jruby.RubyModule;
import org.jruby.RubyNumeric;
import org.jruby.RubyObject;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallbackFactory;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.load.BasicLibraryService;

import org.jruby.util.ByteList;

public class RedclothAttributes extends RedclothScanService.Base {

%%{

machine redcloth_attributes;
include redcloth_common "redcloth_common.java.rl";

C2_CLAS = ( "(" ( [^)#]+ >A %{ STORE("class_buf"); } )? ("#" [^)]+ >A %{STORE("id_buf");} )? ")" ) ;
C2_LNGE = ( "[" [^\]]+ >A %{ STORE("lang_buf"); } "]" ) ;
C2_STYL = ( "{" [^}]+ >A %{ STORE("style_buf"); } "}" ) ;
C2 = ( C2_CLAS | C2_STYL | C2_LNGE )+ ;

mtext_with_attributes = ( C2 mtext >A %T ) >X ;

inline := |*

mtext_with_attributes { SET_ATTRIBUTES(); } ;

*|;

link_text_with_attributes = C2 "."* " "* ( mtext+ ) >A %{ STORE("name"); } ;
link_text_without_attributes = ( mtext+ ) >B %{ STORE_B("name_without_attributes"); } ;

link_says := |*

link_text_with_attributes { SET_ATTRIBUTES(); } ;
link_text_without_attributes { SET_ATTRIBUTE("name_without_attributes", "name"); } ;

*|;

}%%

%% write data nofinal;

public void SET_ATTRIBUTES() {
SET_ATTRIBUTE("class_buf", "class");
SET_ATTRIBUTE("id_buf", "id");
SET_ATTRIBUTE("lang_buf", "lang");
SET_ATTRIBUTE("style_buf", "style");
}

public void SET_ATTRIBUTE(String B, String A) {
buf = ((RubyHash)regs).aref(runtime.newSymbol(B));
if(!buf.isNil()) {
((RubyHash)regs).aset(runtime.newSymbol(A), buf);
}
}

private int machine;
private IRubyObject buf;

public RedclothAttributes(int machine, IRubyObject self, byte[] data, int p, int pe) {
this.runtime = self.getRuntime();
this.self = self;

// This is GROSS but necessary for EOF matching
this.data = new byte[pe+1];
System.arraycopy(data, p, this.data, 0, pe);
this.data[pe] = 0;

this.p = 0;
this.pe = pe+1;
this.eof = this.pe;
this.orig_p = 0;
this.orig_pe = this.pe;

this.regs = RubyHash.newHash(runtime);
this.buf = runtime.getNil();
this.machine = machine;
}

public IRubyObject parse() {
%% write init;

cs = machine;

%% write exec;

return regs;
}

public static IRubyObject attributes(IRubyObject self, IRubyObject str) {
ByteList bl = str.convertToString().getByteList();
int cs = redcloth_attributes_en_inline;
return new RedclothAttributes(cs, self, bl.bytes, bl.begin, bl.realSize).parse();
}

public static IRubyObject link_attributes(IRubyObject self, IRubyObject str) {
ByteList bl = str.convertToString().getByteList();
int cs = redcloth_attributes_en_link_says;
return new RedclothAttributes(cs, self, bl.bytes, bl.begin, bl.realSize).parse();
}
}
121 changes: 121 additions & 0 deletions ext/redcloth_scan/redcloth_common.java.rl
@@ -0,0 +1,121 @@
%%{

machine redcloth_common;

action A { reg = p; }
action B { bck = p; }
action T { STORE("text"); }
action X { CLEAR_REGS(); reg = -1; }
action cat { CAT(block); }
action esc { strCatEscaped(self, block, data, ts, te); }
action esc_pre { strCatEscapedForPreformatted(self, block, data, ts, te); }
action ignore { ((RubyString)block).append(self.callMethod(runtime.getCurrentContext(), "ignore", regs)); }

# simple
LF = ( '\n' ) ;
default = ^0 ;
EOF = 0 ;

# textile modifiers
A_LEFT = "<" %{ ASET("align", "left"); } ;
A_RIGHT = ">" %{ ASET("align", "right"); } ;
A_JUSTIFIED = "<>" %{ ASET("align", "justify"); } ;
A_CENTER = "=" %{ ASET("align", "center"); } ;
A_PADLEFT = "(" >A %{ AINC("padding-left"); } ;
A_PADRIGHT = ")" >A %{ AINC("padding-right"); } ;
A_HLGN = ( A_LEFT | A_RIGHT | A_JUSTIFIED | A_CENTER | A_PADLEFT | A_PADRIGHT ) ;
A_LIMIT = ( A_LEFT | A_CENTER | A_RIGHT ) ;
A_VLGN = ( "-" %{ ASET("vertical-align", "middle"); } | "^" %{ ASET("vertical-align", "top"); } | "~" %{ ASET("vertical-align", "bottom"); } ) ;
C_CLAS = ( "(" ( [^)#]+ >A %{ STORE("class"); } )? ("#" [^)]+ >A %{STORE("id");} )? ")" ) ;
C_LNGE = ( "[" [^\]]+ >A %{ STORE("lang"); } "]" ) ;
C_STYL = ( "{" [^}]+ >A %{ STORE("style"); } "}" ) ;
S_CSPN = ( "\\" [0-9]+ >A %{ STORE("colspan"); } ) ;
S_RSPN = ( "/" [0-9]+ >A %{ STORE("rowspan"); } ) ;
D_HEADER = "_" %{ ASET("th", "true"); } ;
A = ( ( A_HLGN | A_VLGN )* ) ;
A2 = ( A_LIMIT? ) ;
S = ( S_CSPN | S_RSPN )* ;
C = ( C_CLAS | C_STYL | C_LNGE )* ;
D = ( D_HEADER ) ;
N_CONT = "_" %{ list_continue = 1; };
N_NUM = digit+ >A %{ STORE("start"); };
N = ( N_CONT | N_NUM )? ;
PUNCT = ( "!" | '"' | "#" | "$" | "%" | "&" | "'" | "," | "-" | "." | "/" | ":" | ";" | "=" | "?" | "\\" | "^" | "`" | "|" | "~" | "[" | "]" | "(" | ")" | "<" ) ;
dotspace = ("." " "*) ;
indent = [ \t]* ;

# very un-DRY; Adrian says an action-stripping macro will come in a future Ragel version
A_LEFT_noactions = "<" ;
A_RIGHT_noactions = ">" ;
A_JUSTIFIED_noactions = "<>" ;
A_CENTER_noactions = "=" ;
A_PADLEFT_noactions = "(" ;
A_PADRIGHT_noactions = ")" ;
A_HLGN_noactions = ( A_LEFT_noactions | A_RIGHT_noactions | A_JUSTIFIED_noactions | A_CENTER_noactions | A_PADLEFT_noactions | A_PADRIGHT_noactions ) ;
A_VLGN_noactions = ( "-" | "^" | "~" ) ;
C_CLAS_noactions = ( "(" ( [^)#]+ )? ("#" [^)]+ )? ")" ) ;
C_LNGE_noactions = ( "[" [^\]]+ "]" ) ;
C_STYL_noactions = ( "{" [^}]+ "}" ) ;
A_noactions = ( ( A_HLGN_noactions | A_VLGN_noactions )* ) ;
C_noactions = ( C_CLAS_noactions | C_STYL_noactions | C_LNGE_noactions )* ;
C_noquotes_noactions = C_noactions -- '"' ;

# text blocks
trailing = PUNCT - ("'" | '"') ;
chars = (default - space)+ ;
phrase = chars -- trailing ;

# html tags (from Hpricot)
NameChar = [\-A-Za-z0-9._:?] ;
Name = [A-Za-z_:] NameChar* ;
NameAttr = NameChar+ ;
Q1Attr = [^']* ;
Q2Attr = [^"]* ;
UnqAttr = ( space | [^ \t\r\n<>"'] [^ \t\r\n<>]* ) ;
Nmtoken = NameChar+ ;
Attr = NameAttr space* "=" space* ('"' Q2Attr '"' | "'" Q1Attr "'" | UnqAttr space+ ) space* ;
AttrEnd = ( NameAttr space* "=" space* UnqAttr? | Nmtoken ) ;
AttrSet = ( Attr | Nmtoken space+ ) ;

script_tag_start = ( "<script" [^>]* ">" ) >X >A %T ;
script_tag_end = ( "</script>" >A %T LF? ) >X ;


# URI tokens (lifted from Mongrel)
CTL = (cntrl | 127);
safe = ("$" | "-" | "_" | ".");
extra = ("!" | "*" | "'" | "(" | ")" | "," | "#");
reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+");
unsafe = (CTL | " " | "\"" | "%" | "<" | ">");
national = any -- (alpha | digit | reserved | extra | safe | unsafe);
unreserved = (alpha | digit | safe | extra | national);
escape = ("%" xdigit xdigit);
uchar = (unreserved | escape);
pchar = (uchar | ":" | "@" | "&" | "=" | "+");
scheme = ( alpha | digit | "+" | "-" | "." )+ ;
absolute_uri = (scheme ":" (uchar | reserved )*);
safepath = (pchar* (alpha | digit | safe) pchar*) ;
path = (safepath ( "/" pchar* )*) ;
query = ( uchar | reserved )* ;
param = ( pchar | "/" )* ;
params = (param ( ";" param )*) ;
rel_path = (path (";" params)?) ("?" query)?;
absolute_path = ("/"+ rel_path?);
target = ("#" pchar*) ;
uri = (target | absolute_uri | absolute_path | rel_path) ;

# common
title = ( '(' default+ >A %{ STORE("title"); } :> ')' ) ;
word = ( alnum | safe | " " ) ;
mspace = ( ( " " | "\t" | LF )+ ) -- LF{2} ;
mtext = ( chars (mspace chars)* ) ;

# conditionals
action starts_line {
p == orig_p || data[(p-1)] == '\r' || data[(p-1)] == '\n' || data[(p-1)] == '\f'
}
action starts_phrase {
p == orig_p || data[(p-1)] == '\r' || data[(p-1)] == '\n' || data[(p-1)] == '\f' || data[(p-1)] == ' '
}

}%%;

0 comments on commit fd82982

Please sign in to comment.