module DetMachineToHaskell2(dfaToHaskell,CaseOf(..),OutputFun(..)) where
import PPrint
import HaskellChars
import HsTokens
import List(partition,sort,sortBy,nub)
import DFA(DFA(..))
import qualified OrdMap as OM
import OpTypes(cmpBy)
import MUtils(collectBySnd)
import Trace(trace)
dfaToHaskell charclasses modname imports funname ((init,final),DFA dfa) =
"module" & modname & "("!funname!")" & "where" & nl &
vmap ("import"&) imports & nl &
"type" & "Output" & "=" & "[(Token,String)]" & nl &
"type" & "Input" & "=" & "String" & nl &
"type" & "Acc" & "=" & "Input" & "-- reversed" & nl &
"type" & "Lexer" & "=" & "Input -> Output" & nl &
"type" & "LexerState" & "=" & "(Acc->Lexer) -> Acc -> Lexer" & nl &
nl &
funname & "::" & "Lexer" & nl &
funname & "is" & "=" & start init "is" & nl &
nl &
charclassfundef &
statesToHaskell final charclassfun dfa
where
(charclassfundef,charclassfun) =
case charclasses::(Maybe [(HaskellChar,Int)]) of
Nothing -> (nil,id)
Just ccs -> (charClassFunToHaskell ccs & nl,("cclass" &))
charClassFunToHaskell ccs =
"cclass" & "::" & "Char" & "->" & "Int" & nl &
"cclass" & "c" & "=" & nl &
indented (haskellCharCase "c" show "0" ccs) & nl
state st = "state"!st
scall st err acc is = state st & err & acc & is -- state function call
lhs st is = scall st "err" "as" is -- lhs of state function
startstate st = "start"!st
start st is = startstate st & is -- (re)start from state
startlhs st is = start st is -- lhs of state start function
statesToHaskell final ccfun dfa =
vmap (stateToHaskell final (ccfun,alphabet)) states
where
states = OM.toList dfa
alphabet =
case errorValue of
Just e -> Just (e:nub [c|(_,(iedges,_))<-states,(c,_)<-iedges])
Nothing -> Nothing
stateToHaskell final ccinfo ste@(st,(_,oedges)) =
startdef &
state st & "::" & "LexerState" & nl &
stateToHaskell'' final ccinfo ste
where
-- If there are output edges, this state can't be a start state.
startdef =
if null oedges
then startstate st & "::" & "Lexer" & nl &
startlhs st "is" & "=" & scall st err (show "") "is" & nl
else nil
err = "("!"\\"&"as"&"is"&"->"&oedgesToHaskell "is" oedges !")"
stateToHaskell'' final ccinfo (st,([],oedges@(_:_))) =
lhs st "is" & "=" & indented (oedgesToHaskell "is" oedges) & nl
stateToHaskell'' final ccinfo (st,es@(_,oedges)) =
lhs st "[]" & "=" & indented (eofEdge st final oedges) & nl &
lhs st "iis@(i:is)" & "=" &
stateToHaskell' ccinfo es & nl
eofEdge st final [] | st `elem` final = "gotEOF" & "as"
eofEdge _ _ oedges =
opterrfun oedges "[]" ("err"&"as"&"[]")
--oedgesToHaskell "[]" oedges
stateToHaskell' ccinfo ([], oedges) = oedgesToHaskell "iis" oedges
stateToHaskell' (ccfun,Just allClasses) (iedges@(_:_),oedges) =
nl &
indented (opterrfun oedges "iis"(
caseExp (ccfun (pr"i"))
opt_iedgeToHaskell'
(opt_iedgeToHaskell' iedge')
iedges''))
where
(_,iedge'):iedges' = sortBy order $
collectBySnd [(c,lookup c iedges)|c<-allClasses]
order = cmpBy (negate.length.fst)
iedges'' = [(c,st)|(cs,st)<-iedges',c<-cs]
opt_iedgeToHaskell' = maybe ("err"&"as"&"iis") iedgeToHaskell'
stateToHaskell' (ccfun,Nothing) (iedges,oedges) =
nl &
indented (opterrfun oedges "iis"(
caseExp (ccfun (pr"i"))
iedgeToHaskell'
("err"&"as"&"iis") -- (oedgesToHaskell "iis" oedges)
iedges))
opterrfun oedges iis body =
if null oedges
then body
else body&nl&"where"&"err"&"_ _"&"="&oedgesToHaskell iis oedges
else "let"&"err"&"_ _"&"="&oedgesToHaskell iis oedges & nl &
"in"&body
-}
--iedgesToHaskell = vpr . map iedgeToHaskell
--iedgeToHaskell (c,st) = show c & "->" & iedgeToHaskell' st
iedgeToHaskell' st = scall st "err" "(i:as)" "is"
oedgesToHaskell is = oedgesToHaskell' "as" is
oedgesToHaskell' as is [] = "gotError" & as & is
oedgesToHaskell' as is [oedge] = oedgeToHaskell as is oedge
oedgesToHaskell' as is oedges0 =
trace msg $
oedgeToHaskell as is oedge
-- & nl & "--" & msg
where
-- On ambiguities, make a choice by comparing token classes:
oedges = sort oedges0
oedge = last oedges -- give priority to later tokens in the token data type
msg = "Machine is nondeterministic: "++show oedges
oedgeToHaskell as is (os,st) =
-- "("!show os!","&"reverse"&"as"!")"&":"&state st & show "" & is
output os (pr as) (pr st) (pr is)
--
class Show token => OutputFun token where
output :: token -> Document -> Document -> Document -> Document
output = default_output
default_output token as next is =
"output" & show token & as & "("!startstate next & is !")"
instance OutputFun Token where
output token as next is =
case token of
NestedCommentStart -> "nestedComment" & as & is & state next
_ -> default_output token as next is
class CaseOf a where
caseExp :: (Printable exp,Printable rhs) =>
exp -> (v->rhs) -> rhs -> [(a,v)] -> Document
errorValue :: Maybe a
errorValue = Nothing
--
instance CaseOf HaskellChar where caseExp = haskellCharCase
haskellCharCase e rhs defaultrhs cases =
caseE e (haskelLCharCaseBranches cases)
where
haskelLCharCaseBranches cases =
case partition (isAscii . fst) cases of
(as,us) -> vpr' (map asciiCharClass as++[uniCharClasses us])
isAscii (ASCII _) = True
isAscii _ = False
asciiCharClass (ASCII c,n) = show c & "->" & rhs n
uniCharClasses [] = "_" & "->" & defaultrhs
uniCharClasses us =
"c" & indented (
vpr' $ ("|" & "isAscii" & "c" & "->" & defaultrhs):
map uniCharClass us ++
[defaultcase])
uniCharClass (u,n) = "|" & tstFunc u & "c" & "->" & rhs n
defaultcase = "|" & "otherwise" & "->" & defaultrhs
tstFunc u =
case u of
UniWhite -> "isSpace"
UniSymbol -> "isSymbol"
UniDigit -> "isDigit"
UniLarge -> "isUpper"
UniSmall -> "isLower"
instance CaseOf Int where caseExp = simpleCase; errorValue=Just 0
instance CaseOf Char where caseExp = simpleCase
simpleCase e rhs defaultrhs cases =
caseE e (branches cases)
where
branches cases = vpr' (map branch cases++[defaultbranch])
branch (a,v) = show a & "->" & rhs v
defaultbranch = "_" & "->" & defaultrhs
vpr' = prsep nl
caseE e bs = "case" & e & "of" & nl & indented bs