Changeset 8

Show
Ignore:
Timestamp:
02/11/05 08:54:56 (4 years ago)
Author:
autrijus
svk:copy_cache_prev:
1041
Message:

* checkin.

Files:
1 added
8 modified

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 
    113[Changes for 6.0.1 - February 7, 2005] 
    214 
  • src/AST.hs

    r7 r8  
    2626    vCast (VRef v)      = vCast v 
    2727    vCast (VPair _ v)   = vCast v 
     28    vCast (VArray (MkArray v))    = vCast $ VList v 
    2829    vCast v             = doCast v 
    2930    castV :: n -> Val 
     
    3334    fmapVal :: (n -> n) -> Val -> Val 
    3435    fmapVal f = castV . f . vCast 
     36 
     37instance 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 
     45instance Context VHash where 
     46    castV = VHash 
     47    vCast x = MkHash $ listToFM (map vCast $ vCast x)  
    3548 
    3649instance Context VSub where 
     
    107120    where 
    108121    str = show x  
     122 
     123instance Context VArray where 
     124    castV = VArray 
     125    vCast x = MkArray (vCast x)  
    109126 
    110127instance Context VList where 
     
    186203    deriving (Show, Eq, Ord) 
    187204 
    188 data SubType = SubMethod | SubRoutine | SubMulti 
    189     deriving (Show, Eq, Ord) 
     205data SubType = SubMethod | SubRoutine | SubBlock 
     206    deriving (Show, Eq, Ord) 
     207 
     208data 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 
     219type Params = [Param] 
    190220 
    191221data VSub = Sub 
    192     { subType       :: SubType 
     222    { isMulti       :: Bool 
     223    , subType       :: SubType 
    193224    , subAssoc      :: String 
    194     , subParams     :: [Cxt] 
     225    , subParams     :: Params 
    195226    , subReturns    :: Cxt 
    196227    , subFun        :: Exp 
     
    214245 
    215246data Exp 
    216     = App String [Exp] 
     247    = App String [Exp] [Exp] 
    217248    | Syn String [Exp] 
    218249    | Prim ([Val] -> Val) 
     
    223254    deriving (Show, Eq, Ord) 
    224255 
    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  
     256extractExp :: Exp -> ([Exp], [String]) -> ([Exp], [String]) 
     257extractExp exp (exps, vs) = (exp':exps, vs') 
     258    where 
     259    (exp', vs') = extract (exp, vs) 
     260 
     261extract :: (Exp, [String]) -> (Exp, [String]) 
     262extract ((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 
     266extract ((Syn n exps), vs) = (Syn n exps', vs') 
     267    where 
     268    (exps', vs') = foldr extractExp ([], vs) exps 
     269extract ((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) 
     277extract ((Parens exp), vs) = ((Parens exp'), vs') 
     278    where 
     279    (exp', vs') = extract (exp, vs) 
     280extract other = other 
     281 
     282cxtOf '*' '$'   = "List" 
     283cxtOf '*' '@'   = "List" 
     284cxtOf _   _     = "Scalar" 
     285 
     286buildParam 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 
     299defaultArrayParam   = buildParam "" "*" "@_" (Val VUndef) 
     300defaultHashParam    = buildParam "" "*" "%_" (Val VUndef) 
     301defaultScalarParam  = buildParam "" "*" "$_" (Val VUndef) 
  • src/Eval.hs

    r7 r8  
    1616 
    1717import AST 
     18import Bind 
    1819import Prim 
    1920import Context 
     
    5960    = Nothing 
    6061 
    61 applyFun :: Env -> Exp -> [Val] -> Val 
    62 applyFun env (Prim f) vals = f vals 
    63 applyFun env body vals 
     62chainFun :: Env -> Params -> Exp -> Params -> Exp -> [Val] -> Val 
     63chainFun 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 
     72data ApplyArg = ApplyArg 
     73    { argName       :: String 
     74    , argValue      :: Val 
     75    , argCollapsed  :: Bool 
     76    } 
     77    deriving (Show, Eq, Ord) 
     78 
     79applyFun :: Env -> [ApplyArg] -> Exp -> Val 
     80applyFun env bound (Prim f) = f [ argValue arg | arg <- bound, (argName arg !! 1) /= '_' ] 
     81applyFun env bound body 
    6482    | Val val   <- exp          = val 
    6583    | otherwise                 = VError "Invalid expression" exp 
    6684    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 
     89apply :: Env -> VSub -> [Exp] -> [Exp] -> ((Env -> Env), Exp) 
     90apply 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 
    83105 
    84106juncApply f args 
    85     | (before, (VJunc j vs, cxt):after) <- break isTotalJunc args 
    86     = VJunc j [ juncApply f (before ++ ((v, cxt):after)) | v <- vs ] 
    87     | (before, (VJunc j vs, cxt):after) <- break isPartialJunc args 
    88     = 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 ] 
    90112    = val 
    91113    | otherwise 
    92     = f $ map fst args  
     114    = f args 
     115 
     116isTotalJunc (ApplyArg _ (VJunc JAll _) b)   = not b 
     117isTotalJunc (ApplyArg _ (VJunc JNone _) b)  = not b 
     118isTotalJunc _                   = False 
     119 
     120isPartialJunc (ApplyArg _ (VJunc JOne _) b) = not b 
     121isPartialJunc (ApplyArg _ (VJunc JAny _) b) = not b 
     122isPartialJunc _                 = False 
     123 
     124toGlobal name 
     125    | (sigil, identifier) <- break (\x -> isAlpha x || x == '_') name 
     126    , last sigil /= '*' 
     127    = sigil ++ ('*':identifier) 
     128    | otherwise = name 
    93129 
    94130retVal :: Val -> ((Env -> Env), Exp) 
    95131retVal val = (id, Val val) 
     132 
     133isGlobalExp (Syn name _) = name `elem` map ("&infix:" ++) (words ":= ::=") 
     134isGlobalExp _ = False 
    96135 
    97136reduce :: Env -> Exp -> ((Env -> Env), Exp) 
     
    99138    | Just val <- lookup var sym 
    100139    = retVal val 
     140    | Just val <- lookup (toGlobal var) sym 
     141    = retVal val 
    101142    | otherwise 
    102143    = retVal $ VError ("Undefined variable " ++ var) exp 
     
    105146    | name `isInfix` ";" 
    106147    , [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 
    109151    = (const env', exp) 
    110152    | name `isInfix` ":=" 
     
    115157    , [Var var _, Val val]  <- exps 
    116158    = (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) 
    118185    runStatement :: Cxt -> (Env, Exp) -> Exp -> (Env, Exp) 
    119186    runStatement cxt (env, (Val val)) exp 
     
    127194    isInfix name s = name == "&infix:" ++ s 
    128195 
    129 reduce env@Env{ cxt = cxt, cls = cls } exp@(App name exps) 
     196reduce env@Env{ cxt = cxt, cls = cls } exp@(App name invs args) 
    130197    | Just sub <- findSub name 
    131     = applySub sub exps 
    132     | otherwise 
    133     = retVal $ VError ("Undefined subroutine " ++ name ++ (show $ sym env)) exp 
    134     where 
    135     applySub sub exps 
     198    = applySub sub invs args 
     199    | otherwise 
     200    = retVal $ VError ("No compatible subroutine found: " ++ name) exp 
     201    where 
     202    applySub sub invs args 
    136203        -- list-associativity 
    137         | Sub{ subAssoc = "list" }  <- sub 
    138         , (App name' exps'):rest    <- exps 
     204        | Sub{ subAssoc = "list" }      <- sub 
     205        , (App name' invs' args'):rest  <- args 
    139206        , name == name' 
    140         = applySub sub (exps' ++ rest) 
     207        , null invs' 
     208        = applySub sub [] (args' ++ rest) 
    141209        -- fix subParams to agree with number of actual arguments 
    142210        | Sub{ subAssoc = "list", subParams = (p:_) }   <- sub 
    143         , trace ("meow " ++ (show exps)) True 
    144         = apply env sub{ subParams = (length exps) `replicate` p } exps 
     211        , null invs 
     212        = apply env sub{ subParams = (length args) `replicate` p } [] args 
    145213        -- chain-associativity 
    146         | Sub{ subAssoc = "chain", subFun = fun }   <- sub 
    147         , (App name' exps'):rest                    <- exps 
     214        | Sub{ subAssoc = "chain", subFun = fun, subParams = prm }   <- sub 
     215        , (App name' invs' args'):rest              <- args 
    148216        , 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) 
    151220        -- fix subParams to agree with number of actual arguments 
    152221        | 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 
    157225        | otherwise 
    158         = apply env sub exps 
     226        = apply env sub invs args 
    159227    findSub name 
    160228        | ((_, sub):_) <- sort (subs name)  = Just sub 
    161229        | 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" 
    177249 
    178250reduce env (Parens exp) = reduce env exp 
    179251reduce env other = (id, other) 
    180252 
     253arityMatch 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  
    1717    module System.Environment, 
    1818    module System.IO, 
     19    module Control.Monad.Error, 
    1920    module Data.Bits, 
    2021    module Data.List, 
     22    module Data.Either, 
    2123    module Data.Word, 
    2224    module Data.Ratio, 
     
    3436import System.Environment 
    3537import System.IO hiding (try) 
     38import Control.Monad.Error 
    3639import qualified System.IO (try) 
    3740import Data.Bits 
    3841import Data.Maybe 
     42import Data.Either 
    3943import Data.List 
    4044import Data.Ratio 
  • src/Lexer.hs

    r7 r8  
    1919          , P.commentLine    = "#" 
    2020          , P.nestedComments = False 
    21           , P.identStart     = letter <|> char '_' 
    22           , P.identLetter    = alphaNum <|> oneOf "_" 
     21          , P.identStart     = wordAlpha 
     22          , P.identLetter    = wordAny 
    2323          , P.reservedNames  = words $ 
    2424                "if then else do while skip" 
     
    3939          } 
    4040 
     41wordAlpha   = satisfy (\x -> (isAlpha x || x == '_')) <?> "alphabetic word character" 
     42wordAny     = satisfy (\x -> (isAlphaNum x || x == '_')) <?> "word character" 
     43 
    4144perl6Lexer = P.makeTokenParser perl6Def 
    4245reservedOp = P.reservedOp perl6Lexer 
     
    4952braces     = P.braces perl6Lexer 
    5053brackets   = P.brackets perl6Lexer 
     54symbol     = P.symbol perl6Lexer 
    5155stringLiteral = choice 
    5256    [ P.stringLiteral  perl6Lexer 
  • src/Parser.hs

    r7 r8  
    1717type StateParser a = GenParser Char () a 
    1818 
    19 operators :: OperatorTable Char () Exp 
    20 operators = 
     19tightOperators = 
    2120    [ methOps  " . .+ .? .* .+ .() .[] .{} .<<>> .= "   -- Method postfix 
    2221    , postOps  " ++ -- "                                -- Auto-Increment 
     
    3736    , leftOps  " || ^^ // "                             -- Tight Or 
    3837    , ternOps  [("??", "::")]                           -- Ternary 
    39     , rightSyn " = := ::= += **= xx= "                  -- Assignment 
    40     , listOps  " , "                                    -- List Item Separator 
    41     , preOps   primitiveListFunctions                   -- List Operator 
     38    , leftSyn  " = := ::= += **= xx= "                  -- Assignment 
     39    ] 
     40 
     41looseOperators = 
     42    [ preOps   primitiveListFunctions                   -- List Operator 
    4243    , leftOps  " ==> "                                  -- Pipe Forward 
    4344    , leftOps  " and "                                  -- Loose And 
    4445    , leftOps  " or xor err "                           -- Loose Or 
    45     , leftSyn  " ; "                                    -- Terminator 
    46     ] 
     46    ] 
     47 
     48operators :: OperatorTable Char () Exp 
     49operators = concat $ 
     50    [ tightOperators 
     51    , [ listOps  " , " ]                                -- Comma 
     52    , looseOperators 
     53    , [ listSyn  " ; " ]                                -- Terminator 
     54    ] 
     55 
     56litOperators = tightOperators ++ looseOperators 
    4757 
    4858primitiveListFunctions = " not <== any all one none" 
     
    5161 
    5262parseOp = buildExpressionParser operators parseTerm 
     63parseLitOp = buildExpressionParser litOperators parseLitTerm 
    5364 
    5465ops f s = [f n | n <- words s] 
    5566 
    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 
     67doApp str args = App str [] args 
     68 
     69preOps      = ops $ makeOp1 Prefix "&prefix:" doApp 
     70postOps     = ops $ makeOp1 Postfix "&postfix:" doApp 
     71leftOps     = ops $ makeOp2 AssocLeft "&infix:" doApp 
     72rightOps    = ops $ makeOp2 AssocRight "&infix:" doApp 
     73noneOps     = ops $ makeOp2 AssocNone "&infix:" doApp 
    6174listOps     = leftOps 
    6275chainOps    = leftOps 
    6376leftSyn     = ops $ makeOp2 AssocLeft "&infix:" Syn 
    6477rightSyn    = ops $ makeOp2 AssocRight "&infix:" Syn 
     78listSyn     = leftSyn 
     79chainSyn    = leftSyn 
    6580 
    6681-- chainOps    = ops $ makeOpChained 
     
    7489    return $ \x y -> con (sigil ++ name) [x,y] 
    7590 
    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 
     91parseParens parse = do 
     92    cs <- parens parse 
     93    return $ Parens cs 
     94 
     95parseTerm = choice 
     96    [ parseDecl 
     97    , parseVar 
     98    , parseLit 
     99    , parseApply 
     100    , parseParens parseOp 
     101    ] 
    89102    <?> "term" 
    90103 
    91 buildSub body = VSub $ Sub 
    92     { subType       = SubRoutine 
    93     , subAssoc      = "pre" 
    94     , subParams     = ["*List"] 
    95     , subReturns    = "Any" 
    96     , subFun        = body 
     104parseLitTerm = choice 
     105    [ parseVar 
     106    , parseLit 
     107    , parseApply 
     108    , parseParens parseLitOp 
     109    ] 
     110    <?> "argument" 
     111 
     112parseTrait trait = do 
     113    symbol "is" 
     114    symbol trait 
     115    identifier 
     116 
     117parseBareTrait trait = do 
     118    choice [ parseTrait trait 
     119           , do { symbol trait ; identifier } 
     120           ] 
     121 
     122parseContext = do 
     123    lead    <- upper 
     124    rest    <- many1 wordAny 
     125    return (lead:rest) 
     126 
     127parseParamDefault True  = return $ Val VUndef 
     128parseParamDefault False = option (Val VUndef) $ do 
     129    symbol "=" 
     130    parseLitOp 
     131 
     132parseFormalParam = 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 
     140parseApply = lexeme $ do 
     141    name            <- identifier 
     142    (invs:args:_)   <- parseParamList parseLitTerm 
     143    return $ App ('&':name) invs args 
     144 
     145parseParamList 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 
     153parseFormalParameters = do 
     154    (invs:args:_) <- parseParamList parseFormalParam 
     155    return $ (map (\e -> e { isInvocant = True }) invs) ++ args 
     156 
     157nameToParam :: String -> Param 
     158nameToParam 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 
    97166    } 
    98167 
    99168parseDecl = lexeme $ do 
    100     lexeme (string "sub") 
     169    multi   <- option False $ do { symbol "multi" ; return True } 
     170    symbol "sub" 
    101171    pos     <- getPosition 
    102172    name    <- identifier 
     173    cxt     <- option "Any" $ parseBareTrait "returns" 
     174    formal  <- option Nothing $ return . Just =<< parens parseFormalParameters 
    103175    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)] 
    105189 
    106190maybeParens p = choice [ parens p, p ] 
    107191 
    108 parseApply = lexeme $ do 
    109     name    <- identifier 
    110     args    <- maybeParens $ parseTerm `sepBy` (lexeme $ char ',') 
    111     return $ App ('&':name) args 
    112  
    113 parseVar = lexeme $ do 
     192parseVarName = lexeme $ do 
     193    sigil   <- oneOf "$@%&" 
     194    caret   <- option "" $ choice [ string "^", string "*" ] 
     195    name    <- many1 wordAny 
     196    return $ (sigil:caret) ++ name 
     197 
     198parseVar = do 
    114199    pos     <- getPosition 
    115     sigil   <- oneOf "$@%&"