Skip to content

Commit

Permalink
added ml
Browse files Browse the repository at this point in the history
  • Loading branch information
hsk committed Jul 25, 2015
1 parent 7029cfe commit 0c5ba30
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 0 deletions.
81 changes: 81 additions & 0 deletions beautifier/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,84 @@

Scala,JavaScript,Pythonによる実装があります。

パーサコンビネータを作成して、n()でネストしたい文法を括れば、あとはうまい事やってくれます。

文法定義は以下のように非常にシンプルです。

処理速度は、ScalaはJVMの起動が遅い分遅く、JavaScriptが起動が速くて、処理速度も悪くない。Pythonは起動が速いけど処理速度が遅いという感じです。
ただ、文法的にJavaScriptは演算子のオーバーロードが出来ないので分かり辛く、Pythonは演算子の数が少ない。Scalaはより分かりやすいでしょう。

## Scala

object parse extends PrityPrintParser {

override protected val whiteSpace = """(?s)(\s|\(\*.*\*\))+""".r

def keywords = ( """(let|in|if|else|then|rec|begin|end|match|with|try)\b""".r )
def id = ( not(keywords) ~> """[_a-zA-Z0-9]+""".r ).
| ( """[+\-*/.<>=:@]+""".r ).
| ( """[,!]""".r ).
| ( """("(\\.|[^"])*")""".r )
def exp:Parser[Any]
= ( exps ~ rep(";" ~ exps) )
def exps = ( rep1(exp1) )
val exp1 = ( "begin" ~ n(exp) ~ "end" ).
| ( ("match" | "try") ~ n(exp) ~ "with" ~ opt("|") ~ n{exp} ~ rep("|" ~ n{exp}) ).
| ( "(" ~ n{opt(exp)} ~ ")" ).
| ( "{" ~ n{opt(exp)} ~ "}" ).
| ( "[" ~ n{opt(exp)} ~ "]" ).
| ( "let" ~ n(opt("rec") ~ exp) ~ "in" ~ exp ).
| ( "type" ~ n(id ~ "=" ~ exp) ~ ";;" ~ exp ).
| ( "type" ~ n{id ~ "=" ~ n(opt("|") ~ exp) ~ rep("|" ~ n(exp))} ~ ";;" ).
| ( "if" ~ n{exp} ~ "then" ~ n{exp} ~ "else" ~ exp ).
| ( id )

def apply(str: String):String = apply(exp,str)
}

## JavaScript

var keywords = reg(/^(let|in|if|else|then|rec|begin|end|match|with)\b/);

var id = (notp(keywords).next(reg(/^[_a-zA-Z0-9]+/)))
.or(reg(/^[+\-*\/.<>=:@]+/))
.or(reg(/^[,!]/))
.or(reg(/^("(\\.|[^"])*")/));
var exp1 = p("begin", n(exp), "end")
.or(p(p("match").or(p("try")), n(exp), "with", opt("|"), n(exp), rep(p("|", n(exp)))))
.or(p("(", n(opt(exp)), ")"))
.or(p("{", n(opt(exp)), "}"))
.or(p("[", n(opt(exp)), "]"))
.or(p("let", n(p(opt("rec"), exp)), "in", exp))
.or(p("type", n(p(id, "=", exp)), ";;", exp))
.or(p("type", n(id, "=", opt("|"), n(exp), rep(p("|", n(exp)))), ";;"))
.or(p("if", n(exp), "then", n(exp), "else", exp))
.or(id);
var exps = rep1(exp1);
function exp(i) {
return p(exps, rep(p(";", exps)))(i);
}

## Python

keywords = reg(r"^(let|in|if|else|then|rec|begin|end|match|with|type)\b")

id = notp(keywords) >> reg(r"^[_a-zA-Z0-9]+") \
| reg(r'^[+\-*\/.<>:@=][+\-*\/.<>:@=]*') \
| reg(r'^[,!]') \
| reg(r'^("(\\.|[^"])*")')

exp = p(lambda i: (exps + -p(notp(";;") >> p(";"), exps))(i))

exp1 = p("begin", n(exp), "end") \
| p("(", n(~exp), ")") \
| p("{", n(~exp), "}") \
| p("[", n(~exp), "]") \
| p("if", n(exp), "then", n(exp), "else", exp) \
| p("let", n(~p("rec"), exp), "in", exp) \
| p(p("match") | p("try"), n(exp), "with", ~p("|"), n(exp), -p("|", n(exp))) \
| p("function", ~p("|"), n(exp), -p("|", n(exp))) \
| p("type", n(id, "=", ~p("|"), n(exp), -p("|", n(exp))), ~p(";;")) \
| p("type", n(id, "=", exp), ~p(";;")) \
| p("open", n(id, -p(".", id)), ~p(";;")) \
| id
2 changes: 2 additions & 0 deletions beautifier/mincaml2js.scala
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ object test extends App {
*/
}

/*
object Universe {
implicit class RichList[T](self: List[T]) {
Expand Down Expand Up @@ -298,3 +299,4 @@ object Universe {
map(methodToString)
}
*/
8 changes: 8 additions & 0 deletions beautifier/src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
all:
ocamlyacc parser.mly
rm parser.mli
ocamllex lexer.mll
ocamlc syntax.ml parser.ml lexer.ml main.ml

clean:
rm -f *.cm* parser.ml lexer.ml a.out
83 changes: 83 additions & 0 deletions beautifier/src/lexer.mll
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
open Parser
}

let space = [' ' '\t' '\n' '\r']
let digit = ['0'-'9']
let lower = ['a'-'z']
let upper = ['A'-'Z']

rule token = parse
| space+ { token lexbuf }
| "(*" { comment lexbuf; token lexbuf }
| '(' { LPAREN }
| ')' { RPAREN }
| '[' { LBRACK }
| ']' { RBRACK }
| "::" { CONS }
| '@' { AT }
| "as" { AS }
| "begin" { BEGIN }
| "end" { END }
| "match" { MATCH }
| "with" { WITH }
| "when" { WHEN }
| "->" { ARROW }
| "|" { BAR }
| "type" { TYPE }
| "of" { OF }
| ";;" { SEMISEMI }
| "true" { BOOL("true") }
| "false" { BOOL("false") }
| "not" { NOT }
| digit+ { INT(Lexing.lexeme lexbuf) }
| digit+ ('.' digit*)? (['e' 'E'] ['+' '-']? digit+)?
{ FLOAT(Lexing.lexeme lexbuf) }
| '-' { MINUS }
| '+' { PLUS }
| '*' { AST }
| "-." { MINUS_DOT }
| "+." { PLUS_DOT }
| "*." { AST_DOT }
| "/." { SLASH_DOT }
| '=' { EQUAL }
| "<>" { LESS_GREATER }
| "<=" { LESS_EQUAL }
| ">=" { GREATER_EQUAL }
| '<' { LESS }
| '>' { GREATER }
| "if" { IF }
| "then" { THEN }
| "else" { ELSE }
| "let" { LET }
| "in" { IN }
| "rec" { REC }
| "mutable" { MUTABLE }
| "open" { OPEN }
| '{' { LBRACE }
| '}' { RBRACE }
| ':' { COLON }
| ',' { COMMA }
| '_' { IDENT("_") }
| '.' { DOT }
| "<-" { LESS_MINUS }
| ":=" { COLON_EQUAL }
| '!' { EXCLAM }
| ';' { SEMICOLON }
| eof { EOF }
| '"' ([^ '"' '\\'] | '\\' _)* '"' { let s = Lexing.lexeme lexbuf in STRING(String.sub s 1 ((String.length s)-2))}

| upper (digit|lower|upper|'_')* '.' lower (digit|lower|upper|'_')* { IDENT(Lexing.lexeme lexbuf) }
| upper (digit|lower|upper|'_')* { CIDENT(Lexing.lexeme lexbuf) }
| lower (digit|lower|upper|'_')* { IDENT(Lexing.lexeme lexbuf) }
| _ {
failwith
(Printf.sprintf "unknown token %s near characters %d-%d"
(Lexing.lexeme lexbuf)
(Lexing.lexeme_start lexbuf)
(Lexing.lexeme_end lexbuf)) }
and comment = parse
| "*)" { () }
| "(*" { comment lexbuf; comment lexbuf }
| eof { Format.eprintf "warning: unterminated comment@." }
| _ { comment lexbuf }
24 changes: 24 additions & 0 deletions beautifier/src/main.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
let lexbuf outchan l =
(Parser.exp Lexer.token l)

let string s = lexbuf stdout (Lexing.from_string s)

let file f =
let inchan = open_in (f ^ ".ml") in
let outchan = open_out (f ^ ".js") in
try
lexbuf outchan (Lexing.from_channel inchan);
close_in inchan;
close_out outchan;
with e -> (close_in inchan; close_out outchan; raise e)

let () =
let files = ref [] in
Arg.parse
[]
(fun s -> files := !files @ [s])
("Min-Caml beautifier\n" ^
Printf.sprintf "usage: %s ...filenames without \".ml\"..." Sys.argv.(0));
List.iter
(fun f -> ignore (file f))
!files
Loading

0 comments on commit 0c5ba30

Please sign in to comment.