-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add define-type-alias
#1294
base: main
Are you sure you want to change the base?
Add define-type-alias
#1294
Changes from 20 commits
758cf3d
a125e4a
074488b
688322c
287f089
77a2443
e05bd8a
db74f65
ffbef6e
f252499
9dda5c2
314ff0b
fde68b5
c9ba647
5851da6
ff0e7f7
9b3beda
57366b7
1aba695
e6784b8
8619ceb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -173,9 +173,24 @@ | |
"Lookup the type of value SYMBOL in the global environment" | ||
(tc:lookup-value-type entry:*global-environment* symbol)) | ||
|
||
(defun coalton:describe-type-of (symbol) | ||
"Print the type of value SYMBOL along with its type aliases and return it" | ||
(let ((tc:*pprint-type-aliases* t) | ||
(type (tc:lookup-value-type entry:*global-environment* symbol))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like these are inconsistent with how it prints aliases that are imported from other packages. If you :use a package then this will print the alias without the package. If you don't :use a package, but do something like this: (declare adds (aliases2:Int -> Integer -> Integer)) then you will get an error message that does indeed print the package:
I think, since this is for debugging purposes, it would be helpful to always print the package that a type is from unless it is from the current package or coalton-prelude. Maybe any of the library functions. Here is another example. In this error message, we don't "aliases2" (in-package :cl-user)
(defpackage :aliases2
(:use
#:coalton
#:coalton-prelude)
(:export
:Int
:Ham
:Swiss
:Cheese))
(in-package :aliases2)
(coalton-toplevel
(define-type MoldyMilk Ham Swiss)
(define-type-alias Cheese MoldyMilk))
(coalton-toplevel
(define-type-alias Int Integer)) aliases (main package) (in-package :cl-user)
(defpackage :aliases
(:use
#:coalton
#:coalton-prelude))
;; #:aliases2)) <---- not using the other package
(in-package :aliases)
(coalton-toplevel
(declare value-of-cheese (aliases2:Cheese -> Integer))
(define (value-of-cheese chs)
(match chs
((aliases2:Ham) 10)
((aliases2:Swiss) 20))))
(coalton (value-of-cheese "not cheese"))
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will take a closer look at the behavior of First, the use of Second, when package There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense 👍 |
||
(format t "~S~%" type) | ||
type)) | ||
|
||
(defun coalton:describe-type-alias (symbol) | ||
"Lookup the type represented by the type alias SYMBOL in the global environment" | ||
(let ((tc:*pprint-type-aliases* t) | ||
(type (tc:type-alias-entry-type (tc:lookup-type-alias entry:*global-environment* symbol)))) | ||
(tc:with-pprint-variable-context () | ||
(format t "~S~%" type)) | ||
type)) | ||
|
||
(defun coalton:kind-of (symbol) | ||
"Lookup the kind of type SYMBOL in the global environment" | ||
(tc:kind-of (coalton-impl/typechecker::type-entry-type (tc:lookup-type entry:*global-environment* symbol)))) | ||
(tc:kind-of (tc:type-entry-type (tc:lookup-type entry:*global-environment* symbol)))) | ||
|
||
(defun coalton:lookup-code (name) | ||
"Lookup the compiled code of a given definition" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,13 @@ | |
#:toplevel-define-type-repr ; ACCESSOR | ||
#:toplevel-define-type-head-location ; ACCESSOR | ||
#:toplevel-define-type-list ; TYPE | ||
#:toplevel-define-type-alias ; STRUCT | ||
#:make-toplevel-define-type-alias ; CONSTRUCTOR | ||
#:toplevel-define-type-alias-name ; ACCESSOR | ||
#:toplevel-define-type-alias-vars ; ACCESSOR | ||
#:toplevel-define-type-alias-type ; ACCESSOR | ||
#:toplevel-define-type-alias-head-location ; ACCESSOR | ||
#:toplevel-define-type-alias-list ; TYPE | ||
#:struct-field ; STRUCT | ||
#:make-struct-field ; CONSTRUCTOR | ||
#:struct-field-name ; ACCESSOR | ||
|
@@ -112,6 +119,7 @@ | |
#:program-package ; ACCESSOR | ||
#:program-lisp-forms ; ACCESSOR | ||
#:program-types ; ACCESSOR | ||
#:program-type-aliases ; ACCESSOR | ||
#:program-structs ; ACCESSOR | ||
#:program-declares ; ACCESSOR | ||
#:program-defines ; ACCESSOR | ||
|
@@ -169,6 +177,9 @@ | |
;;;; toplevel-define-type := "(" "define-type" identifier docstring? constructor* ")" | ||
;;;; | "(" "define-type" "(" identifier keyword+ ")" docstring? constructor* ")" | ||
;;;; | ||
;;;; toplevel-define-type-alias := "(" "define-type-alias" identifier ty docstring? ")" | ||
;;;; | "(" "define-type-alias" "(" identifier keyword+ ")" ty docstring? ")" | ||
;;;; | ||
;;;; struct-field := "(" identifier docstring? type ")" | ||
;;;; | ||
;;;; toplevel-define-struct := "(" "define-struct" identifier docstring? struct-field* ")" | ||
|
@@ -265,6 +276,22 @@ | |
(deftype toplevel-define-type-list () | ||
'(satisfies toplevel-define-type-list-p)) | ||
|
||
(defstruct (toplevel-define-type-alias | ||
(:include toplevel-definition) | ||
(:copier nil)) | ||
(name (util:required 'name) :type identifier-src :read-only t) | ||
(vars (util:required 'vars) :type keyword-src-list :read-only t) | ||
(type (util:required 'type) :type ty :read-only t) | ||
(head-location (util:required 'head-location) :type source:location :read-only t)) | ||
|
||
(eval-when (:load-toplevel :compile-toplevel :execute) | ||
(defun toplevel-define-type-alias-list-p (x) | ||
(and (alexandria:proper-list-p x) | ||
(every #'toplevel-define-type-alias-p x)))) | ||
|
||
(deftype toplevel-define-type-alias-list () | ||
'(satisfies toplevel-define-type-alias-list-p)) | ||
|
||
(defstruct (struct-field | ||
(:include toplevel-definition) | ||
(:copier nil)) | ||
|
@@ -464,15 +491,16 @@ | |
(export nil :type list)) | ||
|
||
(defstruct program | ||
(package nil :type (or null toplevel-package) :read-only t) | ||
(types nil :type toplevel-define-type-list :read-only nil) | ||
(structs nil :type toplevel-define-struct-list :read-only nil) | ||
(declares nil :type toplevel-declare-list :read-only nil) | ||
(defines nil :type toplevel-define-list :read-only nil) | ||
(classes nil :type toplevel-define-class-list :read-only nil) | ||
(instances nil :type toplevel-define-instance-list :read-only nil) | ||
(lisp-forms nil :type toplevel-lisp-form-list :read-only nil) | ||
(specializations nil :type toplevel-specialize-list :read-only nil)) | ||
(package nil :type (or null toplevel-package) :read-only t) | ||
(types nil :type toplevel-define-type-list :read-only nil) | ||
(type-aliases nil :type toplevel-define-type-alias-list :read-only nil) | ||
(structs nil :type toplevel-define-struct-list :read-only nil) | ||
(declares nil :type toplevel-declare-list :read-only nil) | ||
(defines nil :type toplevel-define-list :read-only nil) | ||
(classes nil :type toplevel-define-class-list :read-only nil) | ||
(instances nil :type toplevel-define-instance-list :read-only nil) | ||
(lisp-forms nil :type toplevel-lisp-form-list :read-only nil) | ||
(specializations nil :type toplevel-specialize-list :read-only nil)) | ||
|
||
(defun read-program (stream source &optional mode) | ||
"Read a PROGRAM from SOURCE (an instance of source-error:source). | ||
|
@@ -520,6 +548,7 @@ If MODE is :macro, a package form is forbidden, and an explicit check is made fo | |
"attribute must be attached to another form"))) | ||
|
||
(setf (program-types program) (nreverse (program-types program))) | ||
(setf (program-type-aliases program) (nreverse (program-type-aliases program))) | ||
(setf (program-structs program) (nreverse (program-structs program))) | ||
(setf (program-declares program) (nreverse (program-declares program))) | ||
(setf (program-defines program) (nreverse (program-defines program))) | ||
|
@@ -858,6 +887,12 @@ If the parsed form is an attribute (e.g., repr or monomorphize), add it to to AT | |
(push type (program-types program)) | ||
t)) | ||
|
||
((coalton:define-type-alias) | ||
(forbid-attributes attributes form source) | ||
(let ((alias (parse-define-type-alias form source))) | ||
(push alias (program-type-aliases program)) | ||
t)) | ||
|
||
((coalton:define-struct) | ||
(let* ((struct (parse-define-struct form source)) | ||
(repr (consume-repr attributes struct "when parsing define-struct"))) | ||
|
@@ -1107,6 +1142,97 @@ consume all attributes"))) | |
:location (form-location source form) | ||
:head-location (form-location source (cst:second form))))) | ||
|
||
(defun parse-define-type-alias (form source) | ||
(declare (type cst:cst form) | ||
(values toplevel-define-type-alias)) | ||
|
||
(assert (cst:consp form)) | ||
|
||
(let (docstring | ||
name | ||
variables) | ||
|
||
;; (define-type-alias) | ||
(unless (cst:consp (cst:rest form)) | ||
(parse-error "Malformed type alias definition" | ||
(note source form "expected body"))) | ||
|
||
(cond | ||
;; (define-type-alias _ ...) | ||
((cst:atom (cst:second form)) | ||
;; (define-type-alias 0.5 ...) | ||
(unless (identifierp (cst:raw (cst:second form))) | ||
(parse-error "Malformed type alias definition" | ||
(note source (cst:second form) "expected symbol"))) | ||
|
||
;; (define-type-alias name ...) | ||
(setf name (make-identifier-src :name (cst:raw (cst:second form)) | ||
:location (form-location source form)))) | ||
|
||
;; (define-type-alias (_ ...) ...) | ||
(t | ||
;; (define-type-alias((name) ...) ...) | ||
(unless (cst:atom (cst:first (cst:second form))) | ||
(parse-error "Malformed type alias definition" | ||
(note source (cst:first (cst:second form)) | ||
"expected symbol") | ||
(help source (cst:second form) | ||
(lambda (existing) | ||
(subseq existing 1 (1- (length existing)))) | ||
"remove parentheses"))) | ||
|
||
;; (define-type-alias (0.5 ...) ...) | ||
(unless (identifierp (cst:raw (cst:first (cst:second form)))) | ||
(parse-error "Malformed type alias definition" | ||
(note source (cst:first (cst:second form)) | ||
"expected symbol"))) | ||
|
||
;; (define-type-alias (name ...) ...) | ||
(setf name (make-identifier-src :name (cst:raw (cst:first (cst:second form))) | ||
:location (form-location source | ||
(cst:first (cst:second form))))) | ||
|
||
;; (define-type-alias (name) ...) | ||
(when (cst:atom (cst:rest (cst:second form))) | ||
(parse-error "Malformed type alias definition" | ||
(note source (cst:second form) | ||
"nullary type aliases should not have parentheses") | ||
(help source (cst:second form) | ||
(lambda (existing) | ||
(subseq existing 1 (1- (length existing)))) | ||
"remove unnecessary parentheses"))) | ||
|
||
;; (define-type-alias (name type-variables+) ...) | ||
(loop :for vars := (cst:rest (cst:second form)) :then (cst:rest vars) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check that the tyvars are unique There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This takes place during the type checking phase, similar to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
:while (cst:consp vars) | ||
:do (push (parse-type-variable (cst:first vars) source) variables)))) | ||
|
||
;; (define-type-alias name) | ||
(unless (cst:consp (cst:rest (cst:rest form))) | ||
(parse-error "Malformed type alias definition" | ||
(note source form "expected type"))) | ||
|
||
;; (define-type-alias name type docstring) | ||
(when (and (cst:consp (cst:nthrest 3 form)) | ||
(cst:atom (cst:fourth form)) | ||
(stringp (cst:raw (cst:fourth form)))) | ||
(setf docstring (cst:raw (cst:fourth form)))) | ||
|
||
;; (define-type-alias name type docstring ...) | ||
(when (and docstring | ||
(cst:consp (cst:nthrest 4 form))) | ||
(parse-error "Malformed type alias definition" | ||
(note source (cst:fifth form) | ||
"unexpected trailing form"))) | ||
|
||
(make-toplevel-define-type-alias | ||
:name name | ||
:vars (reverse variables) | ||
:type (parse-type (cst:third form) source) | ||
:docstring docstring | ||
:location (form-location source form) | ||
:head-location (form-location source (cst:second form))))) | ||
|
||
(defun parse-define-struct (form source) | ||
(declare (type cst:cst form)) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these functions and their output may need some workshopping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any feedback as far as what is good/bad about them?