Changeset 8
- Timestamp:
- 02/11/05 08:54:56 (4 years ago)
- svk:copy_cache_prev:
- 1041
- Files:
-
- 1 added
- 8 modified
-
ChangeLog (modified) (1 diff)
-
src/AST.hs (modified) (6 diffs)
-
src/Bind.hs (added)
-
src/Eval.hs (modified) (6 diffs)
-
src/Internals.hs (modified) (2 diffs)
-
src/Lexer.hs (modified) (3 diffs)
-
src/Parser.hs (modified) (6 diffs)
-
src/Pretty.hs (modified) (1 diff)
-
src/Prim.hs (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
ChangeLog
r6 r8 1 [Changes for 6.0.2 - February 9, 2005] 2 3 * User-defined subroutine (with $_ and @_ as parameters) 4 * Variable binding 5 * Context propagation 6 * Multimethod dispatch 7 * Subtype distancing and casting 8 * Autothreading over chained comparison and multiarg functions 9 * List associativity 10 * Array references as literals 11 * Flattening (slurpy) star 12 1 13 [Changes for 6.0.1 - February 7, 2005] 2 14 -
src/AST.hs
r7 r8 26 26 vCast (VRef v) = vCast v 27 27 vCast (VPair _ v) = vCast v 28 vCast (VArray (MkArray v)) = vCast $ VList v 28 29 vCast v = doCast v 29 30 castV :: n -> Val … … 33 34 fmapVal :: (n -> n) -> Val -> Val 34 35 fmapVal f = castV . f . vCast 36 37 instance Context (Val, Val) where 38 castV (x, y) = VPair x y 39 vCast (VPair x y) = (x, y) 40 vCast (VRef v) = vCast v 41 vCast v = case vCast v of 42 [x, y] -> (x, y) 43 other -> error $ "cannot cast into (Val, Val): " ++ (show v) 44 45 instance Context VHash where 46 castV = VHash 47 vCast x = MkHash $ listToFM (map vCast $ vCast x) 35 48 36 49 instance Context VSub where … … 107 120 where 108 121 str = show x 122 123 instance Context VArray where 124 castV = VArray 125 vCast x = MkArray (vCast x) 109 126 110 127 instance Context VList where … … 186 203 deriving (Show, Eq, Ord) 187 204 188 data SubType = SubMethod | SubRoutine | SubMulti 189 deriving (Show, Eq, Ord) 205 data SubType = SubMethod | SubRoutine | SubBlock 206 deriving (Show, Eq, Ord) 207 208 data Param = Param 209 { isInvocant :: Bool 210 , isSlurpy :: Bool 211 , isOptional :: Bool 212 , isNamed :: Bool 213 , paramName :: String 214 , paramContext :: Cxt 215 , paramDefault :: Exp 216 } 217 deriving (Show, Eq, Ord) 218 219 type Params = [Param] 190 220 191 221 data VSub = Sub 192 { subType :: SubType 222 { isMulti :: Bool 223 , subType :: SubType 193 224 , subAssoc :: String 194 , subParams :: [Cxt]225 , subParams :: Params 195 226 , subReturns :: Cxt 196 227 , subFun :: Exp … … 214 245 215 246 data Exp 216 = App String [Exp] 247 = App String [Exp] [Exp] 217 248 | Syn String [Exp] 218 249 | Prim ([Val] -> Val) … … 223 254 deriving (Show, Eq, Ord) 224 255 225 isTotalJunc (VJunc JAll _, b) = not b 226 isTotalJunc (VJunc JNone _, b) = not b 227 isTotalJunc _ = False 228 229 isPartialJunc (VJunc JOne _, b) = not b 230 isPartialJunc (VJunc JAny _, b) = not b 231 isPartialJunc _ = False 232 256 extractExp :: Exp -> ([Exp], [String]) -> ([Exp], [String]) 257 extractExp exp (exps, vs) = (exp':exps, vs') 258 where 259 (exp', vs') = extract (exp, vs) 260 261 extract :: (Exp, [String]) -> (Exp, [String]) 262 extract ((App n invs args), vs) = (App n invs' args', vs'') 263 where 264 (invs', vs') = foldr extractExp ([], vs) invs 265 (args', vs'') = foldr extractExp ([], vs') args 266 extract ((Syn n exps), vs) = (Syn n exps', vs') 267 where 268 (exps', vs') = foldr extractExp ([], vs) exps 269 extract ((Var name pos), vs) 270 | (sigil:'^':identifer) <- name 271 , name' <- (sigil : identifer) 272 = (Var name' pos, insert name' vs) 273 | name == "$_" 274 = (Var name pos, insert name vs) 275 | otherwise 276 = (Var name pos, vs) 277 extract ((Parens exp), vs) = ((Parens exp'), vs') 278 where 279 (exp', vs') = extract (exp, vs) 280 extract other = other 281 282 cxtOf '*' '$' = "List" 283 cxtOf '*' '@' = "List" 284 cxtOf _ _ = "Scalar" 285 286 buildParam cxt sigil name exp = Param 287 { isInvocant = False 288 , isSlurpy = (sigil == "*") 289 , isOptional = (sigil ==) `any` ["?", "+"] 290 , isNamed = (null sigil || head sigil /= '+') 291 , paramName = name 292 , paramContext = if null cxt then defaultCxt else cxt 293 , paramDefault = exp 294 } 295 where 296 sig = if null sigil then ' ' else head sigil 297 defaultCxt = cxtOf sig (head name) 298 299 defaultArrayParam = buildParam "" "*" "@_" (Val VUndef) 300 defaultHashParam = buildParam "" "*" "%_" (Val VUndef) 301 defaultScalarParam = buildParam "" "*" "$_" (Val VUndef) -
src/Eval.hs
r7 r8 16 16 17 17 import AST 18 import Bind 18 19 import Prim 19 20 import Context … … 59 60 = Nothing 60 61 61 applyFun :: Env -> Exp -> [Val] -> Val 62 applyFun env (Prim f) vals = f vals 63 applyFun env body vals 62 chainFun :: Env -> Params -> Exp -> Params -> Exp -> [Val] -> Val 63 chainFun env p1 f1 p2 f2 (v1:v2:vs) 64 | VBool False <- applyFun env (chainArgs p1 [v1, v2]) f1 65 = VBool False 66 | otherwise 67 = applyFun env (chainArgs p1 (v2:vs)) f2 68 where 69 chainArgs prms vals = map chainArg (prms `zip` vals) 70 chainArg (p, v) = ApplyArg (paramName p) v False 71 72 data ApplyArg = ApplyArg 73 { argName :: String 74 , argValue :: Val 75 , argCollapsed :: Bool 76 } 77 deriving (Show, Eq, Ord) 78 79 applyFun :: Env -> [ApplyArg] -> Exp -> Val 80 applyFun env bound (Prim f) = f [ argValue arg | arg <- bound, (argName arg !! 1) /= '_' ] 81 applyFun env bound body 64 82 | Val val <- exp = val 65 83 | otherwise = VError "Invalid expression" exp 66 84 where 67 (fenv, exp) = reduce (env `addSym` [("$_", head vals),("@_", VList vals)]) body 68 69 chainFun :: Env -> Exp -> Exp -> [Val] -> Val 70 chainFun env f1 f2 (v1:v2:vs) 71 | VBool False <- applyFun env f1 [v1, v2] 72 = VBool False 73 | otherwise 74 = applyFun env f2 (v2:vs) 75 76 apply :: Env -> VSub -> [Exp] -> ((Env -> Env), Exp) 77 apply env@Env{ cls = cls } Sub{ subParams = prms, subFun = fun } exps 78 = retVal $ juncApply eval args 79 where 80 eval = applyFun env fun 81 args = map expToVal (prms `zip` exps) 82 expToVal (cxt, exp) = (evaluate env{ cxt = cxt } exp, isaType cls cxt "Bool") 85 (fenv, exp) = reduce (env `addSym` formal) body 86 formal = filter (not . null . fst) $ map argNameValue bound 87 argNameValue (ApplyArg name val _) = (name, val) 88 89 apply :: Env -> VSub -> [Exp] -> [Exp] -> ((Env -> Env), Exp) 90 apply env@Env{ cls = cls } Sub{ subParams = prms, subFun = fun } invs args = 91 case bindParams prms invs args of 92 Left errMsg -> retVal $ VError errMsg (Val VUndef) 93 Right bindings -> retVal $ juncApply eval (reverse . fst $ foldl doBind ([],env) bindings) 94 where 95 eval bound = applyFun env bound fun 96 doBind :: ([ApplyArg], Env) -> (Param, Exp) -> ([ApplyArg], Env) 97 doBind (bs, env) (prm@Param{ paramName = name, paramContext = cxt}, exp) = 98 let (val, coll) = expToVal env cxt exp in 99 (((ApplyArg name val coll): bs), env `addSym` [(name, val)]) 100 expToVal env cxt exp = (evaluate env{ cxt = cxt } exp, isCollapsed cxt) 101 isCollapsed cxt 102 | isaType cls "Bool" cxt = True 103 | isaType cls "Junction" cxt = True 104 | otherwise = False 83 105 84 106 juncApply f args 85 | (before, ( VJunc j vs, cxt):after) <- break isTotalJunc args86 = VJunc j [ juncApply f (before ++ (( v, cxt):after)) | v <- vs ]87 | (before, ( VJunc j vs, cxt):after) <- break isPartialJunc args88 = VJunc j [ juncApply f (before ++ (( v, cxt):after)) | v <- vs ]89 | (val , _):_ <- [ err | err@(VError _ _,_) <- args ]107 | (before, (ApplyArg name (VJunc j vs) coll):after) <- break isTotalJunc args 108 = VJunc j [ juncApply f (before ++ ((ApplyArg name v coll):after)) | v <- vs ] 109 | (before, (ApplyArg name (VJunc j vs) coll):after) <- break isPartialJunc args 110 = VJunc j [ juncApply f (before ++ ((ApplyArg name v coll):after)) | v <- vs ] 111 | (val:_) <- [ val | (ApplyArg _ val@(VError _ _) _) <- args ] 90 112 = val 91 113 | otherwise 92 = f $ map fst args 114 = f args 115 116 isTotalJunc (ApplyArg _ (VJunc JAll _) b) = not b 117 isTotalJunc (ApplyArg _ (VJunc JNone _) b) = not b 118 isTotalJunc _ = False 119 120 isPartialJunc (ApplyArg _ (VJunc JOne _) b) = not b 121 isPartialJunc (ApplyArg _ (VJunc JAny _) b) = not b 122 isPartialJunc _ = False 123 124 toGlobal name 125 | (sigil, identifier) <- break (\x -> isAlpha x || x == '_') name 126 , last sigil /= '*' 127 = sigil ++ ('*':identifier) 128 | otherwise = name 93 129 94 130 retVal :: Val -> ((Env -> Env), Exp) 95 131 retVal val = (id, Val val) 132 133 isGlobalExp (Syn name _) = name `elem` map ("&infix:" ++) (words ":= ::=") 134 isGlobalExp _ = False 96 135 97 136 reduce :: Env -> Exp -> ((Env -> Env), Exp) … … 99 138 | Just val <- lookup var sym 100 139 = retVal val 140 | Just val <- lookup (toGlobal var) sym 141 = retVal val 101 142 | otherwise 102 143 = retVal $ VError ("Undefined variable " ++ var) exp … … 105 146 | name `isInfix` ";" 106 147 , [left, right] <- exps 107 , (env', exp) <- runStatement "Any" (env, Val VUndef) left 108 , (env', exp) <- runStatement cxt (env', exp) right 148 , (lead, final) <- buildStatements exps 149 , (env', exp) <- foldl (runStatement "Any") (env, Val VUndef) lead 150 , (env', exp) <- runStatement cxt (env', exp) final 109 151 = (const env', exp) 110 152 | name `isInfix` ":=" … … 115 157 , [Var var _, Val val] <- exps 116 158 = (combineEnv id var val, Val VUndef) 117 where 159 | name `isInfix` "=>" 160 , [keyExp, valExp] <- exps 161 , key <- evaluate env keyExp 162 , val <- evaluate env valExp 163 = retVal $ VPair key val 164 | name `isInfix` "," 165 = retVal $ VList $ concatMap (vCast . evaluate env{ cxt = "List" }) exps 166 | name `isInfix` "[]" 167 , [listExp, rangeExp] <- exps 168 , list <- evaluate env{ cxt = "List" } listExp 169 , range <- evaluate env{ cxt = "List" } rangeExp 170 , slice <- unfoldr (doSlice $ vCast list) (map vCast $ vCast range) 171 = retVal $ VList slice 172 where 173 doSlice :: [Val] -> [VInt] -> Maybe (Val, [VInt]) 174 doSlice vs [] = Nothing 175 doSlice vs (n:ns) 176 | genericLength vs > n = Just ((vs `genericIndex` n), ns) 177 | otherwise = Nothing 178 buildStatements exps 179 | ((Syn name' exps'):rest) <- exps 180 , name' `isInfix` ";" 181 = buildStatements (exps' ++ rest) 182 | (global, local) <- partition isGlobalExp exps 183 , stmts <- global ++ local 184 = (init stmts, last stmts) 118 185 runStatement :: Cxt -> (Env, Exp) -> Exp -> (Env, Exp) 119 186 runStatement cxt (env, (Val val)) exp … … 127 194 isInfix name s = name == "&infix:" ++ s 128 195 129 reduce env@Env{ cxt = cxt, cls = cls } exp@(App name exps)196 reduce env@Env{ cxt = cxt, cls = cls } exp@(App name invs args) 130 197 | Just sub <- findSub name 131 = applySub sub exps132 | otherwise 133 = retVal $ VError (" Undefined subroutine " ++ name ++ (show $ sym env)) exp134 where 135 applySub sub exps198 = applySub sub invs args 199 | otherwise 200 = retVal $ VError ("No compatible subroutine found: " ++ name) exp 201 where 202 applySub sub invs args 136 203 -- list-associativity 137 | Sub{ subAssoc = "list" } <- sub138 , (App name' exps'):rest <- exps204 | Sub{ subAssoc = "list" } <- sub 205 , (App name' invs' args'):rest <- args 139 206 , name == name' 140 = applySub sub (exps' ++ rest) 207 , null invs' 208 = applySub sub [] (args' ++ rest) 141 209 -- fix subParams to agree with number of actual arguments 142 210 | Sub{ subAssoc = "list", subParams = (p:_) } <- sub 143 , trace ("meow " ++ (show exps)) True144 = apply env sub{ subParams = (length exps) `replicate` p } exps211 , null invs 212 = apply env sub{ subParams = (length args) `replicate` p } [] args 145 213 -- chain-associativity 146 | Sub{ subAssoc = "chain", subFun = fun } <- sub147 , (App name' exps'):rest <- exps214 | Sub{ subAssoc = "chain", subFun = fun, subParams = prm } <- sub 215 , (App name' invs' args'):rest <- args 148 216 , Just sub' <- findSub name' 149 , Sub{ subAssoc = "chain", subFun = fun' } <- sub' 150 = applySub sub{ subFun = Prim $ chainFun env fun' fun } (exps' ++ rest) 217 , Sub{ subAssoc = "chain", subFun = fun', subParams = prm' } <- sub' 218 , null invs' 219 = applySub sub{ subFun = Prim $ chainFun env prm' fun' prm fun } [] (args' ++ rest) 151 220 -- fix subParams to agree with number of actual arguments 152 221 | Sub{ subAssoc = "chain", subParams = (p:_) } <- sub 153 = apply env sub{ subParams = (length exps) `replicate` p } exps -- XXX Wrong 154 -- apply normally 155 | Sub{ subParams = [('*':p)] } <- sub -- XXX Wrong 156 = apply env sub{ subParams = (length exps) `replicate` p } exps 222 , null invs 223 = apply env sub{ subParams = (length args) `replicate` p } [] args -- XXX Wrong 224 -- normal application 157 225 | otherwise 158 = apply env sub exps226 = apply env sub invs args 159 227 findSub name 160 228 | ((_, sub):_) <- sort (subs name) = Just sub 161 229 | otherwise = Nothing 162 subs name = [ ((subT, deltaFromCxt ret : map deltaFromScalar prms), sub) 163 | (n, val) <- sym env 164 , let sub@(Sub{ subType = subT, subReturns = ret, subParams = prms }) = vCast val 165 , n == name 166 , arityMatch sub prms exps 167 , deltaFromCxt ret /= 0 168 ] 169 deltaFromCxt = deltaType cls cxt 170 deltaFromScalar x = deltaType cls x "Scalar" 171 arityMatch Sub{ subAssoc = assoc, subParams = prms } x y 172 | assoc == "list" = True 173 | Just _ <- find ((== '*') . head) prms 174 , assoc == "pre" = True 175 | (length x) == (length y) = True -- XXX - slurping star 176 | otherwise = False 230 subs name = [ 231 ( (isGlobal, subT, isMulti sub, bound, distance, order) 232 , fromJust fun 233 ) 234 | ((n, val), order) <- sym env `zip` [0..] 235 , let sub@(Sub{ subType = subT, subReturns = ret, subParams = prms }) = vCast val 236 , n == name || n == toGlobal name 237 , let isGlobal = '*' `elem` n 238 , let fun = arityMatch sub (invs ++ args) -- XXX Wrong 239 , isJust fun 240 , deltaFromCxt ret /= 0 241 , let invocants = filter isInvocant prms 242 , let prms' = if null invocants then prms else invocants 243 , let distance = (deltaFromCxt ret : map (deltaFromScalar . paramContext) prms') 244 , let bound = either (const False) (const True) $ bindParams prms invs args 245 ] 246 deltaFromCxt = deltaType cls cxt 247 deltaFromScalar ('*':x) = deltaFromScalar x 248 deltaFromScalar x = deltaType cls x "Scalar" 177 249 178 250 reduce env (Parens exp) = reduce env exp 179 251 reduce env other = (id, other) 180 252 253 arityMatch sub@Sub{ subAssoc = assoc, subParams = prms } args 254 | assoc == "list" = Just sub 255 | isJust $ find isSlurpy prms 256 , assoc == "pre" = Just sub 257 -- | (length prms == length args) = Just sub -- XXX optionals 258 -- | (length prms >= length args) = Just sub 259 | otherwise = Just sub 260 | otherwise = Nothing -
src/Internals.hs
r7 r8 17 17 module System.Environment, 18 18 module System.IO, 19 module Control.Monad.Error, 19 20 module Data.Bits, 20 21 module Data.List, 22 module Data.Either, 21 23 module Data.Word, 22 24 module Data.Ratio, … … 34 36 import System.Environment 35 37 import System.IO hiding (try) 38 import Control.Monad.Error 36 39 import qualified System.IO (try) 37 40 import Data.Bits 38 41 import Data.Maybe 42 import Data.Either 39 43 import Data.List 40 44 import Data.Ratio -
src/Lexer.hs
r7 r8 19 19 , P.commentLine = "#" 20 20 , P.nestedComments = False 21 , P.identStart = letter <|> char '_'22 , P.identLetter = alphaNum <|> oneOf "_"21 , P.identStart = wordAlpha 22 , P.identLetter = wordAny 23 23 , P.reservedNames = words $ 24 24 "if then else do while skip" … … 39 39 } 40 40 41 wordAlpha = satisfy (\x -> (isAlpha x || x == '_')) <?> "alphabetic word character" 42 wordAny = satisfy (\x -> (isAlphaNum x || x == '_')) <?> "word character" 43 41 44 perl6Lexer = P.makeTokenParser perl6Def 42 45 reservedOp = P.reservedOp perl6Lexer … … 49 52 braces = P.braces perl6Lexer 50 53 brackets = P.brackets perl6Lexer 54 symbol = P.symbol perl6Lexer 51 55 stringLiteral = choice 52 56 [ P.stringLiteral perl6Lexer -
src/Parser.hs
r7 r8 17 17 type StateParser a = GenParser Char () a 18 18 19 operators :: OperatorTable Char () Exp 20 operators = 19 tightOperators = 21 20 [ methOps " . .+ .? .* .+ .() .[] .{} .<<>> .= " -- Method postfix 22 21 , postOps " ++ -- " -- Auto-Increment … … 37 36 , leftOps " || ^^ // " -- Tight Or 38 37 , ternOps [("??", "::")] -- Ternary 39 , rightSyn " = := ::= += **= xx= " -- Assignment 40 , listOps " , " -- List Item Separator 41 , preOps primitiveListFunctions -- List Operator 38 , leftSyn " = := ::= += **= xx= " -- Assignment 39 ] 40 41 looseOperators = 42 [ preOps primitiveListFunctions -- List Operator 42 43 , leftOps " ==> " -- Pipe Forward 43 44 , leftOps " and " -- Loose And 44 45 , leftOps " or xor err " -- Loose Or 45 , leftSyn " ; " -- Terminator 46 ] 46 ] 47 48 operators :: OperatorTable Char () Exp 49 operators = concat $ 50 [ tightOperators 51 , [ listOps " , " ] -- Comma 52 , looseOperators 53 , [ listSyn " ; " ] -- Terminator 54 ] 55 56 litOperators = tightOperators ++ looseOperators 47 57 48 58 primitiveListFunctions = " not <== any all one none" … … 51 61 52 62 parseOp = buildExpressionParser operators parseTerm 63 parseLitOp = buildExpressionParser litOperators parseLitTerm 53 64 54 65 ops f s = [f n | n <- words s] 55 66 56 preOps = ops $ makeOp1 Prefix "&prefix:" App 57 postOps = ops $ makeOp1 Postfix "&postfix:" App 58 leftOps = ops $ makeOp2 AssocLeft "&infix:" App 59 rightOps = ops $ makeOp2 AssocRight "&infix:" App 60 noneOps = ops $ makeOp2 AssocNone "&infix:" App 67 doApp str args = App str [] args 68 69 preOps = ops $ makeOp1 Prefix "&prefix:" doApp 70 postOps = ops $ makeOp1 Postfix "&postfix:" doApp 71 leftOps = ops $ makeOp2 AssocLeft "&infix:" doApp 72 rightOps = ops $ makeOp2 AssocRight "&infix:" doApp 73 noneOps = ops $ makeOp2 AssocNone "&infix:" doApp 61 74 listOps = leftOps 62 75 chainOps = leftOps 63 76 leftSyn = ops $ makeOp2 AssocLeft "&infix:" Syn 64 77 rightSyn = ops $ makeOp2 AssocRight "&infix:" Syn 78 listSyn = leftSyn 79 chainSyn = leftSyn 65 80 66 81 -- chainOps = ops $ makeOpChained … … 74 89 return $ \x y -> con (sigil ++ name) [x,y] 75 90 76 parseTerm = parseDecl 77 <|> parseVar 78 <|> parseLit 79 <|> do 80 cs <- parens parseOp 81 return $ Parens cs 82 <|> parseApply 83 {- 84 <|> do 85 cs <- parseOp 86 return cs 87 -} 88 -- <|> nonTerm 91 parseParens parse = do 92 cs <- parens parse 93 return $ Parens cs 94 95 parseTerm = choice 96 [ parseDecl 97 , parseVar 98 , parseLit 99 , parseApply 100 , parseParens parseOp 101 ] 89 102 <?> "term" 90 103 91 buildSub body = VSub $ Sub 92 { subType = SubRoutine 93 , subAssoc = "pre" 94 , subParams = ["*List"] 95 , subReturns = "Any" 96 , subFun = body 104 parseLitTerm = choice 105 [ parseVar 106 , parseLit 107 , parseApply 108 , parseParens parseLitOp 109 ] 110 <?> "argument" 111 112 parseTrait trait = do 113 symbol "is" 114 symbol trait 115 identifier 116 117 parseBareTrait trait = do 118 choice [ parseTrait trait 119 , do { symbol trait ; identifier } 120 ] 121 122 parseContext = do 123 lead <- upper 124 rest <- many1 wordAny 125 return (lead:rest) 126 127 parseParamDefault True = return $ Val VUndef 128 parseParamDefault False = option (Val VUndef) $ do 129 symbol "=" 130 parseLitOp 131 132 parseFormalParam = do 133 cxt <- option "" $ parseContext 134 sigil <- option "" $ choice . map string $ words " ? * + ++ " 135 name <- parseVarName 136 let required = (sigil /=) `all` ["?", "+"] 137 exp <- parseParamDefault required 138 return $ buildParam cxt sigil name exp 139 140 parseApply = lexeme $ do 141 name <- identifier 142 (invs:args:_) <- parseParamList parseLitTerm 143 return $ App ('&':name) invs args 144 145 parseParamList parse = do 146 formal <- maybeParens ((parse `sepBy` symbol ",") `sepBy` symbol ":") 147 case formal of 148 [] -> return [[], []] 149 [args] -> return [[], args] 150 [invocants,args] -> return formal 151 _ -> fail "Only one invocant list allowed" 152 153 parseFormalParameters = do 154 (invs:args:_) <- parseParamList parseFormalParam 155 return $ (map (\e -> e { isInvocant = True }) invs) ++ args 156 157 nameToParam :: String -> Param 158 nameToParam name = Param 159 { isInvocant = False 160 , isSlurpy = (name == "$_") 161 , isOptional = False 162 , isNamed = False 163 , paramName = name 164 , paramContext = (if name == "$_" then "List" else "Scalar") 165 , paramDefault = Val VUndef 97 166 } 98 167 99 168 parseDecl = lexeme $ do 100 lexeme (string "sub") 169 multi <- option False $ do { symbol "multi" ; return True } 170 symbol "sub" 101 171 pos <- getPosition 102 172 name <- identifier 173 cxt <- option "Any" $ parseBareTrait "returns" 174 formal <- option Nothing $ return . Just =<< parens parseFormalParameters 103 175 body <- braces parseOp 104 return $ Syn "&infix:::=" [Var ('&':name) pos, Val (buildSub body)] 176 let (fun, names) = extract (body,[]) 177 params = (maybe [] id formal) ++ map nameToParam names 178 -- Check for placeholder vs formal parameters 179 unless (isNothing formal || null names || names == ["$_"] ) $ 180 fail "Cannot mix placeholder variables with formal parameters" 181 let sub = Sub { isMulti = multi 182 , subType = SubRoutine 183 , subAssoc = "pre" 184 , subReturns = cxt 185 , subParams = if null params then [defaultArrayParam] else params 186 , subFun = fun 187 } 188 return $ Syn "&infix:::=" [Var ('&':name) pos, Val (VSub sub)] 105 189 106 190 maybeParens p = choice [ parens p, p ] 107 191 108 parseApply = lexeme $ do 109 name <- identifier 110 args <- maybeParens $ parseTerm `sepBy` (lexeme $ char ',') 111 return $ App ('&':name) args 112 113 parseVar = lexeme $ do 192 parseVarName = lexeme $ do 193 sigil <- oneOf "$@%&" 194 caret <- option "" $ choice [ string "^", string "*" ] 195 name <- many1 wordAny 196 return $ (sigil:caret) ++ name 197 198 parseVar = do 114 199 pos <- getPosition 115 sigil <- oneOf "$@%&"
