From: Adam Megacz Date: Sat, 22 Jan 2011 06:23:06 +0000 (-0800) Subject: rewrite Haskell parts in Scala X-Git-Url: http://git.megacz.com/?p=wix.git;a=commitdiff_plain;h=13421e4b1878491e2607ca6d11c3f9b8bcf884b8 rewrite Haskell parts in Scala --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7cba725 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +lib/edu.berkeley.sbp.jar +wix.jar diff --git a/Makefile b/Makefile index 523c05b..a1373e3 100644 --- a/Makefile +++ b/Makefile @@ -11,18 +11,22 @@ ghc = $(ghcroot)/compiler/ghc-inplace -fallow-undecidable-instances -fallow- ghc += -fglasgow-exts -cpp -hidir $(pwd)/build/hi -i$(pwd)/build/hi -odir $(pwd)/build/class/ ghclibs = $(ghcroot)/rts/HSrts.jar:$(ghcroot)/libraries/base/HSbase.jar:$(ghcroot)/libraries/stm/HSstm.jar -java = java -Xmx800m -java += $(profile) -cp src:$(ghclibs):$(sbp)/edu.berkeley.sbp.jar:build/class +jvmargs = -Xmx800m -XX:ThreadStackSize=160000 + +java = java $(jvmargs) $(profile) -cp src:$(ghclibs):$(sbp)/edu.berkeley.sbp.jar:build/class + +scala = JAVA_OPTS="$(jvmargs)" scala wix = $(java) HaskellHelper -install: build/class/Main.class build/class/Tib.class - aklog hcoop.net || true +install: wix.jar aklog research.cs.berkeley.edu || true - $(wix) ~/wix/src/ ~/wix/dest/ + $(scala) -cp wix.jar:lib/edu.berkeley.sbp.jar Main ~/docs/wix/src/ ~/docs/wix/dest/ + +# --delete disabled until I can keep it from clobbering GArrow.v rsync -arL --rsync-path=/usr/sww/bin/rsync \ - --progress --verbose --delete \ - /Users/megacz/wix/dest/cs.berkeley.edu/ \ + --progress --verbose \ + ~/docs/wix/dest/cs.berkeley.edu/ \ login.eecs.berkeley.edu:public_html/ docs: @@ -34,14 +38,14 @@ $(sbp): $(sbp)/edu.berkeley.sbp.jar: $(sbp) cd $(sbp); make edu.berkeley.sbp.jar -wix.jar: build/class/Main.class build/class/Tib.class lib/edu.berkeley.sbp.jar - rm -rf tmp - mkdir tmp - cd build/class; for A in $(lambdavm_jars) lib/edu.berkeley.sbp.jar; \ - do jar xvf $$A; done - echo 'Main-Class: HaskellHelper' > build/manifest - cp src/*.g build/class/ - cd build/class; jar cvmf ../manifest ../../wix.jar . +wix.jar: $(shell find src -name \*.java -or -name \*.scala) + rm -rf build + mkdir build + javac -cp lib/edu.berkeley.sbp.jar -d build `find src -name \*.java` + scalac -deprecation -cp lib/edu.berkeley.sbp.jar -sourcepath src -d build `find src -name \*.scala` + echo 'Main-Class: Main' > build/manifest + cp src/*.g build/ + cd build; jar cvmf manifest ../wix.jar . build/class/Tib.class: $(shell find src -name \*.java) lib/edu.berkeley.sbp.jar javac -d build/class -cp lib/edu.berkeley.sbp.jar $(shell find src -name \*.java) diff --git a/entities.java b/entities.java new file mode 100644 index 0000000..bb197a2 --- /dev/null +++ b/entities.java @@ -0,0 +1,68 @@ + new Entity("tm", 0x2122), + new Entity("alef", 0x2135), + new Entity("leftArrow", "<--", 0x2190), + new Entity("rightArrow", "-->", 0x2192), + new Entity("leftDoubleArrow", "<==", 0x21D0), + new Entity("rightDoubleArrow", "==>", 0x21D2), + new Entity("doubleLeftRightArrow", "<==>", 0x21D4), + new Entity("upArrow", 0x2191), + new Entity("downArrow", 0x2193), + new Entity("upDoubleArrow", 0x21D1), + new Entity("downDoubleArrow", 0x21D3), + new Entity("forall", 0x2200), + new Entity("exists", 0x2203), + new Entity("emptySet", 0x2205), + new Entity("in", 0x2208), + new Entity("cent", 0xA2), + new Entity("pi", 0x220F), + new Entity("sigma", 0x2211), + new Entity("infinity", 0x221E), + new Entity("proportional", 0x221D), + new Entity("check", 0x221A), + new Entity("asterisk", 0x2217), + new Entity("minus", 0x2212), + new Entity("angle", 0x2220), + new Entity("and", 0x2227), + new Entity("or", 0x2228), + new Entity("intersection", 0x2229), + new Entity("union", 0x222A), + new Entity("integral", 0x222B), + new Entity("therefore", 0x2234), + new Entity("congruent", 0x2245), + new Entity("similarTo", 0x2248), + new Entity("identical", 0x2261), + new Entity("neq", 0x2260), + new Entity("subset", 0x2282), + new Entity("superset", 0x2283), + new Entity("notSubset", 0x2284), + new Entity("subsetEq", 0x2286), + new Entity("supersetEq", 0x2287), + new Entity("circlePlus", 0x2295), + new Entity("circleTimes", 0x2297), + new Entity("bottom", 0x22A5), + new Entity("cdot", 0x22C5), + new Entity("openDiamonds", 0x25CA), + new Entity("spade", 0x2660), + new Entity("clubs", 0x2663), + new Entity("hearts", 0x2665), + new Entity("diamonds", 0x2666), + new Entity("prime", 0x2032), + new Entity("reals", 0x211C), + new Entity("powerSet", 0x2118), + new Entity("overScore", 0x203E), + new Entity("yen", 0xA5), + new Entity("plusminus", 0xB1), + new Entity("micro", 0xB5), + new Entity("superScriptOne", 0xB9), + new Entity("superScriptTwo", 0xB2), + new Entity("superScriptThree", 0xB3), + new Entity("oneQuarter", 0xBC), + new Entity("oneHalf", 0xBD), + new Entity("threeQuarters", 0xBE), + new Entity("paragraphSymbol", 0xB6), + new Entity("times", 0xD7), + new Entity("daggar", 0x86), + new Entity("sectionSymbol", 0xA7), + new Entity("not", 0xAC), + new Entity("cr", 0x2193), + new Entity("dot", 0xB7), diff --git a/lib/edu.berkeley.sbp.jar b/lib/edu.berkeley.sbp.jar index cfbc206..22b8acf 100644 Binary files a/lib/edu.berkeley.sbp.jar and b/lib/edu.berkeley.sbp.jar differ diff --git a/src/Doc.scala b/src/Doc.scala new file mode 100644 index 0000000..76e4b55 --- /dev/null +++ b/src/Doc.scala @@ -0,0 +1,396 @@ +import edu.berkeley.sbp.scala._ + +import Html.mapToHtml +import Html.joinStrings +import Html.{urlEscape,htmlEscape} +import Html.{pre,stag,tag,stag_,tag_,stag0,link} + +object Doc { + + def concatMap[A,B](f: A => Seq[B], s:Seq[A]) : Seq[B] = + concat(s.map(f)) + + def concat[A](s:Seq[Seq[A]]) : Seq[A] = + s.foldLeft(Seq[A]())(_ ++ _) + + def docFromTree(t:Tree) : Doc = + t match { case Tree(_,Seq(_,Tree(_,a))) => new Doc(new Header(), a.map(sectionFromTree)) } + + def sectionFromTree(t:Tree) : Section = + t match { + case Tree("Section", seq) => + seq(0) match { + case Tree("SectionHeader", Seq(Tree("=",e),c)) => + new Section(e.length-1, textSequenceFromTree(c), paragraphsFromTrees(seq.tail)) + } + } + + def textSequenceFromTree (t:Tree) : Seq[Text] = + t match { + case Tree("Word", chars ) => Seq(new Chars(stringFromTrees(chars))) + case Tree("Ordinal", x ) => Seq(new Command("ordinal", Seq(new Chars(stringFromTrees(x))))) + case Tree("Fraction", Seq(n,d) ) => Seq(new Command("fraction",Seq(new Chars(stringFromTree(n)), + new Chars(stringFromTree(d))))) + case Tree("WS", _ ) => Seq(WS) + case Tree("Quotes", Seq(x) ) => Seq(new Quotes(textSequenceFromTree(x))) + case Tree("Pars", y ) => Seq(new SubPar(paragraphsFromTrees(y))) + case Tree("Command", Seq(x,y) ) => Seq(new Command(stringFromTree(x), textSequenceFromTree(y))) + case Tree("Command", Seq(x) ) => Seq(new Command(stringFromTree(x), Seq())) + case Tree("Link", Seq(text,link) ) => Seq(new Link(urlFromTree(link), textSequenceFromTree(text))) + case Tree("Footnote", x ) => Seq(new Footnote(concatMap(textSequenceFromTree,x))) + case Tree("Keyword", x ) => Seq(new Keyword(concatMap(textSequenceFromTree,x))) + case Tree("Math", x ) => Seq(new Math(stringFromTrees(x))) + case Tree("Italic", Seq(x) ) => Seq(new Styled(Italic , textSequenceFromTree(x))) + case Tree("Bold", Seq(x) ) => Seq(new Styled(Bold , textSequenceFromTree(x))) + case Tree("Highlight", Seq(x) ) => Seq(new Styled(Highlight , textSequenceFromTree(x))) + case Tree("TT", x ) => Seq(new Styled(TT , concatMap(textSequenceFromTree,x))) + case Tree("Strikethrough", x ) => Seq(new Styled(Strikethrough , concatMap(textSequenceFromTree,x))) + case Tree("Superscript", x ) => Seq(new Styled(Superscript , concatMap(textSequenceFromTree,x))) + case Tree("Subscript", x ) => Seq(new Styled(Subscript , concatMap(textSequenceFromTree,x))) + case Tree("Underline", x ) => Seq(new Styled(Underline , concatMap(textSequenceFromTree,x))) + case Tree("(e)", _) => Seq(new GlyphText(Euro)) + case Tree("(r)", _) => Seq(new GlyphText(CircleR)) + case Tree("(c)", _) => Seq(new GlyphText(CircleC)) + case Tree("(tm)", _) => Seq(new GlyphText(TradeMark)) + case Tree("--", _) => Seq(new GlyphText(Emdash)) + case Tree("<-", _) => Seq(new GlyphText(LeftArrow)) + case Tree("<=", _) => Seq(new GlyphText(DoubleLeftArrow)) + case Tree("=>", _) => Seq(new GlyphText(DoubleRightArrow)) + case Tree("<=>", _) => Seq(new GlyphText(DoubleLeftRightArrow)) + case Tree("<->", _) => Seq(new GlyphText(LeftRightArrow)) + case Tree("^o", _) => Seq(new GlyphText(Degree)) + case Tree("...", _) => Seq(new GlyphText(Ellipsis)) + case Tree("Text", ts) => concat(ts.map(textSequenceFromTree)) + case Tree("", Seq()) => Seq() + case t => throw new RuntimeException("unable to create [Text] from " + t) + } + + def hostFromTree(t:Tree) : Host = + t match { + case Tree("IP", Seq(Tree(_,a),Tree(_,b),Tree(_,c),Tree(_,d))) => + new HostIP(intFromTrees(a), intFromTrees(b), intFromTrees(c), intFromTrees(d)) + case Tree("DNS", parts) => + new HostDNS(parts.map( (t:Tree) => t match { case Tree(_, c) => stringFromTrees(c) })) + } + + def urlFromTree(t:Tree) : URL = + t match { + case Tree("URL", stuff) => urlFromTrees(stuff) + case Tree("Email", Seq(Tree("username", un),host)) => new URLEmail(stringFromTrees(un), hostFromTree(host)) + case Tree("Path",stuff) => new URLPath(stuff.map(fromUrlChar).foldLeft("")(_ + _)) + } + + def urlFromTrees(t:Seq[Tree]) : URL = + t match { + case Seq(Tree(_,method), login, host, port, rest @_*) => + new URLNormal(stringFromTrees(method), + None, + hostFromTree(host), + port match { case Tree("Port",port) => { + val q = stringFromTrees(port) + if (q.equals("")) None else Some(java.lang.Integer.parseInt(q)) + } + case _ => None }, + rest match { case Seq(Tree("Path",p), x@_*) => p.map(fromUrlChar).foldLeft("")(_ + _) + case _ => "" }, + rest match { case Seq(_ , Tree("Path",r), x@_*) => Some(stringFromTrees(r)) + case _ => None }) + } + + //fromUrlChar (Tree "%" [(Tree a [] _),(Tree b [] _)] _) = chr $ (fst $ head $ readHex (a++b)) + // FIXME: problem here is the "/" vs "%2F" issue, so we "leave urls urlencoded" + def fromUrlChar(t:Tree) : String = + t match { + case Tree("%", Seq(Tree(a,Seq()),Tree(b,Seq()))) => "%"+a+b + case Tree(x,y) => + if (x.length==1) x + else throw new RuntimeException("could not parse as URL char: " + t) + } + + def paragraphsFromTrees(ts:Seq[Tree]) : Seq[Paragraph] = + consolidate(concatMap(paragraphsFromTree,ts)) + + def paragraphsFromTree(t:Tree) : Seq[Paragraph] = + consolidate (t match { + case Tree("Verbatim", Seq(indent,v)) => Seq(new P( Seq(new Verbatim(unindent(indent,unverbate(v)))))) + case Tree("TextParagraph", Seq(Tree(_,text))) => Seq(new P(concatMap(textSequenceFromTree,text))) + case Tree("Pars", pars ) => concatMap(paragraphsFromTree,pars) + case Tree("HR", _ ) => Seq(HR) + case Tree("OL", a ) => + Seq(new OL(a.map( (t:Tree) => t match { case Tree("LI",x) => paragraphsFromTrees(x)}))) + case Tree("UL", a ) => + Seq(new UL(a.map( (t:Tree) => t match { case Tree("LI",x) => paragraphsFromTrees(x)}))) + case Tree("", _ ) => Seq() + case Tree("Blockquote", pars ) => Seq(Blockquote(paragraphsFromTrees(pars))) + case _ => throw new RuntimeException("unable to create [Paragraph] from " + t) + }) + + def unverbate (t:Tree) : String = + t match { + case Tree("Verbatim",x) => x.map(unverbate).foldLeft("")(_ + _) + case Tree("VerbatimBrace",Seq(x,y)) => unverbate(x)+" "+unverbate(y) + case Tree(t,Seq()) => t + } + + def unindent (t:Tree,v:String) : String = + t match { + case Tree("I", indent) => unindent_(indent.length+1, v) + } + + private def unindent_ (i:Int,v:String) : String = + if (v.length==0) "" + else if (v.charAt(0) == '\n') "\n"+unindent_(i, drop_(i, v.substring(1))) + else v.charAt(0)+unindent_(i, v.substring(1)) + + private def drop_(n:Int, x:String) : String = { + val x_ : Seq[Char] = x; + if (n==0) x + else (x_ match { + case Seq('\n', r@_*) => x + case Seq() => "" + case Seq(a, b@_*) => drop_(n-1, x.substring(1)) + }) + } + + def consolidate(x:Seq[Paragraph]) : Seq[Paragraph] = + x match { + case Seq() => Seq() + case Seq(a) => Seq(a) + case Seq(OL(Seq()), x@_*) => consolidate(x) + case Seq(UL(Seq()), x@_*) => consolidate(x) + case Seq(OL(a), OL(b), x@_*) => consolidate(Seq(OL(a++b))++x) + case Seq(UL(a), UL(b), x@_*) => consolidate(Seq(UL(a++b))++x) + case Seq(a, b @_*) => Seq(a)++consolidate(b) + } + + def intFromTrees(t:Seq[Tree]) : Int = + java.lang.Integer.parseInt(stringFromTrees(t)) + def stringFromTree(t:Tree) : String = + t match { case Tree(h,c) => h++concatMap(stringFromTree,c) } + def stringFromTrees(ts:Seq[Tree]) : String = + ts.map(stringFromTree).foldLeft("")(_ + _) + +} + +class Doc (val header:Header, val sections:Seq[Section]) extends ToHtml { + override def toHtml = + "\n"+ + "\n\n"+ + "\n"+ + "\n"+ + Html.style+ + // FIXME: title tag + "\n"+ + "\n"+ // tell jsmath we will escape stuff manually + Html.jsMath+ // FIXME: only put this in if math appears on the page + "
\n"+ + mapToHtml(sections)+ + "

\n"+ + ""+ + "\n"+ + "
\n"+ + "" +} + +class Header() + +class Section (val level:Int, val header:Seq[Text], val paragraphs:Seq[Paragraph]) extends ToHtml { + def toHtml = "\n\n"+(mapToHtml(header))+"\n\n"+(mapToHtml(paragraphs)) } + +abstract class Paragraph extends ToHtml + case class P (val body :Seq[Text] ) extends Paragraph { override def toHtml = stag_("p",body) } + case object HR extends Paragraph { override def toHtml = stag("hr") } + case class OL (val items:Seq[Seq[Paragraph]] ) extends Paragraph { + override def toHtml = stag0("ol", items.map( (s:Seq[Paragraph]) => stag_("li", s) ).foldLeft("")(_ + _)) } + case class UL (val items:Seq[Seq[Paragraph]] ) extends Paragraph { + override def toHtml = stag0("ul", items.map( (s:Seq[Paragraph]) => stag_("li", s) ).foldLeft("")(_ + _)) } + case class Blockquote (val body :Seq[Paragraph] ) extends Paragraph { + override def toHtml = + "\n\n"+ + "\n"+ + "
\n"+ + mapToHtml(body)+ + "
\n" + } + +abstract class Style + case object TT extends Style + case object Underline extends Style + case object Superscript extends Style + case object Subscript extends Style + case object Strikethrough extends Style + case object Italic extends Style + case object Bold extends Style + case object Highlight extends Style + +abstract class Text extends ToHtml + case object WS extends Text { def toHtml = " " } + case class Chars(val body:String) extends Text { def toHtml = htmlEscape(body) } + case class Quotes(val body:Seq[Text]) extends Text { def toHtml = "“"+mapToHtml(body)+"”" } + case class GlyphText(val body:Glyph) extends Text { override def toHtml = body.toHtml } + case class Math(val body:String) extends Text { override def toHtml = "" +body+ "" } + case class Verbatim(val body:String) extends Text { override def toHtml = pre(body) } + case class Link(val url:URL, val body:Seq[Text]) extends Text { override def toHtml = link(url.toString, body) } + case class Footnote(val body:Seq[Text]) extends Text { override def toHtml = throw new Exception() } + case class Keyword(val body:Seq[Text]) extends Text { override def toHtml = tag_("tt", body) } + case class SubPar(val body:Seq[Paragraph]) extends Text { override def toHtml = stag_("p", body) } + case class Styled(val style:Style, val body:Seq[Text]) extends Text { + override def toHtml = + style match { + case Underline => tag_("u", body) + case TT => tag_("tt", body) + case Italic => tag_("i", body) + case Strikethrough => tag_("strike", body) + case Superscript => tag_("sup", body) + case Subscript => tag_("sub", body) + case Bold => tag_("b", body) + case Highlight => ""+mapToHtml(body)+"" + } + } + case class Command(val command:String, val body:Seq[Text]) extends Text { + override def toHtml = + command match { + case "comment" => "" + case "url" => ""+link(mapToHtml(body),body)+"" + case "WiX" => "WIX" + case "TeX" => "TEX" + case "red" => ""+mapToHtml(body)+"" + case "orange" => ""+mapToHtml(body)+"" + case "green" => ""+mapToHtml(body)+"" + case "sc" => ""+mapToHtml(body)+"" + case "image" => "" + case "imagec" => "
" + case "image2" => "" + case "image3" => "" + case "image4" => "
" + case "warn" => "\n
\n\n"+ + "\n"+ + "
\n"+ + mapToHtml(body)+ + "
\n" + case "announce" => "\n
\n\n"+ + "\n"+ + "
\n"+ + mapToHtml(body)+ + "
\n" + case "br" => "\n
\n" + case "cent" => "½" + case "euro" => "€" + // gross hack + case "ordinal" => { + val x = mapToHtml(body) + if (x.charAt(x.length-1) == '1') x+""+"st"+"" + else if (x.charAt(x.length-1) == '2') x+""+"nd"+"" + else if (x.charAt(x.length-1) == '3') x+""+"rd"+"" + else x+""+"th"+"" + } + // TO DO: use "unicode vulgar fractions" here + // directional quotes: see http://www.dwheeler.com/essays/quotes-in-html.html + /* u'1/2' : u'\u00BD', + // u'1/4' : u'\u00BC', + // u'3/4' : u'\u00BE', + // u'1/3' : u'\u2153', + // u'2/3' : u'\u2154', + // u'1/5' : u'\u2155', + // u'2/5' : u'\u2156', + // u'3/5' : u'\u2157', + // u'4/5' : u'\u2158', + // u'1/6' : u'\u2159', + // u'5/6' : u'\u215A', + // u'1/8' : u'\u215B', + // u'3/8' : u'\u215C', + // u'5/8' : u'\u215D', + // u'7/8' : u'\u215E', + */ + case "fraction" => ""++body(0).toHtml++""++"/"++""++body(1).toHtml++"" + case "rfc" => "RFC"+mapToHtml(body)+"" + case "keystroke:command" => "⌘" + case "keystroke:shift" => "⇧" + case "keystroke:option" => "⌥" + case "keystroke:control" => "⌃" + case "keystroke:capslock" => "⇪" + case "keystroke:apple" => "" + case _ => throw new RuntimeException("unsupported command " + command) + } + } + + +abstract class Glyph extends ToHtml + case object Euro extends Glyph { override def toHtml = "€" } + case object CircleR extends Glyph { override def toHtml = "¢" } + case object CircleC extends Glyph { override def toHtml = "®" } + case object TradeMark extends Glyph { override def toHtml = "™" } + case object ServiceMark extends Glyph { override def toHtml = "™" } + case object Emdash extends Glyph { override def toHtml = "—" } + case object Ellipsis extends Glyph { override def toHtml = "…" /* &cdots;? */ } + case object Cent extends Glyph { override def toHtml = "½" } + case object Daggar extends Glyph { override def toHtml = "†" } + case object DoubleDaggar extends Glyph { override def toHtml = "‡" } + case object Clover extends Glyph { override def toHtml = "⌘" } + case object Flat extends Glyph { override def toHtml = "⋖" } + case object Natural extends Glyph { override def toHtml = "⋗" } + case object Sharp extends Glyph { override def toHtml = "⋘" } + case object CheckMark extends Glyph { override def toHtml = "✓" } + case object XMark extends Glyph { override def toHtml = "✗" } + case object LeftArrow extends Glyph { override def toHtml = "←" } + case object RightArrow extends Glyph { override def toHtml = "→" } + case object DoubleLeftArrow extends Glyph { override def toHtml = "&#;" /* FIXME */ } + case object DoubleRightArrow extends Glyph { override def toHtml = "&#;" /* FIXME */ } + case object DoubleLeftRightArrow extends Glyph { override def toHtml = "&#;" /* FIXME */ } + case object LeftRightArrow extends Glyph { override def toHtml = "&#;" /* FIXME */ } + case object Degree extends Glyph { override def toHtml = "&#;" /* FIXME */ } + +class Login(val user:String, val password:Option[String]) { + override def toString = + password match { + case None => user + case Some(x) => user+":"+urlEscape(x) } +} + +abstract class URL + case class URLPath(val path:String) extends URL { override def toString = path } + case class URLEmail(val user:String, val host:Host) extends URL { override def toString = "mailto:"+user+"@"+host } + case class URLNormal(val method:String, + val login:Option[Login], + val host:Host, + val port:Option[Int], + val path:String, + val ref:Option[String]) extends URL { + override def toString = + method+"://"+ + (login match { + case None => "" + case Some(log) => log+"@" })+ + host+ + "/"+ + path+ + (ref match { + case None => "" + case Some("") => "" + case Some(x) => "#"+x }) + + } + + +abstract class Host + case class HostIP(val ip0:Int, val ip1:Int, val ip2:Int, val ip3:Int) extends Host { + override def toString = ip0+"."+ip1+"."+ip2+"."+ip3 } + case class HostDNS(val parts:Seq[String]) extends Host { + override def toString = joinStrings(parts, ".") } + + + + + + + + + + + + + + diff --git a/src/HaskellHelper.java b/src/HaskellHelper.java index a9efb30..4e3b2c6 100644 --- a/src/HaskellHelper.java +++ b/src/HaskellHelper.java @@ -91,6 +91,7 @@ public class HaskellHelper { } System.out.println(ANSI.green("copying: "+f.getPath())); File dest_ = new File(outdir.getAbsolutePath()+File.separatorChar+suffix+"-"); + new File(dest_.getParent()).mkdirs(); FileOutputStream fos = new FileOutputStream(dest_); FileInputStream fis = new FileInputStream(f); byte[] buf = new byte[1024]; @@ -115,6 +116,7 @@ public class HaskellHelper { Class.forName("Main"). getMethod("main", new Class[] { String[].class }). invoke(null, new Object[] { new String[] { f.getAbsolutePath() } }); + try { new File(new File(outPath).getParent()).mkdirs(); PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(outPath+"+"))); pw.println(ret); @@ -122,7 +124,6 @@ public class HaskellHelper { pw.close(); File dest = new File(outPath); if (dest.exists()) { - try { Process p = Runtime.getRuntime().exec(new String[] { "diff", "-Bub", @@ -138,13 +139,13 @@ public class HaskellHelper { /*else System.out.println(ANSI.blue(s));*/ } p.waitFor(); - } catch (Exception e) { - e.printStackTrace(); - } } new File(outPath+"+").renameTo(dest); if (dest.lastModified() <= f.lastModified()) dest.setLastModified(f.lastModified()+1); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/src/Html.scala b/src/Html.scala new file mode 100644 index 0000000..8ffdea3 --- /dev/null +++ b/src/Html.scala @@ -0,0 +1,216 @@ +trait ToHtml { + def toHtml : String +} + +object Html { + + def style : String = + "\n\n" + + def quoteIconBase64 = + "data:image/png;base64,"+ + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAVCAYAAABPPm7SAAAABmJLR0QA/wD/AP+gvaeTAAAA"+ + "CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wQPAx0rP5obpAAAAWJJREFUOMvdlKFvg0AU"+ + "xr8tVZ1cbU+04lUuwc2WypMX9AxiomoJ/RNYqmaaYKpb5kBys1UkWBCdKLqVs8zwFnrQmYol"+ + "+xLC8X55H/e+wAENhWGoPM/zT6eThQ4lSWJf5EEQuAAqAJXv+95vXCkVtpwZuq4bmM1pmlrM"+ + "LctKWzuwbTsBUNX3lph3Njfd6/WZ9vv9iHkYhsrkPa21zQ9aa9v3fRsAFovFK9cMPgIApdT7"+ + "eDz+RB1Y1XEBwEVe54ZbXKm/N7haNwCQ5zmtVqtnE0op49lspgFgPp+/dfF/EGIPAAaDgZBS"+ + "xgBwPB7vd7vdIwD0+/2v5ry8juNYmgY/P1GWZQ9sQER3XOcwD4fDkA2IqGiNwN8+ERVNY/Pt"+ + "RFQIIcozg+Vy+VKW5dDcMmuz2ThFURAATKfTj7MQ1+v1Ezc7jrMVQpTmocOjOY6znUwmRSvR"+ + "KIpknud0KfEoimSWZQ/N2jfhtb1AvGklDQAAAABJRU5ErkJggg==" + + def warnIconBase64 = + "data:image/png;base64,"+ + "iVBORw0KGgoAAAANSUhEUgAAABQAAAAREAYAAACN1FD9AAAABmJLR0QA/wD/AP+gvaeTAAAA"+ + "CXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAUAAAAEQDeTN6UAAAD/ElEQVRIx8WUbUyV"+ + "ZRjHf+chxDi8yZcDa0mKh/wSuNE5eNYHZBiRwoespayEkdgx22hmjB1glTlenDYlMccAX1cb"+ + "CDFlg+aQ1JGEazGWpixdbbweDucctPF2PNxXX3pw00gL09+X59m1+77+v+d+nueCBRJ+ECAs"+ + "78dnAPp2nLEDtMdpPwMYZhfaf8GU1gLsixwdBRDRr7lRAHmxT0zs+UKAuKmhXgDfGleAYZVh"+ + "lXynC/Z1AYyeX+IFiLjw+MwWAxDQuBqgNVsX+iNta/nWcnV0vD+9Ir1CndDre68AfDH42PzW"+ + "2QDW79UFxkxh6WHp8o5a5lznXCfJ/nPX867nSYArO7AssEyOjOwE8GfGZwC84Pu3edrDLgzK"+ + "AFj06q7DAPt/1evBK4szizMlpXy4tqO2g/MHa9sm2ibwP23M78zvFE0rBAg4U24DqFpieAqA"+ + "6kd+cjuiAAqu6Sfn/n55/fJ6CZOc6YHpATmkNWgNWoOIZtSMmlFE1d9ae2utvDt21ZRiSpHV"+ + "+r43LwFkBT4ysehigKgDvxcC3P5QD5qxNtU11anj8hfhg+GD4YMixipjlbFK5pjyHok8Enn3"+ + "m7yyG2DAEdIFYLy9YMHDLoBjK/WA8fhkb7JXtcqMnJbT4tJFYlpiWmJaRKJio2KjYu8KSp9K"+ + "UAly2ZtpSbWkql/0PrsuAJR3/2cx65cA1qujRgBV6HpWy9fy5dydOz2JPYlqQO4hwZ/gT/CL"+ + "mB1mh9kh93Enq2tP1x7V4wo0pBnS5KehVwBmPjA7AcxtDy2mBQIYPmk/B/CDb26MxGw5teWU"+ + "+krmIdWaak21iiR2JHYkdsi83G7KtmRb1HG9b+PHAK2lJAEQ9EDBt88C5BybGyOLQgtCC8Su"+ + "gkesI1axzRd8Mvdk7slckeoN1RuqN8wvODsyVDNUIxaXP0SFKHlfz8l4GSDTfd+B6Tdh5QCh"+ + "hUUvAlR8o9eDI4qSipLkJcOEqdvUzaX5HmzSNGmaNMFN+037TTvgxInzb96QKTovOo/LRmuJ"+ + "r8QnFr3+2esAB/IX9wAEjd+3cfc+gD2euTFSv2zzss0SIdnTG6c3SqU8AFulrdJWKRJSElIS"+ + "UiLia/Y1+5r/YcNHM9tntku1e2KFZ4VHAvXcwnyAksY5MfNvAOYdQ+8BzHytL5warDtRd2I2"+ + "QjWNh46HqjR11LvGu0aVqUOei56LYlD7PRWeCmlWpe4p95R87h66Yb9hV+7+o71BvUHKoWyj"+ + "jlGHSlbPOTc5N6kkFTqybWSbeksxfHb4rGqd9Q3nDOdI5lRHTXtNu6rWc/vfAJjoXHoNYOl6"+ + "Q70CaFEpYwAZhof+m/5nvv0UoDFLW/UagCXuSQvdSzwAiTv/BGXg1AxNKyCeAAAAAElFTkSu"+ + "QmCC" + + def printIconBase64 = + "data:image/png;base64,"+ + "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAOCAMAAADHVLbdAAAALHRFWHRDcmVhdGlvbiBUaW1l"+ + "AEZyaSAxOSBTZXAgMjAwMyAxODozOTozMiAtMDAwME2jAt8AAAAHdElNRQfTCRMRKABXeznM"+ + "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAACRQTFRF////AAAA7+/v"+ + "3t7ezs7OtbW1ra2tlJSUnJycEBAQKSkphISEbGtEogAAAAF0Uk5TAEDm2GYAAABLSURBVHja"+ + "nY1BEsAgCAMDKm31//81qB3l6h4Y4mYQQNvAmXNv7W/gytcTRj6pppQHNWoW6JWS13Ix86yr"+ + "O7MEPkDWuWLPK/7hoYEOxksDsk8eppEAAAAASUVORK5CYII=" + + def emailIconBase64 = + "data:image/png;base64,"+ + "iVBORw0KGgoAAAANSUhEUgAAABUAAAAOCAMAAAD32Kf8AAAALHRFWHRDcmVhdGlvbiBUaW1l"+ + "AEZyaSAxOSBTZXAgMjAwMyAxODo0MjowOSAtMDAwMBDwv7IAAAAHdElNRQfTCRMRKhqYL6I0"+ + "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAADBQTFRF////AAAAhISE"+ + "9/fv9/f3////CAgI7+/v1tbOxsa9tbWtpaWclJSMlJSUe3t7a2trxDv8WgAAAAF0Uk5TAEDm"+ + "2GYAAABiSURBVHjabc9JEoAgDETRpNOKs/e/rSEYF8jfhHpQFAi6JHpHBg5VOdIj+KeXkgO9"+ + "tUj/Bldo3WdRnktt3fbjgoWKK5EKsunkyryCn86Oxsj/UZqKEkFmNF+mvieFdSK16wFr7QK5"+ + "tASqkwAAAABJRU5ErkJggg==" + + def pdfIconBase64 = + "data:image/png;base64,"+ + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAK3RFWHRDcmVhdGlvbiBUaW1l"+ + "AFRodSA2IE5vdiAyMDAzIDE1OjMwOjAwIC0wMDAwSwt8PwAAAAd0SU1FB9MLBg8fD1x8/t4A"+ + "AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAEZ0FNQQAAsY8L/GEFAAAAQlBMVEX///9zc3Nra2uE"+ + "hITGxsaUlJScnJx7e3uMjIz////39/fv7+/n5+fe3t69vb1jY2OlpaXW1ta1tbVaWlqtra3O"+ + "zs5w48BYAAAAAXRSTlMAQObYZgAAAIdJREFUeNpNz1ESBBEMBNCRwSCJMOT+V10WW9vKz6uO"+ + "iusa0R137ShxjImwHsnSMCbEX6dPiIje+SUKC6hav8CbAQlZD/RmJ1Tdz6oTwETMfAByK0hT"+ + "1kgH7E1phFfjdvS2JlJpN8RAyEHMhgJgaexJTBPyA1JiGoD0BXgg2H8wcFs3/jDvPB+sOwir"+ + "+o6iKQAAAABJRU5ErkJggg==" + + def jsMath = + "\n"+ + "\n"+ + "\n"+ + "\n" + + def urlEscape (s:Seq[Char]) = + s.map(urlEscapeChar).foldLeft("")(_ + _) + + def htmlEscape (s:Seq[Char]) = + s.map(htmlEscapeChar).foldLeft("")(_ + _) + + private def urlEscapeChar (c:Char) : String = + c match { + // non-alphanumerics which may appear unescaped + case '$' => "$" + case '-' => "-" + case '_' => "_" + case '.' => "." + case '!' => "!" + case '*' => "*" + case '\'' => "\'" + case '(' => "(" + case ')' => ")" + case ',' => "," + + // technically these aren't allowed by RFC, but we include them anyways + case '/' => "/" + case ';' => ";" + case '&' => "&" + case '=' => "=" + + // FIXME: this will wind up "disencoding" a %-encoded question mark + case '?' => "?" + + case _ => { + if ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')) + 'c'+"" + else { + val s = "00"+java.lang.Integer.toString(c & 0xff, 16) + return '%'+s.substring(s.length()-1, 2) + } + } + } + + private def htmlEscapeChar (c:Char) = + c match { + case '<' => "<" + case '>' => ">" + case '&' => "&" + case '\'' => "'" + case '\"' => """ + case c => ""+c + } + + def mapToHtml[A <: ToHtml](h:Seq[A]) : String = + h.map((s:A) => s.toHtml).foldLeft("")(_ + _) + + def joinStrings(strings:Seq[String], separator:String) = + if (strings.length == 0) "" + else if (strings.length == 1) strings(0) + else strings(0)+strings.tail.map( (s:String) => separator+s ).foldLeft("")(_ + _) + + def stag(t:String) = "\n<"+t+">\n" + def stag(t:String, body:ToHtml) = "\n<"+t+">\n"+body.toHtml+"\n\n" + def stag0(t:String, body:String) = "\n<"+t+">\n"+body+"\n\n" + def tag(t:String, body:ToHtml) = "<"+t+">"+body.toHtml+"" + def stag_(t:String, body:Seq[ToHtml]) = "\n<"+t+">\n"+mapToHtml(body)+"\n\n" + def tag_(t:String, body:Seq[ToHtml]) = "<"+t+">"+mapToHtml(body)+"" + + def link(ref:String, body:Seq[ToHtml]) : String = { + val img = "style='vertical-align: text-bottom;' border=0 " + val icon = if (ref.endsWith(".pdf")) " " + else if (ref.startsWith("mailto:")) " " + else "" + return ""+icon+mapToHtml(body)+"" + } + + private def pre_(c:Char) : String = + c match { + case ' ' => " " + case '\n' => "
\n" + case a => htmlEscapeChar(a) + } + + def pre(x:String) : String = + "\n
"+(x.map(pre_).foldLeft("")((a,b:String) => a + b))+"\n
\n" + +} + diff --git a/src/Main.scala b/src/Main.scala new file mode 100644 index 0000000..2cd9e44 --- /dev/null +++ b/src/Main.scala @@ -0,0 +1,15 @@ +import edu.berkeley.sbp.Tree +import edu.berkeley.sbp.scala.SBP + +class Main extends TreeToString { + + override def run(t:edu.berkeley.sbp.Tree[String]) : String = + Doc.docFromTree(SBP.mkTree(t)).toHtml +} + +object Main { + + def main(args:Array[String]) = + ScalaHelper.main(args, new Main()) + +} diff --git a/src/ScalaHelper.java b/src/ScalaHelper.java new file mode 100644 index 0000000..85065e2 --- /dev/null +++ b/src/ScalaHelper.java @@ -0,0 +1,154 @@ +// Copyright 2011 the Contributors, as shown in the revision logs. +// Licensed under the Apache Public Source License 2.0 ("the License"). +// You may not use this file except in compliance with the License. +import edu.berkeley.sbp.*; +import edu.berkeley.sbp.misc.*; +import edu.berkeley.sbp.util.*; +import edu.berkeley.sbp.meta.*; +import edu.berkeley.sbp.chr.*; +import java.io.*; + +public class ScalaHelper { + public static boolean isNull(Object o) { return o==null; } + + private static CharParser parser = null; + static { + synchronized(ScalaHelper.class) { + if (parser == null) { + try { + // FIXME: bundle this into the jarfile + InputStream grammarFile = ScalaHelper.class.getClassLoader().getResourceAsStream("wix.g"); + Tree res = new CharParser(GrammarAST.getMetaGrammar()) + .parse(grammarFile).expand1(); + Union grammar = GrammarAST.buildFromAST(res, "s", new GrammarAST.ImportResolver() { + public InputStream getImportStream(String filename) { + return this.getClass().getClassLoader().getResourceAsStream(filename); + } + }); + parser = new CharParser(grammar); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + + public static Tree parseFile(String targetFile) throws Throwable { + Tree ret = null; + try { + Reader r = new InputStreamReader(new FileInputStream(targetFile)); + Input input = new CharInput(new IndentingReader(r, CharAtom.left, CharAtom.right)); + ret = parser.parse(input).expand1(); + } catch (Throwable e) { + e.printStackTrace(); + throw e; + } + if (ret==null) throw new NullPointerException("CharParser returned null"); + return ret; + } + + public static void main(String[] argv, TreeToString t2s) throws Throwable { + if (argv.length != 2) { + System.out.println("usage: java -jar wix.jar [-v] "); + // FIXME: implement this + System.out.println(" | java -jar wix.jar [-v] .wix"); + System.out.println(""); + // FIXME: implement these + System.out.println(" -v print text as it is parsed (sbp.verbose=true)"); + System.out.println(" -vv like -v, but also dump parse tree"); + System.out.println(" -vvv like -vv, but also dump wix tree"); + System.exit(-1); + return; + } + File indir = new File(argv[0]); + File outdir = new File(argv[1]); + if (!indir.isDirectory()) { + process(new File(indir.getParent()), indir.getName(), outdir, t2s); + } else { + process(indir, "", outdir, t2s); + } + } + + private static void process(File indir, String suffix, File outdir, TreeToString t2s) throws Throwable { + File f = new File(indir.getAbsolutePath()+File.separatorChar+suffix); + //System.out.println(f+" "+indir + " " + suffix + " " + outdir); + if (!f.exists()) return; + if (f.isDirectory()) { + for (String s : f.list()) + process(indir, suffix + File.separatorChar + s, outdir, t2s); + return; + } + if (!f.getPath().endsWith(".wix")) { + boolean skip = false; + if (f.getName().equals(".DS_Store")) skip = true; + if (f.getName().equals("._.DS_Store")) skip = true; + if (f.getName().endsWith("-")) skip = true; + if (!skip) { + File dest = new File(outdir.getAbsolutePath()+File.separatorChar+suffix); + if (dest.exists() && dest.lastModified()==f.lastModified() && dest.length()==f.length()) { + System.out.println(ANSI.yellow("no change: "+f.getPath())); + return; + } + System.out.println(ANSI.green("copying: "+f.getPath())); + File dest_ = new File(outdir.getAbsolutePath()+File.separatorChar+suffix+"-"); + new File(dest_.getParent()).mkdirs(); + FileOutputStream fos = new FileOutputStream(dest_); + FileInputStream fis = new FileInputStream(f); + byte[] buf = new byte[1024]; + while(true) { + int numread = fis.read(buf, 0, buf.length); + if (numread==-1) break; + fos.write(buf, 0, numread); + } + fos.close(); + fis.close(); + dest_.renameTo(dest); + dest.setLastModified(f.lastModified()); + } + } else { + String out = "== " + suffix + " "; + while(out.length() < 75) out+="="; + System.out.println(ANSI.yellow(out)); + //System.out.println(); + String outPath = outdir.getAbsolutePath()+File.separatorChar+suffix; + outPath = outPath.substring(0, outPath.length()-".wix".length())+".html"; + if (new File(outPath).exists() && new File(outPath).lastModified() > f.lastModified()) return; + + Tree tree = parseFile(f.getAbsolutePath()); + String ret = t2s.run(tree); + try { + new File(new File(outPath).getParent()).mkdirs(); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(outPath+"+"))); + pw.println(ret); + pw.flush(); + pw.close(); + File dest = new File(outPath); + if (dest.exists()) { + Process p = Runtime.getRuntime().exec(new String[] { + "diff", + "-Bub", + dest.getAbsolutePath(), + new File(outPath+"+").getAbsolutePath() + }); + BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); + br.readLine(); + br.readLine(); + for(String s = br.readLine(); s != null; s = br.readLine()) { + if (s.startsWith("+")) System.out.println(ANSI.green(s)); + else if (s.startsWith("-")) System.out.println(ANSI.red(s)); + /*else System.out.println(ANSI.blue(s));*/ + } + p.waitFor(); + } + new File(outPath+"+").renameTo(dest); + if (dest.lastModified() <= f.lastModified()) + dest.setLastModified(f.lastModified()+1); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public static Object ret; + public static void putBack(String o) { ret = o; } +} diff --git a/src/TreeToString.java b/src/TreeToString.java new file mode 100644 index 0000000..ad9235a --- /dev/null +++ b/src/TreeToString.java @@ -0,0 +1,5 @@ +import edu.berkeley.sbp.*; + +public interface TreeToString { + public abstract String run(Tree t); +} \ No newline at end of file