compiler: better error messages

This commit is contained in:
hellerve 2019-03-12 19:11:12 +01:00
parent 19bf708312
commit 6716edf2af
10 changed files with 340 additions and 209 deletions

View File

@ -60,6 +60,7 @@ library
, text
, ansi-terminal >= 0.9
, cmark
, edit-distance
default-language: Haskell2010

View File

@ -65,7 +65,7 @@ addCommandConfigurable name maybeArity callback =
withArity arity args =
if length args == arity
then callback args
else return (Left (EvalError ("Invalid args to '" ++ name ++ "' command: " ++ joinWithComma (map pretty args))))
else return (Left (EvalError ("Invalid args to '" ++ name ++ "' command: " ++ joinWithComma (map pretty args)) Nothing))
withoutArity args =
callback args
@ -175,7 +175,7 @@ commandProjectGetConfig [xobj@(XObj (Str key) _ _)] =
"file-path-print-length" -> Right $ Str $ show (projectFilePathPrintLength proj)
_ ->
Left $ EvalError ("[CONFIG ERROR] Project.get-config can't understand the key '" ++
key ++ "' at " ++ prettyInfoFromXObj xobj ++ ".")
key) (info xobj)
commandProjectGetConfig [faultyKey] =
do presentError ("First argument to 'Project.config' must be a string: " ++ pretty faultyKey) dynamicNil
@ -229,7 +229,10 @@ commandBuild args =
)
case src of
Left err ->
return (Left (EvalError ("[CODEGEN ERROR] " ++ show err)))
return (Left (EvalError
("I encountered an error when emitting code:\n\n" ++
(show err))
Nothing))
Right okSrc ->
do let compiler = projectCompiler proj
echoCompilationCommand = projectEchoCompilationCommand proj
@ -506,48 +509,48 @@ commandLength [x] =
case x of
XObj (Lst lst) _ _ -> return (Right (XObj (Num IntTy (fromIntegral (length lst))) Nothing Nothing))
XObj (Arr arr) _ _ -> return (Right (XObj (Num IntTy (fromIntegral (length arr))) Nothing Nothing))
_ -> return (Left (EvalError ("Applying 'length' to non-list: " ++ pretty x ++ " at " ++ prettyInfoFromXObj x)))
_ -> return (Left (EvalError ("Applying 'length' to non-list: " ++ pretty x) (info x)))
commandCar :: CommandCallback
commandCar [x] =
case x of
XObj (Lst (car : _)) _ _ -> return (Right car)
XObj (Arr (car : _)) _ _ -> return (Right car)
_ -> return (Left (EvalError ("Applying 'car' to non-list: " ++ pretty x)))
_ -> return (Left (EvalError ("Applying 'car' to non-list: " ++ pretty x) (info x)))
commandCdr :: CommandCallback
commandCdr [x] =
case x of
XObj (Lst (_ : cdr)) i _ -> return (Right (XObj (Lst cdr) i Nothing))
XObj (Arr (_ : cdr)) i _ -> return (Right (XObj (Arr cdr) i Nothing))
_ -> return (Left (EvalError "Applying 'cdr' to non-list or empty list"))
_ -> return (Left (EvalError "Applying 'cdr' to non-list or empty list" (info x)))
commandLast :: CommandCallback
commandLast [x] =
case x of
XObj (Lst lst) _ _ -> return (Right (last lst))
XObj (Arr arr) _ _ -> return (Right (last arr))
_ -> return (Left (EvalError "Applying 'last' to non-list or empty list."))
_ -> return (Left (EvalError "Applying 'last' to non-list or empty list." (info x)))
commandAllButLast :: CommandCallback
commandAllButLast [x] =
case x of
XObj (Lst lst) i _ -> return (Right (XObj (Lst (init lst)) i Nothing))
XObj (Arr arr) i _ -> return (Right (XObj (Arr (init arr)) i Nothing))
_ -> return (Left (EvalError "Applying 'all-but-last' to non-list or empty list."))
_ -> return (Left (EvalError "Applying 'all-but-last' to non-list or empty list." (info x)))
commandCons :: CommandCallback
commandCons [x, xs] =
case xs of
XObj (Lst lst) _ _ -> return (Right (XObj (Lst (x : lst)) (info x) (ty x))) -- TODO: probably not correct to just copy 'i' and 't'?
XObj (Arr arr) _ _ -> return (Right (XObj (Arr (x : arr)) (info x) (ty x)))
_ -> return (Left (EvalError "Applying 'cons' to non-list or empty list."))
_ -> return (Left (EvalError "Applying 'cons' to non-list or empty list." (info x)))
commandConsLast :: CommandCallback
commandConsLast [x, xs] =
case xs of
XObj (Lst lst) i t -> return (Right (XObj (Lst (lst ++ [x])) i t)) -- TODO: should they get their own i:s and t:s
_ -> return (Left (EvalError "Applying 'cons-last' to non-list or empty list."))
_ -> return (Left (EvalError "Applying 'cons-last' to non-list or empty list." (info x)))
commandAppend :: CommandCallback
commandAppend [xs, ys] =
@ -555,13 +558,13 @@ commandAppend [xs, ys] =
(XObj (Lst lst1) i t, XObj (Lst lst2) _ _) ->
return (Right (XObj (Lst (lst1 ++ lst2)) i t)) -- TODO: should they get their own i:s and t:s
_ ->
return (Left (EvalError "Applying 'append' to non-list or empty list."))
return (Left (EvalError "Applying 'append' to non-list or empty list." (info xs)))
commandMacroError :: CommandCallback
commandMacroError [msg] =
case msg of
XObj (Str msg) _ _ -> return (Left (EvalError msg))
x -> return (Left (EvalError (pretty x)))
XObj (Str smsg) _ _ -> return (Left (EvalError smsg (info msg)))
x -> return (Left (EvalError (pretty x) (info msg)))
commandMacroLog :: CommandCallback
commandMacroLog [msg] =
@ -597,7 +600,7 @@ commandEq [a, b] =
(XObj (Lst []) _ _, XObj (Lst []) _ _) ->
Right trueXObj
_ ->
Left (EvalError ("Can't compare " ++ pretty a ++ " with " ++ pretty b))
Left (EvalError ("Can't compare " ++ pretty a ++ " with " ++ pretty b) (info a))
commandLt :: CommandCallback
commandLt [a, b] =
@ -615,7 +618,7 @@ commandLt [a, b] =
if aNum < bNum
then Right trueXObj else Right falseXObj
_ ->
Left (EvalError ("Can't compare (<) " ++ pretty a ++ " with " ++ pretty b))
Left (EvalError ("Can't compare (<) " ++ pretty a ++ " with " ++ pretty b) (info a))
commandGt :: CommandCallback
commandGt [a, b] =
@ -633,7 +636,7 @@ commandGt [a, b] =
if aNum > bNum
then Right trueXObj else Right falseXObj
_ ->
Left (EvalError ("Can't compare (>) " ++ pretty a ++ " with " ++ pretty b))
Left (EvalError ("Can't compare (>) " ++ pretty a ++ " with " ++ pretty b) (info a))
commandCharAt :: CommandCallback
commandCharAt [a, b] =
@ -641,7 +644,7 @@ commandCharAt [a, b] =
(XObj (Str s) _ _, XObj (Num IntTy n) _ _) ->
Right (XObj (Chr (s !! (round n :: Int))) (Just dummyInfo) (Just IntTy))
_ ->
Left (EvalError ("Can't call char-at with " ++ pretty a ++ " and " ++ pretty b))
Left (EvalError ("Can't call char-at with " ++ pretty a ++ " and " ++ pretty b) (info a))
commandIndexOf :: CommandCallback
commandIndexOf [a, b] =
@ -649,7 +652,7 @@ commandIndexOf [a, b] =
(XObj (Str s) _ _, XObj (Chr c) _ _) ->
Right (XObj (Num IntTy (getIdx c s)) (Just dummyInfo) (Just IntTy))
_ ->
Left (EvalError ("Can't call index-of with " ++ pretty a ++ " and " ++ pretty b))
Left (EvalError ("Can't call index-of with " ++ pretty a ++ " and " ++ pretty b) (info a))
where getIdx c s = fromIntegral $ fromMaybe (-1) $ elemIndex c s
commandSubstring :: CommandCallback
@ -658,7 +661,7 @@ commandSubstring [a, b, c] =
(XObj (Str s) _ _, XObj (Num IntTy f) _ _, XObj (Num IntTy t) _ _) ->
Right (XObj (Str (take (round t :: Int) (drop (round f :: Int) s))) (Just dummyInfo) (Just StringTy))
_ ->
Left (EvalError ("Can't call substring with " ++ pretty a ++ ", " ++ pretty b ++ " and " ++ pretty c))
Left (EvalError ("Can't call substring with " ++ pretty a ++ ", " ++ pretty b ++ " and " ++ pretty c) (info a))
commandStringLength :: CommandCallback
commandStringLength [a] =
@ -666,17 +669,17 @@ commandStringLength [a] =
XObj (Str s) _ _ ->
Right (XObj (Num IntTy (fromIntegral (length s))) (Just dummyInfo) (Just IntTy))
_ ->
Left (EvalError ("Can't call length with " ++ pretty a))
Left (EvalError ("Can't call length with " ++ pretty a) (info a))
commandStringJoin :: CommandCallback
commandStringJoin [a] =
return $ case a of
XObj (Arr strings) _ _ ->
case (sequence (map unwrapStringXObj strings)) of
Left err -> Left (EvalError err)
Left err -> Left (EvalError err (info a))
Right result -> Right (XObj (Str (join result)) (Just dummyInfo) (Just StringTy))
_ ->
Left (EvalError ("Can't call join with " ++ pretty a))
Left (EvalError ("Can't call join with " ++ pretty a) (info a))
commandStringDirectory :: CommandCallback
commandStringDirectory [a] =
@ -684,7 +687,7 @@ commandStringDirectory [a] =
XObj (Str s) _ _ ->
Right (XObj (Str (takeDirectory s)) (Just dummyInfo) (Just StringTy))
_ ->
Left (EvalError ("Can't call directory with " ++ pretty a))
Left (EvalError ("Can't call directory with " ++ pretty a) (info a))
commandPlus :: CommandCallback
commandPlus [a, b] =
@ -692,9 +695,9 @@ commandPlus [a, b] =
(XObj (Num aty aNum) _ _, XObj (Num bty bNum) _ _) ->
if aty == bty
then Right (XObj (Num aty (aNum + bNum)) (Just dummyInfo) (Just aty))
else Left (EvalError ("Can't call + with " ++ pretty a ++ " and " ++ pretty b))
else Left (EvalError ("Can't call + with " ++ pretty a ++ " and " ++ pretty b) (info a))
_ ->
Left (EvalError ("Can't call + with " ++ pretty a ++ " and " ++ pretty b))
Left (EvalError ("Can't call + with " ++ pretty a ++ " and " ++ pretty b) (info a))
commandMinus :: CommandCallback
commandMinus [a, b] =
@ -702,9 +705,9 @@ commandMinus [a, b] =
(XObj (Num aty aNum) _ _, XObj (Num bty bNum) _ _) ->
if aty == bty
then Right (XObj (Num aty (aNum - bNum)) (Just dummyInfo) (Just aty))
else Left (EvalError ("Can't call - with " ++ pretty a ++ " and " ++ pretty b))
else Left (EvalError ("Can't call - with " ++ pretty a ++ " and " ++ pretty b) (info a))
_ ->
Left (EvalError ("Can't call - with " ++ pretty a ++ " and " ++ pretty b))
Left (EvalError ("Can't call - with " ++ pretty a ++ " and " ++ pretty b) (info a))
commandDiv :: CommandCallback
commandDiv [a, b] =
@ -714,9 +717,9 @@ commandDiv [a, b] =
(XObj (Num aty aNum) _ _, XObj (Num bty bNum) _ _) ->
if aty == bty
then Right (XObj (Num aty (aNum / bNum)) (Just dummyInfo) (Just aty))
else Left (EvalError ("Can't call / with " ++ pretty a ++ " and " ++ pretty b))
else Left (EvalError ("Can't call / with " ++ pretty a ++ " and " ++ pretty b) (info a))
_ ->
Left (EvalError ("Can't call / with " ++ pretty a ++ " and " ++ pretty b))
Left (EvalError ("Can't call / with " ++ pretty a ++ " and " ++ pretty b) (info a))
commandMul :: CommandCallback
commandMul [a, b] =
@ -724,9 +727,9 @@ commandMul [a, b] =
(XObj (Num aty aNum) _ _, XObj (Num bty bNum) _ _) ->
if aty == bty
then Right (XObj (Num aty (aNum * bNum)) (Just dummyInfo) (Just aty))
else Left (EvalError ("Can't call * with " ++ pretty a ++ " and " ++ pretty b))
else Left (EvalError ("Can't call * with " ++ pretty a ++ " and " ++ pretty b) (info a))
_ ->
Left (EvalError ("Can't call * with " ++ pretty a ++ " and " ++ pretty b))
Left (EvalError ("Can't call * with " ++ pretty a ++ " and " ++ pretty b) (info a))
commandStr :: CommandCallback
commandStr xs =
@ -747,7 +750,7 @@ commandNot [x] =
then return (Right falseXObj)
else return (Right trueXObj)
_ ->
return (Left (EvalError ("Can't perform logical operation (not) on " ++ pretty x)))
return (Left (EvalError ("Can't perform logical operation (not) on " ++ pretty x) (info x)))
commandSaveDocsInternal :: CommandCallback
commandSaveDocsInternal [modulePath] =
@ -756,22 +759,22 @@ commandSaveDocsInternal [modulePath] =
case modulePath of
XObj (Lst xobjs) _ _ ->
case sequence (map unwrapSymPathXObj xobjs) of
Left err -> return (Left (EvalError err))
Left err -> return (Left (EvalError err (info modulePath)))
Right okPaths ->
case sequence (map (getEnvironmentForDocumentation globalEnv) okPaths) of
Left err -> return (Left err)
Right okEnvs -> saveDocs (zip okPaths okEnvs)
x ->
return (Left (EvalError ("Invalid arg to save-docs-internal (expected list of symbols): " ++ pretty x)))
return (Left (EvalError ("Invalid arg to save-docs-internal (expected list of symbols): " ++ pretty x) (info modulePath)))
where getEnvironmentForDocumentation :: Env -> SymPath -> Either EvalError Env
getEnvironmentForDocumentation env path =
case lookupInEnv path env of
Just (_, Binder _ (XObj (Mod foundEnv) _ _)) ->
Right foundEnv
Just (_, Binder _ x) ->
Left (EvalError ("Non module can't be saved: " ++ pretty x))
Left (EvalError ("Non module can't be saved: " ++ pretty x) (info modulePath))
Nothing ->
Left (EvalError ("Can't find module at '" ++ show path ++ "'"))
Left (EvalError ("Can't find module at '" ++ show path ++ "'") (info modulePath))
saveDocs :: [(SymPath, Env)] -> StateT Context IO (Either EvalError XObj)
saveDocs pathsAndEnvs =

View File

@ -32,10 +32,10 @@ indentAmount = 4
data ToCError = InvalidParameter XObj
| InvalidList XObj
| DontVisitObj Obj
| CannotEmitUnit
| CannotEmitExternal
| CannotEmitModKeyword
| DontVisitObj XObj
| CannotEmitUnit XObj
| CannotEmitExternal XObj
| CannotEmitModKeyword XObj
| BinderIsMissingType Binder
| UnresolvedMultiSymbol XObj
| UnresolvedInterfaceSymbol XObj
@ -43,23 +43,40 @@ data ToCError = InvalidParameter XObj
| CannotSet XObj
instance Show ToCError where
show (InvalidParameter xobj) = "Invalid parameter: " ++ show (obj xobj)
show (InvalidList xobj) = "Invalid list: " ++ show (obj xobj)
show (DontVisitObj o) = "Don't visit " ++ show o ++ " (internal compiler error)."
show CannotEmitUnit = "Can't emit code for empty list: ()"
show CannotEmitExternal = "Can't emit code for external function/variable."
show CannotEmitModKeyword = "Can't emit code for Mod."
show (BinderIsMissingType b) = "Binder is missing type: " ++ show b
show (InvalidParameter xobj) =
"I encountered an invalid parameter `" ++ show (obj xobj) ++ "` at " ++
prettyInfoFromXObj xobj ++ "."
show (InvalidList xobj) =
"I encountered an invalid list `" ++ show (obj xobj) ++ "` at " ++
prettyInfoFromXObj xobj ++ "."
show (DontVisitObj xobj) =
"I cant visit " ++ show (obj xobj) ++ " at " ++ prettyInfoFromXObj xobj ++
"."
show (CannotEmitUnit xobj) =
"I can't emit code for the unit type `()` at" ++ prettyInfoFromXObj xobj ++
"."
show (CannotEmitExternal xobj) =
"I cant emit code for the external function/variable `" ++
show (obj xobj) ++ "` at " ++ prettyInfoFromXObj xobj ++ "."
show (CannotEmitModKeyword xobj) =
"I cant emit code for the module `" ++ show (obj xobj) ++ "` at " ++
prettyInfoFromXObj xobj ++ "."
show (BinderIsMissingType b) =
"I encountered a binder `" ++ show b ++ "` that is missing its type."
show (UnresolvedMultiSymbol xobj@(XObj (MultiSym symName symPaths) _ _)) =
"Found ambiguous symbol '" ++ symName ++
"' (alternatives are " ++ joinWithComma (map show symPaths) ++ ")" ++
" at " ++ prettyInfoFromXObj xobj
"I found an ambiguous symbol `" ++ symName ++
"` at " ++ prettyInfoFromXObj xobj ++ "\n\nPossibilities:\n " ++
joinWith "\n " (map show symPaths) ++
"\n\nAll possibilities have the correct type."
show (UnresolvedInterfaceSymbol xobj@(XObj (InterfaceSym symName) _ _)) =
"Found unresolved use of interface '" ++ symName ++ "'" ++
" at " ++ prettyInfoFromXObj xobj
"I found an interface `" ++ symName ++
"` that is unresolved in the context at" ++ prettyInfoFromXObj xobj
show (UnresolvedGenericType xobj@(XObj _ _ (Just t))) =
"Found unresolved generic type '" ++ show t ++ "' at " ++ prettyInfoFromXObj xobj
show (CannotSet xobj) = "Can't emit code for setting " ++ pretty xobj ++ " at " ++ prettyInfoFromXObj xobj
"I found an unresolved generic type `" ++ show t ++
"` for the expression `" ++ show xobj ++ "` at " ++ prettyInfoFromXObj xobj
show (CannotSet xobj) =
"I cant emit code for setting `" ++ pretty xobj ++ "` at " ++
prettyInfoFromXObj xobj ++ "\n\nOnly variables can be reset using `set!`."
data ToCMode = Functions | Globals | All deriving Show
@ -93,32 +110,32 @@ toC toCMode root = emitterSrc (execState (visit startingIndent root) (EmitterSta
'\\' -> "'\\\\'"
x -> ['\'', x, '\'']
Sym _ _ -> visitSymbol indent xobj
Defn -> error (show (DontVisitObj Defn))
Def -> error (show (DontVisitObj Def))
Let -> error (show (DontVisitObj Let))
If -> error (show (DontVisitObj If))
Break -> error (show (DontVisitObj Break))
While -> error (show (DontVisitObj While))
Do -> error (show (DontVisitObj Do))
e@(Typ _) -> error (show (DontVisitObj e))
e@(DefSumtype _) -> error (show (DontVisitObj e))
Mod _ -> error (show CannotEmitModKeyword)
External _ -> error (show CannotEmitExternal)
ExternalType -> error (show (DontVisitObj ExternalType))
e@(Command _) -> error (show (DontVisitObj e))
e@(Deftemplate _) -> error (show (DontVisitObj e))
e@(Instantiate _) -> error (show (DontVisitObj e))
e@(Defalias _) -> error (show (DontVisitObj e))
e@(MultiSym _ _) -> error (show (DontVisitObj e))
e@(InterfaceSym _) -> error (show (DontVisitObj e))
Address -> error (show (DontVisitObj Address))
SetBang -> error (show (DontVisitObj SetBang))
Macro -> error (show (DontVisitObj Macro))
Dynamic -> error (show (DontVisitObj Dynamic))
The -> error (show (DontVisitObj The))
Ref -> error (show (DontVisitObj Ref))
Deref -> error (show (DontVisitObj Deref))
e@(Interface _ _) -> error (show (DontVisitObj e))
Defn -> error (show (DontVisitObj xobj))
Def -> error (show (DontVisitObj xobj))
Let -> error (show (DontVisitObj xobj))
If -> error (show (DontVisitObj xobj))
Break -> error (show (DontVisitObj xobj))
While -> error (show (DontVisitObj xobj))
Do -> error (show (DontVisitObj xobj))
e@(Typ _) -> error (show (DontVisitObj xobj))
e@(DefSumtype _) -> error (show (DontVisitObj xobj))
Mod _ -> error (show (CannotEmitModKeyword xobj))
External _ -> error (show (CannotEmitExternal xobj))
ExternalType -> error (show (DontVisitObj xobj))
e@(Command _) -> error (show (DontVisitObj xobj))
e@(Deftemplate _) -> error (show (DontVisitObj xobj))
e@(Instantiate _) -> error (show (DontVisitObj xobj))
e@(Defalias _) -> error (show (DontVisitObj xobj))
e@(MultiSym _ _) -> error (show (DontVisitObj xobj))
e@(InterfaceSym _) -> error (show (DontVisitObj xobj))
Address -> error (show (DontVisitObj xobj))
SetBang -> error (show (DontVisitObj xobj))
Macro -> error (show (DontVisitObj xobj))
Dynamic -> error (show (DontVisitObj xobj))
The -> error (show (DontVisitObj xobj))
Ref -> error (show (DontVisitObj xobj))
Deref -> error (show (DontVisitObj xobj))
e@(Interface _ _) -> error (show (DontVisitObj xobj))
visitStr' indent str i =
-- | This will allocate a new string every time the code runs:

View File

@ -59,40 +59,40 @@ eval env xobj =
[XObj (Sym (SymPath [] "file") _) _ _] ->
case i of
Just info -> return (Right (XObj (Str (infoFile info)) i t))
Nothing -> return (Left (EvalError ("No information about object " ++ pretty xobj)))
Nothing -> return (Left (EvalError ("No information about object " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "line") _) _ _] ->
case i of
Just info ->
return (Right (XObj (Num IntTy (fromIntegral (infoLine info))) i t))
Nothing ->
return (Left (EvalError ("No information about object " ++ pretty xobj)))
return (Left (EvalError ("No information about object " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "column") _) _ _] ->
case i of
Just info ->
return (Right (XObj (Num IntTy (fromIntegral (infoColumn info))) i t))
Nothing ->
return (Left (EvalError ("No information about object " ++ pretty xobj)))
return (Left (EvalError ("No information about object " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "file") _) _ _, XObj _ infoToCheck _] ->
case infoToCheck of
Just info -> return (Right (XObj (Str (infoFile info)) i t))
Nothing -> return (Left (EvalError ("No information about object " ++ pretty xobj)))
Nothing -> return (Left (EvalError ("No information about object " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "line") _) _ _, XObj _ infoToCheck _] ->
case infoToCheck of
Just info ->
return (Right (XObj (Num IntTy (fromIntegral (infoLine info))) i t))
Nothing ->
return (Left (EvalError ("No information about object " ++ pretty xobj)))
return (Left (EvalError ("No information about object " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "column") _) _ _, XObj _ infoToCheck _] ->
case infoToCheck of
Just info ->
return (Right (XObj (Num IntTy (fromIntegral (infoColumn info))) i t))
Nothing ->
return (Left (EvalError ("No information about object " ++ pretty xobj)))
return (Left (EvalError ("No information about object " ++ pretty xobj) (info xobj)))
XObj Do _ _ : rest ->
do evaledList <- fmap sequence (mapM (eval env) rest)
@ -100,7 +100,7 @@ eval env xobj =
Left e -> return (Left e)
Right ok ->
case ok of
[] -> return (Left (EvalError "No forms in 'do' statement."))
[] -> return (Left (EvalError "No forms in 'do' statement." (info xobj)))
_ -> return (Right (last ok))
XObj (Sym (SymPath [] "list") _) _ _ : rest ->
@ -126,10 +126,10 @@ eval env xobj =
XObj (Bol bb) _ _ ->
if bb then Right trueXObj else Right falseXObj
_ ->
Left (EvalError ("Can't perform logical operation (and) on " ++ pretty okB))
Left (EvalError ("Can't perform logical operation (and) on " ++ pretty okB) (info okB))
else Right falseXObj
_ ->
Left (EvalError ("Can't perform logical operation (and) on " ++ pretty okA))
Left (EvalError ("Can't perform logical operation (and) on " ++ pretty okA) (info okA))
[XObj (Sym (SymPath ["Dynamic"] "or") _) _ _, a, b] ->
do evaledA <- eval env a
@ -144,9 +144,9 @@ eval env xobj =
XObj (Bol bb) _ _ ->
if bb then Right trueXObj else Right falseXObj
_ ->
Left (EvalError ("Can't perform logical operation (or) on " ++ pretty okB))
Left (EvalError ("Can't perform logical operation (or) on " ++ pretty okB) (info okB))
_ ->
Left (EvalError ("Can't perform logical operation (or) on " ++ pretty okA))
Left (EvalError ("Can't perform logical operation (or) on " ++ pretty okA) (info okA))
[XObj If _ _, condition, ifTrue, ifFalse] ->
do evaledCondition <- eval env condition
@ -156,11 +156,21 @@ eval env xobj =
Bol b -> if b
then eval env ifTrue
else eval env ifFalse
_ -> return (Left (EvalError ("Non-boolean expression in if-statement: " ++ pretty okCondition)))
_ -> return (Left (EvalError ("`if` condition contains non-boolean value: " ++ pretty okCondition) (info okCondition)))
Left err -> return (Left err)
[defnExpr@(XObj Defn _ _), name, args, body] ->
specialCommandDefine xobj
[defnExpr@(XObj Defn _ _), name, args@(XObj (Arr a) _ _), body] ->
if all isSym a
then specialCommandDefine xobj
else return (Left (EvalError ("`defn` requires all arguments to be symbols, but it got `" ++ pretty args ++ "`") (info xobj)))
where isSym (XObj (Sym _ _) _ _) = True
isSym _ = False
[defnExpr@(XObj Defn _ _), name, invalidArgs, _] ->
return (Left (EvalError ("`defn` requires an array of symbols as argument list, but it got `" ++ pretty invalidArgs ++ "`") (info xobj)))
(defnExpr@(XObj Defn _ _) : _) ->
return (Left (EvalError ("I didnt understand the `defn` at " ++ prettyInfoFromXObj xobj ++ ":\n\n" ++ pretty xobj ++ "\n\nIs it valid? Every `defn` needs to follow the form `(defn name [arg] body)`.") Nothing))
[defExpr@(XObj Def _ _), name, expr] ->
specialCommandDefine xobj
@ -187,12 +197,12 @@ eval env xobj =
evaledBody <- eval envWithBindings body
return $ do okBody <- evaledBody
Right okBody
else return (Left (EvalError ("Uneven number of forms in let-statement: " ++ pretty xobj))) -- Unreachable?
else return (Left (EvalError ("Uneven number of forms in `let`: " ++ pretty xobj) (info xobj))) -- Unreachable?
XObj (Sym (SymPath [] "register-type") _) _ _ : XObj (Sym (SymPath _ typeName) _) _ _ : rest ->
specialCommandRegisterType typeName rest
XObj (Sym (SymPath _ "register-type") _) _ _ : _ ->
return (Left (EvalError (show "Invalid ars to 'register-type': " ++ pretty xobj)))
return (Left (EvalError (show "Invalid args to `register-type`: " ++ pretty xobj) (info xobj)))
XObj (Sym (SymPath [] "deftype") _) _ _ : nameXObj : rest ->
specialCommandDeftype nameXObj rest
@ -202,62 +212,62 @@ eval env xobj =
[XObj (Sym (SymPath [] "register") _) _ _, XObj (Sym (SymPath _ name) _) _ _, typeXObj, XObj (Str overrideName) _ _] ->
specialCommandRegister name typeXObj (Just overrideName)
XObj (Sym (SymPath [] "register") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'register' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `register`: " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "definterface") _) _ _, nameXObj@(XObj (Sym _ _) _ _), typeXObj] ->
specialCommandDefinterface nameXObj typeXObj
XObj (Sym (SymPath [] "definterface") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'definterface' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `definterface`: " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "defdynamic") _) _ _, (XObj (Sym (SymPath [] name) _) _ _), params, body] ->
specialCommandDefdynamic name params body
XObj (Sym (SymPath [] "defdynamic") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'defdynamic' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `defdynamic`: " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "defmacro") _) _ _, (XObj (Sym (SymPath [] name) _) _ _), params, body] ->
specialCommandDefmacro name params body
XObj (Sym (SymPath [] "defmacro") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'defmacro' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `defmacro`: " ++ pretty xobj) (info xobj)))
XObj (Sym (SymPath [] "defmodule") _) _ _ : (XObj (Sym (SymPath [] moduleName) _) _ _) : innerExpressions ->
specialCommandDefmodule xobj moduleName innerExpressions
XObj (Sym (SymPath [] "defmodule") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'defmodule' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `defmodule`: " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "info") _) _ _, target@(XObj (Sym path @(SymPath _ name) _) _ _)] ->
specialCommandInfo target
XObj (Sym (SymPath [] "info") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'info' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `info`: " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "type") _) _ _, target] ->
specialCommandType target
XObj (Sym (SymPath [] "type") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'type' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `type`: " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "meta-set!") _) _ _, target@(XObj (Sym path @(SymPath _ name) _) _ _), (XObj (Str key) _ _), value] ->
specialCommandMetaSet path key value
XObj (Sym (SymPath [] "meta-set!") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'meta-set!' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `meta-set!`: " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "meta") _) _ _, target@(XObj (Sym path @(SymPath _ name) _) _ _), (XObj (Str key) _ _)] ->
specialCommandMetaGet path key
XObj (Sym (SymPath [] "meta") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'meta' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `meta`: " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "members") _) _ _, target] ->
specialCommandMembers target
XObj (Sym (SymPath [] "members") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'members' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `members`: " ++ pretty xobj) (info xobj)))
[XObj (Sym (SymPath [] "use") _) _ _, xobj@(XObj (Sym path _) _ _)] ->
specialCommandUse xobj path
XObj (Sym (SymPath [] "use") _) _ _ : _ ->
return (Left (EvalError ("Invalid args to 'use' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `use`: " ++ pretty xobj) (info xobj)))
XObj With _ _ : xobj@(XObj (Sym path _) _ _) : forms ->
specialCommandWith xobj path forms
XObj With _ _ : _ ->
return (Left (EvalError ("Invalid args to 'with.' command: " ++ pretty xobj)))
return (Left (EvalError ("Invalid args to `with`: " ++ pretty xobj) (info xobj)))
f:args -> do evaledF <- eval env f
case evaledF of
@ -285,8 +295,8 @@ eval env xobj =
Right okArgs -> getCommand callback okArgs
Left err -> return (Left err)
_ ->
return (Left (EvalError ("Can't eval non-macro / non-dynamic function '" ++ pretty f ++ "' in " ++
pretty xobj ++ " at " ++ prettyInfoFromXObj xobj)))
return (Left (EvalError ("Can't eval '" ++ pretty f ++ "' (its neither a macro nor a dynamic function) in " ++
pretty xobj) (info f)))
evalList _ = error "Can't eval non-list in evalList."
@ -297,7 +307,7 @@ eval env xobj =
Nothing ->
case lookupInEnv path env of
Just (_, Binder _ found) -> return (Right found)
Nothing -> return (Left (EvalError ("Can't find symbol '" ++ show path ++ "' at " ++ prettyInfoFromXObj xobj)))
Nothing -> return (Left (EvalError ("Can't find symbol '" ++ show path ++ "'") (info xobj)))
evalSymbol _ = error "Can't eval non-symbol in evalSymbol."
evalArray :: XObj -> StateT Context IO (Either EvalError XObj)
@ -319,9 +329,7 @@ checkMatchingNrOfArgs xobj params args =
else show paramLen
in if (usesRestArgs && argsLen > paramLen) || (paramLen == argsLen)
then Right ()
else Left (EvalError ("Wrong nr of arguments in call to '" ++ pretty xobj ++ "' at " ++ prettyInfoFromXObj xobj ++
", expected " ++ expected ++ " but got " ++ show argsLen ++ "."
))
else Left (EvalError ("Wrong number of arguments in call to '" ++ pretty xobj ++ "', expected " ++ expected ++ " but got " ++ show argsLen) (info xobj))
-- | Apply a function to some arguments. The other half of 'eval'.
apply :: Env -> XObj -> [XObj] -> [XObj] -> StateT Context IO (Either EvalError XObj)
@ -356,9 +364,9 @@ found binder =
notFound :: ExecutionMode -> XObj -> SymPath -> StateT Context IO (Either EvalError XObj)
notFound execMode xobj path =
do fppl <- fmap (projectFilePathPrintLength . contextProj) get
return $ Left $ EvalError $ case execMode of
return $ Left $ EvalError (case execMode of
Check -> machineReadableInfoFromXObj fppl xobj ++ (" Can't find '" ++ show path ++ "'")
_ -> "Can't find '" ++ show path ++ "'"
_ -> "Can't find '" ++ show path ++ "'") (info xobj)
-- | A command at the REPL
-- | TODO: Is it possible to remove the error cases?
@ -475,7 +483,7 @@ catcher ctx exception =
CancelEvaluationException ->
stop 1
EvalException evalError ->
do putStrLnWithColor Red ("[EVAL ERROR] " ++ show evalError)
do putStrLnWithColor Red (show evalError)
stop 1
where stop returnCode =
case contextExecMode ctx of
@ -515,8 +523,8 @@ define hidden ctx@(Context globalEnv typeEnv _ proj _ _) annXObj =
Just foundSignature ->
do let Just sigTy = xobjToTy foundSignature
when (not (areUnifiable (forceTy annXObj) sigTy)) $
throw $ EvalException (EvalError ("Definition at " ++ prettyInfoFromXObj annXObj ++ " does not match 'sig' annotation " ++
show sigTy ++ ", actual type is " ++ show (forceTy annXObj)))
throw $ EvalException (EvalError ("Definition at " ++ prettyInfoFromXObj annXObj ++ " does not match `sig` annotation " ++
show sigTy ++ ", actual type is `" ++ show (forceTy annXObj) ++ "`.") Nothing)
Nothing ->
return ()
--putStrLnWithColor Blue (show (getPath annXObj) ++ " : " ++ showMaybeTy (ty annXObj) ++ (if hidden then " [HIDDEN]" else ""))
@ -582,7 +590,7 @@ specialCommandDefine xobj =
expansionResult <- expandAll eval globalEnv xobj
ctxAfterExpansion <- get
case expansionResult of
Left err -> return (Left (EvalError (show err)))
Left err -> return (Left (EvalError (show err) Nothing))
Right expanded ->
let xobjFullPath = setFullyQualifiedDefn expanded (SymPath pathStrings (getName xobj))
xobjFullSymbols = setFullyQualifiedSymbols typeEnv globalEnv innerEnv xobjFullPath
@ -591,9 +599,9 @@ specialCommandDefine xobj =
case contextExecMode ctx of
Check ->
let fppl = projectFilePathPrintLength (contextProj ctx)
in return (Left (EvalError (joinWith "\n" (machineReadableErrorStrings fppl err))))
in return (Left (EvalError (joinWith "\n" (machineReadableErrorStrings fppl err)) Nothing))
_ ->
return (Left (EvalError (show err)))
return (Left (EvalError (show err) Nothing))
Right (annXObj, annDeps) ->
do ctxWithDeps <- liftIO $ foldM (define True) ctxAfterExpansion annDeps
ctxWithDef <- liftIO $ define False ctxWithDeps annXObj
@ -620,7 +628,7 @@ specialCommandRegisterType typeName rest =
members ->
case bindingsForRegisteredType typeEnv globalEnv pathStrings typeName members i preExistingModule of
Left errorMessage ->
return (Left (EvalError (show errorMessage)))
return (Left (EvalError (show errorMessage) Nothing))
Right (typeModuleName, typeModuleXObj, deps) ->
let ctx' = (ctx { contextGlobalEnv = envInsertAt globalEnv (SymPath pathStrings typeModuleName) (Binder emptyMeta typeModuleXObj)
, contextTypeEnv = TypeEnv (extendEnv (getTypeEnv typeEnv) typeName typeDefinition)
@ -670,11 +678,11 @@ deftypeInternal nameXObj typeName typeVariableXObjs rest =
Right ok -> put ok
return dynamicNil
Left err ->
return (Left (EvalError ("Invalid type definition for '" ++ pretty nameXObj ++ "':\n\n" ++ show err)))
return (Left (EvalError ("Invalid type definition for '" ++ pretty nameXObj ++ "':\n\n" ++ show err) Nothing))
(_, Nothing) ->
return (Left (EvalError ("Invalid type variables for type definition: " ++ pretty nameXObj)))
return (Left (EvalError ("Invalid type variables for type definition: " ++ pretty nameXObj) (info nameXObj)))
_ ->
return (Left (EvalError ("Invalid name for type definition: " ++ pretty nameXObj)))
return (Left (EvalError ("Invalid name for type definition: " ++ pretty nameXObj) (info nameXObj)))
specialCommandRegister :: String -> XObj -> Maybe String -> StateT Context IO (Either EvalError XObj)
specialCommandRegister name typeXObj overrideName =
@ -694,12 +702,12 @@ specialCommandRegister name typeXObj overrideName =
Check -> let fppl = projectFilePathPrintLength (contextProj ctx)
in machineReadableInfoFromXObj fppl typeXObj ++ " "
_ -> ""
in return (Left (EvalError (prefix ++ err)))
in return (Left (EvalError (prefix ++ err) (info typeXObj)))
Right ctx' ->
do put (ctx' { contextGlobalEnv = env' })
return dynamicNil
Nothing ->
return (Left (EvalError ("Can't understand type when registering '" ++ name ++ "'")))
return (Left (EvalError ("Can't understand type when registering '" ++ name ++ "'") (info typeXObj)))
specialCommandDefinterface :: XObj -> XObj -> StateT Context IO (Either EvalError XObj)
specialCommandDefinterface nameXObj@(XObj (Sym path@(SymPath [] name) _) _ _) typeXObj =
@ -722,7 +730,7 @@ specialCommandDefinterface nameXObj@(XObj (Sym path@(SymPath [] name) _) _ _) ty
return dynamicNil
Nothing ->
return (Left (EvalError ("Invalid type for interface '" ++ name ++ "': " ++
pretty typeXObj ++ " at " ++ prettyInfoFromXObj typeXObj ++ ".")))
pretty typeXObj) (info typeXObj)))
specialCommandDefdynamic :: String -> XObj -> XObj -> StateT Context IO (Either EvalError XObj)
specialCommandDefdynamic name params body =
@ -762,7 +770,7 @@ specialCommandDefmodule xobj moduleName innerExpressions =
put (popModulePath ctxAfterModuleAdditions)
return dynamicNil -- TODO: propagate errors...
Just _ ->
return (Left (EvalError ("Can't redefine '" ++ moduleName ++ "' as module.")))
return (Left (EvalError ("Can't redefine '" ++ moduleName ++ "' as module") (info xobj)))
Nothing ->
do let parentEnv = getEnv env pathStrings
innerEnv = Env (Map.fromList []) (Just parentEnv) (Just moduleName) [] ExternalEnv 0
@ -868,9 +876,9 @@ specialCommandMembers target =
->
return (Right (XObj (Arr (map (\(a, b) -> (XObj (Lst [a, b]) Nothing Nothing)) (pairwise members))) Nothing Nothing))
_ ->
return (Left (EvalError ("Can't find a struct type named '" ++ name ++ "' in type environment.")))
return (Left (EvalError ("Can't find a struct type named '" ++ name ++ "' in type environment") (info target)))
_ ->
return (Left (EvalError ("Can't get the members of non-symbol: " ++ pretty target)))
return (Left (EvalError ("Can't get the members of non-symbol: " ++ pretty target) (info target)))
specialCommandUse :: XObj -> SymPath -> StateT Context IO (Either EvalError XObj)
specialCommandUse xobj path =
@ -886,7 +894,7 @@ specialCommandUse xobj path =
do put $ ctx { contextGlobalEnv = envReplaceEnvAt env pathStrings e' }
return dynamicNil
Nothing ->
return (Left (EvalError ("Can't find a module named '" ++ show path ++ "' at " ++ prettyInfoFromXObj xobj ++ ".")))
return (Left (EvalError ("Can't find a module named '" ++ show path ++ "'") (info xobj)))
specialCommandWith :: XObj -> SymPath -> [XObj] -> StateT Context IO (Either EvalError XObj)
specialCommandWith xobj path forms =
@ -922,7 +930,7 @@ specialCommandMetaSet path key value =
(Just dummyInfo)
(Just (VarTy "a"))))
(SymPath _ _) ->
return (Left (EvalError ("Special command 'meta-set!' failed, can't find '" ++ show path ++ "'.")))
return (Left (EvalError ("Special command 'meta-set!' failed, can't find '" ++ show path ++ "'") (info value)))
where
setMetaOn :: Context -> Binder -> StateT Context IO (Either EvalError XObj)
setMetaOn ctx binder@(Binder metaData xobj) =
@ -949,7 +957,7 @@ specialCommandMetaGet path key =
Nothing ->
return dynamicNil
Nothing ->
return (Left (EvalError ("Special command 'meta' failed, can't find '" ++ show path ++ "'.")))
return (Left (EvalError ("Special command 'meta' failed, can't find '" ++ show path ++ "'") Nothing))
@ -998,19 +1006,19 @@ commandLoad [xobj@(XObj (Str path) _ _)] =
fppl ctx =
projectFilePathPrintLength (contextProj ctx)
invalidPath ctx path =
Left $ EvalError $
(case contextExecMode ctx of
Left $ EvalError
((case contextExecMode ctx of
Check ->
(machineReadableInfoFromXObj (fppl ctx) xobj) ++ " Invalid path: '" ++ path ++ "'"
_ -> "Invalid path: '" ++ path ++ "'") ++
"\n\nIf you tried loading an external package, try appending a version string (like `@master`)."
"\n\nIf you tried loading an external package, try appending a version string (like `@master`)") (info xobj)
invalidPathWith ctx path stderr =
Left $ EvalError $
(case contextExecMode ctx of
Left $ EvalError
((case contextExecMode ctx of
Check ->
(machineReadableInfoFromXObj (fppl ctx) xobj) ++ " Invalid path: '" ++ path ++ "'"
_ -> "Invalid path: '" ++ path ++ "'") ++
"\n\nTried interpreting statement as git import, but got: " ++ stderr
"\n\nI tried interpreting the statement as a git import, but got: " ++ stderr) (info xobj)
tryInstall path =
let split = splitOn "@" path
in tryInstallWithCheckout (joinWith "@" (init split)) (last split)
@ -1061,7 +1069,7 @@ commandLoad [xobj@(XObj (Str path) _ _)] =
ExitFailure _ -> do
return $ invalidPathWith ctx path stderr1
commandLoad [x] =
return $ Left (EvalError ("Invalid args to 'load' command: " ++ pretty x))
return $ Left (EvalError ("Invalid args to 'load' command: " ++ pretty x) (info x))
-- | Load several files in order.
@ -1111,10 +1119,10 @@ commandC [xobj] =
typeEnv = contextTypeEnv ctx
result <- expandAll eval globalEnv xobj
case result of
Left err -> return (Left (EvalError (show err)))
Left err -> return (Left (EvalError (show err) (info xobj)))
Right expanded ->
case annotate typeEnv globalEnv (setFullyQualifiedSymbols typeEnv globalEnv globalEnv expanded) of
Left err -> return (Left (EvalError (show err)))
Left err -> return (Left (EvalError (show err) (info xobj)))
Right (annXObj, annDeps) ->
do liftIO (printC annXObj)
liftIO (mapM printC annDeps)

View File

@ -89,14 +89,18 @@ expand eval env xobj =
return $ do okBindings <- sequence bind
okBody <- expandedBody
Right (XObj (Lst [letExpr, XObj (Arr (concat okBindings)) bindi bindt, okBody]) i t)
else return (Left (EvalError ("Uneven number of forms in let-statement: " ++ pretty xobj ++ " at " ++ prettyInfoFromXObj xobj)))
else return (Left (EvalError (
"I ecountered an odd number of forms inside a `let` (`" ++
pretty xobj ++ "`)")
(info xobj)))
matchExpr@(XObj Match _ _) : expr : rest ->
do ctx <- get
let fppl = projectFilePathPrintLength (contextProj ctx)
if null rest
then return (Left (EvalError ("No forms in match-expression: " ++
machineReadableInfoFromXObj fppl xobj))) -- TODO: fppl shouldn't be decided here
then return (Left
(EvalError "I encountered a `match` without forms"
(info xobj)))
else if even (length rest)
then do expandedExpr <- expand eval env expr
expandedPairs <- mapM (\(l,r) -> do expandedR <- expand eval env r
@ -106,8 +110,9 @@ expand eval env xobj =
return $ do okExpandedExpr <- expandedExpr
okExpandedRest <- expandedRest
return (XObj (Lst (matchExpr : okExpandedExpr : okExpandedRest)) i t)
else return (Left (EvalError ("Uneven number of forms in match-expression: " ++
machineReadableInfoFromXObj fppl xobj)))
else return (Left (EvalError
"I encountered an odd number of forms inside a `match`"
(info xobj)))
doExpr@(XObj Do _ _) : expressions ->
do expandedExpressions <- mapM (expand eval env) expressions
@ -118,11 +123,20 @@ expand eval env xobj =
return $ do okExpression <- expandedExpression
Right (XObj (Lst [withExpr, pathExpr , okExpression]) i t) -- Replace the with-expression with just the expression!
[withExpr@(XObj With _ _), _, _] ->
return (Left (EvalError ("Non-symbol in 'with' expression: " ++ show xobj ++ " at " ++ prettyInfoFromXObj xobj)))
return (Left (EvalError ("I encountered the value `" ++ pretty xobj ++
"` inside a `with` at " ++ prettyInfoFromXObj xobj ++
".\n\n`with` accepts only symbols.")
Nothing))
(XObj With _ _) : _ ->
return (Left (EvalError ("Can't have multiple forms within a 'with' expression (except at top-level) at " ++ prettyInfoFromXObj xobj)))
return (Left (EvalError (
"I encountered multiple forms inside a `with` at " ++
prettyInfoFromXObj xobj ++
".\n\n`with` accepts only one expression, except at the top level.")
Nothing))
XObj Mod{} _ _ : _ ->
return (Left (EvalError "Can't eval module"))
return (Left (EvalError ("I cant evaluate the module `" ++
pretty xobj ++ "`")
(info xobj)))
f:args -> do expandedF <- expand eval env f
expandedArgs <- fmap sequence (mapM (expand eval env) args)
case expandedF of

View File

@ -222,7 +222,7 @@ genConstraints typeEnv root = fmap sort (gen root)
let Just headTy = ty x
genObj o n = XObj (Sym (SymPath [] ("Whereas the " ++ enumerate n ++ " element in the array is " ++ show (getPath o))) Symbol)
(info o) (ty o)
headObj = XObj (Sym (SymPath [] ("I inferred the type of the array from the first element of the array " ++ show (getPath x))) Symbol)
headObj = XObj (Sym (SymPath [] ("I inferred the type of the array from its first element " ++ show (getPath x))) Symbol)
(info x) (Just headTy)
Just (StructTy "Array" [t]) = ty xobj
betweenExprConstraints = zipWith (\o n -> Constraint headTy (forceTy o) headObj (genObj o n) xobj OrdArrBetween) xs [1..]

View File

@ -118,7 +118,7 @@ initialTypes typeEnv rootEnv root = evalState (visit rootEnv root) 0
return (Right (xobj { ty = Just renamed }))
| otherwise -> return (Right (xobj { ty = Just theType }))
Nothing -> return (Left (SymbolMissingType xobj foundEnv))
Nothing -> return (Left (SymbolNotDefined symPath xobj)) -- Gives the error message "Trying to refer to an undefined symbol ..."
Nothing -> return (Left (SymbolNotDefined symPath xobj env)) -- Gives the error message "Trying to refer to an undefined symbol ..."
visitMultiSym :: Env -> XObj -> [SymPath] -> State Integer (Either TypeError XObj)
visitMultiSym _ xobj@(XObj (MultiSym name _) _ _) _ =

View File

@ -3,6 +3,7 @@ module Lookup where
import Data.List (intercalate, foldl')
import qualified Data.Map as Map
import Data.Maybe (mapMaybe, fromMaybe, fromJust)
import Text.EditDistance (defaultEditCosts, levenshteinDistance)
import Types
import Obj
@ -209,3 +210,18 @@ isFunctionType _ = False
isStructType :: Ty -> Bool
isStructType (StructTy _ _) = True
isStructType _ = False
keysInEnvEditDistance :: SymPath -> Env -> Int -> [String]
keysInEnvEditDistance (SymPath [] name) env distance =
let candidates = Map.filterWithKey (\k _ -> (levenshteinDistance defaultEditCosts k name) < distance) (envBindings env)
in Map.keys candidates
keysInEnvEditDistance path@(SymPath (p : ps) name) env distance =
case Map.lookup p (envBindings env) of
Just (Binder _ xobj) ->
case xobj of
(XObj (Mod modEnv) _ _) -> keysInEnvEditDistance (SymPath ps name) modEnv distance
_ -> []
Nothing ->
case envParent env of
Just parent -> keysInEnvEditDistance path parent distance
Nothing -> []

View File

@ -294,10 +294,12 @@ pretty = visit 0
Interface _ _ -> "interface"
With -> "with"
newtype EvalError = EvalError String deriving (Eq)
data EvalError = EvalError String (Maybe Info) deriving (Eq)
instance Show EvalError where
show (EvalError msg) = msg
show (EvalError msg info) = msg ++ getInfo info
where getInfo (Just i) = " at " ++ prettyInfo i ++ "."
getInfo Nothing = ""
-- | Get the type of an XObj as a string.
typeStr :: XObj -> String

View File

@ -6,12 +6,13 @@ import Types
import Obj
import Constraints
import Util
import Lookup
data TypeError = SymbolMissingType XObj Env
| DefnMissingType XObj
| DefMissingType XObj
| ExpressionMissingType XObj
| SymbolNotDefined SymPath XObj
| SymbolNotDefined SymPath XObj Env
| InvalidObj Obj XObj
| CantUseDerefOutsideFunctionApplication XObj
| NotAType XObj
@ -49,103 +50,172 @@ data TypeError = SymbolMissingType XObj Env
instance Show TypeError where
show (SymbolMissingType xobj env) =
"I couldnt find a type for the symbol '" ++ getName xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ " in the environment:\n" ++ prettyEnvironment env ++ "\n\nIt might be too general. You could try adding a type hint using `the`."
"I couldnt find a type for the symbol '" ++ getName xobj ++ "' at " ++
prettyInfoFromXObj xobj ++ " in the environment:\n" ++
prettyEnvironment env ++
"\n\nIt might be too general. You could try adding a type hint using `the`."
show (DefnMissingType xobj) =
"I couldnt find a type for the function definition '" ++ getName xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nIt might be too general. You could try adding a type hint using `the`."
"I couldnt find a type for the function definition '" ++ getName xobj ++
"' at " ++ prettyInfoFromXObj xobj ++
".\n\nIt might be too general. You could try adding a type hint using `the`."
show (DefMissingType xobj) =
"I couldnt find a type for the variable definition '" ++ getName xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nIt might be too general. You could try adding a type hint using `the`."
"I couldnt find a type for the variable definition '" ++ getName xobj ++
"' at " ++ prettyInfoFromXObj xobj ++
".\n\nIt might be too general. You could try adding a type hint using `the`."
show (ExpressionMissingType xobj)=
"I couldnt find a type for the expression '" ++ pretty xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nIt might be too general. You could try adding a type hint using `the`."
show (SymbolNotDefined symPath xobj) =
"I couldnt find the symbol '" ++ show symPath ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nMaybe you forgot to define it?"
"I couldnt find a type for the expression '" ++ pretty xobj ++ "' at " ++
prettyInfoFromXObj xobj ++
".\n\nIt might be too general. You could try adding a type hint using `the`."
show (SymbolNotDefined symPath@(SymPath p _) xobj env) =
"I couldnt find the symbol '" ++ show symPath ++ "' at " ++
prettyInfoFromXObj xobj ++ ".\n\n" ++
matches (keysInEnvEditDistance symPath env 3)
where matches [] = "Maybe you forgot to define it?"
matches x = "Maybe you wanted one of the following?\n " ++ joinWith "\n " (map (\s -> show $ (SymPath p s)) x)
show (InvalidObj Defn xobj) =
"I didnt understand the function definition at " ++ prettyInfoFromXObj xobj ++ ".\n\nIs it valid?"
"I didnt understand the function definition at " ++
prettyInfoFromXObj xobj ++
".\n\nIs it valid? Every `defn` needs to follow the form `(defn name [arg] body)`."
show (CantUseDerefOutsideFunctionApplication xobj) =
"I found a `deref` / `~` that isnt inside a function application at " ++ prettyInfoFromXObj xobj ++ ".\n\nEvery usage of `~` must be inside a function application."
"I found a `deref` / `~` that isnt inside a function application at " ++
prettyInfoFromXObj xobj ++
".\n\nEvery usage of `~` must be inside a function application."
show (InvalidObj If xobj) =
"I didnt understand the `if` statement at " ++ prettyInfoFromXObj xobj ++ ".\n\nIs it valid?"
"I didnt understand the `if` statement at " ++ prettyInfoFromXObj xobj ++
".\n\nIs it valid? Every `if` needs to follow the form `(if cond iftrue iffalse)`."
show (InvalidObj o xobj) =
"I didnt understand the form '" ++ show o ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nIs it valid?"
"I didnt understand the form `" ++ show o ++ "` at " ++
prettyInfoFromXObj xobj ++ ".\n\nIs it valid?"
show (WrongArgCount xobj expected actual) =
"You used the wrong number of arguments in '" ++ getName xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ ". I expected " ++ show expected ++ ", but got " ++ show actual ++ "."
"You used the wrong number of arguments in '" ++ getName xobj ++ "' at " ++
prettyInfoFromXObj xobj ++ ". I expected " ++ show expected ++
", but got " ++ show actual ++ "."
show (NotAFunction xobj) =
"You are trying to call the non-function '" ++ getName xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ "."
"You are trying to call the non-function `" ++ getName xobj ++ "` at " ++
prettyInfoFromXObj xobj ++ "."
show (NoStatementsInDo xobj) =
"There are no expressions inside of the `do` statement at " ++ prettyInfoFromXObj xobj ++ ".\n\nAll do statements need to have one or more expressions in it."
"There are no expressions inside of the `do` statement at " ++
prettyInfoFromXObj xobj ++
".\n\nAll instances of `do` need to have one or more expressions in it."
show (TooManyFormsInBody xobj) =
"There are too many expressions in the body of the form at " ++ prettyInfoFromXObj xobj ++ ".\n\nTry wrapping them in a `do`."
"There are too many expressions in the body of the form at " ++
prettyInfoFromXObj xobj ++ ".\n\nTry wrapping them in a `do`."
show (NoFormsInBody xobj) =
"There are no expressions in the body body of the form at " ++ prettyInfoFromXObj xobj ++ ".\n\nI need exactly one body form. For multiple forms, try using `do`."
"There are no expressions in the body body of the form at " ++
prettyInfoFromXObj xobj ++
".\n\nI need exactly one body form. For multiple forms, try using `do`."
show (UnificationFailed constraint@(Constraint a b aObj bObj ctx _) mappings constraints) =
"I cant match the types '" ++ show (recursiveLookupTy mappings a) ++ "' and '" ++ show (recursiveLookupTy mappings b) ++ "'" ++ extra ++ ".\n\n" ++
"I cant match the types `" ++ show (recursiveLookupTy mappings a) ++
"` and `" ++ show (recursiveLookupTy mappings b) ++ "`" ++ extra ++
".\n\n" ++
--show aObj ++ "\nWITH\n" ++ show bObj ++ "\n\n" ++
" " ++ pretty aObj ++ " : " ++ showTypeFromXObj mappings aObj ++ "\n At " ++ prettyInfoFromXObj aObj ++ "" ++
" " ++ pretty aObj ++ " : " ++ showTypeFromXObj mappings aObj ++
"\n At " ++ prettyInfoFromXObj aObj ++ "" ++
"\n\n" ++
" " ++ pretty bObj ++ " : " ++ showTypeFromXObj mappings bObj ++ "\n At " ++ prettyInfoFromXObj bObj ++ "\n"
" " ++ pretty bObj ++ " : " ++ showTypeFromXObj mappings bObj ++
"\n At " ++ prettyInfoFromXObj bObj ++ "\n"
-- ++ "Constraint: " ++ show constraint ++ "\n\n"
-- "All constraints:\n" ++ show constraints ++ "\n\n" ++
-- "Mappings: \n" ++ show mappings ++ "\n\n"
where extra = if ctx == aObj || ctx == bObj then "" else " within `" ++ snip (pretty ctx) ++ "`"
snip s = if length s > 25 then take 15 s ++ " ... " ++ drop (length s - 5) s else s
snip s = if length s > 25
then take 15 s ++ " ... " ++ drop (length s - 5) s
else s
show (CantDisambiguate xobj originalName theType options) =
"I cant disambiguate the symbol '" ++ originalName ++ "' of type " ++ show theType ++ " at " ++ prettyInfoFromXObj xobj ++
"\nPossibilities:\n " ++ joinWith "\n " (map (\(t, p) -> show p ++ " : " ++ show t) options)
"I found an ambiguous symbol `" ++ originalName ++ "` of type `" ++
show theType ++ "` at " ++ prettyInfoFromXObj xobj ++
"\nPossibilities:\n " ++
joinWith "\n " (map (\(t, p) -> show p ++ " : " ++ show t) options)
show (CantDisambiguateInterfaceLookup xobj name theType options) =
"I cant disambiguate the interface '" ++ name ++ "' of type " ++ show theType ++ " at " ++ prettyInfoFromXObj xobj ++
"\nPossibilities:\n " ++ joinWith "\n " (map (\(t, p) -> show p ++ " : " ++ show t) options)
"I found an ambiguous interface `" ++ name ++ "` of type `" ++
show theType ++ "` at " ++ prettyInfoFromXObj xobj ++
"\nPossibilities:\n " ++
joinWith "\n " (map (\(t, p) -> show p ++ " : " ++ show t) options)
show (SeveralExactMatches xobj name theType options) =
"There are several exact matches for the interface '" ++ name ++ "' of type " ++ show theType ++ " at " ++ prettyInfoFromXObj xobj ++
"\nPossibilities:\n " ++ joinWith "\n " (map (\(t, p) -> show p ++ " : " ++ show t) options)
"There are several exact matches for the interface `" ++ name ++
"` of type `" ++ show theType ++ "` at " ++ prettyInfoFromXObj xobj ++
"\nPossibilities:\n " ++
joinWith "\n " (map (\(t, p) -> show p ++ " : " ++ show t) options)
show (NoMatchingSignature xobj originalName theType options) =
"I cant find any implementation for the interface '" ++ originalName ++
"' of type " ++ show theType ++ " at " ++ prettyInfoFromXObj xobj ++
"\nNone of the possibilities have the correct signature:\n " ++ joinWith
"I cant find any implementation for the interface `" ++ originalName ++
"` of type " ++ show theType ++ " at " ++ prettyInfoFromXObj xobj ++
".\n\nNone of the possibilities have the correct signature:\n " ++ joinWith
"\n " (map (\(t, p) -> show p ++ " : " ++ show t) options)
show (LeadingColon xobj) =
"I found a symbol '" ++ pretty xobj ++ "' that starts with a colon at " ++ prettyInfoFromXObj xobj ++ ".\n\nThis is disallowed."
"I found a symbol '" ++ pretty xobj ++ "' that starts with a colon at " ++
prettyInfoFromXObj xobj ++ ".\n\nThis is disallowed."
show (HolesFound holes) =
"I found the following holes:\n\n " ++ joinWith "\n " (map (\(name, t) -> name ++ " : " ++ show t) holes) ++ "\n"
show (FailedToExpand xobj (EvalError errorMessage)) =
"I failed to expand a macro at " ++ prettyInfoFromXObj xobj ++ ".\n\nThe error message I got was: " ++ errorMessage
"I found the following holes:\n\n " ++
joinWith "\n " (map (\(name, t) -> name ++ " : " ++ show t) holes) ++
"\n"
show (FailedToExpand xobj err@(EvalError _ _)) =
"I failed to expand a macro at " ++ prettyInfoFromXObj xobj ++
".\n\nThe error message I got was: " ++ show err
show (NotAValidType xobj) =
pretty xobj ++ "is not a valid type at " ++ prettyInfoFromXObj xobj
show (FunctionsCantReturnRefTy xobj t) =
"Functions cant return references. " ++ getName xobj ++ " : " ++ show t ++ " at " ++ prettyInfoFromXObj xobj ++ "\n\nYoull have to copy the return value using `@`."
"Functions cant return references. " ++ getName xobj ++ " : " ++ show t
++ " at " ++ prettyInfoFromXObj xobj ++
"\n\nYoull have to copy the return value using `@`."
show (LetCantReturnRefTy xobj t) =
"`let` expressions cant return references. '" ++ pretty xobj ++ "' : " ++ show t ++ " at " ++ prettyInfoFromXObj xobj ++ "\n\nYoull have to copy the return value using `@`."
"`let` expressions cant return references. " ++ pretty xobj ++ " : " ++
show t ++ " at " ++ prettyInfoFromXObj xobj ++
"\n\nYoull have to copy the return value using `@`."
show (GettingReferenceToUnownedValue xobj) =
"Youre referencing a given-away value '" ++ pretty xobj ++ "' at " ++ --"' (expression " ++ freshVar i ++ ") at " ++
prettyInfoFromXObj xobj ++ "\n" ++ show xobj ++ "\n\nYoull have to copy the value using `@`."
"Youre referencing a given-away value `" ++ pretty xobj ++ "` at " ++ --"' (expression " ++ freshVar i ++ ") at " ++
prettyInfoFromXObj xobj ++ "\n" ++ show xobj ++
"\n\nYoull have to copy the value using `@`."
show (UsingUnownedValue xobj) =
"Youre using a given-away value '" ++ pretty xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nYoull have to copy the value using `@`."
"Youre using a given-away value `" ++ pretty xobj ++ "` at " ++
prettyInfoFromXObj xobj ++ ".\n\nYoull have to copy the value using `@`."
show (UsingCapturedValue xobj) =
"Youre using a value '" ++ pretty xobj ++ "' that was captured by a function at " ++ prettyInfoFromXObj xobj ++ "."
"Youre using a value `" ++ pretty xobj ++
"` that was captured by a function at " ++ prettyInfoFromXObj xobj ++ "."
show (ArraysCannotContainRefs xobj) =
"Arrays cant contain references: '" ++ pretty xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nYoull have to make a copy using `@`."
"Arrays cant contain references: `" ++ pretty xobj ++ "` at " ++
prettyInfoFromXObj xobj ++ ".\n\nYoull have to make a copy using `@`."
show (MainCanOnlyReturnUnitOrInt xobj t) =
"The main function can only return an `Int` or a unit type (`()`), but it got `" ++ show t ++ "`."
"The main function can only return an `Int` or a unit type (`()`), but it got `" ++
show t ++ "`."
show (MainCannotHaveArguments xobj c) =
"The main function may not receive arguments, but it got " ++ show c ++ "."
show (CannotConcretize xobj) =
"Im unable to concretize the expression '" ++ pretty xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nIt might be too general. You could try adding a type hint using `the`."
"Im unable to concretize the expression '" ++ pretty xobj ++ "' at " ++
prettyInfoFromXObj xobj ++
".\n\nIt might be too general. You could try adding a type hint using `the`."
show (TooManyAnnotateCalls xobj) =
"There were too many annotation calls when annotating '" ++ pretty xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\n I deduced it was an infinite loop."
"There were too many annotation calls when annotating `" ++ pretty xobj ++
"` at " ++ prettyInfoFromXObj xobj ++
".\n\n I deduced it was an infinite loop."
show (NotAType xobj) =
"I dont understand the type '" ++ pretty xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ "\n\nIs it defined?"
"I dont understand the type '" ++ pretty xobj ++ "' at " ++
prettyInfoFromXObj xobj ++ "\n\nIs it defined?"
show (CannotSet xobj) =
"I cant `set!` the expression " ++ pretty xobj ++ " at " ++ prettyInfoFromXObj xobj ++ ".\n\nOnly variables can be reset using `set!`."
"I cant `set!` the expression `" ++ pretty xobj ++ "` at " ++
prettyInfoFromXObj xobj ++ ".\n\nOnly variables can be reset using `set!`."
show (DoesNotMatchSignatureAnnotation xobj sigTy) =
"The definition at " ++ prettyInfoFromXObj xobj ++ " does not match its annotation provided to `sig` as" ++ show sigTy ++ ", its actual type is " ++ show (forceTy xobj) ++ "."
"The definition at " ++ prettyInfoFromXObj xobj ++
" does not match its annotation provided to `sig` as `" ++ show sigTy ++
"`, its actual type is `" ++ show (forceTy xobj) ++ "`."
show (CannotMatch xobj) =
"I cant `match` '" ++ pretty xobj ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nOnly sumtypes can be matched against."
"I cant `match` `" ++ pretty xobj ++ "` at " ++ prettyInfoFromXObj xobj ++
".\n\nOnly sumtypes can be matched against."
show (InvalidSumtypeCase xobj) =
"I failed to read '" ++ pretty xobj ++ "' as a sumtype case, at " ++ prettyInfoFromXObj xobj ++ ".\n\nSumtype cases look like this: `(Foo Int typevar)`"
"I failed to read `" ++ pretty xobj ++ "` as a sumtype case at " ++
prettyInfoFromXObj xobj ++
".\n\nSumtype cases look like this: `(Foo [Int typevar])`"
show (InvalidMemberType t xobj) =
"I cant use the type '" ++ show t ++ "' as a member type at " ++ prettyInfoFromXObj xobj ++ ".\n\nIs it defined and captured in the head of the type definition?"
"I cant use the type `" ++ show t ++ "` as a member type at " ++
prettyInfoFromXObj xobj ++
".\n\nIs it defined and captured in the head of the type definition?"
show (NotAmongRegisteredTypes t xobj) =
"I cant find a definition for the type '" ++ show t ++ "' at " ++ prettyInfoFromXObj xobj ++ ".\n\nWas it registered?"
"I cant find a definition for the type `" ++ show t ++ "` at " ++
prettyInfoFromXObj xobj ++ ".\n\nWas it registered?"
show (UnevenMembers xobjs) =
"The number of members and types is uneven: '" ++ joinWithComma (map pretty xobjs) ++ "' at " ++ prettyInfoFromXObj (head xobjs) ++ ".\n\nBecause they are pairs of names and their types, they need to be even.\nDid you forget a name or type?"
"The number of members and types is uneven: `" ++
joinWithComma (map pretty xobjs) ++ "` at " ++
prettyInfoFromXObj (head xobjs) ++
".\n\nBecause they are pairs of names and their types, they need to be even.\nDid you forget a name or type?"
machineReadableErrorStrings :: FilePathPrintLength -> TypeError -> [String]
machineReadableErrorStrings fppl err =
@ -161,7 +231,7 @@ machineReadableErrorStrings fppl err =
[machineReadableInfoFromXObj fppl xobj ++ " Variable definition '" ++ getName xobj ++ "' missing type."]
(ExpressionMissingType xobj) ->
[machineReadableInfoFromXObj fppl xobj ++ " Expression '" ++ pretty xobj ++ "' missing type."]
(SymbolNotDefined symPath xobj) ->
(SymbolNotDefined symPath xobj _) ->
[machineReadableInfoFromXObj fppl xobj ++ " Trying to refer to an undefined symbol '" ++ show symPath ++ "'."]
(SymbolMissingType xobj env) ->
[machineReadableInfoFromXObj fppl xobj ++ " Symbol '" ++ getName xobj ++ "' missing type."]
@ -203,7 +273,7 @@ machineReadableErrorStrings fppl err =
-- (HolesFound holes) ->
-- (map (\(name, t) -> machineReadableInfoFromXObj fppl xobj ++ " " ++ name ++ " : " ++ show t) holes)
(FailedToExpand xobj (EvalError errorMessage)) ->
(FailedToExpand xobj (EvalError errorMessage _)) ->
[machineReadableInfoFromXObj fppl xobj ++ "Failed to expand: " ++ errorMessage]
-- TODO: Remove overlapping errors: