Skip to content

Commit

Permalink
fix: add dropLast to List in Prelude and fix a scope check issue for …
Browse files Browse the repository at this point in the history
…reassignments
  • Loading branch information
aboeglin committed Apr 25, 2021
1 parent 7db4800 commit 11c0ea7
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 37 deletions.
3 changes: 3 additions & 0 deletions prelude/__internal__/List.mad
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,9 @@ export includes = (x, xs) => (#- xs.includes(x) -#)
drop :: Number -> List a -> List a
export drop = (amount, xs) => slice(amount, len(xs) - amount - 1, xs)

dropLast :: Number -> List a -> List a
export dropLast = (amount, xs) => slice(0, len(xs) - amount - 1, xs)

dropWhile :: (a -> Boolean) -> List a -> List a
export dropWhile = (pred, xs) => #-{
const n = xs.length
Expand Down
3 changes: 3 additions & 0 deletions prelude/__internal__/List.spec.mad
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
append,
concat,
drop,
dropLast,
dropWhile,
filter,
find,
Expand Down Expand Up @@ -172,5 +173,7 @@ test("sortDesc String", (_) =>
test("drop", (_) => assertEquals(drop(2, [1, 2, 3, 4, 5, 6]), [3, 4, 5, 6]))
test("drop - empty", (_) => assertEquals(drop(2, []), []))

test("dropLast", (_) => assertEquals(dropLast(2, [1, 2, 3, 4, 5, 6]), [1, 2, 3, 4]))

test("dropWhile", (_) => assertEquals(dropWhile((x) => x < 5, [1, 2, 3, 4, 5, 6]), [5, 6]))

79 changes: 42 additions & 37 deletions src/Infer/Scope.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ checkExps _ _ _ [] = return ()
checkExps env globalScope dependencies (e : es) = do
let globalScope' = extendScope globalScope e

collectedAccesses <- collect env Nothing globalScope S.empty e
collectedAccesses <- collect env [] Nothing globalScope S.empty e

catchError (verifyScope env collectedAccesses globalScope dependencies e) pushError

Expand Down Expand Up @@ -81,20 +81,22 @@ isFunction exp = case exp of
_ -> False


collect :: Env -> Maybe String -> InScope -> InScope -> Exp -> Infer Accesses
collect env nameToFind globalScope localScope solvedExp@(Solved tipe area e) = case e of
collect :: Env -> [String] -> Maybe String -> InScope -> InScope -> Exp -> Infer Accesses
collect env foundNames nameToFind globalScope localScope solvedExp@(Solved tipe area e) = case e of
TemplateString exps -> do
globalNamesAccessed <- mapM (collect env nameToFind globalScope localScope) exps
globalNamesAccessed <- mapM (collect env foundNames nameToFind globalScope localScope) exps
return $ foldr S.union S.empty globalNamesAccessed

Var ('.':_) -> return S.empty
Var name -> do
when (nameToFind == Just name) (throwError $ CompilationError (RecursiveVarAccess name) (Context (envCurrentPath env) area []))
case nameToFind of
Just n -> when (n == name && notElem n foundNames) (throwError $ CompilationError (RecursiveVarAccess name) (Context (envCurrentPath env) area []))
Nothing -> return ()
if name `S.member` localScope then return S.empty else return $ S.singleton (name, solvedExp)

App fn arg _ -> do
fnGlobalNamesAccessed <- collect env nameToFind globalScope localScope fn
argGlobalNamesAccessed <- collect env nameToFind globalScope localScope arg
fnGlobalNamesAccessed <- collect env foundNames nameToFind globalScope localScope fn
argGlobalNamesAccessed <- collect env foundNames nameToFind globalScope localScope arg
return $ fnGlobalNamesAccessed <> argGlobalNamesAccessed

Abs (Solved t _ name) body -> do
Expand All @@ -104,75 +106,78 @@ collect env nameToFind globalScope localScope solvedExp@(Solved tipe area e) = c
else
nameToFind
let localScope' = S.insert name localScope
collectFromBody nameToFind' globalScope localScope' body
collectFromBody foundNames nameToFind' globalScope localScope' body

where
collectFromBody :: Maybe String -> InScope -> InScope -> [Exp] -> Infer Accesses
collectFromBody _ _ _ [] = return S.empty
collectFromBody ntf globalScope localScope (e : es) = do
collectFromBody :: [String] -> Maybe String -> InScope -> InScope -> [Exp] -> Infer Accesses
collectFromBody _ _ _ _ [] = return S.empty
collectFromBody foundNames ntf globalScope localScope (e : es) = do
let localScope' = extendScope localScope e
access <- collect env ntf globalScope localScope' e
next <- collectFromBody ntf globalScope localScope' es
access <- collect env foundNames ntf globalScope localScope' e
let nextFound = case getExpName e of
Just n -> n : foundNames
Nothing -> foundNames
next <- collectFromBody nextFound ntf globalScope localScope' es
return $ access <> next

If cond truthy falsy -> do
condAccesses <- collect env nameToFind globalScope localScope cond
truthyAccesses <- collect env nameToFind globalScope localScope truthy
falsyAccesses <- collect env nameToFind globalScope localScope falsy
condAccesses <- collect env foundNames nameToFind globalScope localScope cond
truthyAccesses <- collect env foundNames nameToFind globalScope localScope truthy
falsyAccesses <- collect env foundNames nameToFind globalScope localScope falsy

return $ condAccesses <> truthyAccesses <> falsyAccesses

Assignment name exp -> do
when (name `S.member` globalScope && not (S.null localScope))
(pushError $ CompilationError (NameAlreadyDefined name) (Context (envCurrentPath env) area (envBacktrace env)))

collect env (Just name) globalScope localScope exp
collect env foundNames (Just name) globalScope localScope exp

TypedExp exp _ -> collect env nameToFind globalScope localScope exp
TypedExp exp _ -> collect env foundNames nameToFind globalScope localScope exp

Export exp -> collect env nameToFind globalScope localScope exp
Export exp -> collect env foundNames nameToFind globalScope localScope exp

Access record fieldAccessor -> do
collect env nameToFind globalScope localScope record
collect env foundNames nameToFind globalScope localScope record

Where exp iss -> do
expAccess <- collect env nameToFind globalScope localScope exp
issAccesses <- mapM (collectFromIs env nameToFind globalScope localScope) iss
expAccess <- collect env foundNames nameToFind globalScope localScope exp
issAccesses <- mapM (collectFromIs env foundNames nameToFind globalScope localScope) iss
let issAccesses' = foldr S.union S.empty issAccesses
return $ expAccess <> issAccesses'

TupleConstructor exps -> do
accesses <- mapM (collect env nameToFind globalScope localScope) exps
accesses <- mapM (collect env foundNames nameToFind globalScope localScope) exps
return $ foldr S.union S.empty accesses

ListConstructor items -> do
listItemAccesses <- mapM (collectFromListItem env nameToFind globalScope localScope) items
listItemAccesses <- mapM (collectFromListItem env foundNames nameToFind globalScope localScope) items
return $ foldr S.union S.empty listItemAccesses

Record fields -> do
fieldAccesses <- mapM (collectFromField env nameToFind globalScope localScope) fields
fieldAccesses <- mapM (collectFromField env foundNames nameToFind globalScope localScope) fields
return $ foldr S.union S.empty fieldAccesses

Placeholder _ exp -> collect env nameToFind globalScope localScope exp
Placeholder _ exp -> collect env foundNames nameToFind globalScope localScope exp

_ -> return S.empty


collectFromField :: Env -> Maybe String -> InScope -> InScope -> Field -> Infer Accesses
collectFromField env nameToFind globalScope localScope (Solved _ _ field) = case field of
Field (name, exp) -> collect env nameToFind globalScope localScope exp
FieldSpread exp -> collect env nameToFind globalScope localScope exp
collectFromField :: Env -> [String] -> Maybe String -> InScope -> InScope -> Field -> Infer Accesses
collectFromField env foundNames nameToFind globalScope localScope (Solved _ _ field) = case field of
Field (name, exp) -> collect env foundNames nameToFind globalScope localScope exp
FieldSpread exp -> collect env foundNames nameToFind globalScope localScope exp

collectFromListItem :: Env -> Maybe String -> InScope -> InScope -> ListItem -> Infer Accesses
collectFromListItem env nameToFind globalScope localScope (Solved _ _ li) = case li of
ListItem exp -> collect env nameToFind globalScope localScope exp
ListSpread exp -> collect env nameToFind globalScope localScope exp
collectFromListItem :: Env -> [String] -> Maybe String -> InScope -> InScope -> ListItem -> Infer Accesses
collectFromListItem env foundNames nameToFind globalScope localScope (Solved _ _ li) = case li of
ListItem exp -> collect env foundNames nameToFind globalScope localScope exp
ListSpread exp -> collect env foundNames nameToFind globalScope localScope exp

collectFromIs :: Env -> Maybe String -> InScope -> InScope -> Is -> Infer Accesses
collectFromIs env nameToFind globalScope localScope (Solved _ _ (Is pat exp)) = do
collectFromIs :: Env -> [String] -> Maybe String -> InScope -> InScope -> Is -> Infer Accesses
collectFromIs env foundNames nameToFind globalScope localScope (Solved _ _ (Is pat exp)) = do
let patternScope = buildPatternScope pat
localScope' = localScope <> patternScope
collect env nameToFind globalScope localScope' exp
collect env foundNames nameToFind globalScope localScope' exp

buildPatternScope :: Pattern -> S.Set String
buildPatternScope (Solved _ _ pat) = case pat of
Expand Down

0 comments on commit 11c0ea7

Please sign in to comment.