Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved types support #166

Merged
merged 8 commits into from
May 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
418 changes: 282 additions & 136 deletions README.md

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions spec/HaskellSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,24 @@ spec = do

it "parses right infix partial application" $ do
hs "f = (+1)" `shouldBe` Variable "f" (Application (Reference "+") [MuNumber 1.0])

it "parses type restrictions" $ do
hs "f :: Num a => [a] -> [a]" `shouldBe` SubroutineSignature "f" ["[a]"] "[a]" ["Num a"]

it "parses multiple type restrictions" $ do
hs "f :: (Num a, Eq b) => [a] -> [b]" `shouldBe` SubroutineSignature "f" ["[a]"] "[b]" ["Num a", "Eq b"]

it "parses signatures without type restrictions" $ do
hs "f :: [a] -> [a]" `shouldBe` SubroutineSignature "f" ["[a]"] "[a]" []

it "parses type alias" $ do
hs "type String = [Char]" `shouldBe` TypeAlias "String" "[Char]"

it "parses type alias with arguments" $ do
hs "type List a = [a]" `shouldBe` TypeAlias "List a" "[a]"

it "parses inline type annotations" $ do
hs "x = 1 :: Int" `shouldBe` Variable "x" (TypeCast (MuNumber 1) (SimpleType "Int" []))

it "parses inline type annotations with restrictions" $ do
hs "x = 1 :: (Num a, Foldable t) => t a" `shouldBe` Variable "x" (TypeCast (MuNumber 1) (SimpleType "t a" ["Num a", "Foldable t"]))
2 changes: 1 addition & 1 deletion spec/InspectorSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ spec = do

it "is False otherwise" $ do
assigns (named "x") (Assignment "y" (MuTrue)) `shouldBe` False
assigns (named "x") (Other) `shouldBe` False
assigns (named "x") (Other Nothing Nothing) `shouldBe` False
assigns (named "x") (MuFalse) `shouldBe` False

describe "declaresFunction" $ do
Expand Down
125 changes: 78 additions & 47 deletions spec/JavaSpec.hs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/Language/Mulang/Analyzer/Analysis/Json.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ instance FromJSON EquationBody
instance FromJSON Expression
instance FromJSON Pattern
instance FromJSON Statement
instance FromJSON Type

instance ToJSON AnalysisResult
instance ToJSON ExpectationResult
Expand All @@ -35,4 +36,5 @@ instance ToJSON EquationBody
instance ToJSON Expression
instance ToJSON Pattern
instance ToJSON Statement
instance ToJSON Type

63 changes: 46 additions & 17 deletions src/Language/Mulang/Ast.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,25 @@ module Language.Mulang.Ast (
Code,
Equation(..),
EquationBody(..),
Type(..),
Expression(..),
Statement(..),
Pattern(..),
Identifier,
SubroutineBody,
debug,
pattern Other,
pattern OtherBody,
debugType,
debugPattern,
pattern SimpleEquation,
pattern SimpleFunction,
pattern SimpleProcedure,
pattern SimpleMethod,
pattern SimpleSend,
pattern SubroutineSignature,
pattern VariableSignature,
pattern ModuleSignature,
pattern MuTrue,
pattern MuFalse,
pattern SubroutineTypeSignature,
pattern Subroutine,
pattern Clause,
pattern Call,
Expand All @@ -48,28 +51,49 @@ type Code = String
data Equation = Equation [Pattern] EquationBody deriving (Eq, Show, Read, Generic)

data EquationBody
= UnguardedBody Expression
| GuardedBody [(Expression, Expression)]
deriving (Eq, Show, Read, Generic)
= UnguardedBody Expression
| GuardedBody [(Expression, Expression)]
deriving (Eq, Show, Read, Generic)

type SubroutineBody = [Equation]

-- A Generic Type, that can be used for typing expressions,
-- classes, functions, variables and so on, using a @TypeSignature@
-- or a @TypeCast@
data Type
= SimpleType Identifier [Identifier]
-- ^ simple types, with a type identifier and type constraints
-- Useful for modelling variable types
| ParameterizedType [Identifier] Identifier [Identifier]
-- ^ parameterized types, with type inputs, type identifier and type constraints
-- Useful for modelling functions, methods and procedures types
| ConstrainedType [Identifier]
-- ^ constrained type, with just type constraints.
-- Usefull for modelling classes and interfaces types
| OtherType (Maybe String) (Maybe Type)
-- ^ unrecognized type, with optional code and nested type
deriving (Eq, Show, Read, Generic)

-- | Expression is the root element of a Mulang program.
-- | With the exception of Patterns, nearly everything is an Expression: variable declarations, literals,
-- | control structures, even object oriented classes declarations.
-- |
-- | However, although all those elements can be used as subexpressions and have an dohave an associated value,
-- | Mulang does not state WHICH is that value.
data Expression
= TypeAlias Identifier
= TypeAlias Identifier Identifier
-- ^ Functional programming type alias.
-- Only the type alias identifier is parsed
| Record Identifier
-- ^ Imperative / Functional programming struct declaration.
-- Only the record name is parsed
| TypeSignature Identifier (Maybe [Identifier]) Identifier
| TypeSignature Identifier Type
-- ^ Generic type signature for a computation,
-- composed by a name, parameter types and return type
-- composed by a name and its type
| TypeCast Expression Type
-- ^ Generic type annotation for an expression. For example,
-- a Java cast: (String) anObject => TypeAnnotation (Variable "anObject") "String"
-- a Haskell inline type declaration: ... = x :: Int => TypeAnnotation (Variable "x") "Int"
| EntryPoint Identifier Expression
-- ^ Entry point with its body
| Function Identifier SubroutineBody
Expand Down Expand Up @@ -140,7 +164,7 @@ data Expression
-- ^ Imperative / OOP programming c-style for loop
| Sequence [Expression]
-- ^ Generic sequence of statements
| Unknown (Maybe String) (Maybe Expression)
| Other (Maybe String) (Maybe Expression)
-- ^ Unrecognized expression, with optional description and body
| Equal
| NotEqual
Expand Down Expand Up @@ -186,8 +210,8 @@ data Pattern
| WildcardPattern
-- ^ wildcard pattern @_@
| UnionPattern [Pattern]
| OtherPattern
-- ^ Other unrecognized pattern
| OtherPattern (Maybe String) (Maybe Pattern)
-- ^ Other unrecognized pattern with optional code and nested pattern
deriving (Eq, Show, Read, Generic)

data Statement
Expand All @@ -196,10 +220,17 @@ data Statement
deriving (Eq, Show, Read, Generic)

debug :: Show a => a -> Expression
debug a = Unknown (Just (show a)) Nothing
debug a = Other (Just (show a)) Nothing

debugType :: Show a => a -> Type
debugType a = OtherType (Just (show a)) Nothing

pattern Other = Unknown Nothing Nothing
pattern OtherBody body <- Unknown _ (Just body)
debugPattern :: Show a => a -> Pattern
debugPattern a = OtherPattern (Just (show a)) Nothing

pattern VariableSignature name t cs = TypeSignature name (SimpleType t cs)
pattern SubroutineSignature name args t cs = TypeSignature name (ParameterizedType args t cs)
pattern ModuleSignature name cs = TypeSignature name (ConstrainedType cs)

pattern SimpleEquation params body = Equation params (UnguardedBody body)

Expand All @@ -212,8 +243,6 @@ pattern SimpleMethod name params body = Method name [SimpleEquation params
pattern MuTrue = MuBool True
pattern MuFalse = MuBool False

pattern SubroutineTypeSignature name params return = TypeSignature name (Just params) return

pattern Subroutine name body <- (extractSubroutine -> Just (name, body))
pattern Clause name patterns expressions <- (extractClause -> Just (name, patterns, expressions))

Expand Down
9 changes: 5 additions & 4 deletions src/Language/Mulang/Generator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ declarations e@(Subroutine n b) = (n, e) : concatMap declarations (equationE
declarations e@(Object n b) = (n, e) : declarations b
declarations e@(Clause n _ _) = [(n, e)]
declarations e@(Record n) = [(n, e)]
declarations e@(TypeAlias n) = [(n, e)]
declarations e@(TypeSignature n _ _)= [(n, e)]
declarations e@(TypeAlias n _) = [(n, e)]
declarations e@(TypeSignature n _) = [(n, e)]
declarations e@(Variable n _) = [(n, e)]
declarations _ = []

Expand All @@ -59,8 +59,8 @@ expressions expr = expr : concatMap expressions (subExpressions expr)
subExpressions (Clause _ _ es) = es
subExpressions (EntryPoint _ e) = [e]
subExpressions (For stmts a) = statementExpressions stmts ++ [a]
subExpressions (ForLoop i c p s) = [i, c, p, s]
subExpressions (Forall e1 e2) = [e1, e2]
subExpressions (ForLoop i c p s) = [i, c, p, s]
subExpressions (If a b c) = [a, b, c]
subExpressions (Interface _ _ v) = [v]
subExpressions (Lambda _ a) = [a]
Expand All @@ -71,13 +71,14 @@ expressions expr = expr : concatMap expressions (subExpressions expr)
subExpressions (New _ es) = es
subExpressions (Not e) = [e]
subExpressions (Object _ v) = [v]
subExpressions (OtherBody e) = [e]
subExpressions (Other _ (Just e)) = [e]
subExpressions (Repeat e1 e2) = [e1, e2]
subExpressions (Return v) = [v]
subExpressions (Sequence es) = es
subExpressions (Subroutine _ es) = equationExpressions es
subExpressions (Switch e1 list _) = e1 : concatMap (\(x,y) -> [x,y]) list
subExpressions (Try t cs f) = t : map snd cs ++ [f]
subExpressions (TypeCast e _) = [e]
subExpressions (Variable _ v) = [v]
subExpressions (While e1 e2) = [e1, e2]
subExpressions (Yield v) = [v]
Expand Down
28 changes: 14 additions & 14 deletions src/Language/Mulang/Inspector/Generic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,23 @@ type IdentifierInspection = IdentifierPredicate -> Inspection

typesReturnAs :: IdentifierInspection
typesReturnAs predicate = containsDeclaration f
where f (SubroutineTypeSignature _ _ name) = predicate name
f _ = False
where f (SubroutineSignature _ _ name _) = predicate name
f _ = False

typesParameterAs :: IdentifierInspection
typesParameterAs predicate = containsDeclaration f
where f (SubroutineTypeSignature _ names _) = any predicate names
f _ = False
where f (SubroutineSignature _ names _ _) = any predicate names
f _ = False

typesAs :: IdentifierInspection
typesAs predicate = containsDeclaration f
where f (TypeSignature _ Nothing name) = predicate name
f _ = False
where f (VariableSignature _ name _) = predicate name
f _ = False

usesType :: IdentifierInspection
usesType predicate = containsDeclaration f
where f (TypeSignature _ _ name) | predicate name = True
f (SubroutineTypeSignature _ names _) = any predicate names
where f (VariableSignature _ name _) = predicate name
f (SubroutineSignature _ args ret _) = any predicate (ret:args)
f _ = False

-- | Inspection that tells whether an expression is equal to a given piece of code after being parsed
Expand Down Expand Up @@ -107,8 +107,8 @@ usesFor = containsExpression f
-- | Inspection that tells whether a top level declaration exists
declares :: IdentifierInspection
declares = containsBoundDeclaration f
where f (TypeSignature _ _ _) = False
f _ = True
where f (TypeSignature _ _) = False
f _ = True

-- | Inspection that tells whether an expression is direct recursive
declaresRecursively :: IdentifierInspection
Expand Down Expand Up @@ -154,13 +154,13 @@ declaresComputationWithArity' arityPredicate = containsBoundDeclaration f

declaresTypeAlias :: IdentifierInspection
declaresTypeAlias = containsBoundDeclaration f
where f (TypeAlias _) = True
f _ = False
where f (TypeAlias _ _) = True
f _ = False

declaresTypeSignature :: IdentifierInspection
declaresTypeSignature = containsBoundDeclaration f
where f (TypeSignature _ _ _) = True
f _ = False
where f (TypeSignature _ _) = True
f _ = False

raises :: IdentifierInspection
raises predicate = containsExpression f
Expand Down
49 changes: 31 additions & 18 deletions src/Language/Mulang/Parsers/Haskell.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ mu (HsModule _ _ _ _ decls) = compact (concatMap muDecls decls)
where
mergeDecls decls exp = compact (decls ++ [exp])

muDecls (HsTypeDecl _ name _ _) = [TypeAlias (muName name)]
muDecls (HsTypeDecl _ name args t) = [TypeAlias (unwords . map muName $ name : args) (muTypeId t)]
muDecls (HsDataDecl _ _ name _ _ _ ) = [Record (muName name)]
muDecls (HsTypeSig _ names (HsQualType _ t)) = map (muTypeSignature t) names
muDecls (HsTypeSig _ names (HsQualType constraints t))
= map (muTypeSignature constraints t) names
muDecls (HsFunBind equations) | (HsMatch _ name _ _ _) <- head equations =
[Function (muName name) (map muEquation equations)]
muDecls (HsPatBind _ (HsPVar name) (HsUnGuardedRhs exp) _) = [Variable (muName name) (muExp exp)]
Expand All @@ -57,7 +58,7 @@ mu (HsModule _ _ _ _ decls) = compact (concatMap muDecls decls)
muPat (HsPParen pattern) = muPat pattern
muPat (HsPAsPat name pattern) = AsPattern (muName name) (muPat pattern)
muPat HsPWildCard = WildcardPattern
muPat _ = OtherPattern
muPat p = debugPattern p

muExp (HsVar (UnQual (HsIdent "undefined"))) = Raise (MuString "undefined")

Expand Down Expand Up @@ -89,6 +90,7 @@ mu (HsModule _ _ _ _ decls) = compact (concatMap muDecls decls)
muExp (HsEnumFromThenTo from thn to) = Application (Reference "enumFromThenTo") [(muExp from), (muExp thn), (muExp to)]
muExp (HsListComp exp stmts) = For (map muStmt stmts) (Yield (muExp exp))
muExp (HsDo stmts) | (HsQualifier exp) <- last stmts = For (map muStmt stmts) (Yield (muExp exp))
muExp (HsExpTypeSig _ exp (HsQualType cs t)) = TypeCast (muExp exp) (muType t cs)
muExp e = debug e

muLit (HsCharPrim v) = MuString [v]
Expand Down Expand Up @@ -124,19 +126,30 @@ mu (HsModule _ _ _ _ decls) = compact (concatMap muDecls decls)
muStmt (HsGenerator _ pat exp) = Generator (muPat pat) (muExp exp)
muStmt (HsQualifier exp) = Guard (muExp exp)

muTypeSignature t name = TypeSignature (muName name) (listToMaybe $ init topTypes) (last topTypes)
where topTypes = muTopTypes t

listToMaybe [] = Nothing
listToMaybe xs = Just xs

muTopTypes (HsTyFun i o) = muType i : muTopTypes o
muTopTypes t = [muType t]

muType (HsTyFun i o) = muType i ++ " -> " ++ muType o
muType (HsTyCon name) = muQName name
muType (HsTyVar name) = muName name
muType (HsTyTuple ts) = "(" ++ (intercalate ", " . map muType $ ts) ++ ")"
muType (HsTyApp (HsTyCon (Special HsListCon)) t2) = "[" ++ muType t2 ++ "]"
muType (HsTyApp t1 t2) = muType t1 ++ " " ++ muType t2
muTypeSignature :: [HsAsst] -> HsType -> HsName -> Expression
muTypeSignature cs t name = TypeSignature (muName name) (muType t cs)

muType :: HsType -> [HsAsst] -> Type
muType t cs | null initTypes = SimpleType lastType constraints
| otherwise = ParameterizedType initTypes lastType constraints
where
initTypes = init topTypes
lastType = last topTypes
topTypes = muTopTypes t
constraints = map muConstraint cs

muConstraint :: HsAsst -> Identifier
muConstraint (constraint, targets) =
intercalate " " (muQName constraint : map muTypeId targets)

muTopTypes (HsTyFun i o) = muTypeId i : muTopTypes o
muTopTypes t = [muTypeId t]

muTypeId :: HsType -> Identifier
muTypeId (HsTyFun i o) = muTypeId i ++ " -> " ++ muTypeId o
muTypeId (HsTyCon name) = muQName name
muTypeId (HsTyVar name) = muName name
muTypeId (HsTyTuple ts) = "(" ++ (intercalate ", " . map muTypeId $ ts) ++ ")"
muTypeId (HsTyApp (HsTyCon (Special HsListCon)) t2) = "[" ++ muTypeId t2 ++ "]"
muTypeId (HsTyApp t1 t2) = muTypeId t1 ++ " " ++ muTypeId t2

Loading