{-# LANGUAGE DeriveGeneric, PatternSynonyms, ViewPatterns #-} -- | The Ast module describes a generic, abstract language AST. -- | -- | Since it only describes the AST, but not many aspects of its semantics, Mulang is non-computable, but just a target -- | for code analysis. -- | -- | Mulang AST itself is the combination of other abstract, paradigmatic languages that express the structures of: -- | * imperative programing -- | * object-oriented programing -- | * functional programing -- | * logic programing -- | module Language.Mulang.Ast ( subroutineBodyPatterns, equationPatterns, Code, Equation(..), EquationBody(..), Type(..), Expression(..), Assertion(..), Statement(..), Pattern(..), Identifier, SubroutineBody, debug, debugType, debugPattern, pattern SimpleEquation, pattern SimpleFunction, pattern SimpleProcedure, pattern SimpleMethod, pattern SimpleSend, pattern SubroutineSignature, pattern VariableSignature, pattern ModuleSignature, pattern MuTrue, pattern MuFalse, pattern Subroutine, pattern Clause, pattern Call, pattern Params ) where import GHC.Generics import Language.Mulang.Identifier (Identifier) type Code = String -- | An equation. See @Function@ and @Procedure@ above data Equation = Equation [Pattern] EquationBody deriving (Eq, Show, Read, Generic, Ord) data EquationBody = UnguardedBody Expression | GuardedBody [(Expression, Expression)] deriving (Eq, Show, Read, Generic, Ord) 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 Code) (Maybe Type) -- ^ unrecognized type, with optional code and nested type deriving (Eq, Show, Read, Generic, Ord) -- | 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 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 Type -- ^ Generic type signature for a computation, -- 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 -- ^ Functional / Imperative programming function declaration. -- It is is composed by an identifier and one or more equations | Procedure Identifier SubroutineBody -- ^ Imperative programming procedure declaration. It is composed by a name and one or more equations | Method Identifier SubroutineBody | EqualMethod SubroutineBody | HashMethod SubroutineBody | Variable Identifier Expression | Assignment Identifier Expression | Attribute Identifier Expression -- ^ Object oriented programming attribute declaration, composed by an identifier and an initializer | Object Identifier Expression -- ^ Object oriented programming global, named object declaration, -- composed by a name and a body | Class Identifier (Maybe Identifier) Expression -- ^ Object oriented programming global, class declaration, -- composed by a name, an optional superclass, implemented interfaces and a body | Enumeration Identifier [Identifier] -- ^ Imperative named enumeration of values | Interface Identifier [Identifier] Expression -- ^ Object oriented programming global interface or contract declaration, -- composed by a name, superinterfaces and a body | Rule Identifier [Pattern] [Expression] -- ^ Logic programming declaration of a fact, composed by the rue name, rule arguments, and rule body | Fact Identifier [Pattern] -- ^ Logic programming declaration of a fact , composed by the fact name and fact arguments | Exist Identifier [Pattern] -- ^ Logic programming existential cuantification / consult | Not Expression -- ^ Logic programming negation | Findall Expression Expression Expression -- ^ Logic programming findall | Forall Expression Expression -- ^ Logic programming universal cuantification | Reference Identifier -- ^ Generic variable | Application Expression [Expression] -- ^ Generic, non-curried application of a function or procedure, composed by the applied element itself, and the application arguments | Send Expression Expression [Expression] -- ^ Object oriented programming message send, composed by the reciever, selector and arguments | New Expression [Expression] -- ^ Object oriented instantiation, composed by the class reference and instantiation arguments | Implement Expression -- ^ Object oriented instantiation, interface implementation | Include Expression -- ^ Object oriented instantiation, mixin inclusion | Lambda [Pattern] Expression | If Expression Expression Expression | Return Expression | Yield Expression | While Expression Expression -- ^ Imperative programming conditional repetition control structure, composed by a condition and a body | Repeat Expression Expression -- ^ Imperative programming fixed repetition control structure, composed by a repetition count expression, and a body | Match Expression [Equation] | Switch Expression [(Expression, Expression)] Expression | Try Expression [(Pattern, Expression)] Expression -- ^ Generic try expression, composed by a body, a list of exception-handling patterns and statments, and a finally expression | Raise Expression -- ^ Generic raise expression, like a throw or raise statament, composed by the raised expression | Print Expression -- ^ Generic print expression | For [Statement] Expression | ForLoop Expression Expression Expression Expression -- ^ Imperative / OOP programming c-style for loop | Sequence [Expression] -- ^ Generic sequence of statements | Other (Maybe Code) (Maybe Expression) -- ^ Unrecognized expression, with optional description and body | Equal | NotEqual | Self | None -- ^ Generic value indicating an absent expression, such as when there is no finally in a try or default in a switch or js' undefined | MuNil -- ^ Generic nothing value literal - nil, null or unit | MuObject Expression -- ^ Object oriented unnamed object literal | MuNumber Double -- ^ Generic number literal | MuBool Bool -- ^ Generic boolean literal | MuString String -- ^ Generic string literal | MuChar Char -- ^ Generic char literal | MuSymbol String -- ^ Generic symbol/atom literal | MuTuple [Expression] | MuList [Expression] | TestGroup Expression Expression -- ^ Generic test grouping expression such as describe, context, etc. | Test Expression Expression -- ^ Generic test expression such as it, etc. | Assert Bool Assertion -- ^ Generic assertion expression such as assert, expect, etc. The first parameter indicates whether the assertion is negated or not deriving (Eq, Show, Read, Generic, Ord) data Assertion = Equality Expression Expression -- ^ assert equality between two expressions. e.g.: assert.equals(succ(3), 4) | Truth Expression -- ^ assert truthfulness of boolean expression. e.g.: assert(4 > 3) | Failure Expression Expression -- ^ assert expression fails with an error. e.g.: assert.throws(function () { throw("this breaks") }, "this breaks") deriving (Eq, Show, Read, Generic, Ord) -- | Mulang Patterns are not expressions, but are aimed to match them. -- | They are modeled after Haskell, Prolog, Elixir, Scala and Erlang patterns data Pattern = VariablePattern Identifier -- ^ variable pattern like @X@ | LiteralPattern Code -- ^ literal constant pattern like @4@ | InfixApplicationPattern Pattern Identifier Pattern -- ^ infix application pattern like @4:X@ | ApplicationPattern Identifier [Pattern] -- ^ prefix application pattern like @f _@ | TuplePattern [Pattern] -- ^ tuple pattern like @(3, _)@ | ListPattern [Pattern] -- ^ list pattern like @[x, y, _]@ | FunctorPattern Identifier [Pattern] -- ^ prolog-like functor pattern, like @f(X, 6)@ | AsPattern Identifier Pattern | TypePattern Identifier -- ^ @\@@-pattern | WildcardPattern -- ^ wildcard pattern @_@ | UnionPattern [Pattern] | OtherPattern (Maybe Code) (Maybe Pattern) -- ^ Other unrecognized pattern with optional code and nested pattern deriving (Eq, Show, Read, Generic, Ord) data Statement = Generator Pattern Expression | Guard Expression deriving (Eq, Show, Read, Generic, Ord) debug :: Show a => a -> Expression debug a = Other (Just (show a)) Nothing debugType :: Show a => a -> Type debugType a = OtherType (Just (show a)) Nothing 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) pattern SimpleSend receptor selector args = Send receptor (Reference selector) args pattern SimpleFunction name params body = Function name [SimpleEquation params body] pattern SimpleProcedure name params body = Procedure name [SimpleEquation params body] pattern SimpleMethod name params body = Method name [SimpleEquation params body] pattern MuTrue = MuBool True pattern MuFalse = MuBool False pattern Subroutine name body <- (extractSubroutine -> Just (name, body)) pattern Clause name patterns expressions <- (extractClause -> Just (name, patterns, expressions)) pattern Call operation arguments <- (extractCall -> Just (operation, arguments)) pattern Params params <- (extractParams -> Just params) equationParams :: Equation -> [Pattern] equationParams (Equation p _) = p subroutineBodyPatterns :: SubroutineBody -> [Pattern] subroutineBodyPatterns = concatMap equationPatterns equationPatterns :: Equation -> [Pattern] equationPatterns (Equation p _) = p extractSubroutine :: Expression -> Maybe (Identifier, SubroutineBody) extractSubroutine (Function name body) = Just (name, body) extractSubroutine (Procedure name body) = Just (name, body) extractSubroutine (Method name body) = Just (name, body) extractSubroutine _ = Nothing extractParams :: Expression -> Maybe ([Pattern]) extractParams (Subroutine _ equations) = Just (equationParams.head $ equations) extractParams (Clause _ params _) = Just params extractParams _ = Nothing extractCall :: Expression -> Maybe (Expression, [Expression]) extractCall (Application op args) = Just (op, args) extractCall (Send receptor op args) = Just (op, (receptor:args)) extractCall _ = Nothing extractClause :: Expression -> Maybe (Identifier, [Pattern], [Expression]) extractClause (Fact name patterns) = Just (name, patterns, []) extractClause (Rule name patterns expressions) = Just (name, patterns, expressions) extractClause _ = Nothing