## ml-grinder.pkg
#
# The core of the ML-Grinder library
### Never tell the truth to people who are not worthy of it.
###
### -- Mark Twain,
### Notebook, 1902
local
Author = "Allen Leung"
Email = "leunga@cs.nyu.edu, leunga@dorsai.org"
Version = "1.2.4"
basisForTheMatchCompiler =
string::cat
[ "enum List X = NIL
| . of X * List(X)\n",
"enum Null_Or X = NULL
| THE of X\n",
"enum order = LESS
| EQUAL | GREATER\n"
]
in
package ml_grinder :> Ml_Grinder {
package pp = pp
package re = reg_exp_lib
package err = adl_error
package raw = adl_raw_syntax
package raw_util = adl_raw_syntax_junk
package raw_pp = adl_raw_syntax_unparser
package map_raw_syntax = adl_rewrite_raw_syntax_parsetree
package raw_trans = adl_raw_syntax_translation
package raw_consts = adl_raw_syntax_constants
package parser
=
architecture_description_language_parser_g (
#
package rsu = raw_pp # "rsu" == "raw_syntax_unparser"
adl_mode = FALSE extra_cells = []
)
package match_generic
=
match_gen_g ( # See
src/lib/compiler/back/low/tools/match-compiler/match-gen-g.pkg package rsu = raw_pp # "rsu" == "raw_syntax_unparser"
package rsj = raw_util # "rsj" == "raw_syntax_junk"
package map_raw_syntax = map_raw_syntax
)
# package html_g = html_g
package r = map_raw_syntax
package u = raw_util
package m = match_generic
package p = parser
package tr = raw_trans
i2s = int::to_string
my ++ = pp.++
infix ++
type labeled X = raw::id * X
line_width = REF 160
nolocations = raw_trans::stripMarks
fakeId = "__fake_id__"
# Pretty print as code
fun asML prog
=
pp::lit (pp::setmode "code" ++ pp::text_width *line_width ++ prog)
# Error handling stuff
exception MLGrinderErrorMsg of String
error = err::error
warning = err::warning
fun bug (fn, msg)
=
{ msg = "ml_grinder error: " + fn + ": " + msg;
error msg;
raise exception MLGrinderErrorMsg msg;
}
fun fail msg
=
{ error msg;
raise exception MLGrinderErrorMsg msg;
}
silent = REF FALSE
fun comment text
=
A.@@@("" . "/* " . map (\\ c => " * " + c) text @ [" */", ""])
package map {
enum rule = E of raw::exp -> raw::exp
| SE of raw::structexp -> raw::structexp
| D of raw::decl -> raw::decl
| T of raw::ty -> raw::ty
| P of raw::pat -> raw::pat
};
package rewrite {
enum rule = E of (raw::exp -> raw::exp) -> raw::exp -> raw::exp
| SE of (raw::structexp -> raw::structexp) ->
raw::structexp -> raw::structexp
| D of (raw::decl -> raw::decl) -> raw::decl -> raw::decl
| T of (raw::ty -> raw::ty) -> raw::ty -> raw::ty
| P of (raw::pat -> raw::pat) -> raw::pat -> raw::pat
};
package fold {
enum rule X = E of raw::exp * X -> X
| SE of raw::structexp * X -> X
| D of raw::decl * X -> X
| T of raw::ty * X -> X
| P of raw::pat * X -> X
};
package app {
enum rule = E of raw::exp -> Void
| SE of raw::structexp -> Void
| D of raw::decl -> Void
| T of raw::ty -> Void
| P of raw::pat -> Void
};
package subst {
enum rule = E of String -> Null_Or( raw::exp )
| SE of String -> Null_Or( raw::structexp )
| D of String -> Null_Or( raw::decl )
| T of String -> Null_Or( raw::ty )
| P of String -> Null_Or( raw::pat )
};
nothing = r::noRewrite
# Trace the current line
fun markLines { exp, decl, ty, pat, sexp }
=
{ fun exp' f (e as raw::MARKexp (l, _)) = { err::setLoc l; exp f e; }
| exp' f e = exp f e;
fun decl' f (d as raw::MARKDECL (l, _)) = { err::setLoc l; decl f d; }
| decl' f d = decl f d;
{ exp=exp', decl=decl', ty, pat, sexp };
}
fun mapper rules
=
{ use Map;
fun f ([], e, d, t, p, se) = markLines { exp=e, decl=d, ty=t, pat=p, sexp=se }
| f (E exp . rules, _, d, t, p, se) = f (rules, \\ _ => exp, d, t, p, se)
| f (D decl . rules, e, _, t, p, se) = f (rules, e, \\ _ => decl, t, p, se)
| f (T ty . rules, e, d, _, p, se) = f (rules, e, d, \\ _ => ty, p, se)
| f (P pat . rules, e, d, t, _, se) = f (rules, e, d, t, \\ _ => pat, se)
| f (SE sexp . rules, e, d, t, p, _) = f (rules, e, d, t, p, \\ _ => sexp);
rules = f (rules, nothing, nothing, nothing, nothing, nothing);
r::rewrite rules;
}
fun rewriter rules
=
{ use Rewrite;
fun f ([], e, d, t, p, se) = markLines { exp=e, decl=d, ty=t, pat=p, sexp=se }
| f (E exp . rules, _, d, t, p, se) = f (rules, exp, d, t, p, se)
| f (D decl . rules, e, _, t, p, se) = f (rules, e, decl, t, p, se)
| f (T ty . rules, e, d, _, p, se) = f (rules, e, d, ty, p, se)
| f (P pat . rules, e, d, t, _, se) = f (rules, e, d, t, pat, se)
| f (SE sexp . rules, e, d, t, p, _) = f (rules, e, d, t, p, sexp);
rules = f (rules, nothing, nothing, nothing, nothing, nothing);
r::rewrite rules;
}
fun subster rules
=
{ use Subst;
fun g1 f _ (e as raw::ID_IN_EXPRESSION (raw::IDENT([], x))) =
(case f x of THE e => e
| NULL => e)
| g1 f _ e = e;
fun g2 f _ (e as raw::VAL_DECL[raw::NAMED_VALUE (raw::WILDCARD_PATTERN, raw::LITERAL_IN_EXPRESSION (raw::STRING_LIT x))]) =
(case f x of THE e => e
| NULL => e)
| g2 f _ e = e;
fun g3 f _ (e as raw::IDTY (raw::IDENT([], x))) =
(case f x of THE e => e
| NULL => e)
| g3 f _ e = e;
fun g4 f _ (e as raw::IDPAT x) =
(case f x of THE e => e
| NULL => e)
| g4 f _ e = e;
fun g5 f _ (e as raw::IDSEXP (raw::IDENT([], x))) =
(case f x of THE e => e
| NULL => e)
| g5 f _ e = e;
fun f ([], e, d, t, p, se) = markLines { exp=e, decl=d, ty=t, pat=p, sexp=se }
| f (E exp . rules, _, d, t, p, se) = f (rules, g1 exp, d, t, p, se)
| f (D decl . rules, e, _, t, p, se) = f (rules, e, g2 decl, t, p, se)
| f (T ty . rules, e, d, _, p, se) = f (rules, e, d, g3 ty, p, se)
| f (P pat . rules, e, d, t, _, se) = f (rules, e, d, t, g4 pat, se)
| f (SE sexp . rules, e, d, t, p, _) = f (rules, e, d, t, p, g5 sexp);
rules = f (rules, nothing, nothing, nothing, nothing, nothing);
r::rewrite rules;
}
fun folder rules x
=
{ use Fold;
x = REF x;
fun g f _ y
=
{ x := f (y,*x);
y;
};
fun f ([], e, d, t, p, se) = markLines { exp=e, decl=d, ty=t, pat=p, sexp=se }
| f (E exp . rules, _, d, t, p, se) = f (rules, g exp, d, t, p, se)
| f (D decl . rules, e, _, t, p, se) = f (rules, e, g decl, t, p, se)
| f (T ty . rules, e, d, _, p, se) = f (rules, e, d, g ty, p, se)
| f (P pat . rules, e, d, t, _, se) = f (rules, e, d, t, g pat, se)
| f (SE sexp . rules, e, d, t, p, _) = f (rules, e, d, t, p, g sexp);
rules = f (rules, nothing, nothing, nothing, nothing, nothing);
my { exp, decl, ty, pat, sexp }
=
r::rewrite rules;
fun h f y
=
{ f y;
*x;
};
{ exp = h exp, decl= h decl, ty=h ty, pat=h pat, sexp=h sexp };
}
fun apper rules
=
{ use App;
fun g f _ x
=
{ f x;
x;
};
fun f ([], e, d, t, p, se) = markLines { exp=e, decl=d, ty=t, pat=p, sexp=se }
| f (E exp . rules, _, d, t, p, se) = f (rules, g exp, d, t, p, se)
| f (D decl . rules, e, _, t, p, se) = f (rules, e, g decl, t, p, se)
| f (T ty . rules, e, d, _, p, se) = f (rules, e, d, g ty, p, se)
| f (P pat . rules, e, d, t, _, se) = f (rules, e, d, t, g pat, se)
| f (SE sexp . rules, e, d, t, p, _) = f (rules, e, d, t, p, g sexp);
rules = f (rules, nothing, nothing, nothing, nothing, nothing);
my { exp, decl, ty, pat, sexp }
=
r::rewrite rules;
fun h f x
=
{ f x;
();
};
{ exp = h exp, decl= h decl, ty=h ty, pat=h pat, sexp=h sexp };
}
fun noSimplify x
=
x
# Make a new type
generic package Type (type t) {
type t = t
type pp = pp::pp
type ar = App::rule
type fr X = Fold::rule X
type mr = Map::rule
type rr = Rewrite::rule
type sr = Subst::rule
};
# Map a list out of it
generic package List (type t
my pp: t -> pp::pp
my apply: List( App::rule ) -> t -> Void
my fold: List( Fold::rule(X) ) -> X -> t -> X
my map: List( Map::rule ) -> t -> t
my rewrite: List( Rewrite::rule ) -> t -> t
my subst: List( Subst::rule ) -> t -> t
my simplify: t -> t
my nolocations: t -> t
)
{
package t = Type (type t = List (t) ) use t
list = pp::seq (pp::nop, pp.!! ", ", pp::nop)
pp = \\ x => list (list::map pp x)
show = asML o pp
apply = \\ r => list::apply (apply r)
fold = \\ r => { f = fold r; fold_forward (\\ (e, x) => f x e); }
map = \\ r => list::map (map r)
subst = \\ r => list::map (subst r)
rewrite = \\ r => list::map (rewrite r)
simplify = list::map simplify
nolocations = list::map nolocations
};
# Make a labeled something out of it
generic package Labeled (type t
my pp: labeled( t ) -> pp::pp
my apply: List( App::rule ) -> t -> Void
my fold: List( Fold::rule(X) ) -> X -> t -> X
my map: List( Map::rule ) -> t -> t
my rewrite: List( Rewrite::rule ) -> t -> t
my subst: List( Subst::rule ) -> t -> t
my simplify: t -> t
my nolocations: t -> t
)
{
package t = Type (type t = labeled (t) ) use t
pp = pp
show = asML o pp
apply = \\ r => \\ (l, x) => apply r x
fold = \\ r => \\ u => \\ (l, x) => fold r u x
map = \\ r => \\ (l, x) => (l, map r x)
rewrite = \\ r => \\ (l, x) => (l, rewrite r x)
subst = \\ r => \\ (l, x) => (l, subst r x)
simplify = \\ (l, x) => (l, simplify x)
nolocations = \\ (l, x) => (l, nolocations x)
};
# Declaration
package decl {
package t = Type (type t = raw::decl) use t
fun parse s
=
case p::parseString' *silent s of
[raw::MARKDECL(_, d)] => d
| ds => raw::SEQ_DECL ds
pp = raw_pp::decl
show = asML o pp
simplify = tr::simplify_declaration
map = .decl o mapper
rewrite = .decl o rewriter
apply = .decl o apper
subst = .decl o subster
fun fold r x = .decl (folder r x)
nolocations = nolocations
};
# Make iterators for types without convenient ones
generic package Iterators (type t
my ===> : t -> raw::decl
my <== : String * raw::decl -> t
)
{
fun simplify x = <==("simplify", decl::simplify(===> x))
fun map r x = <==("map", decl::map r (===> x))
fun rewrite r x = <==("rewrite", decl::rewrite r (===> x))
fun subst r x = <==("subst", decl::subst r (===> x))
fun apply r x = decl::apply r (===> x)
fun fold r u x = decl::fold r u (===> x)
fun nolocations x = <==("nolocations", decl::nolocations(===> x))
}
# Expression
package exp {
package t = Type (type t = raw::exp) use t
fun parse s =
case decl::parse("my _ =\n" + s) of
raw::VAL_DECL[raw::NAMED_VALUE(_, e)] => e
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::exp
show = asML o pp
simplify = tr::simplifyExp
map = .exp o mapper
rewrite = .exp o rewriter
apply = .exp o apper
subst = .exp o subster
fun fold r x = .exp (folder r x)
fun nolocations e =
case decl::nolocations (raw::VAL_DECL[raw::NAMED_VALUE (raw::WILDCARD_PATTERN, e)]) of
raw::VAL_DECL[raw::NAMED_VALUE(_, e)] => e
| _ => bug("Exp", "locations")
}
# Expressions
package exps {
fun parse s =
case decl::parse("my _ =\n(" + s + ")") of
raw::VAL_DECL[raw::NAMED_VALUE(_, raw::TUPLE_IN_EXPRESSION e)] => e
| raw::VAL_DECL[raw::NAMED_VALUE(_, e)] => [e]
| _ => raise exception p::PARSE_ERROR
package x = List (Exp) use x
}
package label_expression {
fun parse s =
case decl::parse("{\n" + s + "}") of
raw::VAL_DECL[raw::NAMED_VALUE(_, raw::RECORDexp[e])] => e
| _ => raise exception p::PARSE_ERROR
package x = Labeled (struct use Exp pp = raw_pp::label_expression end) use x
}
# Labeled Expressions:
#
package label_expressions {
fun parse s =
case decl::parse("{\n" + s + "}") of
raw::VAL_DECL[raw::NAMED_VALUE(_, raw::RECORDexp e)] => e
| _ => raise exception p::PARSE_ERROR
package x = List (Label_Expression) use x
}
# Package Expression:
#
package sexp {
package t = Type (type t = raw::structexp) use t
fun parse s =
case decl::parse("package __fake_id__ =\n" + s) of
raw::PACKAGE_DECL(_, _, _, e) => e
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::sexp
show = asML o pp
map = .sexp o mapper
rewrite = .sexp o rewriter
apply = .sexp o apper
subst = .sexp o subster
fun fold r x = .sexp (folder r x)
simplify = tr::simplifySexp
fun nolocations x =
case decl::nolocations (raw::PACKAGE_DECL (fakeId,[], NULL, x)) of
raw::PACKAGE_DECL(_, _, _, x) => x
| _ => bug("Sexp", "locations")
}
# API Expression:
#
package api_expression {
package t = Type (type t = raw::api_expression) use t
fun parse s =
case decl::parse("api f =\n" + s) of
raw::API_DECL(_, e) => e
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::api_expression
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::API_DECL (fakeId, x)
fun <== (name, raw::API_DECL(_, x)) = x
| <== (name, _) = bug("Api_Exp", name)
) use i
}
# Clauses: <clause>
| ... | <clause>
package clauses {
package t = Type (type t = List (raw::clause)) use t
fun parse s =
case exp::parse("\\\n" + s) of
raw::LAMBDA_EXPRESSION c => c
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::clauses
show = asML o pp
isComplex = m::isComplex
package i = Iterators
(type t = t
fun ===> x = raw::VAL_DECL[raw::NAMED_VALUE (raw::WILDCARD_PATTERN, raw::LAMBDA_EXPRESSION x)]
fun <== (name, raw::VAL_DECL[raw::NAMED_VALUE(_, raw::LAMBDA_EXPRESSION x)]) = x
| <== (name, _) = bug("Clauses", name)
) use i
}
# Clause: <pat> => <exp>
# or <pat> where <exp> => <exp> (ml_grinder extension)
package clause {
package t = Type (type t = raw::clause) use t
fun parse s = case Clauses::parse s of [c] => c
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::clause show = asML o pp
fun isComplex c= m::isComplex[c]
package i = Iterators
(type t = t
fun ===> x = raw::VAL_DECL[raw::NAMED_VALUE (raw::WILDCARD_PATTERN, raw::LAMBDA_EXPRESSION [x])]
fun <== (name, raw::VAL_DECL[raw::NAMED_VALUE(_, raw::LAMBDA_EXPRESSION [x])]) = x
| <== (name, _) = bug("Clause", name)
) use i
}
# Funclauses: <funclause>
| ... | <funclause>
package fun_clauses {
use Clauses
fun parse s =
case decl::parse("fun \n" + s) of
raw::FUN_DECL [raw::FUN (f, cs)] => (f, cs)
| _ => raise exception p::PARSE_ERROR
fun nolocations (f, c) = (f, Clauses::nolocations c)
}
/* FunClause: f <pat> ... <pat> = <exp>
* or f <pat> ....<pat> where (<exp>) => <exp> (ml_grinder extension)
*/
package fun_clause {
use Clause
fun parse s =
case FunClauses::parse s of
(f,[c]) => (f, c)
| _ => raise exception p::PARSE_ERROR
fun nolocations (f, c) = (f, Clause::nolocations c)
}
# Function_Defs: <function_def> and ... and <function_def>
package function_defs {
package t = Type (type t = List (raw::function_def)) use t
fun parse s =
case decl::parse("fun .\n" + s)
of raw::FUN_DECL b => b
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::function_defs
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::FUN_DECL x
fun <== (name, raw::FUN_DECL x) = x
| <== (name, _) = bug("Function_Defs", name)
) use i
}
# Fun: f <funclause>
package function_def {
package t = Type (type t = raw::function_def) use t
fun parse s =
case Function_Defs::parse s of [b] => b
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::function_def
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::FUN_DECL [x]
fun <== (name, raw::FUN_DECL [x]) = x
| <== (name, _) = bug("Fun", name)
) use i
}
# Named_Values: <named_value> and ... and <named_value>
package named_values {
package t = Type (type t = List (raw::NAMED_VALUE) ) use t
fun parse s =
case decl::parse("my\n" + s)
of raw::VAL_DECL b => b
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::named_values
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::VAL_DECL x
fun <== (name, raw::VAL_DECL x) = x
| <== (name, _) = bug("Named_Values", name)
) use i
}
# Named_Value: <pat> = <exp>
package named_value {
package t = Type (type t = raw::NAMED_VALUE) use t
fun parse s =
case Named_Values::parse s of [b] => b
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::named_value
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::VAL_DECL [x]
fun <== (name, raw::VAL_DECL [x]) = x
| <== (name, _) = bug("Named_Value", name)
) use i
}
package consbinds {
package t = Type (type t = List( raw::consbind )) use t
fun parse s =
case decl::parse("enum f=\n" + s) of
raw::DATATYPE_DECL ([raw::DATATYPE { cbs=c, ... } ], _) => c
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::consbinds
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::DATATYPE_DECL(
[raw::DATATYPE { name=fakeId, tyvars=[], mc=NULL,
asm=FALSE, field=NULL, cbs=x } ],
[])
fun <== (name, raw::DATATYPE_DECL(
[raw::DATATYPE { cbs, ... } ], _)) = cbs
| <== (name, _) = bug("Consbinds", name)
) use i
}
package consbind {
package t = Type (type t = raw::consbind) use t
fun parse s = case Consbinds::parse s of [c] => c
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::consbind
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::DATATYPE_DECL(
[raw::DATATYPE { name=fakeId, tyvars=[], mc=NULL,
asm=FALSE, field=NULL, cbs=[x] } ],
[])
fun <== (name, raw::DATATYPE_DECL(
[raw::DATATYPE { cbs=[x], ... } ], _)) = x
| <== (name, _) = bug("Constructor_Def", name)
) use i
}
package datatypes {
package t = Type (type t = List( raw::sumtype )) use t
fun parse s =
case decl::parse("enum " + s)
of raw::DATATYPE_DECL (db,[]) => db
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::datatypes
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::DATATYPE_DECL (x,[])
fun <== (name, raw::DATATYPE_DECL (x, _)) = x
| <== (name, _) = bug("Datatypes", name)
) use i
}
package sumtype {
package t = Type (type t = raw::sumtype) use t
fun parse s =
case Datatypes::parse s of [d] => d
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::sumtype
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::DATATYPE_DECL([x],[])
fun <== (name, raw::DATATYPE_DECL([x], _)) = x
| <== (name, _) = bug("Datatype", name)
) use i
}
package typebinds {
package t = Type (type t = List( raw::typebind )) use t
fun parse s =
case decl::parse("type " + s)
of raw::DATATYPE_DECL([], tb) => tb
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::typebinds
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::DATATYPE_DECL([], x)
fun <== (name, raw::DATATYPE_DECL(_, x)) = x
| <== (name, _) = bug("Typebinds", name)
) use i
}
package typebind {
package t = Type (type t = raw::typebind) use t
fun parse s =
case Typebinds::parse s of [d] => d
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::typebind
show = asML o pp
package i = Iterators
(type t = t
fun ===> x = raw::DATATYPE_DECL([],[x])
fun <== (name, raw::DATATYPE_DECL(_,[x])) = x
| <== (name, _) = bug("Typebind", name)
) use i
}
package ty {
package t = Type (type t = raw::ty) use t
fun parse s =
case decl::parse("type __fake_id__=\n" + s) of
raw::DATATYPE_DECL(_,[raw::TYPEBIND(_, _, t)]) => t
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::ty show = asML o pp
map = .ty o mapper
rewrite = .ty o rewriter
apply = .ty o apper
subst = .ty o subster
fun fold r x = .ty (folder r x)
simplify = tr::simplifyTy
fun nolocations t =
case decl::nolocations (raw::DATATYPE_DECL([],[raw::TYPEBIND (fakeId,[], t)])) of
raw::DATATYPE_DECL(_,[raw::TYPEBIND(_, _, t)]) => t
| _ => bug("Ty", "locations")
}
package tys {
fun parse s =
case decl::parse("type t=\n(" + s + ")") of
raw::DATATYPE_DECL(_,[raw::TYPEBIND(_, _, raw::TUPLETY ts)]) => ts
| raw::DATATYPE_DECL(_,[raw::TYPEBIND(_, _, t)]) => [t]
| _ => raise exception p::PARSE_ERROR
package x = List (Ty) use x
}
package labty {
fun parse s =
case decl::parse("type t= {\n" + s + "}") of
raw::DATATYPE_DECL(_,[raw::TYPEBIND(_, _, raw::RECORDTY[t])]) => t
| _ => raise exception p::PARSE_ERROR
package x = Labeled (struct use Ty pp = raw_pp::labty end) use x
}
package labtys {
fun parse s =
case decl::parse("type t= {\n" + s + "}") of
raw::DATATYPE_DECL(_,[raw::TYPEBIND(_, _, raw::RECORDTY ts)]) => ts
| _ => raise exception p::PARSE_ERROR
package x = List (Labty) use x
}
package pat {
package t = Type (type t = raw::pat) use t
type t = raw::pat
fun parse s =
case decl::parse("my\n" + s + " = ()") of
raw::VAL_DECL[raw::NAMED_VALUE (p, _)] => p
| _ => raise exception p::PARSE_ERROR
pp = raw_pp::pat show = asML o pp
map = .pat o mapper
rewrite = .pat o rewriter
apply = .pat o apper
subst = .pat o subster
fun fold r x = .pat (folder r x)
simplify = tr::simplifyPat
fun nolocations p =
case decl::nolocations (raw::VAL_DECL[raw::NAMED_VALUE (p, raw::TUPLE_IN_EXPRESSION [])]) of
raw::VAL_DECL[raw::NAMED_VALUE (p, _)] => p
| _ => bug("Pat", "locations")
}
package pats {
fun parse s =
case decl::parse("my(\n" + s + ")=()") of
raw::VAL_DECL[raw::NAMED_VALUE (raw::TUPLEPAT p, _)] => p
| raw::VAL_DECL[raw::NAMED_VALUE (p, _)] => [p]
| _ => raise exception p::PARSE_ERROR
package x = List (Pat) use x
}
package labpat {
fun parse s =
case decl::parse("my {\n" + s + "} =()") of
raw::VAL_DECL[raw::NAMED_VALUE (raw::RECORD_PATTERN([p], _), _)] => p
| _ => raise exception p::PARSE_ERROR
package x = Labeled (pkg use Pat pp = raw_pp::labpat end) use x
{
package labpats {
fun parse s =
case decl::parse("my {\n" + s + "} =()") of
raw::VAL_DECL[raw::NAMED_VALUE (raw::RECORD_PATTERN (ps, _), _)] => ps
| _ => raise exception p::PARSE_ERROR
package x = List (Labpat) use x
}
package constants {
fun constants ()
=
{ t = raw_consts::newConstTable();
defineConst = raw_consts::const t;
fun declareConsts decl
=
case raw_consts::genConsts t of
[] => decl
| ds => raw::LOCAL_DECL (ds,[decl])
{ defineConst, declareConsts };
}
}
# Input/Output
package io {
type filename = String
fun read_string filename =
let s = file::open_for_read filename
in file::read_all s then file::close_input s
end
fun read_lines filename
=
{ s = file::open_for_read filename;
fun read (text)
=
case file::read_line s of
"" => reverse text
| t => read (t . text)
read [] then file::close_input s;
}
fun stripNL "" = ""
| stripNL s
=
{ i = size s - 1;
if string::get_byte_as_char (s, i) == '\n'
then string::substring (s, 0, i)
else s;
}
fun read_lines' filename
=
map stripNL (read_lines filename);
fun read_verbatim filename
=
A.@@@(read_lines' filename);
fun read_file filename
=
case parser::load filename of
[d] => d
| ds => raw::SEQ_DECL ds;
enum writeOpt =
INFILE of filename
| OUTFILE of filename
| EXT of String
| AUTHOR of String
| VERSION of String
| PROGRAM of String
| EMAIL of String
| COMMENT of List( String )
# Don't write the file if nothing has changed
fun changed (outfile, text)
=
{ ch
=
{ s = file::open_for_read outfile;
t = file::read_all s;
t != text then file::close_input s;
}
except _ => TRUE;
if ch then err::log("[Writing " + outfile + "]")
else err::log("[No change to " + outfile + "]");
ch;
}
fun write_string (filename, text)
=
if changed (filename, text)
then
{ s = file::open filename;
file::write (s, text)
then
file::close s;
}
else ()
fun write_lines (filename, text)
=
write_string (filename, string::cat text)
fun writeFile (opts, generatedProgram)
=
{ infile = REF NULL;
outfile = REF NULL;
extension = REF "pkg";
author = REF NULL;
version = REF NULL;
program = REF NULL;
email = REF NULL;
comment = REF [];
apply (\\ INFILE s => infile := THE s;
| OUTFILE s => outfile := THE s;
| EXT s => extension := s;
| AUTHOR s => author := THE s;
| VERSION s => version := THE s;
| PROGRAM s => program := THE s;
| EMAIL s => email := THE s;
| COMMENT s => comment := s @ *comment) opts;
# Find out what output file to use
outfile
=
case *outfile of
THE f => f
| NULL =>
# Determine outfile name from infile/suffix
case *infile of
NULL => bug("writeFile", "no output filename given")
| THE infile
=>
{ my { base, ext }
=
winix__premicrothread::path::split_base_ext infile;
outfile = winix__premicrothread::path::join_base_ext
{ base, ext=THE *extension };
if infile == outfile
then
bug("writeFile",
"input and output file have the same name: " +
infile)
else outfile;
};
# Create a comment message on top
from = case *infile of
THE f => [" * from \"" + f + "\""]
| NULL => [];
auth = case *author of THE a => a + " + s "
| NULL => "";
prog = case *program of THE p => p + " "
| NULL => "";
ver = case *version of THE v => "(version " + v + ")"
| NULL => "";
by = case auth + prog + ver of "" => []
| s => [" * by " + s];
other = map (\\ s => " * " + s) (*comment);
email = case *email of THE e =>
[" * Please send comments and suggestions to " + e]
| NULL => [] ;
prog' = case *program of THE p => p + " is "
| NULL => "";
comment
=
A.@@@("/*" .
" * This file has been automatically generated" .
from @
by @
email @
[" * [" + prog' +
"built with the ml_grinder library (version " + Version + ")]"] @
other @
[ " */",
""
]
);
# Prettyprint and generate the program
text = decl::show (raw::SEQ_DECL[comment, generatedProgram]);
write_string (outfile, text);
}
}
# The match compiler
package match_compiler {
fakeBasis = decl::parse basisForTheMatchCompiler
fun compileTypes datatypes
=
m::compileTypes (fakeBasis . datatypes)
exception MATCH_COMPILER = m::mc::MATCH_COMPILER
fun compile_case_pattern { datatypes, prog }
=
{ literals = REF m::LitMap::empty;
info = compileTypes datatypes;
# Compile a case statement
fun compileCase (exp, rules)
=
{ dfa = m::compile info rules
m::report { warning=err::warning,
error=err::error,
log=err::log,
dfa,
rules };
m::coder { root=exp, dfa,
fail=\\ () => raw::RAISEexp (u::ID "MATCH"),
literals };
};
# Compile a function
fun fbind (fb as raw::FUN (f, cs as c . _))
=
if Clauses::isComplex cs
then # expand function
{ my raw::CLAUSE (args, _, _)
=
c;
arity = length args;
vars = list::from_fn (arity, \\ i => "p_" + i2s i);
root = raw::TUPLE_IN_EXPRESSION (map u::ID vars);
cs' = map (\\ raw::CLAUSE (ps, g, e) =>
raw::CLAUSE([raw::TUPLEPAT ps], g, e)) cs;
body = compileCase (root, cs');
raw::FUN (f, [raw::CLAUSE (map raw::IDPAT vars, NULL, body)]);
}
else fb
| fbind fb = fb
# Find all occurances of conditional patterns and transform them
prog = decl::map
[Map::D (\\ raw::FUN_DECL fbs => raw::FUN_DECL (map fbind fbs)
| d => d
),
Map::E (\\ e as raw::CASEexp (r, cs) =>
if Clauses::isComplex cs then compileCase (r, cs)
else e
| e => e)
] prog;
litDecls =
m::LitMap::keyed_fold_backward
(\\ (l, v, d) =>
raw::NAMED_VALUE (raw::IDPAT v, raw::LITERAL_IN_EXPRESSION l) . d) [] (*literals);
litDecls = case litDecls of
[] => []
| _ => [raw::VAL_DECL litDecls];
{ prog, literals=litDecls };
}
} # match_compiler
# The lexer generator
package lexer_generator {
exception LEXER_GENERATOR of String
package p = perl_syntax
package lg = lexer_generator_g (perl_syntax::R)
fun compile re = the (number_string::scan_string p::scan re)
fun lexerGenerate prog
=
{ exception WrongForm;
fun exp (origExp as
raw::CASEexp (raw::APPLY_EXPRESSION (raw::ID_IN_EXPRESSION (raw::IDENT(["Lexer"], "lexer")), head),
clauses))
=
( { rules = map (\\ raw::CLAUSE([raw::TUPLEPAT [raw::LITPAT (raw::STRING_LIT re), p]], g, action)
=>
(re, p, g, action)
| _ => raise exception WrongForm
)
clauses;
regexps = map (\\ (re, _, _, _) => compile re) rules;
lexer = lg::compile regexps;
clauses = map (\\ (_, p, g, action) => raw::CLAUSE([p], g, action))
rules;
raw::CASEexp
(raw::APPLY_EXPRESSION (raw::ID_IN_EXPRESSION (raw::IDENT(["Lexer"], "match")), head),
clauses);
}
except
WrongForm => origExp
)
| exp e = e;
prog = decl::map[Map::E exp] prog;
literals = [];
{ prog, literals };
};
} # lexer_generator
}; # ml_grinder
end; # local