packages feed

hydra-0.15.0: src/main/haskell/Hydra/Sources/Haskell/Syntax.hs

-- | A Haskell syntax model, loosely based on Language.Haskell.Tools.AST

module Hydra.Sources.Haskell.Syntax where

-- Standard type-level imports
import           Hydra.Kernel
import           Hydra.Dsl.Annotations (doc)
import           Hydra.Dsl.Bootstrap
import           Hydra.Dsl.Types ((>:))
import qualified Hydra.Dsl.Types as T
import qualified Hydra.Sources.Kernel.Types.Core as Core


ns :: Namespace
ns = Namespace "hydra.haskell.syntax"

define :: String -> Type -> Binding
define = defineType ns

module_ :: Module
module_ = Module {
            moduleNamespace = ns,
            moduleDefinitions = (map toTypeDef definitions),
            moduleTermDependencies = [Core.ns],
            moduleTypeDependencies = [Core.ns],
            moduleDescription = Just "A Haskell syntax model, loosely based on Language.Haskell.Tools.AST"}
  where
    definitions = [
      alternative,
      assertion,
      classAssertion,
      caseRhs,
      constructor,
      ordinaryConstructor,
      recordConstructor,
      constructorWithComments,
      dataDeclaration,
      dataOrNewtype,
      declarationWithComments,
      declaration,
      declarationHead,
      applicationDeclarationHead,
      deriving_,
      export,
      expression,
      applicationExpression,
      caseExpression,
      constructRecordExpression,
      ifExpression,
      infixApplicationExpression,
      lambdaExpression,
      letExpression,
      prefixApplicationExpression,
      sectionExpression,
      typeSignatureExpression,
      updateRecordExpression,
      field,
      fieldWithComments,
      fieldUpdate,
      import_,
      specImport,
      importModifier,
      importExportSpec,
      subspecImportExportSpec,
      literal,
      localBinding,
      localBindings,
      module',
      moduleHead,
      moduleName,
      name,
      namePart,
      operator,
      pattern,
      applicationPattern,
      asPattern,
      recordPattern,
      typedPattern,
      patternField,
      qualifiedName,
      rightHandSide,
      statement,
      type_,
      applicationType,
      contextType,
      functionType,
      infixType,
      typeDeclaration,
      typeSignature,
      typedBinding,
      valueBinding,
      simpleValueBinding,
      variable]

alternative :: Binding -- UAlt
alternative = define "Alternative" $
  doc "A pattern-matching alternative" $
  T.record [
    "pattern">:
      doc "The pattern to match"
      pattern,
    "rhs">:
      doc "The right-hand side of the alternative"
      caseRhs,
    "binds">:
      doc "Optional local bindings" $
      T.maybe localBindings]

assertion :: Binding -- UAssertion (UClassAssert)
assertion = define "Assertion" $
  doc "A type assertion" $
  T.union [
    "class">:
      doc "A class assertion"
      classAssertion,
    "tuple">:
      doc "A tuple of assertions" $
      T.list assertion]
  -- omitted for now: implicit and infix assertions

classAssertion :: Binding -- UClassAssert
classAssertion = define "ClassAssertion" $
  doc "A class assertion" $
  T.record [
    "name">:
      doc "The name of the class"
      name,
    "types">:
      doc "The types to which the class is applied" $
      T.list type_]

caseRhs :: Binding -- UCaseRhs'
caseRhs = define "CaseRhs" $
  doc "The right-hand side of a pattern-matching alternative" $
  -- omitted for now: guarded
  T.wrap expression

constructor :: Binding -- UConDecl
constructor = define "Constructor" $
  doc "A data constructor" $
  -- omitted for now: ordinary (positional), infix
  T.union [
    "ordinary">:
      doc "An ordinary (positional) constructor"
      ordinaryConstructor,
    "record">:
      doc "A record constructor"
      recordConstructor]

ordinaryConstructor :: Binding
ordinaryConstructor = define "OrdinaryConstructor" $
  doc "An ordinary (positional) data constructor" $
  T.record [
    "name">:
      doc "The name of the constructor"
      name,
    "fields">:
      doc "The types of the positional fields" $
      T.list type_]

recordConstructor :: Binding
recordConstructor = define "RecordConstructor" $
  doc "A record-style data constructor" $
  T.record [
    "name">:
      doc "The name of the constructor"
      name,
    "fields">:
      doc "The named fields of the record" $
      T.list fieldWithComments]

constructorWithComments :: Binding
constructorWithComments = define "ConstructorWithComments" $
  doc "A data constructor together with any comments" $
  T.record [
    "body">:
      doc "The constructor"
      constructor,
    "comments">:
      doc "Optional comments" $
      T.maybe T.string]

dataDeclaration :: Binding -- UDataDecl
dataDeclaration = define "DataDeclaration" $
  doc "A data type declaration" $
  T.record [
    "keyword">:
      doc "The 'data' or 'newtype' keyword"
      dataOrNewtype,
    "context">:
      doc "Type class constraints" $
      T.list assertion,
    "head">:
      doc "The declaration head"
      declarationHead,
    "constructors">:
      doc "The data constructors" $
      T.list constructorWithComments,
    "deriving">:
      doc "Derived type class instances" $
      T.list deriving_]

dataOrNewtype :: Binding
dataOrNewtype = define "DataOrNewtype" $
  doc "The 'data' versus 'newtype keyword" $
  T.enum ["data", "newtype"]

declarationWithComments :: Binding
declarationWithComments = define "DeclarationWithComments" $
  doc "A data declaration together with any comments" $
  T.record [
    "body">:
      doc "The declaration"
      declaration,
    "comments">:
      doc "Optional comments" $
      T.maybe T.string]

declaration :: Binding -- UDecl
declaration = define "Declaration" $
  doc "A data or value declaration" $
  -- omitted for now: typeFamily, typeSignature, closedTypeFamily, gDataDecl, typeInst, dataInst, gDataInst, class, inst,
  --                  patternSynonym, deriv, fixity, default, patTypeSig, foreignImport, foreignExport, pragma,
  --                  role, splice
  T.union [
    "data">:
      doc "A data type declaration"
      dataDeclaration,
    "type">:
      doc "A type synonym declaration"
      typeDeclaration,
    "valueBinding">:
      doc "A value binding"
      valueBinding,
    "typedBinding">:
      doc "A typed binding"
      typedBinding]

declarationHead :: Binding -- UDeclHead
declarationHead = define "DeclarationHead" $
  doc "The left-hand side of a declaration" $
  -- omitted for now: infix application
  T.union [
    "application">:
      doc "An application-style declaration head"
      applicationDeclarationHead,
    "parens">:
      doc "A parenthesized declaration head"
      declarationHead,
    "simple">:
      doc "A simple name"
      name]

applicationDeclarationHead :: Binding
applicationDeclarationHead = define "ApplicationDeclarationHead" $
  doc "An application-style declaration head" $
  T.record [
    "function">:
      doc "The function being applied"
      declarationHead,
    "operand">:
      doc "The type variable operand"
      variable]

deriving_ :: Binding -- UDeriving
deriving_ = define "Deriving" $
  doc "A 'deriving' statement" $
  -- omitted for now: infix, parenthesized, and application instance heads
  T.wrap $ T.list name

export :: Binding -- UExportSpec
export = define "Export" $
  doc "An export statement" $
  T.union [
    "declaration">:
      doc "An exported declaration"
      importExportSpec,
    "module">:
      doc "An exported module"
      moduleName]

expression :: Binding -- UExpr
expression = define "Expression" $
  doc "A data expression" $
  -- omitted for now: multi-if, unboxed tuple, tuple section, unboxed tuple section, parallel array,
  --                  enum, parallel array enum, list comp, parallel array comp, type application,
  --                  (all Template Haskell constructors), pragma, arrow definition, arrow application,
  --                  lambda cases, static, unboxed sum, hole
  T.union [
    "application">:
      doc "A function application"
      applicationExpression,
    "case">:
      doc "A case expression"
      caseExpression,
    "constructRecord">:
      doc "A record constructor expression"
      constructRecordExpression,
    "do">:
      doc "A 'do' expression" $
      T.list statement, -- omitted for now: do vs. mdo
    "if">:
      doc "An 'if' expression"
      ifExpression,
    "infixApplication">:
      doc "An infix application"
      infixApplicationExpression,
    "literal">:
      doc "A literal value"
      literal,
    "lambda">:
      doc "A lambda expression"
      lambdaExpression,
    "leftSection">:
      doc "A left section expression"
      sectionExpression,
    "let">:
      doc "A 'let' expression"
      letExpression,
    "list">:
      doc "A list expression" $
      T.list expression,
    "parens">:
      doc "A parenthesized expression"
      expression,
    "prefixApplication">:
      doc "A prefix application"
      prefixApplicationExpression,
    "rightSection">:
      doc "A right section expression"
      sectionExpression,
    "tuple">:
      doc "A tuple expression" $
      T.list expression,
    "typeSignature">:
      doc "A type signature expression"
      typeSignatureExpression,
    "updateRecord">:
      doc "A record update expression"
      updateRecordExpression,
    "variable">:
      doc "A variable reference"
      name]

applicationExpression :: Binding
applicationExpression = define "ApplicationExpression" $
  doc "An application expression" $
  T.record [
    "function">:
      doc "The function being applied"
      expression,
    "argument">:
      doc "The argument"
      expression]

caseExpression :: Binding
caseExpression = define "CaseExpression" $
  doc "A case expression" $
  T.record [
    "case">:
      doc "The expression being matched"
      expression,
    "alternatives">:
      doc "The pattern-matching alternatives" $
      T.list alternative]

constructRecordExpression :: Binding
constructRecordExpression = define "ConstructRecordExpression" $
  doc "A record constructor expression" $
  T.record [
    "name">:
      doc "The constructor name"
      name,
    "fields">:
      doc "The field assignments" $
      T.list fieldUpdate]

ifExpression :: Binding
ifExpression = define "IfExpression" $
  doc "An 'if' expression" $
  T.record [
    "condition">:
      doc "The condition expression"
      expression,
    "then">:
      doc "The 'then' branch"
      expression,
    "else">:
      doc "The 'else' branch"
      expression]

infixApplicationExpression :: Binding
infixApplicationExpression = define "InfixApplicationExpression" $
  doc "An infix application expression" $
  T.record [
    "lhs">:
      doc "The left-hand operand"
      expression,
    "operator">:
      doc "The infix operator"
      operator,
    "rhs">:
      doc "The right-hand operand"
      expression]

lambdaExpression :: Binding
lambdaExpression = define "LambdaExpression" $
  doc "A lambda expression" $
  T.record [
    "bindings">:
      doc "The patterns binding parameters" $
      T.list pattern,
    "inner">:
      doc "The body of the lambda"
      expression]

letExpression :: Binding
letExpression = define "LetExpression" $
  doc "A 'let' expression" $
  T.record [
    "bindings">:
      doc "The local bindings" $
      T.list localBinding,
    "inner">:
      doc "The body of the let expression"
      expression]

prefixApplicationExpression :: Binding
prefixApplicationExpression = define "PrefixApplicationExpression" $
  doc "A prefix expression" $
  T.record [
    "operator">:
      doc "The prefix operator"
      operator,
    "rhs">:
      doc "The operand"
      expression]

sectionExpression :: Binding
sectionExpression = define "SectionExpression" $
  doc "A section expression" $
  T.record [
    "operator">:
      doc "The operator"
      operator,
    "expression">:
      doc "The operand"
      expression]

typeSignatureExpression :: Binding
typeSignatureExpression = define "TypeSignatureExpression" $
  doc "A type signature expression" $
  T.record [
    "inner">:
      doc "The expression being typed"
      expression,
    "type">:
      doc "The type signature"
      type_]

updateRecordExpression :: Binding
updateRecordExpression = define "UpdateRecordExpression" $
  doc "An update record expression" $
  T.record [
    "inner">:
      doc "The record being updated"
      expression,
    "fields">:
      doc "The field updates" $
      T.list fieldUpdate]

field :: Binding -- UFieldDecl
field = define "Field" $
  doc "A field (name/type pair)" $
  T.record [
    "name">:
      doc "The field name"
      name,
    "type">:
      doc "The field type"
      type_]

fieldWithComments :: Binding
fieldWithComments = define "FieldWithComments" $
  doc "A field together with any comments" $
  T.record [
    "field">:
      doc "The field"
      field,
    "comments">:
      doc "Optional comments" $
      T.maybe T.string]

fieldUpdate :: Binding -- UFieldUpdate
fieldUpdate = define "FieldUpdate" $
  doc "A field name and value" $
  -- omitted for now: pun, wildcard
  T.record [
    "name">:
      doc "The field name"
      name,
    "value">:
      doc "The field value"
      expression]

import_ :: Binding -- UImportDecl
import_ = define "Import" $
  doc "An import statement" $
  -- omitted for now: source, safe, pkg
  T.record [
    "qualified">:
      doc "Whether the import is qualified"
      T.boolean,
    "module">:
      doc "The module being imported"
      moduleName,
    "as">:
      doc "Optional alias for the module" $
      T.maybe moduleName,
    "spec">:
      doc "Optional import specification" $
      T.maybe specImport]

specImport :: Binding
specImport = define "SpecImport" $
  doc "An import specification" $
  T.union [
    "list">:
      doc "A list of imports to include" $
      T.list importExportSpec,
    "hiding">:
      doc "A list of imports to exclude" $
      T.list importExportSpec]

importModifier :: Binding -- UImportModifier
importModifier = define "ImportModifier" $
  doc "An import modifier ('pattern' or 'type')" $
  T.enum ["pattern", "type"]

importExportSpec :: Binding -- UIESpec
importExportSpec = define "ImportExportSpec" $
  doc "An import or export specification" $
  T.record [
    "modifier">:
      doc "Optional import modifier" $
      T.maybe importModifier,
    "name">:
      doc "The name being imported or exported"
      name,
    "subspec">:
      doc "Optional subspecification" $
      T.maybe subspecImportExportSpec]

subspecImportExportSpec :: Binding
subspecImportExportSpec = define "SubspecImportExportSpec" $
  doc "A subspecification within an import/export" $
  T.union [
    "all">:
      doc "Import/export all"
      T.unit,
    "list">:
      doc "Import/export specific names" $
      T.list name]

literal :: Binding -- ULiteral
literal = define "Literal" $
  doc "A literal value" $
  -- omitted for now: frac, primChar
  T.union [
    "char">:
      doc "A character literal"
      T.uint16,
    "double">:
      doc "A double-precision floating point literal"
      T.float64,
    "float">:
      doc "A single-precision floating point literal"
      T.float32,
    "int">:
      doc "A 32-bit integer literal"
      T.int32,
    "integer">:
      doc "An arbitrary-precision integer literal"
      T.bigint,
    "string">:
      doc "A string literal"
      T.string]

localBinding :: Binding -- ULocalBind
localBinding = define "LocalBinding" $
  doc "A local binding" $
  -- omitted for now: fixity, pragma
  T.union [
    "signature">:
      doc "A type signature"
      typeSignature,
    "value">:
      doc "A value binding"
      valueBinding]

localBindings :: Binding -- ULocalBinds
localBindings = define "LocalBindings" $
  doc "A collection of local bindings" $
  T.wrap $ T.list localBinding

module' :: Binding -- UModule
module' = define "Module" $
  doc "A Haskell module" $
  -- omitted for now: pragma
  T.record [
    "head">:
      doc "Optional module head" $
      T.maybe moduleHead,
    "imports">:
      doc "Import statements" $
      T.list import_,
    "declarations">:
      doc "Module declarations" $
      T.list declarationWithComments]

moduleHead :: Binding -- UModuleHead
moduleHead = define "ModuleHead" $
  doc "A module head" $
  -- omitted for now: pragma
  T.record [
    "comments">:
      doc "Optional module-level comments" $
      T.maybe T.string,
    "name">:
      doc "The module name"
      moduleName,
    "exports">:
      doc "Export list" $
      T.list export] -- UExportSpecs

moduleName :: Binding -- UModuleName
moduleName = define "ModuleName" $
  doc "A module name" $
  T.wrap T.string

name :: Binding -- UName
name = define "Name" $
  doc "A name" $
  T.union [
    "implicit">:
      doc "An implicit name"
      qualifiedName,
    "normal">:
      doc "A normal name"
      qualifiedName,
    "parens">:
      doc "A parenthesized name"
      qualifiedName]

namePart :: Binding -- UNamePart
namePart = define "NamePart" $
  doc "A component of a qualified name" $
  T.wrap T.string

operator :: Binding -- UOperator
operator = define "Operator" $
  doc "An operator" $
  T.union [
    "backtick">:
      doc "A function used as an infix operator"
      qualifiedName,
    "normal">:
      doc "A normal infix operator"
      qualifiedName]

pattern :: Binding -- UPattern
pattern = define "Pattern" $
  doc "A pattern" $
  -- omitted for now: unboxed tuples, parallel arrays, irrefutable, bang, view, splice, quasiquote, plusk, unboxed sum
  T.union [
    "application">:
      doc "An application pattern"
      applicationPattern,
    "as">:
      doc "An 'as' pattern"
      asPattern,
    "list">:
      doc "A list pattern" $
      T.list pattern,
    "literal">:
      doc "A literal pattern"
      literal,
    "name">:
      doc "A name pattern"
      name,
    "parens">:
      doc "A parenthesized pattern"
      pattern,
    "record">:
      doc "A record pattern"
      recordPattern,
    "tuple">:
      doc "A tuple pattern" $
      T.list pattern,
    "typed">:
      doc "A typed pattern"
      typedPattern,
    "wildcard">:
      doc "A wildcard pattern"
      T.unit]

applicationPattern :: Binding
applicationPattern = define "ApplicationPattern" $
  doc "An application pattern" $
  T.record [
    "name">:
      doc "The constructor name"
      name,
    "args">:
      doc "The pattern arguments" $
      T.list pattern]

asPattern :: Binding
asPattern = define "AsPattern" $
  doc "An 'as' pattern" $
  T.record [
    "name">:
      doc "The bound name"
      name,
    "inner">:
      doc "The inner pattern"
      pattern]

recordPattern :: Binding
recordPattern = define "RecordPattern" $
  doc "A record pattern" $
  T.record [
    "name">:
      doc "The constructor name"
      name,
    "fields">:
      doc "The field patterns" $
      T.list patternField]

typedPattern :: Binding
typedPattern = define "TypedPattern" $
  doc "A typed pattern" $
  T.record [
    "inner">:
      doc "The inner pattern"
      pattern,
    "type">:
      doc "The type annotation"
      type_]

patternField :: Binding -- UPatternField
patternField = define "PatternField" $
  doc "A pattern field" $
  -- omitted for now: puns, wildcards
  T.record [
    "name">:
      doc "The field name"
      name,
    "pattern">:
      doc "The field pattern"
      pattern]

qualifiedName :: Binding -- UQualifiedName
qualifiedName = define "QualifiedName" $
  doc "A qualified name" $
  T.record [
    "qualifiers">:
      doc "The qualifier parts" $
      T.list namePart,
    "unqualified">:
      doc "The unqualified name part"
      namePart]

rightHandSide :: Binding -- URhs
rightHandSide = define "RightHandSide" $
  doc "A right-hand side of a binding" $
  -- omitted for now: guarded rhs
  T.wrap expression

statement :: Binding -- UStmt
statement = define "Statement" $
  doc "A do-notation statement" $
  T.wrap expression

type_ :: Binding -- UType
type_ = define "Type" $
  doc "A type expression" $
  -- omitted for now: forall, unboxed tuple, parallel array, kinded, promoted, splice, quasiquote, bang,
  --                  lazy, unpack, nounpack, wildcard, named wildcard, sum
  T.union [
    "application">:
      doc "An application type"
      applicationType,
    "ctx">:
      doc "A context type"
      contextType,
    "function">:
      doc "A function type"
      functionType,
    "infix">:
      doc "An infix type"
      infixType,
    "list">:
      doc "A list type"
      type_,
    "parens">:
      doc "A parenthesized type"
      type_,
    "tuple">:
      doc "A tuple type" $
      T.list type_,
    "variable">:
      doc "A type variable or type name"
      name]

applicationType :: Binding
applicationType = define "ApplicationType" $
  doc "An application type" $
  T.record [
    "context">:
      doc "The type being applied"
      type_,
    "argument">:
      doc "The type argument"
      type_]

contextType :: Binding
contextType = define "ContextType" $
  doc "A type with a context (type class constraints)" $
  T.record [
    "ctx">:
      doc "The type class context"
      assertion, -- UContext
    "type">:
      doc "The constrained type"
      type_]

functionType :: Binding
functionType = define "FunctionType" $
  doc "A function type" $
  T.record [
    "domain">:
      doc "The domain type"
      type_,
    "codomain">:
      doc "The codomain type"
      type_]

infixType :: Binding
infixType = define "InfixType" $
  doc "An infix type application" $
  T.record [
    "lhs">:
      doc "The left-hand type"
      type_,
    "operator">:
      doc "The type operator"
      operator,
    "rhs">:
      doc "The right-hand operator"
      operator]

typeDeclaration :: Binding -- UTypeDecl
typeDeclaration = define "TypeDeclaration" $
  doc "A type synonym declaration" $
  T.record [
    "name">:
      doc "The declaration head"
      declarationHead,
    "type">:
      doc "The type being defined"
      type_]

typeSignature :: Binding -- UTypeSignature
typeSignature = define "TypeSignature" $
  doc "A type signature" $
  T.record [
    "name">:
      doc "The name being typed"
      name,
    "type">:
      doc "The type"
      type_]

typedBinding :: Binding -- Added for convenience
typedBinding = define "TypedBinding" $
  doc "A binding with its type signature" $
  T.record [
    "typeSignature">:
      doc "The type signature"
      typeSignature,
    "valueBinding">:
      doc "The value binding"
      valueBinding]

valueBinding :: Binding -- UValueBind
valueBinding = define "ValueBinding" $
  doc "A value binding" $
  -- omitted for now: funBind
  T.union [
    "simple">:
      doc "A simple value binding"
      simpleValueBinding]

simpleValueBinding :: Binding
simpleValueBinding = define "SimpleValueBinding" $
  doc "A simple value binding" $
  T.record [
    "pattern">:
      doc "The pattern being bound"
      pattern,
    "rhs">:
      doc "The right-hand side"
      rightHandSide,
    "localBindings">:
      doc "Optional local bindings (where clause)" $
      T.maybe localBindings]

variable :: Binding
variable = define "Variable" $
  doc "A type variable" $
  -- omitted for now: kind constraints
  T.wrap name