LslPlus-0.1.0: Language/Lsl/Render.hs
module Language.Lsl.Render(renderCompiledScript) where
import Data.List(foldl',intersperse)
import Language.Lsl.Syntax(Expr(..),Func(..),FuncDec(..),Global(..),Handler(..),State(..),Statement(..),
Ctx(..),Var(..),LSLType(..),Component(..),ctxItems,validLSLScript,CompiledLSLScript(..))
-- | 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 globals funcs states) =
(renderString "// LSL script generated: " . renderString stamp . renderString "\n" .
renderGlobals globals . renderFuncs funcs . renderStates states) ""
renderSequence r = (foldl' (.) blank) . (map r)
renderGlobals = renderSequence renderGlobal
renderGlobal (GDecl var val) = renderVar var .
case val of
Nothing -> renderString ";\n"
Just expr -> renderString " = " . renderSimple expr . renderString ";\n"
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 (State (Ctx _ "default") handlers) =
renderString "default {\n" . renderHandlers handlers . renderString "}\n"
renderState (State (Ctx _ name) handlers) =
renderString "state " . renderString name . renderString " {\n" . renderHandlers handlers . renderString "}\n"
renderHandlers = renderSequence renderHandler
renderHandler (Handler (Ctx _ name) vars stmts) = renderHandler' name vars stmts
renderHandler' name vars stmts =
renderIndent 0 . 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 renderFunc
renderFunc (Func dec stmts) =
renderFuncDec dec . renderString "{\n" . renderStatements 0 stmts . renderString "}\n"
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 ')' . renderStatement True n stmt
renderStatement' n (DoWhile stmt expr) =
renderString "do " . 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 ")" . renderStatement True n stmt
renderStatement' n (If expr stmt1 stmt2) =
renderString "if (" . renderCtxExpr expr . renderChar ')' . 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
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) = shows 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) = renderVarAccess var . renderString " = " . renderCtxExpr 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) = renderVarAccess va . renderString "++"
renderExpression (PostDec va) = renderVarAccess va . renderString "--"
renderExpression (PreInc va) = renderString "++" . renderVarAccess va
renderExpression (PreDec va) = renderString "--" . renderVarAccess va
renderBinExpr op expr1 expr2 = renderChar '(' . renderCtxExpr expr1 . renderChar ' ' .
renderString op . renderChar ' ' . renderCtxExpr expr2 . renderChar ')'
renderAssignment va op expr = renderVarAccess va . renderChar ' ' . renderString op . renderChar ' ' . renderCtxExpr expr
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