Copyright© 2019 Elias Castegren and Kiko Fernandez-Reyes
LicenseMIT
Stabilityexperimental
Portabilityportable
Safe HaskellNone

Applicative.Typechecker

Description

This module includes everything you need to get started type checking a program. To build the Abstract Syntax Tree (AST), please import and build Applicative.AST.

The main entry point to the type checker is the combinator tcProgram, which takes an AST and returns either a list of errors, or the typed program. For example, for the following program (using a made up syntax):

class C
  val f: Foo

should be parsed to generate this AST:

testClass1 =
 ClassDef {cname = "C"
          ,fields = [FieldDef {fmod = Val, fname = "f", ftype = ClassType "Foo"}]
          ,methods = []}

To type check the AST, run the tcProgram combinator as follows:

tcProgram testClass1

This is an increment on top of the Typechecker module, that refactors the type checker to be able to throw multiple errors.

Synopsis

Documentation

data Except err a Source #

Define our own Exception datatype to be able to redefine the Applicative interface

Constructors

Result a 
Error err 
Instances
Semigroup err => Monad (Except err) Source # 
Instance details

Defined in Applicative.Typechecker

Methods

(>>=) :: Except err a -> (a -> Except err b) -> Except err b

(>>) :: Except err a -> Except err b -> Except err b

return :: a -> Except err a

fail :: String -> Except err a

Functor (Except err) Source # 
Instance details

Defined in Applicative.Typechecker

Methods

fmap :: (a -> b) -> Except err a -> Except err b

(<$) :: a -> Except err b -> Except err a

Semigroup err => Applicative (Except err) Source # 
Instance details

Defined in Applicative.Typechecker

Methods

pure :: a -> Except err a

(<*>) :: Except err (a -> b) -> Except err a -> Except err b

liftA2 :: (a -> b -> c) -> Except err a -> Except err b -> Except err c

(*>) :: Except err a -> Except err b -> Except err b

(<*) :: Except err a -> Except err b -> Except err a

(Show a, Show err) => Show (Except err a) Source # 
Instance details

Defined in Applicative.Typechecker

Methods

showsPrec :: Int -> Except err a -> ShowS

show :: Except err a -> String

showList :: [Except err a] -> ShowS

throwError :: TCError -> Except TCErrors a Source #

Throw a type checking Error

newtype TCErrors Source #

Declaration of type checking errors. An error will (usually) be created using the helper function throwError. As an example:

throwError $ DuplicateClassError (Name "Foo")

throws an error that indicates that the class is defined multiple times.

Constructors

TCErrors (NonEmpty TCError) 
Instances
Show TCErrors Source # 
Instance details

Defined in Applicative.Typechecker

Methods

showsPrec :: Int -> TCErrors -> ShowS

show :: TCErrors -> String

showList :: [TCErrors] -> ShowS

Semigroup TCErrors Source # 
Instance details

Defined in Applicative.Typechecker

Methods

(<>) :: TCErrors -> TCErrors -> TCErrors

sconcat :: NonEmpty TCErrors -> TCErrors

stimes :: Integral b => b -> TCErrors -> TCErrors

data TCError Source #

Declaration of a type checking errors

Constructors

UnknownClassError Name

Reference of a class that does not exists

UnknownFieldError Name

Reference of a field that does not exists

UnknownMethodError Name

Reference of a method that does not exists

UnboundVariableError Name

Unbound variable

TypeMismatchError Type Type

Type mismatch error, the first Type refers to the formal type argument, the second Type refers to the actual type argument.

ImmutableFieldError Expr

Immutable field error, used when someone violates immutability

NonLValError Expr

Error to indicate that a one cannot assign a value to expression Expr

PrimitiveNullError Type

Error indicating that the return type cannot be Null

NonClassTypeError Type

Used to indicate that Type is not of a class type

NonArrowTypeError Type

Expecting a function (arrow) type but got another type instead.

ConstructorCallError Type

Tried to call a constructor outside of instantiation

UninferrableError Expr

Cannot infer type of Expr

MultipleErrors [TCError]

Contains multiple errors during type checking

Instances
Show TCError Source # 
Instance details

Defined in Applicative.Typechecker

Methods

showsPrec :: Int -> TCError -> ShowS

show :: TCError -> String

showList :: [TCError] -> ShowS

data Env Source #

Environment. The Env is used during type checking, and is updated as the type checker runs. Most likely, one uses the Reader monad to hide details of how the environment is updated, via the common local function.

Constructors

Env 

Fields

emptyEnv :: Env Source #

Generates an empty environment.

lookupClass :: Env -> Name -> Except TCErrors ClassDef Source #

Helper function to lookup a class given a Name and an Env. For example:

typecheck env (ClassType c) = do
  _ <- lookupClass env c
  return $ ClassType c

lookupField :: Env -> Type -> Name -> Except TCErrors FieldDef Source #

Look up a field by its Type and Name in the Env, returning an error indicating whether the field was found or not.

lookupMethod :: Env -> Type -> Name -> Except TCErrors MethodDef Source #

Find a method declaration by its Type (ty) and field name f

lookupVar :: Env -> Name -> Except TCErrors Type Source #

Look up a variable by its Name in the Env, returning an exception with the type checking error, TCError, or the Type of the variable x.

genEnv :: Program -> Env Source #

Generates an environment (symbol's table) from a Program,

addVariable :: Env -> Name -> Type -> Env Source #

Add a variable name and its type to the environment Env.

addParameters :: Env -> [Param] -> Env Source #

Add a list of parameters, Param, to the environment.

tcProgram :: Program -> Except TCErrors Program Source #

Main entry point of the type checker. This function type checks an AST returning either a list of errors or a well-typed program. For instance, assuming the following made up language: > > class C > val f: Foo >

it should be parsed to generate the following AST:

testClass1 =
 ClassDef {cname = "C"
          ,fields = [FieldDef {fmod = Val, fname = "f", ftype = ClassType "Foo"}]
          ,methods = []}

To type check the AST, run the tcProgram combinator as follows:

tcProgram testClass1

which either returns a list of errors or the resulting typed AST.

class Typecheckable a where Source #

The type class defines how to type check an AST node.

Methods

typecheck :: Env -> a -> Except TCErrors a Source #

Type check the well-formedness of an AST node.

hasType :: Env -> Expr -> Type -> Except TCErrors Expr Source #

This combinator is used whenever a certain type is expected. This function is quite important. Here follows an example:

doTypecheck mdef@(MethodDef {mparams, mbody, mtype}) = do
  -- typecheck the well-formedness of types of method parameters
  mparams' <- mapM typecheck mparams
  mtype' <- typecheck mtype

  -- extend environment with method parameters and typecheck body
  mbody' <- local (addParameters mparams) $ hasType mbody mtype'
  ...

in the last line, because we are type checking a method declaration, it is statically known what should be the return type of the function body. In these cases, one should use the hasType combinator.

testClass1 :: ClassDef Source #

Class definition for didactic purposes. This AST represents the following class, which is named C, contains an immutable field f of type Foo:

class C:
  val f: Foo

This class is ill-typed, as there is no declaration of Foo anywhere. To check how to type checker catches this error, run:

tcProgram (Program [testClass1])

testClass2 :: ClassDef Source #

Test program with a class, field, method, and variable access. The class Bar does not exist in the environment. The variable access is unbound.

This program is the AST equivalent of the following syntax:

class D
  val g: Bar
  def m(): Int
    x