Skip to content

Commit bfa58d2

Browse files
committed
inferrer: Add.
1 parent 66b7935 commit bfa58d2

File tree

4 files changed

+140
-12
lines changed

4 files changed

+140
-12
lines changed

lamber.asd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
((:file "package")
2222
(:file "utils")
2323
(:file "reader")
24+
(:file "inferrer")
2425
(:file "compiler")
2526
(:file "evaluator")
2627
(:file "printer")

source/compiler.lisp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -171,15 +171,18 @@
171171
nil)))
172172

173173
(defun optimize (tree)
174-
(let ((optimized
175-
(tree-shake
176-
(tree-shake
177-
(tree-shake
178-
(warn-on-shadowing
179-
(warn-on-suspicious-applications
180-
(warn-on-unbound
181-
(de-alias
182-
(plug-dummy-for-lib tree))))))))))
183-
(if (dry-run-p optimized)
184-
'|nil|
185-
optimized)))
174+
(multiple-value-bind (expr return-type all-types)
175+
(type-infer
176+
(tree-shake
177+
(de-alias
178+
(plug-dummy-for-lib tree))))
179+
(let ((optimized
180+
(tree-shake
181+
(tree-shake
182+
(tree-shake
183+
(warn-on-shadowing
184+
(warn-on-suspicious-applications
185+
(warn-on-unbound expr))))))))
186+
(if (dry-run-p optimized)
187+
'|nil|
188+
(values optimized return-type)))))

source/inferrer.lisp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
;;;; SPDX-FileCopyrightText: Artyom Bologov
2+
;;;; SPDX-License-Identifier: BSD-2 Clause
3+
4+
(in-package :lamber)
5+
6+
(define-generic type-infer ((tree (eql '|nil|)) &optional sym-types defined-types)
7+
"Infer the DEFINED-TYPE returned by TREE.
8+
Return
9+
1. The TREE itself, modified when necessary.
10+
2. It's type, where inferrable.
11+
3. And possibly modified SYM-TYPES.
12+
13+
Looks up the types of symbols in SYM-TYPES whenever necessary.
14+
DEFINED-TYPES are types defined so far.
15+
NIL is always an always defined 'anything' type.
16+
Raises warnings if there are type mismatches."
17+
(declare (ignorable defined-types))
18+
(values tree nil sym-types))
19+
20+
(defmethod type-infer ((tree (eql '|false|)) &optional sym-types defined-types)
21+
(declare (ignorable defined-types))
22+
(values tree '|bool| sym-types))
23+
(defmethod type-infer ((tree (eql '|true|)) &optional sym-types defined-types)
24+
(declare (ignorable defined-types))
25+
(values tree '|bool| sym-types))
26+
27+
(defmethod type-infer ((tree integer) &optional sym-types defined-types)
28+
(declare (ignorable defined-types))
29+
(values tree '|int| sym-types))
30+
31+
(defmethod type-infer ((tree character) &optional sym-types defined-types)
32+
(declare (ignorable defined-types))
33+
(values tree '|char| sym-types))
34+
35+
(defmethod type-infer ((tree string) &optional sym-types defined-types)
36+
(declare (ignorable defined-types))
37+
(values tree '|str| sym-types))
38+
39+
(defmethod type-infer ((tree symbol) &optional sym-types defined-types)
40+
(declare (ignorable defined-types))
41+
(values tree (cdr (assoc tree sym-types)) sym-types))
42+
43+
(defun merge-sym-types (types1 types2)
44+
"Merge the TYPES1 and TYPES2 type alists.
45+
Warn if there are mismatches."
46+
;; TODO
47+
)
48+
49+
(defun infer-let (tree &optional sym-types defined-types)
50+
(destructuring-bind (let ((name value)) body)
51+
tree
52+
(declare (ignorable let))
53+
(cond
54+
((eq 'type value)
55+
(type-infer
56+
body sym-types `((,name . 0) ,@defined-types)))
57+
((and (consp value)
58+
(eq 'type (first value)))
59+
;; What a spaghetti dish, yummy!
60+
(destructuring-bind (type (&rest args) body)
61+
value
62+
(declare (ignorable type))
63+
(let* ((constructor `(lambda (,@args) ,body))
64+
(defined-types `((,name . ,(length args)) ,@defined-types))
65+
(dummies (mapcar #'gensym args))
66+
(sym-types
67+
`((,name . (|fn| (,@dummies)
68+
`(,type ,@dummies)))
69+
,@(mapcar #'(lambda (arg dummy)
70+
(cons arg `(|fn| ((,type ,@dummies)) ,dummy)))
71+
args dummies)
72+
,@sym-types)))
73+
(multiple-value-bind (body-expr body-type final-sym-types)
74+
(type-infer body sym-types defined-types)
75+
(values `(let ((,name ,constructor)) ,body-expr)
76+
body-type
77+
(merge-sym-types sym-types final-sym-types))))))
78+
(t (multiple-value-bind (expr type new-sym-types)
79+
(type-infer value sym-types defined-types)
80+
(let ((merged-types (merge-sym-types `((,name ,type))
81+
(merge-sym-types sym-types new-sym-types))))
82+
(multiple-value-bind (body body-type new-new-sym-types)
83+
(type-infer body merged-types defined-types)
84+
(values `(let ((,name ,expr))
85+
,body)
86+
body-type
87+
(merge-sym-types merged-types new-new-sym-types)))))))))
88+
89+
(defmethod type-infer ((tree cons) &optional sym-types defined-types)
90+
(declare (ignorable defined-types))
91+
(let ((head (first tree)))
92+
(cond
93+
((eql 'let head)
94+
(infer-let tree sym-types defined-types))
95+
((and (assoc head defined-types)
96+
(zerop (cdr (assoc head defined-types)))
97+
(second tree)
98+
(symbolp (second tree)))
99+
(destructuring-bind (type sym)
100+
tree
101+
(values sym type `((,sym ,type) ,@sym-types))))
102+
((and (assoc head defined-types)
103+
(plusp (cdr (assoc head defined-types))))
104+
(unless (second tree)
105+
(warn "Constructed types (like ~a) should have arguments" head))
106+
(loop for sub in (rest tree)
107+
for (expr type syms)
108+
= (multiple-value-list (type-infer sub))
109+
collect type into types
110+
collect expr into exprs
111+
do (setf sym-types (merge-sym-types sym-types syms))
112+
finally (values `(,head ,@exprs) `(,head ,@types) sym-types)))
113+
;; TODOTODOTODO
114+
)))

source/reader.lisp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@
5858
`(lambda (,@(uiop:ensure-list args))
5959
,body)
6060
next))))
61+
((memqual-string (first list) '("type" "constructor"))
62+
(if (eq '|end| (second list))
63+
(values 'type (nthcdr 2 list))
64+
(let ((args (second list)))
65+
(multiple-value-bind (body next)
66+
(%read (nthcdr 2 list))
67+
(values
68+
`(type (,@(uiop:ensure-list args))
69+
,body)
70+
next)))))
6171
(t
6272
(loop for elem in list
6373
until (ignore-errors (memqual-string elem '("let" "def" "define" "local" "var" "alias" "if" "then" "else" "end" ".")))

0 commit comments

Comments
 (0)