{- $Id: Parser.hs,v 1.1.2.33 2009/02/20 18:00:03 orlov Exp $ -}
{- vim: set syntax=haskell expandtab tabstop=4: -}
module Parser {-(
eval, compile, uncompile
)-} where
import Prelude
import System.IO.Unsafe (unsafePerformIO)
import List (elemIndices, mapAccumL)
import Monad (ap, foldM, liftM, when, zipWithM_)
import UU_Offside
import UU_Parsing hiding (Exp, Symbol, Parser, parse)
import UU_Scanner
import StateParser
import qualified XSG
import qualified URA
---------------------------------------------------------------------------------------------------
eval :: FileName -> String -> [Branch]
eval file str = map uncompile (eval' file str)
compile :: FileName -> XSG.Prog
compile file = snd $ compileFile file
uncompile :: XSG.Exps -> Branch
uncompile es = zipWith ($) (cycle [ActAssign, ActCompare]) $ snd $ mapAccumL (mapAccumL printExp) [] ess where
(cd, es') = XSG.mkCond es
ess = (concatMap (\(e1 XSG.:=: e2) -> [[e1], [e2]]) cd)++[es']
printExp vs (XSG.VAR v) =
case elemIndices v (vs++[v]) of
[n] -> (vs++[v], ExpNew vt (XSG.myShow vt++XSG.myShow n, noPos)) where vt = uncompileVar v
[n, _] -> (vs , ExpId (XSG.myShow vt++XSG.myShow n, noPos)) where vt = uncompileVar v
printExp vs (XSG.C (cN, _) []) = (vs , ExpId (cN, noPos))
printExp vs (XSG.C (cN, _) es) = (vs', ExpConcat $ (ExpId (cN, noPos)):es') where
(vs', es') = mapAccumL printExp vs es
uncompileVar (XSG.X _) = X
uncompileVar (XSG.Y _) = Y
uncompileVar (XSG.W _) = W
uncompileVar (XSG.L _) = W
--uncompileBranch :: (XSG.Exps, XSG.Branch) -> Branch
uncompileBranch :: (XSG.Vars, XSG.Branch) -> Branch
uncompileBranch (args,(ts, cd, es)) = (ActCompare qs0) : zipWith ($) (cycle [ActAssign, ActCompare]) (qs4++qs3)
where ess1 = map (\(_ XSG.:= (_, es)) -> es) ts
ls1 = map length ess1
es2 = concatMap (\(e1 XSG.:=: e2) -> [e1, e2]) cd
l2 = length es2
esA = (concat ess1)++es2++es
(cdF, esF) = XSG.mkCond esA
(esF1, ess1F) = (mapAccumL $ flip (\t -> (\(x,y)->(y,x)) . splitAt t)) esF ls1
(es2F, esF2) = splitAt l2 esF1
cdF2 = cdF++(map (\[x,y] -> (x XSG.:=: y)) $ snd $ (mapAccumL $ flip (\t -> (\(x,y)->(y,x)) . splitAt t)) es2F (take (l2 `div` 2) $ repeat 2))
essG = (concatMap (\(e1 XSG.:=: e2) -> [[e1], [e2]]) cdF2)++[esF2]
vs0 = []
(vs1, qs0) = mapAccumL printExp vs0 $ map XSG.v2e args
(vs2, qs1) = mapAccumL (\vs (_ XSG.:= (fn, _), es) -> printFun vs (fn,es)) vs1 (zip ts ess1F)
(vs3, qs2) = mapAccumL (mapAccumL printVar) vs2 (map (\(vs XSG.:= _) -> vs) ts)
(vs4, qs3) = mapAccumL (mapAccumL printExp) vs3 essG
qs4 = concat $ zipWith (\x y -> [x, [y]]) qs2 qs1
printExp vs (XSG.VAR v) = printVar vs v
printExp vs (XSG.C (cN, _) []) = (vs , ExpId (cN, noPos))
printExp vs (XSG.C (cN, _) es) = (vs', ExpConcat $ (ExpId (cN, noPos)):es')
where (vs', es') = mapAccumL printExp vs es
printVar vs v = case elemIndices v (vs++[v]) of
[n] -> (vs++[v], ExpNew (uncompileVar v) ('x':XSG.myShow n, noPos))
[n, _] -> (vs , ExpId ('x':XSG.myShow n, noPos) )
printFun vs (fN, es) = (vs', ExpConcat $ (ExpId (fN, noPos)):es')
where (vs', es') = mapAccumL printExp vs es
---------------------------------------------------------------------------------------------------
eval' :: FileName -> String -> [XSG.Exps]
eval' file str = URA.int (main:prog) [] XSG.initIdx
where (tbl, prog) = compileFile file
br = parse' pBranchA str
main = XSG.FUNC "$EVAL$" [] [compileBranch tbl XSG.initIdx [] br]
compileFile :: FileName -> (SymbolTable, XSG.Prog)
compileFile = compileModule . parse . unsafePerformIO . readFile
parse :: Parsible a => String -> a
parse = parse' parser
parse' p input = unsafePerformIO io where
io = parseIO (unOP p) (Input (scanXSG (convert input), NoContext))
unOP (OP p) = p
scanXSG input = scan keywordstxt keywordsops specchars opchars "online.xsg" initPos $ convert input where^I
keywordstxt = []
keywordsops = []
specchars = "{;}()!?@=,:"
opchars = ""
---------------------------------------- Parsing datatypes ----------------------------------------
type FileName = String
type Id = String
type CtorType = Int
type FuncType = (Int, Int)
data Decl = CtorDecl [(Id, Pos)] CtorType
| FuncDecl [(Id, Pos)] FuncType
data VarType = X | Y | W
data Exp = ExpId (Id, Pos)
| ExpNew VarType (Id, Pos) -- @x !y ?w
| ExpConcat Exps
type Exps = [Exp]
data Act = ActAssign Exps
| ActCompare Exps
type Branch = [Act]
data Func = Func (Id, Pos) [Branch]
type Prog = [Either Decl Func]
sep c x y = x++c++y
instance XSG.MyShow VarType where
myShow X = "X"
myShow Y = "Y"
myShow W = "W"
instance XSG.MyShow Pos where
myShow (Pos x y) = show (x, y)
instance XSG.MyShow Decl where
myShow (CtorDecl ids ar ) =
XSG.intersperseShow "," (map fst ids)++[symType]++" "++(XSG.myShow ar)++"\n"
myShow (FuncDecl ids (ar, co)) =
XSG.intersperseShow "," (map fst ids)++[symType]++" "++(XSG.myShow ar)++[symAssign]++" "++(XSG.myShow co)++"\n"
instance XSG.MyShow Exp where
myShow (ExpId (id, _) ) = id
myShow (ExpConcat es ) = "("++(XSG.myShow es)++")"
myShow (ExpNew tp (id, _)) = [symNew tp]++id where
symNew X = symNewX
symNew Y = symNewY
symNew W = symNewW
instance XSG.MyShow Exps where
myShow [] = "()"
myShow es = foldr1 (sep " ") (map XSG.myShow es)
instance XSG.MyShow Act where
myShow (ActAssign es ) = [symAssign]++" "++(XSG.myShow es)
myShow (ActCompare es) = [symCompare]++(XSG.myShow es)
instance XSG.MyShow Branch where
myShow br = concatMap XSG.myShow br
instance XSG.MyShow [Branch] where
myShow brs = concatMap (\x -> (XSG.myShow x)++"\n") brs
instance XSG.MyShow Func where
myShow (Func (id, _) [] ) = id++" "++[symLast]++"\n"
myShow (Func (id, _) brs) = id++"\n "++(XSG.intersperseShow "\n " brs)++[symLast]++"\n"
instance XSG.MyShow Prog where
myShow prog = concatMap (either XSG.myShow XSG.myShow) prog
getExpsPos = getExpPos . head where
getExpPos (ExpId (_, pos)) = pos
getExpPos (ExpNew _ (_, pos)) = pos
getExpPos (ExpConcat (e:_)) = getExpPos e
getBranchPos = getActPos . last where
getActPos (ActAssign e ) = getExpsPos e
getActPos (ActCompare e) = getExpsPos e
--------------------------------------------- Syntax ----------------------------------------------
(symCompare, symAssign, symNewX, symNewY, symNewW, symNext, symBegin, symEnd, symType, symLast) =
('=', ',', '@', '!', '?', ';', '{' , '}', ':', ' ')
--------------------------------------------- Parsers ---------------------------------------------
class Parsible a where
parser :: OffsideParser [] Pair Token a
type Parser = OffsideParser [] Pair Token
pId :: Parser (Id,Pos)
pId = getIdPos <$> (pSym (Tok TkVarid "" "?id?" noPos "") <|> pSym (Tok TkConid "" "?id?" noPos ""))
where getIdPos (Tok _ _ id pos _) = (id, pos)
pCompare, pAssign, pNext, pBegin, pEnd, pType :: Parser String
pCompare = pSpec symCompare
pAssign = pSpec symAssign
pNext = pOnside (pSpec symNext)
pBegin = pSpec symBegin
pEnd = pSpec symEnd
pType = pSpec symType
pNew :: Parser VarType
pNew = X <$ pSpec symNewX <|> Y <$ pSpec symNewY <|> W <$ pSpec symNewW
pExp :: Parser Exp
pExp = (ExpId <$> pId) <|>
(ExpNew <$> pNew <*> pId) <|>
(ExpConcat <$ pOParen <*> pExps <* pCParen)
instance Parsible Exp where parser = pExp
pExps :: Parser Exps
pExps = pList1_ng pExp
instance Parsible Exps where parser = pExps
pAct :: Parser Act
pAct = (ActAssign <$ pAssign <*> pExps) <|>
(ActCompare <$ pCompare <*> pExps)
instance Parsible Act where parser = pAct
pBranchA, pBranchC :: Parser Branch
pBranch' :: (Exps->Act) -> Parser Branch
pBranch' dflt = (:) <$> (dflt <$> pExps <|> pAct) <*> pList_ng pAct
pBranchA = pBranch' ActAssign
pBranchC = pBranch' ActCompare
instance Parsible Branch where parser = pBranchC
pFunc :: Parser Func
pFunc = Func <$> pId <*> pBlock1 pBegin pNext pEnd pBranchC
instance Parsible Func where parser = pFunc
pInt :: Parser Int
pInt = read <$> pInteger10
pCtorDecl,pFuncDecl :: Parser Decl
pCtorDecl = CtorDecl <$> pListSep (pSpec ',') pId <* pType <*> pCtorType where
pCtorType = (makeCtorType <$> pList_ng pId) <|> pInt
makeCtorType = length
pFuncDecl = FuncDecl <$> pListSep (pSpec ',') pId <* pType <*> pFuncType where
pFuncType = (makeFuncType <$> pList pId <* pAssign <*> pList_ng pId) <|>
((,) <$> pInt <* pAssign <*> pInt)
makeFuncType as rs = (length as, length rs)
instance Parsible Decl where parser = pFuncDecl <|> pCtorDecl
instance Parsible Prog where parser = pBlock1 pBegin pNext pEnd (Left <$> parser <|> Right <$> parser)
-------------------------------------------- COMPILER ---------------------------------------------
data Symbol = Constructor Id CtorType
| Function Id FuncType
| Variable Id XSG.Var
| Unknown
data SymbolTable = SymbolTable (Id -> Symbol) (Id -> Symbol -> SymbolTable)
emptySymbolTable = tbl
where tbl = SymbolTable (const Unknown) (new tbl)
new (SymbolTable find add) id sym = tbl'
where tbl' = SymbolTable find' (new tbl')
find' id' | id == id' = sym
| otherwise = find id'
addSymbol :: Symbol -> SymbolTable -> SymbolTable
addSymbol sym@(Constructor id _ ) (SymbolTable _ add) = add id sym
addSymbol sym@(Function id (_, _)) (SymbolTable _ add) = add id sym
addSymbol sym@(Variable id _ ) (SymbolTable _ add) = add id sym
getSymbol :: SymbolTable -> (Id, Pos) -> Symbol
getSymbol (SymbolTable find _) (id, pos) = check (find id)
where check Unknown = error ("symbol '"++(XSG.myShow id)++"' at position "++(XSG.myShow pos)++" is undefined")
check s = s
data MONAD a = MONAD (SymbolTable -> XSG.Index -> (SymbolTable, a))
instance Prelude.Monad MONAD where
return x = MONAD (\tbl idx -> (tbl, x))
(MONAD x) >>= f = MONAD (\tbl idx -> let idx1:idx2:_ = XSG.newIdxs idx
(tbl', a) = x tbl idx1
MONAD y = f a
in y tbl' idx2)
compileSymbol :: Pos -> (Symbol, XSG.Index) -> (XSG.Terms, XSG.Exps) -> (XSG.Terms, XSG.Exps)
compileSymbol pos (Constructor id ar , idx) (ts, es) = check `seq` (ts, (XSG.C (id, idx) es1):es2)
where (es1, es2) = splitAt ar es
check = when (ar /= length es1) $ error ("constructor arity mismatch at position "++(XSG.myShow pos)++" ("++(XSG.myShow $ ar)++"/="++(XSG.myShow $ length es1)++")") :: [()]
compileSymbol pos (Function id (ar, co), idx) (ts, es) = check `seq` ((vs XSG.:= (id, es1)):ts, (XSG.v2e vs)++es2)
where (es1, es2) = splitAt ar es
vs = XSG.fresh co XSG.L idx
check = when (ar /= length es1) $ error ("function arity mismatch at position "++(XSG.myShow pos)++" ("++(XSG.myShow $ ar)++"/="++(XSG.myShow $ length es1)++")") :: [()]
compileSymbol pos (Variable _ xsgVar , idx) (ts, es) = (ts, (XSG.v2e xsgVar):es)
compileVar X = XSG.X
compileVar Y = XSG.Y
compileVar W = XSG.W
compileExp :: Exp -> MONAD ((XSG.Terms, XSG.Exps) -> (XSG.Terms, XSG.Exps))
compileExp (ExpId idp ) = liftM (compileSymbol (snd idp)) (MONAD (\tbl idx -> (tbl, (getSymbol tbl idp, idx))))
compileExp (ExpNew typ idp) = do s <- liftM (Variable (fst idp) . compileVar typ) (MONAD (,))
liftM (compileSymbol (snd idp)) (MONAD (\tbl idx -> (addSymbol s tbl, (s, idx))))
compileExp (ExpConcat esC) = liftM (\(ts, es) (ts', es') -> (ts++ts', es++es')) (compileExps esC)
compileExps :: Exps -> MONAD (XSG.Terms, XSG.Exps)
compileExps = foldr (ap . compileExp) (return ([], []))
compileAct :: XSG.State -> Act -> MONAD XSG.State
compileAct (ts, cd, es) (ActAssign esA ) = do (ts', es') <- compileExps esA
return (ts++ts', cd, es')
compileAct (ts, cd, es) (ActCompare esC) = do (ts', es') <- compileExps esC
when (length es /= length es') $ error ("clash coarity mismatch at position "++(XSG.myShow $ getExpsPos esC)++" ("++(XSG.myShow $ length es)++"/="++(XSG.myShow $ length es')++")")
return (ts++ts', cd++(zipWith (XSG.:=:) es es'), es')
compileBranch :: SymbolTable -> XSG.Index -> XSG.Exps -> Branch -> XSG.State
compileBranch tbl idx es br = snd $ f tbl idx
where MONAD f = foldM compileAct ([], [], es) br
compileFunc :: SymbolTable -> Func -> XSG.Func
compileFunc tbl (Func idp brs) = check `seq` XSG.FUNC id vs (st:sts)
where Function id (ar, co) = getSymbol tbl idp
vs = XSG.fresh ar XSG.X idx1
sts = map (compileBranch tbl idx2 (XSG.v2e vs)) brs
st = ([],[],XSG.v2e $ XSG.fresh co XSG.Y idx3)
check = zipWithM_ (\(_, _, es) br -> when (length es /= co) $ error ("function coarity mismatch at position "++(XSG.myShow $ getBranchPos br)++" ("++(XSG.myShow co)++"/="++(XSG.myShow $ length es)++")")) sts brs :: [()]
idx1:idx2:idx3:_ = XSG.newIdxs XSG.initIdx
compileModule :: Prog -> (SymbolTable, XSG.Prog)
compileModule prog = (tbl, map (compileFunc tbl) funcs)
where (decls, funcs) = uneither prog
tbl = foldr addSymbol emptySymbolTable $ concatMap compDecl decls
compDecl (FuncDecl ids tp) = map (flip Function tp . fst) ids
compDecl (CtorDecl ids tp) = map (flip Constructor tp . fst) ids
uneither = foldr (either (\x (xs, ys) -> (x:xs, ys)) (\y (xs, ys) -> (xs, y:ys))) ([], [])
-------------------------------------- UU_Parsing internals ---------------------------------------
convert = map f
where f '\CR' = '\n'
f x = x
instance Offside Token where
getPos t = let p = pos t
in (column p, line p)
{--------------------------------------------- TRASH ----------------------------------------------
getArity (Function _ (x,_)) = x
getArity (Constructor _ x) = x
getArity (Variable _ _) = 0
getCoarity (Function _ (_,x)) = x
getCoarity (Constructor _ _) = 1
getCoarity (Variable _ _) = 1
getSymbol (SymbolTable find _) x = find x
solve :: SymbolTable -> Exp -> (SymbolTable, Int, Int) -- find arity/coarity/new symbols
--solve tbl (ExpNew (id,_)) = (tbl !+! Variable id (XSG.P "_"), 0, 1) --TODO?
solve tbl (ExpId (id,pos)) = (tbl, getArity s, getCoarity s) where
s = mustGetSymbol tbl (id,pos)
solve tbl (ExpConcat es) = (tbl', 0, c0) where
(tbl', _, c0) = checkNoArity (foldl process (tbl, 0, 0) es)
checkNoArity x@(_, 0, _) = x
checkNoArity (_, a, _) = error ("expression " ++ showWithPos' es ++ " is not ground (arity " ++ XSG.myShow a ++ ")")
process (tbl, a1, c1) e2 = (tbl', a0, c0) where
(tbl', a2, c2) = solve tbl e2
(a0, c0) = (a1 -. c2 + a2 , c1 + c2 -. a1)
x -. y = if x>y then x-y else 0
coarity tbl exp = c where
(_, _, c) = solve tbl exp
class Cast a b where
cast :: a -> b
---------------------------------------------------------------------------------------------------
-- dont use offside 2d syntax right now
pOnsideSemi :: (InputState state Token, OutputState out) => OffsideParser state out Token String
pOnsideSemi = pOnside pSemi
---------------------------------------------------------------------------------------------------
compile (Func (id, pos) brs) = XSG.FUNC id (genVars 0 arity) body where
tbl = table
arity = getArity (getSymbol tbl id)
genVars k n = map xVar [k+1..k+n]
body = map compileBranch brs
compileBranch [ActAssign e] = [] XSG.:=> [XSG.RES res] where
res = map XSG.VAR (genVars arity (coarity tbl e))
patch :: XSG.Exp -> XSG.Exp
patch = flip XSG.renum []
testFun = "test , nil; ,cons !x !y."
main = coarity table (parseXSG "cons (concat !x !y) x (cons y nil)" ::Exp)
main' = (parseXSG prog ::Prog)
prog = concat [
"concat nil !ys , ys;",
" (cons !x !xs) !ys , cons x (concat xs ys).",
"split !xs , nil xs;",
" (cons !x !xs) , (!ys !zs) = split xs , (cons x ys) zs.",
"split' concat !xs !ys, xs ys."]
test str = map patch exps :: XSG.Exps where
(_,_,stack) = generateCalls table 0 (parseXSG str :: Exp)
exps = map cast (reverse stack)
--compile :: SymbolTable -> Func -> XSG.Func
xVar n = XSG.X [n] -- FIXME!! replace with XSG.P
--lVar n = XSG.P ("l" ++ XSG.myShow n) -- TODO?
data StackItem = StackItem Symbol [StackItem]
instance Cast StackItem XSG.Exp where
cast (StackItem (Variable _ bind) [] ) = XSG.VAR bind
cast (StackItem (Constructor id _) args) = XSG.C (id,[]) (map cast args)
type Stack = [StackItem]
type Index = Int
generateCalls :: SymbolTable -> Index -> Exp -> (SymbolTable, Index, Stack)
generateCalls tbl idx (ExpConcat es) = (tbl', idx', res) where
res = checkGround res'
(tbl', idx', res') = foldl process (tbl, idx, []) es
checkGround (res1:_) | isNotGround res1 = error ("expression " ++ showWithPos' es ++ " is not ground")
checkGround res = res
process (tbl, idx, stack) (ExpId (id,pos)) = (tbl, idx, eval (symbol `push` stack)) where
symbol = mustGetSymbol tbl (id,pos)
process (tbl, idx, stack) (ExpNew (id,pos)) = (tbl !+! var, idx+1, eval (var `push` stack )) where
var = Variable id (xVar idx)
process (tbl, idx, stack) (ExpConcat es) = (tbl', idx', foldr eval' stack stack') where
eval' x xs = eval (x:xs)
(tbl', idx', stack') = generateCalls tbl idx (ExpConcat es)
push symbol stack = StackItem symbol [] : stack
eval stack@(top:_) | isNotGround top = stack
eval (top1:top2:stack) | isNotGround top2 = eval (apply top2 top1 : stack) where
apply (StackItem ctor@(Constructor _ _) args) arg = StackItem ctor (args++[arg])
eval stack = stack -- dont need?
isGround (StackItem (Variable _ _ ) _ ) = True
isGround (StackItem (Constructor _ arity) args) = arity == length args
isNotGround = not.isGround
--------------------------------------------------------------------------------------------------}