diff options
author | tomsmeding <tom.smeding@gmail.com> | 2019-11-18 18:33:06 +0100 |
---|---|---|
committer | tomsmeding <tom.smeding@gmail.com> | 2019-11-18 18:33:06 +0100 |
commit | 095970d60c7912d330c7c33501a1634c533eced1 (patch) | |
tree | c6276b25bbe564175346f1be7f8eb4fbbbe31bf4 | |
parent | 6ff145b50b2b56d610a16cc047c311d3f3552bf4 (diff) |
Refactor analyseValue, fix Let
-rw-r--r-- | Compiler.hs | 71 | ||||
-rw-r--r-- | VM.hs | 1 |
2 files changed, 50 insertions, 22 deletions
diff --git a/Compiler.hs b/Compiler.hs index 913d568..0272950 100644 --- a/Compiler.hs +++ b/Compiler.hs @@ -16,50 +16,71 @@ data TaggedValue = TVList [TaggedValue] | TVNum Int | TVString String - | TVName Name (Maybe Int) -- Nothing: unknown, Just n: defined n lambdas up (0 = current lambda arg) + | TVName Name (Maybe Int) -- Nothing: unknown (external/builtin), Just n: defined n lambdas up (0 = current lambda arg) | TVQuoted Value | TVDefine Name TaggedValue | TVLambda [Name] TaggedValue [Name] -- (args) (body) (closure slot names) + | TVLet (Name, TaggedValue) TaggedValue | TVEllipsis deriving Show -- also does some preprocessing, like parsing lambda's and defines analyseValue :: Value -> TaggedValue -analyseValue = go [] +analyseValue = go (Map.empty, 0) where - go :: [Set.Set Name] -> Value -> TaggedValue - go scopes (VList [VName "define", VName name, VList args, body]) - | Just names <- mapM fromVName args = go scopes (VList [VName "define", VName name, VLambda names body]) + -- env: (name -> lambda depth at which name is defined, current lambda depth) + go :: (Map.Map Name Int, Int) -> Value -> TaggedValue + go env (VList [VName "define", VName name, VList args, body]) + | Just names <- mapM fromVName args = go env (VList [VName "define", VName name, VLambda names body]) | otherwise = error "Invalid 'define' shorthand syntax: Invalid argument list" - go scopes (VList [VName "define", VName name, value]) = TVDefine name (go scopes value) - go scopes (VList [VName "lambda", VList args, body]) - | Just names <- mapM fromVName args = go scopes (VLambda names body) + go env (VList [VName "define", VName name, value]) = TVDefine name (go env value) + go _ (VList (VName "define" : _)) = error "Invalid 'define' syntax" + + go (envd, depth) (VList [VName "lambda", VList args, body]) + | Just names <- mapM fromVName args = go (envd, depth + 1) (VLambda names body) | otherwise = error "Invalid 'lambda' syntax: Invalid argument list" go _ (VList (VName "lambda" : _)) = error "Invalid 'lambda' syntax" - go scopes (VList [VName "let", VList args, body]) = - case sequence [if length p == 2 then Just (p !! 0, p !! 1) else Nothing | VList p <- args] of + + -- go env (VList [VName "let", VList args, body]) = + -- case sequence [if length p == 2 then Just (p !! 0, p !! 1) else Nothing | VList p <- args] of + -- Just pairs -> + -- go env (VList (VList [VName "lambda", VList (map fst pairs), body] : map snd pairs)) + -- Nothing -> + -- error "Invalid 'let' syntax: Invalid variable list (not all pairs)" + go env (VList [VName "let", VList args, body]) = + case sequence [case p of { [VName n, v] -> Just (n, v); _ -> Nothing } | VList p <- args] of Just pairs -> - go scopes (VList (VList [VName "lambda", VList (map fst pairs), body] : map snd pairs)) + go env (VLet pairs body) Nothing -> error "Invalid 'let' syntax: Invalid variable list (not all pairs)" go _ (VList (VName "let" : _)) = error "Invalid 'let' syntax: Invalid argument list" - go scopes (VList values) = TVList (map (go scopes) values) + + go env (VList values) = TVList (map (go env) values) go _ (VNum n) = TVNum n go _ (VString s) = TVString s - go scopes (VName name) = TVName name (findIndex id (map (Set.member name) scopes)) + go (envd, _) (VName name) = TVName name (Map.lookup name envd) go _ (VQuoted value) = TVQuoted value - go scopes (VLambda args body) = - let t = go (Set.fromList args : scopes) body - in TVLambda args t (Set.toList (collectEscapes 0 t)) + go (envd, depth) (VLambda args body) = + let t = go (foldr (flip Map.insert depth) envd args, depth) body + in TVLambda args t (Set.toList (collectEscapes depth t)) + go (envd, depth) (VLet ((name, value) : args) body) = + TVLet (name, go (envd, depth) value) + (go (Map.insert name depth envd, depth) (VLet args body)) + go env (VLet [] body) = go env body go _ (VBuiltin _) = undefined go _ VEllipsis = TVEllipsis - go _ (VLet _ _) = error "'let' should not be present yet at this point" collectEscapes :: Int -> TaggedValue -> Set.Set Name - collectEscapes limit (TVList values) = Set.unions (map (collectEscapes limit) values) - collectEscapes limit (TVName name (Just n)) | n > limit = Set.singleton name - collectEscapes limit (TVLambda _ body _) = collectEscapes (limit + 1) body - collectEscapes _ _ = Set.empty + collectEscapes depth (TVList values) = Set.unions (map (collectEscapes depth) values) + collectEscapes depth (TVName name (Just d)) = if d < depth then Set.singleton name else Set.empty + collectEscapes depth (TVDefine _ value) = collectEscapes depth value + collectEscapes depth (TVLambda _ body _) = collectEscapes depth body + collectEscapes depth (TVLet (_, value) body) = collectEscapes depth value <> collectEscapes depth body + collectEscapes _ (TVName _ Nothing) = Set.empty -- external/builtin names do not need to be captured + collectEscapes _ (TVNum _) = Set.empty + collectEscapes _ (TVString _) = Set.empty + collectEscapes _ (TVQuoted _) = Set.empty + collectEscapes _ TVEllipsis = Set.empty data CompState = CompState @@ -73,7 +94,7 @@ data CompState = CompState , csDatas :: [Value] } deriving Show -data ScopeItem = SIParam Int | SIClosure Int | SIGlobal +data ScopeItem = SIParam Int | SIClosure Int | SIGlobal | SIRef Ref deriving Show newtype CM a = CM {unCM :: StateT CompState (Except String) a} @@ -272,10 +293,16 @@ genTValue (TVLambda args body closure) nextnext = do return r setTerm $ IJmp nextnext return resref +genTValue (TVLet (name, value) body) nextnext = do + b <- newBlock + r <- genTValue value b + switchBlock b + withScope (Map.singleton name (SIRef r)) (genTValue body nextnext) genTValue (TVName name _) nextnext = do r <- genTemp lookupVar name >>= \si -> case si of Right ref -> addIns (r, IAssign ref) + Left (SIRef ref) -> addIns (r, IAssign ref) Left (SIParam n) -> addIns (r, IParam n) Left (SIClosure n) -> addIns (r, IClosure n) Left SIGlobal -> do @@ -111,6 +111,7 @@ vmRunBuiltin state "print" as = putStrLn (intercalate ", " (map printshow as)) > vmRunBuiltin state "=" [a, b] = return (if equalOp a b then RVNum 1 else RVNum 0, state) vmRunBuiltin state "<=" [RVNum a, RVNum b] = return (RVNum (fromEnum (a <= b)), state) vmRunBuiltin state "+" [RVNum a, RVNum b] = return (RVNum (a + b), state) +vmRunBuiltin state "+" [RVString a, RVString b] = return (RVString (a ++ b), state) vmRunBuiltin state "-" [RVNum a, RVNum b] = return (RVNum (a - b), state) vmRunBuiltin state "null?" [v] = return (RVNum (case v of { RVList [] -> 1; _ -> 0 }), state) vmRunBuiltin state "car" [RVList l] = case l of |