LslPlus 0.3.4 → 0.3.5
raw patch · 8 files changed
+171/−59 lines, 8 files
Files
- LslPlus.cabal +2/−1
- src/Language/Lsl/Internal/Exec.hs +59/−29
- src/Language/Lsl/Internal/InternalLLFuncs.hs +9/−6
- src/Language/Lsl/Internal/Optimize.hs +32/−16
- src/Language/Lsl/Render.hs +2/−2
- src/Language/Lsl/Syntax.hs +38/−4
- src/LslPlus.hs +1/−1
- src/Text/Here.hs +28/−0
LslPlus.cabal view
@@ -1,5 +1,5 @@ Name: LslPlus -version: 0.3.4 +version: 0.3.5 Synopsis: An execution and testing framework for the Linden Scripting Language (LSL) Description: Provides a framework for executing Linden Scripting Language scripts offline, @@ -74,6 +74,7 @@ Language.Lsl.UnitTest Language.Lsl.UnitTestEnv Language.Lsl.WorldDef + Text.Here Text.ParserCombinators.ParsecExtras.Language Text.ParserCombinators.ParsecExtras.Token Ghc-Options: -fwarn-unused-imports
src/Language/Lsl/Internal/Exec.hs view
@@ -1,4 +1,4 @@-{-# OPTIONS_GHC -XNoMonomorphismRestriction #-} +{-# OPTIONS_GHC -XNoMonomorphismRestriction -XDeriveDataTypeable #-} module Language.Lsl.Internal.Exec( ScriptImage(..), EvalState, @@ -22,7 +22,8 @@ --import Debug.Trace import Data.Bits((.&.),(.|.),xor,shiftL,shiftR,complement) -import Data.List(intersperse,find) +import Data.List(intersperse,find,intercalate) +import Data.Data import qualified Data.Map as M import Data.Maybe(isJust) @@ -49,17 +50,21 @@ findState, fromMCtx, predefFuncs, - isTextLocation) + isTextLocation, + rmCtx) import Language.Lsl.Internal.Type(LSLType(..),LSLValue(..),typeOfLSLComponent,typeOfLSLValue,toFloat,toSVal, lslShowVal,replaceLslValueComponent,vecMulScalar,rotMulVec,parseVector,parseRotation, parseInt,parseFloat,invRot,rotMul,vcross,Component(..),lslValueComponent) import Language.Lsl.Internal.Key(nullKey,nextKey) import Language.Lsl.Internal.Evaluation(EvalResult(..),Event(..),ScriptInfo(..)) import Language.Lsl.Internal.Constants(findConstVal,llcZeroRotation,llcZeroVector) +import Language.Lsl.Render import Control.Monad(foldM_,when,mplus,msum,join,zipWithM) import Control.Monad.State(lift,StateT(..)) import Control.Monad.Error(ErrorT(..)) +import Debug.Trace(trace) + -- initialize a script for execution initLSLScript :: RealFloat a => CompiledLSLScript -> ScriptImage a initLSLScript (CompiledLSLScript globals fs ss) = @@ -153,7 +158,7 @@ [] -> (Nothing,Nothing) _ -> let (_,ctx,_,_) = last frames in (ctx,Just 1) collapseFrame (Frame name ctx line (ss,_)) = - (name,ctx,line,concat $ map fst ss) + (name,ctx,line,concat $ map scopeMem ss) -- a soft reset occurs when a script that has been running, but -- has been persisted to inventory, is reactivated. The curState -- stays the same, but if the script was running or sleeping, the @@ -304,13 +309,15 @@ frameStacks :: (ScopeStack a, EvalStack) } deriving (Show) type LabelSet = [LBlock] -type Scope a = (MemRegion a,LabelSet) +--type Scope a = (MemRegion a,LabelSet) type ScopeStack a = [Scope a] type CallStack a = [Frame a] - +data Scope a = Scope { scopeMem :: !(MemRegion a), scopeLabels :: !LabelSet, scopeMarks :: Int } + deriving (Show) + readVarScope :: String -> Scope a -> Maybe (LSLValue a) -readVarScope name (mem,_) = readMem name mem +readVarScope name (Scope { scopeMem = mem }) = readMem name mem readVarSStack :: String -> ScopeStack a -> Maybe (LSLValue a) readVarSStack name ss = foldl mplus Nothing $ map (readVarScope name) ss readVarFrame :: String -> Frame a -> Maybe (LSLValue a) @@ -319,7 +326,7 @@ readVarCallStack name = (readVarFrame name) . head writeVarScope :: String -> LSLValue a -> Scope a -> Maybe (Scope a) -writeVarScope name val (mem,l) = writeMem name val mem >>= return . (flip (,) l) +writeVarScope name val s@(Scope { scopeMem = mem} ) = writeMem name val mem >>= \ mem' -> return s { scopeMem = mem' } writeVarSStack rs name val [] = Nothing writeVarSStack rs name val (s:ss) = case writeVarScope name val s of @@ -344,11 +351,9 @@ | EvCons | EvMkVec | EvMkRot | EvPop | EvReturn | EvDiscard | EvBind String LSLType | EvCond Statement Statement | EvCall String (Maybe SourceContext) [Var] [Ctx Statement] Bool - | EvPredef String | EvLoop Expr [Ctx Expr] Statement - deriving (Show) - --- Note: lifted from Hudak, p.273 ---queryState :: Monad w => (EvalState w a -> a) -> Eval w b a + | EvPredef String | EvLoop Expr [Ctx Expr] Statement | EvMark + deriving (Show,Data,Typeable) + queryState q = evalT (\s -> (q s, s)) updateState :: Monad w => (EvalState w a -> EvalState w a) -> Eval w a () updateState u = evalT (\s -> ((), u s)) @@ -430,7 +435,7 @@ pushScope mem labels = do (frame:frames) <- getCallStack let (ss,es) = frameStacks frame - setCallStack (frame { frameStacks = ((mem,labels):ss,es) }:frames) + setCallStack (frame { frameStacks = (Scope { scopeMem = mem, scopeLabels = labels, scopeMarks = 0}:ss,es) }:frames) pushVal value = do vstack <- getVStack @@ -468,12 +473,23 @@ let (ss,e:es) = frameStacks frame setCallStack (frame { frameStacks = (ss,es) }:frames) return e +getEStack :: Monad w => Eval w a [EvalElement] +getEStack = + do (frame:frames) <- getCallStack + return $ snd $ frameStacks frame popElements 0 = return () popElements n = do popElement popElements (n - 1) +popMarks 0 = return () +popMarks n = do + e <- popElement + case e of + EvMark -> popMarks (n - 1) + _ -> popMarks n + pushElement element = do (frame:frames) <- getCallStack let (ss,es) = frameStacks frame @@ -529,8 +545,8 @@ initVar1 name t mval = do --(((m,l):ss,es):cs) <- getCallStack (frame:frames) <- getCallStack - let ((m,l):ss,es) = frameStacks frame - let frame' = frame { frameStacks = (((initVar name t mval):m,l):ss,es) } + let (sc@Scope { scopeMem = m }:ss,es) = frameStacks frame + let frame' = frame { frameStacks = (sc { scopeMem = initVar name t mval:m }:ss,es) } setCallStack (frame':frames) initVars1 :: (RealFloat a, Read a, Monad w) => [Var] -> [LSLValue a] -> Eval w a () @@ -543,14 +559,23 @@ let (ss,es) = frameStacks frame case ss of [] -> fail ("label " ++ name ++ " not found") - ((m,l):ss') -> + (Scope {scopeLabels = l, scopeMarks = marks}:ss') -> case findLBlock name l of - Just (LBlock _ stmts) -> return (n,stmts) + Just (LBlock _ stmts) -> return (n + marks,stmts) Nothing -> do setCallStack (frame { frameStacks = (ss',es) }:frames) - f (n + 1) + f (n + marks + 1) in f 1 +modMark f = do + (frame:frames) <- getCallStack + let (ss,es) = frameStacks frame + case ss of + [] -> return () + (sc@Scope { scopeMarks = marks }:ss') -> do + let marks' = f marks + let sc' = sc { scopeMarks = marks' } + setCallStack (frame { frameStacks = (sc':ss',es) }:frames) data ExecutionState = Waiting | Executing | Halted | SleepingTil Int | Erroneous String | Crashed String | Suspended Breakpoint | WaitingTil Int -- in a waiting state, but won't process new events until time t @@ -590,7 +615,7 @@ initStacks pushFrame (concat $ intersperse "." path) ctx Nothing pushScope mem $ labelBlocks stmts - pushElement (EvBlock stmts) + pushElements [EvMark,EvBlock stmts] setExecutionState Executing where updateGlobals [] = return () updateGlobals ((name,val):bs) = @@ -644,7 +669,7 @@ do initStacks pushFrame name ctx Nothing pushScope mem $ labelBlocks stmts - pushElement (EvBlock stmts) + pushElements [EvMark,EvBlock stmts] setExecutionState Executing setCurrentEvent event evalScript maxTick queue' @@ -698,6 +723,7 @@ in do cs <- getCallStack vs <- getVStack + es <- getEStack noMoreElements <- elementStackEmpty if noMoreElements then popAndCheck else do @@ -708,9 +734,10 @@ logMsg ("return: " ++ lslShowVal val) popAndCheck EvBlock [] -> popScope >> eval' + EvMark -> modMark ((-)1) >> continue EvBlock (s:ss) -> pushElements [EvBlock ss,EvCtxStatement s] EvCtxStatement s -> do - pushElements [EvStatement $ ctxItem s] + pushElement (EvStatement $ ctxItem s) case srcCtx s of Just (SourceContext { srcTextLocation = txtl }) -> let bp = mkBreakpoint (textName txtl) (textLine0 txtl) 0 in @@ -727,26 +754,29 @@ continue EvStatement (Decl (Var name t) mexpr) -> pushElements [EvBind name t,EvMexpr $ fromMCtx mexpr] EvStatement (If expr stmt1 stmt2) -> pushElements [EvCond stmt1 stmt2,EvExpr $ ctxItem expr] - EvStatement (While expr stmt) -> pushElements [EvLoop (ctxItem expr) [] stmt,EvExpr $ ctxItem expr] - EvStatement (DoWhile stmt expr) -> - pushElements [EvLoop (ctxItem expr) [] stmt, EvExpr (ctxItem expr),EvStatement stmt] + EvStatement (While expr stmt) -> modMark (+1) >> pushElements [EvMark,EvLoop (ctxItem expr) [] stmt,EvExpr $ ctxItem expr] + EvStatement (DoWhile stmt expr) -> modMark (+1) >> + pushElements [EvMark,EvLoop (ctxItem expr) [] stmt, EvExpr (ctxItem expr),EvStatement stmt] EvStatement (For mexpr1 mexpr2 mexpr3 stmt) -> do let expr = case mexpr2 of Nothing -> (IntLit 1) Just expr2 -> ctxItem expr2 + modMark (+1) + pushElement EvMark pushElement (EvLoop expr (mexpr3) stmt) pushElement (EvExpr expr) pushElements [EvDiscard, EvExpr (ListExpr mexpr1)] continue EvStatement (Compound ss) -> do pushScope [] $ labelBlocks ss + pushElement EvMark pushElement (EvBlock ss) continue EvStatement (Label _) -> eval' EvStatement (Jump name) -> do (n,stmts) <- unwindToLabel name - popElements n - pushElement (EvBlock stmts) + popMarks n + pushElements [EvMark,EvBlock stmts] continue EvMexpr Nothing -> pushVal VoidVal >> continue EvMexpr (Just expr) -> pushElements [EvExpr expr] @@ -845,7 +875,7 @@ -- a void function may not have an explicit return; if it does, this -- element will get popped off without being evaluated. when voidFunc (pushElement EvReturn >> pushElement (EvMexpr Nothing)) - pushElement (EvBlock stmts) + pushElements [EvMark,EvBlock stmts] continue EvPredef name -> evalPredef' name EvGet (name,c) -> @@ -962,7 +992,7 @@ (IVal i1,FVal f2) -> toLslBool $ fromInt i1 == f2 (v1,v2) -> toLslBool $ v1 == v2 EvNe -> evalBinary $ \ val1 val2 -> case (val1,val2) of - (LVal l1, LVal l2) -> toLslBool $ length l1 /= length l2 -- special case of LSL weirdness + (LVal l1, LVal l2) -> IVal (length l1 - length l2) -- special case of LSL weirdness (SVal s, KVal k) -> toLslBool $ s /= k (KVal k, SVal s) -> toLslBool $ k /= s (FVal f1,IVal i2) -> toLslBool $ f1 /= fromInt i2
src/Language/Lsl/Internal/InternalLLFuncs.hs view
@@ -352,12 +352,15 @@ listStatSumSquares l = sum $ map (**2.0) l listStatGeometricMean l = product l ** (1.0 / fromInt (length l)) -llRot2Angle _ [RVal _ _ _ w] = continueWith $ FVal (2.0 * acos w) -llRot2Axis _ [RVal x y z w] = - let sinVal = sqrt (1.0 - w*w) - v = if sinVal == 0.0 then VVal 0.0 0.0 0.0 - else VVal (x/sinVal) (y/sinVal) (z/sinVal) in - continueWith $ v +normalizeQuaternion (x,y,z,w) = (x/mag,y/mag,z/mag,w/mag) + where mag = sqrt (x*x + y*y + z*z + w*w) +llRot2Angle _ [RVal x y z w] = continueWith $ FVal (2.0 * acos w') + where (_,_,_,w') = normalizeQuaternion (x,y,z,w) +llRot2Axis _ [RVal x y z w] = continueWith v + where (x',y',z',w') = normalizeQuaternion (x,y,z,w) + sinVal = sqrt (1.0 - w'*w') + v = if sinVal == 0.0 then VVal 0.0 0.0 0.0 + else VVal (x'/sinVal) (y'/sinVal) (z'/sinVal) llAxisAngle2Rot _ [vval@(VVal x y z), FVal r] = (continueWith . rot2RVal) (axisAngleToRotation (vVal2Vec vval) r)
src/Language/Lsl/Internal/Optimize.hs view
@@ -37,7 +37,6 @@ scc = graphInfo fsIn funFacts = sccsPurity gcs basicFunctionFacts scc pure = Set.fromList [ nm | (nm,ff) <- M.toList funFacts, isPureFunction ff] - --pure = trace (show pure') pure' ifs = [ f | AcyclicSCC f <- scc, inlineable f] -- inlineables nifs = [ f | f <- fsIn, fname f `notElem` (map fname ifs)] -- non-inlineables ss1 = if inline then simp $ map runInliningOnState (simp ss) else ss @@ -120,7 +119,7 @@ data OptimizerState = OptimizerState { optAllFuncs :: !(M.Map String (Ctx Func)), optFunFacts :: !(M.Map String FunctionFacts), - optNameIndex :: Int, + optNameIndex :: !Int, optGlobalNames :: !(Set.Set String), optVerbotenNames :: !(Set.Set String), optLocals :: ![[String]], @@ -128,7 +127,7 @@ optRenames :: !(M.Map String String), -- names that must be renamed in the function to-be-inlined optRewrites :: !(M.Map String Expr), optRetVar :: !(Maybe String), - optStmts :: ![[Ctx Statement]] } + optStmts :: ![[Ctx Statement]] } deriving Show type OState a = State.State OptimizerState a @@ -158,7 +157,7 @@ refreshOState :: OState () refreshOState = do st <- get - put st { optRenames = M.empty, optRetVar = Nothing, optStmts = [] } + put $ st { optRenames = M.empty, optRetVar = Nothing, optStmts = [] } pushLocal s = do st <- get @@ -171,9 +170,8 @@ let i = optNameIndex st let name = "_" ++ s ++ show i put st { optNameIndex = i + 1 } - st <- get verboten <- isVerboten name - if not verboten + if not verboten then do addVerboten name return name else mkName s -- make another... @@ -261,7 +259,6 @@ -- simplify $ nullCtx (Compound (parmVars ++ stmts))) where ps = funcParms fd -tr x = trace (show $ nullify x) x nullify :: Data a => a -> a nullify = everywhere (mkT doNullify) where doNullify :: Maybe SourceContext -> Maybe SourceContext @@ -427,7 +424,8 @@ let locals = optLocals st put st { optLocals = []:locals } sss <- mapM performInliningForStmt ss - put st { optLocals = locals } + st' <- get + put st' { optLocals = locals } return [(nullCtx (Compound (concat sss)))] performInliningForStmt (Ctx _ (While expr s)) = do refreshOState @@ -854,6 +852,10 @@ nameToLit :: M.Map String Expr -> String -> Maybe Expr nameToLit m s = predefToLit s `mplus` constVarToLit m s +nameToLitR m s = case nameToLit m s of + Just e@(Get (nm,All)) -> nameToLitR m (ctxItem nm) `mplus` (Just e) + v -> v + exprsToVals :: [Ctx Expr] -> Maybe [LSLValue Double] exprsToVals es = mapM exprToVal es where exprToVal :: Ctx Expr -> Maybe (LSLValue Double) @@ -873,7 +875,7 @@ Nothing -> Nothing Just vs -> Just $ LVal vs exprToVal _ = Nothing - + simplifyE :: Expr -> SimpState Expr simplifyE (Neg (Ctx _ (IntLit i))) = return (IntLit (-i)) simplifyE (Not (Ctx _ (IntLit i))) = return (IntLit (fromBool (i == 0))) @@ -908,13 +910,11 @@ simplifyE (Le (Ctx _ (FloatLit i)) (Ctx _ (FloatLit j))) = return (IntLit (bb2int (<=) i j)) simplifyE (Equal (Ctx _ (FloatLit i)) (Ctx _ (FloatLit j))) = return (IntLit (bb2int (==) i j)) simplifyE (NotEqual (Ctx _ (FloatLit i)) (Ctx _ (FloatLit j))) = return (IntLit (bb2int (==) i j)) -simplifyE e@(Div (Ctx _ (FloatLit i)) (Ctx _ (FloatLit j))) | j /= 0 = return (FloatLit ( i / j)) - | otherwise = return e +simplifyE e@(Div (Ctx _ (FloatLit i)) (Ctx _ (FloatLit j))) = return $ checkVal e (FVal ( i / j)) simplifyE (Add (Ctx _ (IntLit i)) (Ctx _ (FloatLit j))) = return (FloatLit (fromIntegral i + j)) simplifyE (Mul (Ctx _ (IntLit i)) (Ctx _ (FloatLit j))) = return (FloatLit (fromIntegral i * j)) simplifyE (Sub (Ctx _ (IntLit i)) (Ctx _ (FloatLit j))) = return (FloatLit (fromIntegral i - j)) -simplifyE e@(Div (Ctx _ (IntLit i)) (Ctx _ (FloatLit j))) | j /= 0 = return (FloatLit ( fromIntegral i / j)) - | otherwise = return e +simplifyE e@(Div (Ctx _ (IntLit i)) (Ctx _ (FloatLit j))) = return $ checkVal e (FVal ( fromIntegral i / j)) simplifyE (Equal (Ctx _ (IntLit i)) (Ctx _ (FloatLit j))) = return (IntLit (if fromIntegral i == j then 1 else 0)) simplifyE (NotEqual (Ctx _ (IntLit i)) (Ctx _ (FloatLit j))) = return (IntLit (if fromIntegral i == j then 0 else 1)) simplifyE (Lt (Ctx _ (IntLit i)) (Ctx _ (FloatLit j))) = return (IntLit (if fromIntegral i < j then 1 else 0)) @@ -940,7 +940,7 @@ where name = ctxItem nm newExpr = do m <- get >>= return . siConstants - return $ case nameToLit m name of + return $ case nameToLitR m name of Nothing -> e Just e' -> case (c,e') of (All,VecExpr _ _ _) -> e @@ -970,7 +970,7 @@ then case simSFunc (script,[nm]) [] vs of Left _ -> return e Right (VoidVal,_) -> return e - Right (v,_) -> return $ valToExpr v + Right (v,_) -> return $ checkVal e v else return e simplifyE e@(Cast LLString (Ctx _ (IntLit i))) = return (StringLit (show i)) simplifyE e@(Cast LLString (Ctx _ (FloatLit f))) = return (StringLit s) @@ -984,6 +984,22 @@ simplifyE e@(RotExpr eX eY eZ eS) = return (RotExpr (toFloatLit eX) (toFloatLit eY) (toFloatLit eZ) (toFloatLit eS)) simplifyE e = return e +infinity :: Double +infinity = read "Infinity" +maxFloat :: Double +maxFloat = (1 + fromIntegral (2^23 - 1) / (2 ^23)) * fromIntegral (2^127) +minFloat = -maxFloat + +invalidLLFloat f = isNaN f || f == infinity || f == -infinity || f < minFloat || f > maxFloat +checkVal :: Expr -> LSLValue Double -> Expr +checkVal expr v@(FVal f) | invalidLLFloat f = expr + | otherwise = valToExpr v +checkVal expr v@(VVal x y z) | invalidLLFloat x || invalidLLFloat y || invalidLLFloat z = expr + | otherwise = valToExpr v +checkVal expr v@(RVal x y z w) | invalidLLFloat x || invalidLLFloat y || invalidLLFloat z || invalidLLFloat w = expr + | otherwise = valToExpr v +checkVal _ v = valToExpr v + -- could simplify for other types, but this should be sufficient for the main use case simplifyS (If (Ctx _ (IntLit 0)) _ stmt) = return stmt simplifyS (If (Ctx _ (IntLit _)) stmt _) = return stmt @@ -1014,4 +1030,4 @@ srcContext _ = True stopCondition :: Data a => a -> Bool -stopCondition = (False `mkQ` string `extQ` srcContext)+stopCondition = (False `mkQ` string `extQ` srcContext)
src/Language/Lsl/Render.hs view
@@ -1,4 +1,4 @@-module Language.Lsl.Render(renderCompiledScript) where +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(..), @@ -102,7 +102,7 @@ renderString "for (" . renderCtxExprs "" mexpr1 . renderString "; " . renderOptionalExpression mexpr2 . renderString "; " . renderCtxExprs "" mexpr3 . renderString ")" . case stmt of - NullStmt -> renderString ";n" + NullStmt -> renderString ";\n" _ -> renderStatement True n stmt renderStatement' n (If expr stmt1 stmt2) = renderString "if (" . renderCtxExpr expr . renderChar ')' .
src/Language/Lsl/Syntax.hs view
@@ -49,7 +49,8 @@ compileLibrary, VState, emptyValidationState, - rewriteCtxExpr) where + rewriteCtxExpr, + rmCtx) where import Language.Lsl.Internal.Type(Component(..),LSLType(..),lslTypeString) import Language.Lsl.Internal.Constants(isConstant,findConstType) @@ -58,8 +59,9 @@ import Language.Lsl.Internal.AccessGenerator(genAccessorsForType,genMAccessorsForType) import Language.Lsl.Internal.Pragmas(Pragma(..)) import Data.Generics +import Data.Generics.Extras.Schemes import Data.Data(Data,Typeable) -import Data.List(find,sort,sortBy,nub,foldl') +import Data.List(find,sort,sortBy,nub,foldl',nubBy,deleteFirstsBy) import qualified Data.Map as M import Data.Maybe(isJust,isNothing) import Language.Lsl.Internal.Util(ctx,findM,lookupM,filtMap,throwStrError) @@ -79,6 +81,11 @@ isTextLocation (Just (TextLocation _ _ _ _ _)) = True isTextLocation _ = False +rmCtx :: Data a => a -> a +rmCtx = everywhere (mkT doNullify) + where doNullify :: Maybe SourceContext -> Maybe SourceContext + doNullify _ = Nothing + -- | A wrapper that can associate a source code context with a value (e.g. a syntax value). data Ctx a = Ctx { srcCtx :: Maybe SourceContext, ctxItem :: a } deriving (Show,Typeable,Data) instance Functor Ctx where @@ -461,9 +468,33 @@ safeHead [] = Nothing safeHead (x:_) = Just x -compileLSLScript' :: Library ->LSLScript -> Validity CompiledLSLScript + +compileLSLScript' :: Library -> LSLScript -> Validity CompiledLSLScript compileLSLScript' library script = evalState (compileLSLScript script) (emptyValidationState { vsLib = library }) +collectLabels :: Data a => a -> [(String,Maybe SourceContext)] +collectLabels = everythingBut (False `mkQ` string `extQ` sctx) (++) [] ([] `mkQ` lab) + where string :: String -> Bool + string = const True + sctx :: SourceContext -> Bool + sctx = const True + lab :: Ctx Statement -> [(String,Maybe SourceContext)] + lab (Ctx ctx (Label s)) = [(s,ctx)] + lab _ = [] + +warnLabelsMany :: Data a => [a] -> [CodeErr] +warnLabelsMany = concatMap warnLabels + +warnLabelsStates = concatMap warnLabelsState + where warnLabelsState (State _ hs) = warnLabelsMany hs + +warnLabels :: Data a => a -> [CodeErr] +warnLabels x = map (\ (name,ctx) -> (ctx,"label " ++ name ++ " is already defined (problem for LSL/Mono)")) problems + where problems = deleteFirstsBy fstEq labels uniques + labels = collectLabels x + uniques = nubBy fstEq labels + fstEq = flip ((==) . fst) . fst + compileLSLScript :: LSLScript -> VState (Validity CompiledLSLScript) compileLSLScript (LSLScript globs states) = do preprocessGlobDefs_ "" globs @@ -477,7 +508,10 @@ globals <- get'vsGlobals funcs <- get'vsFuncs states <- get'vsStates - return $ Right $ CompiledLSLScript (reverse globals) (reverse funcs) (reverse states) + -- for now, error on label warnings since we have no warnings + return $ case warnLabelsStates states ++ warnLabelsMany funcs of + [] -> Right $ CompiledLSLScript (reverse globals) (reverse funcs) (reverse states) + errs -> Left errs _ -> return $ Left $ reverse err preprocessStates states = let snames = map (\ (State cn _) -> ctxItem cn) states in put'vsStateNames snames
src/LslPlus.hs view
@@ -12,7 +12,7 @@ import System import System.Exit -version="0.3.4" +version="0.3.5" usage progName = "Usage: " ++ progName ++ " [Version|MetaData|Compiler|ExpressionHandler|SimMetaData|SystemTester|UnitTester]" main = do progName <- getProgName
+ src/Text/Here.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE TemplateHaskell #-} +----------------------------------------------------------------------------- +-- | +-- Module : Text.Here +-- Copyright : (c) Rob Greayer 2009 +-- License : BSD-style (see the file LICENSE) +-- +-- Maintainer : robgreayer@yahoo.com +-- Stability : provisional +-- Portability : non-portable (uses existentially template haskell) +-- +-- An implementation of 'here' documents, using quasiquotation. +-- +----------------------------------------------------------------------------- +module Text.Here(here) where + +import Data.Generics.Aliases(extQ) +import qualified Language.Haskell.TH as TH +import Language.Haskell.TH.Quote(QuasiQuoter(..),dataToPatQ,dataToExpQ) + +herePat :: String -> TH.Q TH.Pat +herePat s = dataToPatQ (const Nothing) s +hereExp :: String -> TH.Q TH.Exp +hereExp s = dataToExpQ (const Nothing) s + +-- | A quasi-quoter for a string... +here :: QuasiQuoter +here = QuasiQuoter hereExp herePat