LslPlus-0.4.1: src/Language/Lsl/Render.hs
module Language.Lsl.Render(renderCompiledScript,renderStatements,renderCtxStatement,renderStatement) where
import Data.List(foldl',intersperse)
import Language.Lsl.Syntax(Expr(..),Func(..),FuncDec(..),Global(..),Handler(..),State(..),Statement(..),
Ctx(..),Var(..),LSLType(..),Component(..),ctxItems,CompiledLSLScript(..),
SourceContext(..))
import Debug.Trace
tr s x = trace (s ++ show x) x
-- | Generate a string representing an LSL script from a timestamp (string)
-- and a compiled (i.e. validated, with referenced modules included) LSL script.
renderCompiledScript :: String -> CompiledLSLScript -> String
renderCompiledScript stamp (CompiledLSLScript comment globals funcs states) =
(renderString "// LSL script generated: " . renderString stamp . renderString "\n" .
renderString comment .
renderGlobals globals . renderFuncs funcs . renderStates states . renderString "\n") ""
renderSequence r = (foldl' (.) blank) . (map r)
renderGlobals = renderSequence renderGlobal
renderGlobal (GDecl (Ctx sc var) val) = renderPreText sc . renderVar var .
case val of
Nothing -> renderString ";"
Just expr -> renderString " = " . renderSimple expr . renderString ";"
renderCtxSimple (Ctx _ expr) = renderSimple expr
renderSimple (Neg expr) = renderChar '-' . renderCtxExpr expr
renderSimple (ListExpr l) =
renderChar '[' .
(foldl' (.) id $ intersperse (renderChar ',') $ map renderCtxSimple l) .
renderChar ']'
renderSimple (VecExpr x y z) = renderChar '<' . renderCtxSimple x .
renderChar ',' . renderCtxSimple y .
renderChar ',' . renderCtxSimple z .
renderChar '>'
renderSimple (RotExpr x y z s) = renderChar '<' . renderCtxSimple x .
renderChar ',' . renderCtxSimple y .
renderChar ',' . renderCtxSimple z .
renderChar ',' . renderCtxSimple s .
renderChar '>'
renderSimple e = renderExpression e
renderStates = renderSequence renderState
renderState (Ctx ssc (State (Ctx sc "default") handlers)) =
renderPreText ssc .
renderString "default {\n" . renderHandlers handlers . renderString "}"
renderState (Ctx ssc (State (Ctx _ name) handlers)) =
renderPreText ssc .
renderString "state " . renderString name . renderString " {\n" . renderHandlers handlers . renderString "}"
renderHandlers = renderSequence renderHandler
renderHandler (Ctx _ (Handler (Ctx sc name) vars stmts)) = renderPreText1 (renderIndent 0) sc . renderHandler' name vars stmts
renderHandler' name vars stmts =
renderString name . renderChar '(' . renderVarList (ctxItems vars) . renderString ") {\n" .
renderStatements 1 stmts . renderIndent 0 . renderString "}\n"
renderChar = showChar
renderVar (Var nm t) = (renderType t) . renderChar ' ' . (renderString nm)
renderFuncDec (FuncDec name t vars) =
let sp = if t == LLVoid then "" else " " in
renderType t . renderString sp . renderString (ctxItem name) . renderChar '(' .
renderVarList (ctxItems vars) . renderChar ')'
renderVarList [] = blank
renderVarList (v:vars) =
(renderVar v) .
let render' [] = blank
render' (v:vars) = renderChar ',' . renderVar v . render' vars in render' vars
renderFuncs = renderSequence renderCtxFunc
renderCtxFunc (Ctx sc func) = renderPreText sc . renderFunc func
renderFunc (Func dec stmts) =
renderFuncDec dec . renderString "{\n" . renderStatements 0 stmts . renderString "}"
renderIndent 0 = renderString " "
renderIndent n = renderString " " . renderIndent (n - 1)
renderCtxStatement hang n (Ctx _ s) = renderStatement hang n s
renderStatements n = renderSequence (renderCtxStatement False n)
doHang True n = renderString " "
doHang False n = renderIndent n
renderOptionalExpression Nothing = blank
renderOptionalExpression (Just expr) = renderCtxExpr expr
renderStatement hang n stmt = doHang hang n . renderStatement' n stmt
renderStatement' n (Compound stmts) =
renderString "{\n" . renderStatements (n+1) stmts . renderIndent n . renderString "}\n"
renderStatement' n (While expr stmt) =
renderString "while (" . renderCtxExpr expr . renderChar ')' .
case stmt of
NullStmt -> renderString ";\n"
_ -> renderStatement True n stmt
renderStatement' n (DoWhile stmt expr) =
renderString "do " .
(case stmt of
NullStmt -> renderString ";\n"
_ -> renderStatement True n stmt) . doHang False n . renderString "while (" . renderCtxExpr expr . renderString ");\n"
renderStatement' n (For mexpr1 mexpr2 mexpr3 stmt) =
renderString "for (" . renderCtxExprs "" mexpr1 . renderString "; " . renderOptionalExpression mexpr2 .
renderString "; " . renderCtxExprs "" mexpr3 . renderString ")" .
case stmt of
NullStmt -> renderString ";\n"
_ -> renderStatement True n stmt
renderStatement' n (If expr stmt1 stmt2) =
renderString "if (" . renderCtxExpr expr . renderChar ')' .
(case stmt1 of
NullStmt -> renderString ";\n"
If expr (Compound _) _ -> renderStatement True n stmt1
If expr _ NullStmt -> case stmt2 of
NullStmt -> renderStatement True n stmt1
_ -> renderStatement True n (Compound [Ctx Nothing stmt1])
_ -> renderStatement True n stmt1) .
case stmt2 of
NullStmt -> blank
_ -> renderIndent n . renderString "else " . (renderStatement True n stmt2)
renderStatement' n (Decl var val) =
renderVar var .
case val of
Nothing -> renderString ";\n"
Just expr -> renderString " = " . renderCtxExpr expr . renderString ";\n"
renderStatement' n (NullStmt) = blank . renderString "\n"
renderStatement' n (Return Nothing) = renderString "return;\n"
renderStatement' n (Return (Just expr)) = renderString "return " . renderCtxExpr expr . renderString ";\n";
renderStatement' n (StateChange name) = renderString "state " . renderString name . renderString ";\n";
renderStatement' n (Do expr) = renderCtxExpr expr . renderString ";\n";
renderStatement' n (Label s) = renderChar '@' . renderString s . renderString ";\n";
renderStatement' n (Jump s) = renderString "jump " . renderString s . renderString ";\n";
renderExpressions prefix [] = blank
renderExpressions prefix (e:es) = renderString prefix . renderExpression e . renderExpressions "," es
renderCtxName (Ctx _ n) = renderString n
renderCtxExpr (Ctx _ e) = renderExpression e
renderCtxExprs prefix [] = blank
renderCtxExprs prefix (e:es) = renderString prefix . renderCtxExpr e . renderCtxExprs "," es
renderExpression (IntLit i) = shows i
renderExpression (FloatLit f) = shows f
renderExpression (StringLit s) = renderString ('"':go s)
where go [] = "\""
go ('\\':s) = '\\':'\\':go s
go ('\t':s) = '\\':'t':go s
go ('\n':s) = '\\':'n':go s
go ('"':s) = '\\':'"':go s
go (c:s) = c:go s
renderExpression (KeyLit k) = shows k
renderExpression (VecExpr x y z) =
renderChar '<' . renderCtxExpr x . renderChar ',' .
renderCtxExpr y . renderChar ',' .
renderCtxExpr z . renderChar '>'
renderExpression (RotExpr x y z s) =
renderChar '<' . renderCtxExpr x . renderChar ',' .
renderCtxExpr y . renderChar ',' .
renderCtxExpr z . renderChar ',' .
renderCtxExpr s . renderChar '>'
renderExpression (ListExpr l) =
let r prefix [] = blank
r prefix (i:is) = renderString prefix . renderCtxExpr i . r "," is
in renderChar '[' . r "" l . renderChar ']'
renderExpression (Add expr1 expr2) = renderBinExpr "+" expr1 expr2
renderExpression (Sub expr1 expr2) = renderBinExpr "-" expr1 expr2
renderExpression (Mul expr1 expr2) = renderBinExpr "*" expr1 expr2
renderExpression (Div expr1 expr2) = renderBinExpr "/" expr1 expr2
renderExpression (Mod expr1 expr2) = renderBinExpr "%" expr1 expr2
renderExpression (BAnd expr1 expr2) = renderBinExpr "&" expr1 expr2
renderExpression (Xor expr1 expr2) = renderBinExpr "^" expr1 expr2
renderExpression (BOr expr1 expr2) = renderBinExpr "|" expr1 expr2
renderExpression (Lt expr1 expr2) = renderBinExpr "<" expr1 expr2
renderExpression (Gt expr1 expr2) = renderBinExpr ">" expr1 expr2
renderExpression (Le expr1 expr2) = renderBinExpr "<=" expr1 expr2
renderExpression (Ge expr1 expr2) = renderBinExpr ">=" expr1 expr2
renderExpression (And expr1 expr2) = renderBinExpr "&&" expr1 expr2
renderExpression (Or expr1 expr2) = renderBinExpr "||" expr1 expr2
renderExpression (ShiftL expr1 expr2) = renderBinExpr "<<" expr1 expr2
renderExpression (ShiftR expr1 expr2) = renderBinExpr ">>" expr1 expr2
renderExpression (Inv expr) = renderChar '(' . renderChar '~' . renderCtxExpr expr . renderChar ')'
renderExpression (Not expr) = renderChar '(' . renderChar '!' . renderCtxExpr expr . renderChar ')'
renderExpression (Neg expr) = renderChar '(' . renderChar '-' . renderCtxExpr expr . renderChar ')'
renderExpression (Call name exprs) = renderCtxName name . renderChar '(' . renderCtxExprs "" exprs . renderChar ')'
renderExpression (Cast t expr) = renderString "((" . renderType t . renderChar ')' . renderCtxExpr expr . renderChar ')'
renderExpression (Get var) = renderVarAccess var
--renderExpression (Const var) = renderVarAccess var
--renderExpression (Set var expr) = renderChar '(' . renderVarAccess var . renderString " = " . renderCtxExpr expr . renderChar ')'
renderExpression (Set va expr) = renderAssignment va "=" expr
renderExpression (IncBy va expr) = renderAssignment va "+=" expr
renderExpression (DecBy va expr) = renderAssignment va "-=" expr
renderExpression (MulBy va expr) = renderAssignment va "*=" expr
renderExpression (DivBy va expr) = renderAssignment va "/=" expr
renderExpression (ModBy va expr) = renderAssignment va "%=" expr
renderExpression (Equal expr1 expr2) = renderBinExpr "==" expr1 expr2
renderExpression (NotEqual expr1 expr2) = renderBinExpr "!=" expr1 expr2
renderExpression (PostInc va) = renderInParens (renderVarAccess va . renderString "++")
renderExpression (PostDec va) = renderInParens (renderVarAccess va . renderString "--")
renderExpression (PreInc va) = renderInParens (renderString "++" . renderVarAccess va)
renderExpression (PreDec va) = renderInParens (renderString "--" . renderVarAccess va)
renderInParens f = renderChar '(' . f . renderChar ')'
renderBinExpr op expr1 expr2 = renderChar '(' . renderCtxExpr expr1 . renderChar ' ' .
renderString op . renderChar ' ' . renderCtxExpr expr2 . renderChar ')'
renderAssignment va op expr =
renderChar '(' . renderVarAccess va . renderChar ' ' . renderString op . renderChar ' ' . renderCtxExpr expr . renderChar ')'
renderComponent All = blank
renderComponent X = renderString ".x"
renderComponent Y = renderString ".y"
renderComponent Z = renderString ".z"
renderComponent S = renderString ".s"
renderVarAccess (v,c) = renderCtxName v . renderComponent c
renderString s s' = s ++ s'
renderType LLList = renderString "list"
renderType LLInteger = renderString "integer"
renderType LLVector = renderString "vector"
renderType LLFloat = renderString "float"
renderType LLString = renderString "string"
renderType LLRot = renderString "rotation"
renderType LLKey = renderString "key"
renderType LLVoid = blank
blank :: String -> String
blank = id
renderPreText :: (Maybe SourceContext) -> String -> String
renderPreText = maybe (renderString "\n") (renderString . srcPreText)
renderPreText1 :: (String -> String) -> (Maybe SourceContext) -> String -> String
renderPreText1 f = maybe (renderString "\n" . f) (renderString . srcPreText)