|
let ( *> ) (f : 'a -> 'b) (g : 'b -> 'c) : 'a -> 'c = Fun.compose g f |
|
|
|
module Bool = struct |
|
include Bool |
|
|
|
let on_true (func : unit -> unit) (bool : t) : t = |
|
(match bool with |
|
| true -> func () |
|
| false -> ()); |
|
bool |
|
;; |
|
|
|
let on_false (func : unit -> unit) (bool : t) : t = |
|
(match bool with |
|
| false -> func () |
|
| true -> ()); |
|
bool |
|
;; |
|
end |
|
|
|
module Option = struct |
|
include Option |
|
|
|
let on_none (func : unit -> unit) (option : 'a t) : 'a t = |
|
(match option with |
|
| None -> func () |
|
| Some _ -> ()); |
|
option |
|
;; |
|
end |
|
|
|
module String = struct |
|
include String |
|
|
|
let indent ~(count : int) (string : t) : t = |
|
string |
|
|> split_on_char '\n' |
|
|> List.map (Printf.sprintf "%*s%s" count " ") |
|
|> concat "\n" |
|
;; |
|
end |
|
|
|
module List = struct |
|
include List |
|
|
|
let map_on_cons (func : 'a -> 'b) (list : 'a list) : 'b list option = |
|
match list with |
|
| [] -> None |
|
| _ -> Some (List.map func list) |
|
;; |
|
|
|
let count_elements (list : 'a list) : ('a * int) list = |
|
let rec inner (list : 'a list) (acc : ('a * int) list) : ('a * int) list = |
|
match list with |
|
| [] -> acc |
|
| first :: rest -> |
|
let new_count = |
|
List.assoc_opt first acc |> Option.map Int.succ |> Option.value ~default:1 |
|
in |
|
(first, new_count) :: List.remove_assoc first (inner rest acc) |
|
in |
|
inner list [] |
|
;; |
|
end |
|
|
|
module Highlight = struct |
|
let bold = Printf.sprintf "\x1b[1m%s\x1b[22m" |
|
let dim = Printf.sprintf "\x1b[2m%s\x1b[22m" |
|
let fg (color : int) : string -> string = Printf.sprintf "\x1b[3%dm%s\x1b[39m" color |
|
let comment = dim |
|
let keyword = bold *> fg 5 |
|
let operator = fg 5 |
|
let type' = fg 3 |
|
let metatype = fg 1 |
|
let string = fg 2 |
|
let constructor = fg 4 |
|
let name = fg 6 |
|
let error = bold *> fg 1 |
|
let success = bold *> fg 2 |
|
let warning = bold *> fg 3 |
|
let info = bold *> fg 4 |
|
let note = bold *> fg 5 |
|
end |
|
|
|
module Name = struct |
|
type t = string |
|
|
|
let ( = ) = String.equal |
|
let repr (name : t) : string = Highlight.name name |
|
end |
|
|
|
module Syntactic = struct |
|
type t = |
|
| Atom |
|
| Compound |
|
end |
|
|
|
module Core = struct |
|
type term = |
|
| App of term * term |
|
| Fun of parameter list * term |
|
| Var of Name.t |
|
|
|
and kind = |
|
| Arrow of kind * kind |
|
| Axial of kind * Name.t list |
|
| Bottom |
|
| Product of kind * kind |
|
| Var of Name.t |
|
|
|
and parameter = Named of Name.t * kind |
|
|
|
let rec term_to_syntactic (term : term) : Syntactic.t = |
|
match term with |
|
| App _ | Fun _ -> Compound |
|
| Var _ -> Atom |
|
;; |
|
|
|
let kind_to_syntactic (kind : kind) : Syntactic.t = |
|
match kind with |
|
| Axial _ | Bottom | Var _ -> Atom |
|
| Arrow _ | Product _ -> Compound |
|
;; |
|
|
|
let rec repr_term (term : term) : string = |
|
match term with |
|
| App (function', argument) -> |
|
Printf.sprintf |
|
"%s %s" |
|
(repr_term_considering_precedence function') |
|
(repr_term_considering_precedence argument) |
|
| Fun (parameters, body) -> |
|
Printf.sprintf |
|
"%s %s %s %s" |
|
(Highlight.keyword "fun") |
|
(parameters |> List.map repr_parameter |> String.concat " ") |
|
(Highlight.operator "->") |
|
(repr_term body) |
|
| Var name -> Name.repr name |
|
|
|
and repr_term_considering_precedence (term : term) : string = |
|
let repr = repr_term term in |
|
match term_to_syntactic term with |
|
| Atom -> repr |
|
| Compound -> "(" ^ repr ^ ")" |
|
|
|
and repr_kind (kind : kind) : string = |
|
match kind with |
|
| Arrow (left, right) -> |
|
Printf.sprintf |
|
"%s %s %s" |
|
(repr_kind_considering_precedence left) |
|
(Highlight.operator "->") |
|
(repr_kind right) |
|
| Axial (subkind, axes) -> |
|
Printf.sprintf |
|
"%s[%s]" |
|
(repr_kind_considering_precedence subkind) |
|
(List.map Name.repr axes |> String.concat ", ") |
|
| Bottom -> Printf.sprintf "%s" (Highlight.metatype "\u{22A5}") |
|
| Product (left, right) -> |
|
Printf.sprintf |
|
"%s %s %s" |
|
(repr_kind left) |
|
(Highlight.operator "*") |
|
(repr_kind_considering_precedence right) |
|
| Var name -> Highlight.type' name |
|
|
|
and repr_kind_considering_precedence (kind : kind) : string = |
|
let repr = repr_kind kind in |
|
match kind_to_syntactic kind with |
|
| Atom -> repr |
|
| Compound -> "(" ^ repr ^ ")" |
|
|
|
and repr_parameter (parameter : parameter) : string = |
|
match parameter with |
|
| Named (name, kind) -> Printf.sprintf "(%s : %s)" (Name.repr name) (repr_kind kind) |
|
;; |
|
|
|
module Term = struct |
|
type t = term |
|
|
|
let app (function' : t) (argument' : t) : t = App (function', argument') |
|
let fun' (parameters : parameter list) (body : t) : t = Fun (parameters, body) |
|
let var (name : Name.t) : t = Var name |
|
let repr = repr_term |
|
end |
|
|
|
module Kind = struct |
|
type t = kind |
|
|
|
let arrow (left : t) (right : t) : t = Arrow (left, right) |
|
let axial (subkind : kind) (axes : Name.t list) : t = Axial (subkind, axes) |
|
let product (left : t) (right : t) : t = Product (left, right) |
|
let var (name : Name.t) : t = Var name |
|
|
|
let is_bottom (kind : t) : bool = |
|
match kind with |
|
| Bottom -> true |
|
| _ -> false |
|
;; |
|
|
|
let repr = repr_kind |
|
|
|
module Notation = struct |
|
let ( --> ) = arrow |
|
let ( @ ) = axial |
|
let ( * ) = product |
|
end |
|
end |
|
|
|
module Parameter = struct |
|
type t = parameter |
|
|
|
let named (name : Name.t) (kind : kind) : t = Named (name, kind) |
|
let repr = repr_parameter |
|
end |
|
|
|
module Definition = struct |
|
module Let = struct |
|
type t = |
|
{ binding : Name.t |
|
; body : Term.t |
|
} |
|
|
|
let repr : t -> string = function |
|
| { binding; body } -> |
|
Printf.sprintf |
|
"%s %s %s %s" |
|
(Highlight.keyword "let") |
|
(Highlight.name binding) |
|
(Highlight.operator "=") |
|
(Term.repr body) |
|
;; |
|
end |
|
|
|
module Origin = struct |
|
type t = |
|
{ name : Name.t |
|
; annotation : Kind.t |
|
} |
|
|
|
let repr { name; annotation } : string = |
|
Printf.sprintf |
|
"%s %s %s : %s\n" |
|
(Highlight.operator "|") |
|
(Highlight.keyword "origin") |
|
(Highlight.constructor name) |
|
(Kind.repr annotation) |
|
;; |
|
end |
|
|
|
module Unit = struct |
|
type t = |
|
{ name : Name.t |
|
; axis : Name.t |
|
; annotation : Kind.t |
|
} |
|
|
|
let repr { name; axis; annotation } : string = |
|
Printf.sprintf |
|
"%s %s[%s] %s : %s\n" |
|
(Highlight.operator "|") |
|
(Highlight.keyword "unit") |
|
(Highlight.name axis) |
|
(Highlight.constructor name) |
|
(Kind.repr annotation) |
|
;; |
|
end |
|
|
|
module Global_algebraic_type = struct |
|
type t = |
|
{ binding : Name.t |
|
; axes : Name.t list |
|
; origin : Origin.t |
|
; units : Unit.t list |
|
} |
|
|
|
let repr_axes (axes : Name.t list) : string = |
|
match axes with |
|
| [] -> "" |
|
| _ -> |
|
axes |> List.map Highlight.name |> String.concat " " |> Printf.sprintf " [ %s ]" |
|
;; |
|
|
|
let repr_units (units : Unit.t list) : string = |
|
match units with |
|
| [] -> "" |
|
| _ -> units |> List.map Unit.repr |> String.concat "" |
|
;; |
|
|
|
let repr { binding; axes; origin; units } : string = |
|
Printf.sprintf |
|
"%s %s%s %s\n %s%s" |
|
(Highlight.keyword "type") |
|
(Highlight.type' binding) |
|
(repr_axes axes) |
|
(Highlight.operator "=") |
|
(Origin.repr origin) |
|
(repr_units units |> String.indent ~count:2) |
|
;; |
|
end |
|
|
|
module Type = struct |
|
type t = |
|
| Cartesian of Global_algebraic_type.t (* product *) |
|
| Cocartesian of Global_algebraic_type.t (* sum *) |
|
|
|
let repr : t -> string = function |
|
| Cartesian gat -> |
|
Printf.sprintf |
|
"%s %s" |
|
(Highlight.keyword "cartesian") |
|
(Global_algebraic_type.repr gat) |
|
| Cocartesian gat -> |
|
Printf.sprintf |
|
"%s %s" |
|
(Highlight.keyword "cocartesian") |
|
(Global_algebraic_type.repr gat) |
|
;; |
|
end |
|
end |
|
|
|
module Statement = struct |
|
type t = |
|
| Comment of string |
|
| Let of Definition.Let.t |
|
| Type of Definition.Type.t |
|
|
|
let let' (binding : Name.t) (body : Term.t) : t = Let { binding; body } |
|
|
|
let cartesian_type |
|
(binding : Name.t) |
|
(axes : Name.t list) |
|
(origin : Definition.Origin.t) |
|
(units : Definition.Unit.t list) |
|
: t |
|
= |
|
Type (Cartesian { binding; axes; origin; units }) |
|
;; |
|
|
|
let cocartesian_type |
|
(binding : Name.t) |
|
(axes : Name.t list) |
|
(origin : Definition.Origin.t) |
|
(units : Definition.Unit.t list) |
|
: t |
|
= |
|
Type (Cocartesian { binding; axes; origin; units }) |
|
;; |
|
|
|
let repr : t -> string = function |
|
| Comment content -> Printf.sprintf "%s" (Highlight.comment (";; " ^ content)) |
|
| Let definition -> Definition.Let.repr definition |
|
| Type definition -> Definition.Type.repr definition |
|
;; |
|
end |
|
|
|
module Program = struct |
|
type t = Statement.t list |
|
|
|
let repr : t -> string = function |
|
| [] -> "(empty)" |
|
| program -> program |> List.map Statement.repr |> String.concat "\n" |
|
;; |
|
end |
|
|
|
module Diagnosis = struct |
|
type t = |
|
| Argument_type_mismatch of kind_mismatch |
|
| Duplicate_axis of axis_info |
|
| Invalid_origin_type of kind_mismatch |
|
| Invalid_unit_codomain of kind_mismatch |
|
| Name_not_found of Name.t |
|
| Non_functional_application of term_info |
|
| Unbound_axis of Name.t |
|
|
|
and kind_mismatch = |
|
{ expected : Kind.t |
|
; found : Kind.t |
|
} |
|
|
|
and term_info = |
|
{ term : Term.t |
|
; kind : Kind.t |
|
} |
|
|
|
and axis_info = |
|
{ name : Name.t |
|
; kind_name : Name.t |
|
} |
|
|
|
let repr (diagnosis : t) : string = |
|
match diagnosis with |
|
| Argument_type_mismatch { expected; found } -> |
|
Printf.sprintf |
|
"I expected an argument of type %s, but I found %s" |
|
(Kind.repr expected) |
|
(Kind.repr found) |
|
| Duplicate_axis { name; kind_name } -> |
|
Printf.sprintf |
|
"I found the axis %s more than once in the definition of the type %s ; axes \ |
|
should be unique" |
|
(Name.repr name) |
|
(Highlight.type' kind_name) |
|
| Invalid_origin_type { expected; found } -> |
|
Printf.sprintf |
|
"I expected the origin to be of type %s, but I found %s" |
|
(Kind.repr expected) |
|
(Kind.repr found) |
|
| Invalid_unit_codomain { expected; found } -> |
|
Printf.sprintf |
|
"I expected the unit constructor to produce a value of type %s (directly or \ |
|
after an application) but its type is %s" |
|
(Kind.repr expected) |
|
(Kind.repr found) |
|
| Name_not_found name -> |
|
Printf.sprintf "I couldn't find the name %s" (Name.repr name) |
|
| Non_functional_application { term; kind } -> |
|
Printf.sprintf |
|
"the term %s (of type %s) is not a function ; it cannot be applied" |
|
(Term.repr term) |
|
(Kind.repr kind) |
|
| Unbound_axis axis -> |
|
Printf.sprintf |
|
"I found use of an axis %s, but it doesn't exist in this scope" |
|
(Highlight.name axis) |
|
;; |
|
end |
|
|
|
module Diagnostic = struct |
|
type t = |
|
{ diagnosis : Diagnosis.t |
|
; mutable source : Statement.t option |
|
} |
|
|
|
let repr (diagnostic : t) : string = |
|
let buffer = Buffer.create 64 in |
|
let write = Buffer.add_string buffer in |
|
write |
|
@@ Printf.sprintf |
|
"%s %s" |
|
(Highlight.error "error:") |
|
(Diagnosis.repr diagnostic.diagnosis); |
|
(match diagnostic.source with |
|
| Some statement -> write @@ Printf.sprintf "\n | %s" (Statement.repr statement) |
|
| None -> ()); |
|
Buffer.contents buffer |
|
;; |
|
end |
|
|
|
module Review = struct |
|
type t = |
|
{ decision : [ `Pass | `Abort ] |
|
; details : string option |
|
} |
|
|
|
let print ?(out : out_channel = stderr) (review : t) : unit = |
|
match review.decision with |
|
| `Pass -> |
|
Printf.fprintf |
|
out |
|
"%s no type error found in the program\n" |
|
(Highlight.success "success:") |
|
| `Abort -> |
|
(match review.details with |
|
| None -> () |
|
| Some content -> Printf.fprintf out "%s\n" content); |
|
Printf.fprintf out "\n%s\n" (Highlight.error "Aborted.") |
|
;; |
|
end |
|
|
|
module Doctor = struct |
|
type t = { mutable diagnostics : Diagnostic.t list } |
|
|
|
let create () : t = { diagnostics = [] } |
|
|
|
let add_diagnostic |
|
?(source : Statement.t option) |
|
(diagnosis : Diagnosis.t) |
|
(doctor : t) |
|
: unit |
|
= |
|
doctor.diagnostics <- { diagnosis; source } :: doctor.diagnostics |
|
;; |
|
|
|
let review (doctor : t) : Review.t = |
|
let decision = if List.is_empty doctor.diagnostics then `Pass else `Abort in |
|
let details = |
|
doctor.diagnostics |
|
|> List.rev |
|
|> List.map_on_cons Diagnostic.repr |
|
|> Option.map (String.concat "\n") |
|
in |
|
{ decision; details } |
|
;; |
|
end |
|
|
|
module Context = Quickmap.Make (Name) (Kind) |
|
|
|
class analyzer ?(context : Context.t = Context.empty) ~(doctor : Doctor.t) () = |
|
object (self) |
|
val mutable context = context |
|
val doctor = doctor |
|
|
|
(* term checking *) |
|
|
|
method fetch_term (name : Name.t) : Kind.t option = Context.get name context |
|
|
|
method infer_kind_of_term (term : Term.t) : Kind.t = |
|
match term with |
|
| App (function', argument) -> self#apply_term function' argument |
|
| Fun (parameters, body) -> |
|
let body_kind = self#infer_kind_of_term body in |
|
(match parameters with |
|
| [] -> body_kind |
|
| first :: rest -> |
|
let first_parameter_kind = self#infer_kind_of_parameter first in |
|
Arrow (first_parameter_kind, self#infer_kind_of_term (Fun (rest, body)))) |
|
| Var name -> |
|
self#fetch_term name |
|
|> Option.on_none (fun () -> Doctor.add_diagnostic (Name_not_found name) doctor) |
|
|> Option.value ~default:Bottom |
|
|
|
method infer_kind_of_parameter (parameter : Parameter.t) : Kind.t = |
|
match parameter with |
|
| Named (_, kind) -> kind |
|
|
|
method apply_term (function' : Term.t) (argument : Term.t) : Kind.t = |
|
let function_kind = self#infer_kind_of_term function' in |
|
let argument_kind = self#infer_kind_of_term argument in |
|
if Kind.is_bottom argument_kind |
|
then Bottom |
|
else self#apply_kind function_kind argument_kind |
|
|
|
method apply_kind (function_kind : Kind.t) (argument_kind : Kind.t) : Kind.t = |
|
match function_kind with |
|
| Var name -> |
|
let function_resolved_maybe = self#fetch_term name in |
|
(match function_resolved_maybe with |
|
| None -> |
|
Doctor.add_diagnostic (Name_not_found name) doctor; |
|
Bottom |
|
| Some function_resolved -> self#apply_kind function_resolved argument_kind) |
|
| Axial (subkind, _) -> |
|
(* if the function itself is axis-bound it doesn't really matter *) |
|
self#apply_kind subkind argument_kind |
|
| Arrow (left, right) -> |
|
if self#check_kind ~expected:left argument_kind |
|
then right |
|
else ( |
|
Doctor.add_diagnostic |
|
(Argument_type_mismatch { expected = left; found = argument_kind }) |
|
doctor; |
|
Bottom) |
|
| Product _ -> |
|
Doctor.add_diagnostic |
|
(Non_functional_application { term = Var "???"; kind = function_kind }) |
|
doctor; |
|
Bottom |
|
| Bottom -> Bottom |
|
|
|
method check_term ~(expected : Term.t) (found : Term.t) : bool = |
|
match expected, found with |
|
| App (function_expected, argument_expected), App (function_found, argument_found) |
|
-> |
|
self#check_term ~expected:function_expected function_found |
|
&& self#check_term ~expected:argument_expected argument_found |
|
| Fun (parameters_expected, body_expected), Fun (parameters_found, body_found) -> |
|
List.for_all2 |
|
(fun expected -> self#check_parameter ~expected) |
|
parameters_expected |
|
parameters_found |
|
&& self#check_term ~expected:body_expected body_found |
|
| Var name_expected, Var name_found -> Name.(name_expected = name_found) |
|
| _, _ -> false |
|
|
|
method check_kind ~(expected : Kind.t) (found : Kind.t) : bool = |
|
match expected, found with |
|
| Arrow (left_expected, right_expected), Arrow (left_found, right_found) -> |
|
self#check_kind ~expected:left_expected left_found |
|
&& self#check_kind ~expected:right_expected right_found |
|
| Axial (subkind_expected, axes_expected), Axial (subkind_found, axes_found) -> |
|
self#check_kind ~expected:subkind_expected subkind_found |
|
&& List.for_all (fun axis -> List.mem axis axes_found) axes_expected |
|
| Product (left_expected, right_expected), Product (left_found, right_found) -> |
|
self#check_kind ~expected:left_expected left_found |
|
&& self#check_kind ~expected:right_expected right_found |
|
| Var name_expected, Var name_found -> Name.(name_expected = name_found) |
|
| _, Axial (type_found, _) -> |
|
(* "axis surplus" is fine *) |
|
self#check_kind ~expected type_found |
|
| _, _ -> false |
|
|
|
method check_parameter ~(expected : Parameter.t) (found : Parameter.t) : bool = |
|
match expected, found with |
|
| Named (_, kind_expected), Named (_, kind_found) -> |
|
self#check_kind ~expected:kind_expected kind_found |
|
|
|
(* statement checking *) |
|
|
|
method check_duplicate_axes (gat : Definition.Global_algebraic_type.t) : unit = |
|
let axes_count = List.count_elements gat.axes in |
|
axes_count |
|
|> List.filter (fun (_, count) -> count > 1) |
|
|> List.iter (fun (name, count) -> |
|
Doctor.add_diagnostic (Duplicate_axis { name; kind_name = gat.binding }) doctor) |
|
|
|
method check_origin_definition |
|
(origin : Definition.Origin.t) |
|
~from:(gat : Definition.Global_algebraic_type.t) |
|
: bool = |
|
self#check_kind ~expected:(Var gat.binding) origin.annotation |
|
|> Bool.on_false (fun () -> |
|
Doctor.add_diagnostic |
|
(Invalid_origin_type { expected = Var gat.binding; found = origin.annotation }) |
|
doctor) |
|
|
|
method check_unit_return_kind (return_kind : Kind.t) (gat : Kind.t) : bool = |
|
match return_kind with |
|
| Arrow (_, right) -> self#check_unit_return_kind right gat |
|
| Axial (subkind, _) -> self#check_unit_return_kind subkind gat |
|
| Var _ -> self#check_kind ~expected:gat return_kind |
|
| Product _ -> false |
|
| Bottom -> |
|
failwith "bottom leak: it should not be possible to use ⊥ in user code" |
|
|
|
method check_unit_definition |
|
(unit : Definition.Unit.t) |
|
~from:(gat : Definition.Global_algebraic_type.t) |
|
: bool = |
|
List.mem unit.axis gat.axes |
|
|> Bool.on_false (fun () -> Doctor.add_diagnostic (Unbound_axis unit.axis) doctor) |
|
&& self#check_unit_return_kind unit.annotation (Var gat.binding) |
|
|> Bool.on_false (fun () -> |
|
Doctor.add_diagnostic |
|
(Invalid_unit_codomain |
|
{ expected = Var gat.binding; found = unit.annotation }) |
|
doctor) |
|
|
|
method constrain_kind (return_kind : Kind.t) (axis : Name.t) : Kind.t = |
|
match return_kind with |
|
| Arrow (left, right) -> |
|
Arrow (self#constrain_kind left axis, self#constrain_kind right axis) |
|
| Axial (subkind, axes) -> Axial (subkind, axis :: axes) |
|
| _ -> Axial (return_kind, [ axis ]) |
|
|
|
method get_unit_kind |
|
(unit : Definition.Unit.t) |
|
(gat : Definition.Global_algebraic_type.t) |
|
~(is_cocartesian : bool) |
|
: Kind.t = |
|
if self#check_unit_definition unit ~from:gat |
|
then |
|
if is_cocartesian |
|
then self#constrain_kind unit.annotation unit.axis |
|
else unit.annotation |
|
else Bottom |
|
|
|
method check_global_algebraic_type_definition |
|
?(is_cocartesian : bool = false) |
|
(gat : Definition.Global_algebraic_type.t) |
|
: unit = |
|
let open Kind.Notation in |
|
(* 1) no duplicate axes *) |
|
self#check_duplicate_axes gat; |
|
(* 2) valid origin *) |
|
let origin_kind = |
|
if self#check_origin_definition gat.origin ~from:gat |
|
then gat.origin.annotation @ gat.axes |
|
else Bottom |
|
in |
|
context <- Context.add gat.origin.name origin_kind context; |
|
(* 3) valid units *) |
|
List.iter |
|
(fun (unit : Definition.Unit.t) -> |
|
context |
|
<- Context.add |
|
unit.name |
|
(self#get_unit_kind ~is_cocartesian unit gat) |
|
context) |
|
gat.units |
|
|
|
method check_type_definition (type' : Definition.Type.t) : unit = |
|
match type' with |
|
| Cartesian gat -> self#check_global_algebraic_type_definition gat |
|
| Cocartesian gat -> |
|
self#check_global_algebraic_type_definition ~is_cocartesian:true gat |
|
|
|
method check_statement (statement : Statement.t) : unit = |
|
match statement with |
|
| Comment _ -> () |
|
| Let { binding; body } -> |
|
let body_type = self#infer_kind_of_term body in |
|
context <- Context.add binding body_type context |
|
| Type type' -> self#check_type_definition type' |
|
|
|
method check_program (program : Program.t) : unit = |
|
match program with |
|
| [] -> () |
|
| first :: rest -> |
|
self#check_statement first; |
|
self#check_program rest |
|
end |
|
end |
|
|
|
open Core |
|
|
|
let nat = Kind.var "Nat" |
|
let int = Kind.var "Int" |
|
let plane = Kind.var "Plane" |
|
|
|
let program : Program.t = |
|
[ Statement.cartesian_type |
|
"Plane" |
|
[ "x"; "y" ] |
|
{ name = "Origin"; annotation = plane } |
|
[ { name = "Right"; axis = "x"; annotation = Arrow (plane, plane) } |
|
; { name = "Up"; axis = "y"; annotation = Arrow (plane, plane) } |
|
] |
|
; Statement.cocartesian_type |
|
"Int" |
|
[ "x"; "y" ] |
|
{ name = "O"; annotation = int } |
|
[ { name = "S"; axis = "x"; annotation = Arrow (int, int) } |
|
; { name = "P"; axis = "y"; annotation = Arrow (int, int) } |
|
] |
|
; Comment "this is fine" |
|
; Statement.let' "bar" (App (Var "Up", App (Var "Right", Var "Origin"))) |
|
; Comment "this is not" |
|
; Statement.let' "impossible" (App (Var "P", App (Var "S", Var "O"))) |
|
] |
|
;; |
|
|
|
let doctor = Doctor.create () |
|
let analyzer = new analyzer ~doctor () |
|
let () = Printf.printf "%s\n" (Program.repr program) |
|
let () = Printf.printf "%s\n" (String.make 40 '-') |
|
let () = analyzer#check_program program |
|
let () = Review.print (Doctor.review doctor) |