packages feed

mulang-4.4.0: src/Language/Mulang/Ast.hs

{-# 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